Version 1.15.0-dev.2.0

Merge commit '7ab578d21ffec146e7889edd847a408eeb8a5e26' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 045ba6a..6a62b7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,27 @@
   * Added `Uri.queryParametersAll` to handle multiple query parameters with
     the same name.
 
+* `dart:io`
+  * Added `SecurityContext.usePrivateKeyBytes`,
+          `SecurityContext.useCertificateChainBytes`,
+          `SecurityContext.setTrustedCertificatesBytes`, and
+          `SecurityContext.setClientAuthoritiesBytes`.
+  * The non-`Bytes` methods of `SecurityContext` are being renamed -`Sync`, as
+    they will do synchronous IO. The non-`Bytes` and non-`Sync` methods are
+    deprecated and will be removed in a later release.
+  * **Breaking** The named `directory` argument of
+    `SecurityContext.setTrustedCertificates` is no longer supported.
+    The method now only supports one argument for the PEM file name containing
+    the trusted certificates.
+
+## 1.14.1 - 2016-02-04
+
+Patch release, resolves one issue:
+
+* Debugger: Fixes a VM crash when a debugger attempts to set a break point
+during isolate initialization.
+(SDK issue [25618](https://github.com/dart-lang/sdk/issues/25618))
+
 ## 1.14.0 - 2016-01-28
 
 ### Core library changes
diff --git a/DEPS b/DEPS
index fdb11dc..d605a86 100644
--- a/DEPS
+++ b/DEPS
@@ -67,7 +67,7 @@
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "plugin_tag": "@0.1.0",
   "pool_tag": "@1.2.1",
-  "pub_rev": "@57a17f2567d1ff3325960d0960f939fa243b5fd7",
+  "pub_rev": "@bd5c77abcb609d95340632b96344b59035e70376",
   "pub_cache_tag": "@v0.1.0",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
diff --git a/dart.gyp b/dart.gyp
index a0c5a85..a7d4f95 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -25,6 +25,7 @@
       'type': 'none',
       'dependencies': [
         'runtime/dart-runtime.gyp:dart',
+        'runtime/dart-runtime.gyp:dart_noopt',
         'runtime/dart-runtime.gyp:dart_precompiled_runtime',
         'runtime/dart-runtime.gyp:dart_no_snapshot',
         'runtime/dart-runtime.gyp:run_vm_tests',
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/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 73bc612..430a2e6 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -23,6 +23,7 @@
 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';
@@ -302,13 +303,18 @@
       this.defaultSdk,
       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);
+    contextManager = new ContextManagerImpl(
+        resourceProvider,
+        packageResolverProvider,
+        embeddedResolverProvider,
+        packageMapProvider,
+        instrumentationService);
     ServerContextManagerCallbacks contextManagerCallbacks =
         new ServerContextManagerCallbacks(this, resourceProvider);
     contextManager.callbacks = contextManagerCallbacks;
@@ -1459,7 +1465,7 @@
     context.contentCache = analysisServer.overlayState;
     analysisServer.folderMap[folder] = context;
     _locateEmbedderYamls(context, disposition);
-    context.sourceFactory = _createSourceFactory(context, disposition);
+    context.sourceFactory = _createSourceFactory(context, disposition, folder);
     context.analysisOptions =
         new AnalysisOptionsImpl.from(analysisServer.defaultContextOptions);
     analysisServer._onContextsChangedController
@@ -1530,7 +1536,8 @@
   void updateContextPackageUriResolver(
       Folder contextFolder, FolderDisposition disposition) {
     AnalysisContext context = analysisServer.folderMap[contextFolder];
-    context.sourceFactory = _createSourceFactory(context, disposition);
+    context.sourceFactory =
+        _createSourceFactory(context, disposition, contextFolder);
     analysisServer._onContextsChangedController
         .add(new ContextsChangedEvent(changed: [context]));
     analysisServer.schedulePerformAnalysisOperation(context);
@@ -1548,12 +1555,26 @@
    * Set up a [SourceFactory] that resolves packages as appropriate for the
    * given [disposition].
    */
-  SourceFactory _createSourceFactory(
-      InternalAnalysisContext context, FolderDisposition disposition) {
+  SourceFactory _createSourceFactory(InternalAnalysisContext context,
+      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
@@ -1564,6 +1585,7 @@
       // 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/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 2140f7c..92efe4d 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -12,6 +12,7 @@
 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';
@@ -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';
@@ -399,6 +401,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].
    */
@@ -459,8 +468,12 @@
   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._instrumentationService) {
     absolutePathContext = resourceProvider.absolutePathContext;
     pathContext = resourceProvider.pathContext;
   }
@@ -834,14 +847,57 @@
       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));
+          }
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 62e284e..2cdb251 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -19,6 +19,7 @@
 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';
@@ -297,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.
    */
@@ -414,7 +421,7 @@
     // Create the sockets and start listening for requests.
     //
     socketServer = new SocketServer(analysisServerOptions, defaultSdk, service,
-        serverPlugin, packageResolverProvider);
+        serverPlugin, packageResolverProvider, embeddedUriResolverProvider);
     httpServer = new HttpAnalysisServer(socketServer);
     stdioServer = new StdioAnalysisServer(socketServer);
     socketServer.userDefinedPlugins = _userDefinedPlugins;
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 c04bd75..ffdf72d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -447,7 +447,8 @@
           if (numRequired != 0) {
             sb.append(', ');
           }
-          _appendParameterForArgument(sb, numRequired, argument);
+          _appendParameterForArgument(
+              sb, new Set<String>(), numRequired, argument);
           if (numRequired != numParameters) {
             sb.append(', ');
           }
@@ -463,7 +464,8 @@
             sb.append(', ');
           }
           sb.append('[');
-          _appendParameterForArgument(sb, numRequired, argument);
+          _appendParameterForArgument(
+              sb, new Set<String>(), numRequired, argument);
           sb.append(']');
           // add proposal
           _insertBuilder(sb, targetElement);
@@ -1249,7 +1251,7 @@
           // add field
           addEolIfNotFirst();
           sb.append(utils.getIndent(1));
-          _appendType(sb, element.type.returnType);
+          _appendType(sb, element.type.returnType, orVar: true);
           sb.append(element.name);
           sb.append(';');
           sb.append(eol);
@@ -2032,6 +2034,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;
@@ -2047,7 +2050,7 @@
         hasNamedParameters = true;
         sb.append('{');
       }
-      _appendParameterForArgument(sb, i, argument);
+      _appendParameterForArgument(sb, usedNames, i, argument);
     }
     if (hasNamedParameters) {
       sb.append('}');
@@ -2238,7 +2241,7 @@
           {
             sb.startPosition('TYPE$i');
             sb.append(typeSource);
-            _addSuperTypeProposals(sb, new Set(), type);
+            _addSuperTypeProposals(sb, type);
             sb.endPosition();
           }
           sb.append(' ');
@@ -2333,14 +2336,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(' ');
     }
@@ -2348,7 +2351,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];
@@ -2821,16 +2823,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);
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 63aefd9..c69bf69 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -1033,7 +1033,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)) {
@@ -1041,7 +1042,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) {
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..7855298 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -31,6 +31,16 @@
 
 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/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index 1efbfd9..9fd17ca 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -12,6 +12,7 @@
 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_io.dart';
@@ -28,6 +29,7 @@
   final DirectoryBasedDartSdk defaultSdk;
   final InstrumentationService instrumentationService;
   final ServerPlugin serverPlugin;
+  final EmbeddedResolverProvider embeddedResolverProvider;
   final ResolverProvider packageResolverProvider;
 
   /**
@@ -46,7 +48,8 @@
       this.defaultSdk,
       this.instrumentationService,
       this.serverPlugin,
-      this.packageResolverProvider);
+      this.packageResolverProvider,
+      this.embeddedResolverProvider);
 
   /**
    * Create an analysis server which will communicate with the client using the
@@ -91,6 +94,7 @@
         defaultSdk,
         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 0887d07..a65b1610 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';
@@ -1353,6 +1354,16 @@
           int processorCount = errorProcessors?.length ?? 0;
           buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
         });
+        
+        SourceFactory sourceFactory = context.sourceFactory;
+        if (sourceFactory is SourceFactoryImpl) {
+          buffer.write('<h3>Resolvers</h3>');
+          for (UriResolver resolver in sourceFactory.resolvers) {
+            buffer.write('<p>');
+            buffer.write(resolver.runtimeType);
+            buffer.write('</p>');
+          }
+        }
 
         _writeFiles(
             buffer, 'Priority Files (${priorityNames.length})', priorityNames);
diff --git a/pkg/analysis_server/lib/src/status/validator.dart b/pkg/analysis_server/lib/src/status/validator.dart
index 10dc8ac..b153c29 100644
--- a/pkg/analysis_server/lib/src/status/validator.dart
+++ b/pkg/analysis_server/lib/src/status/validator.dart
@@ -24,6 +24,7 @@
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/model.dart';
 import 'package:html/dom.dart' as html;
+import 'package:analyzer/src/dart/element/element.dart';
 
 /**
  * A class used to compare two element models for equality.
@@ -1193,11 +1194,11 @@
     //
     // 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 +1217,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 +1309,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/starter.dart b/pkg/analysis_server/lib/starter.dart
index 42c9861..bb2f0f6 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -6,6 +6,7 @@
 
 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/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 0d59bdf..d225c90 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -72,6 +72,8 @@
 
   UriResolver packageResolver = null;
 
+  UriResolver embeddedUriResolver = null;
+
   String projPath = '/my/proj';
 
   AnalysisError missing_return =
@@ -127,16 +129,20 @@
     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,
+        InstrumentationService.NULL_SERVICE);
     callbacks = new TestContextManagerCallbacks(resourceProvider);
     manager.callbacks = callbacks;
     resourceProvider.newFolder(projPath);
@@ -280,6 +286,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]);
@@ -1292,8 +1351,8 @@
   exclude:
     - 'example'
 ''');
-    manager.setRoots(
-        <String>[project, example], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[project, example], <String>[], <String, String>{});
     // verify
     {
       ContextInfo rootInfo = manager.rootInfo;
@@ -1356,8 +1415,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;
@@ -1384,8 +1443,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;
@@ -1408,8 +1467,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;
@@ -1555,8 +1614,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]);
@@ -1603,8 +1662,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]);
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/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/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 2b0db03..dfb6a60 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -2127,6 +2127,28 @@
 ''');
   }
 
+  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 {
+  var f;
+}
+''');
+  }
+
   test_createMissingOverrides_functionTypeAlias() async {
     resolveTestUnit('''
 typedef int Binary(int left, int right);
@@ -3760,6 +3782,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() {
@@ -3884,6 +3932,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 {
@@ -4406,6 +4459,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 {
@@ -4436,19 +4517,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)']);
   }
 
@@ -4482,18 +4563,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 {
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/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 2190ee1..b4e9f46 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -116,6 +116,7 @@
         DirectoryBasedDartSdk.defaultSdk,
         InstrumentationService.NULL_SERVICE,
         serverPlugin,
+        null,
         null);
   }
 }
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/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 1237fd1..31dd785 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -2,6 +2,38 @@
 // for 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/element/element.dart';
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index 7e2848e..0cdb170 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -2,6 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/**
+ * 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';
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index bb52303d..c7e971a 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -2,6 +2,38 @@
 // for 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';
@@ -744,7 +776,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-abstract class ElementAnnotation {
+abstract class ElementAnnotation implements ConstantEvaluationTarget {
   /**
    * An empty list of annotations.
    */
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 9f079a9..f49c170 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -2,6 +2,24 @@
 // for 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';
@@ -166,6 +184,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.
@@ -173,10 +197,10 @@
   List<DartType> get normalParameterTypes;
 
   /**
-   * The names of the required positional parameters of this type of function,
+   * The names of the optional positional parameters of this type of function,
    * in the order that the parameters appear.
    */
-  List<String> get normalParameterNames;
+  List<String> get optionalParameterNames;
 
   /**
    * Return a map from the names of optional (positional) parameters to the
@@ -188,12 +212,6 @@
   List<DartType> get optionalParameterTypes;
 
   /**
-   * 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 list containing the parameters elements of this type of function.
    * The parameter types are in the same order as they appear in the declaration
    * of the function.
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/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/analyzer/lib/source/embedder.dart b/pkg/analyzer/lib/source/embedder.dart
index af30e76..bbc6659 100644
--- a/pkg/analyzer/lib/source/embedder.dart
+++ b/pkg/analyzer/lib/source/embedder.dart
@@ -19,151 +19,10 @@
 import 'package:yaml/yaml.dart';
 
 const String _DART_COLON_PREFIX = 'dart:';
+const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs';
 
-/// 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.
-class EmbedderYamlLocator {
-  static const String EMBEDDER_FILE_NAME = '_embedder.yaml';
-
-  // Map from package's library directory to the parsed
-  // YamlMap.
-  final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>();
-
-  EmbedderYamlLocator(Map<String, List<Folder>> packageMap) {
-    if (packageMap != null) {
-      refresh(packageMap);
-    }
-  }
-
-  void refresh(Map<String, List<Folder>> packageMap) {
-    // Clear existing.
-    embedderYamls.clear();
-    if (packageMap == null) {
-      return;
-    }
-    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) {
-    YamlNode yaml;
-    try {
-      yaml = loadYaml(embedderYaml);
-    } catch (_) {
-      // TODO(pquitslund): Notify developer that something is wrong with the
-      // _embedder.yaml file in libDir.
-      return;
-    }
-    if (yaml == null) {
-      // TODO(pquitslund): Notify developer that something is wrong with the
-      // _embedder.yaml file in libDir.
-      return;
-    }
-    if (yaml is! YamlMap) {
-      // TODO(pquitslund): Notify developer that something is wrong with the
-      // _embedder.yaml file in libDir.
-      return;
-    }
-    embedderYamls[libDir] = yaml;
-  }
-
-  /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string.
-  /// Returns null if the file doesn't exist.
-  String _readEmbedderYaml(Folder libDir) {
-    File file = libDir.getChild(EMBEDDER_FILE_NAME);
-    try {
-      return file.readAsStringSync();
-    } on FileSystemException {
-      // File can't be read.
-      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);
-  }
-
-  void _processEmbedderYaml(Folder libDir, YamlMap map) {
-    YamlNode embedded_libs = map['embedded_libs'];
-    if (embedded_libs == null) {
-      return;
-    }
-    if (embedded_libs is! YamlMap) {
-      return;
-    }
-    (embedded_libs as YamlMap)
-        .forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
-  }
-
-  /// 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);
-  }
-
-  /// 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;
-  }
-}
+/// 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
@@ -229,7 +88,8 @@
           continue;
         }
         var relPath = filePath
-            .substring(prefix.length).replaceAll(JavaFile.separator, '/');
+            .substring(prefix.length)
+            .replaceAll(JavaFile.separator, '/');
         path = '$_DART_COLON_PREFIX${library.shortName}/$relPath';
         break;
       }
@@ -291,3 +151,148 @@
     }
   }
 }
+
+/// 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.
+class EmbedderYamlLocator {
+  static const String EMBEDDER_FILE_NAME = '_embedder.yaml';
+
+  // Map from package's library directory to the parsed
+  // YamlMap.
+  final Map<Folder, YamlMap> embedderYamls = new HashMap<Folder, YamlMap>();
+
+  EmbedderYamlLocator(Map<String, List<Folder>> packageMap) {
+    if (packageMap != null) {
+      refresh(packageMap);
+    }
+  }
+
+  /// 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();
+    if (packageMap == null) {
+      return;
+    }
+    packageMap.forEach(_processPackage);
+  }
+
+  /// Given the yaml for an embedder ([embedderYaml]) and a folder
+  /// ([libDir]), setup the uri mapping.
+  void _processEmbedderYaml(Folder libDir, String embedderYaml) {
+    YamlNode yaml;
+    try {
+      yaml = loadYaml(embedderYaml);
+    } catch (_) {
+      // TODO(pquitslund): Notify developer that something is wrong with the
+      // _embedder.yaml file in libDir.
+      return;
+    }
+    if (yaml == null) {
+      // TODO(pquitslund): Notify developer that something is wrong with the
+      // _embedder.yaml file in libDir.
+      return;
+    }
+    if (yaml is! YamlMap) {
+      // TODO(pquitslund): Notify developer that something is wrong with the
+      // _embedder.yaml file in libDir.
+      return;
+    }
+    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.
+  String _readEmbedderYaml(Folder libDir) {
+    File file = libDir.getChild(EMBEDDER_FILE_NAME);
+    try {
+      return file.readAsStringSync();
+    } on FileSystemException {
+      // File can't be read.
+      return null;
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 09c35ac..d0d131d 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -1875,6 +1875,7 @@
       PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
           typeProvider,
           unitSource,
+          _cache,
           sourceEntry,
           unitEntry,
           oldUnit,
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 26e3b76..342d4a6 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -1957,6 +1957,14 @@
       _name != null ? (_name.staticElement as ClassElement) : null;
 
   @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (abstractKeyword != null) {
+      return abstractKeyword;
+    }
+    return typedefKeyword;
+  }
+
+  @override
   ImplementsClause get implementsClause => _implementsClause;
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 1a21746..33bc821 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -29,12 +29,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 +84,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 +103,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,7 +213,9 @@
   }
 
   @override
-  ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) => new ClassTypeAlias(
+  ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) {
+    cloneToken(node.abstractKeyword);
+    return new ClassTypeAlias(
       cloneNode(node.documentationComment),
       cloneNodeList(node.metadata),
       cloneToken(node.typedefKeyword),
@@ -197,6 +227,7 @@
       cloneNode(node.withClause),
       cloneNode(node.implementsClause),
       cloneToken(node.semicolon));
+  }
 
   @override
   Comment visitComment(Comment node) {
@@ -216,12 +247,16 @@
 
   @override
   CompilationUnit visitCompilationUnit(CompilationUnit node) {
+    ScriptTag scriptTag = cloneNode(node.scriptTag);
+    List<Directive> directives = cloneNodeList(node.directives);
+    List<CompilationUnitMember> declarations = cloneNodeList(node.declarations);
+    Token endToken = cloneToken(node.endToken);
+    Token beginToken = scriptTag?.beginToken ??
+        (directives.isEmpty ? null : directives.first.beginToken) ??
+        (declarations.isEmpty ? null : declarations.first.beginToken) ??
+        endToken;
     CompilationUnit clone = new CompilationUnit(
-        cloneToken(node.beginToken),
-        cloneNode(node.scriptTag),
-        cloneNodeList(node.directives),
-        cloneNodeList(node.declarations),
-        cloneToken(node.endToken));
+        beginToken, scriptTag, directives, declarations, endToken);
     clone.lineInfo = node.lineInfo;
     return clone;
   }
@@ -887,6 +922,54 @@
       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;
+    }
+    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) {
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index df8f470..7422233 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -39,10 +39,10 @@
         return null;
       }
       ElementHolder holder = new ElementHolder();
-      ElementBuilder builder = new ElementBuilder(holder);
-      unit.accept(builder);
       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;
@@ -167,6 +167,7 @@
       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;
@@ -207,6 +208,7 @@
           explicitlyImportsCore = true;
         }
         ImportElementImpl importElement = new ImportElementImpl(node.offset);
+        importElement.metadata = _getElementAnnotations(node.metadata);
         StringLiteral uriLiteral = node.uri;
         if (uriLiteral != null) {
           importElement.uriOffset = uriLiteral.offset;
@@ -243,6 +245,32 @@
     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();
+  }
+
   /**
    * If the given [node] has a documentation comment, remember its content
    * and range into the given [element].
@@ -277,6 +305,12 @@
  */
 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;
@@ -310,7 +344,7 @@
    *
    * @param initialHolder the element holder associated with the compilation unit being built
    */
-  ElementBuilder(ElementHolder initialHolder) {
+  ElementBuilder(ElementHolder initialHolder, this.compilationUnitElement) {
     _currentHolder = initialHolder;
   }
 
@@ -374,6 +408,7 @@
     }
     SimpleIdentifier className = node.name;
     ClassElementImpl element = new ClassElementImpl.forNode(className);
+    element.metadata = _createElementAnnotations(node.metadata);
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
     InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
@@ -422,6 +457,7 @@
     _visitChildren(holder, node);
     SimpleIdentifier className = node.name;
     ClassElementImpl element = new ClassElementImpl.forNode(className);
+    element.metadata = _createElementAnnotations(node.metadata);
     element.abstract = node.abstractKeyword != null;
     element.mixinApplication = true;
     List<TypeParameterElement> typeParameters = holder.typeParameters;
@@ -451,6 +487,7 @@
     SimpleIdentifier constructorName = node.name;
     ConstructorElementImpl element =
         new ConstructorElementImpl.forNode(constructorName);
+    element.metadata = _createElementAnnotations(node.metadata);
     _setDoc(element, node);
     if (node.externalKeyword != null) {
       element.external = true;
@@ -491,6 +528,7 @@
     SimpleIdentifier variableName = node.identifier;
     LocalVariableElementImpl element =
         new LocalVariableElementImpl.forNode(variableName);
+    element.metadata = _createElementAnnotations(node.metadata);
     ForEachStatement statement = node.parent as ForEachStatement;
     int declarationEnd = node.offset + node.length;
     int statementEnd = statement.offset + statement.length;
@@ -512,14 +550,15 @@
     SimpleIdentifier parameterName = normalParameter.identifier;
     ParameterElementImpl parameter;
     if (normalParameter is FieldFormalParameter) {
-      parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
+      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(parameterName);
+      parameter = new DefaultParameterElementImpl.forNode(parameterName);
     }
     parameter.const3 = node.isConst;
     parameter.final2 = node.isFinal;
@@ -555,6 +594,7 @@
   Object visitEnumDeclaration(EnumDeclaration node) {
     SimpleIdentifier enumName = node.name;
     ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
+    enumElement.metadata = _createElementAnnotations(node.metadata);
     enumElement.enum2 = true;
     _setDoc(enumElement, node);
     InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
@@ -570,6 +610,12 @@
   }
 
   @override
+  Object visitExportDirective(ExportDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitExportDirective(node);
+  }
+
+  @override
   Object visitFieldDeclaration(FieldDeclaration node) {
     bool wasInField = _inFieldContext;
     _inFieldContext = true;
@@ -588,7 +634,7 @@
       FieldElement field =
           _fieldMap == null ? null : _fieldMap[parameterName.name];
       FieldFormalParameterElementImpl parameter =
-          new FieldFormalParameterElementImpl(parameterName);
+          new FieldFormalParameterElementImpl.forNode(parameterName);
       parameter.const3 = node.isConst;
       parameter.final2 = node.isFinal;
       parameter.parameterKind = node.kind;
@@ -605,6 +651,7 @@
     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();
@@ -629,6 +676,7 @@
         SimpleIdentifier functionName = node.name;
         FunctionElementImpl element =
             new FunctionElementImpl.forNode(functionName);
+        element.metadata = _createElementAnnotations(node.metadata);
         _setDoc(element, node);
         if (node.externalKeyword != null) {
           element.external = true;
@@ -676,6 +724,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          getter.metadata = _createElementAnnotations(node.metadata);
           _setDoc(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
@@ -702,6 +751,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          setter.metadata = _createElementAnnotations(node.metadata);
           _setDoc(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
@@ -792,6 +842,7 @@
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     FunctionTypeAliasElementImpl element =
         new FunctionTypeAliasElementImpl.forNode(aliasName);
+    element.metadata = _createElementAnnotations(node.metadata);
     _setDoc(element, node);
     element.parameters = parameters;
     element.typeParameters = typeParameters;
@@ -821,6 +872,7 @@
     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();
@@ -828,6 +880,12 @@
   }
 
   @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) {
@@ -841,6 +899,12 @@
   }
 
   @override
+  Object visitLibraryDirective(LibraryDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitLibraryDirective(node);
+  }
+
+  @override
   Object visitMethodDeclaration(MethodDeclaration node) {
     try {
       ElementHolder holder = new ElementHolder();
@@ -863,6 +927,7 @@
         }
         MethodElementImpl element =
             new MethodElementImpl(nameOfMethod, methodName.offset);
+        element.metadata = _createElementAnnotations(node.metadata);
         _setDoc(element, node);
         element.abstract = node.isAbstract;
         if (node.externalKeyword != null) {
@@ -900,6 +965,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          getter.metadata = _createElementAnnotations(node.metadata);
           _setDoc(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
@@ -926,6 +992,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          setter.metadata = _createElementAnnotations(node.metadata);
           _setDoc(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
@@ -992,6 +1059,12 @@
   }
 
   @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;
@@ -1007,7 +1080,10 @@
       _currentHolder.addParameter(parameter);
       parameterName.staticElement = parameter;
     }
-    return super.visitSimpleFormalParameter(node);
+    super.visitSimpleFormalParameter(node);
+    (node.element as ElementImpl).metadata =
+        _createElementAnnotations(node.metadata);
+    return null;
   }
 
   @override
@@ -1037,6 +1113,7 @@
     SimpleIdentifier parameterName = node.name;
     TypeParameterElementImpl typeParameter =
         new TypeParameterElementImpl.forNode(parameterName);
+    typeParameter.metadata = _createElementAnnotations(node.metadata);
     TypeParameterTypeImpl typeParameterType =
         new TypeParameterTypeImpl(typeParameter);
     typeParameter.type = typeParameterType;
@@ -1153,6 +1230,26 @@
     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) {
+      (variableDeclaration.element as ElementImpl).metadata =
+          elementAnnotations;
+    }
+    return null;
+  }
+
   /**
    * Build the table mapping field names to field elements for the fields defined in the current
    * class.
@@ -1186,6 +1283,23 @@
   }
 
   /**
+   * 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.
    *
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 1ae2e9d..74c0bba 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -16,7 +16,7 @@
 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/resolver.dart';
@@ -1460,9 +1460,17 @@
   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;
@@ -1487,9 +1495,16 @@
   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;
@@ -1568,7 +1583,18 @@
    * The element representing the field, variable, or constructor being used as
    * an annotation.
    */
-  final Element element;
+  Element element;
+
+  /**
+   * The compliation 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
@@ -1578,16 +1604,18 @@
   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;
 
   @override
+  AnalysisContext get context => compilationUnit.library.context;
+
+  @override
   bool get isDeprecated {
     if (element != null) {
       LibraryElement library = element.library;
@@ -1635,6 +1663,14 @@
     return false;
   }
 
+  /**
+   * Get the library containing this annotation.
+   */
+  Source get librarySource => compilationUnit.librarySource;
+
+  @override
+  Source get source => compilationUnit.source;
+
   @override
   String toString() => '@$element';
 }
@@ -1765,13 +1801,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;
   }
@@ -2524,16 +2554,17 @@
   FieldElement field;
 
   /**
-   * Initialize a newly created parameter element to have the given [name].
+   * Initialize a newly created parameter element to have the given [name] and
+   * [nameOffset].
    */
-  FieldFormalParameterElementImpl(Identifier name) : super.forNode(name);
+  FieldFormalParameterElementImpl(String name, int nameOffset)
+      : super(name, nameOffset);
 
   /**
-   * Initialize a newly created parameter element to have the given [name] and
-   * [offset].
+   * Initialize a newly created parameter element to have the given [name].
    */
-  FieldFormalParameterElementImpl.forNameAndOffset(String name, int nameOffset)
-      : super(name, nameOffset);
+  FieldFormalParameterElementImpl.forNode(Identifier name)
+      : super.forNode(name);
 
   @override
   bool get isInitializingFormal => true;
@@ -4095,7 +4126,7 @@
 
   /**
    * Initialize a newly created parameter element to have the given [name] and
-   * [offset].
+   * [nameOffset].
    */
   ParameterElementImpl(String name, int nameOffset) : super(name, nameOffset);
 
@@ -4107,8 +4138,8 @@
   /**
    * Creates a synthetic parameter with [name], [type] and [kind].
    */
-  factory ParameterElementImpl.synthetic(String name, DartType type,
-      ParameterKind kind) {
+  factory ParameterElementImpl.synthetic(
+      String name, DartType type, ParameterKind kind) {
     ParameterElementImpl element = new ParameterElementImpl(name, -1);
     element.type = type;
     element.synthetic = true;
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index bc073d8..57cbcb9 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -12,7 +12,7 @@
 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';
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 0383846..1b9c290 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -11,7 +11,7 @@
 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';
@@ -29,12 +29,7 @@
   /**
    * 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.
@@ -136,12 +131,7 @@
   /**
    * 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.
@@ -155,7 +145,7 @@
    * Constructor used by [CircularTypeImpl].
    */
   DynamicTypeImpl._circular()
-      : super(_INSTANCE.element, Keyword.DYNAMIC.syntax);
+      : super(instance.element, Keyword.DYNAMIC.syntax);
 
   @override
   int get hashCode => 1;
@@ -378,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;
   }
 
   /**
@@ -425,26 +398,10 @@
 
   @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;
   }
 
@@ -458,26 +415,10 @@
 
   @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;
   }
 
@@ -776,225 +717,135 @@
       [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.
+    bool relation = _trivialFunctionRelation(type);
+    if (relation != null) {
+      return relation;
+    }
 
-    // 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 structuralCompare(this, type,
+        (TypeImpl t, TypeImpl s) => t.isMoreSpecificThan(s, withDynamic));
   }
 
   @override
   bool isSubtypeOf(DartType type) {
-    // trivial base cases
-    if (type == null) {
+    bool relation = _trivialFunctionRelation(type);
+    if (relation != null) {
+      return relation;
+    }
+
+    return structuralCompare(
+        this, type, (TypeImpl t, TypeImpl s) => t.isAssignableTo(s));
+  }
+
+  /**
+   * Tests if [other] meets any of the easy relation cases for [isSubtypeOf]
+   * and [isMoreSpecificThan].
+   *
+   * Returns `true` if the relation is known to hold, `false` if it isn't, or
+   * `null` if it's unknown and a deeper structural comparison is needed.
+   */
+  bool _trivialFunctionRelation(DartType other) {
+    // Trivial base cases.
+    if (other == null) {
       return false;
-    } else if (identical(this, type) ||
-        type.isDynamic ||
-        type.isDartCoreFunction ||
-        type.isObject) {
+    } else if (identical(this, other) ||
+        other.isDynamic ||
+        other.isDartCoreFunction ||
+        other.isObject) {
       return true;
-    } else if (type is! FunctionType) {
+    } else if (other is! FunctionType) {
       return false;
-    } else if (this == type) {
+    } else if (this == other) {
       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;
+
+    return null;
+  }
+
+  /**
+   * 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 structuralCompare(FunctionType t, FunctionType s,
+      bool parameterRelation(DartType t, DartType s),
+      [bool returnRelation(DartType t, DartType s)]) {
+    // Test the return types.
+    returnRelation ??= parameterRelation;
     DartType sRetType = s.returnType;
-    return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo(sRetType);
+    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;
   }
 
   @override
@@ -1109,6 +960,33 @@
     }
     return true;
   }
+
+  /**
+   * 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);
+      }
+    }
+  }
 }
 
 /**
@@ -1134,7 +1012,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)
@@ -2472,12 +2350,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.
@@ -2547,17 +2420,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/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 1f5635c..7123029 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -13,6 +13,8 @@
 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/element_handle.dart'
+    show ConstructorElementHandle;
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, RecordingErrorListener;
@@ -28,6 +30,16 @@
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/task/dart.dart';
 
+ConstructorElementImpl _getConstructorImpl(ConstructorElement constructor) {
+  if (constructor is ConstructorElementHandle) {
+    constructor = (constructor as ConstructorElementHandle).actualElement;
+  }
+  while (constructor is ConstructorMember) {
+    constructor = (constructor as ConstructorMember).baseElement;
+  }
+  return constructor;
+}
+
 /**
  * Callback used by [ReferenceFinder] to report that a dependency was found.
  */
@@ -237,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;
@@ -339,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;
@@ -384,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 {
@@ -454,14 +456,10 @@
   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);
@@ -473,8 +471,7 @@
             getConstRedirectedConstructor(constant);
         if (redirectedConstructor != null) {
           ConstructorElement redirectedConstructorBase =
-              ConstantEvaluationEngine
-                  ._getConstructorBase(redirectedConstructor);
+              _getConstructorImpl(redirectedConstructor);
           callback(redirectedConstructorBase);
           return;
         } else if (constant.isFactory) {
@@ -502,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);
             }
@@ -522,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);
@@ -549,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 {
@@ -603,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
@@ -693,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;
@@ -911,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
@@ -1012,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';
 }
 
 /**
@@ -1310,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;
   }
 
@@ -1372,14 +1327,6 @@
     }
     return null;
   }
-
-  AnalysisContext _getOwningContext() {
-    if (context is InternalAnalysisContext) {
-      InternalAnalysisContext internalContext = context;
-      return internalContext.getContextFor(librarySource);
-    }
-    return context;
-  }
 }
 
 /**
@@ -5213,8 +5160,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);
       }
@@ -5236,8 +5182,7 @@
   Object visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
     super.visitRedirectingConstructorInvocation(node);
-    ConstructorElement target =
-        ConstantEvaluationEngine._getConstructorBase(node.staticElement);
+    ConstructorElement target = _getConstructorImpl(node.staticElement);
     if (target != null) {
       _callback(target);
     }
@@ -5259,8 +5204,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_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 5bf9630..b5cddef 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -205,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;
   }
 
@@ -336,7 +336,7 @@
           }
         }
       }
-      setMetadata(constructorElement, node);
+      resolveMetadata(node);
     }
     return null;
   }
@@ -392,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;
   }
 
@@ -410,20 +410,20 @@
       // 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;
   }
 
@@ -455,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;
   }
 
@@ -484,7 +484,7 @@
       if (library != null) {
         _resolveCombinators(library, node.combinators);
       }
-      setMetadata(importElement, node);
+      resolveMetadata(node);
     }
     return null;
   }
@@ -577,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;
   }
 
@@ -821,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;
   }
 
@@ -1029,7 +1023,7 @@
 
   @override
   Object visitSimpleFormalParameter(SimpleFormalParameter node) {
-    _setMetadataForParameter(node.element, node);
+    _resolveMetadataForParameter(node.element, node);
     return null;
   }
 
@@ -1183,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;
   }
 
@@ -2217,6 +2211,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').
@@ -2433,23 +2436,6 @@
   }
 
   /**
-   * 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;
-    }
-  }
-
-  /**
    * 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.
    */
@@ -2476,48 +2462,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);
       }
     }
   }
@@ -2568,6 +2527,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;
+    }
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index ac73a8a..4cb96b4 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -4642,6 +4642,7 @@
       stringMembersArrayListSet.add(newStrMember);
     }
     List<String> stringMembersArray = new List.from(stringMembersArrayListSet);
+    stringMembersArray.sort();
     AnalysisErrorWithProperties analysisError;
     if (stringMembersArray.length == 1) {
       analysisError = _errorReporter.newErrorWithProperties(
diff --git a/pkg/analyzer/lib/src/generated/generated/shared_messages.dart b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
index 2c1465c..5faa0c0 100644
--- a/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
+++ b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
@@ -9,9 +9,14 @@
 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 AnalysisOptionsErrorCode exampleMessage = const AnalysisOptionsErrorCode(
-    'exampleMessage',
-    "{2} {1} {0}",
-    "an explanation on how to fix things");  // Generated. Don't edit.
+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.
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index d810b92..b19b4b1 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -909,8 +909,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) ||
@@ -924,6 +922,7 @@
         isByTask(PropagateVariableTypesInUnitTask.DESCRIPTOR) ||
         isByTask(PropagateVariableTypeTask.DESCRIPTOR) ||
         isByTask(ScanDartTask.DESCRIPTOR) ||
+        isByTask(ResolveConstantExpressionTask.DESCRIPTOR) ||
         isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) ||
         isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
         isByTask(ResolveLibraryTask.DESCRIPTOR) ||
@@ -953,42 +952,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.
@@ -1008,14 +1009,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;
@@ -1026,20 +1027,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.
@@ -1080,7 +1084,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);
@@ -1280,8 +1284,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');
@@ -1359,16 +1363,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;
@@ -1385,6 +1390,7 @@
   PoorMansIncrementalResolver(
       this._typeProvider,
       this._unitSource,
+      this._cache,
       this._sourceEntry,
       this._unitEntry,
       this._oldUnit,
@@ -1445,6 +1451,7 @@
             _shiftTokens(firstPair.oldToken);
             {
               IncrementalResolver incrementalResolver = new IncrementalResolver(
+                  _cache,
                   _sourceEntry,
                   _unitEntry,
                   _unitElement,
@@ -1571,6 +1578,7 @@
         }
         // perform incremental resolution
         IncrementalResolver incrementalResolver = new IncrementalResolver(
+            _cache,
             _sourceEntry,
             _unitEntry,
             _unitElement,
@@ -1649,6 +1657,7 @@
     NodeReplacer.replace(oldComment, newComment);
     // update elements
     IncrementalResolver incrementalResolver = new IncrementalResolver(
+        _cache,
         _sourceEntry,
         _unitEntry,
         _unitElement,
@@ -2037,36 +2046,78 @@
  */
 class _DeclarationMismatchException {}
 
+/**
+ * Adjusts the location of each Element that moved.
+ *
+ * Since operator== and hashCode of an Element are based
+ * on the element location, we also need to remove each
+ * moved element from the cache to avoid a memory leak.
+ */
 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) {
+      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/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index acd2337..fd684ed 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -250,7 +250,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";
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 4f249be..7a39b04 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -14,6 +14,8 @@
 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';
@@ -4169,7 +4171,7 @@
     return false;
   }
 
-  bool _isLikelyParameterList() {
+  bool _isLikelyArgumentList() {
     if (_matches(TokenType.OPEN_PAREN)) {
       return true;
     }
@@ -4237,7 +4239,7 @@
     if (!parseGenericMethods) {
       return false;
     }
-    Token token = _skipTypeArgumentList(_peek());
+    Token token = _skipTypeParameterList(_peek());
     return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
   }
 
@@ -4457,7 +4459,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) {
@@ -4665,8 +4667,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,
@@ -4694,7 +4696,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;
@@ -7302,7 +7304,7 @@
         _matches(TokenType.OPEN_PAREN) ||
         (parseGenericMethods && _matches(TokenType.LT))) {
       do {
-        if (_isLikelyParameterList()) {
+        if (_isLikelyArgumentList()) {
           TypeArgumentList typeArguments = _parseOptionalTypeArguments();
           ArgumentList argumentList = parseArgumentList();
           if (operand is PropertyAccess) {
@@ -9410,15 +9412,12 @@
       'CONST_CLASS', "Classes cannot be declared to be 'const'");
 
   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_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',
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 612912d..ecfe204 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -15,6 +15,7 @@
 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/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';
@@ -2030,50 +2031,59 @@
 }
 
 /**
- * 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 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) {
+    ElementGatherer gatherer = new ElementGatherer();
+    element.accept(gatherer);
+    _expectedElements = gatherer.elements;
     _enclosingUnit = element;
+    _expectedElements.remove(element);
     unit.element = element;
     unit.accept(this);
+    _validateResolution();
   }
 
   @override
@@ -2097,7 +2107,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;
     }
@@ -2109,7 +2121,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;
     }
@@ -2122,13 +2136,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;
     }
@@ -2137,8 +2162,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
@@ -2149,11 +2177,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;
@@ -2162,7 +2186,9 @@
     ParameterElement outerParameter = _enclosingParameter;
     try {
       _enclosingParameter = element;
-      return super.visitDefaultFormalParameter(node);
+      super.visitDefaultFormalParameter(node);
+      _resolveMetadata(node.metadata, element);
+      return null;
     } finally {
       _enclosingParameter = outerParameter;
     }
@@ -2176,21 +2202,34 @@
     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(
+      exportElement = _findExport(
+          node,
           library.exports,
           _enclosingUnit.context.sourceFactory
               .resolveUri(_enclosingUnit.source, uri));
       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
@@ -2201,7 +2240,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitFieldFormalParameter(node);
+        super.visitFieldFormalParameter(node);
+        _resolveMetadata(node.metadata, element);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2229,17 +2270,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;
     }
@@ -2248,8 +2300,8 @@
   @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);
       node.element = element;
     }
     ExecutableElement outerExecutable = _enclosingExecutable;
@@ -2268,7 +2320,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;
     }
@@ -2282,7 +2336,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitFunctionTypedFormalParameter(node);
+        super.visitFunctionTypedFormalParameter(node);
+        _resolveMetadata(node.metadata, _enclosingParameter);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2294,16 +2350,19 @@
   @override
   Object visitImportDirective(ImportDirective node) {
     String uri = _getStringValue(node.uri);
+    ImportElement importElement;
     if (uri != null) {
       LibraryElement library = _enclosingUnit.library;
-      ImportElement importElement = _findImport(
+      importElement = _findImport(
+          node,
           library.imports,
           _enclosingUnit.context.sourceFactory
-              .resolveUri(_enclosingUnit.source, uri),
-          node.prefix);
+              .resolveUri(_enclosingUnit.source, uri));
       node.element = importElement;
     }
-    return super.visitImportDirective(node);
+    super.visitImportDirective(node);
+    _resolveMetadata(node.metadata, importElement);
+    return null;
   }
 
   @override
@@ -2317,8 +2376,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
@@ -2329,19 +2391,25 @@
       SimpleIdentifier methodName = node.name;
       String nameOfMethod = methodName.name;
       if (property == null) {
-        _enclosingExecutable = _findWithNameAndOffset(
-            _enclosingClass.methods, nameOfMethod, methodName.offset);
+        _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods,
+            methodName, nameOfMethod, 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, methodName.name + '=', 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;
     }
@@ -2350,12 +2418,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
@@ -2372,7 +2444,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitSimpleFormalParameter(node);
+        super.visitSimpleFormalParameter(node);
+        _resolveMetadata(node.metadata, element);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2399,22 +2473,33 @@
   }
 
   @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);
+    super.visitTypeParameter(node);
+    _resolveMetadata(node.metadata, element);
+    return null;
   }
 
   @override
@@ -2422,11 +2507,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);
@@ -2435,11 +2522,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;
@@ -2448,64 +2531,73 @@
     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) {
+    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] and that has the given [prefix]. Throw an
+   * [ElementMismatchException] if an element corresponding to the identifier
+   * cannot be found.
    */
   ImportElement _findImport(
-      List<ImportElement> imports, Source source, SimpleIdentifier prefix) {
+      ImportDirective node, List<ImportElement> imports, Source source) {
+    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) {
@@ -2519,52 +2611,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) {
@@ -2578,32 +2694,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) {
@@ -2611,6 +2717,61 @@
     }
     return literal.stringValue;
   }
+
+  /**
+   * 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.
+   */
+  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) {
+      buffer.write(separator);
+      buffer.write(parent.runtimeType.toString());
+      separator = ', ';
+      parent = parent.parent;
+    }
+    throw new ElementMismatchException(buffer.toString());
+  }
+
+  /**
+   * If [element] is not `null`, associate each [Annotation] in [astMetadata]
+   * with the corresponding [ElementAnnotation] in [element.metadata].
+   *
+   * 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 _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];
+      }
+    }
+  }
+
+  /**
+   * Throw an exception if there are non-synthetic elements in the element model
+   * that were not associated with an AST node.
+   */
+  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());
+    }
+  }
 }
 
 /**
@@ -2974,6 +3135,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.
@@ -7277,6 +7447,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;
   }
 
@@ -7724,7 +7902,7 @@
     //
     if (node.metadata != null) {
       node.metadata.accept(this);
-      ElementResolver.setMetadata(node.element, node);
+      ElementResolver.resolveMetadata(node);
     }
     //
     // Continue the enum resolution.
@@ -10864,8 +11042,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.
@@ -10882,12 +11060,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;
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 49ea3ba..3fc2113 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -265,7 +265,12 @@
       : super(type, value, offset);
 
   @override
-  CommentToken copy() => new DocumentationCommentToken(type, _value, offset);
+  CommentToken copy() {
+    DocumentationCommentToken copy =
+        new DocumentationCommentToken(type, _value, offset);
+    references.forEach((ref) => copy.references.add(ref.copy()));
+    return copy;
+  }
 }
 
 /**
@@ -2580,7 +2585,8 @@
    * operators can have an effect because evaluation of the right-hand operand
    * is conditional.
    */
-  bool get isAssociativeOperator => this == AMPERSAND ||
+  bool get isAssociativeOperator =>
+      this == AMPERSAND ||
       this == AMPERSAND_AMPERSAND ||
       this == BAR ||
       this == BAR_BAR ||
@@ -2608,7 +2614,8 @@
   /**
    * Return `true` if this token type represents an operator.
    */
-  bool get isOperator => _tokenClass != TokenClass.NO_CLASS &&
+  bool get isOperator =>
+      _tokenClass != TokenClass.NO_CLASS &&
       this != OPEN_PAREN &&
       this != OPEN_SQUARE_BRACKET &&
       this != PERIOD;
@@ -2640,7 +2647,8 @@
    * Return `true` if this token type represents an operator that can be defined
    * by users.
    */
-  bool get isUserDefinableOperator => identical(lexeme, "==") ||
+  bool get isUserDefinableOperator =>
+      identical(lexeme, "==") ||
       identical(lexeme, "~") ||
       identical(lexeme, "[]") ||
       identical(lexeme, "[]=") ||
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index a50eb95..8cdb8f2 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -19,7 +19,7 @@
 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 SdkBundle;
 import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:path/path.dart' as pathos;
 
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index c9d1b45..8fcdad3 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -379,9 +379,7 @@
   }
 
   @override
-  String get encoding {
-    throw new UnsupportedOperationException('$fullName does not exist.');
-  }
+  String get encoding => uri.toString();
 
   @override
   int get hashCode => fullName.hashCode;
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index a2f01f1..7e697eb 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -35,7 +35,9 @@
       new Annotation(
           TokenFactory.tokenFromType(TokenType.AT),
           name,
-          TokenFactory.tokenFromType(TokenType.PERIOD),
+          constructorName == null
+              ? null
+              : TokenFactory.tokenFromType(TokenType.PERIOD),
           constructorName,
           arguments);
 
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 282b52e..72d8acf 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -118,6 +118,9 @@
     constructor.returnType = type;
     constructor.enclosingElement = definingClass;
     constructor.type = new FunctionTypeImpl(constructor);
+    if (!constructor.isSynthetic) {
+      constructor.constantInitializers = <ConstructorInitializer>[];
+    }
     return constructor;
   }
 
@@ -234,7 +237,7 @@
 
   static FieldFormalParameterElementImpl fieldFormalParameter(
           Identifier name) =>
-      new FieldFormalParameterElementImpl(name);
+      new FieldFormalParameterElementImpl.forNode(name);
 
   static FunctionElementImpl functionElement(String functionName) =>
       functionElement4(functionName, null, null, null, null);
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 4bf5cc9..b3aaea8 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -192,12 +192,20 @@
     if (_deprecatedType == null) {
       ClassElementImpl deprecatedElement =
           ElementFactory.classElement2("Deprecated");
+      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.constantInitializers = <ConstructorInitializer>[
-        AstFactory.constructorFieldInitializer(
-            true, 'expires', AstFactory.identifier3('expires'))
-      ];
+      (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;
     }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index fb48bbe..16e0817 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -16,7 +16,6 @@
 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.
@@ -313,6 +312,7 @@
 
   /**
    * 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).
@@ -327,83 +327,13 @@
         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;
+    return FunctionTypeImpl.structuralCompare(
+        f1,
+        f2,
+        (DartType t1, DartType t2) =>
+            _isSubtypeOf(t2, t1, null, dynamicIsBottom: fuzzyArrows),
+        isSubtypeOf);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/utilities_collection.dart b/pkg/analyzer/lib/src/generated/utilities_collection.dart
index 6a71b97..453ee37 100644
--- a/pkg/analyzer/lib/src/generated/utilities_collection.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_collection.dart
@@ -466,25 +466,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/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index c2ad576..545064a 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -223,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);
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 46ef9fa..8f2fe1e 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -7,515 +7,84 @@
 
 library analyzer.src.summary.format;
 
-import 'base.dart' as base;
 import 'flat_buffers.dart' as fb;
+import 'idl.dart' as idl;
 
-/**
- * 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 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
-}
-
-class _ReferenceKindReader extends fb.Reader<ReferenceKind> {
+class _ReferenceKindReader extends fb.Reader<idl.ReferenceKind> {
   const _ReferenceKindReader() : super();
 
   @override
   int get size => 4;
 
   @override
-  ReferenceKind read(fb.BufferPointer bp) {
+  idl.ReferenceKind read(fb.BufferPointer bp) {
     int index = const fb.Uint32Reader().read(bp);
-    return ReferenceKind.values[index];
+    return idl.ReferenceKind.values[index];
   }
 }
 
-/**
- * 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,
-
-  /**
-   * 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
-}
-
-class _UnlinkedConstOperationReader extends fb.Reader<UnlinkedConstOperation> {
+class _UnlinkedConstOperationReader extends fb.Reader<idl.UnlinkedConstOperation> {
   const _UnlinkedConstOperationReader() : super();
 
   @override
   int get size => 4;
 
   @override
-  UnlinkedConstOperation read(fb.BufferPointer bp) {
+  idl.UnlinkedConstOperation read(fb.BufferPointer bp) {
     int index = const fb.Uint32Reader().read(bp);
-    return UnlinkedConstOperation.values[index];
+    return idl.UnlinkedConstOperation.values[index];
   }
 }
 
-/**
- * Enum used to indicate the kind of an executable.
- */
-enum UnlinkedExecutableKind {
-  /**
-   * Executable is a function or method.
-   */
-  functionOrMethod,
+class _UnlinkedConstructorInitializerKindReader extends fb.Reader<idl.UnlinkedConstructorInitializerKind> {
+  const _UnlinkedConstructorInitializerKindReader() : super();
 
-  /**
-   * Executable is a getter.
-   */
-  getter,
+  @override
+  int get size => 4;
 
-  /**
-   * Executable is a setter.
-   */
-  setter,
-
-  /**
-   * Executable is a constructor.
-   */
-  constructor
+  @override
+  idl.UnlinkedConstructorInitializerKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint32Reader().read(bp);
+    return idl.UnlinkedConstructorInitializerKind.values[index];
+  }
 }
 
-class _UnlinkedExecutableKindReader extends fb.Reader<UnlinkedExecutableKind> {
+class _UnlinkedExecutableKindReader extends fb.Reader<idl.UnlinkedExecutableKind> {
   const _UnlinkedExecutableKindReader() : super();
 
   @override
   int get size => 4;
 
   @override
-  UnlinkedExecutableKind read(fb.BufferPointer bp) {
+  idl.UnlinkedExecutableKind read(fb.BufferPointer bp) {
     int index = const fb.Uint32Reader().read(bp);
-    return UnlinkedExecutableKind.values[index];
+    return idl.UnlinkedExecutableKind.values[index];
   }
 }
 
-/**
- * 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
-}
-
-class _UnlinkedParamKindReader extends fb.Reader<UnlinkedParamKind> {
+class _UnlinkedParamKindReader extends fb.Reader<idl.UnlinkedParamKind> {
   const _UnlinkedParamKindReader() : super();
 
   @override
   int get size => 4;
 
   @override
-  UnlinkedParamKind read(fb.BufferPointer bp) {
+  idl.UnlinkedParamKind read(fb.BufferPointer bp) {
     int index = const fb.Uint32Reader().read(bp);
-    return UnlinkedParamKind.values[index];
+    return idl.UnlinkedParamKind.values[index];
   }
 }
 
-class EntityRefBuilder extends Object with _EntityRefMixin implements EntityRef {
+class EntityRefBuilder extends Object with _EntityRefMixin implements idl.EntityRef {
   bool _finished = false;
 
-  int _slot;
-  int _reference;
-  int _paramReference;
   List<int> _implicitFunctionTypeIndices;
+  int _paramReference;
+  int _reference;
+  int _slot;
   List<EntityRefBuilder> _typeArguments;
 
   @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
-  int get reference => _reference ??= 0;
-
-  /**
-   * Index into [UnlinkedUnit.references] for the entity being referred to, or
-   * zero if this is a reference to a type parameter.
-   */
-  void set reference(int _value) {
-    assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _reference = _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
-   * 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.
-   */
-  void set paramReference(int _value) {
-    assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _paramReference = _value;
-  }
-
-  @override
   List<int> get implicitFunctionTypeIndices => _implicitFunctionTypeIndices ??= <int>[];
 
   /**
@@ -547,76 +116,7 @@
   }
 
   @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({int slot, int reference, int paramReference, List<int> implicitFunctionTypeIndices, List<EntityRefBuilder> typeArguments})
-    : _slot = slot,
-      _reference = reference,
-      _paramReference = paramReference,
-      _implicitFunctionTypeIndices = implicitFunctionTypeIndices,
-      _typeArguments = typeArguments;
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_implicitFunctionTypeIndices;
-    fb.Offset offset_typeArguments;
-    if (!(_implicitFunctionTypeIndices == null || _implicitFunctionTypeIndices.isEmpty)) {
-      offset_implicitFunctionTypeIndices = fbBuilder.writeListUint32(_implicitFunctionTypeIndices);
-    }
-    if (!(_typeArguments == null || _typeArguments.isEmpty)) {
-      offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (_slot != null && _slot != 0) {
-      fbBuilder.addUint32(0, _slot);
-    }
-    if (_reference != null && _reference != 0) {
-      fbBuilder.addUint32(1, _reference);
-    }
-    if (_paramReference != null && _paramReference != 0) {
-      fbBuilder.addUint32(2, _paramReference);
-    }
-    if (offset_implicitFunctionTypeIndices != null) {
-      fbBuilder.addOffset(3, offset_implicitFunctionTypeIndices);
-    }
-    if (offset_typeArguments != null) {
-      fbBuilder.addOffset(4, offset_typeArguments);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * 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 [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.
-   */
-  int get slot;
-
-  /**
-   * Index into [UnlinkedUnit.references] for the entity being referred to, or
-   * zero if this is a reference to a type parameter.
-   */
-  int get reference;
+  int get paramReference => _paramReference ??= 0;
 
   /**
    * If this is a reference to a type parameter, one-based index into the list
@@ -637,38 +137,90 @@
    * If the type being referred to is not a type parameter, [paramReference] is
    * zero.
    */
-  int get paramReference;
+  void set paramReference(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _paramReference = _value;
+  }
+
+  @override
+  int get reference => _reference ??= 0;
 
   /**
-   * 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.
+   * Index into [UnlinkedUnit.references] for the entity being referred to, or
+   * zero if this is a reference to a type parameter.
    */
-  List<int> get implicitFunctionTypeIndices;
+  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<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.
    */
-  List<EntityRef> get typeArguments;
+  void set typeArguments(List<EntityRefBuilder> _value) {
+    assert(!_finished);
+    _typeArguments = _value;
+  }
+
+  EntityRefBuilder({List<int> implicitFunctionTypeIndices, int paramReference, int reference, int slot, List<EntityRefBuilder> typeArguments})
+    : _implicitFunctionTypeIndices = implicitFunctionTypeIndices,
+      _paramReference = paramReference,
+      _reference = reference,
+      _slot = slot,
+      _typeArguments = typeArguments;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_implicitFunctionTypeIndices;
+    fb.Offset offset_typeArguments;
+    if (!(_implicitFunctionTypeIndices == null || _implicitFunctionTypeIndices.isEmpty)) {
+      offset_implicitFunctionTypeIndices = fbBuilder.writeListUint32(_implicitFunctionTypeIndices);
+    }
+    if (!(_typeArguments == null || _typeArguments.isEmpty)) {
+      offset_typeArguments = fbBuilder.writeList(_typeArguments.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_implicitFunctionTypeIndices != null) {
+      fbBuilder.addOffset(0, offset_implicitFunctionTypeIndices);
+    }
+    if (_paramReference != null && _paramReference != 0) {
+      fbBuilder.addUint32(1, _paramReference);
+    }
+    if (_reference != null && _reference != 0) {
+      fbBuilder.addUint32(2, _reference);
+    }
+    if (_slot != null && _slot != 0) {
+      fbBuilder.addUint32(3, _slot);
+    }
+    if (offset_typeArguments != null) {
+      fbBuilder.addOffset(4, offset_typeArguments);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _EntityRefReader extends fb.TableReader<_EntityRefImpl> {
@@ -678,64 +230,76 @@
   _EntityRefImpl createObject(fb.BufferPointer bp) => new _EntityRefImpl(bp);
 }
 
-class _EntityRefImpl extends Object with _EntityRefMixin implements EntityRef {
+class _EntityRefImpl extends Object with _EntityRefMixin implements idl.EntityRef {
   final fb.BufferPointer _bp;
 
   _EntityRefImpl(this._bp);
 
-  int _slot;
-  int _reference;
-  int _paramReference;
   List<int> _implicitFunctionTypeIndices;
-  List<EntityRef> _typeArguments;
-
-  @override
-  int get slot {
-    _slot ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
-    return _slot;
-  }
-
-  @override
-  int get reference {
-    _reference ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _reference;
-  }
-
-  @override
-  int get paramReference {
-    _paramReference ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _paramReference;
-  }
+  int _paramReference;
+  int _reference;
+  int _slot;
+  List<idl.EntityRef> _typeArguments;
 
   @override
   List<int> get implicitFunctionTypeIndices {
-    _implicitFunctionTypeIndices ??= const fb.ListReader<int>(const fb.Uint32Reader()).vTableGet(_bp, 3, const <int>[]);
+    _implicitFunctionTypeIndices ??= const fb.ListReader<int>(const fb.Uint32Reader()).vTableGet(_bp, 0, const <int>[]);
     return _implicitFunctionTypeIndices;
   }
 
   @override
-  List<EntityRef> get typeArguments {
-    _typeArguments ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 4, const <EntityRef>[]);
+  int get paramReference {
+    _paramReference ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _paramReference;
+  }
+
+  @override
+  int get reference {
+    _reference ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _reference;
+  }
+
+  @override
+  int get slot {
+    _slot ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _slot;
+  }
+
+  @override
+  List<idl.EntityRef> get typeArguments {
+    _typeArguments ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 4, const <idl.EntityRef>[]);
     return _typeArguments;
   }
 }
 
-abstract class _EntityRefMixin implements EntityRef {
+abstract class _EntityRefMixin implements idl.EntityRef {
   @override
   Map<String, Object> toMap() => {
-    "slot": slot,
-    "reference": reference,
-    "paramReference": paramReference,
     "implicitFunctionTypeIndices": implicitFunctionTypeIndices,
+    "paramReference": paramReference,
+    "reference": reference,
+    "slot": slot,
     "typeArguments": typeArguments,
   };
 }
 
-class LinkedDependencyBuilder extends Object with _LinkedDependencyMixin implements LinkedDependency {
+class LinkedDependencyBuilder extends Object with _LinkedDependencyMixin implements idl.LinkedDependency {
   bool _finished = false;
 
-  String _uri;
   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 ??= '';
@@ -752,66 +316,32 @@
     _uri = _value;
   }
 
-  @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;
-  }
-
-  LinkedDependencyBuilder({String uri, List<String> parts})
-    : _uri = uri,
-      _parts = parts;
+  LinkedDependencyBuilder({List<String> parts, String uri})
+    : _parts = parts,
+      _uri = uri;
 
   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);
-    }
+    fb.Offset offset_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 (_uri != null) {
+      offset_uri = fbBuilder.writeString(_uri);
     }
+    fbBuilder.startTable();
     if (offset_parts != null) {
-      fbBuilder.addOffset(1, offset_parts);
+      fbBuilder.addOffset(0, offset_parts);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(1, offset_uri);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * Information about a dependency that exists between one library and another
- * due to an "import" declaration.
- */
-abstract class LinkedDependency 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 _LinkedDependencyReader extends fb.TableReader<_LinkedDependencyImpl> {
   const _LinkedDependencyReader();
 
@@ -819,54 +349,42 @@
   _LinkedDependencyImpl createObject(fb.BufferPointer bp) => new _LinkedDependencyImpl(bp);
 }
 
-class _LinkedDependencyImpl extends Object with _LinkedDependencyMixin implements LinkedDependency {
+class _LinkedDependencyImpl extends Object with _LinkedDependencyMixin implements idl.LinkedDependency {
   final fb.BufferPointer _bp;
 
   _LinkedDependencyImpl(this._bp);
 
-  String _uri;
   List<String> _parts;
-
-  @override
-  String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _uri;
-  }
+  String _uri;
 
   @override
   List<String> get parts {
-    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
     return _parts;
   }
+
+  @override
+  String get uri {
+    _uri ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _uri;
+  }
 }
 
-abstract class _LinkedDependencyMixin implements LinkedDependency {
+abstract class _LinkedDependencyMixin implements idl.LinkedDependency {
   @override
   Map<String, Object> toMap() => {
-    "uri": uri,
     "parts": parts,
+    "uri": uri,
   };
 }
 
-class LinkedExportNameBuilder extends Object with _LinkedExportNameMixin implements LinkedExportName {
+class LinkedExportNameBuilder extends Object with _LinkedExportNameMixin implements idl.LinkedExportName {
   bool _finished = false;
 
-  String _name;
   int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
   int _unit;
-  ReferenceKind _kind;
-
-  @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 dependency => _dependency ??= 0;
@@ -882,6 +400,29 @@
   }
 
   @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;
 
   /**
@@ -896,22 +437,11 @@
     _unit = _value;
   }
 
-  @override
-  ReferenceKind get kind => _kind ??= ReferenceKind.classOrEnum;
-
-  /**
-   * The kind of the entity being referred to.
-   */
-  void set kind(ReferenceKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  LinkedExportNameBuilder({String name, int dependency, int unit, ReferenceKind kind})
-    : _name = name,
-      _dependency = dependency,
-      _unit = unit,
-      _kind = kind;
+  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);
@@ -921,54 +451,22 @@
       offset_name = fbBuilder.writeString(_name);
     }
     fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
     if (_dependency != null && _dependency != 0) {
-      fbBuilder.addUint32(1, _dependency);
+      fbBuilder.addUint32(0, _dependency);
+    }
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
+      fbBuilder.addUint32(1, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(2, offset_name);
     }
     if (_unit != null && _unit != 0) {
-      fbBuilder.addUint32(2, _unit);
-    }
-    if (_kind != null && _kind != ReferenceKind.classOrEnum) {
-      fbBuilder.addUint32(3, _kind.index);
+      fbBuilder.addUint32(3, _unit);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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 {
-
-  /**
-   * Name of the exported entity.  For an exported setter, this name includes
-   * the trailing '='.
-   */
-  String get name;
-
-  /**
-   * Index into [LinkedLibrary.dependencies] for the library in which the
-   * entity is defined.
-   */
-  int get dependency;
-
-  /**
-   * 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.
-   */
-  int get unit;
-
-  /**
-   * The kind of the entity being referred to.
-   */
-  ReferenceKind get kind;
-}
-
 class _LinkedExportNameReader extends fb.TableReader<_LinkedExportNameImpl> {
   const _LinkedExportNameReader();
 
@@ -976,73 +474,59 @@
   _LinkedExportNameImpl createObject(fb.BufferPointer bp) => new _LinkedExportNameImpl(bp);
 }
 
-class _LinkedExportNameImpl extends Object with _LinkedExportNameMixin implements LinkedExportName {
+class _LinkedExportNameImpl extends Object with _LinkedExportNameMixin implements idl.LinkedExportName {
   final fb.BufferPointer _bp;
 
   _LinkedExportNameImpl(this._bp);
 
-  String _name;
   int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
   int _unit;
-  ReferenceKind _kind;
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
 
   @override
   int get dependency {
-    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
     return _dependency;
   }
 
   @override
-  int get unit {
-    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _unit;
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, idl.ReferenceKind.classOrEnum);
+    return _kind;
   }
 
   @override
-  ReferenceKind get kind {
-    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 3, ReferenceKind.classOrEnum);
-    return _kind;
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 2, '');
+    return _name;
+  }
+
+  @override
+  int get unit {
+    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _unit;
   }
 }
 
-abstract class _LinkedExportNameMixin implements LinkedExportName {
+abstract class _LinkedExportNameMixin implements idl.LinkedExportName {
   @override
   Map<String, Object> toMap() => {
-    "name": name,
     "dependency": dependency,
-    "unit": unit,
     "kind": kind,
+    "name": name,
+    "unit": unit,
   };
 }
 
-class LinkedLibraryBuilder extends Object with _LinkedLibraryMixin implements LinkedLibrary {
+class LinkedLibraryBuilder extends Object with _LinkedLibraryMixin implements idl.LinkedLibrary {
   bool _finished = false;
 
-  List<LinkedUnitBuilder> _units;
   List<LinkedDependencyBuilder> _dependencies;
-  List<int> _importDependencies;
   List<LinkedExportNameBuilder> _exportNames;
+  List<int> _importDependencies;
   int _numPrelinkedDependencies;
-
-  @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;
-  }
+  List<LinkedUnitBuilder> _units;
 
   @override
   List<LinkedDependencyBuilder> get dependencies => _dependencies ??= <LinkedDependencyBuilder>[];
@@ -1069,19 +553,6 @@
   }
 
   @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
   List<LinkedExportNameBuilder> get exportNames => _exportNames ??= <LinkedExportNameBuilder>[];
 
   /**
@@ -1097,6 +568,19 @@
   }
 
   @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;
 
   /**
@@ -1110,12 +594,26 @@
     _numPrelinkedDependencies = _value;
   }
 
-  LinkedLibraryBuilder({List<LinkedUnitBuilder> units, List<LinkedDependencyBuilder> dependencies, List<int> importDependencies, List<LinkedExportNameBuilder> exportNames, int numPrelinkedDependencies})
-    : _units = units,
-      _dependencies = dependencies,
-      _importDependencies = importDependencies,
+  @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,
-      _numPrelinkedDependencies = numPrelinkedDependencies;
+      _importDependencies = importDependencies,
+      _numPrelinkedDependencies = numPrelinkedDependencies,
+      _units = units;
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
@@ -1125,98 +623,45 @@
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_units;
     fb.Offset offset_dependencies;
-    fb.Offset offset_importDependencies;
     fb.Offset offset_exportNames;
-    if (!(_units == null || _units.isEmpty)) {
-      offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
-    }
+    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 (!(_importDependencies == null || _importDependencies.isEmpty)) {
-      offset_importDependencies = fbBuilder.writeListUint32(_importDependencies);
-    }
     if (!(_exportNames == null || _exportNames.isEmpty)) {
       offset_exportNames = fbBuilder.writeList(_exportNames.map((b) => b.finish(fbBuilder)).toList());
     }
-    fbBuilder.startTable();
-    if (offset_units != null) {
-      fbBuilder.addOffset(0, offset_units);
+    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(1, offset_dependencies);
+      fbBuilder.addOffset(0, offset_dependencies);
+    }
+    if (offset_exportNames != null) {
+      fbBuilder.addOffset(1, offset_exportNames);
     }
     if (offset_importDependencies != null) {
       fbBuilder.addOffset(2, offset_importDependencies);
     }
-    if (offset_exportNames != null) {
-      fbBuilder.addOffset(3, offset_exportNames);
-    }
     if (_numPrelinkedDependencies != null && _numPrelinkedDependencies != 0) {
-      fbBuilder.addUint32(4, _numPrelinkedDependencies);
+      fbBuilder.addUint32(3, _numPrelinkedDependencies);
+    }
+    if (offset_units != null) {
+      fbBuilder.addOffset(4, offset_units);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * Linked summary of a library.
- */
-abstract class LinkedLibrary extends base.SummaryClass {
-  factory LinkedLibrary.fromBuffer(List<int> buffer) {
-    fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
-    return const _LinkedLibraryReader().read(rootRef);
-  }
-
-  /**
-   * 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.
-   */
-  List<LinkedUnit> 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` 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).
-   */
-  List<LinkedDependency> get dependencies;
-
-  /**
-   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
-   * of the library being imported.
-   */
-  List<int> get importDependencies;
-
-  /**
-   * 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.
-   */
-  List<LinkedExportName> get exportNames;
-
-  /**
-   * 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).
-   */
-  int get numPrelinkedDependencies;
+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> {
@@ -1226,27 +671,27 @@
   _LinkedLibraryImpl createObject(fb.BufferPointer bp) => new _LinkedLibraryImpl(bp);
 }
 
-class _LinkedLibraryImpl extends Object with _LinkedLibraryMixin implements LinkedLibrary {
+class _LinkedLibraryImpl extends Object with _LinkedLibraryMixin implements idl.LinkedLibrary {
   final fb.BufferPointer _bp;
 
   _LinkedLibraryImpl(this._bp);
 
-  List<LinkedUnit> _units;
-  List<LinkedDependency> _dependencies;
+  List<idl.LinkedDependency> _dependencies;
+  List<idl.LinkedExportName> _exportNames;
   List<int> _importDependencies;
-  List<LinkedExportName> _exportNames;
   int _numPrelinkedDependencies;
+  List<idl.LinkedUnit> _units;
 
   @override
-  List<LinkedUnit> get units {
-    _units ??= const fb.ListReader<LinkedUnit>(const _LinkedUnitReader()).vTableGet(_bp, 0, const <LinkedUnit>[]);
-    return _units;
+  List<idl.LinkedDependency> get dependencies {
+    _dependencies ??= const fb.ListReader<idl.LinkedDependency>(const _LinkedDependencyReader()).vTableGet(_bp, 0, const <idl.LinkedDependency>[]);
+    return _dependencies;
   }
 
   @override
-  List<LinkedDependency> get dependencies {
-    _dependencies ??= const fb.ListReader<LinkedDependency>(const _LinkedDependencyReader()).vTableGet(_bp, 1, const <LinkedDependency>[]);
-    return _dependencies;
+  List<idl.LinkedExportName> get exportNames {
+    _exportNames ??= const fb.ListReader<idl.LinkedExportName>(const _LinkedExportNameReader()).vTableGet(_bp, 1, const <idl.LinkedExportName>[]);
+    return _exportNames;
   }
 
   @override
@@ -1256,110 +701,38 @@
   }
 
   @override
-  List<LinkedExportName> get exportNames {
-    _exportNames ??= const fb.ListReader<LinkedExportName>(const _LinkedExportNameReader()).vTableGet(_bp, 3, const <LinkedExportName>[]);
-    return _exportNames;
+  int get numPrelinkedDependencies {
+    _numPrelinkedDependencies ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _numPrelinkedDependencies;
   }
 
   @override
-  int get numPrelinkedDependencies {
-    _numPrelinkedDependencies ??= const fb.Uint32Reader().vTableGet(_bp, 4, 0);
-    return _numPrelinkedDependencies;
+  List<idl.LinkedUnit> get units {
+    _units ??= const fb.ListReader<idl.LinkedUnit>(const _LinkedUnitReader()).vTableGet(_bp, 4, const <idl.LinkedUnit>[]);
+    return _units;
   }
 }
 
-abstract class _LinkedLibraryMixin implements LinkedLibrary {
+abstract class _LinkedLibraryMixin implements idl.LinkedLibrary {
   @override
   Map<String, Object> toMap() => {
-    "units": units,
     "dependencies": dependencies,
-    "importDependencies": importDependencies,
     "exportNames": exportNames,
+    "importDependencies": importDependencies,
     "numPrelinkedDependencies": numPrelinkedDependencies,
+    "units": units,
   };
 }
 
-class LinkedReferenceBuilder extends Object with _LinkedReferenceMixin implements LinkedReference {
+class LinkedReferenceBuilder extends Object with _LinkedReferenceMixin implements idl.LinkedReference {
   bool _finished = false;
 
-  int _dependency;
-  ReferenceKind _kind;
-  int _unit;
-  int _numTypeParameters;
-  String _name;
   int _containingReference;
-
-  @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).
-   */
-  void set dependency(int _value) {
-    assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _dependency = _value;
-  }
-
-  @override
-  ReferenceKind get kind => _kind ??= 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(ReferenceKind _value) {
-    assert(!_finished);
-    _kind = _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;
-  }
-
-  @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;
-  }
-
-  @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;
-  }
+  int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
+  int _numTypeParameters;
+  int _unit;
 
   @override
   int get containingReference => _containingReference ??= 0;
@@ -1381,63 +754,62 @@
     _containingReference = _value;
   }
 
-  LinkedReferenceBuilder({int dependency, ReferenceKind kind, int unit, int numTypeParameters, String name, int containingReference})
-    : _dependency = dependency,
-      _kind = kind,
-      _unit = unit,
-      _numTypeParameters = numTypeParameters,
-      _name = name,
-      _containingReference = containingReference;
-
-  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 != ReferenceKind.classOrEnum) {
-      fbBuilder.addUint32(1, _kind.index);
-    }
-    if (_unit != null && _unit != 0) {
-      fbBuilder.addUint32(2, _unit);
-    }
-    if (_numTypeParameters != null && _numTypeParameters != 0) {
-      fbBuilder.addUint32(3, _numTypeParameters);
-    }
-    if (offset_name != null) {
-      fbBuilder.addOffset(4, offset_name);
-    }
-    if (_containingReference != null && _containingReference != 0) {
-      fbBuilder.addUint32(5, _containingReference);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * Information about the resolution of an [UnlinkedReference].
- */
-abstract class LinkedReference extends base.SummaryClass {
+  @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).
+   * member), or if [kind] is [ReferenceKind.prefix].
    */
-  int get dependency;
+  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].
    */
-  ReferenceKind get kind;
+  void set kind(idl.ReferenceKind _value) {
+    assert(!_finished);
+    _kind = _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 accepts.  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
@@ -1448,33 +820,48 @@
    * Zero if this entity is contained within another entity (e.g. a class
    * member).
    */
-  int get unit;
+  void set unit(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _unit = _value;
+  }
 
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int get numTypeParameters;
+  LinkedReferenceBuilder({int containingReference, int dependency, idl.ReferenceKind kind, String name, int numTypeParameters, int unit})
+    : _containingReference = containingReference,
+      _dependency = dependency,
+      _kind = kind,
+      _name = name,
+      _numTypeParameters = numTypeParameters,
+      _unit = unit;
 
-  /**
-   * 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".
-   */
-  String get name;
-
-  /**
-   * 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.
-   */
-  int get containingReference;
+  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(0, _containingReference);
+    }
+    if (_dependency != null && _dependency != 0) {
+      fbBuilder.addUint32(1, _dependency);
+    }
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
+      fbBuilder.addUint32(2, _kind.index);
+    }
+    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(5, _unit);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _LinkedReferenceReader extends fb.TableReader<_LinkedReferenceImpl> {
@@ -1484,68 +871,68 @@
   _LinkedReferenceImpl createObject(fb.BufferPointer bp) => new _LinkedReferenceImpl(bp);
 }
 
-class _LinkedReferenceImpl extends Object with _LinkedReferenceMixin implements LinkedReference {
+class _LinkedReferenceImpl extends Object with _LinkedReferenceMixin implements idl.LinkedReference {
   final fb.BufferPointer _bp;
 
   _LinkedReferenceImpl(this._bp);
 
-  int _dependency;
-  ReferenceKind _kind;
-  int _unit;
-  int _numTypeParameters;
-  String _name;
   int _containingReference;
+  int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
+  int _numTypeParameters;
+  int _unit;
+
+  @override
+  int get containingReference {
+    _containingReference ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _containingReference;
+  }
 
   @override
   int get dependency {
-    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
     return _dependency;
   }
 
   @override
-  ReferenceKind get kind {
-    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, ReferenceKind.classOrEnum);
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 2, idl.ReferenceKind.classOrEnum);
     return _kind;
   }
 
   @override
-  int get unit {
-    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _unit;
-  }
-
-  @override
-  int get numTypeParameters {
-    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
-    return _numTypeParameters;
-  }
-
-  @override
   String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 4, '');
+    _name ??= const fb.StringReader().vTableGet(_bp, 3, '');
     return _name;
   }
 
   @override
-  int get containingReference {
-    _containingReference ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
-    return _containingReference;
+  int get numTypeParameters {
+    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 4, 0);
+    return _numTypeParameters;
+  }
+
+  @override
+  int get unit {
+    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
+    return _unit;
   }
 }
 
-abstract class _LinkedReferenceMixin implements LinkedReference {
+abstract class _LinkedReferenceMixin implements idl.LinkedReference {
   @override
   Map<String, Object> toMap() => {
+    "containingReference": containingReference,
     "dependency": dependency,
     "kind": kind,
-    "unit": unit,
-    "numTypeParameters": numTypeParameters,
     "name": name,
-    "containingReference": containingReference,
+    "numTypeParameters": numTypeParameters,
+    "unit": unit,
   };
 }
 
-class LinkedUnitBuilder extends Object with _LinkedUnitMixin implements LinkedUnit {
+class LinkedUnitBuilder extends Object with _LinkedUnitMixin implements idl.LinkedUnit {
   bool _finished = false;
 
   List<LinkedReferenceBuilder> _references;
@@ -1605,28 +992,6 @@
   }
 }
 
-/**
- * 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).
-   */
-  List<LinkedReference> get references;
-
-  /**
-   * List associating slot ids found inside the unlinked summary for the
-   * compilation unit with propagated and inferred types.
-   */
-  List<EntityRef> get types;
-}
-
 class _LinkedUnitReader extends fb.TableReader<_LinkedUnitImpl> {
   const _LinkedUnitReader();
 
@@ -1634,28 +999,28 @@
   _LinkedUnitImpl createObject(fb.BufferPointer bp) => new _LinkedUnitImpl(bp);
 }
 
-class _LinkedUnitImpl extends Object with _LinkedUnitMixin implements LinkedUnit {
+class _LinkedUnitImpl extends Object with _LinkedUnitMixin implements idl.LinkedUnit {
   final fb.BufferPointer _bp;
 
   _LinkedUnitImpl(this._bp);
 
-  List<LinkedReference> _references;
-  List<EntityRef> _types;
+  List<idl.LinkedReference> _references;
+  List<idl.EntityRef> _types;
 
   @override
-  List<LinkedReference> get references {
-    _references ??= const fb.ListReader<LinkedReference>(const _LinkedReferenceReader()).vTableGet(_bp, 0, const <LinkedReference>[]);
+  List<idl.LinkedReference> get references {
+    _references ??= const fb.ListReader<idl.LinkedReference>(const _LinkedReferenceReader()).vTableGet(_bp, 0, const <idl.LinkedReference>[]);
     return _references;
   }
 
   @override
-  List<EntityRef> get types {
-    _types ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 1, const <EntityRef>[]);
+  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 LinkedUnit {
+abstract class _LinkedUnitMixin implements idl.LinkedUnit {
   @override
   Map<String, Object> toMap() => {
     "references": references,
@@ -1663,24 +1028,13 @@
   };
 }
 
-class SdkBundleBuilder extends Object with _SdkBundleMixin implements SdkBundle {
+class SdkBundleBuilder extends Object with _SdkBundleMixin implements idl.SdkBundle {
   bool _finished = false;
 
-  List<String> _linkedLibraryUris;
   List<LinkedLibraryBuilder> _linkedLibraries;
-  List<String> _unlinkedUnitUris;
+  List<String> _linkedLibraryUris;
   List<UnlinkedUnitBuilder> _unlinkedUnits;
-
-  @override
-  List<String> get linkedLibraryUris => _linkedLibraryUris ??= <String>[];
-
-  /**
-   * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
-   */
-  void set linkedLibraryUris(List<String> _value) {
-    assert(!_finished);
-    _linkedLibraryUris = _value;
-  }
+  List<String> _unlinkedUnitUris;
 
   @override
   List<LinkedLibraryBuilder> get linkedLibraries => _linkedLibraries ??= <LinkedLibraryBuilder>[];
@@ -1694,14 +1048,14 @@
   }
 
   @override
-  List<String> get unlinkedUnitUris => _unlinkedUnitUris ??= <String>[];
+  List<String> get linkedLibraryUris => _linkedLibraryUris ??= <String>[];
 
   /**
-   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
    */
-  void set unlinkedUnitUris(List<String> _value) {
+  void set linkedLibraryUris(List<String> _value) {
     assert(!_finished);
-    _unlinkedUnitUris = _value;
+    _linkedLibraryUris = _value;
   }
 
   @override
@@ -1715,11 +1069,22 @@
     _unlinkedUnits = _value;
   }
 
-  SdkBundleBuilder({List<String> linkedLibraryUris, List<LinkedLibraryBuilder> linkedLibraries, List<String> unlinkedUnitUris, List<UnlinkedUnitBuilder> unlinkedUnits})
-    : _linkedLibraryUris = linkedLibraryUris,
-      _linkedLibraries = linkedLibraries,
-      _unlinkedUnitUris = unlinkedUnitUris,
-      _unlinkedUnits = unlinkedUnits;
+  @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;
+  }
+
+  SdkBundleBuilder({List<LinkedLibraryBuilder> linkedLibraries, List<String> linkedLibraryUris, List<UnlinkedUnitBuilder> unlinkedUnits, List<String> unlinkedUnitUris})
+    : _linkedLibraries = linkedLibraries,
+      _linkedLibraryUris = linkedLibraryUris,
+      _unlinkedUnits = unlinkedUnits,
+      _unlinkedUnitUris = unlinkedUnitUris;
 
   List<int> toBuffer() {
     fb.Builder fbBuilder = new fb.Builder();
@@ -1729,67 +1094,42 @@
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_linkedLibraryUris;
     fb.Offset offset_linkedLibraries;
-    fb.Offset offset_unlinkedUnitUris;
+    fb.Offset offset_linkedLibraryUris;
     fb.Offset offset_unlinkedUnits;
-    if (!(_linkedLibraryUris == null || _linkedLibraryUris.isEmpty)) {
-      offset_linkedLibraryUris = fbBuilder.writeList(_linkedLibraryUris.map((b) => fbBuilder.writeString(b)).toList());
-    }
+    fb.Offset offset_unlinkedUnitUris;
     if (!(_linkedLibraries == null || _linkedLibraries.isEmpty)) {
       offset_linkedLibraries = fbBuilder.writeList(_linkedLibraries.map((b) => b.finish(fbBuilder)).toList());
     }
-    if (!(_unlinkedUnitUris == null || _unlinkedUnitUris.isEmpty)) {
-      offset_unlinkedUnitUris = fbBuilder.writeList(_unlinkedUnitUris.map((b) => fbBuilder.writeString(b)).toList());
+    if (!(_linkedLibraryUris == null || _linkedLibraryUris.isEmpty)) {
+      offset_linkedLibraryUris = fbBuilder.writeList(_linkedLibraryUris.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_linkedLibraryUris != null) {
-      fbBuilder.addOffset(0, offset_linkedLibraryUris);
-    }
     if (offset_linkedLibraries != null) {
-      fbBuilder.addOffset(1, offset_linkedLibraries);
+      fbBuilder.addOffset(0, offset_linkedLibraries);
     }
-    if (offset_unlinkedUnitUris != null) {
-      fbBuilder.addOffset(2, offset_unlinkedUnitUris);
+    if (offset_linkedLibraryUris != null) {
+      fbBuilder.addOffset(1, offset_linkedLibraryUris);
     }
     if (offset_unlinkedUnits != null) {
-      fbBuilder.addOffset(3, offset_unlinkedUnits);
+      fbBuilder.addOffset(2, offset_unlinkedUnits);
+    }
+    if (offset_unlinkedUnitUris != null) {
+      fbBuilder.addOffset(3, offset_unlinkedUnitUris);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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 [linkedLibraries], e.g. `dart:core`.
-   */
-  List<String> get linkedLibraryUris;
-
-  /**
-   * Linked libraries.
-   */
-  List<LinkedLibrary> get linkedLibraries;
-
-  /**
-   * 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;
+idl.SdkBundle readSdkBundle(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _SdkBundleReader().read(rootRef);
 }
 
 class _SdkBundleReader extends fb.TableReader<_SdkBundleImpl> {
@@ -1799,88 +1139,77 @@
   _SdkBundleImpl createObject(fb.BufferPointer bp) => new _SdkBundleImpl(bp);
 }
 
-class _SdkBundleImpl extends Object with _SdkBundleMixin implements SdkBundle {
+class _SdkBundleImpl extends Object with _SdkBundleMixin implements idl.SdkBundle {
   final fb.BufferPointer _bp;
 
   _SdkBundleImpl(this._bp);
 
+  List<idl.LinkedLibrary> _linkedLibraries;
   List<String> _linkedLibraryUris;
-  List<LinkedLibrary> _linkedLibraries;
+  List<idl.UnlinkedUnit> _unlinkedUnits;
   List<String> _unlinkedUnitUris;
-  List<UnlinkedUnit> _unlinkedUnits;
 
   @override
-  List<String> get linkedLibraryUris {
-    _linkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
-    return _linkedLibraryUris;
-  }
-
-  @override
-  List<LinkedLibrary> get linkedLibraries {
-    _linkedLibraries ??= const fb.ListReader<LinkedLibrary>(const _LinkedLibraryReader()).vTableGet(_bp, 1, const <LinkedLibrary>[]);
+  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 unlinkedUnitUris {
-    _unlinkedUnitUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 2, const <String>[]);
-    return _unlinkedUnitUris;
+  List<String> get linkedLibraryUris {
+    _linkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _linkedLibraryUris;
   }
 
   @override
-  List<UnlinkedUnit> get unlinkedUnits {
-    _unlinkedUnits ??= const fb.ListReader<UnlinkedUnit>(const _UnlinkedUnitReader()).vTableGet(_bp, 3, const <UnlinkedUnit>[]);
+  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 _SdkBundleMixin implements SdkBundle {
+abstract class _SdkBundleMixin implements idl.SdkBundle {
   @override
   Map<String, Object> toMap() => {
-    "linkedLibraryUris": linkedLibraryUris,
     "linkedLibraries": linkedLibraries,
-    "unlinkedUnitUris": unlinkedUnitUris,
+    "linkedLibraryUris": linkedLibraryUris,
     "unlinkedUnits": unlinkedUnits,
+    "unlinkedUnitUris": unlinkedUnitUris,
   };
 }
 
-class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements UnlinkedClass {
+class UnlinkedClassBuilder extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
   bool _finished = false;
 
-  String _name;
-  int _nameOffset;
+  List<UnlinkedConstBuilder> _annotations;
   UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  EntityRefBuilder _supertype;
-  List<EntityRefBuilder> _mixins;
-  List<EntityRefBuilder> _interfaces;
-  List<UnlinkedVariableBuilder> _fields;
   List<UnlinkedExecutableBuilder> _executables;
+  List<UnlinkedVariableBuilder> _fields;
+  bool _hasNoSupertype;
+  List<EntityRefBuilder> _interfaces;
   bool _isAbstract;
   bool _isMixinApplication;
-  bool _hasNoSupertype;
+  List<EntityRefBuilder> _mixins;
+  String _name;
+  int _nameOffset;
+  EntityRefBuilder _supertype;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
 
   @override
-  String get name => _name ??= '';
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Name of the class.
+   * Annotations for this class.
    */
-  void set name(String _value) {
+  void set annotations(List<UnlinkedConstBuilder> _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;
+    _annotations = _value;
   }
 
   @override
@@ -1896,49 +1225,14 @@
   }
 
   @override
-  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+  List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
 
   /**
-   * Type parameters of the class, if any.
+   * Executable objects (methods, getters, and setters) contained in the class.
    */
-  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+  void set executables(List<UnlinkedExecutableBuilder> _value) {
     assert(!_finished);
-    _typeParameters = _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<EntityRefBuilder> get mixins => _mixins ??= <EntityRefBuilder>[];
-
-  /**
-   * Mixins appearing in a `with` clause, if any.
-   */
-  void set mixins(List<EntityRefBuilder> _value) {
-    assert(!_finished);
-    _mixins = _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;
+    _executables = _value;
   }
 
   @override
@@ -1953,14 +1247,26 @@
   }
 
   @override
-  List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
+  bool get hasNoSupertype => _hasNoSupertype ??= false;
 
   /**
-   * Executable objects (methods, getters, and setters) contained in the class.
+   * Indicates whether this class is the core "Object" class (and hence has no
+   * supertype)
    */
-  void set executables(List<UnlinkedExecutableBuilder> _value) {
+  void set hasNoSupertype(bool _value) {
     assert(!_finished);
-    _executables = _value;
+    _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
@@ -1986,175 +1292,159 @@
   }
 
   @override
-  bool get hasNoSupertype => _hasNoSupertype ??= false;
+  List<EntityRefBuilder> get mixins => _mixins ??= <EntityRefBuilder>[];
 
   /**
-   * Indicates whether this class is the core "Object" class (and hence has no
-   * supertype)
+   * Mixins appearing in a `with` clause, if any.
    */
-  void set hasNoSupertype(bool _value) {
+  void set mixins(List<EntityRefBuilder> _value) {
     assert(!_finished);
-    _hasNoSupertype = _value;
+    _mixins = _value;
   }
 
-  UnlinkedClassBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder supertype, List<EntityRefBuilder> mixins, List<EntityRefBuilder> interfaces, List<UnlinkedVariableBuilder> fields, List<UnlinkedExecutableBuilder> executables, bool isAbstract, bool isMixinApplication, bool hasNoSupertype})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _documentationComment = documentationComment,
-      _typeParameters = typeParameters,
-      _supertype = supertype,
-      _mixins = mixins,
-      _interfaces = interfaces,
-      _fields = fields,
-      _executables = executables,
-      _isAbstract = isAbstract,
-      _isMixinApplication = isMixinApplication,
-      _hasNoSupertype = hasNoSupertype;
-
-  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.addUint32(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();
-  }
-}
-
-/**
- * Unlinked summary information about a class declaration.
- */
-abstract class UnlinkedClass extends base.SummaryClass {
+  @override
+  String get name => _name ??= '';
 
   /**
    * Name of the class.
    */
-  String get name;
+  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.
    */
-  int get nameOffset;
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
 
-  /**
-   * 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;
+  @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).
    */
-  EntityRef get supertype;
+  void set supertype(EntityRefBuilder _value) {
+    assert(!_finished);
+    _supertype = _value;
+  }
+
+  @override
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
 
   /**
-   * Mixins appearing in a `with` clause, if any.
+   * Type parameters of the class, if any.
    */
-  List<EntityRef> get mixins;
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _value;
+  }
 
-  /**
-   * Interfaces appearing in an `implements` clause, if any.
-   */
-  List<EntityRef> get interfaces;
+  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;
 
-  /**
-   * 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;
+  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(0, offset_annotations);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(1, offset_documentationComment);
+    }
+    if (offset_executables != null) {
+      fbBuilder.addOffset(2, offset_executables);
+    }
+    if (offset_fields != null) {
+      fbBuilder.addOffset(3, offset_fields);
+    }
+    if (_hasNoSupertype == true) {
+      fbBuilder.addBool(4, true);
+    }
+    if (offset_interfaces != null) {
+      fbBuilder.addOffset(5, offset_interfaces);
+    }
+    if (_isAbstract == true) {
+      fbBuilder.addBool(6, true);
+    }
+    if (_isMixinApplication == true) {
+      fbBuilder.addBool(7, true);
+    }
+    if (offset_mixins != null) {
+      fbBuilder.addOffset(8, offset_mixins);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(9, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(10, _nameOffset);
+    }
+    if (offset_supertype != null) {
+      fbBuilder.addOffset(11, offset_supertype);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(12, offset_typeParameters);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedClassReader extends fb.TableReader<_UnlinkedClassImpl> {
@@ -2164,131 +1454,128 @@
   _UnlinkedClassImpl createObject(fb.BufferPointer bp) => new _UnlinkedClassImpl(bp);
 }
 
-class _UnlinkedClassImpl extends Object with _UnlinkedClassMixin implements UnlinkedClass {
+class _UnlinkedClassImpl extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
   final fb.BufferPointer _bp;
 
   _UnlinkedClassImpl(this._bp);
 
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  EntityRef _supertype;
-  List<EntityRef> _mixins;
-  List<EntityRef> _interfaces;
-  List<UnlinkedVariable> _fields;
-  List<UnlinkedExecutable> _executables;
+  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;
-  bool _hasNoSupertype;
+  List<idl.EntityRef> _mixins;
+  String _name;
+  int _nameOffset;
+  idl.EntityRef _supertype;
+  List<idl.UnlinkedTypeParam> _typeParameters;
 
   @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, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 1, null);
     return _documentationComment;
   }
 
   @override
-  List<UnlinkedTypeParam> get typeParameters {
-    _typeParameters ??= const fb.ListReader<UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 3, const <UnlinkedTypeParam>[]);
-    return _typeParameters;
-  }
-
-  @override
-  EntityRef get supertype {
-    _supertype ??= const _EntityRefReader().vTableGet(_bp, 4, null);
-    return _supertype;
-  }
-
-  @override
-  List<EntityRef> get mixins {
-    _mixins ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 5, const <EntityRef>[]);
-    return _mixins;
-  }
-
-  @override
-  List<EntityRef> get interfaces {
-    _interfaces ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 6, const <EntityRef>[]);
-    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>[]);
+  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, 3, const <idl.UnlinkedVariable>[]);
+    return _fields;
+  }
+
+  @override
+  bool get hasNoSupertype {
+    _hasNoSupertype ??= const fb.BoolReader().vTableGet(_bp, 4, false);
+    return _hasNoSupertype;
+  }
+
+  @override
+  List<idl.EntityRef> get interfaces {
+    _interfaces ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 5, const <idl.EntityRef>[]);
+    return _interfaces;
+  }
+
+  @override
   bool get isAbstract {
-    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 9, false);
+    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 6, false);
     return _isAbstract;
   }
 
   @override
   bool get isMixinApplication {
-    _isMixinApplication ??= const fb.BoolReader().vTableGet(_bp, 10, false);
+    _isMixinApplication ??= const fb.BoolReader().vTableGet(_bp, 7, false);
     return _isMixinApplication;
   }
 
   @override
-  bool get hasNoSupertype {
-    _hasNoSupertype ??= const fb.BoolReader().vTableGet(_bp, 11, false);
-    return _hasNoSupertype;
+  List<idl.EntityRef> get mixins {
+    _mixins ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 8, const <idl.EntityRef>[]);
+    return _mixins;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 9, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 10, 0);
+    return _nameOffset;
+  }
+
+  @override
+  idl.EntityRef get supertype {
+    _supertype ??= const _EntityRefReader().vTableGet(_bp, 11, null);
+    return _supertype;
+  }
+
+  @override
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 12, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
   }
 }
 
-abstract class _UnlinkedClassMixin implements UnlinkedClass {
+abstract class _UnlinkedClassMixin implements idl.UnlinkedClass {
   @override
   Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
+    "annotations": annotations,
     "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "supertype": supertype,
-    "mixins": mixins,
-    "interfaces": interfaces,
-    "fields": fields,
     "executables": executables,
+    "fields": fields,
+    "hasNoSupertype": hasNoSupertype,
+    "interfaces": interfaces,
     "isAbstract": isAbstract,
     "isMixinApplication": isMixinApplication,
-    "hasNoSupertype": hasNoSupertype,
+    "mixins": mixins,
+    "name": name,
+    "nameOffset": nameOffset,
+    "supertype": supertype,
+    "typeParameters": typeParameters,
   };
 }
 
-class UnlinkedCombinatorBuilder extends Object with _UnlinkedCombinatorMixin implements UnlinkedCombinator {
+class UnlinkedCombinatorBuilder extends Object with _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
   bool _finished = false;
 
-  List<String> _shows;
   List<String> _hides;
-
-  @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;
-  }
+  List<String> _shows;
 
   @override
   List<String> get hides => _hides ??= <String>[];
@@ -2301,47 +1588,41 @@
     _hides = _value;
   }
 
-  UnlinkedCombinatorBuilder({List<String> shows, List<String> hides})
-    : _shows = shows,
-      _hides = hides;
-
-  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();
-  }
-}
-
-/**
- * Unlinked summary information about a `show` or `hide` combinator in an
- * import or export declaration.
- */
-abstract class UnlinkedCombinator extends base.SummaryClass {
+  @override
+  List<String> get shows => _shows ??= <String>[];
 
   /**
    * List of names which are shown.  Empty if this is a `hide` combinator.
    */
-  List<String> get shows;
+  void set shows(List<String> _value) {
+    assert(!_finished);
+    _shows = _value;
+  }
 
-  /**
-   * List of names which are hidden.  Empty if this is a `show` combinator.
-   */
-  List<String> get hides;
+  UnlinkedCombinatorBuilder({List<String> hides, List<String> shows})
+    : _hides = hides,
+      _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 (offset_hides != null) {
+      fbBuilder.addOffset(0, offset_hides);
+    }
+    if (offset_shows != null) {
+      fbBuilder.addOffset(1, offset_shows);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedCombinatorReader extends fb.TableReader<_UnlinkedCombinatorImpl> {
@@ -2351,54 +1632,54 @@
   _UnlinkedCombinatorImpl createObject(fb.BufferPointer bp) => new _UnlinkedCombinatorImpl(bp);
 }
 
-class _UnlinkedCombinatorImpl extends Object with _UnlinkedCombinatorMixin implements UnlinkedCombinator {
+class _UnlinkedCombinatorImpl extends Object with _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
   final fb.BufferPointer _bp;
 
   _UnlinkedCombinatorImpl(this._bp);
 
-  List<String> _shows;
   List<String> _hides;
-
-  @override
-  List<String> get shows {
-    _shows ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
-    return _shows;
-  }
+  List<String> _shows;
 
   @override
   List<String> get hides {
-    _hides ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    _hides ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
     return _hides;
   }
+
+  @override
+  List<String> get shows {
+    _shows ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _shows;
+  }
 }
 
-abstract class _UnlinkedCombinatorMixin implements UnlinkedCombinator {
+abstract class _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
   @override
   Map<String, Object> toMap() => {
-    "shows": shows,
     "hides": hides,
+    "shows": shows,
   };
 }
 
-class UnlinkedConstBuilder extends Object with _UnlinkedConstMixin implements UnlinkedConst {
+class UnlinkedConstBuilder extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
   bool _finished = false;
 
-  List<UnlinkedConstOperation> _operations;
-  List<int> _ints;
   List<double> _doubles;
-  List<String> _strings;
+  List<int> _ints;
+  bool _isInvalid;
+  List<idl.UnlinkedConstOperation> _operations;
   List<EntityRefBuilder> _references;
+  List<String> _strings;
 
   @override
-  List<UnlinkedConstOperation> get operations => _operations ??= <UnlinkedConstOperation>[];
+  List<double> get doubles => _doubles ??= <double>[];
 
   /**
-   * Sequence of operations to execute (starting with an empty stack) to form
-   * the constant value.
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
    */
-  void set operations(List<UnlinkedConstOperation> _value) {
+  void set doubles(List<double> _value) {
     assert(!_finished);
-    _operations = _value;
+    _doubles = _value;
   }
 
   @override
@@ -2416,26 +1697,27 @@
   }
 
   @override
-  List<double> get doubles => _doubles ??= <double>[];
+  bool get isInvalid => _isInvalid ??= false;
 
   /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   * Indicates whether the expression is not a valid potentially constant
+   * expression.
    */
-  void set doubles(List<double> _value) {
+  void set isInvalid(bool _value) {
     assert(!_finished);
-    _doubles = _value;
+    _isInvalid = _value;
   }
 
   @override
-  List<String> get strings => _strings ??= <String>[];
+  List<idl.UnlinkedConstOperation> get operations => _operations ??= <idl.UnlinkedConstOperation>[];
 
   /**
-   * Sequence of strings consumed by the operations `pushString` and
-   * `invokeConstructor`.
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
    */
-  void set strings(List<String> _value) {
+  void set operations(List<idl.UnlinkedConstOperation> _value) {
     assert(!_finished);
-    _strings = _value;
+    _operations = _value;
   }
 
   @override
@@ -2452,99 +1734,70 @@
     _references = _value;
   }
 
-  UnlinkedConstBuilder({List<UnlinkedConstOperation> operations, List<int> ints, List<double> doubles, List<String> strings, List<EntityRefBuilder> references})
-    : _operations = operations,
-      _ints = ints,
-      _doubles = doubles,
-      _strings = strings,
-      _references = references;
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_operations;
-    fb.Offset offset_ints;
-    fb.Offset offset_doubles;
-    fb.Offset offset_strings;
-    fb.Offset offset_references;
-    if (!(_operations == null || _operations.isEmpty)) {
-      offset_operations = fbBuilder.writeListUint32(_operations.map((b) => b.index).toList());
-    }
-    if (!(_ints == null || _ints.isEmpty)) {
-      offset_ints = fbBuilder.writeListUint32(_ints);
-    }
-    if (!(_doubles == null || _doubles.isEmpty)) {
-      offset_doubles = fbBuilder.writeListFloat64(_doubles);
-    }
-    if (!(_strings == null || _strings.isEmpty)) {
-      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    if (!(_references == null || _references.isEmpty)) {
-      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_operations != null) {
-      fbBuilder.addOffset(0, offset_operations);
-    }
-    if (offset_ints != null) {
-      fbBuilder.addOffset(1, offset_ints);
-    }
-    if (offset_doubles != null) {
-      fbBuilder.addOffset(2, offset_doubles);
-    }
-    if (offset_strings != null) {
-      fbBuilder.addOffset(3, offset_strings);
-    }
-    if (offset_references != null) {
-      fbBuilder.addOffset(4, offset_references);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * 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 operations to execute (starting with an empty stack) to form
-   * the constant value.
-   */
-  List<UnlinkedConstOperation> get operations;
-
-  /**
-   * Sequence of unsigned 32-bit integers consumed by the operations
-   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
-   * `makeList`, and `makeMap`.
-   */
-  List<int> get ints;
-
-  /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
-   */
-  List<double> get doubles;
+  @override
+  List<String> get strings => _strings ??= <String>[];
 
   /**
    * Sequence of strings consumed by the operations `pushString` and
    * `invokeConstructor`.
    */
-  List<String> get strings;
+  void set strings(List<String> _value) {
+    assert(!_finished);
+    _strings = _value;
+  }
 
-  /**
-   * 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.
-   */
-  List<EntityRef> get references;
+  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.writeListUint32(_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(0, offset_doubles);
+    }
+    if (offset_ints != null) {
+      fbBuilder.addOffset(1, offset_ints);
+    }
+    if (_isInvalid == true) {
+      fbBuilder.addBool(2, true);
+    }
+    if (offset_operations != null) {
+      fbBuilder.addOffset(3, offset_operations);
+    }
+    if (offset_references != null) {
+      fbBuilder.addOffset(4, offset_references);
+    }
+    if (offset_strings != null) {
+      fbBuilder.addOffset(5, offset_strings);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedConstReader extends fb.TableReader<_UnlinkedConstImpl> {
@@ -2554,21 +1807,22 @@
   _UnlinkedConstImpl createObject(fb.BufferPointer bp) => new _UnlinkedConstImpl(bp);
 }
 
-class _UnlinkedConstImpl extends Object with _UnlinkedConstMixin implements UnlinkedConst {
+class _UnlinkedConstImpl extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
   final fb.BufferPointer _bp;
 
   _UnlinkedConstImpl(this._bp);
 
-  List<UnlinkedConstOperation> _operations;
-  List<int> _ints;
   List<double> _doubles;
+  List<int> _ints;
+  bool _isInvalid;
+  List<idl.UnlinkedConstOperation> _operations;
+  List<idl.EntityRef> _references;
   List<String> _strings;
-  List<EntityRef> _references;
 
   @override
-  List<UnlinkedConstOperation> get operations {
-    _operations ??= const fb.ListReader<UnlinkedConstOperation>(const _UnlinkedConstOperationReader()).vTableGet(_bp, 0, const <UnlinkedConstOperation>[]);
-    return _operations;
+  List<double> get doubles {
+    _doubles ??= const fb.Float64ListReader().vTableGet(_bp, 0, const <double>[]);
+    return _doubles;
   }
 
   @override
@@ -2578,54 +1832,206 @@
   }
 
   @override
-  List<double> get doubles {
-    _doubles ??= const fb.Float64ListReader().vTableGet(_bp, 2, const <double>[]);
-    return _doubles;
+  bool get isInvalid {
+    _isInvalid ??= const fb.BoolReader().vTableGet(_bp, 2, false);
+    return _isInvalid;
+  }
+
+  @override
+  List<idl.UnlinkedConstOperation> get operations {
+    _operations ??= const fb.ListReader<idl.UnlinkedConstOperation>(const _UnlinkedConstOperationReader()).vTableGet(_bp, 3, const <idl.UnlinkedConstOperation>[]);
+    return _operations;
+  }
+
+  @override
+  List<idl.EntityRef> get references {
+    _references ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 4, const <idl.EntityRef>[]);
+    return _references;
   }
 
   @override
   List<String> get strings {
-    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 3, const <String>[]);
+    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 5, const <String>[]);
     return _strings;
   }
-
-  @override
-  List<EntityRef> get references {
-    _references ??= const fb.ListReader<EntityRef>(const _EntityRefReader()).vTableGet(_bp, 4, const <EntityRef>[]);
-    return _references;
-  }
 }
 
-abstract class _UnlinkedConstMixin implements UnlinkedConst {
+abstract class _UnlinkedConstMixin implements idl.UnlinkedConst {
   @override
   Map<String, Object> toMap() => {
-    "operations": operations,
-    "ints": ints,
     "doubles": doubles,
-    "strings": strings,
+    "ints": ints,
+    "isInvalid": isInvalid,
+    "operations": operations,
     "references": references,
+    "strings": strings,
   };
 }
 
-class UnlinkedDocumentationCommentBuilder extends Object with _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
+class UnlinkedConstructorInitializerBuilder extends Object with _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
   bool _finished = false;
 
-  String _text;
-  int _offset;
-  int _length;
+  List<UnlinkedConstBuilder> _arguments;
+  UnlinkedConstBuilder _expression;
+  idl.UnlinkedConstructorInitializerKind _kind;
+  String _name;
 
   @override
-  String get text => _text ??= '';
+  List<UnlinkedConstBuilder> get arguments => _arguments ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Text of the documentation comment, with '\r\n' replaced by '\n'.
-   *
-   * References appearing within the doc comment in square brackets are not
-   * specially encoded.
+   * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
+   * invocation.  Otherwise empty.
    */
-  void set text(String _value) {
+  void set arguments(List<UnlinkedConstBuilder> _value) {
     assert(!_finished);
-    _text = _value;
+    _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(0, offset_arguments);
+    }
+    if (offset_expression != null) {
+      fbBuilder.addOffset(1, offset_expression);
+    }
+    if (_kind != null && _kind != idl.UnlinkedConstructorInitializerKind.field) {
+      fbBuilder.addUint32(2, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(3, 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, 0, 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, 3, '');
+    return _name;
+  }
+}
+
+abstract class _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
+  @override
+  Map<String, Object> toMap() => {
+    "arguments": arguments,
+    "expression": expression,
+    "kind": kind,
+    "name": name,
+  };
+}
+
+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
@@ -2642,21 +2048,23 @@
   }
 
   @override
-  int get length => _length ??= 0;
+  String get text => _text ??= '';
 
   /**
-   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+   * 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 length(int _value) {
+  void set text(String _value) {
     assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _length = _value;
+    _text = _value;
   }
 
-  UnlinkedDocumentationCommentBuilder({String text, int offset, int length})
-    : _text = text,
+  UnlinkedDocumentationCommentBuilder({int length, int offset, String text})
+    : _length = length,
       _offset = offset,
-      _length = length;
+      _text = text;
 
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
@@ -2666,44 +2074,19 @@
       offset_text = fbBuilder.writeString(_text);
     }
     fbBuilder.startTable();
-    if (offset_text != null) {
-      fbBuilder.addOffset(0, offset_text);
+    if (_length != null && _length != 0) {
+      fbBuilder.addUint32(0, _length);
     }
     if (_offset != null && _offset != 0) {
       fbBuilder.addUint32(1, _offset);
     }
-    if (_length != null && _length != 0) {
-      fbBuilder.addUint32(2, _length);
+    if (offset_text != null) {
+      fbBuilder.addOffset(2, offset_text);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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();
 
@@ -2711,19 +2094,19 @@
   _UnlinkedDocumentationCommentImpl createObject(fb.BufferPointer bp) => new _UnlinkedDocumentationCommentImpl(bp);
 }
 
-class _UnlinkedDocumentationCommentImpl extends Object with _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
+class _UnlinkedDocumentationCommentImpl extends Object with _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
   final fb.BufferPointer _bp;
 
   _UnlinkedDocumentationCommentImpl(this._bp);
 
-  String _text;
-  int _offset;
   int _length;
+  int _offset;
+  String _text;
 
   @override
-  String get text {
-    _text ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _text;
+  int get length {
+    _length ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _length;
   }
 
   @override
@@ -2733,30 +2116,54 @@
   }
 
   @override
-  int get length {
-    _length ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _length;
+  String get text {
+    _text ??= const fb.StringReader().vTableGet(_bp, 2, '');
+    return _text;
   }
 }
 
-abstract class _UnlinkedDocumentationCommentMixin implements UnlinkedDocumentationComment {
+abstract class _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
   @override
   Map<String, Object> toMap() => {
-    "text": text,
-    "offset": offset,
     "length": length,
+    "offset": offset,
+    "text": text,
   };
 }
 
-class UnlinkedEnumBuilder extends Object with _UnlinkedEnumMixin implements UnlinkedEnum {
+class UnlinkedEnumBuilder extends Object with _UnlinkedEnumMixin implements idl.UnlinkedEnum {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
   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 ??= '';
 
   /**
@@ -2780,18 +2187,6 @@
   }
 
   @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
   List<UnlinkedEnumValueBuilder> get values => _values ??= <UnlinkedEnumValueBuilder>[];
 
   /**
@@ -2802,71 +2197,52 @@
     _values = _value;
   }
 
-  UnlinkedEnumBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedEnumValueBuilder> values})
-    : _name = name,
-      _nameOffset = nameOffset,
+  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_name;
+    fb.Offset offset_annotations;
     fb.Offset offset_documentationComment;
+    fb.Offset offset_name;
     fb.Offset offset_values;
-    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 (_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_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addUint32(1, _nameOffset);
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(0, offset_annotations);
     }
     if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
+      fbBuilder.addOffset(1, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(2, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(3, _nameOffset);
     }
     if (offset_values != null) {
-      fbBuilder.addOffset(3, offset_values);
+      fbBuilder.addOffset(4, offset_values);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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();
 
@@ -2874,80 +2250,65 @@
   _UnlinkedEnumImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumImpl(bp);
 }
 
-class _UnlinkedEnumImpl extends Object with _UnlinkedEnumMixin implements UnlinkedEnum {
+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;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedEnumValue> _values;
+  List<idl.UnlinkedEnumValue> _values;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 1, null);
+    return _documentationComment;
+  }
 
   @override
   String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    _name ??= const fb.StringReader().vTableGet(_bp, 2, '');
     return _name;
   }
 
   @override
   int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 3, 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>[]);
+  List<idl.UnlinkedEnumValue> get values {
+    _values ??= const fb.ListReader<idl.UnlinkedEnumValue>(const _UnlinkedEnumValueReader()).vTableGet(_bp, 4, const <idl.UnlinkedEnumValue>[]);
     return _values;
   }
 }
 
-abstract class _UnlinkedEnumMixin implements UnlinkedEnum {
+abstract class _UnlinkedEnumMixin implements idl.UnlinkedEnum {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "documentationComment": documentationComment,
     "name": name,
     "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
     "values": values,
   };
 }
 
-class UnlinkedEnumValueBuilder extends Object with _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
+class UnlinkedEnumValueBuilder extends Object with _UnlinkedEnumValueMixin implements idl.UnlinkedEnumValue {
   bool _finished = false;
 
+  UnlinkedDocumentationCommentBuilder _documentationComment;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-
-  @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;
-  }
 
   @override
   UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
@@ -2961,127 +2322,11 @@
     _documentationComment = _value;
   }
 
-  UnlinkedEnumValueBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _documentationComment = documentationComment;
-
-  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.addUint32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * 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 extends Object with _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedEnumValueImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _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
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-}
-
-abstract class _UnlinkedEnumValueMixin implements UnlinkedEnumValue {
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-  };
-}
-
-class UnlinkedExecutableBuilder extends Object with _UnlinkedExecutableMixin implements UnlinkedExecutable {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  EntityRefBuilder _returnType;
-  List<UnlinkedParamBuilder> _parameters;
-  UnlinkedExecutableKind _kind;
-  bool _isAbstract;
-  bool _isStatic;
-  bool _isConst;
-  bool _isFactory;
-  bool _isExternal;
-  int _inferredReturnTypeSlot;
-
   @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.
+   * Name of the enumerated value.
    */
   void set name(String _value) {
     assert(!_finished);
@@ -3092,10 +2337,7 @@
   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(); }").
+   * Offset of the enum value name relative to the beginning of the file.
    */
   void set nameOffset(int _value) {
     assert(!_finished);
@@ -3103,6 +2345,122 @@
     _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(0, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(1, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(2, _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, 0, null);
+    return _documentationComment;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _nameOffset;
+  }
+}
+
+abstract class _UnlinkedEnumValueMixin implements idl.UnlinkedEnumValue {
+  @override
+  Map<String, Object> toMap() => {
+    "documentationComment": documentationComment,
+    "name": name,
+    "nameOffset": nameOffset,
+  };
+}
+
+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 _isStatic;
+  idl.UnlinkedExecutableKind _kind;
+  String _name;
+  int _nameOffset;
+  List<UnlinkedParamBuilder> _parameters;
+  EntityRefBuilder _returnType;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
+
+  @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;
 
@@ -3116,52 +2474,19 @@
   }
 
   @override
-  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+  int get inferredReturnTypeSlot => _inferredReturnTypeSlot ??= 0;
 
   /**
-   * Type parameters of the executable, if any.  Empty if support for generic
-   * method syntax is disabled.
+   * 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 typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+  void set inferredReturnTypeSlot(int _value) {
     assert(!_finished);
-    _typeParameters = _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.
-   */
-  void set returnType(EntityRefBuilder _value) {
-    assert(!_finished);
-    _returnType = _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
-  UnlinkedExecutableKind get kind => _kind ??= UnlinkedExecutableKind.functionOrMethod;
-
-  /**
-   * The kind of the executable (function/method, getter, setter, or
-   * constructor).
-   */
-  void set kind(UnlinkedExecutableKind _value) {
-    assert(!_finished);
-    _kind = _value;
+    assert(_value == null || _value >= 0);
+    _inferredReturnTypeSlot = _value;
   }
 
   @override
@@ -3176,6 +2501,39 @@
   }
 
   @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 isStatic => _isStatic ??= false;
 
   /**
@@ -3191,148 +2549,32 @@
   }
 
   @override
-  bool get isConst => _isConst ??= false;
+  idl.UnlinkedExecutableKind get kind => _kind ??= idl.UnlinkedExecutableKind.functionOrMethod;
 
   /**
-   * Indicates whether the executable is declared using the `const` keyword.
+   * The kind of the executable (function/method, getter, setter, or
+   * constructor).
    */
-  void set isConst(bool _value) {
+  void set kind(idl.UnlinkedExecutableKind _value) {
     assert(!_finished);
-    _isConst = _value;
+    _kind = _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 isExternal => _isExternal ??= false;
-
-  /**
-   * Indicates whether the executable is declared using the `external` keyword.
-   */
-  void set isExternal(bool _value) {
-    assert(!_finished);
-    _isExternal = _value;
-  }
-
-  @override
-  int get inferredReturnTypeSlot => _inferredReturnTypeSlot ??= 0;
-
-  /**
-   * If this executable's return type is inferrable, nonzero slot id
-   * identifying which entry in [LinkedLibrary.types] contains the inferred
-   * return type.  If there is no matching entry in [LinkedLibrary.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;
-  }
-
-  UnlinkedExecutableBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder returnType, List<UnlinkedParamBuilder> parameters, UnlinkedExecutableKind kind, bool isAbstract, bool isStatic, bool isConst, bool isFactory, bool isExternal, int inferredReturnTypeSlot})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _documentationComment = documentationComment,
-      _typeParameters = typeParameters,
-      _returnType = returnType,
-      _parameters = parameters,
-      _kind = kind,
-      _isAbstract = isAbstract,
-      _isStatic = isStatic,
-      _isConst = isConst,
-      _isFactory = isFactory,
-      _isExternal = isExternal,
-      _inferredReturnTypeSlot = inferredReturnTypeSlot;
-
-  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.addUint32(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.addUint32(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 (_isExternal == true) {
-      fbBuilder.addBool(11, true);
-    }
-    if (_inferredReturnTypeSlot != null && _inferredReturnTypeSlot != 0) {
-      fbBuilder.addUint32(12, _inferredReturnTypeSlot);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * Unlinked summary information about a function, method, getter, or setter
- * declaration.
- */
-abstract class UnlinkedExecutable extends base.SummaryClass {
+  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.
    */
-  String get name;
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
 
   /**
    * Offset of the executable name relative to the beginning of the file.  For
@@ -3340,76 +2582,145 @@
    * 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;
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
 
-  /**
-   * 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 executable is a
-   * constructor or the return type is implicit.
-   */
-  EntityRef get returnType;
+  @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.
    */
-  List<UnlinkedParam> get parameters;
+  void set parameters(List<UnlinkedParamBuilder> _value) {
+    assert(!_finished);
+    _parameters = _value;
+  }
+
+  @override
+  EntityRefBuilder get returnType => _returnType;
 
   /**
-   * The kind of the executable (function/method, getter, setter, or
-   * constructor).
+   * Declared return type of the executable.  Absent if the executable is a
+   * constructor or the return type is implicit.
    */
-  UnlinkedExecutableKind get kind;
+  void set returnType(EntityRefBuilder _value) {
+    assert(!_finished);
+    _returnType = _value;
+  }
+
+  @override
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
 
   /**
-   * Indicates whether the executable is declared using the `abstract` keyword.
+   * Type parameters of the executable, if any.  Empty if support for generic
+   * method syntax is disabled.
    */
-  bool get isAbstract;
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _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).
-   */
-  bool get isStatic;
+  UnlinkedExecutableBuilder({List<UnlinkedConstBuilder> annotations, List<UnlinkedConstructorInitializerBuilder> constantInitializers, UnlinkedDocumentationCommentBuilder documentationComment, int inferredReturnTypeSlot, bool isAbstract, bool isConst, bool isExternal, bool isFactory, bool isStatic, idl.UnlinkedExecutableKind kind, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters})
+    : _annotations = annotations,
+      _constantInitializers = constantInitializers,
+      _documentationComment = documentationComment,
+      _inferredReturnTypeSlot = inferredReturnTypeSlot,
+      _isAbstract = isAbstract,
+      _isConst = isConst,
+      _isExternal = isExternal,
+      _isFactory = isFactory,
+      _isStatic = isStatic,
+      _kind = kind,
+      _name = name,
+      _nameOffset = nameOffset,
+      _parameters = parameters,
+      _returnType = returnType,
+      _typeParameters = typeParameters;
 
-  /**
-   * 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 is declared using the `external` keyword.
-   */
-  bool get isExternal;
-
-  /**
-   * If this executable's return type is inferrable, nonzero slot id
-   * identifying which entry in [LinkedLibrary.types] contains the inferred
-   * return type.  If there is no matching entry in [LinkedLibrary.types], then
-   * no return type was inferred for this variable, so its static type is
-   * `dynamic`.
-   */
-  int get inferredReturnTypeSlot;
+  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_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 (!(_constantInitializers == null || _constantInitializers.isEmpty)) {
+      offset_constantInitializers = fbBuilder.writeList(_constantInitializers.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(0, offset_annotations);
+    }
+    if (offset_constantInitializers != null) {
+      fbBuilder.addOffset(1, offset_constantInitializers);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(2, offset_documentationComment);
+    }
+    if (_inferredReturnTypeSlot != null && _inferredReturnTypeSlot != 0) {
+      fbBuilder.addUint32(3, _inferredReturnTypeSlot);
+    }
+    if (_isAbstract == true) {
+      fbBuilder.addBool(4, true);
+    }
+    if (_isConst == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (_isExternal == true) {
+      fbBuilder.addBool(6, true);
+    }
+    if (_isFactory == true) {
+      fbBuilder.addBool(7, true);
+    }
+    if (_isStatic == true) {
+      fbBuilder.addBool(8, true);
+    }
+    if (_kind != null && _kind != idl.UnlinkedExecutableKind.functionOrMethod) {
+      fbBuilder.addUint32(9, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(10, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(11, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(12, offset_parameters);
+    }
+    if (offset_returnType != null) {
+      fbBuilder.addOffset(13, offset_returnType);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(14, offset_typeParameters);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedExecutableReader extends fb.TableReader<_UnlinkedExecutableImpl> {
@@ -3419,129 +2730,157 @@
   _UnlinkedExecutableImpl createObject(fb.BufferPointer bp) => new _UnlinkedExecutableImpl(bp);
 }
 
-class _UnlinkedExecutableImpl extends Object with _UnlinkedExecutableMixin implements UnlinkedExecutable {
+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 _isStatic;
+  idl.UnlinkedExecutableKind _kind;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  EntityRef _returnType;
-  List<UnlinkedParam> _parameters;
-  UnlinkedExecutableKind _kind;
-  bool _isAbstract;
-  bool _isStatic;
-  bool _isConst;
-  bool _isFactory;
-  bool _isExternal;
-  int _inferredReturnTypeSlot;
+  List<idl.UnlinkedParam> _parameters;
+  idl.EntityRef _returnType;
+  List<idl.UnlinkedTypeParam> _typeParameters;
 
   @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, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
+  List<idl.UnlinkedConstructorInitializer> get constantInitializers {
+    _constantInitializers ??= const fb.ListReader<idl.UnlinkedConstructorInitializer>(const _UnlinkedConstructorInitializerReader()).vTableGet(_bp, 1, const <idl.UnlinkedConstructorInitializer>[]);
+    return _constantInitializers;
   }
 
   @override
-  UnlinkedDocumentationComment get documentationComment {
+  idl.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
-  EntityRef get returnType {
-    _returnType ??= const _EntityRefReader().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 ??= const _UnlinkedExecutableKindReader().vTableGet(_bp, 6, UnlinkedExecutableKind.functionOrMethod);
-    return _kind;
+  int get inferredReturnTypeSlot {
+    _inferredReturnTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _inferredReturnTypeSlot;
   }
 
   @override
   bool get isAbstract {
-    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 7, false);
+    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 4, false);
     return _isAbstract;
   }
 
   @override
+  bool get isConst {
+    _isConst ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    return _isConst;
+  }
+
+  @override
+  bool get isExternal {
+    _isExternal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
+    return _isExternal;
+  }
+
+  @override
+  bool get isFactory {
+    _isFactory ??= const fb.BoolReader().vTableGet(_bp, 7, false);
+    return _isFactory;
+  }
+
+  @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;
+  idl.UnlinkedExecutableKind get kind {
+    _kind ??= const _UnlinkedExecutableKindReader().vTableGet(_bp, 9, idl.UnlinkedExecutableKind.functionOrMethod);
+    return _kind;
   }
 
   @override
-  bool get isFactory {
-    _isFactory ??= const fb.BoolReader().vTableGet(_bp, 10, false);
-    return _isFactory;
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 10, '');
+    return _name;
   }
 
   @override
-  bool get isExternal {
-    _isExternal ??= const fb.BoolReader().vTableGet(_bp, 11, false);
-    return _isExternal;
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 11, 0);
+    return _nameOffset;
   }
 
   @override
-  int get inferredReturnTypeSlot {
-    _inferredReturnTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 12, 0);
-    return _inferredReturnTypeSlot;
+  List<idl.UnlinkedParam> get parameters {
+    _parameters ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 12, const <idl.UnlinkedParam>[]);
+    return _parameters;
+  }
+
+  @override
+  idl.EntityRef get returnType {
+    _returnType ??= const _EntityRefReader().vTableGet(_bp, 13, null);
+    return _returnType;
+  }
+
+  @override
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 14, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
   }
 }
 
-abstract class _UnlinkedExecutableMixin implements UnlinkedExecutable {
+abstract class _UnlinkedExecutableMixin implements idl.UnlinkedExecutable {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "constantInitializers": constantInitializers,
+    "documentationComment": documentationComment,
+    "inferredReturnTypeSlot": inferredReturnTypeSlot,
+    "isAbstract": isAbstract,
+    "isConst": isConst,
+    "isExternal": isExternal,
+    "isFactory": isFactory,
+    "isStatic": isStatic,
+    "kind": kind,
     "name": name,
     "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "returnType": returnType,
     "parameters": parameters,
-    "kind": kind,
-    "isAbstract": isAbstract,
-    "isStatic": isStatic,
-    "isConst": isConst,
-    "isFactory": isFactory,
-    "isExternal": isExternal,
-    "inferredReturnTypeSlot": inferredReturnTypeSlot,
+    "returnType": returnType,
+    "typeParameters": typeParameters,
   };
 }
 
-class UnlinkedExportNonPublicBuilder extends Object with _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
+class UnlinkedExportNonPublicBuilder extends Object with _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
   int _offset;
-  int _uriOffset;
   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;
@@ -3556,19 +2895,6 @@
   }
 
   @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;
-  }
-
-  @override
   int get uriEnd => _uriEnd ??= 0;
 
   /**
@@ -3581,50 +2907,47 @@
     _uriEnd = _value;
   }
 
-  UnlinkedExportNonPublicBuilder({int offset, int uriOffset, int uriEnd})
-    : _offset = offset,
-      _uriOffset = uriOffset,
-      _uriEnd = uriEnd;
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fbBuilder.startTable();
-    if (_offset != null && _offset != 0) {
-      fbBuilder.addUint32(0, _offset);
-    }
-    if (_uriOffset != null && _uriOffset != 0) {
-      fbBuilder.addUint32(1, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addUint32(2, _uriEnd);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * Unlinked summary information about an export declaration (stored outside
- * [UnlinkedPublicNamespace]).
- */
-abstract class UnlinkedExportNonPublic extends base.SummaryClass {
-
-  /**
-   * Offset of the "export" keyword.
-   */
-  int get offset;
+  @override
+  int get uriOffset => _uriOffset ??= 0;
 
   /**
    * Offset of the URI string (including quotes) relative to the beginning of
    * the file.
    */
-  int get uriOffset;
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
 
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  int get uriEnd;
+  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(0, offset_annotations);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(1, _offset);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(2, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(3, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedExportNonPublicReader extends fb.TableReader<_UnlinkedExportNonPublicImpl> {
@@ -3634,25 +2957,26 @@
   _UnlinkedExportNonPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportNonPublicImpl(bp);
 }
 
-class _UnlinkedExportNonPublicImpl extends Object with _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
+class _UnlinkedExportNonPublicImpl extends Object with _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
   final fb.BufferPointer _bp;
 
   _UnlinkedExportNonPublicImpl(this._bp);
 
+  List<idl.UnlinkedConst> _annotations;
   int _offset;
-  int _uriOffset;
   int _uriEnd;
+  int _uriOffset;
 
   @override
-  int get offset {
-    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
-    return _offset;
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _uriOffset;
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _offset;
   }
 
   @override
@@ -3660,33 +2984,29 @@
     _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 _UnlinkedExportNonPublicMixin implements UnlinkedExportNonPublic {
+abstract class _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
     "offset": offset,
-    "uriOffset": uriOffset,
     "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
   };
 }
 
-class UnlinkedExportPublicBuilder extends Object with _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
+class UnlinkedExportPublicBuilder extends Object with _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
   bool _finished = false;
 
-  String _uri;
   List<UnlinkedCombinatorBuilder> _combinators;
-
-  @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;
-  }
+  String _uri;
 
   @override
   List<UnlinkedCombinatorBuilder> get combinators => _combinators ??= <UnlinkedCombinatorBuilder>[];
@@ -3699,47 +3019,41 @@
     _combinators = _value;
   }
 
-  UnlinkedExportPublicBuilder({String uri, List<UnlinkedCombinatorBuilder> combinators})
-    : _uri = uri,
-      _combinators = combinators;
-
-  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();
-  }
-}
-
-/**
- * Unlinked summary information about an export declaration (stored inside
- * [UnlinkedPublicNamespace]).
- */
-abstract class UnlinkedExportPublic extends base.SummaryClass {
+  @override
+  String get uri => _uri ??= '';
 
   /**
    * URI used in the source code to reference the exported library.
    */
-  String get uri;
+  void set uri(String _value) {
+    assert(!_finished);
+    _uri = _value;
+  }
 
-  /**
-   * Combinators contained in this import declaration.
-   */
-  List<UnlinkedCombinator> get combinators;
+  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(0, offset_combinators);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(1, offset_uri);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedExportPublicReader extends fb.TableReader<_UnlinkedExportPublicImpl> {
@@ -3749,85 +3063,58 @@
   _UnlinkedExportPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportPublicImpl(bp);
 }
 
-class _UnlinkedExportPublicImpl extends Object with _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
+class _UnlinkedExportPublicImpl extends Object with _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
   final fb.BufferPointer _bp;
 
   _UnlinkedExportPublicImpl(this._bp);
 
+  List<idl.UnlinkedCombinator> _combinators;
   String _uri;
-  List<UnlinkedCombinator> _combinators;
+
+  @override
+  List<idl.UnlinkedCombinator> get combinators {
+    _combinators ??= const fb.ListReader<idl.UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 0, const <idl.UnlinkedCombinator>[]);
+    return _combinators;
+  }
 
   @override
   String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    _uri ??= const fb.StringReader().vTableGet(_bp, 1, '');
     return _uri;
   }
-
-  @override
-  List<UnlinkedCombinator> get combinators {
-    _combinators ??= const fb.ListReader<UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 1, const <UnlinkedCombinator>[]);
-    return _combinators;
-  }
 }
 
-abstract class _UnlinkedExportPublicMixin implements UnlinkedExportPublic {
+abstract class _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
   @override
   Map<String, Object> toMap() => {
-    "uri": uri,
     "combinators": combinators,
+    "uri": uri,
   };
 }
 
-class UnlinkedImportBuilder extends Object with _UnlinkedImportMixin implements UnlinkedImport {
+class UnlinkedImportBuilder extends Object with _UnlinkedImportMixin implements idl.UnlinkedImport {
   bool _finished = false;
 
-  String _uri;
-  int _offset;
-  int _prefixReference;
+  List<UnlinkedConstBuilder> _annotations;
   List<UnlinkedCombinatorBuilder> _combinators;
   bool _isDeferred;
   bool _isImplicit;
-  int _uriOffset;
-  int _uriEnd;
+  int _offset;
   int _prefixOffset;
+  int _prefixReference;
+  String _uri;
+  int _uriEnd;
+  int _uriOffset;
 
   @override
-  String get uri => _uri ??= '';
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * URI used in the source code to reference the imported library.
+   * Annotations for this import declaration.
    */
-  void set uri(String _value) {
+  void set annotations(List<UnlinkedConstBuilder> _value) {
     assert(!_finished);
-    _uri = _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 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;
+    _annotations = _value;
   }
 
   @override
@@ -3864,16 +3151,55 @@
   }
 
   @override
-  int get uriOffset => _uriOffset ??= 0;
+  int get offset => _offset ??= 0;
 
   /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.  If [isImplicit] is true, zero.
+   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
+   * is true, zero.
    */
-  void set uriOffset(int _value) {
+  void set offset(int _value) {
     assert(!_finished);
     assert(_value == null || _value >= 0);
-    _uriOffset = _value;
+    _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
@@ -3890,128 +3216,78 @@
   }
 
   @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;
-  }
-
-  UnlinkedImportBuilder({String uri, int offset, int prefixReference, List<UnlinkedCombinatorBuilder> combinators, bool isDeferred, bool isImplicit, int uriOffset, int uriEnd, int prefixOffset})
-    : _uri = uri,
-      _offset = offset,
-      _prefixReference = prefixReference,
-      _combinators = combinators,
-      _isDeferred = isDeferred,
-      _isImplicit = isImplicit,
-      _uriOffset = uriOffset,
-      _uriEnd = uriEnd,
-      _prefixOffset = prefixOffset;
-
-  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.addUint32(1, _offset);
-    }
-    if (_prefixReference != null && _prefixReference != 0) {
-      fbBuilder.addUint32(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.addUint32(6, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addUint32(7, _uriEnd);
-    }
-    if (_prefixOffset != null && _prefixOffset != 0) {
-      fbBuilder.addUint32(8, _prefixOffset);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * 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;
+  int get uriOffset => _uriOffset ??= 0;
 
   /**
    * Offset of the URI string (including quotes) relative to the beginning of
    * the file.  If [isImplicit] is true, zero.
    */
-  int get uriOffset;
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
 
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.  If [isImplicit] is true, zero.
-   */
-  int get uriEnd;
+  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;
 
-  /**
-   * Offset of the prefix name relative to the beginning of the file, or zero
-   * if there is no prefix.
-   */
-  int get prefixOffset;
+  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(0, offset_annotations);
+    }
+    if (offset_combinators != null) {
+      fbBuilder.addOffset(1, offset_combinators);
+    }
+    if (_isDeferred == true) {
+      fbBuilder.addBool(2, true);
+    }
+    if (_isImplicit == true) {
+      fbBuilder.addBool(3, true);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(4, _offset);
+    }
+    if (_prefixOffset != null && _prefixOffset != 0) {
+      fbBuilder.addUint32(5, _prefixOffset);
+    }
+    if (_prefixReference != null && _prefixReference != 0) {
+      fbBuilder.addUint32(6, _prefixReference);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(7, offset_uri);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(8, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(9, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedImportReader extends fb.TableReader<_UnlinkedImportImpl> {
@@ -4021,159 +3297,155 @@
   _UnlinkedImportImpl createObject(fb.BufferPointer bp) => new _UnlinkedImportImpl(bp);
 }
 
-class _UnlinkedImportImpl extends Object with _UnlinkedImportMixin implements UnlinkedImport {
+class _UnlinkedImportImpl extends Object with _UnlinkedImportMixin implements idl.UnlinkedImport {
   final fb.BufferPointer _bp;
 
   _UnlinkedImportImpl(this._bp);
 
-  String _uri;
-  int _offset;
-  int _prefixReference;
-  List<UnlinkedCombinator> _combinators;
+  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedCombinator> _combinators;
   bool _isDeferred;
   bool _isImplicit;
-  int _uriOffset;
-  int _uriEnd;
+  int _offset;
   int _prefixOffset;
+  int _prefixReference;
+  String _uri;
+  int _uriEnd;
+  int _uriOffset;
 
   @override
-  String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _uri;
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get offset {
-    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _offset;
-  }
-
-  @override
-  int get prefixReference {
-    _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _prefixReference;
-  }
-
-  @override
-  List<UnlinkedCombinator> get combinators {
-    _combinators ??= const fb.ListReader<UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 3, const <UnlinkedCombinator>[]);
+  List<idl.UnlinkedCombinator> get combinators {
+    _combinators ??= const fb.ListReader<idl.UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 1, const <idl.UnlinkedCombinator>[]);
     return _combinators;
   }
 
   @override
   bool get isDeferred {
-    _isDeferred ??= const fb.BoolReader().vTableGet(_bp, 4, false);
+    _isDeferred ??= const fb.BoolReader().vTableGet(_bp, 2, false);
     return _isDeferred;
   }
 
   @override
   bool get isImplicit {
-    _isImplicit ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    _isImplicit ??= const fb.BoolReader().vTableGet(_bp, 3, false);
     return _isImplicit;
   }
 
   @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
-    return _uriOffset;
-  }
-
-  @override
-  int get uriEnd {
-    _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
-    return _uriEnd;
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 4, 0);
+    return _offset;
   }
 
   @override
   int get prefixOffset {
-    _prefixOffset ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    _prefixOffset ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
     return _prefixOffset;
   }
+
+  @override
+  int get prefixReference {
+    _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
+    return _prefixReference;
+  }
+
+  @override
+  String get uri {
+    _uri ??= const fb.StringReader().vTableGet(_bp, 7, '');
+    return _uri;
+  }
+
+  @override
+  int get uriEnd {
+    _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    return _uriEnd;
+  }
+
+  @override
+  int get uriOffset {
+    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
+    return _uriOffset;
+  }
 }
 
-abstract class _UnlinkedImportMixin implements UnlinkedImport {
+abstract class _UnlinkedImportMixin implements idl.UnlinkedImport {
   @override
   Map<String, Object> toMap() => {
-    "uri": uri,
-    "offset": offset,
-    "prefixReference": prefixReference,
+    "annotations": annotations,
     "combinators": combinators,
     "isDeferred": isDeferred,
     "isImplicit": isImplicit,
-    "uriOffset": uriOffset,
-    "uriEnd": uriEnd,
+    "offset": offset,
     "prefixOffset": prefixOffset,
+    "prefixReference": prefixReference,
+    "uri": uri,
+    "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
   };
 }
 
-class UnlinkedParamBuilder extends Object with _UnlinkedParamMixin implements UnlinkedParam {
+class UnlinkedParamBuilder extends Object with _UnlinkedParamMixin implements idl.UnlinkedParam {
   bool _finished = false;
 
-  String _name;
-  int _nameOffset;
-  EntityRefBuilder _type;
-  List<UnlinkedParamBuilder> _parameters;
-  UnlinkedParamKind _kind;
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedConstBuilder _defaultValue;
+  int _inferredTypeSlot;
   bool _isFunctionTyped;
   bool _isInitializingFormal;
-  int _inferredTypeSlot;
+  idl.UnlinkedParamKind _kind;
+  String _name;
+  int _nameOffset;
+  List<UnlinkedParamBuilder> _parameters;
+  EntityRefBuilder _type;
 
   @override
-  String get name => _name ??= '';
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Name of the parameter.
+   * Annotations for this parameter.
    */
-  void set name(String _value) {
+  void set annotations(List<UnlinkedConstBuilder> _value) {
     assert(!_finished);
-    _name = _value;
+    _annotations = _value;
   }
 
   @override
-  int get nameOffset => _nameOffset ??= 0;
+  UnlinkedConstBuilder get defaultValue => _defaultValue;
 
   /**
-   * Offset of the parameter name relative to the beginning of the file.
+   * 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 nameOffset(int _value) {
+  void set defaultValue(UnlinkedConstBuilder _value) {
+    assert(!_finished);
+    _defaultValue = _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);
-    _nameOffset = _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
-  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
-  UnlinkedParamKind get kind => _kind ??= UnlinkedParamKind.required;
-
-  /**
-   * Kind of the parameter.
-   */
-  void set kind(UnlinkedParamKind _value) {
-    assert(!_finished);
-    _kind = _value;
+    _inferredTypeSlot = _value;
   }
 
   @override
@@ -4200,134 +3472,131 @@
   }
 
   @override
-  int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+  idl.UnlinkedParamKind get kind => _kind ??= idl.UnlinkedParamKind.required;
 
   /**
-   * If this parameter's type is inferrable, 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
-   * inferrable, 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.
+   * Kind of the parameter.
    */
-  void set inferredTypeSlot(int _value) {
+  void set kind(idl.UnlinkedParamKind _value) {
     assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _inferredTypeSlot = _value;
+    _kind = _value;
   }
 
-  UnlinkedParamBuilder({String name, int nameOffset, EntityRefBuilder type, List<UnlinkedParamBuilder> parameters, UnlinkedParamKind kind, bool isFunctionTyped, bool isInitializingFormal, int inferredTypeSlot})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _type = type,
-      _parameters = parameters,
-      _kind = kind,
-      _isFunctionTyped = isFunctionTyped,
-      _isInitializingFormal = isInitializingFormal,
-      _inferredTypeSlot = inferredTypeSlot;
-
-  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.addUint32(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.addUint32(4, _kind.index);
-    }
-    if (_isFunctionTyped == true) {
-      fbBuilder.addBool(5, true);
-    }
-    if (_isInitializingFormal == true) {
-      fbBuilder.addBool(6, true);
-    }
-    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
-      fbBuilder.addUint32(7, _inferredTypeSlot);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * Unlinked summary information about a function parameter.
- */
-abstract class UnlinkedParam extends base.SummaryClass {
+  @override
+  String get name => _name ??= '';
 
   /**
    * Name of the parameter.
    */
-  String get name;
+  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.
    */
-  int get nameOffset;
+  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.
    */
-  EntityRef get type;
+  void set type(EntityRefBuilder _value) {
+    assert(!_finished);
+    _type = _value;
+  }
 
-  /**
-   * If [isFunctionTyped] is `true`, the parameters of the function type.
-   */
-  List<UnlinkedParam> get parameters;
+  UnlinkedParamBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedConstBuilder defaultValue, int inferredTypeSlot, bool isFunctionTyped, bool isInitializingFormal, idl.UnlinkedParamKind kind, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder type})
+    : _annotations = annotations,
+      _defaultValue = defaultValue,
+      _inferredTypeSlot = inferredTypeSlot,
+      _isFunctionTyped = isFunctionTyped,
+      _isInitializingFormal = isInitializingFormal,
+      _kind = kind,
+      _name = name,
+      _nameOffset = nameOffset,
+      _parameters = parameters,
+      _type = type;
 
-  /**
-   * 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;
-
-  /**
-   * If this parameter's type is inferrable, 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
-   * inferrable, 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.
-   */
-  int get inferredTypeSlot;
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_defaultValue;
+    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 (_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(0, offset_annotations);
+    }
+    if (offset_defaultValue != null) {
+      fbBuilder.addOffset(1, offset_defaultValue);
+    }
+    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+      fbBuilder.addUint32(2, _inferredTypeSlot);
+    }
+    if (_isFunctionTyped == true) {
+      fbBuilder.addBool(3, true);
+    }
+    if (_isInitializingFormal == true) {
+      fbBuilder.addBool(4, true);
+    }
+    if (_kind != null && _kind != idl.UnlinkedParamKind.required) {
+      fbBuilder.addUint32(5, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(6, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(7, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(8, offset_parameters);
+    }
+    if (offset_type != null) {
+      fbBuilder.addOffset(9, offset_type);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedParamReader extends fb.TableReader<_UnlinkedParamImpl> {
@@ -4337,100 +3606,115 @@
   _UnlinkedParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedParamImpl(bp);
 }
 
-class _UnlinkedParamImpl extends Object with _UnlinkedParamMixin implements UnlinkedParam {
+class _UnlinkedParamImpl extends Object with _UnlinkedParamMixin implements idl.UnlinkedParam {
   final fb.BufferPointer _bp;
 
   _UnlinkedParamImpl(this._bp);
 
-  String _name;
-  int _nameOffset;
-  EntityRef _type;
-  List<UnlinkedParam> _parameters;
-  UnlinkedParamKind _kind;
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedConst _defaultValue;
+  int _inferredTypeSlot;
   bool _isFunctionTyped;
   bool _isInitializingFormal;
-  int _inferredTypeSlot;
+  idl.UnlinkedParamKind _kind;
+  String _name;
+  int _nameOffset;
+  List<idl.UnlinkedParam> _parameters;
+  idl.EntityRef _type;
 
   @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, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
+  idl.UnlinkedConst get defaultValue {
+    _defaultValue ??= const _UnlinkedConstReader().vTableGet(_bp, 1, null);
+    return _defaultValue;
   }
 
   @override
-  EntityRef get type {
-    _type ??= const _EntityRefReader().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 ??= const _UnlinkedParamKindReader().vTableGet(_bp, 4, UnlinkedParamKind.required);
-    return _kind;
+  int get inferredTypeSlot {
+    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _inferredTypeSlot;
   }
 
   @override
   bool get isFunctionTyped {
-    _isFunctionTyped ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    _isFunctionTyped ??= const fb.BoolReader().vTableGet(_bp, 3, false);
     return _isFunctionTyped;
   }
 
   @override
   bool get isInitializingFormal {
-    _isInitializingFormal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
+    _isInitializingFormal ??= const fb.BoolReader().vTableGet(_bp, 4, false);
     return _isInitializingFormal;
   }
 
   @override
-  int get inferredTypeSlot {
-    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
-    return _inferredTypeSlot;
+  idl.UnlinkedParamKind get kind {
+    _kind ??= const _UnlinkedParamKindReader().vTableGet(_bp, 5, idl.UnlinkedParamKind.required);
+    return _kind;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 6, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 7, 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, 9, null);
+    return _type;
   }
 }
 
-abstract class _UnlinkedParamMixin implements UnlinkedParam {
+abstract class _UnlinkedParamMixin implements idl.UnlinkedParam {
   @override
   Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "type": type,
-    "parameters": parameters,
-    "kind": kind,
+    "annotations": annotations,
+    "defaultValue": defaultValue,
+    "inferredTypeSlot": inferredTypeSlot,
     "isFunctionTyped": isFunctionTyped,
     "isInitializingFormal": isInitializingFormal,
-    "inferredTypeSlot": inferredTypeSlot,
+    "kind": kind,
+    "name": name,
+    "nameOffset": nameOffset,
+    "parameters": parameters,
+    "type": type,
   };
 }
 
-class UnlinkedPartBuilder extends Object with _UnlinkedPartMixin implements UnlinkedPart {
+class UnlinkedPartBuilder extends Object with _UnlinkedPartMixin implements idl.UnlinkedPart {
   bool _finished = false;
 
-  int _uriOffset;
+  List<UnlinkedConstBuilder> _annotations;
   int _uriEnd;
+  int _uriOffset;
 
   @override
-  int get uriOffset => _uriOffset ??= 0;
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
+   * Annotations for this part declaration.
    */
-  void set uriOffset(int _value) {
+  void set annotations(List<UnlinkedConstBuilder> _value) {
     assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _uriOffset = _value;
+    _annotations = _value;
   }
 
   @override
@@ -4446,40 +3730,43 @@
     _uriEnd = _value;
   }
 
-  UnlinkedPartBuilder({int uriOffset, int uriEnd})
-    : _uriOffset = uriOffset,
-      _uriEnd = uriEnd;
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fbBuilder.startTable();
-    if (_uriOffset != null && _uriOffset != 0) {
-      fbBuilder.addUint32(0, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addUint32(1, _uriEnd);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * Unlinked summary information about a part declaration.
- */
-abstract class UnlinkedPart extends base.SummaryClass {
+  @override
+  int get uriOffset => _uriOffset ??= 0;
 
   /**
    * Offset of the URI string (including quotes) relative to the beginning of
    * the file.
    */
-  int get uriOffset;
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
 
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  int get uriEnd;
+  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(0, offset_annotations);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(1, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(2, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedPartReader extends fb.TableReader<_UnlinkedPartImpl> {
@@ -4489,18 +3776,19 @@
   _UnlinkedPartImpl createObject(fb.BufferPointer bp) => new _UnlinkedPartImpl(bp);
 }
 
-class _UnlinkedPartImpl extends Object with _UnlinkedPartMixin implements UnlinkedPart {
+class _UnlinkedPartImpl extends Object with _UnlinkedPartMixin implements idl.UnlinkedPart {
   final fb.BufferPointer _bp;
 
   _UnlinkedPartImpl(this._bp);
 
-  int _uriOffset;
+  List<idl.UnlinkedConst> _annotations;
   int _uriEnd;
+  int _uriOffset;
 
   @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
-    return _uriOffset;
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
@@ -4508,23 +3796,54 @@
     _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 _UnlinkedPartMixin implements UnlinkedPart {
+abstract class _UnlinkedPartMixin implements idl.UnlinkedPart {
   @override
   Map<String, Object> toMap() => {
-    "uriOffset": uriOffset,
+    "annotations": annotations,
     "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
   };
 }
 
-class UnlinkedPublicNameBuilder extends Object with _UnlinkedPublicNameMixin implements UnlinkedPublicName {
+class UnlinkedPublicNameBuilder extends Object with _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
   bool _finished = false;
 
-  String _name;
-  ReferenceKind _kind;
-  int _numTypeParameters;
   List<UnlinkedPublicNameBuilder> _constMembers;
+  idl.ReferenceKind _kind;
+  String _name;
+  int _numTypeParameters;
+
+  @override
+  List<UnlinkedPublicNameBuilder> get constMembers => _constMembers ??= <UnlinkedPublicNameBuilder>[];
+
+  /**
+   * If this [UnlinkedPublicName] is a class, the list of members which can be
+   * referenced from constants - static constant fields, static methods, and
+   * constructors.  Otherwise empty.
+   */
+  void set constMembers(List<UnlinkedPublicNameBuilder> _value) {
+    assert(!_finished);
+    _constMembers = _value;
+  }
+
+  @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
   String get name => _name ??= '';
@@ -4538,17 +3857,6 @@
   }
 
   @override
-  ReferenceKind get kind => _kind ??= ReferenceKind.classOrEnum;
-
-  /**
-   * The kind of object referred to by the name.
-   */
-  void set kind(ReferenceKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  @override
   int get numTypeParameters => _numTypeParameters ??= 0;
 
   /**
@@ -4561,87 +3869,40 @@
     _numTypeParameters = _value;
   }
 
-  @override
-  List<UnlinkedPublicNameBuilder> get constMembers => _constMembers ??= <UnlinkedPublicNameBuilder>[];
-
-  /**
-   * If this [UnlinkedPublicName] is a class, the list of members which can be
-   * referenced from constants - static constant fields, static methods, and
-   * constructors.  Otherwise empty.
-   */
-  void set constMembers(List<UnlinkedPublicNameBuilder> _value) {
-    assert(!_finished);
-    _constMembers = _value;
-  }
-
-  UnlinkedPublicNameBuilder({String name, ReferenceKind kind, int numTypeParameters, List<UnlinkedPublicNameBuilder> constMembers})
-    : _name = name,
+  UnlinkedPublicNameBuilder({List<UnlinkedPublicNameBuilder> constMembers, idl.ReferenceKind kind, String name, int numTypeParameters})
+    : _constMembers = constMembers,
       _kind = kind,
-      _numTypeParameters = numTypeParameters,
-      _constMembers = constMembers;
+      _name = name,
+      _numTypeParameters = numTypeParameters;
 
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_name;
     fb.Offset offset_constMembers;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
+    fb.Offset offset_name;
     if (!(_constMembers == null || _constMembers.isEmpty)) {
       offset_constMembers = fbBuilder.writeList(_constMembers.map((b) => b.finish(fbBuilder)).toList());
     }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
     }
-    if (_kind != null && _kind != ReferenceKind.classOrEnum) {
+    fbBuilder.startTable();
+    if (offset_constMembers != null) {
+      fbBuilder.addOffset(0, offset_constMembers);
+    }
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
       fbBuilder.addUint32(1, _kind.index);
     }
-    if (_numTypeParameters != null && _numTypeParameters != 0) {
-      fbBuilder.addUint32(2, _numTypeParameters);
+    if (offset_name != null) {
+      fbBuilder.addOffset(2, offset_name);
     }
-    if (offset_constMembers != null) {
-      fbBuilder.addOffset(3, offset_constMembers);
+    if (_numTypeParameters != null && _numTypeParameters != 0) {
+      fbBuilder.addUint32(3, _numTypeParameters);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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 name itself.
-   */
-  String get name;
-
-  /**
-   * The kind of object referred to by the name.
-   */
-  ReferenceKind get kind;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int get numTypeParameters;
-
-  /**
-   * If this [UnlinkedPublicName] is a class, the list of members which can be
-   * referenced from constants - static constant fields, static methods, and
-   * constructors.  Otherwise empty.
-   */
-  List<UnlinkedPublicName> get constMembers;
-}
-
 class _UnlinkedPublicNameReader extends fb.TableReader<_UnlinkedPublicNameImpl> {
   const _UnlinkedPublicNameReader();
 
@@ -4649,59 +3910,70 @@
   _UnlinkedPublicNameImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNameImpl(bp);
 }
 
-class _UnlinkedPublicNameImpl extends Object with _UnlinkedPublicNameMixin implements UnlinkedPublicName {
+class _UnlinkedPublicNameImpl extends Object with _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
   final fb.BufferPointer _bp;
 
   _UnlinkedPublicNameImpl(this._bp);
 
+  List<idl.UnlinkedPublicName> _constMembers;
+  idl.ReferenceKind _kind;
   String _name;
-  ReferenceKind _kind;
   int _numTypeParameters;
-  List<UnlinkedPublicName> _constMembers;
 
   @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
+  List<idl.UnlinkedPublicName> get constMembers {
+    _constMembers ??= const fb.ListReader<idl.UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 0, const <idl.UnlinkedPublicName>[]);
+    return _constMembers;
   }
 
   @override
-  ReferenceKind get kind {
-    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, ReferenceKind.classOrEnum);
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, idl.ReferenceKind.classOrEnum);
     return _kind;
   }
 
   @override
-  int get numTypeParameters {
-    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
-    return _numTypeParameters;
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 2, '');
+    return _name;
   }
 
   @override
-  List<UnlinkedPublicName> get constMembers {
-    _constMembers ??= const fb.ListReader<UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 3, const <UnlinkedPublicName>[]);
-    return _constMembers;
+  int get numTypeParameters {
+    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _numTypeParameters;
   }
 }
 
-abstract class _UnlinkedPublicNameMixin implements UnlinkedPublicName {
+abstract class _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
   @override
   Map<String, Object> toMap() => {
-    "name": name,
-    "kind": kind,
-    "numTypeParameters": numTypeParameters,
     "constMembers": constMembers,
+    "kind": kind,
+    "name": name,
+    "numTypeParameters": numTypeParameters,
   };
 }
 
-class UnlinkedPublicNamespaceBuilder extends Object with _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
+class UnlinkedPublicNamespaceBuilder extends Object with _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
   bool _finished = false;
 
-  List<UnlinkedPublicNameBuilder> _names;
   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>[];
 
   /**
@@ -4716,17 +3988,6 @@
   }
 
   @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<String> get parts => _parts ??= <String>[];
 
   /**
@@ -4737,9 +3998,9 @@
     _parts = _value;
   }
 
-  UnlinkedPublicNamespaceBuilder({List<UnlinkedPublicNameBuilder> names, List<UnlinkedExportPublicBuilder> exports, List<String> parts})
-    : _names = names,
-      _exports = exports,
+  UnlinkedPublicNamespaceBuilder({List<UnlinkedExportPublicBuilder> exports, List<UnlinkedPublicNameBuilder> names, List<String> parts})
+    : _exports = exports,
+      _names = names,
       _parts = parts;
 
   List<int> toBuffer() {
@@ -4750,24 +4011,24 @@
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_names;
     fb.Offset offset_exports;
+    fb.Offset offset_names;
     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 (!(_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_names != null) {
-      fbBuilder.addOffset(0, offset_names);
-    }
     if (offset_exports != null) {
-      fbBuilder.addOffset(1, offset_exports);
+      fbBuilder.addOffset(0, offset_exports);
+    }
+    if (offset_names != null) {
+      fbBuilder.addOffset(1, offset_names);
     }
     if (offset_parts != null) {
       fbBuilder.addOffset(2, offset_parts);
@@ -4776,34 +4037,9 @@
   }
 }
 
-/**
- * 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;
+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> {
@@ -4813,25 +4049,25 @@
   _UnlinkedPublicNamespaceImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNamespaceImpl(bp);
 }
 
-class _UnlinkedPublicNamespaceImpl extends Object with _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
+class _UnlinkedPublicNamespaceImpl extends Object with _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
   final fb.BufferPointer _bp;
 
   _UnlinkedPublicNamespaceImpl(this._bp);
 
-  List<UnlinkedPublicName> _names;
-  List<UnlinkedExportPublic> _exports;
+  List<idl.UnlinkedExportPublic> _exports;
+  List<idl.UnlinkedPublicName> _names;
   List<String> _parts;
 
   @override
-  List<UnlinkedPublicName> get names {
-    _names ??= const fb.ListReader<UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 0, const <UnlinkedPublicName>[]);
-    return _names;
+  List<idl.UnlinkedExportPublic> get exports {
+    _exports ??= const fb.ListReader<idl.UnlinkedExportPublic>(const _UnlinkedExportPublicReader()).vTableGet(_bp, 0, const <idl.UnlinkedExportPublic>[]);
+    return _exports;
   }
 
   @override
-  List<UnlinkedExportPublic> get exports {
-    _exports ??= const fb.ListReader<UnlinkedExportPublic>(const _UnlinkedExportPublicReader()).vTableGet(_bp, 1, const <UnlinkedExportPublic>[]);
-    return _exports;
+  List<idl.UnlinkedPublicName> get names {
+    _names ??= const fb.ListReader<idl.UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 1, const <idl.UnlinkedPublicName>[]);
+    return _names;
   }
 
   @override
@@ -4841,16 +4077,16 @@
   }
 }
 
-abstract class _UnlinkedPublicNamespaceMixin implements UnlinkedPublicNamespace {
+abstract class _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
   @override
   Map<String, Object> toMap() => {
-    "names": names,
     "exports": exports,
+    "names": names,
     "parts": parts,
   };
 }
 
-class UnlinkedReferenceBuilder extends Object with _UnlinkedReferenceMixin implements UnlinkedReference {
+class UnlinkedReferenceBuilder extends Object with _UnlinkedReferenceMixin implements idl.UnlinkedReference {
   bool _finished = false;
 
   String _name;
@@ -4907,29 +4143,6 @@
   }
 }
 
-/**
- * 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".
-   */
-  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();
 
@@ -4937,7 +4150,7 @@
   _UnlinkedReferenceImpl createObject(fb.BufferPointer bp) => new _UnlinkedReferenceImpl(bp);
 }
 
-class _UnlinkedReferenceImpl extends Object with _UnlinkedReferenceMixin implements UnlinkedReference {
+class _UnlinkedReferenceImpl extends Object with _UnlinkedReferenceMixin implements idl.UnlinkedReference {
   final fb.BufferPointer _bp;
 
   _UnlinkedReferenceImpl(this._bp);
@@ -4958,7 +4171,7 @@
   }
 }
 
-abstract class _UnlinkedReferenceMixin implements UnlinkedReference {
+abstract class _UnlinkedReferenceMixin implements idl.UnlinkedReference {
   @override
   Map<String, Object> toMap() => {
     "name": name,
@@ -4966,37 +4179,26 @@
   };
 }
 
-class UnlinkedTypedefBuilder extends Object with _UnlinkedTypedefMixin implements UnlinkedTypedef {
+class UnlinkedTypedefBuilder extends Object with _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  EntityRefBuilder _returnType;
   List<UnlinkedParamBuilder> _parameters;
+  EntityRefBuilder _returnType;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
 
   @override
-  String get name => _name ??= '';
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Name of the typedef.
+   * Annotations for this typedef.
    */
-  void set name(String _value) {
+  void set annotations(List<UnlinkedConstBuilder> _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;
+    _annotations = _value;
   }
 
   @override
@@ -5012,14 +4214,37 @@
   }
 
   @override
-  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+  String get name => _name ??= '';
 
   /**
-   * Type parameters of the typedef, if any.
+   * Name of the typedef.
    */
-  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+  void set name(String _value) {
     assert(!_finished);
-    _typeParameters = _value;
+    _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
@@ -5034,105 +4259,76 @@
   }
 
   @override
-  List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
-
-  /**
-   * Parameters of the executable, if any.
-   */
-  void set parameters(List<UnlinkedParamBuilder> _value) {
-    assert(!_finished);
-    _parameters = _value;
-  }
-
-  UnlinkedTypedefBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, EntityRefBuilder returnType, List<UnlinkedParamBuilder> parameters})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _documentationComment = documentationComment,
-      _typeParameters = typeParameters,
-      _returnType = returnType,
-      _parameters = parameters;
-
-  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.addUint32(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();
-  }
-}
-
-/**
- * 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;
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
 
   /**
    * Type parameters of the typedef, if any.
    */
-  List<UnlinkedTypeParam> get typeParameters;
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _value;
+  }
 
-  /**
-   * Return type of the typedef.
-   */
-  EntityRef get returnType;
+  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;
 
-  /**
-   * Parameters of the executable, if any.
-   */
-  List<UnlinkedParam> get parameters;
+  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(0, offset_annotations);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(1, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(2, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(3, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(4, offset_parameters);
+    }
+    if (offset_returnType != null) {
+      fbBuilder.addOffset(5, offset_returnType);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(6, offset_typeParameters);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedTypedefReader extends fb.TableReader<_UnlinkedTypedefImpl> {
@@ -5142,73 +4338,105 @@
   _UnlinkedTypedefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypedefImpl(bp);
 }
 
-class _UnlinkedTypedefImpl extends Object with _UnlinkedTypedefMixin implements UnlinkedTypedef {
+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;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  EntityRef _returnType;
-  List<UnlinkedParam> _parameters;
+  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, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 1, null);
+    return _documentationComment;
+  }
 
   @override
   String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    _name ??= const fb.StringReader().vTableGet(_bp, 2, '');
     return _name;
   }
 
   @override
   int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
     return _nameOffset;
   }
 
   @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
+  List<idl.UnlinkedParam> get parameters {
+    _parameters ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 4, const <idl.UnlinkedParam>[]);
+    return _parameters;
   }
 
   @override
-  List<UnlinkedTypeParam> get typeParameters {
-    _typeParameters ??= const fb.ListReader<UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 3, const <UnlinkedTypeParam>[]);
-    return _typeParameters;
-  }
-
-  @override
-  EntityRef get returnType {
-    _returnType ??= const _EntityRefReader().vTableGet(_bp, 4, null);
+  idl.EntityRef get returnType {
+    _returnType ??= const _EntityRefReader().vTableGet(_bp, 5, null);
     return _returnType;
   }
 
   @override
-  List<UnlinkedParam> get parameters {
-    _parameters ??= const fb.ListReader<UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 5, const <UnlinkedParam>[]);
-    return _parameters;
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 6, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
   }
 }
 
-abstract class _UnlinkedTypedefMixin implements UnlinkedTypedef {
+abstract class _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "documentationComment": documentationComment,
     "name": name,
     "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "returnType": returnType,
     "parameters": parameters,
+    "returnType": returnType,
+    "typeParameters": typeParameters,
   };
 }
 
-class UnlinkedTypeParamBuilder extends Object with _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
+class UnlinkedTypeParamBuilder extends Object with _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
+  EntityRefBuilder _bound;
   String _name;
   int _nameOffset;
-  EntityRefBuilder _bound;
+
+  @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 ??= '';
@@ -5233,70 +4461,44 @@
     _nameOffset = _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;
-  }
-
-  UnlinkedTypeParamBuilder({String name, int nameOffset, EntityRefBuilder bound})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _bound = bound;
+  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_name;
+    fb.Offset offset_annotations;
     fb.Offset offset_bound;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
+    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);
     }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
     }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addUint32(1, _nameOffset);
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(0, offset_annotations);
     }
     if (offset_bound != null) {
-      fbBuilder.addOffset(2, offset_bound);
+      fbBuilder.addOffset(1, offset_bound);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(2, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(3, _nameOffset);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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.
-   */
-  EntityRef get bound;
-}
-
 class _UnlinkedTypeParamReader extends fb.TableReader<_UnlinkedTypeParamImpl> {
   const _UnlinkedTypeParamReader();
 
@@ -5304,137 +4506,71 @@
   _UnlinkedTypeParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeParamImpl(bp);
 }
 
-class _UnlinkedTypeParamImpl extends Object with _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
+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;
-  EntityRef _bound;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.EntityRef get bound {
+    _bound ??= const _EntityRefReader().vTableGet(_bp, 1, null);
+    return _bound;
+  }
 
   @override
   String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    _name ??= const fb.StringReader().vTableGet(_bp, 2, '');
     return _name;
   }
 
   @override
   int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
     return _nameOffset;
   }
-
-  @override
-  EntityRef get bound {
-    _bound ??= const _EntityRefReader().vTableGet(_bp, 2, null);
-    return _bound;
-  }
 }
 
-abstract class _UnlinkedTypeParamMixin implements UnlinkedTypeParam {
+abstract class _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "bound": bound,
     "name": name,
     "nameOffset": nameOffset,
-    "bound": bound,
   };
 }
 
-class UnlinkedUnitBuilder extends Object with _UnlinkedUnitMixin implements UnlinkedUnit {
+class UnlinkedUnitBuilder extends Object with _UnlinkedUnitMixin implements idl.UnlinkedUnit {
   bool _finished = false;
 
-  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<UnlinkedConstBuilder> _libraryAnnotations;
+  UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
+  String _libraryName;
+  int _libraryNameLength;
+  int _libraryNameOffset;
   List<UnlinkedPartBuilder> _parts;
+  UnlinkedPublicNamespaceBuilder _publicNamespace;
+  List<UnlinkedReferenceBuilder> _references;
   List<UnlinkedTypedefBuilder> _typedefs;
   List<UnlinkedVariableBuilder> _variables;
 
   @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 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
-  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
-  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
-  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<UnlinkedClassBuilder> get classes => _classes ??= <UnlinkedClassBuilder>[];
 
   /**
@@ -5491,6 +4627,67 @@
   }
 
   @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>[];
 
   /**
@@ -5502,6 +4699,32 @@
   }
 
   @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>[];
 
   /**
@@ -5523,19 +4746,20 @@
     _variables = _value;
   }
 
-  UnlinkedUnitBuilder({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})
-    : _libraryName = libraryName,
-      _libraryNameOffset = libraryNameOffset,
-      _libraryNameLength = libraryNameLength,
-      _libraryDocumentationComment = libraryDocumentationComment,
-      _publicNamespace = publicNamespace,
-      _references = references,
-      _classes = classes,
+  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;
 
@@ -5547,30 +4771,19 @@
   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());
     }
@@ -5586,9 +4799,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());
     }
@@ -5596,138 +4824,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.addUint32(1, _libraryNameOffset);
-    }
-    if (_libraryNameLength != null && _libraryNameLength != 0) {
-      fbBuilder.addUint32(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(0, offset_classes);
     }
     if (offset_enums != null) {
-      fbBuilder.addOffset(7, offset_enums);
+      fbBuilder.addOffset(1, offset_enums);
     }
     if (offset_executables != null) {
-      fbBuilder.addOffset(8, offset_executables);
+      fbBuilder.addOffset(2, offset_executables);
     }
     if (offset_exports != null) {
-      fbBuilder.addOffset(9, offset_exports);
+      fbBuilder.addOffset(3, offset_exports);
     }
     if (offset_imports != null) {
-      fbBuilder.addOffset(10, offset_imports);
+      fbBuilder.addOffset(4, offset_imports);
+    }
+    if (offset_libraryAnnotations != null) {
+      fbBuilder.addOffset(5, offset_libraryAnnotations);
+    }
+    if (offset_libraryDocumentationComment != null) {
+      fbBuilder.addOffset(6, offset_libraryDocumentationComment);
+    }
+    if (offset_libraryName != null) {
+      fbBuilder.addOffset(7, offset_libraryName);
+    }
+    if (_libraryNameLength != null && _libraryNameLength != 0) {
+      fbBuilder.addUint32(8, _libraryNameLength);
+    }
+    if (_libraryNameOffset != null && _libraryNameOffset != 0) {
+      fbBuilder.addUint32(9, _libraryNameOffset);
     }
     if (offset_parts != null) {
-      fbBuilder.addOffset(11, offset_parts);
+      fbBuilder.addOffset(10, offset_parts);
+    }
+    if (offset_publicNamespace != null) {
+      fbBuilder.addOffset(11, offset_publicNamespace);
+    }
+    if (offset_references != null) {
+      fbBuilder.addOffset(12, offset_references);
     }
     if (offset_typedefs != null) {
-      fbBuilder.addOffset(12, offset_typedefs);
+      fbBuilder.addOffset(13, offset_typedefs);
     }
     if (offset_variables != null) {
-      fbBuilder.addOffset(13, offset_variables);
+      fbBuilder.addOffset(14, offset_variables);
     }
     return fbBuilder.endTable();
   }
 }
 
-/**
- * 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 is used to represent
-   * the absence of a reference in places where a reference is optional (for
-   * example [UnlinkedReference.prefixReference or
-   * UnlinkedImport.prefixReference]).
-   */
-  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> {
@@ -5737,144 +4885,241 @@
   _UnlinkedUnitImpl createObject(fb.BufferPointer bp) => new _UnlinkedUnitImpl(bp);
 }
 
-class _UnlinkedUnitImpl extends Object with _UnlinkedUnitMixin 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
-  String get libraryName {
-    _libraryName ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _libraryName;
-  }
-
-  @override
-  int get libraryNameOffset {
-    _libraryNameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _libraryNameOffset;
-  }
-
-  @override
-  int get libraryNameLength {
-    _libraryNameLength ??= const fb.Uint32Reader().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>[]);
+  List<idl.UnlinkedClass> get classes {
+    _classes ??= const fb.ListReader<idl.UnlinkedClass>(const _UnlinkedClassReader()).vTableGet(_bp, 0, const <idl.UnlinkedClass>[]);
     return _classes;
   }
 
   @override
-  List<UnlinkedEnum> get enums {
-    _enums ??= const fb.ListReader<UnlinkedEnum>(const _UnlinkedEnumReader()).vTableGet(_bp, 7, const <UnlinkedEnum>[]);
+  List<idl.UnlinkedEnum> get enums {
+    _enums ??= const fb.ListReader<idl.UnlinkedEnum>(const _UnlinkedEnumReader()).vTableGet(_bp, 1, const <idl.UnlinkedEnum>[]);
     return _enums;
   }
 
   @override
-  List<UnlinkedExecutable> get executables {
-    _executables ??= const fb.ListReader<UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 8, const <UnlinkedExecutable>[]);
+  List<idl.UnlinkedExecutable> get executables {
+    _executables ??= const fb.ListReader<idl.UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 2, const <idl.UnlinkedExecutable>[]);
     return _executables;
   }
 
   @override
-  List<UnlinkedExportNonPublic> get exports {
-    _exports ??= const fb.ListReader<UnlinkedExportNonPublic>(const _UnlinkedExportNonPublicReader()).vTableGet(_bp, 9, const <UnlinkedExportNonPublic>[]);
+  List<idl.UnlinkedExportNonPublic> get exports {
+    _exports ??= const fb.ListReader<idl.UnlinkedExportNonPublic>(const _UnlinkedExportNonPublicReader()).vTableGet(_bp, 3, const <idl.UnlinkedExportNonPublic>[]);
     return _exports;
   }
 
   @override
-  List<UnlinkedImport> get imports {
-    _imports ??= const fb.ListReader<UnlinkedImport>(const _UnlinkedImportReader()).vTableGet(_bp, 10, const <UnlinkedImport>[]);
+  List<idl.UnlinkedImport> get imports {
+    _imports ??= const fb.ListReader<idl.UnlinkedImport>(const _UnlinkedImportReader()).vTableGet(_bp, 4, const <idl.UnlinkedImport>[]);
     return _imports;
   }
 
   @override
-  List<UnlinkedPart> get parts {
-    _parts ??= const fb.ListReader<UnlinkedPart>(const _UnlinkedPartReader()).vTableGet(_bp, 11, const <UnlinkedPart>[]);
+  List<idl.UnlinkedConst> get libraryAnnotations {
+    _libraryAnnotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 5, const <idl.UnlinkedConst>[]);
+    return _libraryAnnotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get libraryDocumentationComment {
+    _libraryDocumentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 6, null);
+    return _libraryDocumentationComment;
+  }
+
+  @override
+  String get libraryName {
+    _libraryName ??= const fb.StringReader().vTableGet(_bp, 7, '');
+    return _libraryName;
+  }
+
+  @override
+  int get libraryNameLength {
+    _libraryNameLength ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    return _libraryNameLength;
+  }
+
+  @override
+  int get libraryNameOffset {
+    _libraryNameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
+    return _libraryNameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedPart> get parts {
+    _parts ??= const fb.ListReader<idl.UnlinkedPart>(const _UnlinkedPartReader()).vTableGet(_bp, 10, const <idl.UnlinkedPart>[]);
     return _parts;
   }
 
   @override
-  List<UnlinkedTypedef> get typedefs {
-    _typedefs ??= const fb.ListReader<UnlinkedTypedef>(const _UnlinkedTypedefReader()).vTableGet(_bp, 12, const <UnlinkedTypedef>[]);
+  idl.UnlinkedPublicNamespace get publicNamespace {
+    _publicNamespace ??= const _UnlinkedPublicNamespaceReader().vTableGet(_bp, 11, null);
+    return _publicNamespace;
+  }
+
+  @override
+  List<idl.UnlinkedReference> get references {
+    _references ??= const fb.ListReader<idl.UnlinkedReference>(const _UnlinkedReferenceReader()).vTableGet(_bp, 12, const <idl.UnlinkedReference>[]);
+    return _references;
+  }
+
+  @override
+  List<idl.UnlinkedTypedef> get typedefs {
+    _typedefs ??= const fb.ListReader<idl.UnlinkedTypedef>(const _UnlinkedTypedefReader()).vTableGet(_bp, 13, const <idl.UnlinkedTypedef>[]);
     return _typedefs;
   }
 
   @override
-  List<UnlinkedVariable> get variables {
-    _variables ??= const fb.ListReader<UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 13, const <UnlinkedVariable>[]);
+  List<idl.UnlinkedVariable> get variables {
+    _variables ??= const fb.ListReader<idl.UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 14, const <idl.UnlinkedVariable>[]);
     return _variables;
   }
 }
 
-abstract class _UnlinkedUnitMixin implements UnlinkedUnit {
+abstract class _UnlinkedUnitMixin implements idl.UnlinkedUnit {
   @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,
   };
 }
 
-class UnlinkedVariableBuilder extends Object with _UnlinkedVariableMixin implements UnlinkedVariable {
+class UnlinkedVariableBuilder extends Object with _UnlinkedVariableMixin implements idl.UnlinkedVariable {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedConstBuilder _constExpr;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  int _inferredTypeSlot;
+  bool _isConst;
+  bool _isFinal;
+  bool _isStatic;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  EntityRefBuilder _type;
-  UnlinkedConstBuilder _constExpr;
-  bool _isStatic;
-  bool _isFinal;
-  bool _isConst;
   int _propagatedTypeSlot;
-  int _inferredTypeSlot;
+  EntityRefBuilder _type;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this variable.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  UnlinkedConstBuilder get constExpr => _constExpr;
+
+  /**
+   * 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 constExpr(UnlinkedConstBuilder _value) {
+    assert(!_finished);
+    _constExpr = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the variable, or `null` if there is no
+   * documentation comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+
+  /**
+   * 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 inferredTypeSlot(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _inferredTypeSlot = _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.
+   *
+   * 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).
+   */
+  void set isStatic(bool _value) {
+    assert(!_finished);
+    _isStatic = _value;
+  }
 
   @override
   String get name => _name ??= '';
@@ -5900,78 +5145,6 @@
   }
 
   @override
-  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
-
-  /**
-   * Documentation comment for the variable, or `null` if there is no
-   * documentation comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _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
-  UnlinkedConstBuilder get constExpr => _constExpr;
-
-  /**
-   * If [isConst] is true, and the variable has an initializer, the constant
-   * expression in the initializer.
-   */
-  void set constExpr(UnlinkedConstBuilder _value) {
-    assert(!_finished);
-    _constExpr = _value;
-  }
-
-  @override
-  bool get isStatic => _isStatic ??= false;
-
-  /**
-   * 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).
-   */
-  void set isStatic(bool _value) {
-    assert(!_finished);
-    _isStatic = _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 isConst => _isConst ??= false;
-
-  /**
-   * Indicates whether the variable is declared using the `const` keyword.
-   */
-  void set isConst(bool _value) {
-    assert(!_finished);
-    _isConst = _value;
-  }
-
-  @override
   int get propagatedTypeSlot => _propagatedTypeSlot ??= 0;
 
   /**
@@ -5989,155 +5162,88 @@
   }
 
   @override
-  int get inferredTypeSlot => _inferredTypeSlot ??= 0;
-
-  /**
-   * If this variable is inferrable, 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 inferredTypeSlot(int _value) {
-    assert(!_finished);
-    assert(_value == null || _value >= 0);
-    _inferredTypeSlot = _value;
-  }
-
-  UnlinkedVariableBuilder({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, EntityRefBuilder type, UnlinkedConstBuilder constExpr, bool isStatic, bool isFinal, bool isConst, int propagatedTypeSlot, int inferredTypeSlot})
-    : _name = name,
-      _nameOffset = nameOffset,
-      _documentationComment = documentationComment,
-      _type = type,
-      _constExpr = constExpr,
-      _isStatic = isStatic,
-      _isFinal = isFinal,
-      _isConst = isConst,
-      _propagatedTypeSlot = propagatedTypeSlot,
-      _inferredTypeSlot = inferredTypeSlot;
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    fb.Offset offset_type;
-    fb.Offset offset_constExpr;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    if (_type != null) {
-      offset_type = _type.finish(fbBuilder);
-    }
-    if (_constExpr != null) {
-      offset_constExpr = _constExpr.finish(fbBuilder);
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addUint32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    if (offset_type != null) {
-      fbBuilder.addOffset(3, offset_type);
-    }
-    if (offset_constExpr != null) {
-      fbBuilder.addOffset(4, offset_constExpr);
-    }
-    if (_isStatic == true) {
-      fbBuilder.addBool(5, true);
-    }
-    if (_isFinal == true) {
-      fbBuilder.addBool(6, true);
-    }
-    if (_isConst == true) {
-      fbBuilder.addBool(7, true);
-    }
-    if (_propagatedTypeSlot != null && _propagatedTypeSlot != 0) {
-      fbBuilder.addUint32(8, _propagatedTypeSlot);
-    }
-    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
-      fbBuilder.addUint32(9, _inferredTypeSlot);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-/**
- * 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;
+  EntityRefBuilder get type => _type;
 
   /**
    * Declared type of the variable.  Absent if the type is implicit.
    */
-  EntityRef get type;
+  void set type(EntityRefBuilder _value) {
+    assert(!_finished);
+    _type = _value;
+  }
 
-  /**
-   * If [isConst] is true, and the variable has an initializer, the constant
-   * expression in the initializer.
-   */
-  UnlinkedConst get constExpr;
+  UnlinkedVariableBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedConstBuilder constExpr, UnlinkedDocumentationCommentBuilder documentationComment, int inferredTypeSlot, bool isConst, bool isFinal, bool isStatic, String name, int nameOffset, int propagatedTypeSlot, EntityRefBuilder type})
+    : _annotations = annotations,
+      _constExpr = constExpr,
+      _documentationComment = documentationComment,
+      _inferredTypeSlot = inferredTypeSlot,
+      _isConst = isConst,
+      _isFinal = isFinal,
+      _isStatic = isStatic,
+      _name = name,
+      _nameOffset = nameOffset,
+      _propagatedTypeSlot = propagatedTypeSlot,
+      _type = 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;
-
-  /**
-   * 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.
-   */
-  int get propagatedTypeSlot;
-
-  /**
-   * If this variable is inferrable, 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`.
-   */
-  int get inferredTypeSlot;
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_constExpr;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_name;
+    fb.Offset offset_type;
+    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 (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (_type != null) {
+      offset_type = _type.finish(fbBuilder);
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(0, offset_annotations);
+    }
+    if (offset_constExpr != null) {
+      fbBuilder.addOffset(1, offset_constExpr);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(2, offset_documentationComment);
+    }
+    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+      fbBuilder.addUint32(3, _inferredTypeSlot);
+    }
+    if (_isConst == true) {
+      fbBuilder.addBool(4, true);
+    }
+    if (_isFinal == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (_isStatic == true) {
+      fbBuilder.addBool(6, true);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(7, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(8, _nameOffset);
+    }
+    if (_propagatedTypeSlot != null && _propagatedTypeSlot != 0) {
+      fbBuilder.addUint32(9, _propagatedTypeSlot);
+    }
+    if (offset_type != null) {
+      fbBuilder.addOffset(10, offset_type);
+    }
+    return fbBuilder.endTable();
+  }
 }
 
 class _UnlinkedVariableReader extends fb.TableReader<_UnlinkedVariableImpl> {
@@ -6147,96 +5253,104 @@
   _UnlinkedVariableImpl createObject(fb.BufferPointer bp) => new _UnlinkedVariableImpl(bp);
 }
 
-class _UnlinkedVariableImpl extends Object with _UnlinkedVariableMixin 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;
+  bool _isConst;
+  bool _isFinal;
+  bool _isStatic;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  EntityRef _type;
-  UnlinkedConst _constExpr;
-  bool _isStatic;
-  bool _isFinal;
-  bool _isConst;
   int _propagatedTypeSlot;
-  int _inferredTypeSlot;
+  idl.EntityRef _type;
 
   @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, 0, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
+  idl.UnlinkedConst get constExpr {
+    _constExpr ??= const _UnlinkedConstReader().vTableGet(_bp, 1, null);
+    return _constExpr;
   }
 
   @override
-  UnlinkedDocumentationComment get documentationComment {
+  idl.UnlinkedDocumentationComment get documentationComment {
     _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
     return _documentationComment;
   }
 
   @override
-  EntityRef get type {
-    _type ??= const _EntityRefReader().vTableGet(_bp, 3, null);
-    return _type;
-  }
-
-  @override
-  UnlinkedConst get constExpr {
-    _constExpr ??= const _UnlinkedConstReader().vTableGet(_bp, 4, null);
-    return _constExpr;
-  }
-
-  @override
-  bool get isStatic {
-    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 5, false);
-    return _isStatic;
-  }
-
-  @override
-  bool get isFinal {
-    _isFinal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
-    return _isFinal;
+  int get inferredTypeSlot {
+    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _inferredTypeSlot;
   }
 
   @override
   bool get isConst {
-    _isConst ??= const fb.BoolReader().vTableGet(_bp, 7, false);
+    _isConst ??= const fb.BoolReader().vTableGet(_bp, 4, false);
     return _isConst;
   }
 
   @override
+  bool get isFinal {
+    _isFinal ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    return _isFinal;
+  }
+
+  @override
+  bool get isStatic {
+    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 6, false);
+    return _isStatic;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 7, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    return _nameOffset;
+  }
+
+  @override
   int get propagatedTypeSlot {
-    _propagatedTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    _propagatedTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
     return _propagatedTypeSlot;
   }
 
   @override
-  int get inferredTypeSlot {
-    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
-    return _inferredTypeSlot;
+  idl.EntityRef get type {
+    _type ??= const _EntityRefReader().vTableGet(_bp, 10, null);
+    return _type;
   }
 }
 
-abstract class _UnlinkedVariableMixin implements UnlinkedVariable {
+abstract class _UnlinkedVariableMixin implements idl.UnlinkedVariable {
   @override
   Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "constExpr": constExpr,
+    "documentationComment": documentationComment,
+    "inferredTypeSlot": inferredTypeSlot,
+    "isConst": isConst,
+    "isFinal": isFinal,
+    "isStatic": isStatic,
     "name": name,
     "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "type": type,
-    "constExpr": constExpr,
-    "isStatic": isStatic,
-    "isFinal": isFinal,
-    "isConst": isConst,
     "propagatedTypeSlot": propagatedTypeSlot,
-    "inferredTypeSlot": inferredTypeSlot,
+    "type": type,
   };
 }
 
diff --git a/pkg/analyzer/tool/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
similarity index 77%
rename from pkg/analyzer/tool/summary/idl.dart
rename to pkg/analyzer/lib/src/summary/idl.dart
index 927cbb3..6ec0ded 100644
--- a/pkg/analyzer/tool/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -3,19 +3,20 @@
 // 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.
+ * 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 non-typical semantics:
- * - Fields of type List are never null, and have a default value of the empty
- *   list.
- * - Fields of type int are unsigned 32-bit integers, 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.
+ * 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
@@ -40,6 +41,9 @@
  */
 library analyzer.tool.summary.idl;
 
+import 'base.dart' as base;
+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,
@@ -70,43 +74,7 @@
  * Summary information about a reference to a an entity such as a type, top
  * level executable, or executable within a class.
  */
-class EntityRef {
-  /**
-   * 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.
-   */
-  int slot;
-
-  /**
-   * Index into [UnlinkedUnit.references] for the entity being referred to, or
-   * zero if this is a reference to a type parameter.
-   */
-  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;
-
+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
@@ -129,21 +97,63 @@
    * generic class, then the type arguments in [typeArguments] are applied
    * first to the class and then to the method.
    */
-  List<int> implicitFunctionTypeIndices;
+  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.
+   */
+  int get paramReference;
+
+  /**
+   * Index into [UnlinkedUnit.references] for the entity being referred to, or
+   * zero if this is a reference to a type parameter.
+   */
+  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.
+   */
+  int get slot;
 
   /**
    * 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.
    */
-  List<EntityRef> typeArguments;
+  List<EntityRef> get typeArguments;
 }
 
 /**
  * Information about a dependency that exists between one library and another
  * due to an "import" declaration.
  */
-class LinkedDependency {
+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.
+   */
+  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.
@@ -151,31 +161,30 @@
    * `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;
+  String get uri;
 }
 
 /**
  * Information about a single name in the export namespace of the library that
  * is not in the public namespace.
  */
-class LinkedExportName {
-  /**
-   * Name of the exported entity.  For an exported setter, this name includes
-   * the trailing '='.
-   */
-  String name;
-
+abstract class LinkedExportName extends base.SummaryClass {
   /**
    * Index into [LinkedLibrary.dependencies] for the library in which the
    * entity is defined.
    */
-  int dependency;
+  int get dependency;
+
+  /**
+   * The kind of the entity being referred to.
+   */
+  ReferenceKind get kind;
+
+  /**
+   * Name of the exported entity.  For an exported setter, this name includes
+   * the trailing '='.
+   */
+  String get name;
 
   /**
    * Integer index indicating which unit in the exported library contains the
@@ -183,26 +192,16 @@
    * zero represents the defining compilation unit, and nonzero values
    * represent parts in the order of the corresponding `part` declarations.
    */
-  int unit;
-
-  /**
-   * The kind of the entity being referred to.
-   */
-  ReferenceKind kind;
+  int get unit;
 }
 
 /**
  * Linked summary of a library.
  */
 @topLevel
-class LinkedLibrary {
-  /**
-   * 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.
-   */
-  List<LinkedUnit> units;
+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
@@ -220,13 +219,7 @@
    * anti-dependency (e.g. the result of type propagation or type inference
    * depends on the lack of a certain declaration in the library).
    */
-  List<LinkedDependency> dependencies;
-
-  /**
-   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
-   * of the library being imported.
-   */
-  List<int> importDependencies;
+  List<LinkedDependency> get dependencies;
 
   /**
    * Information about entities in the export namespace of the library that are
@@ -235,59 +228,34 @@
    *
    * Sorted by name.
    */
-  List<LinkedExportName> exportNames;
+  List<LinkedExportName> get exportNames;
+
+  /**
+   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
+   * of the library being imported.
+   */
+  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).
    */
-  int numPrelinkedDependencies;
+  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.
+   */
+  List<LinkedUnit> get units;
 }
 
 /**
  * Information about the resolution of an [UnlinkedReference].
  */
-class LinkedReference {
-  /**
-   * 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).
-   */
-  int dependency;
-
-  /**
-   * The kind of the entity being referred to.  For the pseudo-types `dynamic`
-   * and `void`, the kind is [ReferenceKind.classOrEnum].
-   */
-  ReferenceKind kind;
-
-  /**
-   * 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).
-   */
-  int unit;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int numTypeParameters;
-
-  /**
-   * 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".
-   */
-  String name;
-
+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
@@ -299,13 +267,52 @@
    * LinkedUnit.references[i].containingReference != 0, then
    * LinkedUnit.references[i].containingReference < i.
    */
-  int containingReference;
+  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].
+   */
+  int get dependency;
+
+  /**
+   * The kind of the entity being referred to.  For the pseudo-types `dynamic`
+   * and `void`, the kind is [ReferenceKind.classOrEnum].
+   */
+  ReferenceKind get kind;
+
+  /**
+   * 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".
+   */
+  String get name;
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it accepts.  Otherwise zero.
+   */
+  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).
+   */
+  int get unit;
 }
 
 /**
  * Linked summary of a compilation unit.
  */
-class LinkedUnit {
+abstract class LinkedUnit extends base.SummaryClass {
   /**
    * Information about the resolution of references within the compilation
    * unit.  Each element of [UnlinkedUnit.references] has a corresponding
@@ -314,13 +321,13 @@
    * additional elements are references that are only referred to implicitly
    * (e.g. elements involved in inferred or propagated types).
    */
-  List<LinkedReference> references;
+  List<LinkedReference> get references;
 
   /**
    * List associating slot ids found inside the unlinked summary for the
    * compilation unit with propagated and inferred types.
    */
-  List<EntityRef> types;
+  List<EntityRef> get types;
 }
 
 /**
@@ -385,113 +392,121 @@
  * Information about SDK.
  */
 @topLevel
-class SdkBundle {
-  /**
-   * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
-   */
-  List<String> linkedLibraryUris;
+abstract class SdkBundle extends base.SummaryClass {
+  factory SdkBundle.fromBuffer(List<int> buffer) =>
+      generated.readSdkBundle(buffer);
 
   /**
    * Linked libraries.
    */
-  List<LinkedLibrary> linkedLibraries;
+  List<LinkedLibrary> get linkedLibraries;
 
   /**
-   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   * The list of URIs of items in [linkedLibraries], e.g. `dart:core`.
    */
-  List<String> unlinkedUnitUris;
+  List<String> get linkedLibraryUris;
 
   /**
    * Unlinked information for the compilation units constituting the SDK.
    */
-  List<UnlinkedUnit> unlinkedUnits;
+  List<UnlinkedUnit> get unlinkedUnits;
+
+  /**
+   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   */
+  List<String> get unlinkedUnitUris;
 }
 
 /**
  * Unlinked summary information about a class declaration.
  */
-class UnlinkedClass {
+abstract class UnlinkedClass extends base.SummaryClass {
   /**
-   * Name of the class.
+   * Annotations for this class.
    */
-  String name;
-
-  /**
-   * Offset of the class name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
+  List<UnlinkedConst> get annotations;
 
   /**
    * Documentation comment for the class, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
 
   /**
-   * Type parameters of the class, if any.
+   * Executable objects (methods, getters, and setters) contained in the class.
    */
-  List<UnlinkedTypeParam> typeParameters;
+  List<UnlinkedExecutable> get executables;
+
+  /**
+   * Field declarations contained in the class.
+   */
+  List<UnlinkedVariable> get fields;
+
+  /**
+   * Indicates whether this class is the core "Object" class (and hence has no
+   * supertype)
+   */
+  bool get hasNoSupertype;
+
+  /**
+   * Interfaces appearing in an `implements` clause, if any.
+   */
+  List<EntityRef> get interfaces;
+
+  /**
+   * 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;
+
+  /**
+   * Mixins appearing in a `with` clause, if any.
+   */
+  List<EntityRef> get mixins;
+
+  /**
+   * Name of the class.
+   */
+  String get name;
+
+  /**
+   * Offset of the class name relative to the beginning of the file.
+   */
+  @informative
+  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).
    */
-  EntityRef supertype;
+  EntityRef get supertype;
 
   /**
-   * Mixins appearing in a `with` clause, if any.
+   * Type parameters of the class, if any.
    */
-  List<EntityRef> mixins;
-
-  /**
-   * Interfaces appearing in an `implements` clause, if any.
-   */
-  List<EntityRef> 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;
+  List<UnlinkedTypeParam> get typeParameters;
 }
 
 /**
  * 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;
-
+abstract class UnlinkedCombinator extends base.SummaryClass {
   /**
    * List of names which are hidden.  Empty if this is a `show` combinator.
    */
-  List<String> hides;
+  List<String> get hides;
+
+  /**
+   * List of names which are shown.  Empty if this is a `hide` combinator.
+   */
+  List<String> get shows;
 }
 
 /**
@@ -504,30 +519,30 @@
  * 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.
  */
-class UnlinkedConst {
+abstract class UnlinkedConst extends base.SummaryClass {
   /**
-   * Sequence of operations to execute (starting with an empty stack) to form
-   * the constant value.
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
    */
-  List<UnlinkedConstOperation> operations;
+  List<double> get doubles;
 
   /**
    * Sequence of unsigned 32-bit integers consumed by the operations
    * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
    * `makeList`, and `makeMap`.
    */
-  List<int> ints;
+  List<int> get ints;
 
   /**
-   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   * Indicates whether the expression is not a valid potentially constant
+   * expression.
    */
-  List<double> doubles;
+  bool get isInvalid;
 
   /**
-   * Sequence of strings consumed by the operations `pushString` and
-   * `invokeConstructor`.
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
    */
-  List<String> strings;
+  List<UnlinkedConstOperation> get operations;
 
   /**
    * Sequence of language constructs consumed by the operations
@@ -535,7 +550,13 @@
    * that in the case of `pushReference` (and sometimes `invokeConstructor` the
    * actual entity being referred to may be something other than a type.
    */
-  List<EntityRef> references;
+  List<EntityRef> get references;
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  List<String> get strings;
 }
 
 /**
@@ -604,6 +625,12 @@
   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].
@@ -823,138 +850,187 @@
 }
 
 /**
+ * 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.
+   */
+  List<UnlinkedConst> get arguments;
+
+  /**
+   * If [kind] is `field`, the expression of the field initializer.
+   * Otherwise `null`.
+   */
+  UnlinkedConst get expression;
+
+  /**
+   * The kind of the constructor initializer (field, redirect, super).
+   */
+  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.
+   */
+  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.
  */
-class UnlinkedDocumentationComment {
+abstract class UnlinkedDocumentationComment extends base.SummaryClass {
+  /**
+   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+   */
+  int get length;
+
+  /**
+   * Offset of the beginning of the documentation comment relative to the
+   * beginning of the file.
+   */
+  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.
    */
-  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;
+  String get text;
 }
 
 /**
  * Unlinked summary information about an enum declaration.
  */
-class UnlinkedEnum {
+abstract class UnlinkedEnum extends base.SummaryClass {
   /**
-   * Name of the enum type.
+   * Annotations for this enum.
    */
-  String name;
-
-  /**
-   * Offset of the enum name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
+  List<UnlinkedConst> get annotations;
 
   /**
    * Documentation comment for the enum, or `null` if there is no documentation
    * comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Name of the enum type.
+   */
+  String get name;
+
+  /**
+   * Offset of the enum name relative to the beginning of the file.
+   */
+  @informative
+  int get nameOffset;
 
   /**
    * Values listed in the enum declaration, in declaration order.
    */
-  List<UnlinkedEnumValue> values;
+  List<UnlinkedEnumValue> get 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;
-
+abstract class UnlinkedEnumValue extends base.SummaryClass {
   /**
    * Documentation comment for the enum value, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Name of the enumerated value.
+   */
+  String get name;
+
+  /**
+   * Offset of the enum value name relative to the beginning of the file.
+   */
+  @informative
+  int get nameOffset;
 }
 
 /**
  * Unlinked summary information about a function, method, getter, or setter
  * declaration.
  */
-class UnlinkedExecutable {
+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.
+   * Annotations for this executable.
    */
-  String name;
+  List<UnlinkedConst> get annotations;
 
   /**
-   * 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(); }").
+   * If a constant [UnlinkedExecutableKind.constructor], the constructor
+   * initializers.  Otherwise empty.
    */
-  @informative
-  int nameOffset;
+  List<UnlinkedConstructorInitializer> get constantInitializers;
 
   /**
    * Documentation comment for the executable, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
 
   /**
-   * Type parameters of the executable, if any.  Empty if support for generic
-   * method syntax is disabled.
+   * 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`.
    */
-  List<UnlinkedTypeParam> typeParameters;
-
-  /**
-   * Declared return type of the executable.  Absent if the executable is a
-   * constructor or the return type is implicit.
-   */
-  EntityRef 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;
+  int get inferredReturnTypeSlot;
 
   /**
    * Indicates whether the executable is declared using the `abstract` keyword.
    */
-  bool isAbstract;
+  bool get isAbstract;
+
+  /**
+   * Indicates whether the executable is declared using the `const` keyword.
+   */
+  bool get isConst;
+
+  /**
+   * Indicates whether the executable is declared using the `external` keyword.
+   */
+  bool get isExternal;
+
+  /**
+   * Indicates whether the executable is declared using the `factory` keyword.
+   */
+  bool get isFactory;
 
   /**
    * Indicates whether the executable is declared using the `static` keyword.
@@ -963,31 +1039,48 @@
    * not declared using the `static` keyword (even though they are considered
    * static for semantic purposes).
    */
-  bool isStatic;
+  bool get isStatic;
 
   /**
-   * Indicates whether the executable is declared using the `const` keyword.
+   * The kind of the executable (function/method, getter, setter, or
+   * constructor).
    */
-  bool isConst;
+  UnlinkedExecutableKind get kind;
 
   /**
-   * Indicates whether the executable is declared using the `factory` keyword.
+   * 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.
    */
-  bool isFactory;
+  String get name;
 
   /**
-   * Indicates whether the executable is declared using the `external` keyword.
+   * 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(); }").
    */
-  bool isExternal;
+  @informative
+  int get nameOffset;
 
   /**
-   * If this executable's return type is inferrable, nonzero slot id
-   * identifying which entry in [LinkedLibrary.types] contains the inferred
-   * return type.  If there is no matching entry in [LinkedLibrary.types], then
-   * no return type was inferred for this variable, so its static type is
-   * `dynamic`.
+   * 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.
    */
-  int inferredReturnTypeSlot;
+  List<UnlinkedParam> get parameters;
+
+  /**
+   * Declared return type of the executable.  Absent if the executable is a
+   * constructor or the return type is implicit.
+   */
+  EntityRef get returnType;
+
+  /**
+   * Type parameters of the executable, if any.  Empty if support for generic
+   * method syntax is disabled.
+   */
+  List<UnlinkedTypeParam> get typeParameters;
 }
 
 /**
@@ -1019,59 +1112,86 @@
  * Unlinked summary information about an export declaration (stored outside
  * [UnlinkedPublicNamespace]).
  */
-class UnlinkedExportNonPublic {
+abstract class UnlinkedExportNonPublic extends base.SummaryClass {
+  /**
+   * Annotations for this export directive.
+   */
+  List<UnlinkedConst> get annotations;
+
   /**
    * 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;
+  int get offset;
 
   /**
    * End of the URI string (including quotes) relative to the beginning of the
    * file.
    */
   @informative
-  int uriEnd;
+  int get uriEnd;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  @informative
+  int get uriOffset;
 }
 
 /**
  * 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;
-
+abstract class UnlinkedExportPublic extends base.SummaryClass {
   /**
    * Combinators contained in this import declaration.
    */
-  List<UnlinkedCombinator> combinators;
+  List<UnlinkedCombinator> get combinators;
+
+  /**
+   * URI used in the source code to reference the exported library.
+   */
+  String get uri;
 }
 
 /**
  * Unlinked summary information about an import declaration.
  */
-class UnlinkedImport {
+abstract class UnlinkedImport extends base.SummaryClass {
   /**
-   * URI used in the source code to reference the imported library.
+   * Annotations for this import declaration.
    */
-  String uri;
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * 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;
 
   /**
    * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
    * is true, zero.
    */
   @informative
-  int offset;
+  int get offset;
+
+  /**
+   * Offset of the prefix name relative to the beginning of the file, or zero
+   * if there is no prefix.
+   */
+  @informative
+  int get prefixOffset;
 
   /**
    * Index into [UnlinkedUnit.references] of the prefix declared by this
@@ -1079,100 +1199,95 @@
    *
    * Note that multiple imports can declare the same prefix.
    */
-  int prefixReference;
+  int get prefixReference;
 
   /**
-   * Combinators contained in this import declaration.
+   * URI used in the source code to reference the imported library.
    */
-  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;
+  String get uri;
 
   /**
    * End of the URI string (including quotes) relative to the beginning of the
    * file.  If [isImplicit] is true, zero.
    */
   @informative
-  int uriEnd;
+  int get uriEnd;
 
   /**
-   * Offset of the prefix name relative to the beginning of the file, or zero
-   * if there is no prefix.
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.  If [isImplicit] is true, zero.
    */
   @informative
-  int prefixOffset;
+  int get uriOffset;
 }
 
 /**
  * Unlinked summary information about a function parameter.
  */
-class UnlinkedParam {
+abstract class UnlinkedParam extends base.SummaryClass {
+  /**
+   * Annotations for this parameter.
+   */
+  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].
+   */
+  UnlinkedConst get defaultValue;
+
+  /**
+   * 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.
+   */
+  int get inferredTypeSlot;
+
+  /**
+   * 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;
+
+  /**
+   * Kind of the parameter.
+   */
+  UnlinkedParamKind get kind;
+
   /**
    * Name of the parameter.
    */
-  String name;
+  String get name;
 
   /**
    * Offset of the parameter name relative to the beginning of the file.
    */
   @informative
-  int nameOffset;
+  int get nameOffset;
+
+  /**
+   * If [isFunctionTyped] is `true`, the parameters of the function type.
+   */
+  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.
    */
-  EntityRef 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;
-
-  /**
-   * If this parameter's type is inferrable, 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
-   * inferrable, 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.
-   */
-  int inferredTypeSlot;
+  EntityRef get type;
 }
 
 /**
@@ -1198,20 +1313,25 @@
 /**
  * Unlinked summary information about a part declaration.
  */
-class UnlinkedPart {
+abstract class UnlinkedPart extends base.SummaryClass {
   /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
+   * Annotations for this part declaration.
    */
-  @informative
-  int uriOffset;
+  List<UnlinkedConst> get annotations;
 
   /**
    * End of the URI string (including quotes) relative to the beginning of the
    * file.
    */
   @informative
-  int uriEnd;
+  int get uriEnd;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  @informative
+  int get uriOffset;
 }
 
 /**
@@ -1222,29 +1342,29 @@
  * 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.
-   */
-  ReferenceKind kind;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int numTypeParameters;
-
+abstract class UnlinkedPublicName extends base.SummaryClass {
   /**
    * If this [UnlinkedPublicName] is a class, the list of members which can be
    * referenced from constants - static constant fields, static methods, and
    * constructors.  Otherwise empty.
    */
-  List<UnlinkedPublicName> constMembers;
+  List<UnlinkedPublicName> get constMembers;
+
+  /**
+   * The kind of object referred to by the name.
+   */
+  ReferenceKind get kind;
+
+  /**
+   * The name itself.
+   */
+  String get name;
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it accepts.  Otherwise zero.
+   */
+  int get numTypeParameters;
 }
 
 /**
@@ -1253,36 +1373,39 @@
  * required from dependent libraries in order to perform prelinking.
  */
 @topLevel
-class UnlinkedPublicNamespace {
+abstract class UnlinkedPublicNamespace extends base.SummaryClass {
+  factory UnlinkedPublicNamespace.fromBuffer(List<int> buffer) =>
+      generated.readUnlinkedPublicNamespace(buffer);
+
+  /**
+   * Export declarations in the compilation unit.
+   */
+  List<UnlinkedExportPublic> get exports;
+
   /**
    * 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;
+  List<UnlinkedPublicName> get names;
 
   /**
    * URIs referenced by part declarations in the compilation unit.
    */
-  List<String> parts;
+  List<String> get parts;
 }
 
 /**
  * Unlinked summary information about a name referred to in one library that
  * might be defined in another.
  */
-class UnlinkedReference {
+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".
    */
-  String name;
+  String get name;
 
   /**
    * Prefix used to refer to the entity, or zero if no prefix is used.  This is
@@ -1292,104 +1415,154 @@
    * UnlinkedUnit.references[i].prefixReference != 0, then
    * UnlinkedUnit.references[i].prefixReference < i.
    */
-  int prefixReference;
+  int get prefixReference;
 }
 
 /**
  * Unlinked summary information about a typedef declaration.
  */
-class UnlinkedTypedef {
+abstract class UnlinkedTypedef extends base.SummaryClass {
   /**
-   * Name of the typedef.
+   * Annotations for this typedef.
    */
-  String name;
-
-  /**
-   * Offset of the typedef name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
+  List<UnlinkedConst> get annotations;
 
   /**
    * Documentation comment for the typedef, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
 
   /**
-   * Type parameters of the typedef, if any.
+   * Name of the typedef.
    */
-  List<UnlinkedTypeParam> typeParameters;
+  String get name;
 
   /**
-   * Return type of the typedef.
+   * Offset of the typedef name relative to the beginning of the file.
    */
-  EntityRef returnType;
+  @informative
+  int get nameOffset;
 
   /**
    * Parameters of the executable, if any.
    */
-  List<UnlinkedParam> parameters;
+  List<UnlinkedParam> get parameters;
+
+  /**
+   * Return type of the typedef.
+   */
+  EntityRef get returnType;
+
+  /**
+   * Type parameters of the typedef, if any.
+   */
+  List<UnlinkedTypeParam> get typeParameters;
 }
 
 /**
  * Unlinked summary information about a type parameter declaration.
  */
-class UnlinkedTypeParam {
+abstract class UnlinkedTypeParam extends base.SummaryClass {
   /**
-   * Name of the type parameter.
+   * Annotations for this type parameter.
    */
-  String name;
-
-  /**
-   * Offset of the type parameter name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
+  List<UnlinkedConst> get annotations;
 
   /**
    * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
    * null.
    */
-  EntityRef bound;
+  EntityRef get bound;
+
+  /**
+   * Name of the type parameter.
+   */
+  String get name;
+
+  /**
+   * Offset of the type parameter name relative to the beginning of the file.
+   */
+  @informative
+  int get nameOffset;
 }
 
 /**
  * Unlinked summary information about a compilation unit ("part file").
  */
 @topLevel
-class UnlinkedUnit {
-  /**
-   * Name of the library (from a "library" declaration, if present).
-   */
-  String libraryName;
+abstract class UnlinkedUnit extends base.SummaryClass {
+  factory UnlinkedUnit.fromBuffer(List<int> buffer) =>
+      generated.readUnlinkedUnit(buffer);
 
   /**
-   * Offset of the library name relative to the beginning of the file (or 0 if
-   * the library has no name).
+   * Classes declared in the compilation unit.
    */
-  @informative
-  int libraryNameOffset;
+  List<UnlinkedClass> get classes;
 
   /**
-   * Length of the library name as it appears in the source code (or 0 if the
-   * library has no name).
+   * Enums declared in the compilation unit.
    */
-  @informative
-  int libraryNameLength;
+  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;
+
+  /**
+   * Annotations for the library declaration, or the empty list if there is no
+   * library declaration.
+   */
+  List<UnlinkedConst> get libraryAnnotations;
 
   /**
    * Documentation comment for the library, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment libraryDocumentationComment;
+  UnlinkedDocumentationComment get libraryDocumentationComment;
+
+  /**
+   * Name of the library (from a "library" declaration, if present).
+   */
+  String get libraryName;
+
+  /**
+   * Length of the library name as it appears in the source code (or 0 if the
+   * library has no name).
+   */
+  @informative
+  int get libraryNameLength;
+
+  /**
+   * Offset of the library name relative to the beginning of the file (or 0 if
+   * the library has no name).
+   */
+  @informative
+  int get libraryNameOffset;
+
+  /**
+   * Part declarations in the compilation unit.
+   */
+  List<UnlinkedPart> get parts;
 
   /**
    * Unlinked public namespace of this compilation unit.
    */
-  UnlinkedPublicNamespace publicNamespace;
+  UnlinkedPublicNamespace get publicNamespace;
 
   /**
    * Top level and prefixed names referred to by this compilation unit.  The
@@ -1398,83 +1571,60 @@
    * example [UnlinkedReference.prefixReference or
    * UnlinkedImport.prefixReference]).
    */
-  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;
+  List<UnlinkedReference> get references;
 
   /**
    * Typedefs declared in the compilation unit.
    */
-  List<UnlinkedTypedef> typedefs;
+  List<UnlinkedTypedef> get typedefs;
 
   /**
    * Top level variables declared in the compilation unit.
    */
-  List<UnlinkedVariable> variables;
+  List<UnlinkedVariable> get variables;
 }
 
 /**
  * Unlinked summary information about a top level variable, local variable, or
  * a field.
  */
-class UnlinkedVariable {
+abstract class UnlinkedVariable extends base.SummaryClass {
   /**
-   * Name of the variable.
+   * Annotations for this variable.
    */
-  String name;
+  List<UnlinkedConst> get annotations;
 
   /**
-   * 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].
    */
-  @informative
-  int nameOffset;
+  UnlinkedConst get constExpr;
 
   /**
    * Documentation comment for the variable, or `null` if there is no
    * documentation comment.
    */
   @informative
-  UnlinkedDocumentationComment documentationComment;
+  UnlinkedDocumentationComment get documentationComment;
 
   /**
-   * Declared type of the variable.  Absent if the type is implicit.
+   * 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`.
    */
-  EntityRef type;
+  int get inferredTypeSlot;
 
   /**
-   * If [isConst] is true, and the variable has an initializer, the constant
-   * expression in the initializer.
+   * Indicates whether the variable is declared using the `const` keyword.
    */
-  UnlinkedConst constExpr;
+  bool get isConst;
+
+  /**
+   * Indicates whether the variable is declared using the `final` keyword.
+   */
+  bool get isFinal;
 
   /**
    * Indicates whether the variable is declared using the `static` keyword.
@@ -1483,17 +1633,18 @@
    * declared using the `static` keyword (even though they are considered
    * static for semantic purposes).
    */
-  bool isStatic;
+  bool get isStatic;
 
   /**
-   * Indicates whether the variable is declared using the `final` keyword.
+   * Name of the variable.
    */
-  bool isFinal;
+  String get name;
 
   /**
-   * Indicates whether the variable is declared using the `const` keyword.
+   * Offset of the variable name relative to the beginning of the file.
    */
-  bool isConst;
+  @informative
+  int get nameOffset;
 
   /**
    * If this variable is propagable, nonzero slot id identifying which entry in
@@ -1503,13 +1654,10 @@
    *
    * Non-propagable variables have a [propagatedTypeSlot] of zero.
    */
-  int propagatedTypeSlot;
+  int get propagatedTypeSlot;
 
   /**
-   * If this variable is inferrable, 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`.
+   * Declared type of the variable.  Absent if the type is implicit.
    */
-  int inferredTypeSlot;
+  EntityRef get type;
 }
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/prelink.dart b/pkg/analyzer/lib/src/summary/prelink.dart
index b885a7b..82ab7c5 100644
--- a/pkg/analyzer/lib/src/summary/prelink.dart
+++ b/pkg/analyzer/lib/src/summary/prelink.dart
@@ -3,6 +3,7 @@
 // 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';
 
 /**
@@ -195,7 +196,7 @@
             Map<String, _Meaning> namespace = <String, _Meaning>{};
             name.constMembers.forEach((executable) {
               namespace[executable.name] = new _Meaning(unitNum,
-                  executable.kind, dependency, executable.numTypeParameters);
+                  executable.kind, 0, executable.numTypeParameters);
             });
             return new _ClassMeaning(
                 unitNum, dependency, name.numTypeParameters, namespace);
diff --git a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
index 75d142e..4edd4cd 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],
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 4a182ed..0a71496 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -10,6 +10,7 @@
 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/element_handle.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -19,7 +20,7 @@
 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/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 
 /**
  * Implementation of [ElementResynthesizer] used when resynthesizing an element
@@ -261,7 +262,9 @@
   Expression get expr => stack.single;
 
   Expression build() {
-    // TODO(scheglov) complete implementation
+    if (uc.isInvalid) {
+      return AstFactory.identifier3(r'$$invalidConstExpr$$');
+    }
     for (UnlinkedConstOperation operation in uc.operations) {
       switch (operation) {
         case UnlinkedConstOperation.pushNull:
@@ -425,8 +428,21 @@
           _pushInstanceCreation();
           break;
         case UnlinkedConstOperation.length:
-          return AstFactory.nullLiteral();
-//          throw new StateError('Unsupported constant operation $operation');
+          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;
@@ -439,8 +455,10 @@
       (node.name as SimpleIdentifier).staticElement = type.element;
       return node;
     } else if (type is InterfaceType) {
-      List<TypeName> argumentNodes =
-          type.typeArguments.map(_buildTypeAst).toList();
+      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;
@@ -449,6 +467,28 @@
     throw new StateError('Unsupported type $type');
   }
 
+  /**
+   * Return the [ConstructorElement] by applying [typeArgumentRefs] to the
+   * given linked [info].  Both cases when [info] is a [ClassElement] and
+   * [ConstructorElement] are supported.
+   */
+  _DeferredConstructorElement _createConstructorElement(
+      _ReferenceInfo info, List<EntityRef> typeArgumentRefs) {
+    bool isClass = info.element is ClassElement;
+    _ReferenceInfo classInfo = isClass ? info : info.enclosing;
+    List<DartType> typeArguments =
+        typeArgumentRefs.map(resynthesizer.buildType).toList();
+    InterfaceType classType = classInfo.buildType((i) {
+      if (i < typeArguments.length) {
+        return typeArguments[i];
+      } else {
+        return DynamicTypeImpl.instance;
+      }
+    }, const <int>[]);
+    String name = isClass ? '' : info.name;
+    return new _DeferredConstructorElement(classType, name);
+  }
+
   InterpolationElement _newInterpolationElement(Expression expr) {
     if (expr is SimpleStringLiteral) {
       return new InterpolationString(expr.literal, expr.value);
@@ -485,28 +525,18 @@
   void _pushInstanceCreation() {
     EntityRef ref = uc.references[refPtr++];
     _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
-    // prepare ClassElement / ConstructorElement
-    String className;
-    ClassElement classElement;
+    // prepare ConstructorElement
     String constructorName;
-    ConstructorElement constructorElement;
     if (info.element is ConstructorElement) {
       constructorName = info.name;
-      constructorElement = info.element;
-      className = info.enclosing.name;
-      classElement = info.enclosing.element as ClassElement;
     } else if (info.element is ClassElement) {
-      className = info.name;
-      classElement = info.element;
       constructorName = null;
-      constructorElement = new ConstructorElementHandle(
-          resynthesizer.summaryResynthesizer,
-          new ElementLocationImpl.con3(
-              classElement.location.components.toList()..add('')));
     } else {
       throw new StateError('Unsupported element for invokeConstructor '
           '${info.element?.runtimeType}');
     }
+    _DeferredConstructorElement constructorElement =
+        _createConstructorElement(info, ref.typeArguments);
     // prepare arguments
     List<Expression> arguments;
     {
@@ -522,13 +552,11 @@
       }
     }
     // create TypeName
-    SimpleIdentifier typeNameNode = AstFactory.identifier3(className);
-    typeNameNode.staticElement = classElement;
-    TypeName typeNode = AstFactory.typeName3(typeNameNode);
+    TypeName typeNode = _buildTypeAst(constructorElement.definingType);
     // create ConstructorName
     ConstructorName constructorNode;
     if (constructorName != null) {
-      constructorNode = AstFactory.constructorName(typeNode, info.name);
+      constructorNode = AstFactory.constructorName(typeNode, constructorName);
       constructorNode.name.staticElement = constructorElement;
     } else {
       constructorNode = AstFactory.constructorName(typeNode, null);
@@ -576,6 +604,45 @@
 }
 
 /**
+ * The constructor element that has been resynthesized from a summary.  The
+ * actual element won't be constructed until it is requested.  But properties
+ * [definingType], [displayName], [enclosingElement] and [name] can be used
+ * without creating the actual element.
+ */
+class _DeferredConstructorElement extends ConstructorElementHandle {
+  final InterfaceType definingType;
+  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 {
+    ConstructorElement element = enclosingElement.getNamedConstructor(name);
+    return new ConstructorMember(element, definingType);
+  }
+
+  @override
+  AnalysisContext get context => definingType.element.context;
+
+  @override
+  String get displayName => name;
+
+  @override
+  ClassElement get enclosingElement {
+    return definingType.element;
+  }
+}
+
+/**
  * An instance of [_LibraryResynthesizer] is responsible for resynthesizing the
  * elements in a single library from that library's summary.
  */
@@ -635,6 +702,18 @@
   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 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.
@@ -661,6 +740,13 @@
   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.
    */
@@ -679,6 +765,40 @@
       ?.toList();
 
   /**
+   * Build the annotations for the given [element].
+   */
+  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) {
@@ -713,6 +833,7 @@
         buildVariable(serializedVariable, memberHolder);
       }
       bool constructorFound = false;
+      constructors = <String, ConstructorElementImpl>{};
       for (UnlinkedExecutable serializedExecutable
           in serializedClass.executables) {
         switch (serializedExecutable.kind) {
@@ -747,10 +868,13 @@
       correspondingType.typeArguments = currentTypeArguments;
       classElement.type = correspondingType;
       buildDocumentation(classElement, serializedClass.documentationComment);
+      buildAnnotations(classElement, serializedClass.annotations);
+      resolveConstructorInitializers(classElement);
       unitHolder.addType(classElement);
     } finally {
       currentTypeParameters = <TypeParameterElement>[];
       fields = null;
+      constructors = null;
     }
   }
 
@@ -774,6 +898,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.
@@ -781,13 +928,19 @@
   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);
+    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();
+    holder.addConstructor(currentConstructor);
+    currentConstructor = null;
   }
 
   /**
@@ -816,6 +969,7 @@
     classElement.type = enumType;
     classElement.supertype = summaryResynthesizer.typeProvider.objectType;
     buildDocumentation(classElement, serializedEnum.documentationComment);
+    buildAnnotations(classElement, serializedEnum.annotations);
     ElementHolder memberHolder = new ElementHolder();
     FieldElementImpl indexField = new FieldElementImpl('index', -1);
     indexField.final2 = true;
@@ -959,6 +1113,7 @@
         oldTypeParametersLength, currentTypeParameters.length);
     buildDocumentation(
         executableElement, serializedExecutable.documentationComment);
+    buildAnnotations(executableElement, serializedExecutable.annotations);
   }
 
   /**
@@ -980,6 +1135,7 @@
         serializedExportPublic.combinators.map(buildCombinator).toList();
     exportElement.uriOffset = serializedExportNonPublic.uriOffset;
     exportElement.uriEnd = serializedExportNonPublic.uriEnd;
+    buildAnnotations(exportElement, serializedExportNonPublic.annotations);
     return exportElement;
   }
 
@@ -1039,17 +1195,6 @@
   }
 
   /**
-   * Resynthesize a [FieldElement].
-   */
-  FieldElement buildField(UnlinkedVariable serializedField) {
-    FieldElementImpl fieldElement =
-        new FieldElementImpl(serializedField.name, -1);
-    fieldElement.type = buildType(serializedField.type);
-    fieldElement.const3 = serializedField.isConst;
-    return fieldElement;
-  }
-
-  /**
    * Build the implicit getter and setter associated with [element], and place
    * them in [holder].
    */
@@ -1150,6 +1295,7 @@
       importElement.uriOffset = serializedImport.uriOffset;
       importElement.uriEnd = serializedImport.uriEnd;
       importElement.deferred = serializedImport.isDeferred;
+      buildAnnotations(importElement, serializedImport.annotations);
     }
     importElement.prefixOffset = serializedImport.prefixOffset;
     if (serializedImport.prefixReference != 0) {
@@ -1167,6 +1313,9 @@
    * 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 library = new LibraryElementImpl(
         summaryResynthesizer.context,
@@ -1174,8 +1323,7 @@
         hasName ? unlinkedUnits[0].libraryNameOffset : -1,
         unlinkedUnits[0].libraryNameLength);
     buildDocumentation(library, unlinkedUnits[0].libraryDocumentationComment);
-    CompilationUnitElementImpl definingCompilationUnit =
-        new CompilationUnitElementImpl(librarySource.shortName);
+    buildAnnotations(library, unlinkedUnits[0].libraryAnnotations);
     library.definingCompilationUnit = definingCompilationUnit;
     definingCompilationUnit.source = librarySource;
     definingCompilationUnit.librarySource = librarySource;
@@ -1206,8 +1354,11 @@
     }
     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.
@@ -1266,13 +1417,34 @@
   ParameterElement buildParameter(UnlinkedParam serializedParameter) {
     ParameterElementImpl parameterElement;
     if (serializedParameter.isInitializingFormal) {
-      parameterElement = new FieldFormalParameterElementImpl.forNameAndOffset(
-          serializedParameter.name, serializedParameter.nameOffset)
-        ..field = fields[serializedParameter.name];
+      FieldFormalParameterElementImpl initializingParameter;
+      if (serializedParameter.defaultValue != null) {
+        DefaultFieldFormalParameterElementImpl defaultParameter =
+            new DefaultFieldFormalParameterElementImpl(
+                serializedParameter.name, serializedParameter.nameOffset);
+        initializingParameter = defaultParameter;
+        defaultParameter.constantInitializer =
+            _buildConstExpression(serializedParameter.defaultValue);
+      } else {
+        initializingParameter = new FieldFormalParameterElementImpl(
+            serializedParameter.name, serializedParameter.nameOffset);
+      }
+      parameterElement = initializingParameter;
+      initializingParameter.field = fields[serializedParameter.name];
     } else {
-      parameterElement = new ParameterElementImpl(
-          serializedParameter.name, serializedParameter.nameOffset);
+      if (serializedParameter.defaultValue != null) {
+        DefaultParameterElementImpl defaultParameter =
+            new DefaultParameterElementImpl(
+                serializedParameter.name, serializedParameter.nameOffset);
+        parameterElement = defaultParameter;
+        defaultParameter.constantInitializer =
+            _buildConstExpression(serializedParameter.defaultValue);
+      } else {
+        parameterElement = new ParameterElementImpl(
+            serializedParameter.name, serializedParameter.nameOffset);
+      }
     }
+    buildAnnotations(parameterElement, serializedParameter.annotations);
     if (serializedParameter.isFunctionTyped) {
       FunctionElementImpl parameterTypeElement =
           new FunctionElementImpl('', -1);
@@ -1326,6 +1498,7 @@
     partUnit.source = unitSource;
     partUnit.librarySource = librarySource;
     partUnit.uri = uri;
+    buildAnnotations(partUnit, partDecl.annotations);
     return partUnit;
   }
 
@@ -1386,6 +1559,7 @@
       functionTypeAliasElement.typeParameters = currentTypeParameters;
       buildDocumentation(
           functionTypeAliasElement, serializedTypedef.documentationComment);
+      buildAnnotations(functionTypeAliasElement, serializedTypedef.annotations);
       unitHolder.addTypeAlias(functionTypeAliasElement);
     } finally {
       currentTypeParameters = <TypeParameterElement>[];
@@ -1406,6 +1580,7 @@
         new TypeParameterElementImpl(
             serializedTypeParameter.name, serializedTypeParameter.nameOffset);
     typeParameterElement.type = new TypeParameterTypeImpl(typeParameterElement);
+    buildAnnotations(typeParameterElement, serializedTypeParameter.annotations);
     return typeParameterElement;
   }
 
@@ -1421,10 +1596,8 @@
             new ConstTopLevelVariableElementImpl(
                 serializedVariable.name, serializedVariable.nameOffset);
         element = constElement;
-        // TODO(scheglov) share const builder?
-        _ConstExprBuilder builder =
-            new _ConstExprBuilder(this, serializedVariable.constExpr);
-        constElement.constantInitializer = builder.build();
+        constElement.constantInitializer =
+            _buildConstExpression(serializedVariable.constExpr);
       } else {
         element = new TopLevelVariableElementImpl(
             serializedVariable.name, serializedVariable.nameOffset);
@@ -1433,8 +1606,17 @@
       unitHolder.addTopLevelVariable(element);
       buildImplicitAccessors(element, unitHolder);
     } else {
-      FieldElementImpl element = new FieldElementImpl(
-          serializedVariable.name, serializedVariable.nameOffset);
+      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);
+      }
       buildVariableCommonParts(element, serializedVariable);
       element.static = serializedVariable.isStatic;
       holder.addField(element);
@@ -1456,6 +1638,7 @@
     element.propagatedType =
         buildLinkedType(serializedVariable.propagatedTypeSlot);
     buildDocumentation(element, serializedVariable.documentationComment);
+    buildAnnotations(element, serializedVariable.annotations);
   }
 
   /**
@@ -1469,6 +1652,19 @@
   }
 
   /**
+   * 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;
+  }
+
+  /**
    * Build the components of an [ElementLocationImpl] for the entity in the
    * given [unit] of the dependency located at [dependencyIndex], and having
    * the given [name].
@@ -1526,6 +1722,7 @@
       }
       Element element;
       DartType type;
+      int numTypeParameters = linkedReference.numTypeParameters;
       if (linkedReference.kind == ReferenceKind.unresolved) {
         type = summaryResynthesizer.typeProvider.undefinedType;
         element = type.element;
@@ -1555,37 +1752,43 @@
           case ReferenceKind.classOrEnum:
             element = new ClassElementHandle(summaryResynthesizer, location);
             break;
-          case ReferenceKind.typedef:
-            element = new FunctionTypeAliasElementHandle(
-                summaryResynthesizer, location);
-            break;
-          case ReferenceKind.topLevelPropertyAccessor:
-            element = new PropertyAccessorElementHandle(
-                summaryResynthesizer, location);
-            break;
           case ReferenceKind.constructor:
             assert(location.components.length == 4);
             element =
                 new ConstructorElementHandle(summaryResynthesizer, location);
+            numTypeParameters = enclosingInfo.numTypeParameters;
+            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.method:
-            assert(location.components.length == 4);
-            element = new MethodElementHandle(summaryResynthesizer, location);
+          case ReferenceKind.topLevelFunction:
+            assert(location.components.length == 3);
+            element = new FunctionElementHandle(summaryResynthesizer, location);
             break;
-          default:
-            // This is an element that doesn't (yet) need to be referred to
-            // directly, so don't bother populating an element for it.
-            // TODO(paulberry): add support for more kinds, as needed.
+          case ReferenceKind.topLevelPropertyAccessor:
+            element = new PropertyAccessorElementHandle(
+                summaryResynthesizer, location);
+            break;
+          case ReferenceKind.typedef:
+            element = new FunctionTypeAliasElementHandle(
+                summaryResynthesizer, location);
+            break;
+          case ReferenceKind.prefix:
+          case ReferenceKind.unresolved:
             break;
         }
       }
-      referenceInfos[i] = new _ReferenceInfo(enclosingInfo, name, element, type,
-          linkedReference.numTypeParameters);
+      referenceInfos[i] = new _ReferenceInfo(
+          enclosingInfo, name, element, type, numTypeParameters);
     }
   }
 
@@ -1594,14 +1797,6 @@
    * contained in it.
    */
   void populateUnit(CompilationUnitElementImpl unit, int unitNum) {
-    linkedUnit = linkedLibrary.units[unitNum];
-    unlinkedUnit = unlinkedUnits[unitNum];
-    linkedTypeMap = <int, EntityRef>{};
-    for (EntityRef t in linkedUnit.types) {
-      linkedTypeMap[t.slot] = t;
-    }
-    populateReferenceInfos();
-    unitHolder = new ElementHolder();
     unlinkedUnit.classes.forEach(buildClass);
     unlinkedUnit.enums.forEach(buildEnum);
     unlinkedUnit.executables.forEach(buildExecutable);
@@ -1637,14 +1832,65 @@
       elementMap[accessor.identifier] = accessor;
     }
     resummarizedElements[absoluteUri] = elementMap;
-    unitHolder = null;
-    linkedUnit = null;
-    unlinkedUnit = null;
-    linkedTypeMap = null;
-    referenceInfos = null;
   }
 
   /**
+   * 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?']));
+
+  /**
    * 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 `?`.
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index 20d646d..e5f4c4f 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/generated/scanner.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';
 
@@ -26,16 +27,47 @@
 class _ConstExprSerializer extends AbstractConstExprSerializer {
   final _SummarizeAstVisitor visitor;
 
-  _ConstExprSerializer(this.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
-  EntityRefBuilder serializeConstructorName(ConstructorName constructor) {
-    EntityRefBuilder typeBuilder = serializeType(constructor.type);
-    if (constructor.name == null) {
+  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 {
-      String name = constructor.name.name;
-      int nameRef = visitor.serializeReference(typeBuilder.reference, name);
+      int nameRef =
+          visitor.serializeReference(typeBuilder.reference, name.name);
       return new EntityRefBuilder(
           reference: nameRef, typeArguments: typeBuilder.typeArguments);
     }
@@ -44,9 +76,9 @@
   EntityRefBuilder serializeIdentifier(Identifier identifier) {
     EntityRefBuilder b = new EntityRefBuilder();
     if (identifier is SimpleIdentifier) {
-      b.reference = visitor.serializeReference(null, identifier.name);
+      b.reference = visitor.serializeSimpleReference(identifier.name);
     } else if (identifier is PrefixedIdentifier) {
-      int prefix = visitor.serializeReference(null, identifier.prefix.name);
+      int prefix = visitor.serializeSimpleReference(identifier.prefix.name);
       b.reference =
           visitor.serializeReference(prefix, identifier.identifier.name);
     } else {
@@ -77,19 +109,6 @@
 }
 
 /**
- * An [_OtherScopedEntity] is a [_ScopedEntity] that does not refer to a type
- * parameter.  Since we don't need to track any special information about these
- * types of scoped entities, it is a singleton class.
- */
-class _OtherScopedEntity extends _ScopedEntity {
-  static final _OtherScopedEntity _instance = new _OtherScopedEntity._();
-
-  factory _OtherScopedEntity() => _instance;
-
-  _OtherScopedEntity._();
-}
-
-/**
  * 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
@@ -116,6 +135,18 @@
 }
 
 /**
+ * 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 {}
@@ -199,7 +230,8 @@
 
   /**
    * List of [_Scope]s currently in effect.  This is used to resolve type names
-   * to type parameters within classes, typedefs, and executables.
+   * to type parameters within classes, typedefs, and executables, as well as
+   * references to class members.
    */
   final List<_Scope> scopes = <_Scope>[];
 
@@ -242,11 +274,23 @@
   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;
 
   /**
+   * A flag indicating whether a variable declaration is in the context of a
+   * field declaration.
+   */
+  bool inFieldContext = false;
+
+  /**
    * Create a slot id for storing a propagated or inferred type.
    */
   int assignTypeSlot() => ++numSlots;
@@ -255,7 +299,8 @@
    * Build a [_Scope] object containing the names defined within the body of a
    * class declaration.
    */
-  _Scope buildClassMemberScope(NodeList<ClassMember> members) {
+  _Scope buildClassMemberScope(
+      String className, NodeList<ClassMember> members) {
     _Scope scope = new _Scope();
     for (ClassMember member in members) {
       // TODO(paulbery): consider replacing these if-tests with dynamic method
@@ -263,16 +308,16 @@
       if (member is MethodDeclaration) {
         if (member.isSetter || member.isOperator) {
           // We don't have to handle setters or operators because the only
-          // thing we look up is type names.
+          // things we look up are type names and identifiers.
         } else {
-          scope[member.name.name] = new _OtherScopedEntity();
+          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 thing we look up is type names.
-          scope[field.name.name] = new _OtherScopedEntity();
+          // the only things we look up are type names and identifiers.
+          scope[field.name.name] = new _ScopedClassMember(className);
         }
       }
     }
@@ -280,6 +325,22 @@
   }
 
   /**
+   * Serialize the given list of [annotations].  If there are no annotations,
+   * the empty list is returned.
+   */
+  List<UnlinkedConstBuilder> serializeAnnotations(
+      NodeList<Annotation> annotations) {
+    if (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].
    */
@@ -293,7 +354,8 @@
       ImplementsClause implementsClause,
       NodeList<ClassMember> members,
       bool isMixinApplication,
-      Comment documentationComment) {
+      Comment documentationComment,
+      NodeList<Annotation> annotations) {
     int oldScopesLength = scopes.length;
     List<UnlinkedExecutableBuilder> oldExecutables = executables;
     executables = <UnlinkedExecutableBuilder>[];
@@ -318,7 +380,7 @@
           implementsClause.interfaces.map(serializeTypeName).toList();
     }
     if (members != null) {
-      scopes.add(buildClassMemberScope(members));
+      scopes.add(buildClassMemberScope(name, members));
       for (ClassMember member in members) {
         member.accept(this);
       }
@@ -328,6 +390,7 @@
     b.fields = variables;
     b.isAbstract = abstractKeyword != null;
     b.documentationComment = serializeDocumentation(documentationComment);
+    b.annotations = serializeAnnotations(annotations);
     classes.add(b);
     scopes.removeLast();
     assert(scopes.length == oldScopesLength);
@@ -368,6 +431,7 @@
     b.libraryNameOffset = libraryNameOffset;
     b.libraryNameLength = libraryNameLength;
     b.libraryDocumentationComment = libraryDocumentationComment;
+    b.libraryAnnotations = libraryAnnotations;
     b.classes = classes;
     b.enums = enums;
     b.executables = executables;
@@ -384,8 +448,10 @@
   /**
    * Serialize the given [expression], creating an [UnlinkedConstBuilder].
    */
-  UnlinkedConstBuilder serializeConstExpr(Expression expression) {
-    _ConstExprSerializer serializer = new _ConstExprSerializer(this);
+  UnlinkedConstBuilder serializeConstExpr(Expression expression,
+      [Set<String> constructorParameterNames]) {
+    _ConstExprSerializer serializer =
+        new _ConstExprSerializer(this, constructorParameterNames);
     serializer.serialize(expression);
     return serializer.toBuilder();
   }
@@ -422,6 +488,7 @@
       bool isTopLevel,
       bool isDeclaredStatic,
       Comment documentationComment,
+      NodeList<Annotation> annotations,
       TypeParameterList typeParameters,
       bool isExternal) {
     int oldScopesLength = scopes.length;
@@ -462,6 +529,7 @@
       }
     }
     b.documentationComment = serializeDocumentation(documentationComment);
+    b.annotations = serializeAnnotations(annotations);
     if (returnType == null && !isSemanticallyStatic) {
       b.inferredReturnTypeSlot = assignTypeSlot();
     }
@@ -493,6 +561,7 @@
     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;
@@ -525,6 +594,30 @@
       });
 
   /**
+   * 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
@@ -561,7 +654,7 @@
         b.reference = serializeReference(null, name);
       } else if (identifier is PrefixedIdentifier) {
         int prefixIndex = prefixIndices.putIfAbsent(identifier.prefix.name,
-            () => serializeReference(null, identifier.prefix.name));
+            () => serializeSimpleReference(identifier.prefix.name));
         b.reference =
             serializeReference(prefixIndex, identifier.identifier.name);
       } else {
@@ -610,8 +703,12 @@
    * Serialize the given [variables] into [UnlinkedVariable]s, and store them
    * in [this.variables].
    */
-  void serializeVariables(VariableDeclarationList variables,
-      bool isDeclaredStatic, Comment documentationComment, bool isField) {
+  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;
@@ -621,7 +718,8 @@
       b.nameOffset = variable.name.offset;
       b.type = serializeTypeName(variables.type);
       b.documentationComment = serializeDocumentation(documentationComment);
-      if (variable.isConst) {
+      b.annotations = serializeAnnotations(annotations);
+      if (variable.isConst || variable.isFinal && inFieldContext) {
         Expression initializer = variable.initializer;
         if (initializer != null) {
           b.constExpr = serializeConstExpr(initializer);
@@ -654,7 +752,8 @@
         node.implementsClause,
         node.members,
         false,
-        node.documentationComment);
+        node.documentationComment,
+        node.metadata);
   }
 
   @override
@@ -669,7 +768,8 @@
         node.implementsClause,
         null,
         true,
-        node.documentationComment);
+        node.documentationComment,
+        node.metadata);
   }
 
   @override
@@ -689,13 +789,28 @@
     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();
+    }
     executables.add(b);
   }
 
   @override
   UnlinkedParamBuilder visitDefaultFormalParameter(
       DefaultFormalParameter node) {
-    return node.parameter.accept(this);
+    UnlinkedParamBuilder b = node.parameter.accept(this);
+    if (node.defaultValue != null) {
+      b.defaultValue = serializeConstExpr(node.defaultValue);
+    }
+    return b;
   }
 
   @override
@@ -708,6 +823,7 @@
             name: value.name.name, nameOffset: value.name.offset))
         .toList();
     b.documentationComment = serializeDocumentation(node.documentationComment);
+    b.annotations = serializeAnnotations(node.metadata);
     enums.add(b);
   }
 
@@ -715,13 +831,19 @@
   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, true);
+    try {
+      inFieldContext = true;
+      serializeVariables(node.fields, node.staticKeyword != null,
+          node.documentationComment, node.metadata, true);
+    } finally {
+      inFieldContext = false;
+    }
   }
 
   @override
@@ -751,6 +873,7 @@
         true,
         false,
         node.documentationComment,
+        node.metadata,
         node.functionExpression.typeParameters,
         node.externalKeyword != null));
   }
@@ -773,6 +896,7 @@
         .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);
@@ -790,6 +914,7 @@
   @override
   void visitImportDirective(ImportDirective node) {
     UnlinkedImportBuilder b = new UnlinkedImportBuilder();
+    b.annotations = serializeAnnotations(node.metadata);
     if (node.uri.stringValue == 'dart:core') {
       hasCoreBeenImported = true;
     }
@@ -814,6 +939,7 @@
     libraryNameLength = node.name.length;
     libraryDocumentationComment =
         serializeDocumentation(node.documentationComment);
+    libraryAnnotations = serializeAnnotations(node.metadata);
   }
 
   @override
@@ -828,6 +954,7 @@
         false,
         node.isStatic,
         node.documentationComment,
+        node.metadata,
         node.typeParameters,
         node.externalKeyword != null));
   }
@@ -835,7 +962,9 @@
   @override
   void visitPartDirective(PartDirective node) {
     parts.add(new UnlinkedPartBuilder(
-        uriOffset: node.uri.offset, uriEnd: node.uri.end));
+        uriOffset: node.uri.offset,
+        uriEnd: node.uri.end,
+        annotations: serializeAnnotations(node.metadata)));
   }
 
   @override
@@ -850,7 +979,8 @@
 
   @override
   void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
-    serializeVariables(node.variables, false, node.documentationComment, false);
+    serializeVariables(
+        node.variables, false, node.documentationComment, node.metadata, false);
   }
 
   @override
@@ -861,6 +991,7 @@
     if (node.bound != null) {
       b.bound = serializeTypeName(node.bound);
     }
+    b.annotations = serializeAnnotations(node.metadata);
     return b;
   }
 
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
index 8d4f97b..b644788 100644
--- a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -7,6 +7,36 @@
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/scanner.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
@@ -14,6 +44,11 @@
  */
 abstract class AbstractConstExprSerializer {
   /**
+   * See [UnlinkedConstBuilder.isInvalid].
+   */
+  bool isInvalid = false;
+
+  /**
    * See [UnlinkedConstBuilder.operations].
    */
   final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[];
@@ -39,84 +74,61 @@
   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) {
-    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) {
-      references.add(serializeIdentifier(expr));
-      operations.add(UnlinkedConstOperation.pushReference);
-    } else if (expr is InstanceCreationExpression) {
-      _serializeInstanceCreation(expr);
-    } 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 _ConstExprSerializationError(
-            'Only "identity" function invocation is allowed.');
-      }
-      if (expr.argumentList == null ||
-          expr.argumentList.arguments.length != 2) {
-        throw new _ConstExprSerializationError(
-            '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 _ConstExprSerializationError('Unknown expression type: $expr');
+    try {
+      _serialize(expr);
+    } on StateError {
+      isInvalid = true;
     }
   }
 
   /**
-   * Return [EntityRefBuilder] that corresponds to the given [constructor].
+   * Serialize the given [annotation] into this serializer state.
    */
-  EntityRefBuilder serializeConstructorName(ConstructorName constructor);
+  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].
    */
@@ -132,6 +144,9 @@
    * serializer.
    */
   UnlinkedConstBuilder toBuilder() {
+    if (isInvalid) {
+      return new UnlinkedConstBuilder(isInvalid: true);
+    }
     return new UnlinkedConstBuilder(
         operations: operations,
         ints: ints,
@@ -161,9 +176,85 @@
     }
   }
 
+  /**
+   * 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);
+    _serialize(expr.leftOperand);
+    _serialize(expr.rightOperand);
     TokenType operator = expr.operator.type;
     if (operator == TokenType.EQ_EQ) {
       operations.add(UnlinkedConstOperation.equal);
@@ -204,35 +295,13 @@
     } else if (operator == TokenType.PERCENT) {
       operations.add(UnlinkedConstOperation.modulo);
     } else {
-      throw new _ConstExprSerializationError('Unknown operator: $operator');
+      throw new StateError('Unknown operator: $operator');
     }
   }
 
-  void _serializeInstanceCreation(InstanceCreationExpression expr) {
-    ConstructorName constructor = expr.constructorName;
-    List<Expression> arguments = expr.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(serializeConstructorName(constructor));
-  }
-
   void _serializeListLiteral(ListLiteral expr) {
     List<Expression> elements = expr.elements;
-    elements.forEach(serialize);
+    elements.forEach(_serialize);
     ints.add(elements.length);
     if (expr.typeArguments != null &&
         expr.typeArguments.arguments.length == 1) {
@@ -245,8 +314,8 @@
 
   void _serializeMapLiteral(MapLiteral expr) {
     for (MapLiteralEntry entry in expr.entries) {
-      serialize(entry.key);
-      serialize(entry.value);
+      _serialize(entry.key);
+      _serialize(entry.value);
     }
     ints.add(expr.entries.length);
     if (expr.typeArguments != null &&
@@ -260,7 +329,7 @@
   }
 
   void _serializePrefixExpression(PrefixExpression expr) {
-    serialize(expr.operand);
+    _serialize(expr.operand);
     TokenType operator = expr.operator.type;
     if (operator == TokenType.BANG) {
       operations.add(UnlinkedConstOperation.not);
@@ -269,7 +338,7 @@
     } else if (operator == TokenType.TILDE) {
       operations.add(UnlinkedConstOperation.complement);
     } else {
-      throw new _ConstExprSerializationError('Unknown operator: $operator');
+      throw new StateError('Unknown operator: $operator');
     }
   }
 
@@ -293,7 +362,7 @@
           operations.add(UnlinkedConstOperation.pushString);
           strings.add(element.value);
         } else {
-          serialize((element as InterpolationExpression).expression);
+          _serialize((element as InterpolationExpression).expression);
         }
       }
       operations.add(UnlinkedConstOperation.concatenate);
@@ -301,15 +370,3 @@
     }
   }
 }
-
-/**
- * Error that describes a problem during a constant expression serialization.
- */
-class _ConstExprSerializationError {
-  final String message;
-
-  _ConstExprSerializationError(this.message);
-
-  @override
-  String toString() => message;
-}
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 4d90318..168e91b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/generated/resolver.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';
 
@@ -221,6 +222,7 @@
         unlinkedUnit.libraryNameLength = libraryElement.nameLength;
         unlinkedUnit.libraryDocumentationComment =
             serializeDocumentation(libraryElement);
+        unlinkedUnit.libraryAnnotations = serializeAnnotations(libraryElement);
       }
       unlinkedUnit.publicNamespace = new UnlinkedPublicNamespaceBuilder(
           exports: libraryElement.exports.map(serializeExportPublic).toList(),
@@ -233,8 +235,10 @@
       unlinkedUnit.imports =
           libraryElement.imports.map(serializeImport).toList();
       unlinkedUnit.parts = libraryElement.parts
-          .map((CompilationUnitElement e) =>
-              new UnlinkedPartBuilder(uriOffset: e.uriOffset, uriEnd: e.uriEnd))
+          .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,
@@ -331,6 +335,21 @@
   }
 
   /**
+   * 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();
+  }
+
+  /**
    * Serialize the given [classElement], creating an [UnlinkedClass].
    */
   UnlinkedClassBuilder serializeClass(ClassElement classElement) {
@@ -375,6 +394,7 @@
     b.isAbstract = classElement.isAbstract;
     b.isMixinApplication = classElement.isMixinApplication;
     b.documentationComment = serializeDocumentation(classElement);
+    b.annotations = serializeAnnotations(classElement);
     return b;
   }
 
@@ -435,8 +455,10 @@
   /**
    * Serialize the given [expression], creating an [UnlinkedConstBuilder].
    */
-  UnlinkedConstBuilder serializeConstExpr(Expression expression) {
-    _ConstExprSerializer serializer = new _ConstExprSerializer(this);
+  UnlinkedConstBuilder serializeConstExpr(Expression expression,
+      [Set<String> constructorParameterNames]) {
+    _ConstExprSerializer serializer =
+        new _ConstExprSerializer(this, constructorParameterNames);
     serializer.serialize(expression);
     return serializer.toBuilder();
   }
@@ -475,6 +497,7 @@
     }
     b.values = values;
     b.documentationComment = serializeDocumentation(enumElement);
+    b.annotations = serializeAnnotations(enumElement);
     return b;
   }
 
@@ -505,10 +528,22 @@
       } 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;
+      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;
     }
@@ -517,6 +552,7 @@
         executableElement.enclosingElement is ClassElement;
     b.isExternal = executableElement.isExternal;
     b.documentationComment = serializeDocumentation(executableElement);
+    b.annotations = serializeAnnotations(executableElement);
     return b;
   }
 
@@ -529,6 +565,7 @@
     b.offset = exportElement.nameOffset;
     b.uriOffset = exportElement.uriOffset;
     b.uriEnd = exportElement.uriEnd;
+    b.annotations = serializeAnnotations(exportElement);
     return b;
   }
 
@@ -549,6 +586,7 @@
    */
   UnlinkedImportBuilder serializeImport(ImportElement importElement) {
     UnlinkedImportBuilder b = new UnlinkedImportBuilder();
+    b.annotations = serializeAnnotations(importElement);
     b.isDeferred = importElement.isDeferred;
     b.combinators = importElement.combinators.map(serializeCombinator).toList();
     if (importElement.prefix != null) {
@@ -586,6 +624,7 @@
         b.kind = UnlinkedParamKind.named;
         break;
     }
+    b.annotations = serializeAnnotations(parameter);
     b.isInitializingFormal = parameter.isInitializingFormal;
     DartType type = parameter.type;
     if (parameter.hasImplicitType) {
@@ -607,6 +646,13 @@
         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);
+      }
+    }
     return b;
   }
 
@@ -657,6 +703,7 @@
     b.returnType = serializeTypeRef(typedefElement.returnType, typedefElement);
     b.parameters = typedefElement.parameters.map(serializeParam).toList();
     b.documentationComment = serializeDocumentation(typedefElement);
+    b.annotations = serializeAnnotations(typedefElement);
     return b;
   }
 
@@ -671,6 +718,7 @@
     if (typeParameter.bound != null) {
       b.bound = serializeTypeRef(typeParameter.bound, typeParameter);
     }
+    b.annotations = serializeAnnotations(typeParameter);
     return b;
   }
 
@@ -776,7 +824,8 @@
     b.isFinal = variable.isFinal;
     b.isConst = variable.isConst;
     b.documentationComment = serializeDocumentation(variable);
-    if (variable.isConst && variable is ConstVariableElement) {
+    b.annotations = serializeAnnotations(variable);
+    if (variable is ConstVariableElement) {
       ConstVariableElement constVariable = variable as ConstVariableElement;
       Expression initializer = constVariable.constantInitializer;
       if (initializer != null) {
@@ -830,11 +879,15 @@
 
   int _getElementReferenceId(Element element, {bool linked: false}) {
     return referenceMap.putIfAbsent(element, () {
-      LibraryElement dependentLibrary = element?.library;
+      LibraryElement dependentLibrary;
+      if (element != null) {
+        Element enclosingElement = element.enclosingElement;
+        if (enclosingElement is CompilationUnitElement) {
+          dependentLibrary = enclosingElement.library;
+        }
+      }
       int unit;
       if (dependentLibrary == null) {
-        assert(element == librarySerializer.typeProvider.dynamicType.element ||
-            element == null);
         unit = 0;
         dependentLibrary = librarySerializer.libraryElement;
       } else {
@@ -904,24 +957,59 @@
 class _ConstExprSerializer extends AbstractConstExprSerializer {
   final _CompilationUnitSerializer serializer;
 
-  _ConstExprSerializer(this.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
-  EntityRefBuilder serializeConstructorName(ConstructorName constructor) {
-    DartType type = constructor.type.type;
-    EntityRefBuilder typeRef = serializer.serializeTypeRef(type, null);
-    if (constructor.name == null) {
+  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 = serializer.serializeTypeRef(type.type, null);
+    if (name == null) {
       return typeRef;
     } else {
       int typeId = typeRef.reference;
       LinkedReference typeLinkedRef = serializer.linkedReferences[typeId];
       serializer.unlinkedReferences.add(new UnlinkedReferenceBuilder(
-          name: constructor.name.name, prefixReference: typeId));
+          name: name.name, prefixReference: typeId));
       int refId = serializer.linkedReferences.length;
       serializer.linkedReferences.add(new LinkedReferenceBuilder(
-          kind: ReferenceKind.constructor,
-          dependency: typeLinkedRef.dependency,
-          unit: typeLinkedRef.unit));
+          kind: ReferenceKind.constructor, unit: typeLinkedRef.unit));
       return new EntityRefBuilder(
           reference: refId, typeArguments: typeRef.typeArguments);
     }
@@ -934,12 +1022,17 @@
     if (identifier is PrefixedIdentifier &&
         element is PropertyAccessorElement &&
         !element.isStatic) {
-      assert(element.name == 'length');
+      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));
   }
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 95c33f4..b12a34e 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -14,7 +14,7 @@
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart'
     show DartUriResolver, Source, SourceFactory, SourceKind;
-import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
 import 'package:analyzer/src/task/dart.dart'
     show
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index bafe917..c001aed 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -117,6 +117,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.
  *
@@ -561,24 +572,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.
@@ -1672,30 +1665,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)
     };
   }
@@ -4071,94 +4042,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.
  */
@@ -4296,6 +4179,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
  */
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 0f3b523..a041729 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -722,11 +722,10 @@
             this.exception = new CaughtException(exception, stackTrace);
             return null;
           } catch (exception, stackTrace) {
-            this.exception = new CaughtException(
-                throw new AnalysisException(
-                    'Cannot create work order to build $inputResult for $inputTarget',
-                    exception),
-                stackTrace);
+            this.exception = new CaughtException(exception, stackTrace);
+            throw new AnalysisException(
+                'Cannot create work order to build $inputResult for $inputTarget',
+                this.exception);
             return null;
           }
         }
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index 4f39f6b..8295439 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -138,6 +138,19 @@
       }
     }
 
+    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.
+    if (element is FunctionElement ||
+        element is MethodElement && element.isStatic) {
+      return new StaticTypeError(rules, expression, toT, reason: reason);
+    }
+
     // TODO(vsm): Change this to an assert when we have generic methods and
     // fix TypeRules._coerceTo to disallow implicit sideways casts.
     if (!rules.isSubtypeOf(toT, fromT)) {
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 05b5f1a..b106dee 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -15,6 +15,7 @@
     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';
 
 /**
  * Sets the type of the field. This is stored in the field itself, and the
@@ -28,8 +29,7 @@
   if (field is PropertyInducingElementImpl) {
     (field.getter as ExecutableElementImpl).returnType = newType;
     if (!field.isFinal && !field.isConst) {
-      (field.setter.parameters[0] as ParameterElementImpl).type =
-          newType;
+      (field.setter.parameters[0] as ParameterElementImpl).type = newType;
     }
   }
 }
@@ -122,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;
   }
 
   /**
@@ -173,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) {
       //
@@ -270,19 +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;
-      }
       (element as ExecutableElementImpl).returnType =
-          _computeReturnType(overriddenMethods);
+          _computeReturnType(overriddenTypes.map((t) => t.returnType));
       if (element is PropertyAccessorElement) {
         _updateSyntheticVariableType(element);
       }
@@ -295,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);
         }
@@ -326,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 + '=');
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index ee26679..2061e63 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -8,6 +8,7 @@
 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';
@@ -266,6 +267,50 @@
 
 @reflectiveTest
 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) {
+    compilationUnit = ParserTestCase.parseCompilationUnit(code);
+    ElementHolder holder = new ElementHolder();
+    ElementBuilder builder = new ElementBuilder(holder, compilationUnitElement);
+    compilationUnit.accept(builder);
+    return holder;
+  }
+
+  /**
+   * 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'''
@@ -274,20 +319,213 @@
   set zzz(y) {}
 }
 ''';
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
-    ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
-    unit.accept(builder);
-    ClassElement classElement = holder.types[0];
+    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 =
@@ -316,7 +554,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);
@@ -332,7 +570,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);
@@ -351,7 +589,7 @@
 
   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);
@@ -373,7 +611,7 @@
 
   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";
@@ -401,7 +639,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";
@@ -455,7 +693,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, '', []);
@@ -485,7 +723,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, '', []);
@@ -509,7 +747,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, '', []);
@@ -535,7 +773,7 @@
 
   void test_visitConstructorDeclaration_external() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
     ConstructorDeclaration constructorDeclaration =
         AstFactory.constructorDeclaration2(
@@ -564,7 +802,7 @@
 
   void test_visitConstructorDeclaration_factory() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
     ConstructorDeclaration constructorDeclaration =
         AstFactory.constructorDeclaration2(
@@ -591,7 +829,7 @@
 
   void test_visitConstructorDeclaration_minimal() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
     ConstructorDeclaration constructorDeclaration =
         AstFactory.constructorDeclaration2(
@@ -623,7 +861,7 @@
 
   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 =
@@ -653,7 +891,7 @@
 
   void test_visitConstructorDeclaration_unnamed() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
     ConstructorDeclaration constructorDeclaration =
         AstFactory.constructorDeclaration2(
@@ -682,7 +920,7 @@
   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);
@@ -708,7 +946,7 @@
   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);
@@ -734,7 +972,7 @@
   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(
@@ -760,7 +998,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(
@@ -785,7 +1023,7 @@
 
   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"]);
@@ -802,7 +1040,7 @@
 
   void test_visitFieldDeclaration() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String firstFieldName = "x";
     String secondFieldName = "y";
     FieldDeclaration fieldDeclaration =
@@ -838,7 +1076,7 @@
 
   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);
@@ -858,7 +1096,7 @@
 
   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,
@@ -882,7 +1120,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([
@@ -899,7 +1137,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,
@@ -927,7 +1165,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,
@@ -962,7 +1200,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'),
@@ -991,7 +1229,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,
@@ -1026,7 +1264,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(
@@ -1056,7 +1294,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);
@@ -1072,7 +1310,7 @@
 
   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(
@@ -1097,7 +1335,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);
@@ -1120,7 +1358,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);
@@ -1145,7 +1383,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());
@@ -1161,7 +1399,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,
@@ -1193,7 +1431,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,
@@ -1227,7 +1465,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,
@@ -1267,7 +1505,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,
@@ -1304,7 +1542,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,
@@ -1342,7 +1580,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,
@@ -1377,7 +1615,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,
@@ -1410,7 +1648,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,
@@ -1452,7 +1690,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,
@@ -1490,7 +1728,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,
@@ -1529,7 +1767,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,
@@ -1560,7 +1798,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,
@@ -1593,7 +1831,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";
@@ -1656,7 +1894,7 @@
 
   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),
@@ -1686,7 +1924,7 @@
   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);
@@ -1713,7 +1951,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);
@@ -1739,7 +1977,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);
@@ -1754,7 +1992,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";
@@ -1785,7 +2023,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";
@@ -1814,7 +2052,7 @@
 
   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.accept(builder);
@@ -1829,7 +2067,7 @@
 
   void test_visitVariableDeclaration_inConstructor() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // C() {var v;}
     //
@@ -1860,7 +2098,7 @@
 
   void test_visitVariableDeclaration_inMethod() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // m() {T v;}
     //
@@ -1890,7 +2128,7 @@
 
   void test_visitVariableDeclaration_localNestedInFunction() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // var f = () {var v;};
     //
@@ -1931,7 +2169,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);
@@ -1955,7 +2193,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));
@@ -1979,7 +2217,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 =
@@ -2007,7 +2245,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);
@@ -2036,6 +2274,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();
@@ -2578,7 +2819,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());
@@ -2587,6 +2828,9 @@
     expect(enums, hasLength(1));
     return enums[0];
   }
+
+  ElementBuilder _makeBuilder(ElementHolder holder) =>
+      new ElementBuilder(holder, new CompilationUnitElementImpl('test.dart'));
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index f82c31e..4b611b7 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -499,7 +499,14 @@
    * represents a reference to a compile-time constant variable).
    */
   void test_visitAnnotation_constantVariable() {
-    _node = AstFactory.annotation(AstFactory.identifier3('x'));
+    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));
   }
 
@@ -508,11 +515,27 @@
    * constructor.
    */
   void test_visitAnnotation_invocation() {
-    _node = AstFactory.annotation2(
-        AstFactory.identifier3('A'), null, AstFactory.argumentList());
+    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));
@@ -590,10 +613,10 @@
   List<Annotation> _findAnnotations() {
     Set<Annotation> annotations = new Set<Annotation>();
     for (ConstantEvaluationTarget target in _findConstants()) {
-      if (target is ConstantEvaluationTarget_Annotation) {
+      if (target is ElementAnnotationImpl) {
         expect(target.context, same(_context));
         expect(target.source, same(_source));
-        annotations.add(target.annotation);
+        annotations.add(target.annotationAst);
       }
     }
     return new List<Annotation>.from(annotations);
@@ -1824,6 +1847,7 @@
   }
 
   int _assertValidInt(EvaluationResultImpl result) {
+    expect(result, isNotNull);
     expect(result.value, isNotNull);
     DartObjectImpl value = result.value;
     expect(value.type, typeProvider.intType);
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 188cc26..4620528 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -6,6 +6,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.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';
@@ -18,6 +19,7 @@
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(DeclarationResolverMetadataTest);
   runReflectiveTests(DeclarationResolverTest);
   runReflectiveTests(StrongModeDeclarationResolverTest);
 }
@@ -35,28 +37,208 @@
 }
 
 @reflectiveTest
-class DeclarationResolverTest extends ResolverTestCase {
-  void fail_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));
+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() {
     super.setUp();
@@ -141,6 +323,27 @@
     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 {
@@ -160,6 +363,27 @@
     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));
+  }
 }
 
 /**
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 6b321b0..9e3b75a 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -22,8 +22,10 @@
 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';
@@ -118,6 +120,20 @@
   }
 }
 
+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");
+    }
+  }
+}
+
 @reflectiveTest
 class DeclarationMatcherTest extends ResolverTestCase {
   void setUp() {
@@ -3078,7 +3094,7 @@
     // build elements
     {
       ElementHolder holder = new ElementHolder();
-      ElementBuilder builder = new ElementBuilder(holder);
+      ElementBuilder builder = new ElementBuilder(holder, oldUnit.element);
       newUnit.accept(builder);
     }
     // match
@@ -3121,6 +3137,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 {
@@ -3426,6 +3457,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);
@@ -3437,6 +3471,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;
@@ -3444,11 +3482,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;
@@ -3458,6 +3497,8 @@
       LibraryElement library = resolve2(source);
       fullNewUnit = resolveCompilationUnit(source, library);
     }
+    _checkCacheEntries(cache);
+
     try {
       assertSameResolution(unit, fullNewUnit);
     } on IncrementalResolutionMismatch catch (mismatch) {
@@ -3477,6 +3518,7 @@
     library = resolve2(source);
     unit = resolveCompilationUnit(source, library);
     _runTasks();
+    _checkCacheEntries(analysisContext2.analysisCache);
   }
 
   void _runTasks() {
@@ -4502,6 +4544,19 @@
     expect(errors, isEmpty);
   }
 
+  void test_updateConstantInitializer() {
+    _resolveUnit(r'''
+main() {
+  const v = const [Unknown];
+}
+''');
+    _updateAndValidate(r'''
+main() {
+   const v = const [Unknown];
+}
+''');
+  }
+
   void test_updateErrors_addNew_hint1() {
     _resolveUnit(r'''
 int main() {
@@ -4867,6 +4922,7 @@
           analysisContext.getErrors(source).errors;
       _assertEqualErrors(newErrors, newFullErrors);
     }
+    _checkCacheEntries(analysisContext2.analysisCache);
   }
 
   static void _assertEqualToken(Token incrToken, Token fullToken) {
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 9ce75c6..de21885 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -170,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) {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 2855c21..2b33566 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -7136,6 +7136,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",
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index c05f4fd..01b0b73 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1598,17 +1598,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() {
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index adccead..5e6cfa4 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -7,7 +7,7 @@
 import 'dart:collection';
 
 import 'package:analyzer/dart/ast/ast.dart'
-    show AstNode, NodeLocator, SimpleIdentifier;
+    show AstNode, SimpleIdentifier;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index d07f422..32b2487 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 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';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
@@ -29,7 +30,6 @@
   runReflectiveTests(SourceRangeTest);
   runReflectiveTests(BooleanArrayTest);
   runReflectiveTests(DirectedGraphTest);
-  runReflectiveTests(ListUtilitiesTest);
   runReflectiveTests(MultipleMapIteratorTest);
   runReflectiveTests(SingleMapIteratorTest);
   runReflectiveTests(TokenMapTest);
@@ -63,1663 +63,1039 @@
 @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_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; }');
   }
 
   /**
@@ -1730,16 +1106,119 @@
    * @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;
+    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;
+      }
     }
   }
 }
@@ -3276,39 +2755,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>();
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
index 39e43bd..4453ab0 100644
--- a/pkg/analyzer/test/src/summary/prelinker_test.dart
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -7,7 +7,7 @@
 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/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/prelink.dart';
 import 'package:unittest/unittest.dart';
 
@@ -88,5 +88,6 @@
     }
     linked = new LinkedLibrary.fromBuffer(
         prelink(unlinkedUnits[0], getPart, getImport).toBuffer());
+    validateLinkedLibrary(linked);
   }
 }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index ce262d3..a19d1fa 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -4,23 +4,28 @@
 
 library test.src.serialization.elements_test;
 
+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/element_handle.dart';
 import 'package:analyzer/src/generated/engine.dart';
 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/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 = ' | ';
@@ -30,7 +35,7 @@
 @reflectiveTest
 class ResynthTest extends ResolverTestCase {
   Set<Source> otherLibrarySources = new Set<Source>();
-  bool shouldCompareConstValues = false;
+  bool constantInitializersAreInvalid = false;
 
   /**
    * Determine the analysis options that should be used for this test.
@@ -46,11 +51,13 @@
     otherLibrarySources.add(addNamedSource(filePath, contents));
   }
 
-  void checkLibrary(String text, {bool allowErrors: false}) {
+  void checkLibrary(String text,
+      {bool allowErrors: false, bool dumpSummaries: false}) {
     Source source = addSource(text);
     LibraryElementImpl original = resolve2(source);
     LibraryElementImpl resynthesized = resynthesizeLibraryElement(
-        encodeLibrary(original, allowErrors: allowErrors),
+        encodeLibrary(original,
+            allowErrors: allowErrors, dumpSummaries: dumpSummaries),
         source.uri.toString(),
         original);
     checkLibraryElements(original, resynthesized);
@@ -99,7 +106,6 @@
           original.loadLibraryFunction as ExecutableElementImpl,
           '(loadLibraryFunction)');
     }
-    // TODO(paulberry): test metadata.
   }
 
   /**
@@ -191,10 +197,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++) {
@@ -216,46 +224,76 @@
     }
     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 compareConstantExpressions(Expression r, Expression o, String desc) {
-    void compareLists(List<Object> rItems, List<Object> oItems) {
-      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) {
-          compareConstantExpressions(rItem, oItem, desc);
-        } else if (rItem is TypeName && oItem is TypeName) {
-          compareConstantExpressions(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) {
-          compareConstantExpressions(rItem.expression, oItem.expression, desc);
-        } else if (rItem is MapLiteralEntry && oItem is MapLiteralEntry) {
-          compareConstantExpressions(rItem.key, oItem.key, desc);
-          compareConstantExpressions(rItem.value, oItem.value, 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 {
-          fail('$desc Incompatible item types: '
-              '${rItem.runtimeType} vs. ${oItem.runtimeType}');
+          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 {
@@ -265,18 +303,26 @@
       // resynthesis and should not check them here.
       if (o is ParenthesizedExpression) {
         // We don't resynthesize parenthesis, so just ignore it.
-        compareConstantExpressions(r, o.expression, desc);
+        compareConstAsts(r, o.expression, desc);
       } else if (o is SimpleIdentifier && r is SimpleIdentifier) {
-        expect(r.name, o.name);
+        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.
+        // We often don't resynthesize prefixed identifiers.
         // We use simple identifiers with correct elements.
-        compareConstantExpressions(r, o.identifier, desc);
+        compareConstAsts(r, o.identifier, 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 && r is SimpleIdentifier) {
         // We don't resynthesize property access.
         // We use simple identifiers with correct elements.
-        compareConstantExpressions(r, o.propertyName, desc);
+        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) {
@@ -286,7 +332,7 @@
       } else if (o is DoubleLiteral && r is DoubleLiteral) {
         expect(r.value, o.value, reason: desc);
       } else if (o is StringInterpolation && r is StringInterpolation) {
-        compareLists(r.elements, o.elements);
+        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.
@@ -299,24 +345,26 @@
             reason: desc);
       } else if (o is NamedExpression && r is NamedExpression) {
         expect(r.name.label.name, o.name.label.name, reason: desc);
-        compareConstantExpressions(r.expression, o.expression, desc);
+        compareConstAsts(r.expression, o.expression, desc);
       } else if (o is BinaryExpression && r is BinaryExpression) {
         expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
-        compareConstantExpressions(r.leftOperand, o.leftOperand, desc);
-        compareConstantExpressions(r.rightOperand, o.rightOperand, 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);
-        compareConstantExpressions(r.operand, o.operand, desc);
+        compareConstAsts(r.operand, o.operand, desc);
       } else if (o is ConditionalExpression && r is ConditionalExpression) {
-        compareConstantExpressions(r.condition, o.condition, desc);
-        compareConstantExpressions(r.thenExpression, o.thenExpression, desc);
-        compareConstantExpressions(r.elseExpression, o.elseExpression, desc);
+        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) {
-        compareLists(r.typeArguments?.arguments, o.typeArguments?.arguments);
-        compareLists(r.elements, o.elements);
+        compareConstAstLists(
+            r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+        compareConstAstLists(r.elements, o.elements, desc);
       } else if (o is MapLiteral && r is MapLiteral) {
-        compareLists(r.typeArguments?.arguments, o.typeArguments?.arguments);
-        compareLists(r.entries, o.entries);
+        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);
@@ -330,11 +378,47 @@
         TypeName rType = rConstructor.type;
         expect(oType, isNotNull, reason: desc);
         expect(rType, isNotNull, reason: desc);
-        compareConstantExpressions(rType.name, oType.name, desc);
-        compareConstantExpressions(rConstructor.name, oConstructor.name, desc);
-        compareLists(r.argumentList.arguments, o.argumentList.arguments);
-      } else if (o is ConstructorName && r is ConstructorName) {
-        fail('Not implemented for ${r.runtimeType} vs. ${o.runtimeType}');
+        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}');
       }
@@ -344,7 +428,23 @@
   void compareConstructorElements(ConstructorElementImpl resynthesized,
       ConstructorElementImpl original, String desc) {
     compareExecutableElements(resynthesized, original, desc);
-    // TODO(paulberry): test redirectedConstructor and constantInitializers
+    compareConstAstLists(resynthesized.constantInitializers,
+        original.constantInitializers, desc);
+    // TODO(paulberry): test redirectedConstructor
+  }
+
+  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) {
@@ -356,6 +456,7 @@
     expect(resynthesized.documentationComment, original.documentationComment,
         reason: desc);
     expect(resynthesized.docRange, original.docRange, reason: desc);
+    compareMetadata(resynthesized.metadata, original.metadata, desc);
     // Modifiers are a pain to test via handles.  So just test them via the
     // actual element.
     ElementImpl actualResynthesized = getActualElement(resynthesized, desc);
@@ -366,6 +467,13 @@
       expect(got, want,
           reason: 'Mismatch in $desc.$modifier: got $got, want $want');
     }
+    // Validate members.
+    if (actualOriginal is Member) {
+      expect(actualResynthesized, new isInstanceOf<Member>(), reason: desc);
+    } else {
+      expect(actualResynthesized, isNot(new isInstanceOf<Member>()),
+          reason: desc);
+    }
   }
 
   void compareExecutableElements(ExecutableElement resynthesized,
@@ -456,6 +564,15 @@
     }
   }
 
+  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
@@ -655,13 +772,14 @@
       VariableElementImpl original, String desc) {
     compareElements(resynthesized, original, desc);
     compareTypes(resynthesized.type, original.type, desc);
-    // TODO(scheglov) implement and validate other constant variable types
-    if (shouldCompareConstValues &&
-        original is ConstTopLevelVariableElementImpl) {
-      compareConstantExpressions(resynthesized.constantInitializer,
-          original.constantInitializer, desc);
+    if (original is ConstVariableElement) {
+      Expression initializer = resynthesized.constantInitializer;
+      if (constantInitializersAreInvalid) {
+        _assertUnresolvedIdentifier(initializer, desc);
+      } else {
+        compareConstAsts(initializer, original.constantInitializer, desc);
+      }
     }
-    // TODO(paulberry): test initializer
   }
 
   /**
@@ -672,12 +790,12 @@
    * Errors will lead to a test failure unless [allowErrors] is `true`.
    */
   _TestSummaryResynthesizer encodeLibrary(LibraryElementImpl library,
-      {bool allowErrors: false}) {
+      {bool allowErrors: false, bool dumpSummaries: false}) {
     if (!allowErrors) {
       assertNoErrors(library.source);
     }
     addLibrary('dart:core');
-    return encodeLibraryElement(library);
+    return encodeLibraryElement(library, dumpSummaries: dumpSummaries);
   }
 
   /**
@@ -687,7 +805,8 @@
    * Caller is responsible for checking the library for errors, and adding any
    * dependent libraries using [addLibrary].
    */
-  _TestSummaryResynthesizer encodeLibraryElement(LibraryElementImpl library) {
+  _TestSummaryResynthesizer encodeLibraryElement(LibraryElementImpl library,
+      {bool dumpSummaries: false}) {
     Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
     LinkedLibrary getLinkedSummaryFor(LibraryElement lib) {
       LibrarySerializationResult serialized = serializeLibrary(
@@ -706,6 +825,14 @@
       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,
@@ -721,10 +848,12 @@
   }
 
   ElementImpl getActualElement(Element element, String desc) {
-    if (element is ElementHandle) {
-      return element.actualElement;
-    } else if (element is ElementImpl) {
+    if (element is ElementImpl) {
       return element;
+    } else if (element is ElementHandle) {
+      return getActualElement(element.actualElement, desc);
+    } else if (element is Member) {
+      return getActualElement(element.baseElement, desc);
     } else {
       fail('Unexpected type for resynthesized ($desc):'
           ' ${element.runtimeType}');
@@ -1065,8 +1194,124 @@
     checkLibrary('class C {} class D {}');
   }
 
+  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() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 class C {
   const C.named(bool a, int b, int c, {String d, double e});
@@ -1076,7 +1321,6 @@
   }
 
   test_const_invokeConstructor_named_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1091,7 +1335,6 @@
   }
 
   test_const_invokeConstructor_named_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1106,7 +1349,6 @@
   }
 
   test_const_invokeConstructor_unnamed() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 class C {
   const C();
@@ -1116,7 +1358,6 @@
   }
 
   test_const_invokeConstructor_unnamed_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1131,7 +1372,6 @@
   }
 
   test_const_invokeConstructor_unnamed_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1145,8 +1385,129 @@
 ''');
   }
 
+  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 methodNamed({p: 1 + 2}) {}
+}
+''');
+  }
+
   test_const_reference_staticField() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 class C {
   static const int F = 42;
@@ -1156,7 +1517,6 @@
   }
 
   test_const_reference_staticField_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1171,7 +1531,6 @@
   }
 
   test_const_reference_staticField_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1186,7 +1545,6 @@
   }
 
   test_const_reference_staticMethod() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 class C {
   static int m(int a, String b) => 42;
@@ -1196,7 +1554,6 @@
   }
 
   test_const_reference_staticMethod_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1211,7 +1568,6 @@
   }
 
   test_const_reference_staticMethod_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1225,8 +1581,38 @@
 ''');
   }
 
+  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() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const A = 1;
 const B = A + 2;
@@ -1234,7 +1620,6 @@
   }
 
   test_const_reference_topLevelVariable_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1247,7 +1632,6 @@
   }
 
   test_const_reference_topLevelVariable_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1260,7 +1644,6 @@
   }
 
   test_const_reference_type() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 class C {}
 class D<T> {}
@@ -1277,7 +1660,6 @@
   }
 
   test_const_reference_type_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1294,7 +1676,6 @@
   }
 
   test_const_reference_type_imported_withPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource(
         '/a.dart',
         r'''
@@ -1311,7 +1692,6 @@
   }
 
   test_const_topLevel_binary() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vEqual = 1 == 2;
 const vAnd = true && false;
@@ -1335,21 +1715,18 @@
   }
 
   test_const_topLevel_conditional() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vConditional = (1 == 2) ? 11 : 22;
 ''');
   }
 
   test_const_topLevel_identical() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vIdentical = (1 == 2) ? 11 : 22;
 ''');
   }
 
   test_const_topLevel_literal() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vNull = null;
 const vBoolFalse = false;
@@ -1365,7 +1742,6 @@
   }
 
   test_const_topLevel_prefix() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vNotEqual = 1 != 2;
 const vNot = !true;
@@ -1375,7 +1751,6 @@
   }
 
   test_const_topLevel_typedList() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vNull = const <Null>[];
 const vDynamic = const <dynamic>[1, 2, 3];
@@ -1387,7 +1762,6 @@
   }
 
   test_const_topLevel_typedList_imported() {
-    shouldCompareConstValues = true;
     addLibrarySource('/a.dart', 'class C {}');
     checkLibrary(r'''
 import 'a.dart';
@@ -1396,7 +1770,6 @@
   }
 
   test_const_topLevel_typedList_importedWithPrefix() {
-    shouldCompareConstValues = true;
     addLibrarySource('/a.dart', 'class C {}');
     checkLibrary(r'''
 import 'a.dart' as p;
@@ -1405,7 +1778,6 @@
   }
 
   test_const_topLevel_typedMap() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const vDynamic1 = const <dynamic, int>{};
 const vDynamic2 = const <int, dynamic>{};
@@ -1415,19 +1787,35 @@
   }
 
   test_const_topLevel_untypedList() {
-    shouldCompareConstValues = true;
     checkLibrary(r'''
 const v = const [1, 2, 3];
 ''');
   }
 
   test_const_topLevel_untypedMap() {
-    shouldCompareConstValues = true;
     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 {
@@ -1438,6 +1826,77 @@
 }''');
   }
 
+  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_core() {
     String uri = 'dart:core';
     LibraryElementImpl original =
@@ -1581,7 +2040,7 @@
   }
 
   test_field_propagatedType_final_dep_inLib() {
-    addNamedSource('/a.dart', 'final a = 1;');
+    addLibrarySource('/a.dart', 'final a = 1;');
     checkLibrary('''
 import "a.dart";
 class C {
@@ -1929,6 +2388,150 @@
     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 {
@@ -2351,6 +2954,12 @@
     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 {
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
index aa7dff0..af0ad99 100644
--- a/pkg/analyzer/test/src/summary/summarize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -9,7 +9,7 @@
 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/summary/format.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';
@@ -92,6 +92,7 @@
     }
     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)];
diff --git a/pkg/analyzer/test/src/summary/summarize_elements_test.dart b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
index 7b679b9..b854d31 100644
--- a/pkg/analyzer/test/src/summary/summarize_elements_test.dart
+++ b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
@@ -9,6 +9,7 @@
 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'
@@ -92,6 +93,7 @@
     {
       List<int> buffer = serializedLib.linked.toBuffer();
       linked = new LinkedLibrary.fromBuffer(buffer);
+      validateLinkedLibrary(linked);
     }
     unlinkedUnits = serializedLib.unlinkedUnits.map((UnlinkedUnitBuilder b) {
       List<int> buffer = b.toBuffer();
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 868fab4..63009b8 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -15,7 +15,7 @@
 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/idl.dart';
 import 'package:analyzer/src/summary/public_namespace_computer.dart'
     as public_namespace;
 import 'package:analyzer/src/summary/summarize_elements.dart'
@@ -186,6 +186,20 @@
   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].
    */
@@ -1526,6 +1540,33 @@
     ]);
   }
 
+  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);
@@ -1540,6 +1581,31 @@
     ]);
   }
 
+  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);');
@@ -1598,10 +1664,12 @@
       0
     ], referenceValidators: [
       (EntityRef r) {
-        checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+        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);
@@ -1630,10 +1698,12 @@
       0
     ], referenceValidators: [
       (EntityRef r) {
-        checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+        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',
                   inLibraryDefiningUnit: true)
@@ -1770,10 +1840,11 @@
       0,
       0
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
               expectedKind: ReferenceKind.constructor,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
               ])
     ]);
   }
@@ -1796,10 +1867,11 @@
       0,
       0
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'named',
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
               expectedKind: ReferenceKind.constructor,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
                 new _PrefixExpectation(ReferenceKind.prefix, 'p',
                     inLibraryDefiningUnit: true)
               ])
@@ -1930,7 +2002,7 @@
     _assertUnlinkedConst(variable.constExpr, operators: [
       UnlinkedConstOperation.pushReference
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'length',
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
               expectedKind: ReferenceKind.propertyAccessor,
               prefixExpectations: [
                 new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
@@ -2360,10 +2432,11 @@
     _assertUnlinkedConst(variable.constExpr, operators: [
       UnlinkedConstOperation.pushReference
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'F',
+      (EntityRef r) => checkTypeRef(r, null, null, 'F',
               expectedKind: ReferenceKind.propertyAccessor,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
               ])
     ]);
   }
@@ -2383,16 +2456,35 @@
     _assertUnlinkedConst(variable.constExpr, operators: [
       UnlinkedConstOperation.pushReference
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'F',
+      (EntityRef r) => checkTypeRef(r, null, null, 'F',
               expectedKind: ReferenceKind.propertyAccessor,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
                 new _PrefixExpectation(ReferenceKind.prefix, 'p',
                     inLibraryDefiningUnit: true),
               ])
     ]);
   }
 
+  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 {
@@ -2426,10 +2518,11 @@
     _assertUnlinkedConst(variable.constExpr, operators: [
       UnlinkedConstOperation.pushReference
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'm',
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
               ])
     ]);
   }
@@ -2449,10 +2542,82 @@
     _assertUnlinkedConst(variable.constExpr, operators: [
       UnlinkedConstOperation.pushReference
     ], referenceValidators: [
-      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'm',
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
               expectedKind: ReferenceKind.method,
               prefixExpectations: [
-                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p',
+                    inLibraryDefiningUnit: true)
+              ])
+    ]);
+  }
+
+  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',
                     inLibraryDefiningUnit: true)
               ])
@@ -2503,6 +2668,17 @@
     ]);
   }
 
+  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_pushString_adjacent() {
     UnlinkedVariable variable =
         serializeVariableText('const v = "aaa" "b" "ccc";');
@@ -2628,6 +2804,140 @@
     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:
@@ -2664,7 +2974,7 @@
   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 elment model doesn't record whether a
+      // element model because the element model doesn't record whether a
       // function-typed parameter's return type is implicit.
       return;
     }
@@ -2702,6 +3012,26 @@
     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);
+    _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.
@@ -2721,12 +3051,22 @@
   }
 
   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);
+    expect(parameter.defaultValue, isNull);
+  }
+
+  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);
+    _assertUnlinkedConst(parameter.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializing_formal_non_function_typed() {
@@ -2738,12 +3078,23 @@
   }
 
   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);
+    expect(parameter.defaultValue, isNull);
+  }
+
+  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);
+    _assertUnlinkedConst(parameter.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
   }
 
   test_constructor_initializing_formal_required() {
@@ -2764,6 +3115,19 @@
     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);
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
   test_constructor_named() {
     String text = 'class C { C.foo(); }';
     UnlinkedExecutable executable = findExecutable('foo',
@@ -3314,19 +3678,56 @@
     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);
+    _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}) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.named);
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.named);
+    expect(param.defaultValue, isNull);
+  }
+
+  test_executable_param_kind_named_withDefault() {
+    UnlinkedExecutable executable = serializeExecutableText('f({x: 42}) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.named);
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
   }
 
   test_executable_param_kind_positional() {
     UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.positional);
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.defaultValue, isNull);
+  }
+
+  test_executable_param_kind_positional_withDefault() {
+    UnlinkedExecutable executable = serializeExecutableText('f([x = 42]) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
   }
 
   test_executable_param_kind_required() {
     UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.required);
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.required);
+    expect(param.defaultValue, isNull);
   }
 
   test_executable_param_name() {
@@ -3700,6 +4101,7 @@
     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);
   }
@@ -3729,6 +4131,18 @@
     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() {
@@ -4222,9 +4636,7 @@
         greaterThanOrEqualTo(unlinkedUnits[0].references.length));
     LinkedReference linkedReference =
         linked.units[0].references[type.reference];
-    int expectedDep =
-        checkHasDependency(absUri('/b.dart'), 'b.dart', fullyLinked: true);
-    expect(linkedReference.dependency, expectedDep);
+    expect(linkedReference.dependency, 0);
     expect(linkedReference.kind, ReferenceKind.method);
     expect(linkedReference.name, 'f');
     expect(linkedReference.numTypeParameters, 0);
@@ -4415,6 +4827,299 @@
     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) {}', '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 {
@@ -5101,6 +5806,7 @@
     UnlinkedVariable variable =
         serializeVariableText('final int i = 0;', variableName: 'i');
     expect(variable.isFinal, isTrue);
+    expect(variable.constExpr, isNull);
   }
 
   test_variable_implicit_dynamic() {
@@ -5232,14 +5938,52 @@
     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 _assertUnlinkedConst(UnlinkedConst constExpr,
-      {List<UnlinkedConstOperation> operators,
+      {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);
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index e351c39..a259e62 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -185,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(
@@ -242,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': '''
@@ -469,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);
@@ -1072,10 +1139,7 @@
     // 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());
@@ -1102,10 +1166,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]);
   }
@@ -1169,9 +1230,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));
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 65de58d..0a00961 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);
@@ -51,11 +53,11 @@
           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;
         Object obj = 42;
@@ -82,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;
@@ -139,15 +141,17 @@
           (/*info:DYNAMIC_INVOKE*/f.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 {
@@ -219,11 +223,11 @@
         baz().toString();
         baz().hashCode;
       }
-    '''
+    ''');
   });
 
-  testChecker('Constructors', {
-    '/main.dart': '''
+  test('Constructors', () {
+    checkFile('''
       const num z = 25;
       Object obj = "world";
 
@@ -253,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;
       }
-   '''
+   ''');
   });
 
-  testChecker('Unbound type name', {
-    '/main.dart': '''
+  test('Unbound type name', () {
+    checkFile('''
       void main() {
          /*pass should be severe:STATIC_TYPE_ERROR*/AToB y;
       }
-   '''
+   ''');
   });
 
   // Regression test for https://github.com/dart-lang/sdk/issues/25069
-  testChecker('Void subtyping', {
-    '/main.dart': '''
+  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 {}
@@ -304,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 {}
@@ -328,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 {}
@@ -353,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 {}
@@ -381,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 {}
@@ -422,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
@@ -434,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;
@@ -474,11 +488,11 @@
           f = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: classes', {
-    '/main.dart': '''
+    test('classes', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -509,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 {}
 
@@ -557,31 +571,31 @@
         }
         {
           Left f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
           f = left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right;
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
         {
           Right f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
           f = right;
           f = bot;
         }
         {
           Bottom 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 literal variance', {
-    '/main.dart': '''
+    test('function literal variance', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -603,31 +617,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 {}
@@ -662,11 +676,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 {}
@@ -682,12 +793,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;
@@ -705,32 +903,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 {}
@@ -767,11 +964,11 @@
         bot = bot;
       }
     }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: named and optional parameters', {
-    '/main.dart': '''
+    test('named and optional parameters', () {
+      checkFile('''
 
       class A {}
 
@@ -886,11 +1083,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);
@@ -908,7 +1105,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;
          }
@@ -916,7 +1113,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;
@@ -949,31 +1146,32 @@
            f = (n2n as Function);
          }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: void', {
-    '/main.dart': '''
+    test('void', () {
+      checkFile('''
 
       class A {
         void bar() => null;
         void foo() => bar; // allowed
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function subtyping: uninferred closure', {
-    '/main.dart': '''
+    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));
       }
-    '''
+    ''');
+    });
   });
 
-  testChecker('Relaxed casts', {
-    '/main.dart': '''
+  test('Relaxed casts', () {
+    checkFile('''
 
       class A {}
 
@@ -1047,11 +1245,11 @@
         }
 
       }
-   '''
+   ''');
   });
 
-  testChecker('Type checking literals', {
-    '/main.dart': '''
+  test('Type checking literals', () {
+    checkFile('''
           test() {
             num n = 3;
             int i = 3;
@@ -1090,11 +1288,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;
@@ -1107,11 +1305,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;
@@ -1119,38 +1317,38 @@
             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('factory constructor downcast', {
-    '/main.dart': r'''
+  test('factory constructor downcast', () {
+    checkFile(r'''
         class Animal {
           Animal();
           factory Animal.cat() => return new Cat();
@@ -1161,11 +1359,11 @@
         void main() {
           Cat c = /*info:ASSIGNMENT_CAST*/new Animal.cat();
           c = /*severe:STATIC_TYPE_ERROR*/new Animal();
-        }'''
+        }''');
   });
 
-  testChecker('field/field override', {
-    '/main.dart': '''
+  test('field/field override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1190,11 +1388,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 {
@@ -1214,7 +1413,8 @@
             /*severe:INVALID_METHOD_OVERRIDE*/String _m1();
           }
     ''',
-    '/main.dart': '''
+        name: '/helper.dart');
+    checkFile('''
           import 'helper.dart' as helper;
 
           class Child extends helper.Base {
@@ -1224,11 +1424,11 @@
 
             String _m1();
           }
-    '''
+    ''');
   });
 
-  testChecker('getter/getter override', {
-    '/main.dart': '''
+  test('getter/getter override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1246,11 +1446,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 {}
@@ -1275,11 +1475,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 {}
@@ -1299,11 +1499,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 {}
@@ -1343,11 +1543,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 {}
@@ -1369,11 +1569,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 {}
 
@@ -1388,11 +1588,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;
           }
@@ -1412,11 +1612,11 @@
           class DerivedFuture4<A> extends Future<A> {
             /*=B*/ then/*<B>*/(Object onValue(A a)) => null;
           }
-      '''
+      ''');
   });
 
-  testChecker('generic function wrong number of arguments', {
-      '/main.dart': r'''
+  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;
 
@@ -1437,11 +1637,11 @@
             x = /*severe:STATIC_TYPE_ERROR*/bar(y: 1, x: 2, z: 3);
             x = /*severe:STATIC_TYPE_ERROR*/bar(x: 1);
           }
-      '''
+      ''');
   });
 
-  testChecker('type promotion from dynamic', {
-    '/main.dart': r'''
+  test('type promotion from dynamic', () {
+    checkFile(r'''
           f() {
             dynamic x;
             if (x is int) {
@@ -1456,11 +1656,11 @@
               String z = /*severe:STATIC_TYPE_ERROR*/x;
             }
           }
-    '''
+    ''');
   });
 
-  testChecker('unary operators', {
-    '/main.dart': '''
+  test('unary operators', () {
+    checkFile('''
       class A {
         A operator ~() {}
         A operator +(int x) {}
@@ -1492,11 +1692,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) {}
@@ -1557,11 +1757,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() {
@@ -1574,11 +1774,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) {}
@@ -1656,11 +1856,11 @@
             a[b] += /*severe:STATIC_TYPE_ERROR*/z;
             (/*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'); }
@@ -1691,11 +1891,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";
@@ -1706,21 +1906,21 @@
               int j = i + 1;
             }
           }
-        '''
+        ''');
   });
 
-  testChecker('loadLibrary', {
-    '/lib1.dart': '''library lib1;''',
-    '/main.dart': r'''
+  test('loadLibrary', () {
+    addFile('''library lib1;''', name: '/lib1.dart');
+    checkFile(r'''
         import 'lib1.dart' deferred as lib1;
         main() {
           Future f = lib1.loadLibrary();
-        }'''
+        }''');
   });
 
   group('invalid overrides', () {
-    testChecker('child override', {
-      '/main.dart': '''
+    test('child override', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1759,11 +1959,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 {}
 
@@ -1774,10 +1974,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 {}
 
@@ -1792,11 +1992,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 {}
 
@@ -1811,11 +2011,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 {}
 
@@ -1829,11 +2029,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 {}
 
@@ -1853,11 +2053,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 {}
 
@@ -1875,14 +2075,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 {}
 
@@ -1904,11 +2104,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 {}
 
@@ -1919,11 +2119,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 {}
 
@@ -1938,11 +2138,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 {}
 
@@ -1956,14 +2156,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 {}
 
@@ -1988,13 +2187,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 {}
 
@@ -2006,10 +2205,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 {}
 
@@ -2021,10 +2220,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 {}
 
@@ -2036,10 +2235,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 {}
 
@@ -2051,10 +2250,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 {}
 
@@ -2072,13 +2271,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 {}
 
@@ -2094,10 +2293,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 {}
 
@@ -2113,10 +2312,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 {}
 
@@ -2132,10 +2331,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 {}
 
@@ -2150,10 +2349,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 {}
 
@@ -2171,13 +2370,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 {}
 
@@ -2193,10 +2392,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 {}
 
@@ -2212,10 +2411,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 {}
 
@@ -2231,10 +2430,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 {}
 
@@ -2254,10 +2453,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 {}
 
@@ -2272,13 +2471,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 {}
 
@@ -2295,11 +2494,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 {}
 
@@ -2322,11 +2521,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 {}
 
@@ -2345,11 +2544,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 {}
 
@@ -2374,11 +2573,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 {}
 
@@ -2402,11 +2601,11 @@
                   with /*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 {}
 
@@ -2429,12 +2628,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);
@@ -2484,12 +2683,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;
 
@@ -2525,11 +2724,11 @@
             return new Future<bool>.value(false);
           }
         }
-    '''
+    ''');
     });
 
-    testChecker('async*', {
-      '/main.dart': '''
+    test('async*', () {
+      checkFile('''
         import 'dart:async';
 
         dynamic x;
@@ -2544,11 +2743,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;
@@ -2563,7 +2762,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 eccb4f2..663ee78 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,9 @@
             final c2 = 1;
           }
       ''',
-    '/e.dart': '''
+        name: '/c.dart');
+    addFile(
+        '''
           import 'a.dart';
           part 'e2.dart';
 
@@ -252,16 +273,21 @@
             final e6 = new A().a2;
           }
       ''',
-    '/f.dart': '''
+        name: '/e.dart');
+    addFile(
+        '''
           part 'f2.dart';
       ''',
-    '/e2.dart': '''
+        name: '/f.dart');
+    addFile(
+        '''
           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,12 +325,11 @@
             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();
@@ -346,11 +371,11 @@
           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 +401,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 +433,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 +501,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 +527,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 +542,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 +558,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 +586,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 +604,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 +621,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 +640,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 +659,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,11 +677,11 @@
           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));
         }
@@ -679,17 +706,19 @@
           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;
@@ -701,20 +730,22 @@
           int y = new C().x;
           String y = /*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 +769,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 +787,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 +816,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 +848,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 +865,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 +882,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 +909,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 +935,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 +953,8 @@
           static final a2 = b1;
         }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart';
         final m1 = a1;
         final m2 = A.a2;
@@ -926,11 +963,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 +978,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;
         }
       ''',
-    '/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 +1008,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 +1026,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 +1048,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 +1087,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 +1099,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 +1111,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 +1123,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 +1138,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,23 +1177,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);
@@ -1207,51 +1248,51 @@
   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 = '''
+    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) {};
       }
@@ -1268,41 +1309,41 @@
         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) {};
       }
@@ -1319,61 +1360,61 @@
         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> m1 = /*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 = {};
@@ -1383,18 +1424,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>{};
@@ -1402,19 +1443,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 () {
@@ -1447,11 +1488,11 @@
           Function2<String, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x.substring(3);
         }
       }
-      '''
+      ''');
   });
 
-  testChecker('downwards inference initializing formal, default formal', {
-    '/main.dart': '''
+  test('downwards inference initializing formal, default formal', () {
+    checkFile('''
       typedef T Function2<S, T>([S x]);
       class Foo {
         List<int> x;
@@ -1461,20 +1502,20 @@
       void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {}
 // We do this inference in an early task but don't preserve the infos.
       Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
-'''
+''');
   });
 
-  testChecker('downwards inference async/await', {
-    '/main.dart': '''
+  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]);
-        '''
+        ''');
   });
 
-  testChecker('downwards inference foreach', {
-    '/main.dart': '''
+  test('downwards inference foreach', () {
+    checkFile('''
       import 'dart:async';
       void main() {
         for(int x in /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3]) {
@@ -1482,11 +1523,11 @@
         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*/[];
@@ -1501,11 +1542,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);
@@ -1514,30 +1555,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);
@@ -1568,11 +1609,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));
@@ -1583,13 +1624,26 @@
           Future<String> results2 = results.then((List<int> list)
             => list.fold('', (String x, int y) => x + y.toString()));
         }
-    '''
+    ''');
     });
 
     // TODO(jmesserly): we should change how this inference works.
     // For now this test will cover what we use.
-    testChecker('infer JS builtin', {
-      '/main.dart': '''
+    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;
 
@@ -1611,9 +1665,8 @@
   takeOOI(/*severe:STATIC_TYPE_ERROR*/math.max);
   takeIDI(/*severe:STATIC_TYPE_ERROR*/math.max);
   takeDID(/*severe:STATIC_TYPE_ERROR*/math.max);
-
-  takeOON(/*warning:DOWN_CAST_COMPOSITE*/math.max);
-  takeOOO(/*warning:DOWN_CAST_COMPOSITE*/math.max);
+  takeOON(/*severe:STATIC_TYPE_ERROR*/math.max);
+  takeOOO(/*severe:STATIC_TYPE_ERROR*/math.max);
 
   // Also test SimpleIdentifier
   takeIII(min);
@@ -1629,10 +1682,9 @@
   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);
 
-  takeOON(/*warning:DOWN_CAST_COMPOSITE*/min);
-  takeOOO(/*warning:DOWN_CAST_COMPOSITE*/min);
-  
   // Also PropertyAccess
   takeIII(new C().m);
   takeDDD(new C().m);
@@ -1648,6 +1700,8 @@
   takeIDI(/*severe:STATIC_TYPE_ERROR*/new C().m);
   takeDID(/*severe:STATIC_TYPE_ERROR*/new C().m);
 
+  // Note: this is a warning because a downcast of a method tear-off could work
+  // (derived method can be a subtype).
   takeOON(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
   takeOOO(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
 }
@@ -1666,13 +1720,13 @@
 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/dev_compiler/issues/47
-  testChecker('null literal should not infer as bottom', {
-    '/main.dart': '''
+  test('null literal should not infer as bottom', () {
+    checkFile('''
       var h = null;
       void foo(int f(Object _)) {}
 
@@ -1690,6 +1744,37 @@
         foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) => null);
         foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) => throw "not implemented");
       }
-  '''
+  ''');
+  });
+
+  // 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().m/*<int>*/(42);
+  print(y);
+}
+    ''');
   });
 }
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 5e346d0..83c0477 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -22,18 +22,113 @@
 import 'package:source_span/source_span.dart';
 import 'package:unittest/unittest.dart';
 
-const String GREEN_COLOR = '\u001b[32m';
 
-const String NO_COLOR = '\u001b[0m';
+MemoryResourceProvider files;
+bool _checkCalled;
 
-const String _CYAN_COLOR = '\u001b[36m';
+initStrongModeTests() {
+  setUp(() {
+    AnalysisEngine.instance.processRequiredPlugins();
+    files = new MemoryResourceProvider();
+    _checkCalled = false;
+  });
 
-const String _MAGENTA_COLOR = '\u001b[35m';
+  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;
+  });
+}
 
-const String _RED_COLOR = '\u001b[31m';
+/// Adds a file using [addFile] and calls [check].
+void checkFile(String content) {
+  addFile(content);
+  check();
+}
+
+/// 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);
+}
+
+/// 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.
+void 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.strongModeHints = true;
+  context.sourceFactory = new SourceFactory([
+    new MockDartSdk(_mockSdkSources, reportMissing: true).resolver,
+    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();
+  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);
+    }
+  }
+}
 
 /// Sample mock SDK sources.
-final Map<String, String> mockSdkSources = {
+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)
@@ -128,19 +223,6 @@
   '''
 };
 
-/// 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;
-}
-
 SourceSpanWithContext createSpanHelper(
     LineInfo lineInfo, int start, int end, Source source, String content) {
   var startLoc = locationForOffset(lineInfo, source.uri, start);
@@ -195,93 +277,6 @@
   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');
-
-    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;
-
-    context.sourceFactory = new SourceFactory([
-      new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
-      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();
-    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);
-      }
-    }
-  });
-}
-
 /// 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 {
@@ -485,16 +480,34 @@
 
     var span = _createSpan(node.offset, node.length);
     var levelName = expected.level.name.toLowerCase();
-    var msg = span.message(expected.typeName, color: colorOf(levelName));
+    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));
+    var msg = span.message(actual.message, color: _colorOf(levelName));
     return '$levelName: [${errorCodeName(actual.errorCode)}] $msg';
   }
+
+  /// 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) {
+    const String CYAN_COLOR = '\u001b[36m';
+    const String MAGENTA_COLOR = '\u001b[35m';
+    const String RED_COLOR = '\u001b[31m';
+
+    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;
+  }
 }
 
 class _MockSdkSource implements Source {
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/tool/summary/build_sdk_summary.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
similarity index 63%
rename from pkg/analyzer/tool/summary/build_sdk_summary.dart
rename to pkg/analyzer/tool/summary/build_sdk_summaries.dart
index 738e0a1..2e680da 100644
--- a/pkg/analyzer/tool/summary/build_sdk_summary.dart
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -8,19 +8,22 @@
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/format.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 outputFilePath = args[0];
-  if (FileSystemEntity.isDirectorySync(outputFilePath)) {
-    print("'$outputFilePath' is a directory.");
+  String outputDirectoryPath = args[0];
+  if (!FileSystemEntity.isDirectorySync(outputDirectoryPath)) {
+    print("'$outputDirectoryPath' is not a directory.");
     _printUsage();
+    exitCode = 1;
     return;
   }
   //
@@ -32,16 +35,37 @@
     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.
+  //
+  _buildSummary(sdkPath, outputDirectoryPath, false);
+  _buildSummary(sdkPath, outputDirectoryPath, true);
+}
+
+/**
+ * The name of the SDK summaries builder application.
+ */
+const BINARY_NAME = "build_sdk_summaries";
+
+/**
+ * Build a strong or spec mode summary for the Dart SDK at [sdkPath].
+ */
+void _buildSummary(
+    String sdkPath, String outputDirectoryPath, bool strongMode) {
+  print('Generating ${strongMode ? 'strong' : 'spec'} mode summary.');
+  Stopwatch sw = new Stopwatch()..start();
+  //
   // Prepare SDK.
   //
   DirectoryBasedDartSdk sdk = new DirectoryBasedDartSdk(new JavaFile(sdkPath));
   AnalysisContext context = sdk.context;
+  context.analysisOptions = new AnalysisOptionsImpl()..strongMode = strongMode;
   //
   // Serialize each SDK library.
   //
@@ -50,13 +74,11 @@
   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);
-    // TODO(paulberry): also build a summary of the SDK in strong mode.
     LibrarySerializationResult libraryResult =
-        serializeLibrary(libraryElement, context.typeProvider, false);
+        serializeLibrary(libraryElement, context.typeProvider, strongMode);
     linkedLibraryUris.add(lib.shortName);
     linkedLibraries.add(libraryResult.linked);
     unlinkedUnitUris.addAll(libraryResult.unitUris);
@@ -70,18 +92,20 @@
       linkedLibraries: linkedLibraries,
       unlinkedUnitUris: unlinkedUnitUris,
       unlinkedUnits: unlinkedUnits);
+  String outputFilePath =
+      join(outputDirectoryPath, strongMode ? 'strong.sum' : 'spec.sum');
   File file = new File(outputFilePath);
   file.writeAsBytesSync(sdkBundle.toBuffer(), mode: FileMode.WRITE_ONLY);
+  //
+  // Done.
+  //
+  print('\tDone in ${sw.elapsedMilliseconds} ms.');
 }
 
 /**
- * The name of the SDK summary builder application.
- */
-const BINARY_NAME = "build_sdk_summary";
-
-/**
- * Print information about how to use the SDK summary builder.
+ * Print information about how to use the SDK summaries builder.
  */
 void _printUsage() {
-  print('Usage: $BINARY_NAME output_file_path [sdk_path]');
+  print('Usage: $BINARY_NAME output_directory_path [sdk_path]');
+  print('Build files spec.sum and strong.sum in the output directory.');
 }
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index afd790d..5c2d2bf 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -44,7 +44,7 @@
   // 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');
+  String idlPath = join(pkgPath, 'lib', 'src', 'summary', 'idl.dart');
   File idlFile = provider.getFile(idlPath);
   Source idlSource = provider.getFile(idlPath).createSource();
   String idlText = idlFile.readAsStringSync();
@@ -110,10 +110,11 @@
    * 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;
     }
   }
 
@@ -131,10 +132,11 @@
             new idlModel.FieldType(type.typeName, false);
         return '<${encodedType(elementType)}>[]';
       } else {
-        return 'const <${type.typeName}>[]';
+        return 'const <${idlPrefix(type.typeName)}>[]';
       }
     } else if (_idl.enums.containsKey(type.typeName)) {
-      return '${type.typeName}.${_idl.enums[type.typeName].values[0].name}';
+      return '${idlPrefix(type.typeName)}.'
+          '${_idl.enums[type.typeName].values[0].name}';
     } else if (type.typeName == 'int') {
       return '0';
     } else if (type.typeName == 'String') {
@@ -155,7 +157,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>';
@@ -183,9 +185,18 @@
         idlModel.ClassDeclaration cls =
             new idlModel.ClassDeclaration(doc, decl.name.name, isTopLevel);
         _idl.classes[cls.name] = cls;
+        String expectedBase = 'base.SummaryClass';
+        if (decl.extendsClause == null ||
+            decl.extendsClause.superclass.name.name != expectedBase) {
+          throw new Exception(
+              'Class `${cls.name}` needs to extend `$expectedBase`');
+        }
         for (ClassMember classMember in decl.members) {
-          if (classMember is FieldDeclaration) {
-            TypeName type = classMember.fields.type;
+          if (classMember is MethodDeclaration && classMember.isGetter) {
+            TypeName type = classMember.returnType;
+            if (type == null) {
+              throw new Exception('Class member needs a type: $classMember');
+            }
             bool isList = false;
             if (type.name.name == 'List' &&
                 type.typeArguments != null &&
@@ -199,10 +210,12 @@
             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.fields.add(new idlModel.FieldDeclaration(
+                doc, classMember.name.name, fieldType));
+          } 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`');
           }
@@ -227,6 +240,22 @@
   }
 
   /**
+   * 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()) {
@@ -273,20 +302,20 @@
     out();
     out('library analyzer.src.summary.format;');
     out();
-    out("import 'base.dart' as base;");
     out("import 'flat_buffers.dart' as fb;");
+    out("import 'idl.dart' as idl;");
     out();
     for (idlModel.EnumDeclaration enm in _idl.enums.values) {
-      _generateEnum(enm);
-      out();
       _generateEnumReader(enm);
       out();
     }
     for (idlModel.ClassDeclaration cls in _idl.classes.values) {
       _generateBuilder(cls);
       out();
-      _generateInterface(cls);
-      out();
+      if (cls.isTopLevel) {
+        _generateReadFunction(cls);
+        out();
+      }
       _generateReader(cls);
       out();
       _generateImpl(cls);
@@ -309,7 +338,7 @@
     String mixinName = '_${name}Mixin';
     List<String> constructorParams = <String>[];
     out('class $builderName extends Object with $mixinName '
-        'implements $name {');
+        'implements ${idlPrefix(name)} {');
     indent(() {
       out('bool _finished = false;');
       // Generate fields.
@@ -468,28 +497,10 @@
     out('}');
   }
 
-  void _generateEnum(idlModel.EnumDeclaration enm) {
-    String name = enm.name;
-    outDoc(enm.documentation);
-    out('enum $name {');
-    indent(() {
-      for (idlModel.EnumValueDeclaration value in enm.values) {
-        outDoc(value.documentation);
-        if (enm.values.last == value) {
-          out('${value.name}');
-        } else {
-          out('${value.name},');
-          out();
-        }
-      }
-    });
-    out('}');
-  }
-
   void _generateEnumReader(idlModel.EnumDeclaration enm) {
     String name = enm.name;
     String readerName = '_${name}Reader';
-    out('class $readerName extends fb.Reader<$name> {');
+    out('class $readerName extends fb.Reader<${idlPrefix(name)}> {');
     indent(() {
       out('const $readerName() : super();');
       out();
@@ -497,10 +508,10 @@
       out('int get size => 4;');
       out();
       out('@override');
-      out('$name read(fb.BufferPointer bp) {');
+      out('${idlPrefix(name)} read(fb.BufferPointer bp) {');
       indent(() {
         out('int index = const fb.Uint32Reader().read(bp);');
-        out('return $name.values[index];');
+        out('return ${idlPrefix(name)}.values[index];');
       });
       out('}');
     });
@@ -511,7 +522,8 @@
     String name = cls.name;
     String implName = '_${name}Impl';
     String mixinName = '_${name}Mixin';
-    out('class $implName extends Object with $mixinName implements $name {');
+    out('class $implName extends Object with $mixinName'
+        ' implements ${idlPrefix(name)} {');
     indent(() {
       out('final fb.BufferPointer _bp;');
       out();
@@ -541,12 +553,12 @@
             String itemCode = 'const fb.StringReader()';
             readCode = 'const fb.ListReader<String>($itemCode)';
           } else if (_idl.classes.containsKey(typeName)) {
-            String itemCode = '$typeName>(const _${typeName}Reader()';
-            readCode = 'const fb.ListReader<$itemCode)';
+            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<$typeName>($itemCode)';
+            readCode = 'const fb.ListReader<${idlPrefix(typeName)}>($itemCode)';
           }
         } else if (typeName == 'bool') {
           readCode = 'const fb.BoolReader()';
@@ -576,34 +588,10 @@
     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('}');
-  }
-
   void _generateMixin(idlModel.ClassDeclaration cls) {
     String name = cls.name;
     String mixinName = '_${name}Mixin';
-    out('abstract class $mixinName implements $name {');
+    out('abstract class $mixinName implements ${idlPrefix(name)} {');
     indent(() {
       // Write toMap().
       out('@override');
@@ -633,6 +621,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/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 49a1c1a..3953adc 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,8 +157,6 @@
   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
@@ -215,10 +212,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 +222,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 +258,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/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 30547e6..58e4359 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -10,6 +10,7 @@
 
 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';
@@ -82,6 +83,9 @@
   CommandLineOptions _previousOptions;
 
   @override
+  EmbeddedResolverProvider embeddedUriResolverProvider;
+
+  @override
   ResolverProvider packageResolverProvider;
 
   /// This Driver's current analysis context.
@@ -320,9 +324,23 @@
           PhysicalResourceProvider.INSTANCE.getResource('.');
       UriResolver resolver = packageResolverProvider(folder);
       if (resolver != null) {
-        // TODO(brianwilkerson) This doesn't support either embedder files or sdk extensions.
+        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>[
-          new DartUriResolver(sdk),
+          sdkResolver,
           resolver,
           new FileUriResolver()
         ];
diff --git a/pkg/analyzer_cli/lib/starter.dart b/pkg/analyzer_cli/lib/starter.dart
index a784a75..e42d39a 100644
--- a/pkg/analyzer_cli/lib/starter.dart
+++ b/pkg/analyzer_cli/lib/starter.dart
@@ -4,6 +4,7 @@
 
 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';
@@ -22,6 +23,14 @@
   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.
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index e84777f..73bbc60 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -597,11 +597,15 @@
     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 (name == dartLibraryEnvironmentPrefix + 'mirrors') {
+      if (libraryName == 'mirrors') {
         return backend.supportsReflection ? "true" : null;
       }
       return "true";
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/cps_ir/backward_null_check_remover.dart b/pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart
index b55a433..6a2c16f 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
@@ -53,7 +53,7 @@
   /// 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;
+    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;
@@ -71,7 +71,7 @@
   /// 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) {
+    if (prim is ReceiverCheck && prim.isNullCheck) {
       Primitive value = prim.value.definition;
       LetPrim let = prim.parent;
       prim..replaceUsesWith(value)..destroy();
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 37dc74b..3ae2c1b 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
@@ -430,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.
@@ -1894,11 +1895,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.
@@ -2428,7 +2438,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);
@@ -2445,7 +2455,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);
@@ -2856,7 +2866,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>[]);
@@ -2865,7 +2875,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]);
@@ -3018,7 +3028,7 @@
     return translateCompounds(node, () {
       return isGetterValid
           ? irBuilder.buildSuperIndex(indexFunction, indexValue)
-          : buildInstanceNoSuchMethod(
+          : buildSuperNoSuchMethod(
               new Selector.index(),
               elements.getGetterTypeMaskInComplexSendSet(node),
               <ir.Primitive>[indexValue]);
@@ -3026,7 +3036,7 @@
       if (isSetterValid) {
         irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result);
       } else {
-        buildInstanceNoSuchMethod(
+        buildSuperNoSuchMethod(
             new Selector.indexSet(),
             elements.getTypeMask(node),
             <ir.Primitive>[indexValue, result]);
@@ -3327,13 +3337,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)]);
   }
 
@@ -3442,7 +3457,7 @@
       Element function,
       ast.Node index, _) {
     // Assume the index getter is missing.
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.index(), elements.getTypeMask(node), [visit(index)]);
   }
 
@@ -3452,7 +3467,7 @@
       Element element,
       op.BinaryOperator operator,
       ast.Node argument, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         elements.getSelector(node),
         elements.getTypeMask(node),
         [visit(argument)]);
@@ -3463,7 +3478,7 @@
       ast.Send node,
       op.UnaryOperator operator,
       Element element, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         elements.getSelector(node), elements.getTypeMask(node), []);
   }
 
@@ -3550,7 +3565,7 @@
       ast.SendSet node,
       FieldElement field,
       ast.Node rhs, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(field.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3617,7 +3632,7 @@
       GetterElement getter,
       ast.Node rhs,
       _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(getter.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3629,7 +3644,7 @@
       MethodElement method,
       ast.Node rhs,
       _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(method.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3639,7 +3654,7 @@
   ir.Primitive visitSuperSetterGet(
       ast.Send node,
       SetterElement setter, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(setter.memberName),
         elements.getTypeMask(node),
         []);
@@ -3654,7 +3669,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);
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 e73dd84..7cb9260 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -260,7 +260,7 @@
   // TODO(johnniwinther): Require source information for all primitives.
   SourceInformation get sourceInformation => null;
 
-  /// If this is a [Refinement], [BoundsCheck] or [NullCheck] node, returns the
+  /// 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.
   ///
@@ -699,6 +699,9 @@
     receiver.parent = this;
     _setParentsOnList(arguments, this);
   }
+
+  bool get isConstructorBodyCall => target is ConstructorBodyElement;
+  bool get isTearOff => selector.isGetter && !target.isGetter;
 }
 
 /// Non-const call to a constructor.
@@ -802,7 +805,7 @@
 class BoundsCheck extends Primitive {
   final Reference<Primitive> object;
   Reference<Primitive> index;
-  Reference<Primitive> length; // FIXME write docs for length
+  Reference<Primitive> length;
   int checks;
   final SourceInformation sourceInformation;
 
@@ -876,53 +879,99 @@
   Primitive get effectiveDefinition => object.definition.effectiveDefinition;
 }
 
-/// Throw an exception if [value] is `null`.
+/// Throw a [NoSuchMethodError] if [value] cannot respond to [selector].
 ///
 /// Returns [value] so this can be used to restrict code motion.
 ///
-/// In the simplest form this compiles to `value.toString;`.
+/// The check can take one of three forms:
 ///
-/// [selector] holds the selector that is the cause of the null check. This is
-/// usually a method that was inlined where [value] the receiver.
+///     value.toString;
+///     value.selectorName;
+///     value.selectorName();    (should only be used if check always fails)
 ///
-/// 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.
+/// 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] 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;          (this form is valid but unused)
+///     if (condition) value.selectorName;
+///     if (condition) value.selectorName();
 ///
-///     if (condition) value.toString;  (or .selector if non-null)
+/// 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.
 ///
-/// The latter form is useful when [condition] is a form understood by the JS
-/// runtime, such as a `typeof` test.
-class NullCheck extends Primitive {
+/// If [useSelector] is false, the first form instead becomes `value.toString;`.
+/// This form is faster when the value is non-null and the accessed property has
+/// been removed by tree shaking.
+///
+/// [selector] may not be one of the selectors implemented by the null object.
+class ReceiverCheck extends Primitive {
   final Reference<Primitive> value;
   final Selector selector;
-  final bool useSelector;
-  final Reference<Primitive> condition;
   final SourceInformation sourceInformation;
+  final Reference<Primitive> condition;
+  final int _flags;
 
-  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);
+  static const int _USE_SELECTOR = 1 << 0;
+  static const int _NULL_CHECK = 1 << 1;
 
-  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;
+  /// True if the selector name should be used in the check; otherwise
+  /// `toString` will be used.
+  bool get useSelector => _flags & _USE_SELECTOR != 0;
+
+  /// True if null is the only possible input that cannot respond to [selector].
+  bool get isNullCheck => _flags & _NULL_CHECK != 0;
+
+
+  /// Constructor for creating checks in arbitrary configurations.
+  ///
+  /// Consider using one of the named constructors instead.
+  ///
+  /// [useSelector] and [isNullCheck] are mandatory named arguments.
+  ReceiverCheck(Primitive value, this.selector, this.sourceInformation,
+        {Primitive condition, bool useSelector, bool isNullCheck})
+      : value = new Reference<Primitive>(value),
+        condition = _optionalReference(condition),
+        _flags = (useSelector ? _USE_SELECTOR : 0) |
+                 (isNullCheck ? _NULL_CHECK : 0);
+
+  /// Simplified constructor for building null checks.
+  ///
+  /// Null must be the only possible input value that does not respond to
+  /// [selector].
+  ReceiverCheck.nullCheck(
+        Primitive value,
+        Selector selector,
+        SourceInformation sourceInformation,
+        {Primitive condition})
+      : this(value,
+            selector,
+            sourceInformation,
+            condition: condition,
+            useSelector: condition != null,
+            isNullCheck: true);
+
+  /// Simplified constructor for building the general check of form:
+  ///
+  ///     if (condition) value.selectorName();
+  ///
+  ReceiverCheck.generalCheck(
+        Primitive value,
+        Selector selector,
+        SourceInformation sourceInformation,
+        Primitive condition)
+      : this(value,
+            selector,
+            sourceInformation,
+            condition: condition,
+            useSelector: true,
+            isNullCheck: false);
 
   bool get isSafeForElimination => false;
   bool get isSafeForReordering => false;
   bool get hasValue => true;
 
-  accept(Visitor visitor) => visitor.visitNullCheck(this);
+  accept(Visitor visitor) => visitor.visitReceiverCheck(this);
 
   void setParentPointers() {
     value.parent = this;
@@ -932,6 +981,10 @@
   }
 
   Primitive get effectiveDefinition => value.definition.effectiveDefinition;
+
+  String get nullCheckString => isNullCheck ? 'null-check' : 'general-check';
+  String get useSelectorString => useSelector ? 'use-selector' : 'no-selector';
+  String get flagString => '$nullCheckString $useSelectorString';
 }
 
 /// An "is" type test.
@@ -1927,6 +1980,16 @@
   }
 }
 
+Reference<Primitive> _reference(Primitive definition) {
+  return new Reference<Primitive>(definition);
+}
+
+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();
 }
@@ -2008,23 +2071,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);
@@ -2074,7 +2139,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);
 }
 
@@ -2397,8 +2462,8 @@
     }
   }
 
-  processNullCheck(NullCheck node) {}
-  visitNullCheck(NullCheck node) {
+  processNullCheck(ReceiverCheck node) {}
+  visitReceiverCheck(ReceiverCheck node) {
     processNullCheck(node);
     processReference(node.value);
     if (node.condition != null) {
@@ -2758,11 +2823,13 @@
     }
   }
 
-  Definition visitNullCheck(NullCheck node) {
-    return new NullCheck(getCopy(node.value), node.sourceInformation,
+  Definition visitReceiverCheck(ReceiverCheck node) {
+    return new ReceiverCheck(getCopy(node.value),
+        node.selector,
+        node.sourceInformation,
         condition: node.condition == null ? null : getCopy(node.condition),
-        selector: node.selector,
-        useSelector: node.useSelector);
+        useSelector: node.useSelector,
+        isNullCheck: node.isNullCheck);
   }
 
   Definition visitForeignCode(ForeignCode 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 37836bf..952f881 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
@@ -448,10 +448,11 @@
     return '(BoundsCheck $object $index $length ${node.checkString})';
   }
 
-  String visitNullCheck(NullCheck node) {
+  String visitReceiverCheck(ReceiverCheck node) {
     String value = access(node.value);
     String condition = optionalAccess(node.condition);
-    return '(NullCheck $value $condition (${node.selector ?? ""}))';
+    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 db1592d..dd69e3e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -393,10 +393,11 @@
     return 'BoundsCheck $object $index $length ${node.checkString}';
   }
 
-  visitNullCheck(cps_ir.NullCheck node) {
+  visitReceiverCheck(cps_ir.ReceiverCheck node) {
     String value = formatReference(node.value);
     String condition = formatReference(node.condition);
-    return 'NullCheck $value condition:$condition selector:${node.selector}';
+    return 'ReceiverCheck $value $condition ${node.selector} '
+        '${node.flagString}';
   }
 }
 
@@ -681,7 +682,7 @@
     unexpectedNode(node);
   }
 
-  visitNullCheck(cps_ir.NullCheck node) {
+  visitReceiverCheck(cps_ir.ReceiverCheck node) {
     unexpectedNode(node);
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
index 7b1d294..26244a4 100644
--- a/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
+++ b/pkg/compiler/lib/src/cps_ir/duplicate_branch.dart
@@ -1,12 +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 dart2js.cps_ir.duplicate_branch;
+library dart2js.cps_ir.duplicate_branch; // FIXME: Rename file.
 
 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:
 ///
@@ -27,6 +38,23 @@
 ///     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
@@ -35,19 +63,26 @@
 // 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 DuplicateBranchEliminator extends TrampolineRecursiveVisitor
-                                implements Pass {
-  String get passName => 'Duplicate branch elimination';
+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 OTHER_TRUTHY = 1 << 1;
-  static const int FALSE = 1 << 2;
-  static const int OTHER_FALSY = 1 << 3;
+  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 | OTHER_TRUTHY;
+  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>{};
@@ -120,4 +155,30 @@
       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.receiver.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.arguments[0].changeTo(dummy);
+        node.callingConvention = CallingConvention.DummyIntercepted;
+      }
+    }
+  }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/gvn.dart b/pkg/compiler/lib/src/cps_ir/gvn.dart
index a4a591f..46f5d93 100644
--- a/pkg/compiler/lib/src/cps_ir/gvn.dart
+++ b/pkg/compiler/lib/src/cps_ir/gvn.dart
@@ -192,7 +192,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 ||
diff --git a/pkg/compiler/lib/src/cps_ir/inline.dart b/pkg/compiler/lib/src/cps_ir/inline.dart
index 554e93e..87892d3 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -246,15 +246,19 @@
   // 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;
+    }
+  }
 }
 
 class InliningVisitor extends TrampolineRecursiveVisitor {
@@ -405,6 +409,14 @@
       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.dartReceiverReference;
     TypeMask abstractReceiver =
         dartReceiver == null ? null : abstractType(dartReceiver);
@@ -512,7 +524,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,
@@ -520,15 +534,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;
   }
@@ -571,4 +586,16 @@
     }
     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;
+    }
+    return false;
+  }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 599476f..337ff32 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -25,7 +25,8 @@
 export 'inline.dart' show Inliner;
 export 'eagerly_load_statics.dart' show EagerlyLoadStatics;
 export 'loop_invariant_branch.dart' show LoopInvariantBranchMotion;
-export 'duplicate_branch.dart' show DuplicateBranchEliminator;
+export 'duplicate_branch.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/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index 808c1c7..f1191ff 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -212,7 +212,7 @@
 /// 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/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index 0a21c3f..ea8bb43 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
@@ -559,11 +575,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 f1944ce..fe35b1f 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -368,7 +368,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 +387,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 +396,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 +405,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 +416,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 +450,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 +511,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 +545,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);
@@ -626,6 +638,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 +702,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) {
@@ -784,11 +809,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.
@@ -1102,41 +1133,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);
@@ -1145,15 +1234,20 @@
 
     /// 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;
     }
 
+    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);
@@ -1184,13 +1278,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.
@@ -1198,8 +1296,7 @@
           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
@@ -1207,8 +1304,7 @@
           if (opname == '>>' &&
               lattice.isDefinitelyUint32(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
-            return makeBinary(BuiltinOperator.NumShr,
-                guard: BuiltinOperator.IsNotNumber);
+            return makeBinary(BuiltinOperator.NumShr, guard: checkIsNumber);
           }
           // Try to use remainder for '%'. Both operands must be non-negative
           // and the divisor must be non-zero.
@@ -1217,14 +1313,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) &&
@@ -1236,18 +1332,13 @@
       }
     }
     if (node.selector.isOperator && node.dartArgumentsLength == 0) {
-      Primitive argument = node.dartReceiver;
-      AbstractConstantValue value = getValue(argument);
-
-      if (lattice.isDefinitelyNum(value, allowNull: true)) {
+      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);
         }
       }
     }
@@ -1263,7 +1354,7 @@
               lattice.isDefinitelyInt(argValue) &&
               isIntNotZero(argValue)) {
             return makeBinary(BuiltinOperator.NumRemainder,
-                guard: BuiltinOperator.IsNotNumber);
+                guard: checkIsNumber);
           }
         }
       } else if (name == 'codeUnitAt') {
@@ -1377,6 +1468,7 @@
 
       case '[]':
         Primitive index = node.dartArgument(0);
+        // TODO(asgerf): Consider inserting a guard and specialize anyway.
         if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = new CpsFragment(node.sourceInformation);
         receiver = makeBoundsCheck(cps, receiver, index);
@@ -1917,20 +2009,10 @@
       // the error message when the receiver is null, but we accept this.
       node.receiver.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);
@@ -2268,9 +2350,12 @@
     }
   }
 
-  visitNullCheck(NullCheck node) {
-    if (!getValue(node.value.definition).isNullable) {
-      node.replaceUsesWith(node.value.definition);
+  visitReceiverCheck(ReceiverCheck node) {
+    Primitive input = node.value.definition;
+    if (!input.type.isNullable &&
+        (node.isNullCheck ||
+         !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
+      node.replaceUsesWith(input);
       return new CpsFragment();
     }
     return null;
@@ -2478,7 +2563,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,
@@ -2486,11 +2571,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;
@@ -2828,8 +2913,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) {
@@ -3109,16 +3199,9 @@
 
   @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
@@ -3127,8 +3210,19 @@
   }
 
   @override
-  void visitNullCheck(NullCheck node) {
-    setValue(node, lattice.nonNullable(getValue(node.value.definition)));
+  void visitReceiverCheck(ReceiverCheck node) {
+    AbstractConstantValue value = getValue(node.value.definition);
+    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)));
+    }
   }
 }
 
@@ -3227,18 +3321,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 48e3242..3500521 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,6 +20,7 @@
   String get passName => 'Update refinements';
 
   final TypeMaskSystem typeSystem;
+  World get classWorld => typeSystem.classWorld;
 
   Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{};
 
@@ -34,20 +36,21 @@
     return next;
   }
 
-  visitNullCheck(NullCheck node) {
+  visitReceiverCheck(ReceiverCheck node) {
     if (refine(node.value)) {
+      // Update the type if the input has changed.
       Primitive value = node.value.definition;
-      if (value.type.isNullable) {
-        // Update the type if the input has changed.
-        node.type = value.type.nonNullable();
+      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 NullCheck as a refinement.
+    // Use the ReceiverCheck as a refinement.
     Primitive value = node.effectiveDefinition;
     Primitive old = refinementFor[value];
     refinementFor[value] = node;
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..a8944c6
--- /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.value);
+  }
+
+  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.arguments.forEach(escape);
+      return;
+    }
+    if (unescaped.isEmpty) return;
+    if (prim is SetField) {
+      escape(prim.value);
+      Primitive object = prim.object.definition;
+      if (object is CreateInstance && unescaped.contains(object)) {
+        int index = getFieldIndex(object.classElement, prim.field);
+        if (index == -1) {
+          // This field is not initialized at creation time, so we cannot pull
+          // set SetField into the CreateInstance instruction.  We have to
+          // leave the instruction here, and this counts as a use of the object.
+          escape(prim.object);
+        } else {
+          // Replace the field initializer with the new value. There are no uses
+          // of the object before this, so the old value cannot have been seen.
+          object.arguments[index].changeTo(prim.value.definition);
+          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.definition;
+      if (object is CreateInstance && unescaped.contains(object)) {
+        int index = getFieldIndex(object.classElement, prim.field);
+        if (index == -1) {
+          escape(prim.object);
+        } else {
+          prim.replaceUsesWith(object.arguments[index].definition);
+          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/generated/shared_messages.dart b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
index c8617cc..2aa258a 100644
--- a/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
@@ -9,29 +9,26 @@
 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 MessageTemplate;
+import '../messages.dart' show MessageKind, MessageTemplate;
 
-enum SharedMessageKind {
-  exampleMessage
-}
-
-const Map<SharedMessageKind, MessageTemplate> TEMPLATES = const <SharedMessageKind, MessageTemplate>{ 
-  SharedMessageKind.exampleMessage: const MessageTemplate(
-    SharedMessageKind.exampleMessage,
-    "#use #named #arguments",
-    howToFix: "an explanation on how to fix things",
+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'''
-      Some multiline example;
-      That generates the bug.''',
-      const {
-      'fileA.dart': r'''
-        or a map from file to content.
-        again multiline''',
-      'fileB.dart': r'''
-        with possibly multiple files.
-        muliline too''',
-      },
+         class C {
+           const C() {}
+         }
+
+         main() => new C();''',
+      r'''
+         class C {
+           const factory C() {}
+         }
+
+         main() => new C();''',
     ]
   ),  // Generated. Don't edit.
 };
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index f394bdf..2679c75 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -74,8 +74,6 @@
 
 import 'generated/shared_messages.dart' as shared_messages;
 
-export 'generated/shared_messages.dart' show SharedMessageKind;
-
 const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
 
 /// Keys for the [MessageTemplate]s.
@@ -146,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,
@@ -290,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,
@@ -979,17 +978,6 @@
         const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY,
           "Redirecting constructor can't have a body."),
 
-      MessageKind.CONST_CONSTRUCTOR_HAS_BODY:
-        const MessageTemplate(MessageKind.CONST_CONSTRUCTOR_HAS_BODY,
-          "Const constructor or factory can't have a body.",
-          howToFix: "Remove the 'const' keyword or the body",
-          examples: const ["""
-class C {
-  const C() {}
-}
-
-main() => new C();"""]),
-
       MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
         const MessageTemplate(
           MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER,
@@ -2336,6 +2324,36 @@
                 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(
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index f9608ba..9628684 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -1312,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,
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/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 2ef185b..8966763 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -10,11 +10,13 @@
 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;
 
@@ -147,9 +149,11 @@
 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) {
@@ -241,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);
   }
@@ -409,15 +430,75 @@
   }
 }
 
+/// 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 {
+class PositionTraceListener extends TraceListener with
+    NodeToSourceInformationMixin {
   final SourceMapper sourceMapper;
 
   PositionTraceListener(this.sourceMapper);
 
   @override
   void onStep(js.Node node, Offset offset, StepKind kind) {
-    SourceInformation sourceInformation = node.sourceInformation;
+    SourceInformation sourceInformation = computeSourceInformation(node);
     if (sourceInformation == null) return;
 
     SourcePositionKind sourcePositionKind = SourcePositionKind.START;
@@ -752,6 +833,8 @@
       notifyStep(parent,
           getOffsetForNode(parent, offsetPosition),
           kind);
+      // The [offsetPosition] should only be used by the first subexpression.
+      offsetPosition = null;
     }
     steps = oldSteps;
   }
@@ -782,6 +865,7 @@
     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);
@@ -794,8 +878,12 @@
   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, getSyntaxOffset(node)), StepKind.NEW);
+        node, getOffsetForNode(node, offsetPosition), StepKind.NEW);
     steps.add(node);
     offsetPosition = null;
   }
@@ -885,7 +973,7 @@
   visitWhile(js.While node) {
     statementOffset = getSyntaxOffset(node);
     if (node.condition != null) {
-      visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+      visitSubexpression(node, node.condition, getSyntaxOffset(node),
           StepKind.WHILE_CONDITION);
     }
     statementOffset = null;
@@ -928,6 +1016,8 @@
   @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);
@@ -1099,7 +1189,7 @@
     StringBuffer sb = new StringBuffer();
     int total = _nodesWithInfoCount + _nodesWithoutInfoCount;
     if (total > 0) {
-      sb.write(_nodesWithoutInfoCount);
+      sb.write(_nodesWithInfoCount);
       sb.write('/');
       sb.write(total);
       sb.write(' (');
@@ -1121,7 +1211,14 @@
       sb.write('\nNodes without info (');
       sb.write(_nodesWithoutInfoCount);
       sb.write(') by runtime type:');
-      _nodesWithoutInfoCountByType.forEach((Type type, int count) {
+      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(' ');
@@ -1140,14 +1237,14 @@
 }
 
 /// [TraceListener] that registers [onStep] callbacks with [coverage].
-class CoverageListener extends TraceListener {
+class CoverageListener extends TraceListener with NodeToSourceInformationMixin {
   final Coverage coverage;
 
   CoverageListener(this.coverage);
 
   @override
   void onStep(js.Node node, Offset offset, StepKind kind) {
-    SourceInformation sourceInformation = node.sourceInformation;
+    SourceInformation sourceInformation = computeSourceInformation(node);
     if (sourceInformation != null) {
       coverage.registerNodeWithInfo(node);
     } else {
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 0138b41..da46d43 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -104,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/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 7407ef7..faa4de3 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -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);
     });
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 1815ee2..eb1e699 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -1031,7 +1031,7 @@
   }
 
   @override
-  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
@@ -1041,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)
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 6e0619b..edc7c55 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -274,13 +274,14 @@
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new EagerlyLoadStatics(), cpsFunction);
       applyCpsPass(new GVN(compiler, typeSystem), cpsFunction);
-      applyCpsPass(new DuplicateBranchEliminator(), 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);
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index eca1917..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
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/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/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 0c8e57c..d06a002 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;
@@ -4551,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
@@ -4691,6 +4696,15 @@
   }
 
   @override
+  void visitUnresolvedSuperSet(
+      ast.Send node,
+      Element element,
+      ast.Node rhs,
+      _) {
+    handleSuperSendSet(node);
+  }
+
+  @override
   void visitSuperSetterGet(
       ast.Send node,
       MethodElement setter,
@@ -6809,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
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/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/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_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index 1ada85b..3785f78 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.
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 1c92ff5..3685137 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -1261,7 +1261,7 @@
   }
 
   @override
-  Statement visitNullCheck(NullCheck node) {
+  Statement visitReceiverCheck(ReceiverCheck node) {
     inEmptyEnvironment(() {
       node.next = visitStatement(node.next);
     });
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 15dc292..a9c2831 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -699,12 +699,16 @@
     }
   }
 
-  visitNullCheck(cps_ir.NullCheck node) => (Statement next) {
-    return new NullCheck(
+  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.condition),
         value: getVariableUse(node.value),
         selector: node.selector,
         useSelector: node.useSelector,
+        useInvoke: !node.isNullCheck,
         next: next,
         sourceInformation: node.sourceInformation);
   };
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 2b4d301..ec2e34a 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -950,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);
   }
 }
 
@@ -1059,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> {
@@ -1077,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 {
@@ -1286,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);
@@ -1546,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 6d2ce7e..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)}');
   }
 }
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 6512c5a..3bf01da 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);
 
diff --git a/pkg/dart_messages/bin/publish.dart b/pkg/dart_messages/bin/publish.dart
index c7b9c11..4b497b8 100644
--- a/pkg/dart_messages/bin/publish.dart
+++ b/pkg/dart_messages/bin/publish.dart
@@ -3,7 +3,7 @@
 // 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';
 
@@ -35,11 +35,11 @@
 
 void emitJson() {
   var input = MESSAGES;
-  var outPath = Platform.script.resolve(jsonPath).toFilePath();
+  var outPath = io.Platform.script.resolve(jsonPath).toFilePath();
   print("Emitting JSON:");
   print("  Input: ${input.length} entries");
   print("  Output: $outPath");
-  new File(outPath).writeAsStringSync(messagesAsJson);
+  new io.File(outPath).writeAsStringSync(messagesAsJson);
   print("Emitting JSON done.");
 }
 
@@ -82,30 +82,24 @@
 ///     };
 void emitDart2js() {
   var input = MESSAGES;
-  var outPath = Platform.script.resolve(dart2jsPath).toFilePath();
+  var outPath = io.Platform.script.resolve(dart2jsPath).toFilePath();
   print("Emitting dart2js:");
   print("  Input: ${input.length} entries");
   print("  Output: $outPath");
 
-  var enumIds = input.keys.toList();
-
   StringBuffer out = new StringBuffer();
   out.writeln(copyrightHeader);
   out.writeln(dontEditWarning);
-  out.writeln("import '../messages.dart' show MessageTemplate;");
+  out.writeln("import '../messages.dart' show MessageKind, MessageTemplate;");
   out.writeln();
-  out.write(("enum SharedMessageKind {\n  "));
-  // We generate on one line on purpose, so that users are less likely to
-  // modify the generated file.
-  out.writeln(enumIds.join(",\n  "));
-  out.writeln("}");
-  out.writeln();
-  out.writeln("const Map<SharedMessageKind, MessageTemplate> TEMPLATES = "
-      "const <SharedMessageKind, MessageTemplate>{ ");
+  out.writeln("const Map<MessageKind, MessageTemplate> TEMPLATES = "
+      "const <MessageKind, MessageTemplate>{ ");
   input.forEach((name, message) {
-    out.writeln("  SharedMessageKind.$name: const MessageTemplate(");
+    if (!message.usedBy.contains(Platform.dart2js)) return;
+
+    out.writeln("  MessageKind.$name: const MessageTemplate(");
     // TODO(floitsch): include id.
-    out.writeln("    SharedMessageKind.$name,");
+    out.writeln("    MessageKind.$name,");
     out.write("    ");
     out.write(escapeString(message.template));
     if (message.howToFix != null) {
@@ -140,7 +134,7 @@
   });
   out.writeln("};");
 
-  new File(outPath).writeAsStringSync(out.toString());
+  new io.File(outPath).writeAsStringSync(out.toString());
   print("Emitting dart2js done.");
 }
 
@@ -182,7 +176,7 @@
 ///         "Just don't do it");
 void emitAnalyzer() {
   var input = MESSAGES;
-  var outPath = Platform.script.resolve(analyzerPath).toFilePath();
+  var outPath = io.Platform.script.resolve(analyzerPath).toFilePath();
   print("Emitting analyzer:");
   print("  Input: ${input.length} entries");
   print("  Output: $outPath");
@@ -191,10 +185,14 @@
   out.writeln(copyrightHeader);
   out.writeln(dontEditWarning);
   out.writeln("import 'package:analyzer/src/generated/error.dart';");
-  out.writeln();
+  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',");
 
@@ -208,7 +206,7 @@
     out.writeln(");  // Generated. Don't edit.");
   });
 
-  new File(outPath).writeAsStringSync(out.toString());
+  new io.File(outPath).writeAsStringSync(out.toString());
   print("Emitting analyzer done.");
 }
 
diff --git a/pkg/dart_messages/lib/generated/shared_messages.json b/pkg/dart_messages/lib/generated/shared_messages.json
index 606bc60..8b20467 100644
--- a/pkg/dart_messages/lib/generated/shared_messages.json
+++ b/pkg/dart_messages/lib/generated/shared_messages.json
@@ -1 +1 @@
-{"exampleMessage":{"id":"use an Id generated by bin/message_id.dart","category":"AnalysisOptionsError","template":"#use #named #arguments","howToFix":"an explanation on how to fix things"}}
\ No newline at end of file
+{"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();"]}}
\ 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 896f52a..32d7935 100644
--- a/pkg/dart_messages/lib/shared_messages.dart
+++ b/pkg/dart_messages/lib/shared_messages.dart
@@ -70,17 +70,25 @@
 
   static final analysisOptionsWarning = new Category("AnalysisOptionsWarning");
 
-  static final checkedModeCompileTimeError = new Category(
-      "CheckedModeCompileTimeError");
+  static final checkedModeCompileTimeError =
+      new Category("CheckedModeCompileTimeError");
+
+  static final parserError = new Category("ParserError");
 
   final String name;
 
   Category(this.name);
 }
 
+enum Platform {
+  dart2js, analyzer,
+}
+const dart2js = Platform.dart2js;
+const analyzer = Platform.analyzer;
 
 class Message {
   final String id;
+  final int subId;
   final Category category;
   final String template;
   // The analyzer fills holes positionally (and not named). The following field
@@ -90,23 +98,37 @@
   // 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 templateHoleOrder;
+  final List<String> templateHoleOrder;
   final String howToFix;
   final List<String> options;
   final List examples;
+  final List<Platform> usedBy;
 
-  Message({this.id, this.category, this.template, this.templateHoleOrder,
-      this.howToFix, this.options, this.examples});
+  Message(
+      {this.id,
+      this.subId: 0,
+      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] =  {
+    jsonified[name] = {
       'id': message.id,
+      'subId': message.subId,
       'category': message.category.name,
       'template': message.template,
-      'howToFix': message.howToFix
+      'templateHoleOrder': message.templateHoleOrder,
+      'howToFix': message.howToFix,
+      'options': message.options,
+      'usedBy': message.usedBy.map((platform) => platform.toString()).toList(),
+      'examples': message.examples,
     };
   });
   return JSON.encode(jsonified);
@@ -119,17 +141,74 @@
       template: "#use #named #arguments",
       templateHoleOrder: ["arguments", "named", "use"],
       howToFix: "an explanation on how to fix things",
-      examples: [r'''
+      examples: [
+        r'''
       Some multiline example;
       That generates the bug.''',
-      {
-      'fileA.dart': '''
+        {
+          'fileA.dart': '''
         or a map from file to content.
         again multiline''',
-      'fileB.dart': '''
+          '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,
+      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,
+      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();"""
+      ]),
 };
diff --git a/pkg/dart_messages/test/dart_messages_test.dart b/pkg/dart_messages/test/dart_messages_test.dart
index b0ef4a5..b05bc3f 100644
--- a/pkg/dart_messages/test/dart_messages_test.dart
+++ b/pkg/dart_messages/test/dart_messages_test.dart
@@ -2,19 +2,19 @@
 // for 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 '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/generated/shared_messages.json');
   var jsonPath = jsonUri.toFilePath();
-  var content = new File(jsonPath).readAsStringSync();
+  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.");
@@ -26,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 07a20f1..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;
@@ -902,7 +904,7 @@
   }
   NamedFunction _clone() => new NamedFunction(name, function);
 
-  int get precedenceLevel => CALL;
+  int get precedenceLevel => LEFT_HAND_SIDE;
 }
 
 class Fun extends Expression {
@@ -921,7 +923,7 @@
 
   Fun _clone() => new Fun(params, body, asyncModifier: asyncModifier);
 
-  int get precedenceLevel => CALL;
+  int get precedenceLevel => LEFT_HAND_SIDE;
 }
 
 class AsyncModifier {
@@ -967,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
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/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index fa81489..f271fbd 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -366,6 +366,7 @@
       'defines': [
         'DART_SHARED_LIB',
         'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
       ],
     },
     {
@@ -628,6 +629,64 @@
       },
     },
     {
+      # dart binary with a snapshot of corelibs built in and support for testing
+      # precompilation (aka --noopt)
+      'target_name': 'dart_noopt',
+      'type': 'executable',
+      'dependencies': [
+        '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',
@@ -760,6 +819,10 @@
         '<(observatory_assets_cc_file)',
         'snapshot_empty.cc',
       ],
+      'defines': [
+        'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
+      ],
       'conditions': [
         ['OS=="win"', {
           'link_settings': {
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/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 e15e49c..d783c85 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));
@@ -959,12 +945,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) {
@@ -1022,9 +1011,6 @@
   EventHandler::Start();
 
   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");
 
   if (IsSnapshottingForPrecompilation()) {
     vm_options.AddArgument("--precompilation");
@@ -1058,8 +1044,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 +1068,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 +1090,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 86d2d5d..123f56f 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -109,8 +109,8 @@
   V(SecurityContext_Allocate, 1)                                               \
   V(SecurityContext_UsePrivateKeyBytes, 3)                                     \
   V(SecurityContext_SetAlpnProtocols, 3)                                       \
-  V(SecurityContext_SetClientAuthorities, 2)                                   \
-  V(SecurityContext_SetTrustedCertificates, 3)                                 \
+  V(SecurityContext_SetClientAuthoritiesBytes, 2)                              \
+  V(SecurityContext_SetTrustedCertificatesBytes, 2)                            \
   V(SecurityContext_TrustBuiltinRoots, 1)                                      \
   V(SecurityContext_UseCertificateChainBytes, 2)                               \
   V(ServerSocket_Accept, 2)                                                    \
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index e8b8d73..d3f411f 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -24,11 +24,12 @@
   IsolateData(const char* url,
               const char* package_root,
               const char* packages_file)
-      : script_url(strdup(url)),
+      : 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);
@@ -46,6 +47,21 @@
     packages_file = NULL;
     free(udp_receive_buffer);
     udp_receive_buffer = NULL;
+    if (builtin_lib_ != NULL) {
+      Dart_DeletePersistentHandle(builtin_lib_);
+    }
+  }
+
+  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;
@@ -55,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 ee655d2..6be11f0 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,7 +90,12 @@
 // 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;
@@ -88,11 +103,12 @@
 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 +171,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 +318,7 @@
   if (*arg != '\0') {
     return false;
   }
-  has_compile_all = true;
+  compile_all = true;
   return true;
 }
 
@@ -322,7 +338,7 @@
   } else {
     precompiled_snapshot_directory = arg;
   }
-  has_gen_precompiled_snapshot = true;
+  gen_precompiled_snapshot = true;
   vm_options->AddArgument("--precompilation");
   return true;
 }
@@ -337,58 +353,67 @@
       (precompiled_snapshot_directory[0] == ':')) {
     precompiled_snapshot_directory = &precompiled_snapshot_directory[1];
   }
-  has_run_precompiled_snapshot = true;
+  run_precompiled_snapshot = true;
   vm_options->AddArgument("--precompilation");
   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) {
+  // Ensure that we are not running 'dart_no_snapshot'.
+  if (isolate_snapshot_buffer == NULL) {
+    Log::PrintErr("Full Application snapshots cannot be run with"
+                  " dart_no_snapshot\n");
+    return false;
+  }
+  return ProcessSnapshotOptionHelper(filename, &run_full_snapshot);
 }
 
 
@@ -436,7 +461,7 @@
   if (*arg != '\0') {
     return false;
   }
-  has_trace_loading = true;
+  trace_loading = true;
   return true;
 }
 
@@ -487,12 +512,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 }
 };
@@ -609,23 +634,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;
 }
@@ -711,6 +742,12 @@
                                                 char** error,
                                                 int* exit_code) {
   ASSERT(script_uri != NULL);
+  if (run_full_snapshot &&
+      !strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME)) {
+    // 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);
@@ -744,11 +781,11 @@
     // 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);
     }
@@ -757,30 +794,29 @@
     return isolate;
   }
 
-  // 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.
@@ -793,6 +829,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.
@@ -849,7 +888,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"
@@ -1018,17 +1057,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;
@@ -1036,6 +1075,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",
@@ -1048,16 +1093,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;
@@ -1106,22 +1150,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);
 }
 
 
@@ -1188,12 +1264,11 @@
     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());
+    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()) {
@@ -1205,12 +1280,12 @@
       }
     }
 
-    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" },
@@ -1240,16 +1315,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;
@@ -1263,15 +1337,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,
@@ -1282,7 +1362,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);
 
@@ -1304,9 +1384,9 @@
       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) {
+        GenerateFullSnapshot();
       }
     }
   }
@@ -1430,10 +1510,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) {
@@ -1456,10 +1536,16 @@
     Platform::Exit(kErrorExitCode);
   }
 
-  if (generate_script_snapshot) {
+  if (generate_script_snapshot || generate_full_snapshot_after_run) {
     vm_options.AddArgument("--load_deferred_eagerly");
   }
 
+#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());
 
   // Start event handler.
@@ -1467,13 +1553,28 @@
   EventHandler::Start();
 
   const uint8_t* instructions_snapshot = NULL;
-  if (has_run_precompiled_snapshot) {
+  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);
+    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.
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/secure_socket.cc b/runtime/bin/secure_socket.cc
index 7f62fcf..fa1f7f1 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -376,17 +376,79 @@
 }
 
 
+// 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 MemBIOScope.
+// Do not call Dart_PropagateError while in a MemBIOScope.
+class MemBIOScope {
+ public:
+  explicit MemBIOScope(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;
+  }
+
+  ~MemBIOScope() {
+    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(MemBIOScope);
+};
+
+
 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
     Dart_NativeArguments args) {
   SSL_CTX* context = GetSecurityContext(args);
 
-  Dart_Handle key_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  if (!Dart_IsTypedData(key_object) && !Dart_IsList(key_object)) {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "keyBytes argument to SecurityContext.usePrivateKeyBytes "
-        "is not a List<int>"));
-  }
-
   Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
   const char* password = NULL;
   if (Dart_IsString(password_object)) {
@@ -403,39 +465,12 @@
         "SecurityContext.usePrivateKey password is not a String or null"));
   }
 
-  uint8_t* key_bytes = NULL;
-  intptr_t key_bytes_len = 0;
-  bool is_typed_data = false;
-  if (Dart_IsTypedData(key_object)) {
-    is_typed_data = true;
-    Dart_TypedData_Type typ;
-    ThrowIfError(Dart_TypedDataAcquireData(
-        key_object,
-        &typ,
-        reinterpret_cast<void**>(&key_bytes),
-        &key_bytes_len));
-  } else {
-    ASSERT(Dart_IsList(key_object));
-    ThrowIfError(Dart_ListLength(key_object, &key_bytes_len));
-    key_bytes = new uint8_t[key_bytes_len];
-    Dart_Handle err =
-        Dart_ListGetAsBytes(key_object, 0, key_bytes, key_bytes_len);
-    if (Dart_IsError(err)) {
-      delete[] key_bytes;
-      Dart_PropagateError(err);
-    }
-  }
-  ASSERT(key_bytes != NULL);
-
-  BIO* bio = BIO_new_mem_buf(key_bytes, key_bytes_len);
-  EVP_PKEY *key = PEM_read_bio_PrivateKey(
-      bio, NULL, PasswordCallback, const_cast<char*>(password));
-  int status = SSL_CTX_use_PrivateKey(context, key);
-  BIO_free(bio);
-  if (is_typed_data) {
-    ThrowIfError(Dart_TypedDataReleaseData(key_object));
-  } else {
-    delete[] key_bytes;
+  int status;
+  {
+    MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    EVP_PKEY *key = PEM_read_bio_PrivateKey(
+        bio.bio(), NULL, PasswordCallback, const_cast<char*>(password));
+    status = SSL_CTX_use_PrivateKey(context, key);
   }
 
   // TODO(24184): Handle different expected errors here - file missing,
@@ -445,29 +480,44 @@
 }
 
 
-void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)(
-    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"));
+static int SetTrustedCertificatesBytes(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;
+    }
   }
 
-  int status = SSL_CTX_load_verify_locations(context, filename, directory);
-  CheckStatus(
-      status, "TlsException", "SSL_CTX_load_verify_locations");
+  uint32_t err = ERR_peek_last_error();
+  if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+      (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+    // Reached the end of the buffer.
+    ERR_clear_error();
+  } else {
+    // Some real error happened.
+    status = 0;
+  }
+
+  return status;
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
+    Dart_NativeArguments args) {
+  SSL_CTX* context = GetSecurityContext(args);
+  int status;
+  {
+    MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    status = SetTrustedCertificatesBytes(context, bio.bio());
+  }
+  CheckStatus(status,
+              "TlsException",
+              "Failure in setTrustedCertificatesBytes");
 }
 
 
@@ -489,17 +539,10 @@
 }
 
 
-static int UseChainBytes(
-    SSL_CTX* context, uint8_t* chain_bytes, intptr_t chain_bytes_len) {
+static int UseChainBytes(SSL_CTX* context, BIO* bio) {
   int status = 0;
-  BIO* bio = BIO_new_mem_buf(chain_bytes, chain_bytes_len);
-  if (bio == NULL) {
-    return 0;
-  }
-
   X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
   if (x509 == NULL) {
-    BIO_free(bio);
     return 0;
   }
 
@@ -510,7 +553,6 @@
   }
   if (status == 0) {
     X509_free(x509);
-    BIO_free(bio);
     return status;
   }
 
@@ -525,7 +567,6 @@
     if (status == 0) {
       X509_free(ca);
       X509_free(x509);
-      BIO_free(bio);
       return status;
     }
     // Note that we must not free `ca` if it was successfully added to the
@@ -544,7 +585,6 @@
   }
 
   X509_free(x509);
-  BIO_free(bio);
   return status;
 }
 
@@ -552,44 +592,10 @@
 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
     Dart_NativeArguments args) {
   SSL_CTX* context = GetSecurityContext(args);
-
-  Dart_Handle chain_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  if (!Dart_IsTypedData(chain_object) && !Dart_IsList(chain_object)) {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "chainBytes argument to SecurityContext.useCertificateChainBytes "
-        "is not a List<int>"));
-  }
-
-  uint8_t* chain_bytes = NULL;
-  intptr_t chain_bytes_len = 0;
-  bool is_typed_data = false;
-  if (Dart_IsTypedData(chain_object)) {
-    is_typed_data = true;
-    Dart_TypedData_Type typ;
-    ThrowIfError(Dart_TypedDataAcquireData(
-        chain_object,
-        &typ,
-        reinterpret_cast<void**>(&chain_bytes),
-        &chain_bytes_len));
-  } else {
-    ASSERT(Dart_IsList(chain_object));
-    ThrowIfError(Dart_ListLength(chain_object, &chain_bytes_len));
-    chain_bytes = new uint8_t[chain_bytes_len];
-    Dart_Handle err =
-        Dart_ListGetAsBytes(chain_object, 0, chain_bytes, chain_bytes_len);
-    if (Dart_IsError(err)) {
-      delete[] chain_bytes;
-      Dart_PropagateError(err);
-    }
-  }
-  ASSERT(chain_bytes != NULL);
-
-  int status = UseChainBytes(context, chain_bytes, chain_bytes_len);
-
-  if (is_typed_data) {
-    ThrowIfError(Dart_TypedDataReleaseData(chain_object));
-  } else {
-    delete[] chain_bytes;
+  int status;
+  {
+    MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    status = UseChainBytes(context, bio.bio());
   }
   CheckStatus(status,
               "TlsException",
@@ -597,20 +603,50 @@
 }
 
 
-void FUNCTION_NAME(SecurityContext_SetClientAuthorities)(
+static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
+  STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null();
+  if (result == NULL) {
+    return NULL;
+  }
+
+  while (true) {
+    X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+    if (x509 == NULL) {
+      break;
+    }
+
+    X509_NAME* x509_name = X509_get_subject_name(x509);
+    if (x509_name == NULL) {
+      sk_X509_NAME_pop_free(result, X509_NAME_free);
+      X509_free(x509);
+      return NULL;
+    }
+
+    // Duplicate the name to put it on the stack.
+    x509_name = X509_NAME_dup(x509_name);
+    if (x509_name == NULL) {
+      sk_X509_NAME_pop_free(result, X509_NAME_free);
+      X509_free(x509);
+      return NULL;
+    }
+    sk_X509_NAME_push(result, x509_name);
+    X509_free(x509);
+  }
+
+  return result;
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
     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"));
-  }
   STACK_OF(X509_NAME)* certificate_names;
-  certificate_names = SSL_load_client_CA_file(filename);
+
+  {
+    MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    certificate_names = GetCertificateNames(bio.bio());
+  }
+
   if (certificate_names != NULL) {
     SSL_CTX_set_client_CA_list(context, certificate_names);
   } else {
diff --git a/runtime/bin/secure_socket_patch.dart b/runtime/bin/secure_socket_patch.dart
index 8ba0117..b15d61a 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -137,24 +137,49 @@
   static final SecurityContext defaultContext =
       new _SecurityContext().._trustBuiltinRoots();
 
-  Future usePrivateKey(String keyFile, {String password}) {
-    return (new File(keyFile)).readAsBytes().then((bytes) {
-      usePrivateKeyBytes(bytes, password: password);
-    });
+  void usePrivateKey(String keyFile, {String password}) {
+    usePrivateKeySync(keyFile, password: password);
+  }
+  void usePrivateKeySync(String keyFile, {String password}) {
+    List<int> bytes = (new File(keyFile)).readAsBytesSync();
+    usePrivateKeyBytes(bytes, password: password);
   }
   void usePrivateKeyBytes(List<int> keyBytes, {String password})
       native "SecurityContext_UsePrivateKeyBytes";
-  void setTrustedCertificates({String file, String directory})
-      native "SecurityContext_SetTrustedCertificates";
-  Future useCertificateChain(String chainFile) {
-    return (new File(chainFile)).readAsBytes().then((bytes) {
-      useCertificateChainBytes(bytes);
-    });
+
+  void setTrustedCertificates(String file) {
+    setTrustedCertificatesSync(file);
+  }
+  void setTrustedCertificatesSync(String file) {
+    List<int> bytes = (new File(file)).readAsBytesSync();
+    setTrustedCertificatesBytes(bytes);
+  }
+  void setTrustedCertificatesBytes(List<int> certBytes)
+      native "SecurityContext_SetTrustedCertificatesBytes";
+
+  void useCertificateChain({String file, String directory}) {
+    if (directory != null) {
+      throw new UnsupportedError(
+          "The directory argument to useCertificateChain is not supported.");
+    }
+    useCertificateChainSync(file);
+  }
+  void useCertificateChainSync(String chainFile) {
+    List<int> bytes = (new File(chainFile)).readAsBytesSync();
+    useCertificateChainBytes(bytes);
   }
   void useCertificateChainBytes(List<int> chainBytes)
       native "SecurityContext_UseCertificateChainBytes";
-  void setClientAuthorities(String file)
-      native "SecurityContext_SetClientAuthorities";
+
+  void setClientAuthorities(String file) {
+    setClientAuthoritiesSync(file);
+  }
+  void setClientAuthoritiesSync(String file) {
+    List<int> bytes = (new File(file)).readAsBytesSync();
+    setClientAuthoritiesBytes(bytes);
+  }
+  void setClientAuthoritiesBytes(List<int> authCertBytes)
+      native "SecurityContext_SetClientAuthoritiesBytes";
   void setAlpnProtocols(List<String> protocols, bool isServer) {
     Uint8List encodedProtocols =
         SecurityContext._protocolsToLengthEncoding(protocols);
diff --git a/runtime/bin/secure_socket_unsupported.cc b/runtime/bin/secure_socket_unsupported.cc
index a4df288..91f4fc7 100644
--- a/runtime/bin/secure_socket_unsupported.cc
+++ b/runtime/bin/secure_socket_unsupported.cc
@@ -116,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"));
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 596aa66..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);
 }
 
@@ -566,9 +563,7 @@
   } else if (new_socket == ServerSocket::kTemporaryFailure) {
     Dart_SetReturnValue(args, Dart_False());
   } 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/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/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index cd2c87f..6ff907c 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,16 +62,11 @@
   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);
+  result = DartUtils::PrepareForScriptLoading(true, false);
   CHECK_RESULT(result);
 
   ASSERT(Dart_IsServiceIsolate(isolate));
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 836295c..08fd57a 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -182,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/dart-runtime.gyp b/runtime/dart-runtime.gyp
index f542dde..915b5b4 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -17,6 +17,7 @@
 
     'libdart_deps': ['libdart_lib_nosnapshot', 'libdart_lib',
                      'libdart_vm_nosnapshot', 'libdart_vm',
+                     'libdart_vm_noopt',
                      'libdart_vm_precompiled_runtime',
                      'libdouble_conversion',],
   },
@@ -56,6 +57,41 @@
       },
     },
     {
+      'target_name': 'libdart_noopt',
+      'type': 'static_library',
+      'dependencies': [
+        'libdart_lib',
+        'libdart_vm_noopt',
+        '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_PRECOMPILER',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'include',
+        ],
+      },
+    },
+    {
       'target_name': 'libdart_precompiled_runtime',
       'type': 'static_library',
       'dependencies': [
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4249382..abc92eb 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
@@ -1038,6 +1078,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 +1175,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 +2280,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 +2521,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/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/mirrors.cc b/runtime/lib/mirrors.cc
index 24254db..b7d95b1 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -783,7 +783,7 @@
       TypeArguments::Handle(instantiator.arguments());
   Error& bound_error = Error::Handle();
   AbstractType& result = AbstractType::Handle(
-      type.InstantiateFrom(type_args, &bound_error, NULL, Heap::kOld));
+      type.InstantiateFrom(type_args, &bound_error, NULL, NULL, Heap::kOld));
   if (!bound_error.IsNull()) {
     Exceptions::PropagateError(bound_error);
     UNREACHABLE();
@@ -1675,7 +1675,7 @@
       // type arguments of the type reflected by the class mirror.
       Error& bound_error = Error::Handle();
       redirect_type ^= redirect_type.InstantiateFrom(
-          type_arguments, &bound_error, NULL, Heap::kOld);
+          type_arguments, &bound_error, NULL, NULL, Heap::kOld);
       if (!bound_error.IsNull()) {
         Exceptions::PropagateError(bound_error);
         UNREACHABLE();
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index 3d307da..51319d7 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -23,6 +23,9 @@
 
 
 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);
@@ -37,6 +40,9 @@
 
 
 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 +106,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 +152,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/vmservice.cc b/runtime/lib/vmservice.cc
index fd5d14b..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();
 }
 
@@ -135,6 +145,9 @@
 
 
 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);
@@ -147,23 +160,32 @@
 
 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
@@ -351,7 +373,14 @@
 }
 
 
+#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);
@@ -403,6 +432,9 @@
   }
 
   return result_list.raw();
+#else
+  return Object::null();
+#endif
 }
 
 }  // namespace dart
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/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/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index f72c425..779c690 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(1));
+    expect(result['minor'], equals(2));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/observatory/tests/service/logging_test.dart b/runtime/observatory/tests/service/logging_test.dart
index cefa67b..b8839f1 100644
--- a/runtime/observatory/tests/service/logging_test.dart
+++ b/runtime/observatory/tests/service/logging_test.dart
@@ -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/service.status b/runtime/observatory/tests/service/service.status
index 7f5372f..e990d12 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -26,3 +26,7 @@
 
 [ $runtime == vm ]
 coverage_test: Pass, Slow
+
+# Service protocol is not supported in product mode.
+[ $mode == product ]
+*: SkipByDesign
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 794cecd..1adcd66 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -33,6 +33,9 @@
     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) {
@@ -280,40 +283,9 @@
 }
 
 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;
+  return hasPausedFor(isolate, ServiceEvent.kPauseStart);
 }
 
-
 // Currying is your friend.
 IsolateTest setBreakpointAtLine(int line) {
   return (Isolate isolate) async {
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/gyp/runtime-configurations.gypi b/runtime/tools/gyp/runtime-configurations.gypi
index 0b053c4..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': {
@@ -113,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/assembler.cc b/runtime/vm/assembler.cc
index f5358c1..495419d 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.");
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index e075dd3..382d833 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_); }
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 9997a98..bd45331 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -12,6 +12,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 AstPrinter::AstPrinter() : indent_(0) { }
 
 
@@ -574,4 +576,6 @@
   THR_Print("}\n");
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/ast_printer_test.cc b/runtime/vm/ast_printer_test.cc
index 082d8dc..588d702 100644
--- a/runtime/vm/ast_printer_test.cc
+++ b/runtime/vm/ast_printer_test.cc
@@ -12,6 +12,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 TEST_CASE(AstPrinter) {
   const TokenPosition kPos = TokenPosition::kNoSource;
   LocalVariable* v =
@@ -36,4 +38,6 @@
   AstPrinter::PrintNode(new UnaryOpNode(kPos, Token::kNEGATE, ll));
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h
index 59a45ac..bd489d0 100644
--- a/runtime/vm/atomic.h
+++ b/runtime/vm/atomic.h
@@ -20,7 +20,12 @@
   // NOTE: Not to be used for any atomic operations involving memory locations
   // that are accessed by generated code.
   static uintptr_t FetchAndIncrement(uintptr_t* p);
-  static uintptr_t FetchAndIncrementBy(intptr_t* p, intptr_t value);
+
+  // 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.
@@ -28,7 +33,12 @@
   // NOTE: Not to be used for any atomic operations involving memory locations
   // that are accessed by generated code.
   static uintptr_t FetchAndDecrement(uintptr_t* p);
-  static uintptr_t FetchAndDecrementBy(intptr_t* p, intptr_t value);
+
+  // 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 48f7f37..c3727af 100644
--- a/runtime/vm/atomic_android.h
+++ b/runtime/vm/atomic_android.h
@@ -21,9 +21,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndIncrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_add(p, value);
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
 }
 
 
@@ -32,9 +31,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndDecrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_sub(p, value);
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
 }
 
 
diff --git a/runtime/vm/atomic_linux.h b/runtime/vm/atomic_linux.h
index 0103b53..15f0396 100644
--- a/runtime/vm/atomic_linux.h
+++ b/runtime/vm/atomic_linux.h
@@ -21,9 +21,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndIncrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_add(p, value);
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
 }
 
 
@@ -32,9 +31,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndDecrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_sub(p, value);
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
 }
 
 
diff --git a/runtime/vm/atomic_macos.h b/runtime/vm/atomic_macos.h
index 1cf951e..fd5af87 100644
--- a/runtime/vm/atomic_macos.h
+++ b/runtime/vm/atomic_macos.h
@@ -21,9 +21,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndIncrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_add(p, value);
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
 }
 
 
@@ -32,9 +31,8 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndDecrementBy(intptr_t* p,
-                                                       intptr_t value) {
-  return __sync_fetch_and_sub(p, value);
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
 }
 
 
diff --git a/runtime/vm/atomic_test.cc b/runtime/vm/atomic_test.cc
index db9be22..6973d8b 100644
--- a/runtime/vm/atomic_test.cc
+++ b/runtime/vm/atomic_test.cc
@@ -26,18 +26,16 @@
 }
 
 
-UNIT_TEST_CASE(FetchAndIncrementBy) {
+UNIT_TEST_CASE(IncrementBy) {
   intptr_t v = 42;
-  EXPECT_EQ(static_cast<uintptr_t>(42),
-            AtomicOperations::FetchAndIncrementBy(&v, 100));
+  AtomicOperations::IncrementBy(&v, 100);
   EXPECT_EQ(static_cast<intptr_t>(142), v);
 }
 
 
-UNIT_TEST_CASE(FetchAndDecrementBy) {
+UNIT_TEST_CASE(DecrementBy) {
   intptr_t v = 42;
-  EXPECT_EQ(static_cast<uintptr_t>(42),
-            AtomicOperations::FetchAndDecrementBy(&v, 41));
+  AtomicOperations::DecrementBy(&v, 41);
   EXPECT_EQ(static_cast<intptr_t>(1), v);
 }
 
diff --git a/runtime/vm/atomic_win.h b/runtime/vm/atomic_win.h
index 2ade768..1563035 100644
--- a/runtime/vm/atomic_win.h
+++ b/runtime/vm/atomic_win.h
@@ -28,16 +28,13 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndIncrementBy(intptr_t* p,
-                                                       intptr_t value) {
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
 #if defined(HOST_ARCH_X64)
-  return static_cast<uintptr_t>(
-      InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
-                               static_cast<LONGLONG>(value)));
+  InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
+                           static_cast<LONGLONG>(value));
 #elif defined(HOST_ARCH_IA32)
-  return static_cast<uintptr_t>(
-      InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
-                             static_cast<LONG>(value)));
+  InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
+                         static_cast<LONG>(value));
 #else
 #error Unsupported host architecture.
 #endif
@@ -57,16 +54,13 @@
 }
 
 
-inline uintptr_t AtomicOperations::FetchAndDecrementBy(intptr_t* p,
-                                                       intptr_t value) {
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
 #if defined(HOST_ARCH_X64)
-  return static_cast<uintptr_t>(
-      InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
-                               static_cast<LONGLONG>(-value)));
+  InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
+                           static_cast<LONGLONG>(-value));
 #elif defined(HOST_ARCH_IA32)
-  return static_cast<uintptr_t>(
-      InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
-                             static_cast<LONG>(-value)));
+  InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
+                         static_cast<LONG>(-value));
 #else
 #error Unsupported host architecture.
 #endif
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 90cf8e6..f626ee9 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"
@@ -33,6 +34,16 @@
 }
 
 
+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.
 //
@@ -278,68 +289,6 @@
 }
 
 
-// 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) {
@@ -349,12 +298,13 @@
 }
 
 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);
+
+  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()));
@@ -362,7 +312,7 @@
   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);
+  result = bin::DartUtils::SetupPackageRoot(buffer, NULL);
   DART_CHECK_VALID(result);
 }
 
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/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index a84a5d9..1288d0b 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -6,6 +6,7 @@
 
 #include "vm/allocation.h"
 #include "vm/code_patcher.h"
+#include "vm/compiler.h"
 #include "vm/flow_graph.h"
 
 namespace dart {
@@ -60,6 +61,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/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/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index ebf9868..f2c7b12 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -123,8 +123,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 +241,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);
@@ -441,7 +440,7 @@
       const TypeArguments& type_args = TypeArguments::Handle(type.arguments());
       Error& bound_error = Error::Handle();
       target_type ^= target_type.InstantiateFrom(
-          type_args, &bound_error, NULL, Heap::kOld);
+          type_args, &bound_error, NULL, NULL, Heap::kOld);
       if (bound_error.IsNull()) {
         target_type ^= FinalizeType(cls, target_type, kCanonicalize);
       } else {
@@ -625,13 +624,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,
@@ -742,10 +742,10 @@
         }
       }
       if (offset > 0) {
-        TrailPtr trail = new Trail(Z, 4);
-        Error& bound_error = Error::Handle();
+        TrailPtr instantiation_trail = new Trail(Z, 4);
+        Error& bound_error = Error::Handle(Z);
         FinalizeTypeArguments(type_class, full_arguments, offset,
-                              &bound_error, pending_types, trail);
+                              &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
@@ -762,6 +762,11 @@
   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.
@@ -809,7 +814,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);
@@ -869,7 +874,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
@@ -896,7 +901,7 @@
                 cls.NumTypeArguments() - cls.NumTypeParameters(),
                 bound_error,
                 pending_types,
-                trail);
+                instantiation_trail);
             Type::Cast(super_type_arg).SetIsFinalized();
           }
         }
@@ -904,7 +909,7 @@
       arguments.SetTypeAt(i, super_type_arg);
     }
     FinalizeTypeArguments(super_class, arguments, super_offset,
-                          bound_error, pending_types, trail);
+                          bound_error, pending_types, instantiation_trail);
   }
 }
 
@@ -919,7 +924,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
@@ -971,8 +976,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
@@ -1002,7 +1007,8 @@
         // 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);
@@ -1023,32 +1029,47 @@
 
 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;
   }
-  const Class& type_class = Class::Handle(type.type_class());
-  Error& bound_error = Error::Handle();
+  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());
+  }
+  const Class& type_class = Class::Handle(Z, type.type_class());
+  Error& bound_error = Error::Handle(Z);
   CheckTypeArgumentBounds(type_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());
+  // 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());
+  }
 }
 
 
@@ -1063,7 +1084,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();
@@ -1092,7 +1117,7 @@
   if (FLAG_trace_type_finalization) {
     THR_Print("Finalizing type '%s' for class '%s'\n",
               String::Handle(Z, resolved_type.Name()).ToCString(),
-              cls.ToCString());
+              String::Handle(Z, cls.Name()).ToCString());
   }
 
   if (resolved_type.IsTypeParameter()) {
@@ -1143,11 +1168,9 @@
   // bounds.
   if (is_root_type) {
     for (intptr_t i = pending_types->length() - 1; i >= 0; i--) {
-      CheckTypeBounds(cls, pending_types->At(i));
-      if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) {
-        THR_Print("Done finalizing recursive type '%s': %s\n",
-                  String::Handle(Z, resolved_type.Name()).ToCString(),
-                  resolved_type.ToCString());
+      const AbstractType& type = pending_types->At(i);
+      if (!type.IsMalformed() && !type.IsCanonical()) {
+        CheckTypeBounds(cls, type);
       }
     }
   }
@@ -1179,13 +1202,14 @@
   }
 
   if (finalization >= kCanonicalize) {
-    if (FLAG_trace_type_finalization && resolved_type.IsRecursive()) {
-      AbstractType& recursive_type =
+    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 recursive type '%s': %s\n",
-                String::Handle(Z, recursive_type.Name()).ToCString(),
-                recursive_type.ToCString());
-      return recursive_type.raw();
+      THR_Print("Done canonicalizing type '%s'\n",
+                String::Handle(Z, canonical_type.Name()).ToCString());
+      return canonical_type.raw();
     }
     return resolved_type.Canonicalize();
   } else {
@@ -1309,7 +1333,8 @@
 
 
 // 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();
@@ -1325,7 +1350,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);
   }
 }
@@ -1767,7 +1792,7 @@
               param.set_bound(param_bound);  // In case part of recursive type.
             }
             param_bound = param_bound.InstantiateFrom(
-                instantiator, &bound_error, NULL, Heap::kOld);
+                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());
@@ -2001,20 +2026,20 @@
         if (type.IsBoundedType()) {
           bounded_type = BoundedType::Cast(type).type();
           bounded_type = bounded_type.InstantiateFrom(
-              instantiator, &bound_error, NULL, Heap::kOld);
+              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, NULL, Heap::kOld);
+              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, NULL, Heap::kOld);
+              instantiator, &bound_error, NULL, NULL, Heap::kOld);
           ASSERT(bound_error.IsNull());
         }
       }
@@ -2313,7 +2338,7 @@
   // unfinalized bounds. It is more efficient to finalize them early.
   // Finalize bounds even if running in production mode, so that a snapshot
   // contains them.
-  FinalizeUpperBounds(cls);
+  FinalizeUpperBounds(cls, kCanonicalizeWellFormed);
   // Finalize super type.
   AbstractType& super_type = AbstractType::Handle(cls.super_type());
   if (!super_type.IsNull()) {
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 92a79ab..e630df0 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -151,7 +151,8 @@
                                       const TypeArguments& arguments,
                                       Error* bound_error);
   static void ResolveUpperBounds(const Class& cls);
-  static void FinalizeUpperBounds(const Class& cls);
+  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);
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 52786ee..c9105ae 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -224,6 +224,9 @@
 
 
 void ClassTable::PrintToJSONObject(JSONObject* object) {
+  if (!FLAG_support_service) {
+    return;
+  }
   Class& cls = Class::Handle();
   object->AddProperty("type", "ClassList");
   {
@@ -317,6 +320,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 +478,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/code_generator.cc b/runtime/vm/code_generator.cc
index 0a207de..bf7508a 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -13,6 +13,7 @@
 #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"
@@ -205,7 +206,8 @@
   ASSERT(!type.IsNull() && !type.IsInstantiated());
   ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
   Error& bound_error = Error::Handle();
-  type = type.InstantiateFrom(instantiator, &bound_error, NULL, Heap::kOld);
+  type =
+      type.InstantiateFrom(instantiator, &bound_error, NULL, NULL, Heap::kOld);
   if (!bound_error.IsNull()) {
     // Throw a dynamic type error.
     const TokenPosition location = GetCallerLocation();
@@ -705,6 +707,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);
@@ -720,6 +726,10 @@
 
 
 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
+  if (!FLAG_support_debugger) {
+    UNREACHABLE();
+    return;
+  }
   const Error& error =
       Error::Handle(isolate->debugger()->DebuggerStepCallback());
   if (!error.IsNull()) {
@@ -1242,13 +1252,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) {
@@ -1371,7 +1383,7 @@
     // 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();
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index c98bfe3..5b67de0 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"
@@ -30,9 +32,10 @@
 #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 +51,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.");
@@ -66,105 +67,76 @@
 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);
 DECLARE_FLAG(bool, precompilation);
 
 
 #ifndef DART_PRECOMPILED_RUNTIME
 
-// 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) {
@@ -211,11 +183,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();
@@ -294,20 +265,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.
+#ifndef PRODUCT
   VMTagScope tagScope(thread, VMTag::kCompileClassTagId);
   TimelineDurationScope tds(thread,
                             thread->isolate()->GetCompilerStream(),
@@ -316,7 +283,11 @@
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "class", cls.ToCString());
   }
+#endif  // !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);
 
@@ -387,8 +358,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();
@@ -448,6 +419,7 @@
     Assembler* assembler,
     FlowGraphCompiler* graph_compiler,
     FlowGraph* flow_graph) {
+  ASSERT(!FLAG_precompilation);
   const Function& function = parsed_function()->function();
   Zone* const zone = thread()->zone();
 
@@ -546,35 +518,31 @@
     }
 
     // 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 (!FLAG_precompilation) {
-      // 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);
-      }
+    // fields it depends on because of store guards.
+    // 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);
     }
   } else {  // not optimized.
-    if (!FLAG_precompilation &&
-        (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()));
@@ -597,13 +565,16 @@
 // If optimized_result_code is not NULL then it is caller's responsibility
 // to install code.
 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
+  ASSERT(!FLAG_precompilation);
   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
   CSTAT_TIMER_SCOPE(thread(), codegen_timer);
   HANDLESCOPE(thread());
 
@@ -616,9 +587,7 @@
   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();
@@ -649,6 +618,10 @@
           const bool clone_descriptors = Compiler::IsBackgroundCompilation();
           function.RestoreICDataMap(ic_data_array, clone_descriptors);
 
+          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) {
@@ -659,9 +632,11 @@
           }
         }
 
+#ifndef PRODUCT
         TimelineDurationScope tds(thread(),
                                   compiler_timeline,
                                   "BuildFlowGraph");
+#endif  // !PRODUCT
         flow_graph = pipeline->BuildFlowGraph(zone,
                                               parsed_function(),
                                               *ic_data_array,
@@ -685,16 +660,20 @@
       const bool reorder_blocks =
           FlowGraph::ShouldReorderBlocks(function, optimized());
       if (reorder_blocks) {
+#ifndef PRODUCT
         TimelineDurationScope tds(thread(),
                                   compiler_timeline,
                                   "BlockScheduler::AssignEdgeWeights");
+#endif  // !PRODUCT
         block_scheduler.AssignEdgeWeights();
       }
 
       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);
@@ -713,9 +692,11 @@
       // 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);
         // Top scope function has no caller (-1).
         caller_inline_id.Add(-1);
@@ -723,16 +704,7 @@
 
         FlowGraphOptimizer optimizer(flow_graph,
                                      use_speculative_inlining,
-                                     &inlining_black_list);
-        if (FLAG_precompilation) {
-          optimizer.PopulateWithICData();
-
-          optimizer.ApplyClassIds();
-          DEBUG_ASSERT(flow_graph->VerifyUseLists());
-
-          FlowGraphTypePropagator::Propagate(flow_graph);
-          DEBUG_ASSERT(flow_graph->VerifyUseLists());
-        }
+                                     NULL);
         optimizer.ApplyICData();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -745,9 +717,11 @@
 
         // 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);
@@ -761,7 +735,7 @@
                                    &inline_id_to_function,
                                    &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());
@@ -772,9 +746,11 @@
         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());
@@ -794,9 +770,11 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
+#ifndef PRODUCT
           TimelineDurationScope tds2(thread(),
                                      compiler_timeline,
                                      "BranchSimplifier");
+#endif  // !PRODUCT
           BranchSimplifier::Simplify(flow_graph);
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -805,9 +783,11 @@
         }
 
         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.
@@ -834,9 +814,11 @@
         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.
           optimizer.WidenSmiToInt32();
@@ -849,9 +831,11 @@
         }
 
         {
+#ifndef PRODUCT
           TimelineDurationScope tds2(thread(),
                                      compiler_timeline,
                                      "CommonSubexpressionElinination");
+#endif  // !PRODUCT
           if (FLAG_common_subexpression_elimination ||
               FLAG_loop_invariant_code_motion) {
             flow_graph->ComputeBlockEffects();
@@ -889,16 +873,20 @@
         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);
@@ -912,9 +900,11 @@
         }
 
         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.
@@ -928,9 +918,11 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
+#ifndef PRODUCT
           TimelineDurationScope tds2(thread(),
                                      compiler_timeline,
                                      "TryCatchAnalyzer::Optimize");
+#endif  // !PRODUCT
           // Optimize try-blocks.
           TryCatchAnalyzer::Optimize(flow_graph);
         }
@@ -941,9 +933,11 @@
         optimizer.EliminateEnvironments();
 
         {
+#ifndef PRODUCT
           TimelineDurationScope tds2(thread(),
                                      compiler_timeline,
                                      "EliminateDeadPhis");
+#endif  // !PRODUCT
           DeadCodeElimination::EliminateDeadPhis(flow_graph);
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
         }
@@ -957,9 +951,11 @@
         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();
@@ -973,9 +969,11 @@
         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.
           optimizer.SelectRepresentations();
@@ -992,10 +990,12 @@
         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
@@ -1008,18 +1008,22 @@
         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 (reorder_blocks) {
+#ifndef PRODUCT
           TimelineDurationScope tds(thread(),
                                     compiler_timeline,
                                     "BlockScheduler::ReorderBlocks");
+#endif  // !PRODUCT
           block_scheduler.ReorderBlocks();
         }
 
@@ -1036,16 +1040,20 @@
                                        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
         if (thread()->IsMutatorThread()) {
           FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
         } else {
@@ -1075,8 +1083,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
@@ -1085,25 +1092,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(FLAG_precompilation);
-        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
@@ -1117,7 +1107,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;
     }
@@ -1128,147 +1118,6 @@
 }
 
 
-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 %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();
-  }
-}
-
-
 #if defined(DEBUG)
 // Verifies that the inliner is always in the list of inlined functions.
 // If this fails run with --trace-inlining-intervals to get more information.
@@ -1294,11 +1143,7 @@
                                        const Function& function,
                                        bool optimized,
                                        intptr_t osr_id) {
-  // Check that we optimize if 'FLAG_precompilation' is set to true,
-  // except if the function is marked as not optimizable.
-  ASSERT(!function.IsOptimizable() ||
-         !FLAG_precompilation || optimized);
-  ASSERT(!FLAG_precompilation || !function.HasCode());
+  ASSERT(!FLAG_precompilation);
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
@@ -1340,7 +1185,7 @@
     CompileParsedFunctionHelper helper(parsed_function, optimized, osr_id);
     const bool success = helper.Compile(pipeline);
     if (!success) {
-      if (optimized && !FLAG_precompilation) {
+      if (optimized) {
         // Optimizer bailed out. Disable optimizations and never try again.
         if (trace_compiler) {
           THR_Print("--> disabling optimizations for '%s'\n",
@@ -1355,8 +1200,8 @@
         // 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,16 +1218,18 @@
                 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)
@@ -1391,15 +1238,14 @@
     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 || FLAG_precompilation);
+    ASSERT(!optimized);
     // Do not attempt to optimize functions that can cause errors.
     function.set_is_optimizable(false);
     return error.raw();
@@ -1411,6 +1257,11 @@
 
 RawError* Compiler::CompileFunction(Thread* thread,
                                     const Function& function) {
+#ifdef DART_PRECOMPILER
+  if (FLAG_precompilation) {
+    return Precompiler::CompileFunction(thread, function);
+  }
+#endif
   Isolate* isolate = thread->isolate();
   VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
   TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function);
@@ -1425,12 +1276,9 @@
   CompilationPipeline* pipeline =
       CompilationPipeline::New(thread->zone(), function);
 
-  const bool optimized =
-      FLAG_precompilation && function.IsOptimizable();
-
   return CompileFunctionHelper(pipeline,
                                function,
-                               optimized,
+                               /* optimized = */ false,
                                kNoOSRDeoptId);
 }
 
@@ -1498,15 +1346,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 +1413,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_precompilation) {
+    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 +1458,23 @@
 
 
 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
+#ifdef DART_PRECOMPILER
+  if (FLAG_precompilation) {
+    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 +1521,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 +1530,13 @@
 }
 
 
+void Compiler::AbortBackgroundCompilation(intptr_t deopt_id) {
+  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:
@@ -1942,8 +1781,19 @@
 #else  // DART_PRECOMPILED_RUNTIME
 
 
-DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
+CompilationPipeline* CompilationPipeline::New(Zone* zone,
+                                              const Function& function) {
   UNREACHABLE();
+  return NULL;
+}
+
+
+DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
+  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()));
 }
 
 
@@ -2005,11 +1855,6 @@
 }
 
 
-void Compiler::CompileStaticInitializer(const Field& field) {
-  UNREACHABLE();
-}
-
-
 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
   ASSERT(field.HasPrecompiledInitializer());
   const Function& initializer =
@@ -2018,13 +1863,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();
 }
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 4aa4249..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,7 +142,11 @@
   // Returns Error::null() if there is no compilation error.
   static RawError* CompileAllFunctions(const Class& cls);
 
-  static bool always_optimize();
+  // 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/coverage.cc b/runtime/vm/coverage.cc
index acb61f3..8ce260b 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -60,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.
@@ -146,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
@@ -240,6 +246,9 @@
 
 
 void CodeCoverage::Write(Thread* thread) {
+  if (!FLAG_support_coverage) {
+    return;
+  }
   if (FLAG_coverage_dir == NULL) {
     return;
   }
@@ -272,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 f1afe992..025c6ed 100644
--- a/runtime/vm/coverage_test.cc
+++ b/runtime/vm/coverage_test.cc
@@ -8,6 +8,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 static RawObject* ExecuteScript(const char* script) {
   TransitionVMToNative transition(Thread::Current());
   Dart_Handle h_lib = TestCase::LoadTestScript(script, NULL);
@@ -137,4 +139,6 @@
   EXPECT_SUBSTRING(buf, js.ToCString());
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a9ddae5..bace9af 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,6 +37,8 @@
 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");
@@ -89,16 +92,22 @@
   OS::InitOnce();
   VirtualMemory::InitOnce();
   OSThread::InitOnce();
-  Timeline::InitOnce();
+  if (FLAG_support_timeline) {
+    Timeline::InitOnce();
+  }
+#ifndef PRODUCT
   TimelineDurationScope tds(Timeline::GetVMStream(),
                             "Dart::InitOnce");
+#endif
   Isolate::InitOnce();
   PortMap::InitOnce();
   FreeListElement::InitOnce();
   Api::InitOnce();
   CodeObservers::InitOnce();
-  ThreadInterrupter::InitOnce();
-  Profiler::InitOnce();
+  if (FLAG_profiler) {
+    ThreadInterrupter::InitOnce();
+    Profiler::InitOnce();
+  }
   SemiSpace::InitOnce();
   Metric::InitOnce();
   StoreBuffer::InitOnce();
@@ -197,7 +206,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,8 +234,11 @@
     return "VM already terminated.";
   }
 
-  // Shut down profiling.
-  Profiler::Shutdown();
+  if (FLAG_profiler) {
+    // Shut down profiling.
+    Profiler::Shutdown();
+  }
+
 
   {
     // Set the VM isolate as current isolate when shutting down
@@ -286,7 +301,9 @@
   }
 
   CodeObservers::DeleteAll();
-  Timeline::Shutdown();
+  if (FLAG_support_timeline) {
+    Timeline::Shutdown();
+  }
 
   return NULL;
 }
@@ -304,15 +321,18 @@
   // Initialize the new isolate.
   Thread* T = Thread::Current();
   Isolate* I = T->isolate();
+#ifndef PRODUCT
   TimelineDurationScope tds(T, I->GetIsolateStream(), "InitializeIsolate");
   tds.SetNumArguments(1);
   tds.CopyArgument(0, "isolateName", I->name());
-
+#endif  // !PRODUCT
   ASSERT(I != NULL);
   StackZone zone(T);
   HandleScope handle_scope(T);
   {
+#ifndef PRODUCT
     TimelineDurationScope tds(T, I->GetIsolateStream(), "ObjectStore::Init");
+#endif  // !PRODUCT
     ObjectStore::Init(I);
   }
 
@@ -322,8 +342,10 @@
   }
   if (snapshot_buffer != NULL) {
     // Read the snapshot and setup the initial state.
+#ifndef PRODUCT
     TimelineDurationScope tds(
         T, I->GetIsolateStream(), "IsolateSnapshotReader");
+#endif  // !PRODUCT
     // TODO(turnidge): Remove once length is not part of the snapshot.
     const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_buffer);
     if (snapshot == NULL) {
@@ -361,7 +383,9 @@
 #endif
 
   {
+#ifndef PRODUCT
     TimelineDurationScope tds(T, I->GetIsolateStream(), "StubCode::Init");
+#endif  // !PRODUCT
     StubCode::Init(I);
   }
 
@@ -376,7 +400,7 @@
 
   if (snapshot_buffer == NULL) {
     if (!I->object_store()->PreallocateObjects()) {
-      return I->object_store()->sticky_error();
+      return T->sticky_error();
     }
   }
 
@@ -388,10 +412,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.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 09c2a10..a826afe 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -52,6 +52,7 @@
 #define Z (T->zone())
 
 
+DECLARE_FLAG(bool, enable_mirrors);
 DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, precompilation);
 DECLARE_FLAG(bool, print_class_table);
@@ -78,6 +79,7 @@
   }
 }
 
+#ifndef PRODUCT
 #define API_TIMELINE_DURATION                                                  \
   TimelineDurationScope tds(Thread::Current(),                                 \
                             Timeline::GetVMApiStream(),                        \
@@ -87,7 +89,10 @@
   TimelineBeginEndScope tbes(Thread::Current(),                                \
                              Timeline::GetVMApiStream(),                       \
                              CURRENT_FUNC)
-
+#else
+#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
@@ -458,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());
 }
 
 
@@ -733,7 +738,7 @@
 // --- Handles ---
 
 DART_EXPORT bool Dart_IsError(Dart_Handle handle) {
-  return RawObject::IsErrorClassId(Api::ClassId(handle));
+  return Api::IsError(handle);
 }
 
 
@@ -1254,11 +1259,11 @@
     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
@@ -1365,6 +1370,70 @@
 }
 
 
+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() {
   Thread* T = Thread::Current();
   CHECK_ISOLATE(T->isolate());
@@ -1512,6 +1581,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;
@@ -1550,9 +1626,9 @@
     }
     ::Dart_EnterIsolate(Api::CastIsolate(I));
   }
-  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();
+  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) {
@@ -1571,8 +1647,24 @@
   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();
@@ -4410,6 +4502,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()) {
@@ -4833,15 +4929,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);
@@ -5437,14 +5535,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());
@@ -5543,7 +5645,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);
+  }
 }
 
 
@@ -5551,13 +5655,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(
@@ -5595,6 +5704,9 @@
                                                   const char* event_kind,
                                                   const uint8_t* bytes,
                                                   intptr_t bytes_length) {
+#ifdef PRODUCT
+  return Api::Success();
+#else
   DARTSCOPE(Thread::Current());
   Isolate* I = T->isolate();
   if (stream_id == NULL) {
@@ -5613,6 +5725,7 @@
   Service::SendEmbedderEvent(I, stream_id, event_kind,
                              bytes, bytes_length);
   return Api::Success();
+#endif  // PRODUCT
 }
 
 
@@ -5622,6 +5735,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(
@@ -5643,6 +5759,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;
@@ -5770,6 +5889,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) {
@@ -5792,6 +5914,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
@@ -5815,6 +5940,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) {
@@ -5836,6 +5964,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) {
@@ -5854,6 +5985,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) {
@@ -5879,6 +6013,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();
   }
@@ -5900,6 +6037,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();
   }
@@ -5919,7 +6059,9 @@
 }
 
 
-#if defined(DART_PRECOMPILED_RUNTIME)
+// 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[],
@@ -5940,7 +6082,7 @@
   return 0;
 }
 
-#else  // DART_PRECOMPILED_RUNTIME
+#else  // DART_PRECOMPILER
 
 DART_EXPORT Dart_Handle Dart_Precompile(
     Dart_QualifiedFunctionName entry_points[],
@@ -6014,7 +6156,7 @@
 
   return Api::Success();
 }
-#endif  // DART_PRECOMPILED_RUNTIME
+#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 ee36410..9820417 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -162,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.
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 0f89952..a35bf99 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -23,6 +23,8 @@
 DECLARE_FLAG(bool, verify_acquired_data);
 DECLARE_FLAG(bool, ignore_patch_signature_mismatch);
 
+#ifndef PRODUCT
+
 TEST_CASE(ErrorHandleBasics) {
   const char* kScriptChars =
       "void testMain() {\n"
@@ -396,6 +398,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,15 +505,29 @@
 }
 
 
+// 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();
+  }
 }
 
 
@@ -543,6 +562,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));
@@ -5981,6 +6032,10 @@
   EXPECT_STREQ("library1_name", cstr);
 }
 
+
+#ifndef PRODUCT
+
+
 TEST_CASE(LibraryId) {
   const char* kLibrary1Chars =
       "library library1_name;";
@@ -6018,6 +6073,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(LibraryUrl) {
   const char* kLibrary1Chars =
       "library library1_name;";
@@ -9120,6 +9178,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 TEST_CASE(Timeline_Dart_TimelineDuration) {
   Isolate* isolate = Isolate::Current();
   // Grab embedder stream.
@@ -9705,4 +9766,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 ec005b6..3c7d316 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
@@ -360,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),
@@ -376,7 +366,6 @@
       OS::PrintErr("*** Deleting Local handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
 
 
@@ -429,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),
@@ -446,7 +432,6 @@
       OS::PrintErr("*** Deleting Persistent handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
 
   // Accessors.
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index bf6a49e..615976f 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -556,7 +556,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 c961249..82511db 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -49,6 +49,8 @@
 DECLARE_FLAG(bool, precompilation);
 
 
+#ifndef PRODUCT
+
 Debugger::EventHandler* Debugger::event_handler_ = NULL;
 
 
@@ -324,7 +326,7 @@
   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());
+        Error::Handle(Thread::Current()->sticky_error());
     ASSERT(error.IsNull() || error.IsUnwindError());
 
     // Only send a resume event when the isolate is not unwinding.
@@ -365,10 +367,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();
 }
 
@@ -2129,7 +2130,7 @@
     SetBreakpointAtEntry(target_function, true);
     return Error::null();
   } else {
-    return isolate_->object_store()->sticky_error();
+    return Thread::Current()->sticky_error();
   }
 }
 
@@ -2323,7 +2324,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();
@@ -2357,7 +2358,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();
@@ -2695,9 +2696,8 @@
   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();
 }
 
@@ -2786,9 +2786,8 @@
   }
 
   // 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();
 }
 
@@ -3279,4 +3278,6 @@
   code_breakpoints_ = bpt;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 9ac461c..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();                                                  \
@@ -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..fdfd262 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -15,6 +15,8 @@
 DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, use_osr);
 
+#ifndef PRODUCT
+
 static bool breakpoint_hit = false;
 static int  breakpoint_hit_counter = 0;
 static Dart_Handle script_lib = NULL;
@@ -2327,4 +2329,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/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index bdb5035..a926fdf 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -138,7 +138,7 @@
   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);
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 3dd538f..229a0aa 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -485,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);
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..bf07877 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)
@@ -1465,6 +1467,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..a6195fb 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)
@@ -774,6 +776,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/exceptions.cc b/runtime/vm/exceptions.cc
index 29f1684..369d099 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -489,10 +489,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,
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
new file mode 100644
index 0000000..259d09b
--- /dev/null
+++ b/runtime/vm/flag_list.h
@@ -0,0 +1,67 @@
+// 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.
+
+#define FLAG_LIST(P, R, D)                                                     \
+R(dedup_instructions, true, bool, false,                                       \
+  "Canonicalize instructions when precompiling.")                              \
+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")                                              \
+R(gc_at_alloc, false, bool, false,                                             \
+  "GC at every allocation.")                                                   \
+P(new_gen_ext_limit, int, 64,                                                  \
+  "maximum total external size (MB) in new gen before triggering GC")          \
+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.")                  \
+R(profiler, false, bool, true,                                                 \
+  "Enable the profiler.")                                                      \
+R(support_ast_printer, false, bool, true,                                      \
+  "Support the AST printer.")                                                  \
+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_handles, bool, false,                                                  \
+  "Traces allocation of handles.")                                             \
+D(trace_zones, bool, false,                                                    \
+  "Traces allocation sizes in the zone.")                                      \
+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..a2a63f7 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -14,6 +14,41 @@
 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)
+// Nothing to be done for the product flag definitions.
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)
+#else  // defined(PRODUCT)
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+#endif  // defined(PRODUCT)
+
+// Define all of the non-product flags here.
+FLAG_LIST(PRODUCT_FLAG_MARCO, RELEASE_FLAG_MARCO, DEBUG_FLAG_MARCO)
+
+#undef RELEASE_FLAG_MARCO
+#undef DEBUG_FLAG_MARCO
+#undef PRODUCT_FLAG_MARCO
+
+
 bool Flags::initialized_ = false;
 
 // List of registered flags.
@@ -421,6 +456,9 @@
 
 
 void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) {
+  if (!FLAG_support_service) {
+    return;
+  }
   if (flag->IsUnrecognized() || flag->type_ == Flag::kFunc) {
     return;
   }
@@ -462,6 +500,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..d3e4869 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,35 @@
   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)
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  const type FLAG_##name = product_value;
+
+#else  // defined(PRODUCT)
+
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  extern type FLAG_##name;
+
+#endif  // defined(PRODUCT)
+
+// Now declare all flags here.
+FLAG_LIST(PRODUCT_FLAG_MARCO, RELEASE_FLAG_MARCO, DEBUG_FLAG_MARCO)
+
+#undef RELEASE_FLAG_MARCO
+#undef DEBUG_FLAG_MARCO
+#undef PRODUCT_FLAG_MARCO
+
 }  // namespace dart
 
 #endif  // VM_FLAGS_H_
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 4097af5..49f81ff 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -52,6 +52,43 @@
 }
 
 
+void FlowGraph::EnsureSSATempIndex(Definition* defn,
+                                   Definition* replacement) {
+  if ((replacement->ssa_temp_index() == -1) &&
+      (defn->ssa_temp_index() != -1)) {
+    AllocateSSAIndexes(replacement);
+  }
+}
+
+
+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());
+    }
+  }
+  iterator->RemoveCurrentFromGraph();
+}
+
+
+
 void FlowGraph::AddToGuardedFields(
     ZoneGrowableArray<const Field*>* array,
     const Field* field) {
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index cf62e82..970a7a0 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;
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 861721a..63bdb24 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -36,7 +36,6 @@
             "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.");
 
@@ -175,7 +174,7 @@
   if (break_target_ == NULL) {
     break_target_ =
         new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                            owner()->try_index());
+                                            try_index());
   }
   return break_target_;
 }
@@ -251,7 +250,7 @@
   if (continue_target_ == NULL) {
     continue_target_ =
         new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                               try_index());
+                                            try_index());
   }
   return continue_target_;
 }
@@ -295,7 +294,7 @@
     if (case_targets_[i] == NULL) {
       case_targets_[i] =
           new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                                 try_index());
+                                              try_index());
     }
     return case_targets_[i];
   }
@@ -1627,7 +1626,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);
@@ -4623,11 +4622,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 =
diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc
index ba8f52a..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);         \
@@ -779,6 +781,7 @@
   spt.Dump();
 }
 
+#endif  // !PRODUCT
 
 static bool SyntheticRoundTripTest(TokenPosition token_pos) {
   const TokenPosition synthetic_token_pos = token_pos.ToSynthetic();
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 69640c4..15851e6 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -53,8 +53,6 @@
 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);
@@ -67,7 +65,6 @@
 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);
@@ -101,7 +98,9 @@
     FLAG_use_field_guards = false;
     FLAG_use_osr = false;
     FLAG_emit_edge_counters = false;
+#ifndef PRODUCT
     FLAG_support_debugger = false;
+#endif
     FLAG_ic_range_profiling = false;
     FLAG_collect_code = false;
     FLAG_load_deferred_eagerly = true;
@@ -269,9 +268,11 @@
 
 
 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();
@@ -934,7 +935,7 @@
     return &intrinsic_slow_path_label_;
   }
 
-  // No deoptimization allowed when 'always_optimize' is set.
+  // No deoptimization allowed when 'FLAG_precompilation' is set.
   if (FLAG_precompilation) {
     if (FLAG_trace_compiler) {
       THR_Print(
@@ -982,7 +983,7 @@
 
 
 RawArray* FlowGraphCompiler::CreateDeoptInfo(Assembler* assembler) {
-  // No deopt information if we 'always_optimize' (no deoptimization allowed).
+  // No deopt information if we precompile (no deoptimization allowed).
   if (FLAG_precompilation) {
     return Array::empty_array().raw();
   }
@@ -1282,10 +1283,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
 }
 
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index e3780cb..4eb7f3f 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -278,7 +278,8 @@
   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));
@@ -318,7 +319,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);
@@ -378,6 +379,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ b(is_instance_lbl, EQ);
   } else {
@@ -405,7 +407,7 @@
   // 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;
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index b86c581..2a237d9 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -270,7 +270,8 @@
   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));
@@ -310,7 +311,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);
@@ -370,6 +371,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ b(is_instance_lbl, EQ);
   } else {
@@ -397,7 +399,7 @@
   // 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;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index e142041..0476344 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -282,7 +282,8 @@
   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));
@@ -322,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);
@@ -381,6 +382,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ j(ZERO, is_instance_lbl);
   } else {
@@ -408,7 +410,7 @@
   // 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;
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 654b755..f9777c0 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -270,7 +270,8 @@
   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));
@@ -309,7 +310,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);
@@ -369,6 +370,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ beq(T0, ZR, is_instance_lbl);
   } else {
@@ -394,7 +396,7 @@
   // 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;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 68004fb..b922bb8 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -278,7 +278,8 @@
   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));
@@ -318,7 +319,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);
@@ -377,6 +378,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ j(ZERO, is_instance_lbl);
   } else {
@@ -404,7 +406,7 @@
   // 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;
@@ -1448,7 +1450,7 @@
     __ popq(right);
     __ popq(left);
   } else {
-    __ cmpl(left, right);
+    __ CompareRegisters(left, right);
   }
   return EQUAL;
 }
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index d0d6b3e..8cec8d7 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -5,6 +5,7 @@
 #include "vm/flow_graph_inliner.h"
 
 #include "vm/block_scheduler.h"
+#include "vm/branch_optimizer.h"
 #include "vm/compiler.h"
 #include "vm/flags.h"
 #include "vm/flow_graph.h"
@@ -706,6 +707,10 @@
               new(Z) ZoneGrowableArray<const ICData*>();
         const bool clone_descriptors = Compiler::IsBackgroundCompilation();
         function.RestoreICDataMap(ic_data_array, clone_descriptors);
+        if (Compiler::IsBackgroundCompilation() &&
+            (function.ic_data_array() == Array::null())) {
+          Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+        }
 
         // Build the callee graph.
         InlineExitCollector* exit_collector =
@@ -805,7 +810,7 @@
           DEBUG_ASSERT(callee_graph->VerifyUseLists());
         }
 
-        if (FLAG_trace_inlining &&
+        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());
@@ -894,8 +899,8 @@
             &call_data->caller, &function, call);
         return true;
       } else {
-        error = isolate()->object_store()->sticky_error();
-        isolate()->object_store()->clear_sticky_error();
+        error = thread()->sticky_error();
+        thread()->clear_sticky_error();
         ASSERT(error.IsLanguageError());
 
         if (LanguageError::Cast(error).kind() == Report::kBailout) {
@@ -1903,7 +1908,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());
@@ -1921,7 +1927,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_);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 848cdb0..f10954a 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5,6 +5,7 @@
 #include "vm/flow_graph_optimizer.h"
 
 #include "vm/bit_vector.h"
+#include "vm/branch_optimizer.h"
 #include "vm/cha.h"
 #include "vm/compiler.h"
 #include "vm/cpu.h"
@@ -31,16 +32,12 @@
 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");
@@ -57,7 +54,6 @@
 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())
@@ -254,6 +250,7 @@
     return true;
   }
 
+#ifdef DART_PRECOMPILER
   if (FLAG_precompilation &&
       (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
     // Check if the target is unique.
@@ -274,6 +271,7 @@
       return true;
     }
   }
+#endif
 
   // Check if getter or setter in function's class and class is currently leaf.
   if (FLAG_guess_icdata_cid &&
@@ -641,44 +639,6 @@
 }
 
 
-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) {
@@ -697,7 +657,7 @@
         // For non-definitions Canonicalize should return either NULL or
         // this.
         ASSERT((replacement == NULL) || current->IsDefinition());
-        ReplaceCurrentInstruction(&it, current, replacement, flow_graph_);
+        flow_graph_->ReplaceCurrentInstruction(&it, current, replacement);
         changed = true;
       }
     }
@@ -3927,6 +3887,7 @@
         type_class,
         TypeArguments::Handle(Z),
         NULL,
+        NULL,
         Heap::kOld);
     results->Add(cls.id());
     results->Add(is_subtype);
@@ -4021,6 +3982,7 @@
                                                 type_class,
                                                 TypeArguments::Handle(),
                                                 NULL,
+                                                NULL,
                                                 Heap::kOld);
     results->Add((*results)[results->length() - 2]);
     results->Add((*results)[results->length() - 2]);
@@ -4497,133 +4459,157 @@
   if (unary_kind != MathUnaryInstr::kIllegal) {
     if (FLAG_precompilation) {
       // 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 (FLAG_precompilation) {
-      // 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)));
+    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;
     }
-    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()));
+    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;
     }
-  } 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);
-            }
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2: {
+      if (FLAG_precompilation) {
+        // No UnboxDouble instructons allowed.
+        return;
+      }
+      // 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()));
           }
         }
-        default:
-          break;
+      }
+      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;
+          }
+        }
       }
     }
   }
@@ -5048,3183 +5034,6 @@
 }
 
 
-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() ||
-      FLAG_precompilation) {
-    // 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);
-  }
-
-  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);
-}
-
-
-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.
@@ -8246,611 +5055,4 @@
 }
 
 
-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
index afbb455..9bbcbdf 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -283,174 +283,6 @@
 };
 
 
-// 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 2f44af3..f9840c6 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -184,7 +184,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 +694,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 +997,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 +1008,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 +1023,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 +1057,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 +1066,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),
@@ -1673,7 +1673,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 +1710,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 +1751,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 +1826,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 +1894,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 85371e0..93e06b7 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -21,12 +21,14 @@
 
 
 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();
 }
@@ -80,13 +82,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());
@@ -216,7 +218,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 +414,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.
@@ -618,7 +621,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 +636,7 @@
     return IsNull();
   }
 
-  return ToAbstractType()->IsMoreSpecificThan(other, NULL, Heap::kOld);
+  return ToAbstractType()->IsMoreSpecificThan(other, NULL, NULL, Heap::kOld);
 }
 
 
@@ -655,7 +658,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,
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index e9f33c3..6fcc90c 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -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);
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/heap.cc b/runtime/vm/heap.cc
index 8a18924..d7846a7 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -26,23 +26,6 @@
 
 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,
@@ -379,9 +362,11 @@
     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();
@@ -404,9 +389,11 @@
     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 +749,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 bd685c5..950223c 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 {
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 12bcc09..207167c 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");
@@ -1217,4 +1219,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/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 9aa7cd5..be7171a 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2057,7 +2057,7 @@
     Error& bound_error = Error::Handle();
     const AbstractType& new_dst_type = AbstractType::Handle(
         dst_type().InstantiateFrom(
-            instantiator_type_args, &bound_error, NULL, Heap::kOld));
+            instantiator_type_args, &bound_error, NULL, 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())) {
@@ -2344,7 +2344,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()
@@ -3543,9 +3543,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 +3570,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 +3590,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 +3629,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 +3646,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:
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f03f11e..f4664dc 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -599,6 +599,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,
@@ -704,8 +718,10 @@
 
   // 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); }                             \
@@ -1054,12 +1070,12 @@
 
   bool IsRedundant() const;
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   virtual TokenPosition token_pos() const {
     return TokenPosition::kParallelMove;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   GrowableArray<MoveOperands*> moves_;   // Elements cannot be null.
 
@@ -1375,7 +1391,7 @@
     return indirect_entries_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   virtual void ClearPredecessors() {}
@@ -1421,11 +1437,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;
@@ -1492,7 +1508,7 @@
     return predecessor_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   friend class BlockEntryInstr;  // Access to predecessor_ when inlining.
@@ -1520,10 +1536,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_;
 };
@@ -1570,7 +1586,7 @@
     return &initial_definitions_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   friend class BlockEntryInstr;  // Access to predecessor_ when inlining.
@@ -1712,6 +1728,9 @@
     return false;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+  PRINT_TO_SUPPORT
+
   bool UpdateType(CompileType new_type) {
     if (type_ == NULL) {
       type_ = ZoneCompileType::Wrap(new_type);
@@ -1753,11 +1772,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)
@@ -1937,8 +1951,6 @@
 
   DECLARE_INSTRUCTION(Phi)
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
 
   BitVector* reaching_defs() const {
@@ -1962,6 +1974,8 @@
     return loop_variable_info_;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   // Direct access to inputs_ in order to resize it due to unreachable
   // predecessors.
@@ -2012,12 +2026,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(); }
 
@@ -2045,12 +2059,13 @@
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual TokenPosition token_pos() const {
     return TokenPosition::kPushArgument;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
 };
@@ -2223,12 +2238,12 @@
     return parallel_move_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   virtual TokenPosition token_pos() const {
     return TokenPosition::kControlFlow;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   BlockEntryInstr* block_;
   JoinEntryInstr* successor_;
@@ -2286,11 +2301,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_;
@@ -2417,8 +2432,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.
@@ -2454,6 +2467,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);
@@ -2535,8 +2550,6 @@
     return false;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   Value* value() const { return inputs_[0]; }
   Range* constraint() const { return constraint_; }
 
@@ -2552,6 +2565,8 @@
     return target_;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   Range* constraint_;
   TargetEntryInstr* target_;
@@ -2572,8 +2587,6 @@
 
   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);
@@ -2582,6 +2595,8 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Object& value_;
   const TokenPosition token_pos_;
@@ -2647,8 +2662,6 @@
   }
   const String& dst_name() const { return dst_name_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -2661,6 +2674,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   AbstractType& dst_type_;
@@ -2684,14 +2699,14 @@
   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 TokenPosition token_pos_;
 
@@ -2747,12 +2762,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_;
@@ -2814,8 +2829,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 {
@@ -2826,6 +2839,8 @@
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  protected:
   friend class FlowGraphOptimizer;
   void set_ic_data(ICData* value) { ic_data_ = value; }
@@ -2883,7 +2898,7 @@
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   InstanceCallInstr* instance_call_;
@@ -2908,8 +2923,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
@@ -2925,6 +2938,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.
@@ -3014,7 +3029,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_;
@@ -3041,8 +3056,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
@@ -3058,6 +3071,8 @@
     return kTagged;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(EqualityCompareInstr);
 };
@@ -3082,8 +3097,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
@@ -3099,6 +3112,8 @@
     return kTagged;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RelationalOpInstr);
 };
@@ -3148,8 +3163,6 @@
     return comparison()->RequiredInputRepresentation(i);
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual CompileType ComputeType() const;
 
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
@@ -3173,6 +3186,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);
@@ -3231,8 +3246,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 {
@@ -3262,6 +3275,8 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const ICData* ic_data_;
   const TokenPosition token_pos_;
@@ -3291,8 +3306,6 @@
 
   const LocalVariable& local() const { return local_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const {
@@ -3305,6 +3318,8 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const LocalVariable& local_;
   bool is_last_;
@@ -3365,8 +3380,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const {
@@ -3383,6 +3396,8 @@
     return TokenPosition::kTempMove;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     value_ = value;
@@ -3410,8 +3425,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; }
@@ -3427,6 +3440,8 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const LocalVariable& local_;
   bool is_dead_;
@@ -3468,14 +3483,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;
@@ -3584,8 +3599,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.
@@ -3604,6 +3617,8 @@
 
   virtual Representation RequiredInputRepresentation(intptr_t index) const;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   friend class FlowGraphOptimizer;  // For ASSERT(initialization_).
 
@@ -3648,7 +3663,7 @@
     return true;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const Field& field_;
@@ -3708,8 +3723,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(); }
@@ -3719,6 +3732,8 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
 
@@ -3746,8 +3761,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
@@ -3757,6 +3770,8 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   bool CanValueBeSmi() const {
     const intptr_t cid = value()->Type()->ToNullableCid();
@@ -4097,12 +4112,12 @@
   const AbstractType& type() const { return type_; }
   virtual TokenPosition token_pos() const { return token_pos_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   Value* value_;
@@ -4144,8 +4159,6 @@
     closure_function_ ^= function.raw();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -4153,6 +4166,8 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const Class& cls_;
@@ -4179,8 +4194,6 @@
   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(); }
@@ -4188,6 +4201,8 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const intptr_t num_context_variables_;
@@ -4256,7 +4271,6 @@
   }
 
   DECLARE_INSTRUCTION(MaterializeObject)
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual intptr_t InputCount() const {
     return values_->length();
@@ -4292,6 +4306,8 @@
     visited_for_liveness_ = true;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*values_)[i] = value;
@@ -4482,8 +4498,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);
@@ -4501,6 +4515,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_;
@@ -4537,12 +4553,12 @@
   const Class& instantiator_class() const { return instantiator_class_; }
   virtual TokenPosition token_pos() const { return token_pos_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const AbstractType& type_;
@@ -4575,14 +4591,14 @@
   const Class& instantiator_class() const { return instantiator_class_; }
   virtual TokenPosition token_pos() const { return token_pos_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
   const TypeArguments& type_arguments_;
@@ -4605,12 +4621,12 @@
   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 TokenPosition token_pos_;
   const intptr_t num_context_variables_;
@@ -4966,10 +4982,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_;
 
@@ -5074,8 +5090,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 {
@@ -5104,6 +5118,8 @@
 
   static const char* KindToCString(MathUnaryKind kind);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MathUnaryKind kind_;
 
@@ -5245,8 +5261,6 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5264,6 +5278,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(BinaryDoubleOp)
   virtual CompileType ComputeType() const;
 
@@ -5297,8 +5313,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 {
@@ -5323,6 +5337,8 @@
     return op_kind() == other->AsBinaryFloat32x4Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -5345,8 +5361,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5382,6 +5396,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Simd32x4Shuffle)
   virtual CompileType ComputeType() const;
 
@@ -5414,8 +5430,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5441,6 +5455,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Simd32x4ShuffleMix)
   virtual CompileType ComputeType() const;
 
@@ -5476,8 +5492,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 {
@@ -5500,6 +5514,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ConstructorInstr);
 };
@@ -5514,8 +5530,6 @@
 
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5538,6 +5552,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4SplatInstr);
 };
@@ -5580,8 +5596,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 {
@@ -5606,6 +5620,8 @@
     return op_kind() == other->AsFloat32x4Comparison()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5629,8 +5645,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 {
@@ -5655,6 +5669,8 @@
     return op_kind() == other->AsFloat32x4MinMax()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5678,8 +5694,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 {
@@ -5707,6 +5721,8 @@
     return op_kind() == other->AsFloat32x4Scale()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5727,8 +5743,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 {
@@ -5753,6 +5767,8 @@
     return op_kind() == other->AsFloat32x4Sqrt()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5775,8 +5791,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 {
@@ -5801,6 +5815,8 @@
     return op_kind() == other->AsFloat32x4ZeroArg()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5824,8 +5840,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 {
@@ -5848,6 +5862,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ClampInstr);
 };
@@ -5870,8 +5886,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 {
@@ -5899,6 +5913,8 @@
     return op_kind() == other->AsFloat32x4With()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5922,8 +5938,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5959,6 +5973,8 @@
            (mask() == other->AsSimd64x2Shuffle()->mask());
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
   const intptr_t mask_;
@@ -5976,8 +5992,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6000,6 +6014,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ToInt32x4Instr);
 };
@@ -6014,8 +6030,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6038,6 +6052,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ToFloat64x2Instr);
 };
@@ -6052,8 +6068,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6076,6 +6090,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float64x2ToFloat32x4Instr);
 };
@@ -6092,8 +6108,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 {
@@ -6111,6 +6125,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2Constructor)
   virtual CompileType ComputeType() const;
 
@@ -6130,8 +6146,6 @@
 
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6154,6 +6168,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float64x2SplatInstr);
 };
@@ -6193,8 +6209,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 {
@@ -6216,6 +6230,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2ZeroArg)
   virtual CompileType ComputeType() const;
 
@@ -6246,8 +6262,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 {
@@ -6273,6 +6287,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2OneArg)
   virtual CompileType ComputeType() const;
 
@@ -6306,8 +6322,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 {
@@ -6330,6 +6344,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4ConstructorInstr);
 };
@@ -6355,8 +6371,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 {
@@ -6379,6 +6393,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4BoolConstructorInstr);
 };
@@ -6397,8 +6413,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 {
@@ -6423,6 +6437,8 @@
     return op_kind() == other->AsInt32x4GetFlag()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6443,8 +6459,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 {
@@ -6473,6 +6487,8 @@
     return other->AsSimd32x4GetSignMask()->op_kind() == op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6496,8 +6512,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 {
@@ -6523,6 +6537,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4SelectInstr);
 };
@@ -6544,8 +6560,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 {
@@ -6573,6 +6587,8 @@
     return op_kind() == other->AsInt32x4SetFlag()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6589,8 +6605,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6613,6 +6627,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4ToFloat32x4Instr);
 };
@@ -6634,8 +6650,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 {
@@ -6660,6 +6674,8 @@
     return op_kind() == other->AsBinaryInt32x4Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -6694,8 +6710,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.
@@ -6709,6 +6723,8 @@
     return op_kind() == other->AsBinaryFloat64x2Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -6746,7 +6762,7 @@
     return GetDeoptId();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
   RawInteger* Evaluate(const Integer& value) const;
 
@@ -6905,7 +6921,8 @@
 
   virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+  PRINT_OPERANDS_TO_SUPPORT
 
   DEFINE_INSTRUCTION_TYPE_CHECK(BinaryIntegerOp)
 
@@ -7148,8 +7165,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;
 
@@ -7172,6 +7187,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -7197,7 +7214,7 @@
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const TokenPosition token_pos_;
@@ -7489,7 +7506,6 @@
 
   DECLARE_INSTRUCTION(InvokeMathCFunction)
   virtual CompileType ComputeType() const;
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -7523,6 +7539,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;
@@ -7554,7 +7572,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_; }
@@ -7580,6 +7597,8 @@
            (other_extract->index() == index());
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const intptr_t index_;
   const Representation definition_rep_;
@@ -7622,7 +7641,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) {
@@ -7676,6 +7694,8 @@
     return "";
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*inputs_)[i] = value;
@@ -7707,8 +7727,6 @@
 
   virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   bool IsNullCheck() const {
     return  DeoptIfNull() || DeoptIfNotNull();
   }
@@ -7729,6 +7747,8 @@
 
   static bool IsImmutableClassId(intptr_t cid);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const ICData& unary_checks_;
   GrowableArray<intptr_t> cids_;  // Sorted, lowest first.
@@ -7790,7 +7810,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_;
@@ -7900,8 +7920,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();
@@ -7909,6 +7927,8 @@
 
   DECLARE_INSTRUCTION(UnboxedIntConverter);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Representation from_representation_;
   const Representation to_representation_;
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 2be4d9a..a86906a 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -7,6 +7,7 @@
 
 #include "vm/intermediate_language.h"
 
+#include "vm/compiler.h"
 #include "vm/cpu.h"
 #include "vm/dart_entry.h"
 #include "vm/flow_graph.h"
@@ -1583,6 +1584,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.
   }
@@ -1737,6 +1742,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.
   }
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 4b8b565..e8bd759 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.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"
@@ -1440,6 +1441,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.
   }
@@ -1591,6 +1596,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.
   }
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 7487d86..f067afe 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"
@@ -1434,6 +1435,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.
   }
@@ -1589,6 +1594,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.
   }
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 79736b9..064bd6e 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.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"
@@ -1614,6 +1615,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.
   }
@@ -1768,6 +1773,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.
   }
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 53ca97b..1f840fd 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.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"
@@ -1457,6 +1458,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.
   }
@@ -1598,6 +1603,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.
   }
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index accc70f..69c723d 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -156,7 +156,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 +167,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();
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index dc99e4c..3214d5f 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -154,6 +154,17 @@
 }
 
 
+NoOOBMessageScope::NoOOBMessageScope(Thread* thread) : StackResource(thread) {
+  isolate()->DeferOOBMessageInterrupts();
+}
+
+
+NoOOBMessageScope::~NoOOBMessageScope() {
+  isolate()->RestoreOOBMessageInterrupts();
+}
+
+
+
 void Isolate::RegisterClass(const Class& cls) {
   class_table()->Register(cls);
 }
@@ -357,7 +368,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;
@@ -445,9 +456,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.
@@ -510,7 +523,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: {
@@ -572,6 +589,9 @@
 
 
 void IsolateMessageHandler::NotifyPauseOnStart() {
+  if (!FLAG_support_service) {
+    return;
+  }
   if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
     StartIsolateScope start_isolate(I);
     StackZone zone(T);
@@ -586,6 +606,9 @@
 
 
 void IsolateMessageHandler::NotifyPauseOnExit() {
+  if (!FLAG_support_service) {
+    return;
+  }
   if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
     StartIsolateScope start_isolate(I);
     StackZone zone(T);
@@ -611,9 +634,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()) {
@@ -638,7 +661,9 @@
     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));
+      if (FLAG_support_debugger) {
+        I->debugger()->SignalExceptionThrown(Instance::Handle(exception));
+      }
     }
   }
 
@@ -668,14 +693,14 @@
   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);
       }
       return kError;
     }
@@ -774,6 +799,8 @@
       simulator_(NULL),
       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),
@@ -823,7 +850,9 @@
   delete heap_;
   delete object_store_;
   delete api_state_;
-  delete debugger_;
+  if (FLAG_support_debugger) {
+    delete debugger_;
+  }
 #if defined(USING_SIMULATOR)
   delete simulator_;
 #endif
@@ -833,7 +862,9 @@
   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;
@@ -868,6 +899,7 @@
   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,                                         \
@@ -875,6 +907,7 @@
                                 Timeline::Stream##name##EnabledFlag());
   ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT);
 #undef ISOLATE_TIMELINE_STREAM_INIT
+#endif  // !PRODUCT
 
   Heap::Init(result,
              is_vm_isolate
@@ -913,8 +946,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"
@@ -927,7 +962,9 @@
     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)) {
@@ -1029,16 +1066,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());
@@ -1068,9 +1095,7 @@
   // 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);
     }
@@ -1080,14 +1105,18 @@
     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);
   }
@@ -1336,8 +1365,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;
@@ -1347,7 +1375,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());
@@ -1359,7 +1387,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);
     }
 
@@ -1402,7 +1430,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;
@@ -1422,7 +1450,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());
     }
@@ -1441,6 +1469,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_) {
@@ -1452,6 +1501,40 @@
 }
 
 
+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_;
+    }
+  }
+}
+
+
+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;
+  }
+}
+
+
 RawError* Isolate::HandleInterrupts() {
   uword interrupt_bits = GetAndClearInterrupts();
   if ((interrupt_bits & kVMInterrupt) != 0) {
@@ -1472,9 +1555,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();
     }
   }
@@ -1571,7 +1655,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()) {
@@ -1580,7 +1664,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());
@@ -1588,15 +1675,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;
@@ -1756,7 +1847,9 @@
       reinterpret_cast<RawObject**>(&registered_service_extension_handlers_));
 
   // 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) {
@@ -1796,6 +1889,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 "",
@@ -1817,14 +1913,15 @@
     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()) {
+  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()->paused_on_exit()) {
+  } else if (message_handler()->is_paused_on_exit()) {
     ASSERT(debugger()->PauseEvent() == NULL);
     ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
     jsobj.AddProperty("pauseEvent", &pause_event);
@@ -1855,8 +1952,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);
   }
@@ -1954,6 +2051,9 @@
 
 
 RawObject* Isolate::InvokePendingServiceExtensionCalls() {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GrowableObjectArray& calls =
       GrowableObjectArray::Handle(GetAndClearPendingServiceExtensionCalls());
   if (calls.IsNull()) {
@@ -2061,6 +2161,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()) {
@@ -2093,6 +2196,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()) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ee0404b..f2a0cc3 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -81,6 +81,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.
@@ -304,6 +314,9 @@
   Mutex* mutex() const { return mutex_; }
 
   Debugger* debugger() const {
+    if (!FLAG_support_debugger) {
+      return NULL;
+    }
     ASSERT(debugger_ != NULL);
     return debugger_;
   }
@@ -353,8 +366,8 @@
 
   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();
   }
@@ -554,10 +567,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();
 
@@ -655,6 +675,7 @@
  private:
   friend class Dart;  // Init, InitOnce, Shutdown.
   friend class IsolateKillerVisitor;  // Kill().
+  friend class NoOOBMessageScope;
 
   explicit Isolate(const Dart_IsolateFlags& api_flags);
 
@@ -681,6 +702,9 @@
     user_tag_ = tag;
   }
 
+  void DeferOOBMessageInterrupts();
+  void RestoreOOBMessageInterrupts();
+
   RawGrowableObjectArray* GetAndClearPendingServiceExtensionCalls();
   RawGrowableObjectArray* pending_service_extension_calls() const {
     return pending_service_extension_calls_;
@@ -744,6 +768,8 @@
   Simulator* simulator_;
   Mutex* mutex_;  // protects stack_limit_, saved_stack_limit_, compiler stats.
   uword saved_stack_limit_;
+  uword deferred_interrupts_mask_;
+  uword deferred_interrupts_;
   uword stack_overflow_flags_;
   int32_t stack_overflow_count_;
   MessageHandler* message_handler_;
@@ -828,10 +854,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_;
@@ -864,6 +892,7 @@
   friend class ServiceIsolate;
   friend class Thread;
   friend class Timeline;
+  friend class IsolateTestHelper;
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 4bf156d..ef3ba53 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -149,4 +149,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/json_stream.cc b/runtime/vm/json_stream.cc
index 6a2694a..b64d6e6 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)
@@ -857,4 +859,6 @@
   free(p);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 985b547..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.
@@ -314,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/longjump.cc b/runtime/vm/longjump.cc
index 5820a47..ef141c9 100644
--- a/runtime/vm/longjump.cc
+++ b/runtime/vm/longjump.cc
@@ -49,7 +49,6 @@
   ASSERT(IsSafeToJump());
 
   Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
 
 #if defined(DEBUG)
 #define CHECK_REUSABLE_HANDLE(name)                                            \
@@ -59,7 +58,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/message.cc b/runtime/vm/message.cc
index 195b2c6..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();
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index 30194cd..e64a05a 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),
@@ -258,6 +258,18 @@
 }
 
 
+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(true, true);
+}
+
+
 MessageHandler::MessageStatus MessageHandler::HandleOOBMessages() {
   if (!oob_message_handling_allowed_) {
     return kOK;
@@ -270,17 +282,33 @@
 }
 
 
-bool MessageHandler::HasOOBMessages() {
-  MonitorLocker ml(&monitor_);
-  return !oob_queue_->IsEmpty();
+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();
 }
 
 
-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.
+bool MessageHandler::ShouldPauseOnExit(MessageStatus status) const {
+  Isolate* owning_isolate = isolate();
+  if (owning_isolate == NULL) {
+    return false;
+  }
   return (status != MessageHandler::kRestart &&
-          status != MessageHandler::kShutdown);
+          status != MessageHandler::kShutdown) &&
+         should_pause_on_exit() && owning_isolate->is_runnable();
+}
+
+
+bool MessageHandler::HasOOBMessages() {
+  MonitorLocker ml(&monitor_);
+  return !oob_queue_->IsEmpty();
 }
 
 
@@ -294,28 +322,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()) {
+      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);
       }
     }
 
@@ -342,39 +361,28 @@
     // 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(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 +451,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..47dfa99 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -56,6 +56,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 +85,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 +116,9 @@
     return paused_timestamp_;
   }
 
+  void PausedOnStart(bool paused);
+  void PausedOnExit(bool paused);
+
   class AcquiredQueues : public ValueObject {
    public:
     AcquiredQueues();
@@ -203,6 +213,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);
@@ -221,10 +236,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..5547282 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -54,6 +54,11 @@
   V(_Double, _div, DoubleDiv, 1201505037)                                      \
   V(::, sin, MathSin, 1741396147)                                              \
   V(::, cos, MathCos, 1951197905)                                              \
+  V(::, tan, MathTan, 982072809)                                               \
+  V(::, asin, MathAsin, 1651042633)                                            \
+  V(::, acos, MathAcos, 1139647090)                                            \
+  V(::, atan, MathAtan, 1668754384)                                            \
+  V(::, atan2, MathAtan2, 1931713076)                                          \
   V(::, min, MathMin, 478627534)                                               \
   V(::, max, MathMax, 212291192)                                               \
   V(::, _doublePow, MathDoublePow, 1286501289)                                 \
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/native_arguments.h b/runtime/vm/native_arguments.h
index 8bb1d6e..ded8b85 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -131,6 +131,10 @@
     *retval_ = value.raw();
   }
 
+  RawObject* ReturnValue() const {
+    return *retval_;
+  }
+
   static intptr_t thread_offset() {
     return OFFSET_OF(NativeArguments, thread_);
   }
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index 2277319..34ea4bf 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -91,6 +91,25 @@
 }
 
 
+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;
@@ -102,6 +121,9 @@
   if (!arguments->IsNativeAutoSetupScope()) {
     TransitionGeneratedToNative transition(thread);
     func(args);
+    if (ReturnValueIsError(arguments)) {
+      PropagateErrors(arguments);
+    }
   } else {
     Isolate* isolate = thread->isolate();
     ApiState* state = isolate->api_state();
@@ -123,6 +145,9 @@
     thread->set_api_top_scope(scope);  // New scope is now the top scope.
 
     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 prev.
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index e9dab6c..c5578f9 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -121,6 +121,9 @@
 
   static uword LinkNativeCallEntry();
   static void LinkNativeCall(Dart_NativeArguments args);
+ private:
+  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 340735f..febf565 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -29,6 +29,7 @@
 #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"
@@ -116,6 +117,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;
@@ -492,6 +494,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();
@@ -842,6 +845,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());
@@ -883,6 +897,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());
 }
@@ -1084,9 +1100,11 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   ASSERT(isolate == thread->isolate());
+#ifndef PRODUCT
   TimelineDurationScope tds(thread,
                             isolate->GetIsolateStream(),
                             "Object::Init");
+#endif
 
 #if defined(DART_NO_SNAPSHOT)
   // Object::Init version when we are running in a version of dart that does
@@ -1724,67 +1742,6 @@
 }
 
 
-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();
 }
@@ -1864,7 +1821,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;
@@ -3669,6 +3626,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.
@@ -3727,6 +3685,7 @@
                                      from_index,
                                      num_type_params,
                                      bound_error,
+                                     bound_trail,
                                      space);
     }
     if (other.IsFunctionClass()) {
@@ -3787,7 +3746,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()) {
@@ -3801,6 +3764,7 @@
                                    other,
                                    other_type_arguments,
                                    bound_error,
+                                   bound_trail,
                                    space)) {
         return true;
       }
@@ -3827,6 +3791,7 @@
                      const Class& other,
                      const TypeArguments& other_type_arguments,
                      Error* bound_error,
+                     TrailPtr bound_trail,
                      Heap::Space space) const {
   return TypeTestNonRecursive(*this,
                               test_kind,
@@ -3834,6 +3799,7 @@
                               other,
                               other_type_arguments,
                               bound_error,
+                              bound_trail,
                               space);
 }
 
@@ -4134,100 +4100,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.
@@ -4306,11 +4178,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;
@@ -4442,6 +4309,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());
@@ -4453,7 +4321,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;
     }
   }
@@ -4461,52 +4333,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.
@@ -4549,6 +4375,7 @@
 
 void TypeArguments::SetTypeAt(intptr_t index,
                                 const AbstractType& value) const {
+  ASSERT(!IsCanonical());
   StorePointer(TypeAddr(index), value.raw());
 }
 
@@ -4726,7 +4553,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() &&
@@ -4749,7 +4577,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);
@@ -4783,7 +4612,7 @@
   // Cache lookup failed. Instantiate the type arguments.
   TypeArguments& result = TypeArguments::Handle();
   result = InstantiateFrom(
-      instantiator_type_arguments, bound_error, NULL, Heap::kOld);
+      instantiator_type_arguments, bound_error, NULL, NULL, Heap::kOld);
   if ((bound_error != NULL) && !bound_error->IsNull()) {
     return result.raw();
   }
@@ -5014,6 +4843,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.
@@ -5074,11 +4908,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());
@@ -5124,6 +4953,9 @@
 
 
 bool Function::HasBreakpoint() const {
+  if (!FLAG_support_debugger) {
+    return false;
+  }
   Thread* thread = Thread::Current();
   return thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone());
 }
@@ -5131,7 +4963,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();
   }
@@ -5784,7 +5616,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()));
 }
 
 
@@ -6127,10 +5960,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()) {
@@ -6139,21 +5974,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;
     }
   }
@@ -6576,7 +6415,9 @@
   while (i < num_fixed_params) {
     param_type = ParameterTypeAt(i);
     ASSERT(!param_type.IsNull());
-    if (instantiate && !param_type.IsInstantiated()) {
+    if (instantiate &&
+        param_type.IsFinalized() &&
+        !param_type.IsInstantiated()) {
       param_type = param_type.InstantiateFrom(instantiator, NULL);
     }
     name = param_type.BuildName(name_visibility);
@@ -6601,7 +6442,9 @@
         pieces->Add(Symbols::ColonSpace());
       }
       param_type = ParameterTypeAt(i);
-      if (instantiate && !param_type.IsInstantiated()) {
+      if (instantiate &&
+          param_type.IsFinalized() &&
+          !param_type.IsInstantiated()) {
         param_type = param_type.InstantiateFrom(instantiator, NULL);
       }
       ASSERT(!param_type.IsNull());
@@ -6699,7 +6542,7 @@
                            &pieces);
   pieces.Add(Symbols::RParenArrow());
   AbstractType& res_type = AbstractType::Handle(zone, result_type());
-  if (instantiate && !res_type.IsInstantiated()) {
+  if (instantiate && res_type.IsFinalized() && !res_type.IsInstantiated()) {
     res_type = res_type.InstantiateFrom(instantiator, NULL);
   }
   name = res_type.BuildName(name_visibility);
@@ -6937,6 +6780,7 @@
   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();
@@ -7062,109 +6906,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());
 }
@@ -7201,11 +6942,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());
@@ -7236,11 +6972,6 @@
 }
 
 
-void RedirectionData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawString* Field::GetterName(const String& field_name) {
   return String::Concat(Symbols::GetterPrefix(), field_name);
 }
@@ -7486,64 +7217,6 @@
 }
 
 
-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).
@@ -7704,7 +7377,8 @@
   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));
@@ -7945,11 +7619,6 @@
 }
 
 
-void LiteralToken::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawGrowableObjectArray* TokenStream::TokenObjects() const {
   return raw_ptr()->token_objects_;
 }
@@ -8144,6 +7813,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.
@@ -8430,23 +8109,6 @@
 }
 
 
-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,
                                 TokenPosition token_pos,
                                 Iterator::StreamType stream_type)
@@ -9005,68 +8667,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.
@@ -9669,7 +9269,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;
@@ -9691,6 +9291,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);
@@ -10231,9 +9876,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();
     }
@@ -10340,6 +9993,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());
@@ -10421,134 +10075,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.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());
@@ -10775,7 +10301,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);
 }
@@ -10843,11 +10371,6 @@
 }
 
 
-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());
 }
@@ -10893,11 +10416,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()) {
@@ -11079,7 +10597,7 @@
 }
 
 
-#if defined(DART_NO_SNAPSHOT)
+#if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
 void Library::CheckFunctionFingerprints() {
   GrowableArray<Library*> all_libs;
   Function& func = Function::Handle();
@@ -11141,7 +10659,7 @@
     FATAL("Fingerprint mismatch.");
   }
 }
-#endif  // defined(DART_NO_SNAPSHOT).
+#endif  // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
 
 
 RawInstructions* Instructions::New(intptr_t size) {
@@ -11169,16 +10687,6 @@
 }
 
 
-void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-}
-
-
 // Encode integer |value| in SLEB128 format and store into |data|.
 static void EncodeSLEB128(GrowableArray<uint8_t>* data,
                           intptr_t value) {
@@ -11276,48 +10784,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);
@@ -11459,34 +10927,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).
@@ -11585,11 +11025,6 @@
 }
 
 
-void CodeSourceMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 const char* CodeSourceMap::ToCString() const {
   // "*" in a printf format specifier tells it to read the field width from
   // the printf argument list.
@@ -11764,11 +11199,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());
@@ -11865,33 +11295,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", 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()));
-  }
-}
-
-
 const char* LocalVarDescriptors::KindToCString(
     RawLocalVarDescriptors::VarInfoKind kind) {
   switch (kind) {
@@ -12121,12 +11524,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;
@@ -12946,86 +12343,6 @@
 }
 
 
-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);
-  }
-}
-
-
 static Token::Kind RecognizeArithmeticOp(const String& name) {
   ASSERT(name.IsSymbol());
   if (name.raw() == Symbols::Plus().raw()) {
@@ -13227,6 +12544,9 @@
 
 
 bool Code::HasBreakpoint() const {
+  if (!FLAG_support_debugger) {
+    return false;
+  }
   return Isolate::Current()->debugger()->HasBreakpoint(*this);
 }
 
@@ -13338,6 +12658,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) {
@@ -13773,106 +13096,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;
@@ -14083,34 +13306,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) {
@@ -14244,11 +13439,6 @@
 }
 
 
-void ContextScope::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawArray* MegamorphicCache::buckets() const {
   return raw_ptr()->buckets_;
 }
@@ -14389,21 +13579,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();
@@ -14475,11 +13650,6 @@
 }
 
 
-void SubtypeTestCache::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 const char* Error::ToErrorCString() const {
   UNREACHABLE();
   return "Internal Error";
@@ -14493,11 +13663,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,
@@ -14538,15 +13703,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,
@@ -14688,15 +13844,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) {
@@ -14777,25 +13924,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();
@@ -14839,17 +13967,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 {
@@ -15202,7 +14319,7 @@
   }
   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);
 }
 
 
@@ -15392,91 +14509,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::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);
-    }
-  }
-}
-
-
 bool AbstractType::IsResolved() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15614,7 +14646,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();
@@ -15674,6 +14707,47 @@
 }
 
 
+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 {
   Zone* zone = Thread::Current()->zone();
   if (IsBoundedType()) {
@@ -15880,6 +14954,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());
@@ -15950,7 +15025,9 @@
     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)) {
       return true;
     }
     return false;  // TODO(regis): We should return "maybe after instantiation".
@@ -16010,6 +15087,7 @@
                            Class::Handle(zone, other.type_class()),
                            TypeArguments::Handle(zone, other.arguments()),
                            bound_error,
+                           bound_trail,
                            space);
 }
 
@@ -16028,11 +15106,6 @@
 }
 
 
-void AbstractType::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  UNREACHABLE();
-}
-
-
 RawType* Type::NullType() {
   return Isolate::Current()->object_store()->null_type();
 }
@@ -16259,7 +15332,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());
@@ -16273,32 +15347,21 @@
   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(), space);
   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 {
@@ -16462,6 +15525,11 @@
       // 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()) {
@@ -16506,6 +15574,11 @@
   // 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
@@ -16564,6 +15637,7 @@
 
 
 void Type::set_arguments(const TypeArguments& value) const {
+  ASSERT(!IsCanonical());
   StorePointer(&raw_ptr()->arguments_, value.raw());
 }
 
@@ -16629,33 +15703,6 @@
 }
 
 
-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(PrettyName());
-  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::SetIsFinalized() const {
   ASSERT(!IsFinalized());
   if (IsInstantiated()) {
@@ -16755,7 +15802,8 @@
 RawAbstractType* FunctionType::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());
@@ -16766,36 +15814,25 @@
   if (arguments() == instantiator_type_arguments.raw()) {
     return raw();
   }
-  // If this type is recursive, we may already be instantiating it.
-  FunctionType& instantiated_type = FunctionType::Handle(zone);
-  instantiated_type ^= OnlyBuddyInTrail(trail);
-  if (!instantiated_type.IsNull()) {
-    ASSERT(IsRecursive());
-    return instantiated_type.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());
-
-  // This uninstantiated type is not modified, as it can be instantiated
-  // with different instantiators. Allocate a new instantiated version of it.
-  instantiated_type =
-      FunctionType::New(cls,
-                        TypeArguments::Handle(zone),
-                        Function::Handle(zone, signature()),
-                        token_pos(),
-                        space);
   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 FunctionType& instantiated_type = FunctionType::Handle(zone,
+      FunctionType::New(cls,
+                        type_arguments,
+                        Function::Handle(zone, signature()),
+                        token_pos(),
+                        space));
   if (IsFinalized()) {
     instantiated_type.SetIsFinalized();
   } else {
@@ -17003,6 +16040,13 @@
   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.
@@ -17100,6 +16144,7 @@
 
 
 void FunctionType::set_arguments(const TypeArguments& value) const {
+  ASSERT(!IsCanonical());
   StorePointer(&raw_ptr()->arguments_, value.raw());
 }
 
@@ -17175,33 +16220,6 @@
 }
 
 
-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(PrettyName());
-  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);
-  }
-}
-
-
 bool TypeRef::IsInstantiated(TrailPtr trail) const {
   if (TestAndAddToTrail(&trail)) {
     return true;
@@ -17227,21 +16245,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();
 }
 
@@ -17253,13 +16278,14 @@
   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();
 }
 
@@ -17296,42 +16322,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(),
@@ -17362,21 +16352,6 @@
 }
 
 
-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::SetIsFinalized() const {
   ASSERT(!IsFinalized());
   set_type_state(RawTypeParameter::kFinalizedUninstantiated);
@@ -17435,7 +16410,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()) {
@@ -17447,6 +16423,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();
 }
 
@@ -17454,12 +16436,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.
@@ -17516,18 +16507,24 @@
 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()));
+  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();
 }
 
@@ -17598,25 +16595,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();
 }
@@ -17701,18 +16679,24 @@
 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()) &&
@@ -17720,34 +16704,49 @@
     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) &&
            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();
 }
 
 
@@ -17829,22 +16828,6 @@
 }
 
 
-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()));
-}
-
-
 TokenPosition MixinAppType::token_pos() const {
   return AbstractType::Handle(MixinTypeAt(0)).token_pos();
 }
@@ -17874,11 +16857,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));
 }
@@ -17920,11 +16898,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());
@@ -17932,15 +16905,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));
@@ -18360,15 +17324,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();
 }
@@ -18486,11 +17441,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);
 }
@@ -18618,15 +17568,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();
 }
@@ -19374,11 +18315,6 @@
 }
 
 
-void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Integer::PrintJSONImpl(stream, ref);
-}
-
-
 // Synchronize with implementation in compiler (intrinsifier).
 class StringHasher : ValueObject {
  public:
@@ -19544,16 +18480,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;
 }
 
 
@@ -20209,44 +19165,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);
-  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 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);
@@ -21136,16 +20054,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.
@@ -21248,37 +20156,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) {
@@ -21496,38 +20373,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:
@@ -21614,45 +20459,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() !=
@@ -21749,15 +20555,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() !=
@@ -21854,15 +20651,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());
@@ -21933,15 +20721,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.
@@ -22030,38 +20809,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);
@@ -22091,39 +20838,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();
   {
@@ -22143,11 +20857,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) {
@@ -22180,11 +20889,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);
 }
@@ -22213,11 +20917,6 @@
 }
 
 
-void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
 const char* Closure::ToCString() const {
   const Function& fun = Function::Handle(function());
   const bool is_implicit_closure = fun.IsImplicitClosureFunction();
@@ -22229,11 +20928,6 @@
 }
 
 
-void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
 RawClosure* Closure::New(const Function& function,
                          const Context& context,
                          Heap::Space space) {
@@ -22341,16 +21035,6 @@
 }
 
 
-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,
@@ -22600,33 +21284,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());
@@ -22642,21 +21299,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();
@@ -22713,21 +21355,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);
@@ -22865,10 +21492,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 a78a0f4..34440a1 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"
@@ -137,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) {              \
@@ -169,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,                             \
@@ -189,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);                                        \
@@ -214,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();                                                       \
@@ -280,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.
@@ -474,6 +493,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_;
@@ -708,8 +732,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.
@@ -811,6 +833,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_;
@@ -884,6 +907,10 @@
 };
 
 
+typedef ZoneGrowableHandlePtrArray<const AbstractType> Trail;
+typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
+
+
 class Class : public Object {
  public:
   intptr_t instance_size() const {
@@ -1105,12 +1132,14 @@
                    const Class& other,
                    const TypeArguments& other_type_arguments,
                    Error* bound_error,
+                   TrailPtr bound_trail = NULL,
                    Heap::Space space = Heap::kNew) const {
     return TypeTest(kIsSubtypeOf,
                     type_arguments,
                     other,
                     other_type_arguments,
                     bound_error,
+                    bound_trail,
                     space);
   }
 
@@ -1119,12 +1148,14 @@
                           const Class& other,
                           const TypeArguments& other_type_arguments,
                           Error* bound_error,
+                          TrailPtr bound_trail = NULL,
                           Heap::Space space = Heap::kNew) const {
     return TypeTest(kIsMoreSpecificThan,
                     type_arguments,
                     other,
                     other_type_arguments,
                     bound_error,
+                    bound_trail,
                     space);
   }
 
@@ -1447,6 +1478,7 @@
                 const Class& other,
                 const TypeArguments& other_type_arguments,
                 Error* bound_error,
+                TrailPtr bound_trail,
                 Heap::Space space) const;
 
   static bool TypeTestNonRecursive(
@@ -1456,6 +1488,7 @@
       const Class& other,
       const TypeArguments& other_type_arguments,
       Error* bound_error,
+      TrailPtr bound_trail,
       Heap::Space space);
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Class, Object);
@@ -1501,9 +1534,6 @@
 };
 
 
-typedef ZoneGrowableHandlePtrArray<const AbstractType> Trail;
-typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
-
 // A TypeArguments is an array of AbstractType.
 class TypeArguments : public Object {
  public:
@@ -1552,8 +1582,10 @@
                    intptr_t from_index,
                    intptr_t len,
                    Error* bound_error,
+                   TrailPtr bound_trail = NULL,
                    Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsSubtypeOf, other, from_index, len, bound_error, space);
+    return TypeTest(kIsSubtypeOf, other, from_index, len,
+                    bound_error, bound_trail, space);
   }
 
   // Check the 'more specific' relationship, considering only a subvector of
@@ -1562,9 +1594,10 @@
                           intptr_t from_index,
                           intptr_t len,
                           Error* bound_error,
+                          TrailPtr bound_trail = NULL,
                           Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsMoreSpecificThan,
-        other, from_index, len, bound_error, space);
+    return TypeTest(kIsMoreSpecificThan, other, from_index, len,
+                    bound_error, bound_trail, space);
   }
 
   // Check if the vectors are equal (they may be null).
@@ -1620,7 +1653,8 @@
   RawTypeArguments* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
 
   // Runtime instantiation with canonicalization. Not to be used during type
@@ -1677,6 +1711,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
@@ -2481,7 +2516,7 @@
                           const Function& other,
                           const TypeArguments& other_type_arguments,
                           Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
+                          Heap::Space space = Heap::kNew) const {
     return TypeTest(kIsMoreSpecificThan,
                     type_arguments,
                     other,
@@ -2542,7 +2577,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.
@@ -2653,11 +2688,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
+  // Uses 'ic_data_array' 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;
+  void RestoreICDataMap(ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
+                        bool clone_descriptors) const;
 
   RawArray* ic_data_array() const;
   void ClearICDataArray() const;
@@ -3435,6 +3469,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;
@@ -3822,6 +3857,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);
@@ -4605,6 +4648,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;
@@ -5107,7 +5151,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 {
@@ -5237,7 +5283,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
 
   // Return a clone of this unfinalized type or the type itself if it is
@@ -5268,6 +5315,17 @@
   // 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);
@@ -5340,15 +5398,18 @@
   // Check the subtype relationship.
   bool IsSubtypeOf(const AbstractType& other,
                    Error* bound_error,
+                   TrailPtr bound_trail = NULL,
                    Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsSubtypeOf, other, bound_error, space);
+    return TypeTest(kIsSubtypeOf, other, bound_error, bound_trail, space);
   }
 
   // Check the 'more specific' relationship.
   bool IsMoreSpecificThan(const AbstractType& other,
                           Error* bound_error,
+                          TrailPtr bound_trail = NULL,
                           Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsMoreSpecificThan, other, bound_error, space);
+    return TypeTest(kIsMoreSpecificThan, other,
+                    bound_error, bound_trail, space);
   }
 
  private:
@@ -5356,6 +5417,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
@@ -5414,7 +5476,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
@@ -5561,7 +5624,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* malformed_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
@@ -5637,7 +5701,8 @@
   virtual RawTypeRef* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
   virtual RawTypeRef* CloneUninstantiated(
       const Class& new_owner,
@@ -5646,17 +5711,6 @@
 
   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));
   }
@@ -5709,6 +5763,7 @@
   bool CheckBound(const AbstractType& bounded_type,
                   const AbstractType& upper_bound,
                   Error* bound_error,
+                  TrailPtr bound_trail = NULL,
                   Heap::Space space = Heap::kNew) const;
   virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
   virtual bool IsInstantiated(TrailPtr trail = NULL) const {
@@ -5719,7 +5774,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
@@ -5804,7 +5860,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
+      TrailPtr instantiation_trail = NULL,
+      TrailPtr bound_trail = NULL,
       Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
@@ -5894,6 +5951,7 @@
 
  private:
   OBJECT_IMPLEMENTATION(Number, Instance);
+
   friend class Class;
 };
 
@@ -6035,7 +6093,7 @@
 
   Smi() : Integer() {}
   BASE_OBJECT_IMPLEMENTATION(Smi, Integer);
-
+  OBJECT_SERVICE_SUPPORT(Smi);
   friend class Api;  // For ValueFromRaw
   friend class Class;
   friend class Object;
@@ -6287,6 +6345,7 @@
     this->SetHash(result);
     return result;
   }
+
   bool HasHash() const {
     ASSERT(Smi::New(0) == NULL);
     return (raw_ptr()->hash_ != NULL);
@@ -6316,9 +6375,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;
@@ -8353,29 +8413,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_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 e2eda2e..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:
@@ -274,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..54bd965
--- /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& 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 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(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;
+    }
+  }
+}
+
+
+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(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 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(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());
+  }
+}
+
+
+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& 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.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& 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);
+      }
+    }
+  }
+}
+
+
+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(PrettyName());
+  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(PrettyName());
+  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(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::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);
+}
+
+
+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()));
+}
+
+
+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 c5a6be6..a3bfae9 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -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()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 2b68902..2cab02b 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -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();
@@ -488,7 +479,7 @@
 
   // 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().
+  // information is stored in Thread::sticky_error().
   bool PreallocateObjects();
 
   void InitKnownObjects();
@@ -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 d681c08..ae009ec 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -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"
@@ -4033,6 +4039,9 @@
 
 
 TEST_CASE(FunctionWithBreakpointNotInlined) {
+  if (!FLAG_support_debugger) {
+    return;
+  }
   const char* kScriptChars =
       "class A {\n"
       "  a() {\n"
@@ -4102,6 +4111,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 class ObjectAccumulator : public ObjectVisitor {
  public:
   explicit ObjectAccumulator(GrowableArray<Object*>* objects)
@@ -4430,6 +4442,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(InstanceEquality) {
   // Test that Instance::OperatorEquals can call a user-defined operator==.
   const char* kScript =
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/pages.cc b/runtime/vm/pages.cc
index 6ea473a..caea245 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -346,8 +346,8 @@
     // Start of the newly allocated page is the allocated object.
     result = page->object_start();
     // Note: usage_.capacity_in_words is increased by AllocatePage.
-    AtomicOperations::FetchAndIncrementBy(&(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;
@@ -384,8 +384,8 @@
       result = TryAllocateInFreshPage(size, type, growth_policy, is_locked);
       // usage_ is updated by the call above.
     } else {
-      AtomicOperations::FetchAndIncrementBy(&(usage_.used_in_words),
-                                            (size >> kWordSizeLog2));
+      AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                    (size >> kWordSizeLog2));
     }
   } else {
     // Large page allocation.
@@ -404,8 +404,8 @@
       if (page != NULL) {
         result = page->object_start();
         // Note: usage_.capacity_in_words is increased by AllocateLargePage.
-        AtomicOperations::FetchAndIncrementBy(&(usage_.used_in_words),
-                                              (size >> kWordSizeLog2));
+        AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                      (size >> kWordSizeLog2));
       }
     }
   }
@@ -434,16 +434,14 @@
 
 void PageSpace::AllocateExternal(intptr_t size) {
   intptr_t size_in_words = size >> kWordSizeLog2;
-  AtomicOperations::FetchAndIncrementBy(&(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;
-  AtomicOperations::FetchAndDecrementBy(&(usage_.external_in_words),
-                                        size_in_words);
+  AtomicOperations::DecrementBy(&(usage_.external_in_words), size_in_words);
 }
 
 
@@ -675,6 +673,9 @@
 
 
 void PageSpace::PrintToJSONObject(JSONObject* object) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   JSONObject space(object, "old");
@@ -715,6 +716,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",
@@ -1009,8 +1013,8 @@
   ASSERT(remaining >= size);
   uword result = bump_top_;
   bump_top_ += size;
-  AtomicOperations::FetchAndIncrementBy(&(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_) {
@@ -1040,8 +1044,8 @@
   FreeList* freelist = &freelist_[HeapPage::kData];
   uword result = freelist->TryAllocateSmallLocked(size);
   if (result != 0) {
-    AtomicOperations::FetchAndIncrementBy(&(usage_.used_in_words),
-                                          (size >> kWordSizeLog2));
+    AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                  (size >> kWordSizeLog2));
     return result;
   }
   result = TryAllocateDataBumpLocked(size, growth_policy);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index bed681e..2449f9d 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -490,6 +490,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");
@@ -497,6 +498,7 @@
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "script", String::Handle(script.url()).ToCString());
   }
+#endif
 
   Parser parser(script, library, TokenPosition::kMinSource);
   parser.ParseTopLevel();
@@ -854,6 +856,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");
@@ -861,6 +864,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);
@@ -919,10 +923,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();
@@ -953,7 +956,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;
   }
@@ -970,18 +973,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:
@@ -1101,12 +1108,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();
@@ -13223,7 +13229,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();
@@ -13387,7 +13397,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(
@@ -13427,7 +13438,7 @@
         return ThrowTypeError(redirect_type.token_pos(), redirect_type);
       }
       if (I->flags().type_checks() &&
-              !redirect_type.IsSubtypeOf(type, NULL, Heap::kOld)) {
+              !redirect_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
         // Additional type checking of the result is necessary.
         type_bound = type.raw();
       }
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index a5e6f2e..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;
 
@@ -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..6af2ff8 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -305,6 +305,9 @@
 
 void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
                                           JSONStream* stream) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", "_Ports");
   Object& msg_handler = Object::Handle();
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index f5098bb..30fb890 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,17 +4,41 @@
 
 #include "vm/precompiler.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_optimizer.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 {
 
@@ -29,6 +53,57 @@
     " 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, precompilation);
+DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
+DECLARE_FLAG(bool, load_deferred_eagerly);
+DECLARE_FLAG(bool, trace_failed_optimization_attempts);
+DECLARE_FLAG(bool, trace_inlining_intervals);
+DECLARE_FLAG(bool, trace_irregexp);
+
+#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 +120,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();
   }
 }
@@ -69,6 +144,7 @@
         GrowableObjectArray::Handle(GrowableObjectArray::New())),
     sent_selectors_(),
     enqueued_functions_(),
+    fields_to_retain_(),
     error_(Error::Handle()) {
 }
 
@@ -118,7 +194,7 @@
 
     I->set_compilation_allowed(false);
 
-    DropUncompiledFunctions();
+    DropFunctions();
     DropFields();
 
     // TODO(rmacnak): DropEmptyClasses();
@@ -128,6 +204,11 @@
     DedupStackmaps();
     DedupStackmapLists();
 
+    if (FLAG_dedup_instructions) {
+      // Reduces binary size but obfuscates profiler results.
+      DedupInstructions();
+    }
+
     I->object_store()->set_compile_time_constants(Array::null_array());
     I->object_store()->set_unique_dynamic_targets(Array::null_array());
 
@@ -311,24 +392,30 @@
 
     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);
-      field = lib.LookupFieldAllowPrivate(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());
@@ -337,12 +424,13 @@
     }
 
     if (func.IsNull() && field.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);
-      }
+      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()) {
@@ -394,7 +482,7 @@
     ASSERT(!function.is_abstract());
     ASSERT(!function.IsRedirectingFactory());
 
-    error_ = Compiler::CompileFunction(thread_, function);
+    error_ = CompileFunction(thread_, function);
     if (!error_.IsNull()) {
       Jump(error_);
     }
@@ -578,7 +666,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 =
@@ -589,6 +681,127 @@
 }
 
 
+RawFunction* Precompiler::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 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;
 
@@ -897,7 +1110,7 @@
 }
 
 
-void Precompiler::DropUncompiledFunctions() {
+void Precompiler::DropFunctions() {
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
   Array& functions = Array::Handle(Z);
@@ -905,6 +1118,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);
@@ -932,6 +1146,15 @@
           retained_functions.Add(function);
           function.DropUncompiledImplicitClosureFunction();
         } 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",
@@ -973,6 +1196,7 @@
   Array& fields = Array::Handle(Z);
   Field& field = Field::Handle(Z);
   GrowableObjectArray& retained_fields = GrowableObjectArray::Handle(Z);
+  String& name = String::Handle(Z);
 
   for (intptr_t i = 0; i < libraries_.Length(); i++) {
     lib ^= libraries_.At(i);
@@ -987,15 +1211,21 @@
       retained_fields = GrowableObjectArray::New();
       for (intptr_t j = 0; j < fields.Length(); j++) {
         field ^= fields.At(j);
-        bool drop = fields_to_retain_.Lookup(&field) == NULL;
-        if (drop) {
+        bool retain = fields_to_retain_.Lookup(&field) != NULL;
+        if (retain) {
+          retained_fields.Add(field);
+        } 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());
           }
-        } else {
-          retained_fields.Add(field);
         }
       }
 
@@ -1170,6 +1400,52 @@
 }
 
 
+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);
@@ -1252,6 +1528,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();
@@ -1272,4 +1549,691 @@
   }
 }
 
+
+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_precompilation);
+  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;
+      // 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);
+        // 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);
+        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,
+                                   &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 (optimizer.Canonicalize()) {
+          // Invoke Canonicalize twice in order to fully canonicalize patterns
+          // like "if (a & const == 0) { }".
+          optimizer.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.
+          optimizer.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.
+          optimizer.WidenSmiToInt32();
+
+          // Unbox doubles. Performed after constant propagation to minimize
+          // interference from phis merging double values and tagged
+          // values coming from dead paths.
+          optimizer.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());
+              optimizer.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();
+              }
+              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.
+          optimizer.InferIntRanges();
+          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.
+        optimizer.EliminateEnvironments();
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "EliminateDeadPhis");
+#endif  // !PRODUCT
+          DeadCodeElimination::EliminateDeadPhis(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        if (optimizer.Canonicalize()) {
+          optimizer.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.
+          optimizer.SelectRepresentations();
+        }
+
+        if (optimizer.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();
+        }
+        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,
+                                       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_precompilation);
+  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_precompilation);
+  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 da267c0..c32a955 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -18,6 +18,7 @@
 class Function;
 class GrowableObjectArray;
 class RawError;
+class SequenceNode;
 class String;
 
 class SymbolKeyValueTrait {
@@ -96,6 +97,29 @@
 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.
@@ -158,9 +182,17 @@
                                      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[]);
@@ -179,14 +211,16 @@
   void ProcessFunction(const Function& function);
   void CheckForNewDynamicFunctions();
 
-  void DropUncompiledFunctions();
+  void DropFunctions();
   void DropFields();
-  void CollectDynamicFunctionNames();
   void BindStaticCalls();
   void DedupStackmaps();
   void DedupStackmapLists();
+  void DedupInstructions();
   void ResetPrecompilerState();
 
+  void CollectDynamicFunctionNames();
+
   class FunctionVisitor : public ValueObject {
    public:
     virtual ~FunctionVisitor() {}
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_service.cc b/runtime/vm/profiler_service.cc
index 17a8a73..8152884 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)
@@ -2407,4 +2409,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 4c30971..55149b2 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -13,6 +13,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, background_compilation);
 DECLARE_FLAG(bool, profile_vm);
 DECLARE_FLAG(int, max_profile_depth);
@@ -1657,5 +1659,6 @@
   }
 }
 
-}  // namespace dart
+#endif  // !PRODUCT
 
+}  // namespace dart
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f4b07eb..c7c44a2 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -637,6 +637,7 @@
   friend class Instance;  // StorePointer
   friend class StackFrame;  // GetCodeObject assertion.
   friend class CodeLookupTableBuilder;  // profiler
+  friend class NativeEntry;  // GetClassId
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
diff --git a/runtime/vm/redundancy_elimination.cc b/runtime/vm/redundancy_elimination.cc
new file mode 100644
index 0000000..effe15e
--- /dev/null
+++ b/runtime/vm/redundancy_elimination.cc
@@ -0,0 +1,3471 @@
+// 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.");
+
+DECLARE_FLAG(bool, fields_may_be_reset);
+DECLARE_FLAG(bool, precompilation);
+DECLARE_FLAG(bool, trace_optimization);
+
+// 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().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);
+  }
+
+  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_precompilation) {
+    // 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) {
+  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);
+  }
+}
+
+
+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_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index 367e65fd..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 TokenPosition kNoSourcePos = TokenPosition::kNoSource;
 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, kNoSourcePos);
+  return new(Z) LoadLocalInstr(*local, TokenPosition::kNoSource);
 }
 
 
 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local,
                                         Value* value) {
-  Do(new(Z) StoreLocalInstr(*local, value, kNoSourcePos));
+  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, kNoSourcePos));
+  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_,
-      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 196b471..42a47d9 100644
--- a/runtime/vm/report.cc
+++ b/runtime/vm/report.cc
@@ -249,6 +249,9 @@
 void Report::TraceJSWarning(const Script& script,
                             TokenPosition token_pos,
                             const String& message) {
+  if (!FLAG_support_service) {
+    return;
+  }
   const int64_t micros = OS::GetCurrentTimeMicros();
   Isolate* isolate = Isolate::Current();
   TraceBuffer* trace_buffer = isolate->trace_buffer();
diff --git a/runtime/vm/report_test.cc b/runtime/vm/report_test.cc
index 08fbe70..d939dd2 100644
--- a/runtime/vm/report_test.cc
+++ b/runtime/vm/report_test.cc
@@ -8,6 +8,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 TEST_CASE(TraceJSWarning) {
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
@@ -77,4 +79,6 @@
   delete trace_buffer;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
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/scavenger.cc b/runtime/vm/scavenger.cc
index 5dc0aae..bcbb79f 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -546,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.
@@ -834,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/service.cc b/runtime/vm/service.cc
index 24c1598..cdfdd288 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -51,6 +51,7 @@
             "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;
 
@@ -2958,14 +2959,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);
@@ -2973,8 +2974,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;
@@ -2992,7 +2994,7 @@
         return true;
       }
     }
-    isolate->Resume();
+    isolate->SetResumeRequest();
     PrintSuccess(js);
     return true;
   }
@@ -3572,7 +3574,7 @@
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "Version");
   jsobj.AddProperty("major", static_cast<intptr_t>(3));
-  jsobj.AddProperty("minor", static_cast<intptr_t>(1));
+  jsobj.AddProperty("minor", static_cast<intptr_t>(2));
   jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
   jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
   return true;
@@ -3957,5 +3959,6 @@
   return NULL;
 }
 
+#endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index bba5252..2103acd 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.1
+# Dart VM Service Protocol 3.2
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 3.1_ of the Dart VM Service Protocol. This
+This document describes of _version 3.2_ 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.
@@ -1881,6 +1881,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;
 
@@ -2471,6 +2474,7 @@
 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.
 
 
 [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..314d635 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) {
@@ -271,4 +273,6 @@
   jsobj->AddPropertyTimeMillis("timestamp", timestamp_);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index dcfc541..d80364e 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -302,8 +302,10 @@
  public:
   virtual void Run() {
     ASSERT(Isolate::Current() == NULL);
+#ifndef PRODUCT
     TimelineDurationScope tds(Timeline::GetVMStream(),
                               "ServiceIsolateStartup");
+#endif  // !PRODUCT
     char* error = NULL;
     Isolate* isolate = NULL;
 
@@ -367,7 +369,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());
       }
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index dd2c004..de6cf73 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) {}
@@ -644,4 +646,6 @@
 
 #endif  // !defined(TARGET_ARCH_ARM64)
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index a1c1d5c..bbeef36 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -234,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();
   }
 }
@@ -2488,7 +2488,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_test.cc b/runtime/vm/snapshot_test.cc
index 2b3df5e..210e43f 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1031,10 +1031,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__;
@@ -1051,7 +1047,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
@@ -1291,6 +1286,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 UNIT_TEST_CASE(ScriptSnapshot) {
   const char* kLibScriptChars =
       "library dart_import_lib;"
@@ -1347,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__;
@@ -1367,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.
   {
@@ -1476,6 +1469,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 UNIT_TEST_CASE(ScriptSnapshot1) {
   const char* kScriptChars =
     "class _SimpleNumEnumerable<T extends num> {"
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 6290b6e..3b9398f 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -111,14 +111,14 @@
 
 
 void SourceReport::PrintCallSitesData(JSONObject* jsobj,
-                                      const Function& func,
+                                      const Function& function,
                                       const Code& code) {
-  const TokenPosition begin_pos = func.token_pos();
-  const TokenPosition 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 descriptors */);
   const PcDescriptors& descriptors = PcDescriptors::Handle(
       zone(), code.pc_descriptors());
 
@@ -143,14 +143,14 @@
 }
 
 void SourceReport::PrintCoverageData(JSONObject* jsobj,
-                                     const Function& func,
+                                     const Function& function,
                                      const Code& code) {
-  const TokenPosition begin_pos = func.token_pos();
-  const TokenPosition 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 descriptors */);
   const PcDescriptors& descriptors = PcDescriptors::Handle(
       zone(), code.pc_descriptors());
 
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
index b213a20..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);
@@ -503,4 +505,6 @@
       buffer);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index d4be5b5..d06b125 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -123,11 +123,13 @@
     stub ^= Code::FinalizeCode(name, &assembler, false /* optimized */);
     stub.set_owner(cls);
     cls.set_allocation_stub(stub);
-    if (FLAG_disassemble_stubs) {
+    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 +161,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 4cf291b..82fc0fb 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -27,7 +27,6 @@
     "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:
@@ -1455,9 +1454,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) {
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 5db34dc..6cbbd7a 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1520,9 +1520,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) {
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index e1e3fff..270e0f6 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -28,7 +28,6 @@
     "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))
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index bd6567d..ff81507 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -26,7 +26,6 @@
     "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:
@@ -1556,9 +1555,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;
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 024fbfa..3f44fc0 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -27,7 +27,6 @@
     "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:
@@ -1455,9 +1454,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) {
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index bee034f..f6735c2 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);
 }
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 adfc4b4..0fa2d40 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -62,6 +62,7 @@
       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),
@@ -175,6 +176,27 @@
 }
 
 
+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;
   Thread* thread = isolate->ScheduleThread(kIsMutatorThread);
@@ -332,11 +354,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_;
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index c5a0c8f..2d8531c 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -40,6 +40,7 @@
 class RawBool;
 class RawObject;
 class RawCode;
+class RawError;
 class RawGrowableObjectArray;
 class RawString;
 class RuntimeEntry;
@@ -365,6 +366,11 @@
   }
 
   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)                                \
@@ -548,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;
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/timeline.cc b/runtime/vm/timeline.cc
index ca6e9a2..8fb0768 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");
@@ -420,6 +422,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.
@@ -665,6 +670,9 @@
 TimelineDurationScope::TimelineDurationScope(TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   timestamp_ = OS::GetCurrentMonotonicMicros();
 }
 
@@ -673,11 +681,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;
   }
@@ -697,6 +711,9 @@
 TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   EmitBegin();
 }
 
@@ -705,16 +722,25 @@
                                              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;
   }
@@ -732,6 +758,9 @@
 
 
 void TimelineBeginEndScope::EmitEnd() {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   if (!ShouldEmitEvent()) {
     return;
   }
@@ -778,6 +807,9 @@
 
 
 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   OSThreadIterator it;
   while (it.HasNext()) {
     OSThread* thread = it.Next();
@@ -871,6 +903,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();
@@ -968,6 +1003,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) {
@@ -994,6 +1032,9 @@
 
 void TimelineEventRingRecorder::PrintJSON(JSONStream* js,
                                           TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1006,6 +1047,9 @@
 
 void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js,
                                                 TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
   PrintJSONEvents(&events, filter);
 }
@@ -1079,6 +1123,9 @@
 
 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js,
                                                TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1091,6 +1138,9 @@
 void TimelineEventStreamingRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
 }
 
@@ -1115,6 +1165,9 @@
 
 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js,
                                              TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1128,6 +1181,9 @@
 void TimelineEventEndlessRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
   PrintJSONEvents(&events, filter);
 }
@@ -1171,6 +1227,9 @@
 void TimelineEventEndlessRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   MutexLocker ml(&lock_);
   // Collect all interesting blocks.
   MallocGrowableArray<TimelineEventBlock*> blocks(8);
@@ -1347,4 +1406,6 @@
   return r;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index a229acf..cf77396 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -344,6 +344,7 @@
   const bool* globally_enabled_;
 };
 
+#ifndef PRODUCT
 #define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, suffix, function)       \
   TimelineDurationScope tds(thread,                                            \
                             thread->isolate()->GetCompilerStream(),            \
@@ -355,7 +356,10 @@
         "function",                                                            \
         function.ToLibNamePrefixedQualifiedCString());                         \
   }
-
+#else
+#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, suffix, function)       \
+  do { } while (false);
+#endif  // !PRODUCT
 
 // See |TimelineDurationScope| and |TimelineBeginEndScope|.
 class TimelineEventScope : public StackResource {
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..05c4abb 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)
@@ -854,4 +856,6 @@
   TimelineTestHelper::Clear(recorder);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/trace_buffer_test.cc b/runtime/vm/trace_buffer_test.cc
index f85941f..1ac6452 100644
--- a/runtime/vm/trace_buffer_test.cc
+++ b/runtime/vm/trace_buffer_test.cc
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 TEST_CASE(TraceBufferEmpty) {
   Isolate* isolate = Isolate::Current();
   TraceBuffer::Init(isolate, 3);
@@ -103,4 +105,6 @@
   delete trace_buffer;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 05d8d3f..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);
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 8e6267e..defaea6 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -306,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/vm.gypi b/runtime/vm/vm.gypi
index c686463..a733877 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -159,6 +159,69 @@
         }]],
     },
     {
+      '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': {
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
+            ],
+          },
+        }],
+        ['OS=="android" and _toolset=="host"', {
+          'link_settings': {
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
+            ],
+          },
+        }],
+        ['OS=="win"', {
+          'sources/' : [
+            ['exclude', 'gdbjit.cc'],
+          ],
+       }],
+       ['dart_vtune_support==0', {
+          'sources/' : [
+            ['exclude', 'vtune\\.(cc|h)$'],
+          ],
+       }],
+       ['dart_vtune_support==1', {
+          'include_dirs': ['<(dart_vtune_root)/include'],
+          'defines': ['DART_VTUNE_SUPPORT'],
+          'link_settings': {
+            'conditions': [
+              ['OS=="linux"', {
+                 'libraries': ['-ljitprofiling'],
+              }],
+              ['OS=="win"', {
+                 'libraries': ['-ljitprofiling.lib'],
+              }],
+            ],
+          },
+        }]],
+    },
+    {
       'target_name': 'libdart_vm_nosnapshot',
       'type': 'static_library',
       'toolsets':['host', 'target'],
@@ -176,6 +239,7 @@
       ],
       'defines': [
         'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
       ],
       'conditions': [
         ['OS=="linux"', {
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 7570631..30df00d 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -63,6 +63,8 @@
     'bootstrap.h',
     'bootstrap_natives.cc',
     'bootstrap_natives.h',
+    'branch_optimizer.cc',
+    'branch_optimizer.h',
     'cha.cc',
     'cha.h',
     'cha_test.cc',
@@ -165,6 +167,7 @@
     'exceptions.h',
     'exceptions_test.cc',
     'find_code_object_test.cc',
+    'flag_list.h',
     'flags.cc',
     'flags.h',
     'flags_test.cc',
@@ -306,6 +309,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',
@@ -351,6 +355,8 @@
     'raw_object.cc',
     'raw_object.h',
     'raw_object_snapshot.cc',
+    'redundancy_elimination.cc',
+    'redundancy_elimination.h',
     'regexp.cc',
     'regexp.h',
     'regexp_assembler.cc',
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 53a1d40..0c5cca2 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -102,11 +102,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..f1398d9 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -24,5 +24,5 @@
 [ $arch == simarm64 ]
 *: Skip
 
-[ $runtime == dart_precompiled ]
+[ $noopt || $runtime == dart_precompiled ]
 sample_extension: RuntimeError # Platform.executable
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 709a73d..9fd0ca1 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -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 510cccb..5dae802 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -1378,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();
 
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/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/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/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/io/http.dart b/sdk/lib/io/http.dart
index 406af67..cfdcc10 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -100,7 +100,7 @@
  *     import 'dart:io';
  *     import "dart:isolate";
  *
- *     main() async {
+ *     main() {
  *       SecurityContext context = new SecurityContext();
  *       var chain =
  *           Platform.script.resolve('certificates/server_chain.pem')
@@ -108,8 +108,8 @@
  *       var key =
  *           Platform.script.resolve('certificates/server_key.pem')
  *           .toFilePath();
- *       await context.useCertificateChain(chain);
- *       await context.usePrivateKey(key, password: 'dartdart');
+ *       context.useCertificateChainSync(chain);
+ *       context.usePrivateKeySync(key, password: 'dartdart');
  *
  *       HttpServer
  *           .bindSecure(InternetAddress.ANY_IP_V6,
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index 4675b60..28351b2 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -18,6 +18,14 @@
  * "-----BEGIN CERTIFICATE -----" and "-----END CERTIFICATE-----".
  * Distinguished encoding rules (DER) is a canonical binary serialization
  * of ASN1 objects into an octet string.
+ *
+ * [usePrivateKey], [setTrustedCertificates], [useCertificateChain], and
+ * [setClientAuthorities] are deprecated. They have been renamed
+ * [usePrivateKeySync], [setTrustedCertificatesSync], [useCertificateChainSync],
+ * and [setClientAuthoritiesSync] to reflect the fact that they do blocking
+ * IO. Async-friendly versions have been added in [usePrivateKeyBytes],
+ * [setTrustedCertificatesBytes], [useCertificateChainBytes], and
+ * [setClientAuthoritiesBytes].
  */
 abstract class SecurityContext {
   external factory SecurityContext();
@@ -41,11 +49,15 @@
    * [keyFile] is a PEM file containing an encrypted
    * private key, encrypted with [password].  An unencrypted file can be
    * used, but this is not usual.
-   *
-   * The function returns a [Future] that completes when the key has been added
-   * to the context.
    */
-  Future usePrivateKey(String keyFile, {String password});
+  void usePrivateKeySync(String keyFile, {String password});
+
+  /**
+   * [usePrivateKey] is deprecated. Use [usePrivateKeySync] or
+   * [usePrivateKeyBytes].
+   */
+  @deprecated
+  void usePrivateKey(String keyFile, {String password});
 
   /**
    * Sets the private key for a server certificate or client certificate.
@@ -62,20 +74,26 @@
    * 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 an optional PEM file containing X509 certificates, usually
+   * [file] is the path to a 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.
    */
-  void setTrustedCertificates({String file, String directory});
+  void setTrustedCertificatesSync(String file);
+
+  /**
+   * [setTrustedCertificates] is deprecated. Use [setTrustedCertificatesSync]
+   * or [setTrustedCertificatesBytes].
+   */
+  @deprecated
+  void setTrustedCertificates(String file);
+
+  /**
+   * Sets the set of trusted X509 certificates used by [SecureSocket]
+   * client connections, when connecting to a secure server.
+   *
+   * [file] is the contents of a PEM file containing X509 certificates, usually
+   * root certificates from certificate authorities.
+   */
+  void setTrustedCertificatesBytes(List<int> certBytes);
 
   /**
    * Sets the chain of X509 certificates served by [SecureServer]
@@ -85,11 +103,15 @@
    * 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 function returns a [Future] that completes when the certificate chain
-   * has been set.
    */
-  Future useCertificateChain(String file);
+  void useCertificateChainSync(String file);
+
+  /**
+   * [useCertificateChain] is deprecated. Use [useCertificateChainSync]
+   * or [useCertificateChainBytes].
+   */
+  @deprecated
+  void useCertificateChain({String file, String directory});
 
   /**
    * Sets the chain of X509 certificates served by [SecureServer]
@@ -109,9 +131,25 @@
    * client.  [file] is a PEM file containing the accepted signing authority
    * certificates - the authority names are extracted from the certificates.
    */
+  void setClientAuthoritiesSync(String file);
+
+  /**
+   * [setClientAuthorities] is deprecated. Use [setClientAuthoritiesSync]
+   * or [setClientAuthoritiesBytes].
+   */
+  @deprecated
   void setClientAuthorities(String file);
 
   /**
+   * Sets the list of authority names that a [SecureServer] will advertise
+   * as accepted, when requesting a client certificate from a connecting
+   * client.  [authCertBytes] is the contents of a PEM file containing the
+   * accepted signing authority certificates - the authority names are extracted
+   * from the certificates.
+   */
+  void setClientAuthoritiesBytes(List<int> authCertBytes);
+
+  /**
    * Sets the list of application-level protocols supported by a client
    * connection or server connection. The ALPN (application level protocol
    * negotiation) extension to TLS allows a client to send a list of
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index c9f507c..7a3b561 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -1949,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
@@ -2988,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
@@ -3167,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
 
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 061649b..502bd58 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -112,18 +112,12 @@
 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/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/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/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/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/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/oes-element-index-uint_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/canvas/webgl/premultiplyalpha-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/webgl/renderbuffer-initialization_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
@@ -1207,34 +1201,88 @@
 
 [ $compiler == none && $runtime == dartium ]
 LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # co19-roll r761: Please triage this failure.
+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 ]
+LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/canvas-2d-webgl-texture_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
+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/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/gl-bind-attrib-location-test_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/gl-pixelstorei_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/object-deletion-behaviour_t01: RuntimeError # Please triage this failure
+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/read-pixels-pack-alignment_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # Issue 25653
+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 # Please triage this failure
+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 # Please triage this failure
+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 # Please triage this failure
+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 # Please triage this failure
+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 # Please triage this failure
+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 # Please triage this failure
+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-rgba4444_t01: RuntimeError # Please triage this failure
+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_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-webgl_t01: RuntimeError # Issue 25653
+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 # 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/webgl-large-texture_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/webgl-texture-binding-preserved_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # Please triage this failure
+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-depth-texture_t01: RuntimeError # Please triage this failure
+
+[ $compiler == none && $runtime == dartium && $system != macos ]
 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/draw-webgl-to-canvas-2d_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
@@ -1251,11 +1299,7 @@
 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
@@ -1272,38 +1316,29 @@
 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
+LayoutTests/fast/canvas/webgl/gl-object-get-calls_t01: RuntimeError #  Issue 20, 22026
+LayoutTests/fast/canvas/webgl/incorrect-context-object-behaviour_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/tex-sub-image-2d-bad-args_t01: RuntimeError # Issue 20, 22026
 
 [ $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/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 2c4e7c7..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,9 +10,12 @@
 // }
 
 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));
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/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/operators2_3.js b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
index bf578b2..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 : 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 9faff59..403b831 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
@@ -1,6 +1,9 @@
 // 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.toString());
 //   print(foo(5));
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 ccfc0a8..837c082 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
@@ -13,10 +13,8 @@
         line = "true";
         break L0;
       }
-      v0 = false;
-    } else
-      v0 = false;
-    line = v0 ? String(v0) : "false";
+    }
+    line = "false";
   }
   if (typeof dartPrint == "function")
     dartPrint(line);
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/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 225701b..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,8 @@
 // Method to test: function(foo)
-foo(a) => a ~/ 13;
+import 'package:expect/expect.dart';
+
+@NoInline() foo(a) => a ~/ 13;
+
 main() {
   print(foo.toString());
   print(foo(5));
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/update_all.dart b/tests/compiler/dart2js/cps_ir/update_all.dart
index 5874a25..59c0bc3 100644
--- a/tests/compiler/dart2js/cps_ir/update_all.dart
+++ b/tests/compiler/dart2js/cps_ir/update_all.dart
@@ -96,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);
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 3d0330e..d3f5ad8 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -50,6 +50,7 @@
 # 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_invokes_test: Fail # 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/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index a886f42..5ba3ec6 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -7,19 +7,13 @@
 import "package:async_helper/async_helper.dart";
 import 'package:compiler/src/diagnostics/messages.dart' show
     MessageKind,
-    MessageTemplate,
-    SharedMessageKind;
+    MessageTemplate;
 
 import 'message_kind_helper.dart';
 
 main(List<String> arguments) {
   List<MessageTemplate> examples = <MessageTemplate>[];
-  List allMessageKinds = []
-      ..addAll(MessageKind.values)
-      ..addAll(SharedMessageKind.values);
-  for (var kind in allMessageKinds) {
-    if (kind == SharedMessageKind.exampleMessage) continue;
-
+  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/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/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
index b689360..c58a21e 100644
--- a/tests/compiler/dart2js/sourcemaps/diff_view.dart
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -1,40 +1,61 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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';
-import 'js_tracer.dart';
 
-const String WITH_SOURCE_INFO_STYLE = 'background-color:#FF8080;';
-const String WITHOUT_SOURCE_INFO_STYLE = 'border: solid 1px #FF8080;';
-const String ADDITIONAL_SOURCE_INFO_STYLE = 'border: solid 1px #8080FF;';
+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>> options = [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 = [];
-      options.add(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=')) {
@@ -45,54 +66,184 @@
       filename = arg;
     }
   }
-  List<String> commonArguments = options[0];
-  List<String> options1;
-  List<String> options2;
-  if (options.length == 1) {
+  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.
-    options1 = [USE_NEW_SOURCE_INFO]..addAll(commonArguments);
-    options2 = [USE_NEW_SOURCE_INFO, Flags.useCpsIr]..addAll(commonArguments);
-  } else if (options.length == 2) {
+    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.
-    options1 = commonArguments;
-    options2 = options[1]..addAll(commonArguments);
+    options.add(commonArguments);
+    options.add(optionSegments[1]..addAll(commonArguments));
   } else {
     // Use specific options for both output columns.
-    options1 = options[1]..addAll(commonArguments);
-    options2 = options[2]..addAll(commonArguments);
+    options.add(optionSegments[1]..addAll(commonArguments));
+    options.add(optionSegments[2]..addAll(commonArguments));
   }
 
-  print('Compiling ${options1.join(' ')} $filename');
-  CodeLinesResult result1 = await computeCodeLines(
-      options1, filename, addAnnotations: addAnnotations);
-  print('Compiling ${options2.join(' ')} $filename');
-  CodeLinesResult result2 = await computeCodeLines(
-      options2, filename, addAnnotations: addAnnotations);
+  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 $filename</title>
+<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: 50%;
-  background-color: #400000;
-  color: #FFFFFF;
-  height: 20px;
+  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-x:auto;
-  vertical-align:top;
+  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;
@@ -106,14 +257,29 @@
 .identical2 {
   background-color: #C0E0C0;
 }
+.line {
+  padding-left: 7em;
+  text-indent: -7em;
+  margin: 0px;
+}
+.column0 {
+}
+.column1 {
+}
+.column2 {
+}
 </style>
 </head>
 <body>''');
 
   sb.write('''
-<div class="header" style="left: 0px;">[${options1.join(',')}]</div>
-<div class="header" style="right: 0px;">[${options2.join(',')}]</div>
-<div style="position:absolute;left:0px;top:22px;width:100%;height:18px;">
+<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
@@ -121,19 +287,36 @@
   <span class="corresponding2">&nbsp;&nbsp;&nbsp;</span> 
   corresponding blocks
 ''');
+
   if (addAnnotations) {
     sb.write('''
   <span style="$WITH_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span>
-  offset with source information
+  <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>
-  offset without source information
+  <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>
-  offset with unneeded source information
+  <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>
-<table style="position:absolute;left:0px;top:40px;width:100%;"><tr>
+</div></div>
+<table class="table">
 ''');
 
   void addCell(String content) {
@@ -146,225 +329,60 @@
 ''');
   }
 
-  List<OutputStructure> structures = [
-      OutputStructure.parse(result1.codeLines),
-      OutputStructure.parse(result2.codeLines)];
-  List<List<CodeLine>> inputLines = [result1.codeLines, result2.codeLines];
-  List<List<HtmlPart>> outputLines = [<HtmlPart>[], <HtmlPart>[]];
-
   /// Marker to alternate output colors.
   bool alternating = false;
 
-  /// Enable 'corresponding' background colors for [f].
-  void withMatching(f()) {
-    HtmlPart start = new ConstHtmlPart(
-        '<div class="corresponding${alternating ? '1' : '2'}">');
-    HtmlPart end = new ConstHtmlPart('</div>');
-    alternating = !alternating;
-    outputLines[0].add(start);
-    outputLines[1].add(start);
-    f();
-    outputLines[0].add(end);
-    outputLines[1].add(end);
-  }
-
-  /// Enable 'identical' background colors for [f].
-  void withIdentical(f()) {
-    HtmlPart start = new ConstHtmlPart(
-        '<div class="identical${alternating ? '1' : '2'}">');
-    HtmlPart end = new ConstHtmlPart('</div>');
-    alternating = !alternating;
-    outputLines[0].add(start);
-    outputLines[1].add(start);
-    f();
-    outputLines[0].add(end);
-    outputLines[1].add(end);
-  }
-
-  /// Output code lines in [range] from input number [index], padding the other
-  /// column with empty lines.
-  void handleSkew(int index, Interval range) {
-    int from = range.from;
-    while (from < range.to) {
-      outputLines[1 - index].add(const ConstHtmlPart('\n'));
-      outputLines[index].add(
-          new CodeLineHtmlPart(inputLines[index][from++]));
+  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));
   }
 
-  /// Output code lines of the [indices] from the corresponding inputs.
-  void addBoth(List<int> indices) {
-    outputLines[0].add(new CodeLineHtmlPart(inputLines[0][indices[0]]));
-    outputLines[1].add(new CodeLineHtmlPart(inputLines[1][indices[1]]));
-  }
-
-  /// Output code lines of the [ranges] from the corresponding inputs.
-  void addBothLines(List<Interval> ranges) {
-    Interval range1 = ranges[0];
-    Interval range2 = ranges[1];
-    int offset = 0;
-    while (range1.from + offset < range1.to &&
-           range2.from + offset < range2.to) {
-      addBoth([range1.from + offset, range2.from + offset]);
-      offset++;
+  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;
     }
-    if (range1.from + offset < range1.to) {
-      handleSkew(0, new Interval(range1.from + offset, range1.to));
-    }
-    if (range2.from + offset < range2.to) {
-      handleSkew(1, new Interval(range2.from + offset, range2.to));
-    }
-  }
-
-  /// 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;
-
-    void flushMatching() {
-      if (currentMatchedIntervals != null) {
-        withIdentical(() {
-          addBothLines(currentMatchedIntervals);
-        });
+    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>');
+        }
       }
-      currentMatchedIntervals = null;
+      sb.write('''</td>''');
     }
-
-    align(
-        inputLines[0],
-        inputLines[1],
-        range1: range1,
-        range2: range2,
-        match: match,
-        handleSkew: (int listIndex, Interval range) {
-          flushMatching();
-          handleSkew(listIndex, range);
-        },
-        handleMatched: (List<int> indices) {
-          if (currentMatchedIntervals == null) {
-            currentMatchedIntervals = [
-              new Interval(indices[0], indices[0] + 1),
-              new Interval(indices[1], indices[1] + 1)];
-          } else {
-            currentMatchedIntervals[0] =
-                new Interval(currentMatchedIntervals[0].from, indices[0] + 1);
-            currentMatchedIntervals[1] =
-                new Interval(currentMatchedIntervals[1].from, indices[1] + 1);
-          }
-        },
-        handleUnmatched: (List<int> indices) {
-          flushMatching();
-          addBoth(indices);
-        });
-
-    flushMatching();
+    sb.write('</tr>');
   }
 
-  /// Output the lines of the library blocks in [childRange] in
-  /// `structures[index]`, padding the other column with empty lines.
-  void addBlock(int index, Interval childRange) {
-    handleSkew(index, structures[index].getChildInterval(childRange));
-  }
-
-  /// Output the members of the [classes] aligned.
-  void addMatchingClasses(List<LibraryClass> classes) {
-    withMatching(() {
-      addBothLines(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) {
-          handleSkew(listIndex,
-              classes[listIndex].getChildInterval(childRange));
-        },
-        handleMatched: (List<int> indices) {
-          List<Interval> intervals =  [
-              classes[0].getChild(indices[0]).interval,
-              classes[1].getChild(indices[1]).interval];
-          withMatching(() {
-            addBothLines(intervals);
-          });
-        },
-        handleUnmatched: (List<int> indices) {
-          List<Interval> intervals =  [
-              classes[0].getChild(indices[0]).interval,
-              classes[1].getChild(indices[1]).interval];
-          addBothLines(intervals);
-        });
-    withMatching(() {
-      addBothLines(classes.map((c) => c.footer).toList());
-    });
-  }
-
-  /// Output 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])];
-
-    withMatching(() {
-      addBothLines(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) {
-          handleSkew(listIndex, blocks[listIndex].getChildInterval(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)) {
-            addMatchingClasses(entities);
-          } else {
-            withMatching(() {
-              addBothLines(entities.map((e) => e.interval).toList());
-            });
-          }
-        },
-        handleUnmatched: (List<int> indices) {
-          List<Interval> intervals =  [
-              blocks[0].getChild(indices[0]).interval,
-              blocks[1].getChild(indices[1]).interval];
-          addBothLines(intervals);
-        });
-    withMatching(() {
-      addBothLines(blocks.map((b) => b.footer).toList());
-    });
-  }
-
-  /// Output 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])];
-    addBothLines([blocks[0].interval, blocks[1].interval]);
-  }
-
-
-  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);
-
-  addCell(htmlPartsToString(outputLines[0], inputLines[0]));
-  addCell(htmlPartsToString(outputLines[1], inputLines[1]));
-
   sb.write('''</tr><tr>''');
-  addCell(result1.coverage.getCoverageReport());
-  addCell(result2.coverage.getCoverageReport());
+
+  addCell(outputs[0].coverage);
+  addCell(outputs[1].coverage);
 
   sb.write('''
-</tr></table>
+</table>
 </body>
 </html>
 ''');
@@ -373,444 +391,14 @@
   print('Diff generated in $out');
 }
 
-/// 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));
-  }
-}
-
-// 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 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_$]+): \[?\{');
-
-/// Subrange of the JavaScript output.
-abstract class OutputEntity {
-  Interval get interval;
-  Interval get header;
-  Interval get footer;
-
-  List<OutputEntity> get children;
-
-  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];
-  }
-}
-
-/// 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);
-
-  Interval get interval => new Interval(0, lines.length);
-
-  Interval get header => new Interval(0, headerEnd);
-
-  Interval get footer => new Interval(footerStart, lines.length);
-
-  /// 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);
-  }
-}
-
-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);
-}
-
-/// 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);
-
-  Interval get header => new Interval(from, headerEnd);
-
-  Interval get footer => new Interval(footerStart, to);
-
-  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 BasicEntity(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 BasicEntity(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);
-    }
-  }
-}
-
-/// A simple member of a library or class.
-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) {}
-}
-
-/// 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);
-
-  Interval get header => new Interval(from, headerEnd);
-
-  Interval get footer => new Interval(footerStart, to);
-
-  void preprocess(List<CodeLine> lines) {
-    int index = headerEnd;
-    BasicEntity current;
-    while (index < footerStart) {
-      String line = lines[index].code;
-      BasicEntity next;
-      Match matchFunction = MEMBER_FUNCTION.firstMatch(line);
-      if (matchFunction != null) {
-        next = new BasicEntity(matchFunction.group(1), index);
-      } else {
-        Match matchClass = MEMBER_OBJECT.firstMatch(line);
-        if (matchClass != null) {
-          next = new BasicEntity(matchClass.group(1), index);
-        } else {
-          Match matchValue = MEMBER_VALUE.firstMatch(line);
-          if (matchValue != null) {
-            next = new BasicEntity(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;
-    }
-  }
-}
-
-class Interval {
-  final int from;
-  final int to;
-
-  const Interval(this.from, this.to);
-
-  int get length => to - from;
-}
-
-class HtmlPart {
-  void printHtmlOn(StringBuffer buffer) {}
-}
-
-class ConstHtmlPart implements HtmlPart {
-  final String html;
-
-  const ConstHtmlPart(this.html);
-
-  @override
-  void printHtmlOn(StringBuffer buffer) {
-    buffer.write(html);
-  }
-}
-
-class CodeLineHtmlPart implements HtmlPart {
-  final CodeLine line;
-
-  CodeLineHtmlPart(this.line);
-
-  @override
-  void printHtmlOn(StringBuffer buffer, [int lineNoWidth]) {
-    line.printHtmlOn(buffer, lineNoWidth);
-  }
-}
-
-/// Convert [parts] to an HTML string while checking invariants for [lines].
-String htmlPartsToString(List<HtmlPart> parts, List<CodeLine> lines) {
-  int lineNoWidth;
-  if (lines.isNotEmpty) {
-    lineNoWidth = '${lines.last.lineNo + 1}'.length;
-  }
-  StringBuffer buffer = new StringBuffer();
-  int expectedLineNo = 0;
-  for (HtmlPart part in parts) {
-    if (part is CodeLineHtmlPart) {
-      if (part.line.lineNo != expectedLineNo) {
-        print('Expected line no $expectedLineNo, found ${part.line.lineNo}');
-        if (part.line.lineNo < expectedLineNo) {
-          print('Duplicate lines:');
-          int index = part.line.lineNo;
-          while (index <= expectedLineNo) {
-            print(lines[index++].code);
-          }
-        } else {
-          print('Missing lines:');
-          int index = expectedLineNo;
-          while (index <= part.line.lineNo) {
-            print(lines[index++].code);
-          }
-        }
-        expectedLineNo = part.line.lineNo;
-      }
-      expectedLineNo++;
-      part.printHtmlOn(buffer, lineNoWidth);
-    } else {
-      part.printHtmlOn(buffer);
-    }
-  }
-  return buffer.toString();
-}
-
 class CodeLinesResult {
   final List<CodeLine> codeLines;
   final Coverage coverage;
+  final Map<int, Element> elementMap;
+  final SourceFileManager sourceFileManager;
 
-  CodeLinesResult(this.codeLines, this.coverage);
+  CodeLinesResult(this.codeLines, this.coverage,
+      this.elementMap, this.sourceFileManager);
 }
 
 /// Compute [CodeLine]s and [Coverage] for [filename] using the given [options].
@@ -819,25 +407,57 @@
     String filename,
     {bool addAnnotations: true}) async {
   SourceMapProcessor processor = new SourceMapProcessor(filename);
-  List<SourceMapInfo> sourceMapInfoList =
-      await processor.process(options, perElement: false);
+  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;
 
-  for (SourceMapInfo info in sourceMapInfoList) {
-    if (info.element != null) continue;
+  SourceMapInfo info = sourceMaps.mainSourceMapInfo;
 
-    List<CodeLine> codeLines;
-    Coverage coverage = new Coverage();
-    List<Annotation> annotations = <Annotation>[];
+  List<CodeLine> codeLines;
+  Coverage coverage = new Coverage();
+  List<Annotation> annotations = <Annotation>[];
 
-    String code = info.code;
-    TraceGraph graph = createTraceGraph(info, coverage);
-    if (addAnnotations) {
-      Set<js.Node> mappedNodes = new Set<js.Node>();
-      for (TraceStep step in graph.steps) {
+  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;
@@ -845,43 +465,104 @@
           offset = info.jsCodePositions[step.node].startPosition;
         }
         if (offset != null) {
-          int id = step.sourceLocation != null
-              ? WITH_SOURCE_INFO : WITHOUT_SOURCE_INFO;
-          annotations.add(
-              new Annotation(id, offset, null));
-        }
-      }
-      if (!options.contains(USE_NEW_SOURCE_INFO)) {
-        for (js.Node node in info.nodeMap.nodes) {
-          if (!mappedNodes.contains(node)) {
-            int offset = info.jsCodePositions[node].startPosition;
-            annotations.add(
-                        new Annotation(ADDITIONAL_SOURCE_INFO, offset, null));
-          }
+          addAnnotation(WITHOUT_SOURCE_INFO, offset, title);
         }
       }
     }
-    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;
-            }
-            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;
-            }
-            return WITHOUT_SOURCE_INFO_STYLE;
+    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 new CodeLinesResult(codeLines, coverage);
+          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
index 1aa40fe..4ea4e91 100644
--- a/tests/compiler/dart2js/sourcemaps/js_tracer.dart
+++ b/tests/compiler/dart2js/sourcemaps/js_tracer.dart
@@ -22,7 +22,8 @@
   return graph;
 }
 
-class StepTraceListener extends TraceListener {
+class StepTraceListener extends TraceListener
+    with NodeToSourceInformationMixin {
   Map<js.Node, TraceStep> steppableMap = <js.Node, TraceStep>{};
   final TraceGraph graph;
 
@@ -30,7 +31,7 @@
 
   @override
   void onStep(js.Node node, Offset offset, StepKind kind) {
-    SourceInformation sourceInformation = node.sourceInformation;
+    SourceInformation sourceInformation = computeSourceInformation(node);
     SourcePositionKind sourcePositionKind = SourcePositionKind.START;
     List text = [node];
     switch (kind) {
@@ -81,14 +82,16 @@
 
     }
     createTraceStep(
+        kind,
         node,
         offset: offset,
         sourceLocation: getSourceLocation(
-            node.sourceInformation, sourcePositionKind),
+            sourceInformation, sourcePositionKind),
         text: text);
   }
 
   void createTraceStep(
+      StepKind kind,
       js.Node node,
       {Offset offset,
        List text,
@@ -101,9 +104,12 @@
     }
 
     TraceStep step = new TraceStep(
-        id, node,
+        kind,
+        id,
+        node,
         offset,
-        text, sourceLocation);
+        text,
+        sourceLocation);
     graph.addStep(step);
 
     steppableMap[node] = step;
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 123cbe2..019e8be 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -5,6 +5,7 @@
 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;
@@ -303,10 +304,11 @@
   }
 
   /// Computes the [SourceMapInfo] for the compiled elements.
-  Future<List<SourceMapInfo>> process(
+  Future<SourceMaps> process(
       List<String> options,
       {bool verbose: true,
-       bool perElement: true}) async {
+       bool perElement: true,
+       bool forMain: false}) async {
     OutputProvider outputProvider = outputToFile
         ? new CloningOutputProvider(targetUri, sourceMapFileUri)
         : new OutputProvider();
@@ -335,7 +337,9 @@
     backend.sourceInformationStrategy = strategy;
     await compiler.run(inputUri);
 
-    List<SourceMapInfo> infoList = <SourceMapInfo>[];
+    SourceMapInfo mainSourceMapInfo;
+    Map<Element, SourceMapInfo> elementSourceMapInfos =
+        <Element, SourceMapInfo>{};
     if (perElement) {
       backend.generatedCode.forEach((Element element, js.Expression node) {
         RecordedSourceInformationProcess subProcess =
@@ -351,15 +355,18 @@
         CodePositionRecorder codePositions = subProcess.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,
+        elementSourceMapInfos[element] = new SourceMapInfo(
+            element,
+            code,
+            node,
             codePoints,
-            codePositions/*strategy.codePositions*/,
-            nodeMap));
+            codePositions,
+            nodeMap);
       });
-    } else {
+    }
+    if (forMain) {
       // TODO(johnniwinther): Supported multiple output units.
       RecordedSourceInformationProcess process = strategy.processMap.keys.first;
       js.Node node = strategy.processMap[process];
@@ -371,19 +378,32 @@
       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(
+      mainSourceMapInfo = new SourceMapInfo(
           null, code, node,
           codePoints,
           codePositions,
-          nodeMap));
+          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;
@@ -457,7 +477,7 @@
 
 
 /// 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 LocationMap nodeMap;
@@ -483,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();
     }
@@ -523,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.
@@ -596,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 52e871d..3ca926b 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -17,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) {
@@ -43,12 +52,13 @@
 
 /// 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]) {
+String lineNumber(int index, {int width, bool useNbsp: false}) {
   String text = '${index + 1}';
+  String padding = useNbsp ? '&nbsp;' : ' ';
   if (width != null && text.length < width) {
-    text = (' ' * (width - text.length)) + text;
+    text = (padding * (width - text.length)) + text;
   }
-  return '<span class="lineNumber">$text </span>';
+  return '<span class="lineNumber">$text$padding</span>';
 }
 
 /// Return the html escaped [text].
@@ -277,8 +287,9 @@
   if (lines.isNotEmpty) {
     lineNoWidth = '${lines.last.lineNo + 1}'.length;
   }
+  HtmlPrintContext context = new HtmlPrintContext(lineNoWidth: lineNoWidth);
   for (CodeLine line in lines) {
-    line.printHtmlOn(htmlBuffer, lineNoWidth);
+    line.printHtmlOn(htmlBuffer, context);
   }
   return htmlBuffer.toString();
 }
@@ -298,20 +309,20 @@
   int lastLine;
   bool pendingSourceLocationsEnd = false;
 
-  void write(String code, String html) {
+  void write(String code, HtmlPart html) {
     if (currentLine != null) {
       currentLine.codeBuffer.write(code);
       currentLine.htmlParts.add(html);
     }
   }
 
-  void startLine() {
-    lines.add(currentLine = new CodeLine(lines.length));
+  void startLine(int currentOffset) {
+    lines.add(currentLine = new CodeLine(lines.length, currentOffset));
   }
 
   void endCurrentLocation() {
     if (pendingSourceLocationsEnd) {
-      write('', '</a>');
+      write('', const ConstHtmlPart('</a>'));
     }
     pendingSourceLocationsEnd = false;
   }
@@ -321,38 +332,40 @@
     if (offset >= code.length) return;
 
     String substring = code.substring(offset, until);
-    offset = until;
     bool first = true;
 
     if (isLast) {
       lastLine = lineIndex;
     }
+    int localOffset = 0;
     if (isFirst) {
-      startLine();
+      startLine(offset + localOffset);
     }
     for (String line in substring.split('\n')) {
       if (!first) {
         endCurrentLocation();
-        write('', '\n');
+        write('', const NewLine());
         lineIndex++;
-        startLine();
+        startLine(offset + localOffset);
       }
       if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) {
         if (line.isNotEmpty) {
           String before = line.substring(0, 1);
-          write(before, escape(before));
+          write(before, new HtmlText(before));
           endCurrentLocation();
           String after = line.substring(1);
-          write(after, escape(after));
+          write(after, new HtmlText(after));
         }
       } else {
-        write(line, escape(line));
+        write(line, new HtmlText(line));
       }
       first = false;
+      localOffset += line.length + 1;
     }
     if (isFirst) {
       firstLine = lineIndex;
     }
+    offset = until;
   }
 
   void insertAnnotations(List<Annotation> annotations) {
@@ -384,29 +397,17 @@
       String onclick = elementScheme.onClick(id, ids);
       String onmouseover = elementScheme.onMouseOver(id, ids);
       String onmouseout = elementScheme.onMouseOut(id, ids);
-      write('', '<a');
-      if (href != null) {
-        write('', ' href="${href}"');
-      }
-      if (name != null) {
-        write('', ' name="${name}"');
-      }
-      if (title != null) {
-        write('', ' title="${escape(title)}"');
-      }
-      write('', ' style="${color}"');
-      if (onclick != null) {
-        write('', ' onclick="${onclick}"');
-      }
-      if (onmouseover != null) {
-        write('', ' onmouseover="${onmouseover}"');
-      }
-      if (onmouseout != null) {
-        write('', ' onmouseout="${onmouseout}"');
-      }
-      write('', '>');
+      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();
     }
@@ -438,30 +439,6 @@
   return lines.sublist(start, end);
 }
 
-class CodeLine {
-  final int lineNo;
-  final StringBuffer codeBuffer = new StringBuffer();
-  final List<String> htmlParts = <String>[];
-  String _code;
-
-  CodeLine(this.lineNo);
-
-  String get code {
-    if (_code == null) {
-      _code = codeBuffer.toString();
-    }
-    return _code;
-  }
-
-  void printHtmlOn(StringBuffer htmlBuffer, [int lineNoWidth]) {
-    htmlBuffer.write(lineNumber(lineNo, lineNoWidth));
-    for (String part in htmlParts) {
-      htmlBuffer.write(part);
-    }
-  }
-}
-
-
 /// Computes the HTML representation for a collection of JavaScript code blocks.
 String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) {
 
@@ -508,7 +485,6 @@
   SourceLocationCollection subcollection =
       new SourceLocationCollection(collection);
   CodeProcessor codeProcessor = new CodeProcessor(name, subcollection);
-  //print('${info.element}:${info.nodeMap.nodes.length}');
   for (js.Node node in info.nodeMap.nodes) {
     info.nodeMap[node].forEach(
         (int targetOffset, List<SourceLocation> sourceLocations) {
@@ -573,6 +549,7 @@
   });
   sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) {
     SourceFile sourceFile = sourceFileManager.getSourceFile(uri);
+    if (sourceFile == null) return;
     StringBuffer codeBuffer = new StringBuffer();
 
     int firstLineIndex;
@@ -595,7 +572,7 @@
              line < firstLineIndex;
              line++) {
           if (line >= 0) {
-            dartCodeBuffer.write(lineNumber(line, lineNoWidth));
+            dartCodeBuffer.write(lineNumber(line, width: lineNoWidth));
             dartCodeBuffer.write(sourceFile.getLineText(line));
           }
         }
@@ -604,7 +581,7 @@
              line <= lastLineIndex + windowSize;
              line++) {
           if (line < sourceFile.lines) {
-            dartCodeBuffer.write(lineNumber(line, lineNoWidth));
+            dartCodeBuffer.write(lineNumber(line, width: lineNoWidth));
             dartCodeBuffer.write(sourceFile.getLineText(line));
           }
         }
@@ -625,7 +602,7 @@
         firstLineIndex = lineIndex;
       } else {
         for (int line = lastLineIndex + 1; line < lineIndex; line++) {
-          codeBuffer.write(lineNumber(line, lineNoWidth));
+          codeBuffer.write(lineNumber(line, width: lineNoWidth));
           codeBuffer.write(sourceFile.getLineText(line));
         }
       }
@@ -640,7 +617,7 @@
           end = locations[i + 1].column;
         }
         if (i == 0) {
-          codeBuffer.write(lineNumber(lineIndex, lineNoWidth));
+          codeBuffer.write(lineNumber(lineIndex, width: lineNoWidth));
           codeBuffer.write(line.substring(0, start));
         }
         codeBuffer.write(
@@ -673,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) {
@@ -700,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
index b21014b..75eec94 100644
--- a/tests/compiler/dart2js/sourcemaps/trace_graph.dart
+++ b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
@@ -8,6 +8,7 @@
 
 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';
 
@@ -15,9 +16,24 @@
   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();
   }
 
@@ -31,6 +47,7 @@
 }
 
 class TraceStep {
+  final kind;
   final int id;
   final node;
   final Offset offset;
@@ -43,6 +60,7 @@
   List stack;
 
   TraceStep(
+      this.kind,
       this.id,
       this.node,
       this.offset,
diff --git a/tests/compiler/dart2js/type_mask_disjoint_test.dart b/tests/compiler/dart2js/type_mask_disjoint_test.dart
index 4cc7a00..90d3f53 100644
--- a/tests/compiler/dart2js/type_mask_disjoint_test.dart
+++ b/tests/compiler/dart2js/type_mask_disjoint_test.dart
@@ -26,9 +26,11 @@
 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 H(), new I(), new J(), new K(), new M(), new N()]);
 }
 """;
 
@@ -79,6 +81,7 @@
     check('A!<', 'E!<');
     check('A!<', 'H!<');
     check('D!<', 'I!<');
+    check('H!<', 'I!*', areDisjoint: false);
 
     // Subclass with subtype
     check('A!<', 'A!*', areDisjoint: false);
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 2cb3918..1399e79 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -58,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
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 402fe6e..8a8dae6 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -102,11 +102,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.
@@ -155,7 +158,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 +216,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 +335,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 +352,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,16 +365,11 @@
 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 ]
@@ -431,31 +425,31 @@
 resource_http_test: Crash # (await for(var b in r.openRead()){bytes.addAll(b);}): await for
 
 [ $compiler == dart2js && $cps_ir && $browser ]
-custom/element_upgrade_test: RuntimeError # Please triage
-js_dart_to_string_test: RuntimeError # Please triage
-custom_elements_23127_test/c2t: RuntimeError # Please triage
-custom_elements_23127_test/c2: RuntimeError # Please triage
-custom_elements_23127_test/baseline: RuntimeError # Please triage
-keyboard_event_test: RuntimeError # Please triage
-js_typed_interop_test: RuntimeError # Please triage
-js_typed_interop_side_cast_test: RuntimeError # Please triage
-js_typed_interop_anonymous_exp_test: RuntimeError # Please triage
-custom_elements_test/register: RuntimeError # Please triage
-js_typed_interop_anonymous2_test: RuntimeError # Please triage
-js_typed_interop_anonymous_test: RuntimeError # Please triage
-js_array_test: RuntimeError # Please triage
-js_function_getter_test/call: RuntimeError # Please triage
-custom/mirrors_test: RuntimeError # Please triage
-custom/constructor_calls_created_synchronously_test: RuntimeError # Please triage
-input_element_test/attributes: Pass # Please triage
-js_function_getter_trust_types_test: RuntimeError # Please triage
-js_typed_interop_side_cast_exp_test: RuntimeError # Please triage
-js_typed_interop_anonymous2_exp_test: RuntimeError # Please triage
-mirrors_js_typed_interop_test: RuntimeError # Please triage
-js_function_getter_test: RuntimeError # Please triage
-custom_elements_23127_test/c1t: RuntimeError # Please triage
-custom_elements_test/innerHtml: RuntimeError # Please triage
-mouse_event_test: RuntimeError # Please triage
-js_test/JsObject_methods: RuntimeError # Please triage
-js_test/Dart_functions: RuntimeError # Please triage
-js_test/new_JsObject: RuntimeError # Please triage
+# 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
+
+# New js-interop support via package:js is only implemented in SSA:
+js_array_test: RuntimeError # Need package:js support #24978
+js_dart_to_string_test: RuntimeError # Need package:js support #24978
+js_function_getter_test/call: RuntimeError # Need package:js support #24978
+js_function_getter_test: RuntimeError # Need package:js support #24978
+js_function_getter_trust_types_test: RuntimeError # Need package:js support #24978
+js_typed_interop_anonymous2_exp_test: RuntimeError # Need package:js support #24978
+js_typed_interop_anonymous2_test: RuntimeError # Need package:js support #24978
+js_typed_interop_anonymous_exp_test: RuntimeError # Need package:js support #24978
+js_typed_interop_anonymous_test: RuntimeError # Need package:js support #24978
+js_typed_interop_side_cast_exp_test: RuntimeError # Need package:js support #24978
+js_typed_interop_side_cast_test: RuntimeError # Need package:js support #24978
+js_typed_interop_test: RuntimeError # Need package:js support #24978
+mirrors_js_typed_interop_test: RuntimeError # Need package:js support #24978
+
+# 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/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 484b88e..5ba9267 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -55,6 +55,8 @@
 unicode_bom_test: Fail # Issue 16067
 vm/debug_break_enabled_vm_test/01: Crash, OK # Expected to hit breakpoint.
 try_catch_optimized1_test: Skip # Srdjan investigating
+issue_25671a_test/01: Skip # RuntimeError (Issue 25671, Issue 25737)
+issue_25671b_test/01: Skip # RuntimeError (Issue 25671, Issue 25737)
 
 [ ($compiler == none || $compiler == precompiler) && $checked ]
 type_variable_bounds4_test/01: Fail # Issue 14006
@@ -116,7 +118,7 @@
 [ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ( $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 || $compiler == precompiler) && ($runtime == dartium || $runtime == drt) ]
 issue23244_test: Fail # Issue 23244
 
 [ ($compiler == none || $compiler == precompiler) && (($runtime == vm || $runtime == dart_precompiled) || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 949b714..03ae9f9 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -242,6 +242,8 @@
 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
diff --git a/tests/language/library_env_test.dart b/tests/language/library_env_test.dart
index d076ede..7095d83 100644
--- a/tests/language/library_env_test.dart
+++ b/tests/language/library_env_test.dart
@@ -12,6 +12,12 @@
   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;
@@ -46,14 +52,12 @@
   hasIoSupport = false;  /// has_no_io_support: ok
 
   if (hasIoSupport != null) {
-    bool expectedResult = hasIoSupport ? true : NOT_PRESENT;
-
-    Expect.equals(expectedResult,
+    // 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: NOT_PRESENT));
-    Expect.equals(expectedResult,
-        const bool.fromEnvironment("dart.library.developer",
-            defaultValue: NOT_PRESENT));
+            defaultValue: false));
   }
 
   bool hasMirrorSupport;
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/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/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/lib.status b/tests/lib/lib.status
index d854ac9..317880e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -348,6 +348,9 @@
 [ $compiler != dart2js ]
 async/dart2js_uncaught_error_test: Skip  # JS-integration only test
 
+[ $noopt && $arch == simarm64 ]
+async/slow_consumer2_test: Pass, RuntimeError # Issue 25726
+
 [ ($noopt || $compiler == precompiler) ]
 mirrors/*: SkipByDesign
 convert/chunked_conversion_utf88_test: Pass, Timeout
diff --git a/tests/standalone/full_coverage_test.dart b/tests/standalone/full_coverage_test.dart
index 9eab81d..98495b1 100644
--- a/tests/standalone/full_coverage_test.dart
+++ b/tests/standalone/full_coverage_test.dart
@@ -220,8 +220,11 @@
   tearDown(() => destroyEnv(testingDirectory));
 
   test('CoverageTests', () {
+    print('Generating coverage data...');
     generateCoverage(testingDirectory);
+    print('Done Generating coverage data.');
 
+    print('Running tests...');
     coverageTests.forEach((cTest) {
       String programDir = path.join(testingDirectory, cTest['name']);
       String programPath = path.join(programDir, "${cTest['name']}.dart");
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
index 5be2ad1..81a43c9 100644
--- a/tests/standalone/io/http_proxy_advanced_test.dart
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -10,15 +10,14 @@
 import 'dart:convert';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                       password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 83d7640..042807c 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -10,15 +10,15 @@
 import 'dart:convert';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(
+      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 7c7f4b8..d90acd4 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -12,12 +12,11 @@
 final HOST_NAME = 'localhost';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 class CustomException {}
 
@@ -32,7 +31,7 @@
   });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+    ..setTrustedCertificatesSync(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 7047f61..27b97ed 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -11,20 +11,19 @@
 
 const HOST_NAME = "localhost";
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                       password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 // TODO: Specify which client certificate roots to trust.
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'))
 // TODO: Set a client certificate here.
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 void main() {
   asyncStart();
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index 7f6e28e..c0bce81 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -11,15 +11,14 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 c96934f..cfa54c2 100644
--- a/tests/standalone/io/https_unauthorized_test.dart
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -14,16 +14,15 @@
 const CERTIFICATE = "localhost_cert";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext untrustedServerContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile(
+  ..useCertificateChainSync(localFile(
       'certificates/untrusted_server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/untrusted_server_key.pem'),
-                         password: 'dartdart');
+  ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 957f873..b63da9e 100644
--- a/tests/standalone/io/raw_secure_server_closing_test.dart
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -15,15 +15,14 @@
 
 InternetAddress HOST;
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 2c112b6..0510ba6 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -15,15 +15,14 @@
 
 InternetAddress HOST;
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                       password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 void testSimpleBind() {
   asyncStart();
@@ -575,13 +574,13 @@
   var chain =
       Platform.script.resolve('certificates/untrusted_server_chain.pem')
       .toFilePath();
-  context.useCertificateChain(chain);
+  context.useCertificateChainSync(chain);
   testSimpleConnectFail(context, false);
   testSimpleConnectFail(context, true);
   var key =
       Platform.script.resolve('certificates/untrusted_server_key.pem')
        .toFilePath();
-  context.usePrivateKey(key, password: 'dartdart');
+  context.usePrivateKeySync(key, password: 'dartdart');
   testSimpleConnectFail(context, false);
   testSimpleConnectFail(context, true);
   testServerListenAfterConnect();
diff --git a/tests/standalone/io/raw_secure_socket_pause_test.dart b/tests/standalone/io/raw_secure_socket_pause_test.dart
index cb2dbfe..9ca848e 100644
--- a/tests/standalone/io/raw_secure_socket_pause_test.dart
+++ b/tests/standalone/io/raw_secure_socket_pause_test.dart
@@ -14,15 +14,14 @@
 import "dart:isolate";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 3462c30..04d8417 100644
--- a/tests/standalone/io/raw_secure_socket_test.dart
+++ b/tests/standalone/io/raw_secure_socket_test.dart
@@ -14,15 +14,14 @@
 import "dart:isolate";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 cfeeb2e..25d64e8 100644
--- a/tests/standalone/io/regress_21160_test.dart
+++ b/tests/standalone/io/regress_21160_test.dart
@@ -11,15 +11,14 @@
 import "dart:typed_data";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 5510245..eeea66b 100644
--- a/tests/standalone/io/secure_bad_certificate_test.dart
+++ b/tests/standalone/io/secure_bad_certificate_test.dart
@@ -12,12 +12,11 @@
 final HOST_NAME = 'localhost';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 class CustomException {}
 
@@ -31,7 +30,7 @@
     }, onError: (e) { if (e is! HandshakeException) throw e; });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+    ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
   SecurityContext badContext = new SecurityContext();
   SecurityContext defaultContext = SecurityContext.defaultContext;
 
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
index 7168223..00ea2dc 100644
--- a/tests/standalone/io/secure_client_raw_server_test.dart
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -14,15 +14,14 @@
 import "package:expect/expect.dart";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 2b47342..360e9e4d 100644
--- a/tests/standalone/io/secure_client_server_test.dart
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -16,15 +16,15 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(
+      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 f6576ee..9515688 100644
--- a/tests/standalone/io/secure_multiple_client_server_test.dart
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -17,15 +17,14 @@
 SecureServerSocket SERVER;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 940ebf6..0ba4103 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -11,23 +11,22 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                       password: 'dartdart')
-  ..setTrustedCertificates(file: localFile('certificates/client_authority.pem'))
-  ..setClientAuthorities(localFile('certificates/client_authority.pem'));
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart')
+  ..setTrustedCertificatesSync(localFile('certificates/client_authority.pem'))
+  ..setClientAuthoritiesSync(localFile('certificates/client_authority.pem'));
 
 SecurityContext clientCertContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
-  ..useCertificateChainBytes(readLocalFile('certificates/client1.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/client1_key.pem'),
-                                       password: 'dartdart');
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'))
+  ..useCertificateChainSync(localFile('certificates/client1.pem'))
+  ..usePrivateKeySync(localFile('certificates/client1_key.pem'),
+                                password: 'dartdart');
 
 SecurityContext clientNoCertContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 Future testClientCertificate({bool required, bool sendCert}) async {
   var server = await SecureServerSocket.bind(HOST, 0, serverContext,
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
index 77337a7..1e2a2d7 100644
--- a/tests/standalone/io/secure_server_closing_test.dart
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -16,15 +16,15 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(
+      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 5bdccfa..33cd57e 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -16,15 +16,14 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 a5885cc..c4738f6 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -26,15 +26,14 @@
 InternetAddress HOST;
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 1db5c0c..4b717b2 100644
--- a/tests/standalone/io/secure_socket_alpn_test.dart
+++ b/tests/standalone/io/secure_socket_alpn_test.dart
@@ -15,15 +15,14 @@
     'The maximum message length supported is 2^13-1';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext clientContext() => new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 SecurityContext serverContext() => new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 // Tests that client/server with same protocol can securely establish a
 // connection, negotiate the protocol and can send data to each other.
diff --git a/tests/standalone/io/secure_socket_renegotiate_client.dart b/tests/standalone/io/secure_socket_renegotiate_client.dart
index d277012..7886706 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'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 class ExpectException implements Exception {
   ExpectException(this.message);
diff --git a/tests/standalone/io/secure_socket_renegotiate_test.dart b/tests/standalone/io/secure_socket_renegotiate_test.dart
index 906bfd8..7cc9346 100644
--- a/tests/standalone/io/secure_socket_renegotiate_test.dart
+++ b/tests/standalone/io/secure_socket_renegotiate_test.dart
@@ -15,12 +15,11 @@
 
 const HOST_NAME = "localhost";
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 Future<SecureServerSocket> runServer() {
   return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/secure_socket_test.dart b/tests/standalone/io/secure_socket_test.dart
index 82fb84c..443e90b 100644
--- a/tests/standalone/io/secure_socket_test.dart
+++ b/tests/standalone/io/secure_socket_test.dart
@@ -13,15 +13,14 @@
 import "dart:io";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 Future<HttpServer> startServer() {
   return HttpServer.bindSecure(
diff --git a/tests/standalone/io/secure_unauthorized_client.dart b/tests/standalone/io/secure_unauthorized_client.dart
index 8677bec..9c764a7 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'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 class ExpectException implements Exception {
   ExpectException(this.message);
diff --git a/tests/standalone/io/secure_unauthorized_test.dart b/tests/standalone/io/secure_unauthorized_test.dart
index 995130f..097a0d0 100644
--- a/tests/standalone/io/secure_unauthorized_test.dart
+++ b/tests/standalone/io/secure_unauthorized_test.dart
@@ -12,13 +12,12 @@
 
 const HOST_NAME = "localhost";
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile(
+  ..useCertificateChainSync(localFile(
       'certificates/untrusted_server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/untrusted_server_key.pem'),
-                         password: 'dartdart');
+  ..usePrivateKeySync(localFile('certificates/untrusted_server_key.pem'),
+                      password: 'dartdart');
 
 Future<SecureServerSocket> runServer() {
   return SecureServerSocket.bind(HOST_NAME, 0, serverContext)
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
index 4048afd4..60577b2 100644
--- a/tests/standalone/io/security_context_argument_test.dart
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -6,7 +6,6 @@
 import "dart:io";
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 bool printException(e) { print(e); return true; }
 bool argumentError(e) => e is ArgumentError;
@@ -16,28 +15,27 @@
 
 void testUsePrivateKeyArguments() {
     var c = new SecurityContext();
-    c.useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'));
-    Expect.throws(() => c.usePrivateKeyBytes(
-          readLocalFile('certificates/server_key.pem'),
-                        password: "dart" * 1000),
+    c.useCertificateChainSync(localFile('certificates/server_chain.pem'));
+    Expect.throws(() => c.usePrivateKeySync(
+        localFile('certificates/server_key.pem'), password: "dart" * 1000),
         argumentError);
-    Expect.throws(() => c.usePrivateKeyBytes(
-          readLocalFile('certificates/server_key.pem')),
+    Expect.throws(() => c.usePrivateKeySync(
+        localFile('certificates/server_key.pem')),
         tlsException);
-    Expect.throws(() => c.usePrivateKeyBytes(
-          readLocalFile('certificates/server_key.pem'), password: "iHackSites"),
+    Expect.throws(() => c.usePrivateKeySync(
+          localFile('certificates/server_key.pem'), password: "iHackSites"),
         tlsException);
-    Expect.throws(() => c.usePrivateKeyBytes(
-          readLocalFile('certificates/server_key_oops.pem'),
-                        password: "dartdart"),
+    Expect.throws(() => c.usePrivateKeySync(
+        localFile('certificates/server_key_oops.pem'),
+                  password: "dartdart"),
         fileSystemException);
-    Expect.throws(() => c.usePrivateKeyBytes(1), argumentOrTypeError);
-    Expect.throws(() => c.usePrivateKeyBytes(null), argumentError);
-    Expect.throws(() => c.usePrivateKeyBytes(
-          readLocalFile('certificates/server_key_oops.pem'), password: 3),
-        fileSystemException);
-    c.usePrivateKeyBytes(
-        readLocalFile('certificates/server_key.pem'), password: "dartdart");
+    Expect.throws(() => c.usePrivateKeySync(1), argumentOrTypeError);
+    Expect.throws(() => c.usePrivateKeySync(null), argumentError);
+    Expect.throws(() => c.usePrivateKeySync(
+        localFile('certificates/server_key.pem'), password: 3),
+        argumentOrTypeError);
+    c.usePrivateKeySync(
+        localFile('certificates/server_key.pem'), password: "dartdart");
 }
 
 void main() {
diff --git a/tests/standalone/io/socket_upgrade_to_secure_test.dart b/tests/standalone/io/socket_upgrade_to_secure_test.dart
index 4cdaa7f..aa5eca0 100644
--- a/tests/standalone/io/socket_upgrade_to_secure_test.dart
+++ b/tests/standalone/io/socket_upgrade_to_secure_test.dart
@@ -18,12 +18,12 @@
 List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 6d2d84c..c2f87ec 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -23,12 +23,11 @@
 const String HOST_NAME = 'localhost';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 class SecurityConfiguration {
   final bool secure;
diff --git a/tests/standalone/io/web_socket_error_test.dart b/tests/standalone/io/web_socket_error_test.dart
index a9ed84a..31969a3 100644
--- a/tests/standalone/io/web_socket_error_test.dart
+++ b/tests/standalone/io/web_socket_error_test.dart
@@ -26,15 +26,14 @@
 const String HOST_NAME = 'localhost';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(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 ab37e93..e8642f5 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -22,15 +22,14 @@
 const String HOST_NAME = 'localhost';
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
-List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChainBytes(readLocalFile('certificates/server_chain.pem'))
-  ..usePrivateKeyBytes(readLocalFile('certificates/server_key.pem'),
-                         password: 'dartdart');
+  ..useCertificateChainSync(localFile('certificates/server_chain.pem'))
+  ..usePrivateKeySync(localFile('certificates/server_key.pem'),
+                      password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificatesSync(localFile('certificates/trusted_certs.pem'));
 
 /**
  * A SecurityConfiguration lets us run the tests over HTTP or HTTPS.
diff --git a/tests/standalone/no_lazy_dispatchers_test.dart b/tests/standalone/no_lazy_dispatchers_test.dart
new file mode 100644
index 0000000..999505f
--- /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/standalone.status b/tests/standalone/standalone.status
index 2804e49..438e394 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -13,6 +13,7 @@
 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.
@@ -237,11 +238,18 @@
 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
+precompilation_dart2js_test: Skip # Platform.executable
 
 full_coverage_test: RuntimeError # Platform.executable
 http_launch_test: RuntimeError # Platform.executable
@@ -258,7 +266,7 @@
 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
+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
@@ -280,3 +288,17 @@
 io/regress_7679_test: RuntimeError # 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
diff --git a/tools/VERSION b/tools/VERSION
index 37bc6da..4d09691 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 15
 PATCH 0
-PRERELEASE 1
+PRERELEASE 2
 PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 91d6864..62717d7 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -48,7 +48,7 @@
   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.',
@@ -90,14 +90,14 @@
   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:
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 5cf2b1a..c84f40d 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -44,6 +44,8 @@
 # ......dart_shared.platform
 # ......dart2dart.platform
 # ......_internal/
+# ......analysis_server/
+# ......analyzer/
 # ......async/
 # ......collection/
 # ......convert/
@@ -137,7 +139,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'))
+
+def CopyDartdocResources(home, sdk_root):
   RESOURCE_DIR = join(sdk_root, 'bin', 'snapshots', 'resources')
   DARTDOC = join(RESOURCE_DIR, 'dartdoc')
 
@@ -282,8 +290,10 @@
 
   # Copy dart2js/pub.
   CopyDartScripts(HOME, SDK_tmp)
+  
   CopySnapshots(SNAPSHOT, SDK_tmp)
   CopyDartdocResources(HOME, SDK_tmp)
+  CopyAnalyzerSources(HOME, LIB)
 
   # Write the 'version' file
   version = utils.GetVersion()
diff --git a/tools/dom/scripts/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index 3e16cf7..e0d28ab 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -126,13 +126,13 @@
     # addEventListener on the target, so we avoid
     'Event.currentTarget': [
       "@Creates('Null')",
-      "@Returns('EventTarget|=Object')",
+      "@Returns('EventTarget|=Object|Null')",
     ],
 
     # Only nodes in the DOM bubble and have target !== currentTarget.
     'Event.target': [
       "@Creates('Node')",
-      "@Returns('EventTarget|=Object')",
+      "@Returns('EventTarget|=Object|Null')",
     ],
 
     'File.lastModifiedDate': [
@@ -273,7 +273,7 @@
 
     'MouseEvent.relatedTarget': [
       "@Creates('Node')",
-      "@Returns('EventTarget|=Object')",
+      "@Returns('EventTarget|=Object|Null')",
     ],
 
     'PopStateEvent.state': [
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 ddf4647..84237ca 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -143,6 +143,13 @@
         ],
       },
 
+      'Dart_Product' : {
+        'abstract': 1,
+        'defines' : [
+          'NDEBUG',
+          'PRODUCT',
+        ]
+      },
 
       # Configurations
       'DebugIA32': {
@@ -163,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',
@@ -181,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',
@@ -202,6 +227,15 @@
         ],
       },
 
+      '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',
@@ -223,6 +257,15 @@
         ],
       },
 
+      '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',
@@ -244,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',
@@ -265,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',
@@ -286,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': {
@@ -306,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',
@@ -324,6 +403,15 @@
         ],
       },
 
+      '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',
@@ -342,6 +430,15 @@
         ],
       },
 
+      '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',
@@ -360,6 +457,15 @@
         ],
       },
 
+      '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',
@@ -378,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',
@@ -396,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',
@@ -414,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',
@@ -432,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',
@@ -450,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',
@@ -468,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
@@ -491,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',
@@ -509,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',
@@ -527,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 307b1c2..98d28fa 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -40,58 +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', ],
+        '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
@@ -107,8 +126,14 @@
           ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
-          'ldflags': ['-m32'],
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
         }]]
       },
 
@@ -136,8 +161,14 @@
           ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
-          'ldflags': ['-m32'],
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
         }]]
       },
 
@@ -167,8 +198,14 @@
           ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
-          'ldflags': ['-m32'],
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
         }]]
       },
 
@@ -190,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
@@ -226,8 +280,15 @@
             ],
           }],
           ['_toolset=="host"',{
-            'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
-            'ldflags': [ '-m32' ],
+            'cflags': [
+              '-O3',
+              '-m32',
+              '-msse2',
+              '-mfpmath=sse',
+            ],
+            'ldflags': [
+              '-m32',
+            ],
         }]]
       },
 
@@ -243,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 c8b0fd3..3650127 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -46,6 +46,7 @@
             'ExceptionHandling': '0',
             'RuntimeTypeInfo': 'false',
             'RuntimeLibrary': '1',  # /MTd - Multi-threaded, static (debug)
+            'OmitFramePointers': 'false',
           },
           'VCLinkerTool': {
             'LinkIncremental': '2',
@@ -58,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.
@@ -88,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',
@@ -96,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 e3d04b6..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,
@@ -92,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 fb3f364..67c52d7 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):
@@ -201,11 +210,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/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index a89aad5..70c1264 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':
@@ -80,7 +79,7 @@
       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 +141,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 +166,6 @@
       args.add('--enable_asserts');
       args.add('--enable_type_checks');
     }
-    if (useNoopt) {
-      args.add('--noopt');
-    }
     return args
         ..addAll(vmOptions)
         ..addAll(sharedOptions)
@@ -220,11 +214,22 @@
     arguments = new List.from(arguments);
     arguments.add('--out=$outputFileName');
 
+    // We want all dart2js compilers to run the vm with the
+    // --abort-on-assertion-errors flag.
+    // We have allowed constant maps as environmentOverrides,
+    // so we modify a new map.
+    var newOverrides = {'DART_VM_OPTIONS': '--abort-on-assertion-errors'};
+    if (environmentOverrides != null) {
+      newOverrides.addAll(environmentOverrides);
+      if (environmentOverrides.containsKey('DART_VM_OPTIONS')) {
+        newOverrides['DART_VM_OPTIONS'] += ' --abort-on-assertion-errors';
+      }
+    }
     return commandBuilder.getCompilationCommand(
         moniker, outputFileName, !useSdk,
         bootstrapDependencies(buildDir),
         computeCompilerPath(buildDir),
-        arguments, environmentOverrides);
+        arguments, newOverrides);
   }
 
   List<Uri> bootstrapDependencies(String buildDir) {
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 2978003..8596c6f 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -66,7 +66,7 @@
   RuntimeConfiguration._subclass();
 
   int computeTimeoutMultiplier({
-      bool isDebug: false,
+      String mode,
       bool isChecked: false,
       String arch}) {
     return 1;
@@ -165,7 +165,7 @@
       : super._subclass();
 
   int computeTimeoutMultiplier({
-      bool isDebug: false,
+      String mode,
       bool isChecked: false,
       String arch}) {
     int multiplier = 1;
@@ -182,7 +182,7 @@
         multiplier *= 4;
         break;
     }
-    if (isDebug) {
+    if (mode == 'debug') {
       multiplier *= 2;
     }
     return multiplier;
@@ -193,7 +193,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.
@@ -201,7 +201,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);
   }
 }
 
@@ -218,8 +218,11 @@
     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)];
   }
 }
 
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 852e86d..8e23169 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',
@@ -692,7 +692,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 +808,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_suite.dart b/tools/testing/dart/test_suite.dart
index fd67ebf..ed354d2 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -212,6 +212,21 @@
     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'];
@@ -2325,7 +2340,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';
diff --git a/tools/utils.py b/tools/utils.py
index f2f0704..8ea1874 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -215,6 +215,7 @@
 BUILD_MODES = {
   'debug': 'Debug',
   'release': 'Release',
+  'product': 'Product',
 }