Version 1.21.0-dev.9.0

Merge commit 'f6fbc40423a146ee378e52dacbc6e3a75f06ec89' into dev
diff --git a/DEPS b/DEPS
index 9aef0a8..97e943b 100644
--- a/DEPS
+++ b/DEPS
@@ -73,8 +73,8 @@
   "isolate_tag": "@0.2.3",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@2.0.2",
-  "kernel_rev": "@11edd6208940d227dc0b2cf87a6518d2508c0858",
-  "linter_tag": "@0.1.28",
+  "kernel_rev": "@8e2b2c03c2a22d9fdf581a8e3ce798f189531081",
+  "linter_tag": "@0.1.29",
   "logging_tag": "@0.11.3+1",
   "markdown_tag": "@0.11.0",
   "matcher_tag": "@0.12.0+2",
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index c0df56e..6bad443 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -107,14 +107,11 @@
     if (server.searchEngine == null) {
       return new Response.noIndexGenerated(request);
     }
-    runZoned(() {
-      try {
-        String requestName = request.method;
-        if (requestName == COMPLETION_GET_SUGGESTIONS) {
-          processRequest(request);
-        }
-      } on RequestFailure catch (exception) {
-        return exception.response;
+    return runZoned(() {
+      String requestName = request.method;
+      if (requestName == COMPLETION_GET_SUGGESTIONS) {
+        processRequest(request);
+        return Response.DELAYED_RESPONSE;
       }
       return null;
     }, onError: (exception, stackTrace) {
@@ -123,7 +120,6 @@
           exception,
           stackTrace);
     });
-    return Response.DELAYED_RESPONSE;
   }
 
   /**
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index e6607ca..3b61ade 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -52,23 +52,22 @@
 }
 
 /**
- * Adds [edit] to the [FileEdit] for the given [element].
+ * Adds [edit] to the file containing the given [element].
  */
 void doSourceChange_addElementEdit(
     SourceChange change, engine.Element element, SourceEdit edit) {
-  engine.AnalysisContext context = element.context;
   engine.Source source = element.source;
-  doSourceChange_addSourceEdit(change, context, source, edit);
+  doSourceChange_addSourceEdit(change, source, edit);
 }
 
 /**
- * Adds [edit] to the [FileEdit] for the given [source].
+ * Adds [edit] for the given [source] to the [change].
  */
-void doSourceChange_addSourceEdit(SourceChange change,
-    engine.AnalysisContext context, engine.Source source, SourceEdit edit) {
+void doSourceChange_addSourceEdit(
+    SourceChange change, engine.Source source, SourceEdit edit,
+    {bool isNewFile: false}) {
   String file = source.fullName;
-  int fileStamp = context.getModificationStamp(source);
-  change.addEdit(file, fileStamp, edit);
+  change.addEdit(file, isNewFile ? -1 : 0, edit);
 }
 
 String getReturnTypeString(engine.Element element) {
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 399ea8b..63d5280 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -10,6 +10,7 @@
     show SearchResult, newSearchResult_fromMatch;
 import 'package:analysis_server/src/services/search/hierarchy.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -92,7 +93,7 @@
   SearchResult _newDeclarationResult(Element refElement) {
     int nameOffset = refElement.nameOffset;
     int nameLength = refElement.nameLength;
-    SearchMatch searchMatch = new SearchMatch(
+    SearchMatch searchMatch = new SearchMatchImpl(
         refElement.context,
         refElement.library.source.uri.toString(),
         refElement.source.uri.toString(),
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 051ae23..f813e78 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -393,7 +393,7 @@
     analysisServerOptions.enablePubSummaryManager =
         results[ENABLE_PUB_SUMMARY_MANAGER];
     analysisServerOptions.finerGrainedInvalidation =
-        true /*results[FINER_GRAINED_INVALIDATION]*/;
+        results[FINER_GRAINED_INVALIDATION];
     analysisServerOptions.noErrorNotification = results[NO_ERROR_NOTIFICATION];
     analysisServerOptions.noIndex = results[NO_INDEX];
     analysisServerOptions.useAnalysisHighlight2 =
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 1a99f8f..1a886be 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -1216,7 +1216,7 @@
         if (isAbsolute(file) && AnalysisEngine.isDartFileName(file)) {
           String libName = _computeLibraryName(file);
           SourceEdit edit = new SourceEdit(0, 0, 'library $libName;$eol$eol');
-          doSourceChange_addSourceEdit(change, context, source, edit);
+          doSourceChange_addSourceEdit(change, source, edit, isNewFile: true);
           _addFix(DartFixKind.CREATE_FILE, [source.shortName]);
         }
       }
@@ -1435,7 +1435,7 @@
       if (source != null) {
         String libName = unitLibraryElement.name;
         SourceEdit edit = new SourceEdit(0, 0, 'part of $libName;$eol$eol');
-        doSourceChange_addSourceEdit(change, context, source, edit);
+        doSourceChange_addSourceEdit(change, source, edit, isNewFile: true);
         _addFix(DartFixKind.CREATE_FILE, [source.shortName]);
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
index 17fdb68..7e18c6b 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
@@ -12,7 +12,6 @@
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/source.dart';
 
 /**
@@ -68,8 +67,6 @@
 
   SourceReference(this._match);
 
-  AnalysisContext get context => _match.context;
-
   Element get element => _match.element;
 
   /**
@@ -106,7 +103,7 @@
    */
   void addEdit(SourceChange change, String newText, {String id}) {
     SourceEdit edit = createEdit(newText, id: id);
-    doSourceChange_addSourceEdit(change, context, unitSource, edit);
+    doSourceChange_addSourceEdit(change, unitSource, edit);
   }
 
   /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index 80fd4b1..cb9d88d 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -16,6 +16,7 @@
 import 'package:analysis_server/src/services/refactoring/rename.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/java_core.dart';
@@ -96,7 +97,7 @@
     } else {
       sourceRange = rangeStartLength(element.nameEnd, 0);
     }
-    return new SourceReference(new SearchMatch(
+    return new SourceReference(new SearchMatchImpl(
         element.context,
         element.library.source.uri.toString(),
         element.source.uri.toString(),
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine.dart b/pkg/analysis_server/lib/src/services/search/search_engine.dart
index 9f283fc..6ea3395 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine.dart
@@ -7,11 +7,7 @@
 import 'dart:async';
 
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/visitor.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
 
 /**
  * Instances of the enum [MatchKind] represent the kind of reference that was
@@ -110,138 +106,53 @@
  * Instances of the class [SearchMatch] represent a match found by
  * [SearchEngine].
  */
-class SearchMatch {
-  /**
-   * The [AnalysisContext] containing the match.
-   */
-  final AnalysisContext context;
-
-  /**
-   * The URI of the source of the library containing the match.
-   */
-  final String libraryUri;
-
-  /**
-   * The URI of the source of the unit containing the match.
-   */
-  final String unitUri;
-
-  /**
-   * The kind of the match.
-   */
-  final MatchKind kind;
-
-  /**
-   * The source range that was matched.
-   */
-  final SourceRange sourceRange;
-
-  /**
-   * Is `true` if the match is a resolved reference to some [Element].
-   */
-  final bool isResolved;
-
-  /**
-   * Is `true` if field or method access is done using qualifier.
-   */
-  final bool isQualified;
-
-  Source _librarySource;
-  Source _unitSource;
-  LibraryElement _libraryElement;
-  Element _element;
-
-  SearchMatch(this.context, this.libraryUri, this.unitUri, this.kind,
-      this.sourceRange, this.isResolved, this.isQualified);
-
+abstract class SearchMatch {
   /**
    * Return the [Element] containing the match. Can return `null` if the unit
    * does not exist, or its element was invalidated, or the element cannot be
    * found, etc.
    */
-  Element get element {
-    if (_element == null) {
-      CompilationUnitElement unitElement =
-          context.getCompilationUnitElement(unitSource, librarySource);
-      if (unitElement != null) {
-        _ContainingElementFinder finder =
-            new _ContainingElementFinder(sourceRange.offset);
-        unitElement.accept(finder);
-        _element = finder.containingElement;
-      }
-    }
-    return _element;
-  }
+  Element get element;
 
   /**
    * The absolute path of the file containing the match.
    */
-  String get file => unitSource.fullName;
+  String get file;
 
-  @override
-  int get hashCode {
-    return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode,
-        kind.hashCode, sourceRange.hashCode);
-  }
+  /**
+   * Is `true` if field or method access is done using qualifier.
+   */
+  bool get isQualified;
+
+  /**
+   * Is `true` if the match is a resolved reference to some [Element].
+   */
+  bool get isResolved;
+
+  /**
+   * The kind of the match.
+   */
+  MatchKind get kind;
 
   /**
    * Return the [LibraryElement] for the [libraryUri] in the [context].
    */
-  LibraryElement get libraryElement {
-    _libraryElement ??= context.getLibraryElement(librarySource);
-    return _libraryElement;
-  }
+  LibraryElement get libraryElement;
 
   /**
    * The library [Source] of the reference.
    */
-  Source get librarySource {
-    _librarySource ??= context.sourceFactory.forUri(libraryUri);
-    return _librarySource;
-  }
+  Source get librarySource;
+
+  /**
+   * The source range that was matched.
+   */
+  SourceRange get sourceRange;
 
   /**
    * The unit [Source] of the reference.
    */
-  Source get unitSource {
-    _unitSource ??= context.sourceFactory.forUri(unitUri);
-    return _unitSource;
-  }
-
-  @override
-  bool operator ==(Object object) {
-    if (identical(object, this)) {
-      return true;
-    }
-    if (object is SearchMatch) {
-      return kind == object.kind &&
-          libraryUri == object.libraryUri &&
-          unitUri == object.unitUri &&
-          isResolved == object.isResolved &&
-          isQualified == object.isQualified &&
-          sourceRange == object.sourceRange;
-    }
-    return false;
-  }
-
-  @override
-  String toString() {
-    StringBuffer buffer = new StringBuffer();
-    buffer.write("SearchMatch(kind=");
-    buffer.write(kind);
-    buffer.write(", libraryUri=");
-    buffer.write(libraryUri);
-    buffer.write(", unitUri=");
-    buffer.write(unitUri);
-    buffer.write(", range=");
-    buffer.write(sourceRange);
-    buffer.write(", isResolved=");
-    buffer.write(isResolved);
-    buffer.write(", isQualified=");
-    buffer.write(isQualified);
-    buffer.write(")");
-    return buffer.toString();
-  }
+  Source get unitSource;
 
   /**
    * Return elements of [matches] which has not-null elements.
@@ -253,24 +164,3 @@
     return matches.where((match) => match.element != null).toList();
   }
 }
-
-/**
- * A visitor that finds the deep-most [Element] that contains the [offset].
- */
-class _ContainingElementFinder extends GeneralizingElementVisitor {
-  final int offset;
-  Element containingElement;
-
-  _ContainingElementFinder(this.offset);
-
-  visitElement(Element element) {
-    if (element is ElementImpl) {
-      if (element.codeOffset != null &&
-          element.codeOffset <= offset &&
-          offset <= element.codeOffset + element.codeLength) {
-        containingElement = element;
-        super.visitElement(element);
-      }
-    }
-  }
-}
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 5b2b6e3..cdd6a91 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -12,10 +12,13 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/resolver.dart' show NamespaceBuilder;
 import 'package:analyzer/src/generated/source.dart' show Source, SourceRange;
+import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/summary/idl.dart';
 
 /**
@@ -127,7 +130,7 @@
         throw new ArgumentError('Unsupported relation kind $relationKind');
       }
     }
-    return new SearchMatch(
+    return new SearchMatchImpl(
         location.context,
         location.libraryUri,
         location.unitUri,
@@ -234,7 +237,7 @@
       for (Directive directive in unit.directives) {
         if (directive is PartOfDirective &&
             directive.element == libraryElement) {
-          matches.add(new SearchMatch(
+          matches.add(new SearchMatchImpl(
               context,
               librarySource.uri.toString(),
               unitSource.uri.toString(),
@@ -288,6 +291,174 @@
 }
 
 /**
+ * Implementation of [SearchMatch].
+ */
+class SearchMatchImpl implements SearchMatch {
+  /**
+   * The [AnalysisContext] containing the match.
+   */
+  final AnalysisContext _context;
+
+  /**
+   * The URI of the source of the library containing the match.
+   */
+  final String libraryUri;
+
+  /**
+   * The URI of the source of the unit containing the match.
+   */
+  final String unitUri;
+
+  /**
+   * The kind of the match.
+   */
+  final MatchKind kind;
+
+  /**
+   * The source range that was matched.
+   */
+  final SourceRange sourceRange;
+
+  /**
+   * Is `true` if the match is a resolved reference to some [Element].
+   */
+  final bool isResolved;
+
+  /**
+   * Is `true` if field or method access is done using qualifier.
+   */
+  final bool isQualified;
+
+  Source _librarySource;
+  Source _unitSource;
+  LibraryElement _libraryElement;
+  Element _element;
+
+  SearchMatchImpl(this._context, this.libraryUri, this.unitUri, this.kind,
+      this.sourceRange, this.isResolved, this.isQualified);
+
+  /**
+   * Return the [Element] containing the match. Can return `null` if the unit
+   * does not exist, or its element was invalidated, or the element cannot be
+   * found, etc.
+   */
+  Element get element {
+    if (_element == null) {
+      CompilationUnitElement unitElement =
+          _context.getCompilationUnitElement(unitSource, librarySource);
+      if (unitElement != null) {
+        _ContainingElementFinder finder =
+            new _ContainingElementFinder(sourceRange.offset);
+        unitElement.accept(finder);
+        _element = finder.containingElement;
+      }
+    }
+    return _element;
+  }
+
+  /**
+   * The absolute path of the file containing the match.
+   */
+  String get file => unitSource.fullName;
+
+  @override
+  int get hashCode {
+    return JenkinsSmiHash.hash4(libraryUri.hashCode, unitUri.hashCode,
+        kind.hashCode, sourceRange.hashCode);
+  }
+
+  /**
+   * Return the [LibraryElement] for the [libraryUri] in the [context].
+   */
+  LibraryElement get libraryElement {
+    _libraryElement ??= _context.getLibraryElement(librarySource);
+    return _libraryElement;
+  }
+
+  /**
+   * The library [Source] of the reference.
+   */
+  Source get librarySource {
+    _librarySource ??= _context.sourceFactory.forUri(libraryUri);
+    return _librarySource;
+  }
+
+  /**
+   * The unit [Source] of the reference.
+   */
+  Source get unitSource {
+    _unitSource ??= _context.sourceFactory.forUri(unitUri);
+    return _unitSource;
+  }
+
+  @override
+  bool operator ==(Object object) {
+    if (identical(object, this)) {
+      return true;
+    }
+    if (object is SearchMatchImpl) {
+      return kind == object.kind &&
+          libraryUri == object.libraryUri &&
+          unitUri == object.unitUri &&
+          isResolved == object.isResolved &&
+          isQualified == object.isQualified &&
+          sourceRange == object.sourceRange;
+    }
+    return false;
+  }
+
+  @override
+  String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write("SearchMatch(kind=");
+    buffer.write(kind);
+    buffer.write(", libraryUri=");
+    buffer.write(libraryUri);
+    buffer.write(", unitUri=");
+    buffer.write(unitUri);
+    buffer.write(", range=");
+    buffer.write(sourceRange);
+    buffer.write(", isResolved=");
+    buffer.write(isResolved);
+    buffer.write(", isQualified=");
+    buffer.write(isQualified);
+    buffer.write(")");
+    return buffer.toString();
+  }
+
+  /**
+   * Return elements of [matches] which has not-null elements.
+   *
+   * When [SearchMatch.element] is not `null` we cache its value, so it cannot
+   * become `null` later.
+   */
+  static List<SearchMatch> withNotNullElement(List<SearchMatch> matches) {
+    return matches.where((match) => match.element != null).toList();
+  }
+}
+
+/**
+ * A visitor that finds the deep-most [Element] that contains the [offset].
+ */
+class _ContainingElementFinder extends GeneralizingElementVisitor {
+  final int offset;
+  Element containingElement;
+
+  _ContainingElementFinder(this.offset);
+
+  visitElement(Element element) {
+    if (element is ElementImpl) {
+      if (element.codeOffset != null &&
+          element.codeOffset <= offset &&
+          offset <= element.codeOffset + element.codeLength) {
+        containingElement = element;
+        super.visitElement(element);
+      }
+    }
+  }
+}
+
+/**
  * Visitor that adds [SearchMatch]es for [importElement], both with an explicit
  * prefix or an implicit one.
  */
@@ -350,7 +521,7 @@
   }
 
   void _addMatchForRange(SourceRange range) {
-    matches.add(new SearchMatch(
+    matches.add(new SearchMatchImpl(
         context, libraryUri, unitUri, MatchKind.REFERENCE, range, true, false));
   }
 }
@@ -407,7 +578,7 @@
 
   void _addMatch(AstNode node, MatchKind kind) {
     bool isQualified = node.parent is Label;
-    matches.add(new SearchMatch(context, libraryUri, unitUri, kind,
+    matches.add(new SearchMatchImpl(context, libraryUri, unitUri, kind,
         rangeNode(node), true, isQualified));
   }
 }
diff --git a/pkg/analysis_server/test/services/correction/status_test.dart b/pkg/analysis_server/test/services/correction/status_test.dart
index 9e60de9..9c9169e 100644
--- a/pkg/analysis_server/test/services/correction/status_test.dart
+++ b/pkg/analysis_server/test/services/correction/status_test.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/services/correction/source_range.dart';
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -41,7 +42,7 @@
     resolveTestUnit('class MyClass {}');
     Element element = findElement('MyClass');
     SourceRange range = rangeElementName(element);
-    SearchMatch match = new SearchMatch(
+    SearchMatch match = new SearchMatchImpl(
         context,
         element.library.source.uri.toString(),
         element.source.uri.toString(),
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 7486496b..0a43fa5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -13,6 +13,8 @@
 import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/dart/analysis/search.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisEngine, AnalysisOptions, ChangeSet;
@@ -67,7 +69,7 @@
   /**
    * The version of data format, should be incremented on every format change.
    */
-  static const int DATA_VERSION = 5;
+  static const int DATA_VERSION = 7;
 
   /**
    * The name of the driver, e.g. the name of the folder.
@@ -176,16 +178,16 @@
   final _resultController = new StreamController<AnalysisResult>();
 
   /**
-   * Mapping from library URIs to the dependency signature of the library.
-   */
-  final _dependencySignatureMap = <Uri, String>{};
-
-  /**
    * The instance of the status helper.
    */
   final StatusSupport _statusSupport = new StatusSupport();
 
   /**
+   * The instance of the [Search] helper.
+   */
+  Search _search;
+
+  /**
    * Create a new instance of [AnalysisDriver].
    *
    * The given [SourceFactory] is cloned to ensure that it does not contain a
@@ -202,9 +204,17 @@
       : _sourceFactory = sourceFactory.clone() {
     _fillSalt();
     _sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
-    _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
-        _resourceProvider, _sourceFactory, _analysisOptions, _salt);
+    _fsState = new FileSystemState(
+        _logger,
+        _byteStore,
+        _contentOverlay,
+        _resourceProvider,
+        _sourceFactory,
+        _analysisOptions,
+        _salt,
+        _sdkBundle.apiSignature);
     _scheduler._add(this);
+    _search = new Search(this);
   }
 
   /**
@@ -258,6 +268,11 @@
   Stream<AnalysisResult> get results => _resultController.stream;
 
   /**
+   * Return the search support for the driver.
+   */
+  Search get search => _search;
+
+  /**
    * Return the stream that produces [AnalysisStatus] events.
    */
   Stream<AnalysisStatus> get status => _statusSupport.stream;
@@ -472,9 +487,9 @@
       }
 
       // Check for the cached result.
-      AnalysisResult result = _getCachedAnalysisResult(file, key);
-      if (result != null) {
-        return result;
+      List<int> bytes = _byteStore.get(key);
+      if (bytes != null) {
+        return _getAnalysisResultFromBytes(file, bytes);
       }
     }
 
@@ -492,16 +507,15 @@
       AnalysisContext analysisContext = _createAnalysisContext(libraryContext);
       try {
         analysisContext.setContents(file.source, file.content);
-        // TODO(scheglov) Add support for parts.
-        CompilationUnit resolvedUnit = withUnit
-            ? analysisContext.resolveCompilationUnit2(
-                file.source, libraryFile.source)
-            : null;
+        CompilationUnit resolvedUnit = analysisContext.resolveCompilationUnit2(
+            file.source, libraryFile.source);
         List<AnalysisError> errors = analysisContext.computeErrors(file.source);
+        AnalysisDriverUnitIndexBuilder index = indexUnit(resolvedUnit);
 
         // Store the result into the cache.
+        List<int> bytes;
         {
-          List<int> bytes = new AnalysisDriverResolvedUnitBuilder(
+          bytes = new AnalysisDriverResolvedUnitBuilder(
                   errors: errors
                       .map((error) => new AnalysisDriverUnitErrorBuilder(
                           offset: error.offset,
@@ -509,7 +523,8 @@
                           uniqueName: error.errorCode.uniqueName,
                           message: error.message,
                           correction: error.correction))
-                      .toList())
+                      .toList(),
+                  index: index)
               .toBuffer();
           String key = _getResolvedUnitKey(libraryFile, file);
           _byteStore.put(key, bytes);
@@ -517,15 +532,9 @@
 
         // Return the result, full or partial.
         _logger.writeln('Computed new analysis result.');
-        return new AnalysisResult(
-            _sourceFactory,
-            file.path,
-            file.uri,
-            withUnit ? file.content : null,
-            file.contentHash,
-            file.lineInfo,
-            resolvedUnit,
-            errors);
+        return _getAnalysisResultFromBytes(file, bytes,
+            content: withUnit ? file.content : null,
+            resolvedUnit: withUnit ? resolvedUnit : null);
       } finally {
         analysisContext.dispose();
       }
@@ -659,26 +668,23 @@
   }
 
   /**
-   * If we know the result [key] for the [file], try to load the analysis
-   * result from the cache. Return `null` if not found.
+   * Load the [AnalysisResult] for the given [file] from the [bytes]. Set
+   * optional [content] and [resolvedUnit].
    */
-  AnalysisResult _getCachedAnalysisResult(FileState file, String key) {
-    List<int> bytes = _byteStore.get(key);
-    if (bytes != null) {
-      var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
-      List<AnalysisError> errors = unit.errors
-          .map((error) => new AnalysisError.forValues(
-              file.source,
-              error.offset,
-              error.length,
-              errorCodeByUniqueName(error.uniqueName),
-              error.message,
-              error.correction))
-          .toList();
-      return new AnalysisResult(_sourceFactory, file.path, file.uri, null,
-          file.contentHash, file.lineInfo, null, errors);
-    }
-    return null;
+  AnalysisResult _getAnalysisResultFromBytes(FileState file, List<int> bytes,
+      {String content, CompilationUnit resolvedUnit}) {
+    var unit = new AnalysisDriverResolvedUnit.fromBuffer(bytes);
+    List<AnalysisError> errors = unit.errors
+        .map((error) => new AnalysisError.forValues(
+            file.source,
+            error.offset,
+            error.length,
+            errorCodeByUniqueName(error.uniqueName),
+            error.message,
+            error.correction))
+        .toList();
+    return new AnalysisResult(_sourceFactory, file.path, file.uri, content,
+        file.contentHash, file.lineInfo, resolvedUnit, errors, unit.index);
   }
 
   /**
@@ -687,15 +693,11 @@
    * not known yet.
    */
   String _getResolvedUnitKey(FileState library, FileState file) {
-    String dependencyHash = _dependencySignatureMap[library.uri];
-    if (dependencyHash != null) {
-      ApiSignature signature = new ApiSignature();
-      signature.addUint32List(_salt);
-      signature.addString(dependencyHash);
-      signature.addString(file.contentHash);
-      return '${signature.toHex()}.resolved';
-    }
-    return null;
+    ApiSignature signature = new ApiSignature();
+    signature.addUint32List(_salt);
+    signature.addString(library.transitiveSignature);
+    signature.addString(file.contentHash);
+    return '${signature.toHex()}.resolved';
   }
 
   /**
@@ -799,7 +801,7 @@
       }
       if (anyApiChanged) {
         _logger.writeln('API signatures mismatch found for $path');
-        _dependencySignatureMap.clear();
+        // TODO(scheglov) schedule analysis of only affected files
         _filesToAnalyze.addAll(_explicitFiles);
       }
       return files[0];
@@ -999,8 +1001,13 @@
    */
   final List<AnalysisError> errors;
 
+  /**
+   * The index of the unit.
+   */
+  final AnalysisDriverUnitIndex index;
+
   AnalysisResult(this.sourceFactory, this.path, this.uri, this.content,
-      this.contentHash, this.lineInfo, this.unit, this.errors);
+      this.contentHash, this.lineInfo, this.unit, this.errors, this.index);
 }
 
 /**
@@ -1139,26 +1146,10 @@
   final FileState file;
   final Uri uri;
 
-  String _dependencySignature;
-
   _LibraryNode(this.driver, this.file, this.uri);
 
   String get dependencySignature {
-    return _dependencySignature ??=
-        driver._dependencySignatureMap.putIfAbsent(uri, () {
-      ApiSignature signature = new ApiSignature();
-      signature.addUint32List(driver._salt);
-      signature.addString(driver._sdkBundle.apiSignature);
-
-      // Add all unlinked API signatures.
-      file.transitiveFiles
-          .map((file) => file.apiSignature)
-          .forEach(signature.addBytes);
-
-      // Combine into a single hash.
-      signature.addString(uri.toString());
-      return signature.toHex();
-    });
+    return file.transitiveSignature;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index da38aca..3540d69 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/referenced_names.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -85,6 +86,7 @@
   String _content;
   String _contentHash;
   LineInfo _lineInfo;
+  Set<String> _referencedNames;
   UnlinkedUnit _unlinked;
   List<int> _apiSignature;
 
@@ -93,6 +95,7 @@
   List<FileState> _partedFiles;
   Set<FileState> _directReferencedFiles = new Set<FileState>();
   Set<FileState> _transitiveFiles;
+  String _transitiveSignature;
 
   FileState._(this._fsState, this.path, this.uri, this.source);
 
@@ -160,6 +163,11 @@
   List<FileState> get partedFiles => _partedFiles;
 
   /**
+   * The external names referenced by the file.
+   */
+  Set<String> get referencedNames => _referencedNames;
+
+  /**
    * Return the set of transitive files - the file itself and all of the
    * directly or indirectly referenced files.
    */
@@ -179,6 +187,24 @@
   }
 
   /**
+   * Return the signature of the file, based on the [transitiveFiles].
+   */
+  String get transitiveSignature {
+    if (_transitiveSignature == null) {
+      ApiSignature signature = new ApiSignature();
+      signature.addUint32List(_fsState._salt);
+      signature.addString(_fsState._sdkApiSignature);
+      signature.addInt(transitiveFiles.length);
+      transitiveFiles
+          .map((file) => file.apiSignature)
+          .forEach(signature.addBytes);
+      signature.addString(uri.toString());
+      _transitiveSignature = signature.toHex();
+    }
+    return _transitiveSignature;
+  }
+
+  /**
    * The [UnlinkedUnit] of the file.
    */
   UnlinkedUnit get unlinked => _unlinked;
@@ -253,20 +279,35 @@
         CompilationUnit unit = parse(AnalysisErrorListener.NULL_LISTENER);
         _fsState._logger.run('Create unlinked for $path', () {
           UnlinkedUnitBuilder unlinkedUnit = serializeAstUnlinked(unit);
-          bytes = unlinkedUnit.toBuffer();
+          List<String> referencedNames = computeReferencedNames(unit).toList();
+          bytes = new AnalysisDriverUnlinkedUnitBuilder(
+                  unit: unlinkedUnit, referencedNames: referencedNames)
+              .toBuffer();
           _fsState._byteStore.put(unlinkedKey, bytes);
         });
       }
     }
 
     // Read the unlinked bundle.
-    _unlinked = new UnlinkedUnit.fromBuffer(bytes);
+    var driverUnlinkedUnit = new AnalysisDriverUnlinkedUnit.fromBuffer(bytes);
+    _referencedNames = new Set<String>.from(driverUnlinkedUnit.referencedNames);
+    _unlinked = driverUnlinkedUnit.unit;
     _lineInfo = new LineInfo(_unlinked.lineStarts);
     List<int> newApiSignature = _unlinked.apiSignature;
     bool apiSignatureChanged = _apiSignature != null &&
         !_equalByteLists(_apiSignature, newApiSignature);
     _apiSignature = newApiSignature;
 
+    // If the API signature changed, flush transitive signatures.
+    if (apiSignatureChanged) {
+      for (FileState file in _fsState._uriToFile.values) {
+        if (file._transitiveFiles != null &&
+            file._transitiveFiles.contains(this)) {
+          file._transitiveSignature = null;
+        }
+      }
+    }
+
     // This file is potentially not a library for its previous parts anymore.
     if (_partedFiles != null) {
       for (FileState part in _partedFiles) {
@@ -382,6 +423,7 @@
   final SourceFactory _sourceFactory;
   final AnalysisOptions _analysisOptions;
   final Uint32List _salt;
+  final String _sdkApiSignature;
 
   /**
    * Mapping from a URI to the corresponding [FileState].
@@ -412,7 +454,8 @@
       this._resourceProvider,
       this._sourceFactory,
       this._analysisOptions,
-      this._salt) {
+      this._salt,
+      this._sdkApiSignature) {
     _testView = new FileSystemStateTestView(this);
   }
 
@@ -502,9 +545,15 @@
 
   FileSystemStateTestView(this.state);
 
-  Set<FileState> get filesWithoutTransitive {
+  Set<FileState> get filesWithoutTransitiveFiles {
     return state._uriToFile.values
         .where((f) => f._transitiveFiles == null)
         .toSet();
   }
+
+  Set<FileState> get filesWithoutTransitiveSignature {
+    return state._uriToFile.values
+        .where((f) => f._transitiveSignature == null)
+        .toSet();
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
new file mode 100644
index 0000000..8191ca4
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -0,0 +1,800 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart'
+    show AnalysisDriverUnitIndexBuilder;
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Return the [CompilationUnitElement] that should be used for [element].
+ * Throw [StateError] if the [element] is not linked into a unit.
+ */
+CompilationUnitElement getUnitElement(Element element) {
+  for (Element e = element; e != null; e = e.enclosingElement) {
+    if (e is CompilationUnitElement) {
+      return e;
+    }
+    if (e is LibraryElement) {
+      return e.definingCompilationUnit;
+    }
+  }
+  throw new StateError('Element not contained in compilation unit: $element');
+}
+
+/**
+ * Index the [unit] into a new [AnalysisDriverUnitIndexBuilder].
+ */
+AnalysisDriverUnitIndexBuilder indexUnit(CompilationUnit unit) {
+  return new _IndexAssembler().assemble(unit);
+}
+
+/**
+ * Information about an element that is actually put into index for some other
+ * related element. For example for a synthetic getter this is the corresponding
+ * non-synthetic field and [IndexSyntheticElementKind.getter] as the [kind].
+ */
+class IndexElementInfo {
+  final Element element;
+  final IndexSyntheticElementKind kind;
+
+  factory IndexElementInfo(Element element) {
+    IndexSyntheticElementKind kind = IndexSyntheticElementKind.notSynthetic;
+    ElementKind elementKind = element.kind;
+    if (elementKind == ElementKind.LIBRARY ||
+        elementKind == ElementKind.COMPILATION_UNIT) {
+      kind = IndexSyntheticElementKind.unit;
+    } else if (element.isSynthetic) {
+      if (elementKind == ElementKind.CONSTRUCTOR) {
+        kind = IndexSyntheticElementKind.constructor;
+        element = element.enclosingElement;
+      } else if (elementKind == ElementKind.FUNCTION &&
+          element.name == 'loadLibrary') {
+        kind = IndexSyntheticElementKind.loadLibrary;
+        element = element.library;
+      } else if (elementKind == ElementKind.FIELD) {
+        FieldElement field = element;
+        kind = IndexSyntheticElementKind.field;
+        element = field.getter ?? field.setter;
+      } else if (elementKind == ElementKind.GETTER ||
+          elementKind == ElementKind.SETTER) {
+        PropertyAccessorElement accessor = element;
+        Element enclosing = element.enclosingElement;
+        bool isEnumGetter = enclosing is ClassElement && enclosing.isEnum;
+        if (isEnumGetter && accessor.name == 'index') {
+          kind = IndexSyntheticElementKind.enumIndex;
+          element = enclosing;
+        } else if (isEnumGetter && accessor.name == 'values') {
+          kind = IndexSyntheticElementKind.enumValues;
+          element = enclosing;
+        } else {
+          kind = accessor.isGetter
+              ? IndexSyntheticElementKind.getter
+              : IndexSyntheticElementKind.setter;
+          element = accessor.variable;
+        }
+      } else if (elementKind == ElementKind.TOP_LEVEL_VARIABLE) {
+        TopLevelVariableElement property = element;
+        kind = IndexSyntheticElementKind.topLevelVariable;
+        element = property.getter ?? property.setter;
+      } else {
+        throw new ArgumentError(
+            'Unsupported synthetic element ${element.runtimeType}');
+      }
+    }
+    return new IndexElementInfo._(element, kind);
+  }
+
+  IndexElementInfo._(this.element, this.kind);
+}
+
+/**
+ * Information about an element referenced in index.
+ */
+class _ElementInfo {
+  /**
+   * The identifier of the [CompilationUnitElement] containing this element.
+   */
+  final int unitId;
+
+  /**
+   * The identifier of the top-level name, or `null` if the element is a
+   * reference to the unit.
+   */
+  final _StringInfo nameIdUnitMember;
+
+  /**
+   * The identifier of the class member name, or `null` if the element is not a
+   * class member or a named parameter of a class member.
+   */
+  final _StringInfo nameIdClassMember;
+
+  /**
+   * The identifier of the named parameter name, or `null` if the element is not
+   * a named parameter.
+   */
+  final _StringInfo nameIdParameter;
+
+  /**
+   * The kind of the element.
+   */
+  final IndexSyntheticElementKind kind;
+
+  /**
+   * The unique id of the element.  It is set after indexing of the whole
+   * package is done and we are assembling the full package index.
+   */
+  int id;
+
+  _ElementInfo(this.unitId, this.nameIdUnitMember, this.nameIdClassMember,
+      this.nameIdParameter, this.kind);
+}
+
+/**
+ * Information about a single relation in a single compilation unit.
+ */
+class _ElementRelationInfo {
+  final _ElementInfo elementInfo;
+  final IndexRelationKind kind;
+  final int offset;
+  final int length;
+  final bool isQualified;
+
+  _ElementRelationInfo(
+      this.elementInfo, this.kind, this.offset, this.length, this.isQualified);
+}
+
+/**
+ * Assembler of a single [CompilationUnit] index.
+ *
+ * The intended usage sequence:
+ *
+ *  - Call [addElementRelation] for each element relation found in the unit.
+ *  - Call [addNameRelation] for each name relation found in the unit.
+ *  - Assign ids to all the [_ElementInfo] in [elementRelations].
+ *  - Call [assemble] to produce the final unit index.
+ */
+class _IndexAssembler {
+  /**
+   * The string to use in place of the `null` string.
+   */
+  static const NULL_STRING = '--nullString--';
+
+  /**
+   * Map associating referenced elements with their [_ElementInfo]s.
+   */
+  final Map<Element, _ElementInfo> elementMap = {};
+
+  /**
+   * Map associating [CompilationUnitElement]s with their identifiers, which
+   * are indices into [unitLibraryUris] and [unitUnitUris].
+   */
+  final Map<CompilationUnitElement, int> unitMap = {};
+
+  /**
+   * The fields [unitLibraryUris] and [unitUnitUris] are used together to
+   * describe each unique [CompilationUnitElement].
+   *
+   * This field contains the library URI of a unit.
+   */
+  final List<_StringInfo> unitLibraryUris = [];
+
+  /**
+   * The fields [unitLibraryUris] and [unitUnitUris] are used together to
+   * describe each unique [CompilationUnitElement].
+   *
+   * This field contains the unit URI of a unit, which might be the same as
+   * the library URI for the defining unit, or a different one for a part.
+   */
+  final List<_StringInfo> unitUnitUris = [];
+
+  /**
+   * Map associating strings with their [_StringInfo]s.
+   */
+  final Map<String, _StringInfo> stringMap = {};
+
+  /**
+   * All element relations.
+   */
+  final List<_ElementRelationInfo> elementRelations = [];
+
+  /**
+   * All unresolved name relations.
+   */
+  final List<_NameRelationInfo> nameRelations = [];
+
+  /**
+   * The [_StringInfo] to use for `null` strings.
+   */
+  _StringInfo nullString;
+
+  _IndexAssembler() {
+    nullString = _getStringInfo(NULL_STRING);
+  }
+
+  void addElementRelation(Element element, IndexRelationKind kind, int offset,
+      int length, bool isQualified) {
+    _ElementInfo elementInfo = _getElementInfo(element);
+    elementRelations.add(new _ElementRelationInfo(
+        elementInfo, kind, offset, length, isQualified));
+  }
+
+  void addNameRelation(
+      String name, IndexRelationKind kind, int offset, bool isQualified) {
+    _StringInfo nameId = _getStringInfo(name);
+    nameRelations.add(new _NameRelationInfo(nameId, kind, offset, isQualified));
+  }
+
+  /**
+   * Index the [unit] and assemble a new [AnalysisDriverUnitIndexBuilder].
+   */
+  AnalysisDriverUnitIndexBuilder assemble(CompilationUnit unit) {
+    unit.accept(new _IndexContributor(this));
+    // sort strings end set IDs
+    List<_StringInfo> stringInfoList = stringMap.values.toList();
+    stringInfoList.sort((a, b) {
+      return a.value.compareTo(b.value);
+    });
+    for (int i = 0; i < stringInfoList.length; i++) {
+      stringInfoList[i].id = i;
+    }
+    // sort elements and set IDs
+    List<_ElementInfo> elementInfoList = elementMap.values.toList();
+    elementInfoList.sort((a, b) {
+      int delta;
+      delta = a.nameIdUnitMember.id - b.nameIdUnitMember.id;
+      if (delta != null) {
+        return delta;
+      }
+      delta = a.nameIdClassMember.id - b.nameIdClassMember.id;
+      if (delta != null) {
+        return delta;
+      }
+      return a.nameIdParameter.id - b.nameIdParameter.id;
+    });
+    for (int i = 0; i < elementInfoList.length; i++) {
+      elementInfoList[i].id = i;
+    }
+    // Sort element and name relations.
+    elementRelations.sort((a, b) {
+      return a.elementInfo.id - b.elementInfo.id;
+    });
+    nameRelations.sort((a, b) {
+      return a.nameInfo.id - b.nameInfo.id;
+    });
+    return new AnalysisDriverUnitIndexBuilder(
+        strings: stringInfoList.map((s) => s.value).toList(),
+        nullStringId: nullString.id,
+        unitLibraryUris: unitLibraryUris.map((s) => s.id).toList(),
+        unitUnitUris: unitUnitUris.map((s) => s.id).toList(),
+        elementKinds: elementInfoList.map((e) => e.kind).toList(),
+        elementUnits: elementInfoList.map((e) => e.unitId).toList(),
+        elementNameUnitMemberIds:
+            elementInfoList.map((e) => e.nameIdUnitMember.id).toList(),
+        elementNameClassMemberIds:
+            elementInfoList.map((e) => e.nameIdClassMember.id).toList(),
+        elementNameParameterIds:
+            elementInfoList.map((e) => e.nameIdParameter.id).toList(),
+        usedElements: elementRelations.map((r) => r.elementInfo.id).toList(),
+        usedElementKinds: elementRelations.map((r) => r.kind).toList(),
+        usedElementOffsets: elementRelations.map((r) => r.offset).toList(),
+        usedElementLengths: elementRelations.map((r) => r.length).toList(),
+        usedElementIsQualifiedFlags:
+            elementRelations.map((r) => r.isQualified).toList(),
+        usedNames: nameRelations.map((r) => r.nameInfo.id).toList(),
+        usedNameKinds: nameRelations.map((r) => r.kind).toList(),
+        usedNameOffsets: nameRelations.map((r) => r.offset).toList(),
+        usedNameIsQualifiedFlags:
+            nameRelations.map((r) => r.isQualified).toList());
+  }
+
+  /**
+   * Return the unique [_ElementInfo] corresponding the [element].  The field
+   * [_ElementInfo.id] is filled by [assemble] during final sorting.
+   */
+  _ElementInfo _getElementInfo(Element element) {
+    if (element is Member) {
+      element = (element as Member).baseElement;
+    }
+    return elementMap.putIfAbsent(element, () {
+      CompilationUnitElement unitElement = getUnitElement(element);
+      int unitId = _getUnitId(unitElement);
+      return _newElementInfo(unitId, element);
+    });
+  }
+
+  /**
+   * Return the unique [_StringInfo] corresponding the given [string].  The
+   * field [_StringInfo.id] is filled by [assemble] during final sorting.
+   */
+  _StringInfo _getStringInfo(String string) {
+    return stringMap.putIfAbsent(string, () {
+      return new _StringInfo(string);
+    });
+  }
+
+  /**
+   * Add information about [unitElement] to [unitUnitUris] and
+   * [unitLibraryUris] if necessary, and return the location in those
+   * arrays representing [unitElement].
+   */
+  int _getUnitId(CompilationUnitElement unitElement) {
+    return unitMap.putIfAbsent(unitElement, () {
+      assert(unitLibraryUris.length == unitUnitUris.length);
+      int id = unitUnitUris.length;
+      unitLibraryUris.add(_getUriInfo(unitElement.library.source.uri));
+      unitUnitUris.add(_getUriInfo(unitElement.source.uri));
+      return id;
+    });
+  }
+
+  /**
+   * Return the unique [_StringInfo] corresponding [uri].  The field
+   * [_StringInfo.id] is filled by [assemble] during final sorting.
+   */
+  _StringInfo _getUriInfo(Uri uri) {
+    String str = uri.toString();
+    return _getStringInfo(str);
+  }
+
+  /**
+   * Return a new [_ElementInfo] for the given [element] in the given [unitId].
+   * This method is static, so it cannot add any information to the index.
+   */
+  _ElementInfo _newElementInfo(int unitId, Element element) {
+    IndexElementInfo info = new IndexElementInfo(element);
+    element = info.element;
+    // Prepare name identifiers.
+    _StringInfo nameIdParameter = nullString;
+    _StringInfo nameIdClassMember = nullString;
+    _StringInfo nameIdUnitMember = nullString;
+    if (element is ParameterElement) {
+      nameIdParameter = _getStringInfo(element.name);
+      element = element.enclosingElement;
+    }
+    if (element?.enclosingElement is ClassElement) {
+      nameIdClassMember = _getStringInfo(element.name);
+      element = element.enclosingElement;
+    }
+    if (element?.enclosingElement is CompilationUnitElement) {
+      nameIdUnitMember = _getStringInfo(element.name);
+    }
+    return new _ElementInfo(unitId, nameIdUnitMember, nameIdClassMember,
+        nameIdParameter, info.kind);
+  }
+}
+
+/**
+ * Visits a resolved AST and adds relationships into the [assembler].
+ */
+class _IndexContributor extends GeneralizingAstVisitor {
+  final _IndexAssembler assembler;
+
+  _IndexContributor(this.assembler);
+
+  void recordIsAncestorOf(Element descendant) {
+    _recordIsAncestorOf(descendant, descendant, false, <ClassElement>[]);
+  }
+
+  /**
+   * Record that the name [node] has a relation of the given [kind].
+   */
+  void recordNameRelation(
+      SimpleIdentifier node, IndexRelationKind kind, bool isQualified) {
+    if (node != null) {
+      assembler.addNameRelation(node.name, kind, node.offset, isQualified);
+    }
+  }
+
+  /**
+   * Record reference to the given operator [Element].
+   */
+  void recordOperatorReference(Token operator, Element element) {
+    recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the location
+   * of the given [node].  The flag [isQualified] is `true` if [node] has an
+   * explicit or implicit qualifier, so cannot be shadowed by a local
+   * declaration.
+   */
+  void recordRelation(
+      Element element, IndexRelationKind kind, AstNode node, bool isQualified) {
+    if (element != null && node != null) {
+      recordRelationOffset(
+          element, kind, node.offset, node.length, isQualified);
+    }
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the given
+   * [offset] and [length].  The flag [isQualified] is `true` if the relation
+   * has an explicit or implicit qualifier, so [element] cannot be shadowed by
+   * a local declaration.
+   */
+  void recordRelationOffset(Element element, IndexRelationKind kind, int offset,
+      int length, bool isQualified) {
+    // Ignore elements that can't be referenced outside of the unit.
+    ElementKind elementKind = element?.kind;
+    if (elementKind == null ||
+        elementKind == ElementKind.DYNAMIC ||
+        elementKind == ElementKind.LABEL ||
+        elementKind == ElementKind.LOCAL_VARIABLE ||
+        elementKind == ElementKind.PREFIX ||
+        elementKind == ElementKind.TYPE_PARAMETER ||
+        elementKind == ElementKind.FUNCTION &&
+            element is FunctionElement &&
+            element.enclosingElement is ExecutableElement ||
+        elementKind == ElementKind.PARAMETER &&
+            element is ParameterElement &&
+            element.parameterKind != ParameterKind.NAMED ||
+        false) {
+      return;
+    }
+    // Add the relation.
+    assembler.addElementRelation(element, kind, offset, length, isQualified);
+  }
+
+  /**
+   * Record that [element] has a relation of the given [kind] at the location
+   * of the given [token].
+   */
+  void recordRelationToken(
+      Element element, IndexRelationKind kind, Token token) {
+    if (element != null && token != null) {
+      recordRelationOffset(element, kind, token.offset, token.length, true);
+    }
+  }
+
+  /**
+   * Record a relation between a super [typeName] and its [Element].
+   */
+  void recordSuperType(TypeName typeName, IndexRelationKind kind) {
+    Identifier name = typeName?.name;
+    if (name != null) {
+      Element element = name.staticElement;
+      bool isQualified;
+      SimpleIdentifier relNode;
+      if (name is PrefixedIdentifier) {
+        isQualified = true;
+        relNode = name.identifier;
+      } else {
+        isQualified = false;
+        relNode = name;
+      }
+      recordRelation(element, kind, relNode, isQualified);
+      recordRelation(
+          element, IndexRelationKind.IS_REFERENCED_BY, relNode, isQualified);
+      typeName.typeArguments?.accept(this);
+    }
+  }
+
+  void recordUriReference(Element element, UriBasedDirective directive) {
+    recordRelation(
+        element, IndexRelationKind.IS_REFERENCED_BY, directive.uri, true);
+  }
+
+  @override
+  visitAssignmentExpression(AssignmentExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitAssignmentExpression(node);
+  }
+
+  @override
+  visitBinaryExpression(BinaryExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitBinaryExpression(node);
+  }
+
+  @override
+  visitClassDeclaration(ClassDeclaration node) {
+    if (node.extendsClause == null) {
+      ClassElement objectElement = node.element.supertype?.element;
+      recordRelationOffset(objectElement, IndexRelationKind.IS_EXTENDED_BY,
+          node.name.offset, 0, true);
+    }
+    recordIsAncestorOf(node.element);
+    super.visitClassDeclaration(node);
+  }
+
+  @override
+  visitClassTypeAlias(ClassTypeAlias node) {
+    recordIsAncestorOf(node.element);
+    super.visitClassTypeAlias(node);
+  }
+
+  @override
+  visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    SimpleIdentifier fieldName = node.fieldName;
+    if (fieldName != null) {
+      Element element = fieldName.staticElement;
+      recordRelation(element, IndexRelationKind.IS_WRITTEN_BY, fieldName, true);
+    }
+    node.expression?.accept(this);
+  }
+
+  @override
+  visitConstructorName(ConstructorName node) {
+    ConstructorElement element = node.staticElement;
+    element = _getActualConstructorElement(element);
+    // record relation
+    if (node.name != null) {
+      int offset = node.period.offset;
+      int length = node.name.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.type.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    node.type.accept(this);
+  }
+
+  @override
+  visitExportDirective(ExportDirective node) {
+    ExportElement element = node.element;
+    recordUriReference(element?.exportedLibrary, node);
+    super.visitExportDirective(node);
+  }
+
+  @override
+  visitExtendsClause(ExtendsClause node) {
+    recordSuperType(node.superclass, IndexRelationKind.IS_EXTENDED_BY);
+  }
+
+  @override
+  visitImplementsClause(ImplementsClause node) {
+    for (TypeName typeName in node.interfaces) {
+      recordSuperType(typeName, IndexRelationKind.IS_IMPLEMENTED_BY);
+    }
+  }
+
+  @override
+  visitImportDirective(ImportDirective node) {
+    ImportElement element = node.element;
+    recordUriReference(element?.importedLibrary, node);
+    super.visitImportDirective(node);
+  }
+
+  @override
+  visitIndexExpression(IndexExpression node) {
+    MethodElement element = node.bestElement;
+    if (element is MethodElement) {
+      Token operator = node.leftBracket;
+      recordRelationToken(element, IndexRelationKind.IS_INVOKED_BY, operator);
+    }
+    super.visitIndexExpression(node);
+  }
+
+  @override
+  visitLibraryIdentifier(LibraryIdentifier node) {}
+
+  @override
+  visitMethodInvocation(MethodInvocation node) {
+    SimpleIdentifier name = node.methodName;
+    Element element = name.bestElement;
+    // unresolved name invocation
+    bool isQualified = node.realTarget != null;
+    if (element == null) {
+      recordNameRelation(name, IndexRelationKind.IS_INVOKED_BY, isQualified);
+    }
+    // element invocation
+    IndexRelationKind kind = element is ClassElement
+        ? IndexRelationKind.IS_REFERENCED_BY
+        : IndexRelationKind.IS_INVOKED_BY;
+    recordRelation(element, kind, name, isQualified);
+    node.target?.accept(this);
+    node.argumentList?.accept(this);
+  }
+
+  @override
+  visitPartDirective(PartDirective node) {
+    Element element = node.element;
+    recordUriReference(element, node);
+    super.visitPartDirective(node);
+  }
+
+  @override
+  visitPostfixExpression(PostfixExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitPostfixExpression(node);
+  }
+
+  @override
+  visitPrefixExpression(PrefixExpression node) {
+    recordOperatorReference(node.operator, node.bestElement);
+    super.visitPrefixExpression(node);
+  }
+
+  @override
+  visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+    ConstructorElement element = node.staticElement;
+    if (node.constructorName != null) {
+      int offset = node.period.offset;
+      int length = node.constructorName.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.thisKeyword.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    super.visitRedirectingConstructorInvocation(node);
+  }
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    // name in declaration
+    if (node.inDeclarationContext()) {
+      return;
+    }
+    Element element = node.bestElement;
+    // record unresolved name reference
+    bool isQualified = _isQualified(node);
+    if (element == null) {
+      bool inGetterContext = node.inGetterContext();
+      bool inSetterContext = node.inSetterContext();
+      IndexRelationKind kind;
+      if (inGetterContext && inSetterContext) {
+        kind = IndexRelationKind.IS_READ_WRITTEN_BY;
+      } else if (inGetterContext) {
+        kind = IndexRelationKind.IS_READ_BY;
+      } else {
+        kind = IndexRelationKind.IS_WRITTEN_BY;
+      }
+      recordNameRelation(node, kind, isQualified);
+    }
+    // this.field parameter
+    if (element is FieldFormalParameterElement) {
+      AstNode parent = node.parent;
+      IndexRelationKind kind =
+          parent is FieldFormalParameter && parent.identifier == node
+              ? IndexRelationKind.IS_WRITTEN_BY
+              : IndexRelationKind.IS_REFERENCED_BY;
+      recordRelation(element.field, kind, node, true);
+      return;
+    }
+    // ignore a local reference to a parameter
+    if (element is ParameterElement && node.parent is! Label) {
+      return;
+    }
+    // record specific relations
+    recordRelation(
+        element, IndexRelationKind.IS_REFERENCED_BY, node, isQualified);
+  }
+
+  @override
+  visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    ConstructorElement element = node.staticElement;
+    if (node.constructorName != null) {
+      int offset = node.period.offset;
+      int length = node.constructorName.end - offset;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+    } else {
+      int offset = node.superKeyword.end;
+      recordRelationOffset(
+          element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+    }
+    node.argumentList?.accept(this);
+  }
+
+  @override
+  visitTypeName(TypeName node) {
+    AstNode parent = node.parent;
+    if (parent is ClassTypeAlias && parent.superclass == node) {
+      recordSuperType(node, IndexRelationKind.IS_EXTENDED_BY);
+    } else {
+      super.visitTypeName(node);
+    }
+  }
+
+  @override
+  visitWithClause(WithClause node) {
+    for (TypeName typeName in node.mixinTypes) {
+      recordSuperType(typeName, IndexRelationKind.IS_MIXED_IN_BY);
+    }
+  }
+
+  /**
+   * If the given [constructor] is a synthetic constructor created for a
+   * [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+   * which is invoked.  Return `null` if a redirection cycle is detected.
+   */
+  ConstructorElement _getActualConstructorElement(
+      ConstructorElement constructor) {
+    Set<ConstructorElement> seenConstructors = new Set<ConstructorElement>();
+    while (constructor != null &&
+        constructor.isSynthetic &&
+        constructor.redirectedConstructor != null) {
+      constructor = constructor.redirectedConstructor;
+      // fail if a cycle is detected
+      if (!seenConstructors.add(constructor)) {
+        return null;
+      }
+    }
+    return constructor;
+  }
+
+  /**
+   * Return `true` if [node] has an explicit or implicit qualifier, so that it
+   * cannot be shadowed by a local declaration.
+   */
+  bool _isQualified(SimpleIdentifier node) {
+    if (node.isQualified) {
+      return true;
+    }
+    AstNode parent = node.parent;
+    return parent is Combinator || parent is Label;
+  }
+
+  void _recordIsAncestorOf(Element descendant, ClassElement ancestor,
+      bool includeThis, List<ClassElement> visitedElements) {
+    if (ancestor == null) {
+      return;
+    }
+    if (visitedElements.contains(ancestor)) {
+      return;
+    }
+    visitedElements.add(ancestor);
+    if (includeThis) {
+      int offset = descendant.nameOffset;
+      int length = descendant.nameLength;
+      assembler.addElementRelation(
+          ancestor, IndexRelationKind.IS_ANCESTOR_OF, offset, length, false);
+    }
+    {
+      InterfaceType superType = ancestor.supertype;
+      if (superType != null) {
+        _recordIsAncestorOf(
+            descendant, superType.element, true, visitedElements);
+      }
+    }
+    for (InterfaceType mixinType in ancestor.mixins) {
+      _recordIsAncestorOf(descendant, mixinType.element, true, visitedElements);
+    }
+    for (InterfaceType implementedType in ancestor.interfaces) {
+      _recordIsAncestorOf(
+          descendant, implementedType.element, true, visitedElements);
+    }
+  }
+}
+
+/**
+ * Information about a single name relation in single compilation unit.
+ */
+class _NameRelationInfo {
+  final _StringInfo nameInfo;
+  final IndexRelationKind kind;
+  final int offset;
+  final bool isQualified;
+
+  _NameRelationInfo(this.nameInfo, this.kind, this.offset, this.isQualified);
+}
+
+/**
+ * Information about a string referenced in the index.
+ */
+class _StringInfo {
+  /**
+   * The value of the string.
+   */
+  final String value;
+
+  /**
+   * The unique id of the string.  It is set after indexing of the whole
+   * package is done and we are assembling the full package index.
+   */
+  int id;
+
+  _StringInfo(this.value);
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/search.dart b/pkg/analyzer/lib/src/dart/analysis/search.dart
new file mode 100644
index 0000000..e28a5b6
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/search.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+
+/**
+ * Search support for an [AnalysisDriver].
+ */
+class Search {
+  final AnalysisDriver _driver;
+
+  Search(this._driver);
+
+  /**
+   * Returns references to the element at the given [offset] in the file with
+   * the given [path].
+   */
+  Future<List<SearchResult>> references(String path, int offset) async {
+    // Search only in added files.
+    if (!_driver.addedFiles.contains(path)) {
+      return const <SearchResult>[];
+    }
+
+    AnalysisResult analysisResult = await _driver.getResult(path);
+    CompilationUnit unit = analysisResult.unit;
+
+    // Prepare the node.
+    AstNode node = new NodeLocator(offset).searchWithin(unit);
+    if (node == null) {
+      return const <SearchResult>[];
+    }
+
+    // Prepare the element.
+    Element element = ElementLocator.locate(node);
+    if (element == null) {
+      return const <SearchResult>[];
+    }
+
+    ElementKind kind = element.kind;
+    if (kind == ElementKind.LABEL || kind == ElementKind.LOCAL_VARIABLE) {
+      Block block = node.getAncestor((n) => n is Block);
+      return _searchReferences_Local(element, unit.element, block);
+    }
+    // TODO(scheglov) support other kinds
+    return [];
+  }
+
+  Future<List<SearchResult>> _searchReferences_Local(
+      Element element,
+      CompilationUnitElement enclosingUnitElement,
+      AstNode enclosingNode) async {
+    _LocalReferencesVisitor visitor =
+        new _LocalReferencesVisitor(element, enclosingUnitElement);
+    enclosingNode?.accept(visitor);
+    return visitor.matches;
+  }
+}
+
+/**
+ * A single search result.
+ */
+class SearchResult {
+  /**
+   * The element that is used at this result.
+   */
+  final Element element;
+
+  /**
+   * The deep most element that contains this result.
+   */
+  final Element enclosingElement;
+
+  /**
+   * The kind of the [element] usage.
+   */
+  final SearchResultKind kind;
+
+  /**
+   * The offset relative to the beginning of the containing file.
+   */
+  final int offset;
+
+  /**
+   * The length of the usage in the containing file context.
+   */
+  final int length;
+
+  /**
+   * Is `true` if a field or a method is using with a qualifier.
+   */
+  final bool isResolved;
+
+  /**
+   * Is `true` if the result is a resolved reference to [element].
+   */
+  final bool isQualified;
+
+  SearchResult._(this.element, this.enclosingElement, this.kind, this.offset,
+      this.length, this.isResolved, this.isQualified);
+
+  @override
+  String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write("SearchResult(kind=");
+    buffer.write(kind);
+    buffer.write(", offset=");
+    buffer.write(offset);
+    buffer.write(", length=");
+    buffer.write(length);
+    buffer.write(", isResolved=");
+    buffer.write(isResolved);
+    buffer.write(", isQualified=");
+    buffer.write(isQualified);
+    buffer.write(", enclosingElement=");
+    buffer.write(enclosingElement);
+    buffer.write(")");
+    return buffer.toString();
+  }
+}
+
+/**
+ * The kind of reference in a [SearchResult].
+ */
+enum SearchResultKind { READ, READ_WRITE, WRITE, INVOCATION, REFERENCE }
+
+/**
+ * A visitor that finds the deep-most [Element] that contains the [offset].
+ */
+class _ContainingElementFinder extends GeneralizingElementVisitor {
+  final int offset;
+  Element containingElement;
+
+  _ContainingElementFinder(this.offset);
+
+  visitElement(Element element) {
+    if (element is ElementImpl) {
+      if (element.codeOffset != null &&
+          element.codeOffset <= offset &&
+          offset <= element.codeOffset + element.codeLength) {
+        containingElement = element;
+        super.visitElement(element);
+      }
+    }
+  }
+}
+
+/**
+ * Visitor that adds [SearchResult]s for local elements of a block, method,
+ * class or a library - labels, local functions, local variables and parameters,
+ * type parameters, import prefixes.
+ */
+class _LocalReferencesVisitor extends RecursiveAstVisitor {
+  final List<SearchResult> matches = <SearchResult>[];
+
+  final Element element;
+  final CompilationUnitElement enclosingUnitElement;
+
+  _LocalReferencesVisitor(this.element, this.enclosingUnitElement);
+
+  @override
+  visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.inDeclarationContext()) {
+      return;
+    }
+    if (node.staticElement == element) {
+      AstNode parent = node.parent;
+      SearchResultKind kind = SearchResultKind.REFERENCE;
+      if (element is FunctionElement) {
+        if (parent is MethodInvocation && parent.methodName == node) {
+          kind = SearchResultKind.INVOCATION;
+        }
+      } else if (element is VariableElement) {
+        bool isGet = node.inGetterContext();
+        bool isSet = node.inSetterContext();
+        if (isGet && isSet) {
+          kind = SearchResultKind.READ_WRITE;
+        } else if (isGet) {
+          if (parent is MethodInvocation && parent.methodName == node) {
+            kind = SearchResultKind.INVOCATION;
+          } else {
+            kind = SearchResultKind.READ;
+          }
+        } else if (isSet) {
+          kind = SearchResultKind.WRITE;
+        }
+      }
+      _addMatch(node, kind);
+    }
+  }
+
+  void _addMatch(AstNode node, SearchResultKind kind) {
+    bool isQualified = node.parent is Label;
+    var finder = new _ContainingElementFinder(node.offset);
+    enclosingUnitElement.accept(finder);
+    matches.add(new SearchResult._(element, finder.containingElement, kind,
+        node.offset, node.length, true, isQualified));
+  }
+}
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 1d91db3..655f5fd 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -131,6 +131,7 @@
 
 class AnalysisDriverResolvedUnitBuilder extends Object with _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
   List<AnalysisDriverUnitErrorBuilder> _errors;
+  AnalysisDriverUnitIndexBuilder _index;
 
   @override
   List<AnalysisDriverUnitErrorBuilder> get errors => _errors ??= <AnalysisDriverUnitErrorBuilder>[];
@@ -142,14 +143,26 @@
     this._errors = value;
   }
 
-  AnalysisDriverResolvedUnitBuilder({List<AnalysisDriverUnitErrorBuilder> errors})
-    : _errors = errors;
+  @override
+  AnalysisDriverUnitIndexBuilder get index => _index;
+
+  /**
+   * The index of the unit.
+   */
+  void set index(AnalysisDriverUnitIndexBuilder value) {
+    this._index = value;
+  }
+
+  AnalysisDriverResolvedUnitBuilder({List<AnalysisDriverUnitErrorBuilder> errors, AnalysisDriverUnitIndexBuilder index})
+    : _errors = errors,
+      _index = index;
 
   /**
    * Flush [informative] data recursively.
    */
   void flushInformative() {
     _errors?.forEach((b) => b.flushInformative());
+    _index?.flushInformative();
   }
 
   /**
@@ -164,6 +177,8 @@
         x?.collectApiSignature(signature);
       }
     }
+    signature.addBool(this._index != null);
+    this._index?.collectApiSignature(signature);
   }
 
   List<int> toBuffer() {
@@ -173,13 +188,20 @@
 
   fb.Offset finish(fb.Builder fbBuilder) {
     fb.Offset offset_errors;
+    fb.Offset offset_index;
     if (!(_errors == null || _errors.isEmpty)) {
       offset_errors = fbBuilder.writeList(_errors.map((b) => b.finish(fbBuilder)).toList());
     }
+    if (_index != null) {
+      offset_index = _index.finish(fbBuilder);
+    }
     fbBuilder.startTable();
     if (offset_errors != null) {
       fbBuilder.addOffset(0, offset_errors);
     }
+    if (offset_index != null) {
+      fbBuilder.addOffset(1, offset_index);
+    }
     return fbBuilder.endTable();
   }
 }
@@ -203,12 +225,19 @@
   _AnalysisDriverResolvedUnitImpl(this._bc, this._bcOffset);
 
   List<idl.AnalysisDriverUnitError> _errors;
+  idl.AnalysisDriverUnitIndex _index;
 
   @override
   List<idl.AnalysisDriverUnitError> get errors {
     _errors ??= const fb.ListReader<idl.AnalysisDriverUnitError>(const _AnalysisDriverUnitErrorReader()).vTableGet(_bc, _bcOffset, 0, const <idl.AnalysisDriverUnitError>[]);
     return _errors;
   }
+
+  @override
+  idl.AnalysisDriverUnitIndex get index {
+    _index ??= const _AnalysisDriverUnitIndexReader().vTableGet(_bc, _bcOffset, 1, null);
+    return _index;
+  }
 }
 
 abstract class _AnalysisDriverResolvedUnitMixin implements idl.AnalysisDriverResolvedUnit {
@@ -216,12 +245,14 @@
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
     if (errors.isNotEmpty) _result["errors"] = errors.map((_value) => _value.toJson()).toList();
+    if (index != null) _result["index"] = index.toJson();
     return _result;
   }
 
   @override
   Map<String, Object> toMap() => {
     "errors": errors,
+    "index": index,
   };
 
   @override
@@ -419,6 +450,871 @@
   String toString() => convert.JSON.encode(toJson());
 }
 
+class AnalysisDriverUnitIndexBuilder extends Object with _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+  List<idl.IndexSyntheticElementKind> _elementKinds;
+  List<int> _elementNameClassMemberIds;
+  List<int> _elementNameParameterIds;
+  List<int> _elementNameUnitMemberIds;
+  List<int> _elementUnits;
+  int _nullStringId;
+  List<String> _strings;
+  List<int> _unitLibraryUris;
+  List<int> _unitUnitUris;
+  List<bool> _usedElementIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedElementKinds;
+  List<int> _usedElementLengths;
+  List<int> _usedElementOffsets;
+  List<int> _usedElements;
+  List<bool> _usedNameIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedNameKinds;
+  List<int> _usedNameOffsets;
+  List<int> _usedNames;
+
+  @override
+  List<idl.IndexSyntheticElementKind> get elementKinds => _elementKinds ??= <idl.IndexSyntheticElementKind>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  void set elementKinds(List<idl.IndexSyntheticElementKind> value) {
+    this._elementKinds = value;
+  }
+
+  @override
+  List<int> get elementNameClassMemberIds => _elementNameClassMemberIds ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the class member element name, or `null` if the element
+   * is a top-level element.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  void set elementNameClassMemberIds(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._elementNameClassMemberIds = value;
+  }
+
+  @override
+  List<int> get elementNameParameterIds => _elementNameParameterIds ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the named parameter name, or `null` if the element is not
+   * a named parameter.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  void set elementNameParameterIds(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._elementNameParameterIds = value;
+  }
+
+  @override
+  List<int> get elementNameUnitMemberIds => _elementNameUnitMemberIds ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the top-level element name, or `null` if the element is
+   * the unit.  The list is sorted in ascending order, so that the client can
+   * quickly check whether an element is referenced in this index.
+   */
+  void set elementNameUnitMemberIds(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._elementNameUnitMemberIds = value;
+  }
+
+  @override
+  List<int> get elementUnits => _elementUnits ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  void set elementUnits(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._elementUnits = value;
+  }
+
+  @override
+  int get nullStringId => _nullStringId ??= 0;
+
+  /**
+   * Identifier of the null string in [strings].
+   */
+  void set nullStringId(int value) {
+    assert(value == null || value >= 0);
+    this._nullStringId = value;
+  }
+
+  @override
+  List<String> get strings => _strings ??= <String>[];
+
+  /**
+   * List of unique element strings used in this index.  The list is sorted in
+   * ascending order, so that the client can quickly check the presence of a
+   * string in this index.
+   */
+  void set strings(List<String> value) {
+    this._strings = value;
+  }
+
+  @override
+  List<int> get unitLibraryUris => _unitLibraryUris ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  void set unitLibraryUris(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._unitLibraryUris = value;
+  }
+
+  @override
+  List<int> get unitUnitUris => _unitUnitUris ??= <int>[];
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  void set unitUnitUris(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._unitUnitUris = value;
+  }
+
+  @override
+  List<bool> get usedElementIsQualifiedFlags => _usedElementIsQualifiedFlags ??= <bool>[];
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  void set usedElementIsQualifiedFlags(List<bool> value) {
+    this._usedElementIsQualifiedFlags = value;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedElementKinds => _usedElementKinds ??= <idl.IndexRelationKind>[];
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  void set usedElementKinds(List<idl.IndexRelationKind> value) {
+    this._usedElementKinds = value;
+  }
+
+  @override
+  List<int> get usedElementLengths => _usedElementLengths ??= <int>[];
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  void set usedElementLengths(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._usedElementLengths = value;
+  }
+
+  @override
+  List<int> get usedElementOffsets => _usedElementOffsets ??= <int>[];
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  void set usedElementOffsets(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._usedElementOffsets = value;
+  }
+
+  @override
+  List<int> get usedElements => _usedElements ??= <int>[];
+
+  /**
+   * Each item of this list is the index into [elementUnits],
+   * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+   * [elementNameParameterIds].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this index.
+   */
+  void set usedElements(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._usedElements = value;
+  }
+
+  @override
+  List<bool> get usedNameIsQualifiedFlags => _usedNameIsQualifiedFlags ??= <bool>[];
+
+  /**
+   * Each item of this list is the `true` if the corresponding name usage
+   * is qualified with some prefix.
+   */
+  void set usedNameIsQualifiedFlags(List<bool> value) {
+    this._usedNameIsQualifiedFlags = value;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedNameKinds => _usedNameKinds ??= <idl.IndexRelationKind>[];
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  void set usedNameKinds(List<idl.IndexRelationKind> value) {
+    this._usedNameKinds = value;
+  }
+
+  @override
+  List<int> get usedNameOffsets => _usedNameOffsets ??= <int>[];
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  void set usedNameOffsets(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._usedNameOffsets = value;
+  }
+
+  @override
+  List<int> get usedNames => _usedNames ??= <int>[];
+
+  /**
+   * Each item of this list is the index into [strings] for a used name.  The
+   * list is sorted in ascending order, so that the client can quickly find
+   * whether a name is used in this index.
+   */
+  void set usedNames(List<int> value) {
+    assert(value == null || value.every((e) => e >= 0));
+    this._usedNames = value;
+  }
+
+  AnalysisDriverUnitIndexBuilder({List<idl.IndexSyntheticElementKind> elementKinds, List<int> elementNameClassMemberIds, List<int> elementNameParameterIds, List<int> elementNameUnitMemberIds, List<int> elementUnits, int nullStringId, List<String> strings, List<int> unitLibraryUris, List<int> unitUnitUris, List<bool> usedElementIsQualifiedFlags, List<idl.IndexRelationKind> usedElementKinds, List<int> usedElementLengths, List<int> usedElementOffsets, List<int> usedElements, List<bool> usedNameIsQualifiedFlags, List<idl.IndexRelationKind> usedNameKinds, List<int> usedNameOffsets, List<int> usedNames})
+    : _elementKinds = elementKinds,
+      _elementNameClassMemberIds = elementNameClassMemberIds,
+      _elementNameParameterIds = elementNameParameterIds,
+      _elementNameUnitMemberIds = elementNameUnitMemberIds,
+      _elementUnits = elementUnits,
+      _nullStringId = nullStringId,
+      _strings = strings,
+      _unitLibraryUris = unitLibraryUris,
+      _unitUnitUris = unitUnitUris,
+      _usedElementIsQualifiedFlags = usedElementIsQualifiedFlags,
+      _usedElementKinds = usedElementKinds,
+      _usedElementLengths = usedElementLengths,
+      _usedElementOffsets = usedElementOffsets,
+      _usedElements = usedElements,
+      _usedNameIsQualifiedFlags = usedNameIsQualifiedFlags,
+      _usedNameKinds = usedNameKinds,
+      _usedNameOffsets = usedNameOffsets,
+      _usedNames = usedNames;
+
+  /**
+   * Flush [informative] data recursively.
+   */
+  void flushInformative() {
+  }
+
+  /**
+   * Accumulate non-[informative] data into [signature].
+   */
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    if (this._strings == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._strings.length);
+      for (var x in this._strings) {
+        signature.addString(x);
+      }
+    }
+    signature.addInt(this._nullStringId ?? 0);
+    if (this._unitLibraryUris == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._unitLibraryUris.length);
+      for (var x in this._unitLibraryUris) {
+        signature.addInt(x);
+      }
+    }
+    if (this._unitUnitUris == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._unitUnitUris.length);
+      for (var x in this._unitUnitUris) {
+        signature.addInt(x);
+      }
+    }
+    if (this._elementKinds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._elementKinds.length);
+      for (var x in this._elementKinds) {
+        signature.addInt(x.index);
+      }
+    }
+    if (this._elementUnits == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._elementUnits.length);
+      for (var x in this._elementUnits) {
+        signature.addInt(x);
+      }
+    }
+    if (this._elementNameUnitMemberIds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._elementNameUnitMemberIds.length);
+      for (var x in this._elementNameUnitMemberIds) {
+        signature.addInt(x);
+      }
+    }
+    if (this._elementNameClassMemberIds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._elementNameClassMemberIds.length);
+      for (var x in this._elementNameClassMemberIds) {
+        signature.addInt(x);
+      }
+    }
+    if (this._elementNameParameterIds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._elementNameParameterIds.length);
+      for (var x in this._elementNameParameterIds) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedElements == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedElements.length);
+      for (var x in this._usedElements) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedElementKinds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedElementKinds.length);
+      for (var x in this._usedElementKinds) {
+        signature.addInt(x.index);
+      }
+    }
+    if (this._usedElementOffsets == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedElementOffsets.length);
+      for (var x in this._usedElementOffsets) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedElementLengths == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedElementLengths.length);
+      for (var x in this._usedElementLengths) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedElementIsQualifiedFlags == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedElementIsQualifiedFlags.length);
+      for (var x in this._usedElementIsQualifiedFlags) {
+        signature.addBool(x);
+      }
+    }
+    if (this._usedNames == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedNames.length);
+      for (var x in this._usedNames) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedNameKinds == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedNameKinds.length);
+      for (var x in this._usedNameKinds) {
+        signature.addInt(x.index);
+      }
+    }
+    if (this._usedNameOffsets == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedNameOffsets.length);
+      for (var x in this._usedNameOffsets) {
+        signature.addInt(x);
+      }
+    }
+    if (this._usedNameIsQualifiedFlags == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._usedNameIsQualifiedFlags.length);
+      for (var x in this._usedNameIsQualifiedFlags) {
+        signature.addBool(x);
+      }
+    }
+  }
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "ADUI");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_elementKinds;
+    fb.Offset offset_elementNameClassMemberIds;
+    fb.Offset offset_elementNameParameterIds;
+    fb.Offset offset_elementNameUnitMemberIds;
+    fb.Offset offset_elementUnits;
+    fb.Offset offset_strings;
+    fb.Offset offset_unitLibraryUris;
+    fb.Offset offset_unitUnitUris;
+    fb.Offset offset_usedElementIsQualifiedFlags;
+    fb.Offset offset_usedElementKinds;
+    fb.Offset offset_usedElementLengths;
+    fb.Offset offset_usedElementOffsets;
+    fb.Offset offset_usedElements;
+    fb.Offset offset_usedNameIsQualifiedFlags;
+    fb.Offset offset_usedNameKinds;
+    fb.Offset offset_usedNameOffsets;
+    fb.Offset offset_usedNames;
+    if (!(_elementKinds == null || _elementKinds.isEmpty)) {
+      offset_elementKinds = fbBuilder.writeListUint8(_elementKinds.map((b) => b.index).toList());
+    }
+    if (!(_elementNameClassMemberIds == null || _elementNameClassMemberIds.isEmpty)) {
+      offset_elementNameClassMemberIds = fbBuilder.writeListUint32(_elementNameClassMemberIds);
+    }
+    if (!(_elementNameParameterIds == null || _elementNameParameterIds.isEmpty)) {
+      offset_elementNameParameterIds = fbBuilder.writeListUint32(_elementNameParameterIds);
+    }
+    if (!(_elementNameUnitMemberIds == null || _elementNameUnitMemberIds.isEmpty)) {
+      offset_elementNameUnitMemberIds = fbBuilder.writeListUint32(_elementNameUnitMemberIds);
+    }
+    if (!(_elementUnits == null || _elementUnits.isEmpty)) {
+      offset_elementUnits = fbBuilder.writeListUint32(_elementUnits);
+    }
+    if (!(_strings == null || _strings.isEmpty)) {
+      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_unitLibraryUris == null || _unitLibraryUris.isEmpty)) {
+      offset_unitLibraryUris = fbBuilder.writeListUint32(_unitLibraryUris);
+    }
+    if (!(_unitUnitUris == null || _unitUnitUris.isEmpty)) {
+      offset_unitUnitUris = fbBuilder.writeListUint32(_unitUnitUris);
+    }
+    if (!(_usedElementIsQualifiedFlags == null || _usedElementIsQualifiedFlags.isEmpty)) {
+      offset_usedElementIsQualifiedFlags = fbBuilder.writeListBool(_usedElementIsQualifiedFlags);
+    }
+    if (!(_usedElementKinds == null || _usedElementKinds.isEmpty)) {
+      offset_usedElementKinds = fbBuilder.writeListUint8(_usedElementKinds.map((b) => b.index).toList());
+    }
+    if (!(_usedElementLengths == null || _usedElementLengths.isEmpty)) {
+      offset_usedElementLengths = fbBuilder.writeListUint32(_usedElementLengths);
+    }
+    if (!(_usedElementOffsets == null || _usedElementOffsets.isEmpty)) {
+      offset_usedElementOffsets = fbBuilder.writeListUint32(_usedElementOffsets);
+    }
+    if (!(_usedElements == null || _usedElements.isEmpty)) {
+      offset_usedElements = fbBuilder.writeListUint32(_usedElements);
+    }
+    if (!(_usedNameIsQualifiedFlags == null || _usedNameIsQualifiedFlags.isEmpty)) {
+      offset_usedNameIsQualifiedFlags = fbBuilder.writeListBool(_usedNameIsQualifiedFlags);
+    }
+    if (!(_usedNameKinds == null || _usedNameKinds.isEmpty)) {
+      offset_usedNameKinds = fbBuilder.writeListUint8(_usedNameKinds.map((b) => b.index).toList());
+    }
+    if (!(_usedNameOffsets == null || _usedNameOffsets.isEmpty)) {
+      offset_usedNameOffsets = fbBuilder.writeListUint32(_usedNameOffsets);
+    }
+    if (!(_usedNames == null || _usedNames.isEmpty)) {
+      offset_usedNames = fbBuilder.writeListUint32(_usedNames);
+    }
+    fbBuilder.startTable();
+    if (offset_elementKinds != null) {
+      fbBuilder.addOffset(4, offset_elementKinds);
+    }
+    if (offset_elementNameClassMemberIds != null) {
+      fbBuilder.addOffset(7, offset_elementNameClassMemberIds);
+    }
+    if (offset_elementNameParameterIds != null) {
+      fbBuilder.addOffset(8, offset_elementNameParameterIds);
+    }
+    if (offset_elementNameUnitMemberIds != null) {
+      fbBuilder.addOffset(6, offset_elementNameUnitMemberIds);
+    }
+    if (offset_elementUnits != null) {
+      fbBuilder.addOffset(5, offset_elementUnits);
+    }
+    if (_nullStringId != null && _nullStringId != 0) {
+      fbBuilder.addUint32(1, _nullStringId);
+    }
+    if (offset_strings != null) {
+      fbBuilder.addOffset(0, offset_strings);
+    }
+    if (offset_unitLibraryUris != null) {
+      fbBuilder.addOffset(2, offset_unitLibraryUris);
+    }
+    if (offset_unitUnitUris != null) {
+      fbBuilder.addOffset(3, offset_unitUnitUris);
+    }
+    if (offset_usedElementIsQualifiedFlags != null) {
+      fbBuilder.addOffset(13, offset_usedElementIsQualifiedFlags);
+    }
+    if (offset_usedElementKinds != null) {
+      fbBuilder.addOffset(10, offset_usedElementKinds);
+    }
+    if (offset_usedElementLengths != null) {
+      fbBuilder.addOffset(12, offset_usedElementLengths);
+    }
+    if (offset_usedElementOffsets != null) {
+      fbBuilder.addOffset(11, offset_usedElementOffsets);
+    }
+    if (offset_usedElements != null) {
+      fbBuilder.addOffset(9, offset_usedElements);
+    }
+    if (offset_usedNameIsQualifiedFlags != null) {
+      fbBuilder.addOffset(17, offset_usedNameIsQualifiedFlags);
+    }
+    if (offset_usedNameKinds != null) {
+      fbBuilder.addOffset(15, offset_usedNameKinds);
+    }
+    if (offset_usedNameOffsets != null) {
+      fbBuilder.addOffset(16, offset_usedNameOffsets);
+    }
+    if (offset_usedNames != null) {
+      fbBuilder.addOffset(14, offset_usedNames);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.AnalysisDriverUnitIndex readAnalysisDriverUnitIndex(List<int> buffer) {
+  fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
+  return const _AnalysisDriverUnitIndexReader().read(rootRef, 0);
+}
+
+class _AnalysisDriverUnitIndexReader extends fb.TableReader<_AnalysisDriverUnitIndexImpl> {
+  const _AnalysisDriverUnitIndexReader();
+
+  @override
+  _AnalysisDriverUnitIndexImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverUnitIndexImpl(bc, offset);
+}
+
+class _AnalysisDriverUnitIndexImpl extends Object with _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _AnalysisDriverUnitIndexImpl(this._bc, this._bcOffset);
+
+  List<idl.IndexSyntheticElementKind> _elementKinds;
+  List<int> _elementNameClassMemberIds;
+  List<int> _elementNameParameterIds;
+  List<int> _elementNameUnitMemberIds;
+  List<int> _elementUnits;
+  int _nullStringId;
+  List<String> _strings;
+  List<int> _unitLibraryUris;
+  List<int> _unitUnitUris;
+  List<bool> _usedElementIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedElementKinds;
+  List<int> _usedElementLengths;
+  List<int> _usedElementOffsets;
+  List<int> _usedElements;
+  List<bool> _usedNameIsQualifiedFlags;
+  List<idl.IndexRelationKind> _usedNameKinds;
+  List<int> _usedNameOffsets;
+  List<int> _usedNames;
+
+  @override
+  List<idl.IndexSyntheticElementKind> get elementKinds {
+    _elementKinds ??= const fb.ListReader<idl.IndexSyntheticElementKind>(const _IndexSyntheticElementKindReader()).vTableGet(_bc, _bcOffset, 4, const <idl.IndexSyntheticElementKind>[]);
+    return _elementKinds;
+  }
+
+  @override
+  List<int> get elementNameClassMemberIds {
+    _elementNameClassMemberIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 7, const <int>[]);
+    return _elementNameClassMemberIds;
+  }
+
+  @override
+  List<int> get elementNameParameterIds {
+    _elementNameParameterIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 8, const <int>[]);
+    return _elementNameParameterIds;
+  }
+
+  @override
+  List<int> get elementNameUnitMemberIds {
+    _elementNameUnitMemberIds ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 6, const <int>[]);
+    return _elementNameUnitMemberIds;
+  }
+
+  @override
+  List<int> get elementUnits {
+    _elementUnits ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 5, const <int>[]);
+    return _elementUnits;
+  }
+
+  @override
+  int get nullStringId {
+    _nullStringId ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 1, 0);
+    return _nullStringId;
+  }
+
+  @override
+  List<String> get strings {
+    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 0, const <String>[]);
+    return _strings;
+  }
+
+  @override
+  List<int> get unitLibraryUris {
+    _unitLibraryUris ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 2, const <int>[]);
+    return _unitLibraryUris;
+  }
+
+  @override
+  List<int> get unitUnitUris {
+    _unitUnitUris ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 3, const <int>[]);
+    return _unitUnitUris;
+  }
+
+  @override
+  List<bool> get usedElementIsQualifiedFlags {
+    _usedElementIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bc, _bcOffset, 13, const <bool>[]);
+    return _usedElementIsQualifiedFlags;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedElementKinds {
+    _usedElementKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bc, _bcOffset, 10, const <idl.IndexRelationKind>[]);
+    return _usedElementKinds;
+  }
+
+  @override
+  List<int> get usedElementLengths {
+    _usedElementLengths ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 12, const <int>[]);
+    return _usedElementLengths;
+  }
+
+  @override
+  List<int> get usedElementOffsets {
+    _usedElementOffsets ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 11, const <int>[]);
+    return _usedElementOffsets;
+  }
+
+  @override
+  List<int> get usedElements {
+    _usedElements ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 9, const <int>[]);
+    return _usedElements;
+  }
+
+  @override
+  List<bool> get usedNameIsQualifiedFlags {
+    _usedNameIsQualifiedFlags ??= const fb.BoolListReader().vTableGet(_bc, _bcOffset, 17, const <bool>[]);
+    return _usedNameIsQualifiedFlags;
+  }
+
+  @override
+  List<idl.IndexRelationKind> get usedNameKinds {
+    _usedNameKinds ??= const fb.ListReader<idl.IndexRelationKind>(const _IndexRelationKindReader()).vTableGet(_bc, _bcOffset, 15, const <idl.IndexRelationKind>[]);
+    return _usedNameKinds;
+  }
+
+  @override
+  List<int> get usedNameOffsets {
+    _usedNameOffsets ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 16, const <int>[]);
+    return _usedNameOffsets;
+  }
+
+  @override
+  List<int> get usedNames {
+    _usedNames ??= const fb.Uint32ListReader().vTableGet(_bc, _bcOffset, 14, const <int>[]);
+    return _usedNames;
+  }
+}
+
+abstract class _AnalysisDriverUnitIndexMixin implements idl.AnalysisDriverUnitIndex {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (elementKinds.isNotEmpty) _result["elementKinds"] = elementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (elementNameClassMemberIds.isNotEmpty) _result["elementNameClassMemberIds"] = elementNameClassMemberIds;
+    if (elementNameParameterIds.isNotEmpty) _result["elementNameParameterIds"] = elementNameParameterIds;
+    if (elementNameUnitMemberIds.isNotEmpty) _result["elementNameUnitMemberIds"] = elementNameUnitMemberIds;
+    if (elementUnits.isNotEmpty) _result["elementUnits"] = elementUnits;
+    if (nullStringId != 0) _result["nullStringId"] = nullStringId;
+    if (strings.isNotEmpty) _result["strings"] = strings;
+    if (unitLibraryUris.isNotEmpty) _result["unitLibraryUris"] = unitLibraryUris;
+    if (unitUnitUris.isNotEmpty) _result["unitUnitUris"] = unitUnitUris;
+    if (usedElementIsQualifiedFlags.isNotEmpty) _result["usedElementIsQualifiedFlags"] = usedElementIsQualifiedFlags;
+    if (usedElementKinds.isNotEmpty) _result["usedElementKinds"] = usedElementKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (usedElementLengths.isNotEmpty) _result["usedElementLengths"] = usedElementLengths;
+    if (usedElementOffsets.isNotEmpty) _result["usedElementOffsets"] = usedElementOffsets;
+    if (usedElements.isNotEmpty) _result["usedElements"] = usedElements;
+    if (usedNameIsQualifiedFlags.isNotEmpty) _result["usedNameIsQualifiedFlags"] = usedNameIsQualifiedFlags;
+    if (usedNameKinds.isNotEmpty) _result["usedNameKinds"] = usedNameKinds.map((_value) => _value.toString().split('.')[1]).toList();
+    if (usedNameOffsets.isNotEmpty) _result["usedNameOffsets"] = usedNameOffsets;
+    if (usedNames.isNotEmpty) _result["usedNames"] = usedNames;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "elementKinds": elementKinds,
+    "elementNameClassMemberIds": elementNameClassMemberIds,
+    "elementNameParameterIds": elementNameParameterIds,
+    "elementNameUnitMemberIds": elementNameUnitMemberIds,
+    "elementUnits": elementUnits,
+    "nullStringId": nullStringId,
+    "strings": strings,
+    "unitLibraryUris": unitLibraryUris,
+    "unitUnitUris": unitUnitUris,
+    "usedElementIsQualifiedFlags": usedElementIsQualifiedFlags,
+    "usedElementKinds": usedElementKinds,
+    "usedElementLengths": usedElementLengths,
+    "usedElementOffsets": usedElementOffsets,
+    "usedElements": usedElements,
+    "usedNameIsQualifiedFlags": usedNameIsQualifiedFlags,
+    "usedNameKinds": usedNameKinds,
+    "usedNameOffsets": usedNameOffsets,
+    "usedNames": usedNames,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class AnalysisDriverUnlinkedUnitBuilder extends Object with _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+  List<String> _referencedNames;
+  UnlinkedUnitBuilder _unit;
+
+  @override
+  List<String> get referencedNames => _referencedNames ??= <String>[];
+
+  /**
+   * List of external names referenced by the unit.
+   */
+  void set referencedNames(List<String> value) {
+    this._referencedNames = value;
+  }
+
+  @override
+  UnlinkedUnitBuilder get unit => _unit;
+
+  /**
+   * Unlinked information for the unit.
+   */
+  void set unit(UnlinkedUnitBuilder value) {
+    this._unit = value;
+  }
+
+  AnalysisDriverUnlinkedUnitBuilder({List<String> referencedNames, UnlinkedUnitBuilder unit})
+    : _referencedNames = referencedNames,
+      _unit = unit;
+
+  /**
+   * Flush [informative] data recursively.
+   */
+  void flushInformative() {
+    _unit?.flushInformative();
+  }
+
+  /**
+   * Accumulate non-[informative] data into [signature].
+   */
+  void collectApiSignature(api_sig.ApiSignature signature) {
+    if (this._referencedNames == null) {
+      signature.addInt(0);
+    } else {
+      signature.addInt(this._referencedNames.length);
+      for (var x in this._referencedNames) {
+        signature.addString(x);
+      }
+    }
+    signature.addBool(this._unit != null);
+    this._unit?.collectApiSignature(signature);
+  }
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "ADUU");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    fb.Offset offset_referencedNames;
+    fb.Offset offset_unit;
+    if (!(_referencedNames == null || _referencedNames.isEmpty)) {
+      offset_referencedNames = fbBuilder.writeList(_referencedNames.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (_unit != null) {
+      offset_unit = _unit.finish(fbBuilder);
+    }
+    fbBuilder.startTable();
+    if (offset_referencedNames != null) {
+      fbBuilder.addOffset(0, offset_referencedNames);
+    }
+    if (offset_unit != null) {
+      fbBuilder.addOffset(1, offset_unit);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.AnalysisDriverUnlinkedUnit readAnalysisDriverUnlinkedUnit(List<int> buffer) {
+  fb.BufferContext rootRef = new fb.BufferContext.fromBytes(buffer);
+  return const _AnalysisDriverUnlinkedUnitReader().read(rootRef, 0);
+}
+
+class _AnalysisDriverUnlinkedUnitReader extends fb.TableReader<_AnalysisDriverUnlinkedUnitImpl> {
+  const _AnalysisDriverUnlinkedUnitReader();
+
+  @override
+  _AnalysisDriverUnlinkedUnitImpl createObject(fb.BufferContext bc, int offset) => new _AnalysisDriverUnlinkedUnitImpl(bc, offset);
+}
+
+class _AnalysisDriverUnlinkedUnitImpl extends Object with _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+  final fb.BufferContext _bc;
+  final int _bcOffset;
+
+  _AnalysisDriverUnlinkedUnitImpl(this._bc, this._bcOffset);
+
+  List<String> _referencedNames;
+  idl.UnlinkedUnit _unit;
+
+  @override
+  List<String> get referencedNames {
+    _referencedNames ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bc, _bcOffset, 0, const <String>[]);
+    return _referencedNames;
+  }
+
+  @override
+  idl.UnlinkedUnit get unit {
+    _unit ??= const _UnlinkedUnitReader().vTableGet(_bc, _bcOffset, 1, null);
+    return _unit;
+  }
+}
+
+abstract class _AnalysisDriverUnlinkedUnitMixin implements idl.AnalysisDriverUnlinkedUnit {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (referencedNames.isNotEmpty) _result["referencedNames"] = referencedNames;
+    if (unit != null) _result["unit"] = unit.toJson();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "referencedNames": referencedNames,
+    "unit": unit,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
 class CodeRangeBuilder extends Object with _CodeRangeMixin implements idl.CodeRange {
   int _length;
   int _offset;
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index 09fbfe4..baf782a 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -789,6 +789,11 @@
    * The full list of analysis errors, both syntactic and semantic.
    */
   errors:[AnalysisDriverUnitError] (id: 0);
+
+  /**
+   * The index of the unit.
+   */
+  index:AnalysisDriverUnitIndex (id: 1);
 }
 
 /**
@@ -822,6 +827,141 @@
 }
 
 /**
+ * Information about a resolved unit.
+ */
+table AnalysisDriverUnitIndex {
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  elementKinds:[IndexSyntheticElementKind] (id: 4);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the class member element name, or `null` if the element
+   * is a top-level element.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  elementNameClassMemberIds:[uint] (id: 7);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the named parameter name, or `null` if the element is not
+   * a named parameter.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  elementNameParameterIds:[uint] (id: 8);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the top-level element name, or `null` if the element is
+   * the unit.  The list is sorted in ascending order, so that the client can
+   * quickly check whether an element is referenced in this index.
+   */
+  elementNameUnitMemberIds:[uint] (id: 6);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  elementUnits:[uint] (id: 5);
+
+  /**
+   * Identifier of the null string in [strings].
+   */
+  nullStringId:uint (id: 1);
+
+  /**
+   * List of unique element strings used in this index.  The list is sorted in
+   * ascending order, so that the client can quickly check the presence of a
+   * string in this index.
+   */
+  strings:[string] (id: 0);
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  unitLibraryUris:[uint] (id: 2);
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  unitUnitUris:[uint] (id: 3);
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  usedElementIsQualifiedFlags:[ubyte] (id: 13);
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  usedElementKinds:[IndexRelationKind] (id: 10);
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  usedElementLengths:[uint] (id: 12);
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  usedElementOffsets:[uint] (id: 11);
+
+  /**
+   * Each item of this list is the index into [elementUnits],
+   * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+   * [elementNameParameterIds].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this index.
+   */
+  usedElements:[uint] (id: 9);
+
+  /**
+   * Each item of this list is the `true` if the corresponding name usage
+   * is qualified with some prefix.
+   */
+  usedNameIsQualifiedFlags:[ubyte] (id: 17);
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  usedNameKinds:[IndexRelationKind] (id: 15);
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  usedNameOffsets:[uint] (id: 16);
+
+  /**
+   * Each item of this list is the index into [strings] for a used name.  The
+   * list is sorted in ascending order, so that the client can quickly find
+   * whether a name is used in this index.
+   */
+  usedNames:[uint] (id: 14);
+}
+
+/**
+ * Information about an unlinked unit.
+ */
+table AnalysisDriverUnlinkedUnit {
+  /**
+   * List of external names referenced by the unit.
+   */
+  referencedNames:[string] (id: 0);
+
+  /**
+   * Unlinked information for the unit.
+   */
+  unit:UnlinkedUnit (id: 1);
+}
+
+/**
  * Information about an element code range.
  */
 table CodeRange {
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index eeb604a..d960c4b 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -70,6 +70,12 @@
    */
   @Id(0)
   List<AnalysisDriverUnitError> get errors;
+
+  /**
+   * The index of the unit.
+   */
+  @Id(1)
+  AnalysisDriverUnitIndex get index;
 }
 
 /**
@@ -108,6 +114,169 @@
 }
 
 /**
+ * Information about a resolved unit.
+ */
+@TopLevel('ADUI')
+abstract class AnalysisDriverUnitIndex extends base.SummaryClass {
+  factory AnalysisDriverUnitIndex.fromBuffer(List<int> buffer) =>
+      generated.readAnalysisDriverUnitIndex(buffer);
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the kind of the synthetic element.
+   */
+  @Id(4)
+  List<IndexSyntheticElementKind> get elementKinds;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the class member element name, or `null` if the element
+   * is a top-level element.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  @Id(7)
+  List<int> get elementNameClassMemberIds;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the named parameter name, or `null` if the element is not
+   * a named parameter.  The list is sorted in ascending order, so that the
+   * client can quickly check whether an element is referenced in this index.
+   */
+  @Id(8)
+  List<int> get elementNameParameterIds;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the identifier of the top-level element name, or `null` if the element is
+   * the unit.  The list is sorted in ascending order, so that the client can
+   * quickly check whether an element is referenced in this index.
+   */
+  @Id(6)
+  List<int> get elementNameUnitMemberIds;
+
+  /**
+   * Each item of this list corresponds to a unique referenced element.  It is
+   * the index into [unitLibraryUris] and [unitUnitUris] for the library
+   * specific unit where the element is declared.
+   */
+  @Id(5)
+  List<int> get elementUnits;
+
+  /**
+   * Identifier of the null string in [strings].
+   */
+  @Id(1)
+  int get nullStringId;
+
+  /**
+   * List of unique element strings used in this index.  The list is sorted in
+   * ascending order, so that the client can quickly check the presence of a
+   * string in this index.
+   */
+  @Id(0)
+  List<String> get strings;
+
+  /**
+   * Each item of this list corresponds to the library URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  @Id(2)
+  List<int> get unitLibraryUris;
+
+  /**
+   * Each item of this list corresponds to the unit URI of a unique library
+   * specific unit referenced in the index.  It is an index into [strings] list.
+   */
+  @Id(3)
+  List<int> get unitUnitUris;
+
+  /**
+   * Each item of this list is the `true` if the corresponding element usage
+   * is qualified with some prefix.
+   */
+  @Id(13)
+  List<bool> get usedElementIsQualifiedFlags;
+
+  /**
+   * Each item of this list is the kind of the element usage.
+   */
+  @Id(10)
+  List<IndexRelationKind> get usedElementKinds;
+
+  /**
+   * Each item of this list is the length of the element usage.
+   */
+  @Id(12)
+  List<int> get usedElementLengths;
+
+  /**
+   * Each item of this list is the offset of the element usage relative to the
+   * beginning of the file.
+   */
+  @Id(11)
+  List<int> get usedElementOffsets;
+
+  /**
+   * Each item of this list is the index into [elementUnits],
+   * [elementNameUnitMemberIds], [elementNameClassMemberIds] and
+   * [elementNameParameterIds].  The list is sorted in ascending order, so
+   * that the client can quickly find element references in this index.
+   */
+  @Id(9)
+  List<int> get usedElements;
+
+  /**
+   * Each item of this list is the `true` if the corresponding name usage
+   * is qualified with some prefix.
+   */
+  @Id(17)
+  List<bool> get usedNameIsQualifiedFlags;
+
+  /**
+   * Each item of this list is the kind of the name usage.
+   */
+  @Id(15)
+  List<IndexRelationKind> get usedNameKinds;
+
+  /**
+   * Each item of this list is the offset of the name usage relative to the
+   * beginning of the file.
+   */
+  @Id(16)
+  List<int> get usedNameOffsets;
+
+  /**
+   * Each item of this list is the index into [strings] for a used name.  The
+   * list is sorted in ascending order, so that the client can quickly find
+   * whether a name is used in this index.
+   */
+  @Id(14)
+  List<int> get usedNames;
+}
+
+/**
+ * Information about an unlinked unit.
+ */
+@TopLevel('ADUU')
+abstract class AnalysisDriverUnlinkedUnit extends base.SummaryClass {
+  factory AnalysisDriverUnlinkedUnit.fromBuffer(List<int> buffer) =>
+      generated.readAnalysisDriverUnlinkedUnit(buffer);
+
+  /**
+   * List of external names referenced by the unit.
+   */
+  @Id(0)
+  List<String> get referencedNames;
+
+  /**
+   * Unlinked information for the unit.
+   */
+  @Id(1)
+  UnlinkedUnit get unit;
+}
+
+/**
  * Information about an element code range.
  */
 abstract class CodeRange extends base.SummaryClass {
diff --git a/pkg/analyzer/lib/src/util/fast_uri.dart b/pkg/analyzer/lib/src/util/fast_uri.dart
index 40681bd..691a51d 100644
--- a/pkg/analyzer/lib/src/util/fast_uri.dart
+++ b/pkg/analyzer/lib/src/util/fast_uri.dart
@@ -183,7 +183,8 @@
     }
     if (refPath.startsWith('../') ||
         refPath.contains('/../') ||
-        refPath.contains('/./')) {
+        refPath.contains('/./') ||
+        refPath.startsWith('/')) {
       Uri slowResult = _fallbackUri.resolveUri(reference);
       return FastUri.parse(slowResult.toString());
     }
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
new file mode 100644
index 0000000..796b9b8
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/dart/analysis/byte_store.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/status.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test/test.dart';
+
+import '../../context/mock_sdk.dart';
+
+class BaseAnalysisDriverTest {
+  static final MockSdk sdk = new MockSdk();
+
+  final MemoryResourceProvider provider = new MemoryResourceProvider();
+  final ByteStore byteStore = new MemoryByteStore();
+  final FileContentOverlay contentOverlay = new FileContentOverlay();
+
+  final StringBuffer logBuffer = new StringBuffer();
+  PerformanceLog logger;
+
+  AnalysisDriverScheduler scheduler;
+  AnalysisDriver driver;
+  final _Monitor idleStatusMonitor = new _Monitor();
+  final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
+  final List<AnalysisResult> allResults = <AnalysisResult>[];
+
+  String testProject;
+  String testFile;
+  String testCode;
+
+  void addTestFile(String content, {bool priority: false}) {
+    testCode = content;
+    provider.newFile(testFile, content);
+    driver.addFile(testFile);
+    if (priority) {
+      driver.priorityFiles = [testFile];
+    }
+  }
+
+  int findOffset(String search) {
+    int offset = testCode.indexOf(search);
+    if (offset < 0) {
+      fail("Did not find '$search' in\n$testCode");
+    }
+    return offset;
+  }
+
+  int getLeadingIdentifierLength(String search) {
+    int length = 0;
+    while (length < search.length) {
+      int c = search.codeUnitAt(length);
+      if (c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      if (c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      if (c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0)) {
+        length++;
+        continue;
+      }
+      break;
+    }
+    return length;
+  }
+
+  void setUp() {
+    new MockSdk();
+    testProject = _p('/test/lib');
+    testFile = _p('/test/lib/test.dart');
+    logger = new PerformanceLog(logBuffer);
+    scheduler = new AnalysisDriverScheduler(logger);
+    driver = new AnalysisDriver(
+        scheduler,
+        logger,
+        provider,
+        byteStore,
+        contentOverlay,
+        new SourceFactory([
+          new DartUriResolver(sdk),
+          new PackageMapUriResolver(provider, <String, List<Folder>>{
+            'test': [provider.getFolder(testProject)]
+          }),
+          new ResourceUriResolver(provider)
+        ], null, provider),
+        new AnalysisOptionsImpl()..strongMode = true);
+    scheduler.start();
+    driver.status.lastWhere((status) {
+      allStatuses.add(status);
+      if (status.isIdle) {
+        idleStatusMonitor.notify();
+      }
+    });
+    driver.results.listen(allResults.add);
+  }
+
+  String _p(String path) => provider.convertPath(path);
+}
+
+class _Monitor {
+  Completer<Null> _completer = new Completer<Null>();
+
+  Future<Null> get signal async {
+    await _completer.future;
+    _completer = new Completer<Null>();
+  }
+
+  void notify() {
+    if (!_completer.isCompleted) {
+      _completer.complete(null);
+    }
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index ec693f4..f4ee85b 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -12,7 +12,6 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
@@ -20,12 +19,14 @@
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../../context/mock_sdk.dart';
+import 'base.dart';
 
 main() {
   defineReflectiveSuite(() {
@@ -216,55 +217,7 @@
 }
 
 @reflectiveTest
-class AnalysisDriverTest {
-  static final MockSdk sdk = new MockSdk();
-
-  final MemoryResourceProvider provider = new MemoryResourceProvider();
-  final ByteStore byteStore = new MemoryByteStore();
-  final FileContentOverlay contentOverlay = new FileContentOverlay();
-
-  final StringBuffer logBuffer = new StringBuffer();
-  PerformanceLog logger;
-
-  AnalysisDriverScheduler scheduler;
-  AnalysisDriver driver;
-  final _Monitor idleStatusMonitor = new _Monitor();
-  final List<AnalysisStatus> allStatuses = <AnalysisStatus>[];
-  final List<AnalysisResult> allResults = <AnalysisResult>[];
-
-  String testProject;
-  String testFile;
-
-  void setUp() {
-    new MockSdk();
-    testProject = _p('/test/lib');
-    testFile = _p('/test/lib/test.dart');
-    logger = new PerformanceLog(logBuffer);
-    scheduler = new AnalysisDriverScheduler(logger);
-    driver = new AnalysisDriver(
-        scheduler,
-        logger,
-        provider,
-        byteStore,
-        contentOverlay,
-        new SourceFactory([
-          new DartUriResolver(sdk),
-          new PackageMapUriResolver(provider, <String, List<Folder>>{
-            'test': [provider.getFolder(testProject)]
-          }),
-          new ResourceUriResolver(provider)
-        ], null, provider),
-        new AnalysisOptionsImpl()..strongMode = true);
-    scheduler.start();
-    driver.status.lastWhere((status) {
-      allStatuses.add(status);
-      if (status.isIdle) {
-        idleStatusMonitor.notify();
-      }
-    });
-    driver.results.listen(allResults.add);
-  }
-
+class AnalysisDriverTest extends BaseAnalysisDriverTest {
   test_addedFiles() async {
     var a = _p('/test/lib/a.dart');
     var b = _p('/test/lib/b.dart');
@@ -394,7 +347,7 @@
   }
 
   test_changeFile_single() async {
-    _addTestFile('var V = 1;', priority: true);
+    addTestFile('var V = 1;', priority: true);
 
     // Initial analysis.
     {
@@ -428,7 +381,7 @@
 
   test_getResult() async {
     String content = 'int f() => 42;';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
@@ -470,7 +423,7 @@
 
   test_getResult_errors() async {
     String content = 'main() { int vv; }';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
@@ -485,8 +438,26 @@
     }
   }
 
+  test_getResult_hasIndex() async {
+    String content = r'''
+foo(int p) {}
+main() {
+  foo(42);
+}
+''';
+    addTestFile(content);
+
+    AnalysisResult result = await driver.getResult(testFile);
+
+    AnalysisDriverUnitIndex index = result.index;
+    int unitId = index.strings.indexOf('package:test/test.dart');
+    int fooId = index.strings.indexOf('foo');
+    expect(unitId, isNonNegative);
+    expect(fooId, isNonNegative);
+  }
+
   test_getResult_inferTypes_finalField() async {
-    _addTestFile(
+    addTestFile(
         r'''
 class C {
   final f = 42;
@@ -500,7 +471,7 @@
   }
 
   test_getResult_inferTypes_instanceMethod() async {
-    _addTestFile(
+    addTestFile(
         r'''
 class A {
   int m(double p) => 1;
@@ -523,7 +494,7 @@
 export 'dart:noSuchLib';
 export 'dart:math';
 ''';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
@@ -540,7 +511,7 @@
 import 'dart:noSuchLib';
 import 'dart:math';
 ''';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     AnalysisResult result = await driver.getResult(testFile);
     expect(result.path, testFile);
@@ -699,7 +670,7 @@
   }
 
   test_getResult_thenRemove() async {
-    _addTestFile('main() {}', priority: true);
+    addTestFile('main() {}', priority: true);
 
     Future<AnalysisResult> resultFuture = driver.getResult(testFile);
     driver.removeFile(testFile);
@@ -712,7 +683,7 @@
 
   test_getResult_twoPendingFutures() async {
     String content = 'main() {}';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     Future<AnalysisResult> future1 = driver.getResult(testFile);
     Future<AnalysisResult> future2 = driver.getResult(testFile);
@@ -1044,7 +1015,7 @@
   }
 
   test_removeFile_changeFile_notAnalyzed() async {
-    _addTestFile('main() {}');
+    addTestFile('main() {}');
 
     // We have a result.
     await _waitForIdle();
@@ -1064,7 +1035,7 @@
 
   test_results_priority() async {
     String content = 'int f() => 42;';
-    _addTestFile(content, priority: true);
+    addTestFile(content, priority: true);
 
     await _waitForIdle();
 
@@ -1105,7 +1076,7 @@
 
   test_results_regular() async {
     String content = 'int f() => 42;';
-    _addTestFile(content);
+    addTestFile(content);
     await _waitForIdle();
 
     expect(allResults, hasLength(1));
@@ -1116,10 +1087,11 @@
     expect(result.contentHash, _md5(content));
     expect(result.unit, isNull);
     expect(result.errors, hasLength(0));
+    expect(result.index, isNotNull);
   }
 
   test_results_status() async {
-    _addTestFile('int f() => 42;');
+    addTestFile('int f() => 42;');
     await _waitForIdle();
 
     expect(allStatuses, hasLength(2));
@@ -1129,14 +1101,6 @@
     expect(allStatuses[1].isIdle, isTrue);
   }
 
-  void _addTestFile(String content, {bool priority: false}) {
-    provider.newFile(testFile, content);
-    driver.addFile(testFile);
-    if (priority) {
-      driver.priorityFiles = [testFile];
-    }
-  }
-
   ClassDeclaration _getClass(CompilationUnit unit, String name) {
     for (CompilationUnitMember declaration in unit.declarations) {
       if (declaration is ClassDeclaration) {
@@ -1233,18 +1197,3 @@
     return hex.encode(md5.convert(UTF8.encode(content)).bytes);
   }
 }
-
-class _Monitor {
-  Completer<Null> _completer = new Completer<Null>();
-
-  Future<Null> get signal async {
-    await _completer.future;
-    _completer = new Completer<Null>();
-  }
-
-  void notify() {
-    if (!_completer.isCompleted) {
-      _completer.complete(null);
-    }
-  }
-}
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index 2ef6802..a97f9c3 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -54,7 +54,7 @@
     AnalysisOptions analysisOptions = new AnalysisOptionsImpl()
       ..strongMode = true;
     fileSystemState = new FileSystemState(logger, byteStore, contentOverlay,
-        provider, sourceFactory, analysisOptions, new Uint32List(0));
+        provider, sourceFactory, analysisOptions, new Uint32List(0), '');
   }
 
   test_getFileForPath_doesNotExist() {
@@ -211,6 +211,21 @@
     expect(files, [filePackageUri, fileFileUri]);
   }
 
+  test_referencedNames() {
+    String path = _p('/aaa/lib/a.dart');
+    provider.newFile(
+        path,
+        r'''
+A foo(B p) {
+  foo(null);
+  C c = new C(p);
+  return c;
+}
+''');
+    FileState file = fileSystemState.getFileForPath(path);
+    expect(file.referencedNames, unorderedEquals(['A', 'B', 'C']));
+  }
+
   test_refresh_differentApiSignature() {
     String path = _p('/aaa/lib/a.dart');
     provider.newFile(
@@ -281,7 +296,7 @@
     fb.transitiveFiles;
     fc.transitiveFiles;
     fd.transitiveFiles;
-    expect(fileSystemState.test.filesWithoutTransitive, isEmpty);
+    expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
 
     // No imports, so just a single file.
     provider.newFile(pa, "");
@@ -290,29 +305,29 @@
     // Import b.dart into a.dart, two files now.
     provider.newFile(pa, "import 'b.dart';");
     fa.refresh();
-    _assertFilesWithoutTransitive([fa]);
+    _assertFilesWithoutTransitiveFiles([fa]);
     _assertTransitiveFiles(fa, [fa, fb]);
 
     // Update b.dart so that it imports c.dart now.
     provider.newFile(pb, "import 'c.dart';");
     fb.refresh();
-    _assertFilesWithoutTransitive([fa, fb]);
+    _assertFilesWithoutTransitiveFiles([fa, fb]);
     _assertTransitiveFiles(fa, [fa, fb, fc]);
     _assertTransitiveFiles(fb, [fb, fc]);
-    _assertFilesWithoutTransitive([]);
+    _assertFilesWithoutTransitiveFiles([]);
 
     // Update b.dart so that it exports d.dart instead.
     provider.newFile(pb, "export 'd.dart';");
     fb.refresh();
-    _assertFilesWithoutTransitive([fa, fb]);
+    _assertFilesWithoutTransitiveFiles([fa, fb]);
     _assertTransitiveFiles(fa, [fa, fb, fd]);
     _assertTransitiveFiles(fb, [fb, fd]);
-    _assertFilesWithoutTransitive([]);
+    _assertFilesWithoutTransitiveFiles([]);
 
     // Update a.dart so that it does not import b.dart anymore.
     provider.newFile(pa, "");
     fa.refresh();
-    _assertFilesWithoutTransitive([fa]);
+    _assertFilesWithoutTransitiveFiles([fa]);
     _assertTransitiveFiles(fa, [fa]);
   }
 
@@ -329,7 +344,7 @@
     // Compute transitive closures for all files.
     fa.transitiveFiles;
     fb.transitiveFiles;
-    _assertFilesWithoutTransitive([]);
+    _assertFilesWithoutTransitiveFiles([]);
 
     // It's a cycle.
     _assertTransitiveFiles(fa, [fa, fb]);
@@ -338,13 +353,54 @@
     // Update a.dart so that it does not import b.dart anymore.
     provider.newFile(pa, "");
     fa.refresh();
-    _assertFilesWithoutTransitive([fa, fb]);
+    _assertFilesWithoutTransitiveFiles([fa, fb]);
     _assertTransitiveFiles(fa, [fa]);
     _assertTransitiveFiles(fb, [fa, fb]);
   }
 
-  void _assertFilesWithoutTransitive(List<FileState> expected) {
-    var actual = fileSystemState.test.filesWithoutTransitive;
+  test_transitiveSignature() {
+    String pa = _p('/aaa/lib/a.dart');
+    String pb = _p('/aaa/lib/b.dart');
+    String pc = _p('/aaa/lib/c.dart');
+    String pd = _p('/aaa/lib/d.dart');
+
+    provider.newFile(pa, "class A {}");
+    provider.newFile(pb, "import 'a.dart';");
+    provider.newFile(pc, "import 'b.dart';");
+    provider.newFile(pd, "class D {}");
+
+    FileState fa = fileSystemState.getFileForPath(pa);
+    FileState fb = fileSystemState.getFileForPath(pb);
+    FileState fc = fileSystemState.getFileForPath(pc);
+    FileState fd = fileSystemState.getFileForPath(pd);
+
+    // Compute transitive closures for all files.
+    expect(fa.transitiveSignature, isNotNull);
+    expect(fb.transitiveSignature, isNotNull);
+    expect(fc.transitiveSignature, isNotNull);
+    expect(fd.transitiveSignature, isNotNull);
+    expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
+
+    // Make an update to a.dart that does not change its API signature.
+    // All transitive signatures are still valid.
+    provider.newFile(pa, "class A {} // the same API signature");
+    fa.refresh();
+    expect(fileSystemState.test.filesWithoutTransitiveFiles, isEmpty);
+
+    // Change a.dart API signature, also flush signatures of b.dart and c.dart,
+    // but d.dart is still OK.
+    provider.newFile(pa, "class A2 {}");
+    fa.refresh();
+    _assertFilesWithoutTransitiveSignatures([fa, fb, fc]);
+  }
+
+  void _assertFilesWithoutTransitiveFiles(List<FileState> expected) {
+    var actual = fileSystemState.test.filesWithoutTransitiveFiles;
+    expect(actual, unorderedEquals(expected));
+  }
+
+  void _assertFilesWithoutTransitiveSignatures(List<FileState> expected) {
+    var actual = fileSystemState.test.filesWithoutTransitiveSignature;
     expect(actual, unorderedEquals(expected));
   }
 
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
new file mode 100644
index 0000000..8c544c7
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -0,0 +1,1267 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'base.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(IndexTest);
+  });
+}
+
+/**
+ * Finds an [Element] with the given [name].
+ */
+Element findChildElement(Element root, String name, [ElementKind kind]) {
+  Element result = null;
+  root.accept(new _ElementVisitorFunctionWrapper((Element element) {
+    if (element.name != name) {
+      return;
+    }
+    if (kind != null && element.kind != kind) {
+      return;
+    }
+    result = element;
+  }));
+  return result;
+}
+
+/**
+ * A function to be called for every [Element].
+ */
+typedef void _ElementVisitorFunction(Element element);
+
+class ExpectedLocation {
+  final CompilationUnitElement unitElement;
+  final int offset;
+  final int length;
+  final bool isQualified;
+
+  ExpectedLocation(
+      this.unitElement, this.offset, this.length, this.isQualified);
+
+  @override
+  String toString() {
+    return '(unit=$unitElement; offset=$offset; length=$length;'
+        ' isQualified=$isQualified)';
+  }
+}
+
+@reflectiveTest
+class IndexTest extends BaseAnalysisDriverTest {
+  CompilationUnit testUnit;
+  CompilationUnitElement testUnitElement;
+  LibraryElement testLibraryElement;
+
+  AnalysisDriverUnitIndex index;
+
+  _ElementIndexAssert assertThat(Element element) {
+    List<_Relation> relations = _getElementRelations(element);
+    return new _ElementIndexAssert(this, element, relations);
+  }
+
+  _NameIndexAssert assertThatName(String name) {
+    return new _NameIndexAssert(this, name);
+  }
+
+  Element findElement(String name, [ElementKind kind]) {
+    return findChildElement(testUnitElement, name, kind);
+  }
+
+  CompilationUnitElement importedUnit({int index: 0}) {
+    List<ImportElement> imports = testLibraryElement.imports;
+    return imports[index].importedLibrary.definingCompilationUnit;
+  }
+
+  test_hasAncestor_ClassDeclaration() async {
+    await _indexTestUnit('''
+class A {}
+class B1 extends A {}
+class B2 implements A {}
+class C1 extends B1 {}
+class C2 extends B2 {}
+class C3 implements B1 {}
+class C4 implements B2 {}
+class M extends Object with A {}
+''');
+    ClassElement classElementA = findElement("A");
+    assertThat(classElementA)
+      ..isAncestorOf('B1 extends A')
+      ..isAncestorOf('B2 implements A')
+      ..isAncestorOf('C1 extends B1')
+      ..isAncestorOf('C2 extends B2')
+      ..isAncestorOf('C3 implements B1')
+      ..isAncestorOf('C4 implements B2')
+      ..isAncestorOf('M extends Object with A');
+  }
+
+  test_hasAncestor_ClassTypeAlias() async {
+    await _indexTestUnit('''
+class A {}
+class B extends A {}
+class C1 = Object with A;
+class C2 = Object with B;
+''');
+    ClassElement classElementA = findElement('A');
+    ClassElement classElementB = findElement('B');
+    assertThat(classElementA)
+      ..isAncestorOf('C1 = Object with A')
+      ..isAncestorOf('C2 = Object with B');
+    assertThat(classElementB)..isAncestorOf('C2 = Object with B');
+  }
+
+  test_isExtendedBy_ClassDeclaration() async {
+    await _indexTestUnit('''
+class A {} // 1
+class B extends A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isExtendedAt('A {} // 2', false)
+      ..isReferencedAt('A {} // 2', false);
+  }
+
+  test_isExtendedBy_ClassDeclaration_isQualified() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+class A {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA).isExtendedAt('A {} // 2', true);
+  }
+
+  test_isExtendedBy_ClassDeclaration_Object() async {
+    await _indexTestUnit('''
+class A {}
+''');
+    ClassElement elementA = findElement('A');
+    ClassElement elementObject = elementA.supertype.element;
+    assertThat(elementObject).isExtendedAt('A {}', true, length: 0);
+  }
+
+  test_isExtendedBy_ClassTypeAlias() async {
+    await _indexTestUnit('''
+class A {}
+class B {}
+class C = A with B;
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isExtendedAt('A with', false)
+      ..isReferencedAt('A with', false);
+  }
+
+  test_isExtendedBy_ClassTypeAlias_isQualified() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+class A {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' as p;
+class B {}
+class C = p.A with B;
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA)
+      ..isExtendedAt('A with', true)
+      ..isReferencedAt('A with', true);
+  }
+
+  test_isImplementedBy_ClassDeclaration() async {
+    await _indexTestUnit('''
+class A {} // 1
+class B implements A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isImplementedAt('A {} // 2', false)
+      ..isReferencedAt('A {} // 2', false);
+  }
+
+  test_isImplementedBy_ClassDeclaration_isQualified() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+class A {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' as p;
+class B implements p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA)
+      ..isImplementedAt('A {} // 2', true)
+      ..isReferencedAt('A {} // 2', true);
+  }
+
+  test_isImplementedBy_ClassTypeAlias() async {
+    await _indexTestUnit('''
+class A {} // 1
+class B {} // 2
+class C = Object with A implements B; // 3
+''');
+    ClassElement elementB = findElement('B');
+    assertThat(elementB)
+      ..isImplementedAt('B; // 3', false)
+      ..isReferencedAt('B; // 3', false);
+  }
+
+  test_isInvokedBy_FieldElement() async {
+    await _indexTestUnit('''
+class A {
+  var field;
+  main() {
+    this.field(); // q
+    field(); // nq
+  }
+}''');
+    FieldElement field = findElement('field');
+    assertThat(field.getter)
+      ..isInvokedAt('field(); // q', true)
+      ..isInvokedAt('field(); // nq', false);
+  }
+
+  test_isInvokedBy_FunctionElement() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+library lib;
+foo() {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart';
+import 'lib.dart' as pref;
+main() {
+  pref.foo(); // q
+  foo(); // nq
+}''');
+    FunctionElement element = importedUnit().functions[0];
+    assertThat(element)
+      ..isInvokedAt('foo(); // q', true)
+      ..isInvokedAt('foo(); // nq', false);
+  }
+
+  test_isInvokedBy_FunctionElement_synthetic_loadLibrary() async {
+    await _indexTestUnit('''
+import 'dart:math' deferred as math;
+main() {
+  math.loadLibrary(); // 1
+  math.loadLibrary(); // 2
+}
+''');
+    LibraryElement mathLib = testLibraryElement.imports[0].importedLibrary;
+    FunctionElement element = mathLib.loadLibraryFunction;
+    assertThat(element).isInvokedAt('loadLibrary(); // 1', true);
+    assertThat(element).isInvokedAt('loadLibrary(); // 2', true);
+  }
+
+  test_isInvokedBy_MethodElement() async {
+    await _indexTestUnit('''
+class A {
+  foo() {}
+  main() {
+    this.foo(); // q
+    foo(); // nq
+  }
+}''');
+    Element element = findElement('foo');
+    assertThat(element)
+      ..isInvokedAt('foo(); // q', true)
+      ..isInvokedAt('foo(); // nq', false);
+  }
+
+  test_isInvokedBy_MethodElement_propagatedType() async {
+    await _indexTestUnit('''
+class A {
+  foo() {}
+}
+main() {
+  var a = new A();
+  a.foo();
+}
+''');
+    Element element = findElement('foo');
+    assertThat(element).isInvokedAt('foo();', true);
+  }
+
+  test_isInvokedBy_operator_binary() async {
+    await _indexTestUnit('''
+class A {
+  operator +(other) => this;
+}
+main(A a) {
+  print(a + 1);
+  a += 2;
+  ++a;
+  a++;
+}
+''');
+    MethodElement element = findElement('+');
+    assertThat(element)
+      ..isInvokedAt('+ 1', true, length: 1)
+      ..isInvokedAt('+= 2', true, length: 2)
+      ..isInvokedAt('++a', true, length: 2)
+      ..isInvokedAt('++;', true, length: 2);
+  }
+
+  test_isInvokedBy_operator_index() async {
+    await _indexTestUnit('''
+class A {
+  operator [](i) => null;
+  operator []=(i, v) {}
+}
+main(A a) {
+  print(a[0]);
+  a[1] = 42;
+}
+''');
+    MethodElement readElement = findElement('[]');
+    MethodElement writeElement = findElement('[]=');
+    assertThat(readElement).isInvokedAt('[0]', true, length: 1);
+    assertThat(writeElement).isInvokedAt('[1]', true, length: 1);
+  }
+
+  test_isInvokedBy_operator_prefix() async {
+    await _indexTestUnit('''
+class A {
+  A operator ~() => this;
+}
+main(A a) {
+  print(~a);
+}
+''');
+    MethodElement element = findElement('~');
+    assertThat(element).isInvokedAt('~a', true, length: 1);
+  }
+
+  test_isInvokedBy_PropertyAccessorElement_getter() async {
+    await _indexTestUnit('''
+class A {
+  get ggg => null;
+  main() {
+    this.ggg(); // q
+    ggg(); // nq
+  }
+}''');
+    PropertyAccessorElement element = findElement('ggg', ElementKind.GETTER);
+    assertThat(element)
+      ..isInvokedAt('ggg(); // q', true)
+      ..isInvokedAt('ggg(); // nq', false);
+  }
+
+  test_isMixedInBy_ClassDeclaration() async {
+    await _indexTestUnit('''
+class A {} // 1
+class B extends Object with A {} // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA)
+      ..isMixedInAt('A {} // 2', false)
+      ..isReferencedAt('A {} // 2', false);
+  }
+
+  test_isMixedInBy_ClassDeclaration_isQualified() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+class A {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' as p;
+class B extends Object with p.A {} // 2
+''');
+    ClassElement elementA = importedUnit().getType('A');
+    assertThat(elementA).isMixedInAt('A {} // 2', true);
+  }
+
+  test_isMixedInBy_ClassTypeAlias() async {
+    await _indexTestUnit('''
+class A {} // 1
+class B = Object with A; // 2
+''');
+    ClassElement elementA = findElement('A');
+    assertThat(elementA).isMixedInAt('A; // 2', false);
+  }
+
+  test_isReferencedBy_ClassElement() async {
+    await _indexTestUnit('''
+class A {
+  static var field;
+}
+main(A p) {
+  A v;
+  new A(); // 2
+  A.field = 1;
+  print(A.field); // 3
+}
+''');
+    ClassElement element = findElement('A');
+    assertThat(element)
+      ..isReferencedAt('A p) {', false)
+      ..isReferencedAt('A v;', false)
+      ..isReferencedAt('A(); // 2', false)
+      ..isReferencedAt('A.field = 1;', false)
+      ..isReferencedAt('A.field); // 3', false);
+  }
+
+  test_isReferencedBy_ClassElement_invocation() async {
+    await _indexTestUnit('''
+class A {}
+main() {
+  A(); // invalid code, but still a reference
+}''');
+    Element element = findElement('A');
+    assertThat(element).isReferencedAt('A();', false);
+  }
+
+  test_isReferencedBy_ClassElement_invocation_isQualified() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+class A {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' as p;
+main() {
+  p.A(); // invalid code, but still a reference
+}''');
+    Element element = importedUnit().getType('A');
+    assertThat(element).isReferencedAt('A();', true);
+  }
+
+  test_isReferencedBy_ClassTypeAlias() async {
+    await _indexTestUnit('''
+class A {}
+class B = Object with A;
+main(B p) {
+  B v;
+}
+''');
+    ClassElement element = findElement('B');
+    assertThat(element)
+      ..isReferencedAt('B p) {', false)
+      ..isReferencedAt('B v;', false);
+  }
+
+  test_isReferencedBy_CompilationUnitElement_export() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+library lib;
+''');
+    await _indexTestUnit('''
+export 'lib.dart';
+''');
+    LibraryElement element = testLibraryElement.exports[0].exportedLibrary;
+    assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+  }
+
+  test_isReferencedBy_CompilationUnitElement_import() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+library lib;
+''');
+    await _indexTestUnit('''
+import 'lib.dart';
+''');
+    LibraryElement element = testLibraryElement.imports[0].importedLibrary;
+    assertThat(element)..isReferencedAt("'lib.dart'", true, length: 10);
+  }
+
+  test_isReferencedBy_CompilationUnitElement_part() async {
+    provider.newFile(_p('$testProject/my_unit.dart'), 'part of my_lib;');
+    await _indexTestUnit('''
+library my_lib;
+part 'my_unit.dart';
+''');
+    CompilationUnitElement element = testLibraryElement.parts[0];
+    assertThat(element)..isReferencedAt("'my_unit.dart';", true, length: 14);
+  }
+
+  test_isReferencedBy_ConstructorElement() async {
+    await _indexTestUnit('''
+class A implements B {
+  A() {}
+  A.foo() {}
+}
+class B extends A {
+  B() : super(); // 1
+  B.foo() : super.foo(); // 2
+  factory B.bar() = A.foo; // 3
+}
+main() {
+  new A(); // 4
+  new A.foo(); // 5
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_foo = classA.constructors[1];
+    // A()
+    assertThat(constA)
+      ..hasRelationCount(2)
+      ..isReferencedAt('(); // 1', true, length: 0)
+      ..isReferencedAt('(); // 4', true, length: 0);
+    // A.foo()
+    assertThat(constA_foo)
+      ..hasRelationCount(3)
+      ..isReferencedAt('.foo(); // 2', true, length: 4)
+      ..isReferencedAt('.foo; // 3', true, length: 4)
+      ..isReferencedAt('.foo(); // 5', true, length: 4);
+  }
+
+  test_isReferencedBy_ConstructorElement_classTypeAlias() async {
+    await _indexTestUnit('''
+class M {}
+class A implements B {
+  A() {}
+  A.named() {}
+}
+class B = A with M;
+class C = B with M;
+main() {
+  new B(); // B1
+  new B.named(); // B2
+  new C(); // C1
+  new C.named(); // C2
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_named = classA.constructors[1];
+    assertThat(constA)
+      ..isReferencedAt('(); // B1', true, length: 0)
+      ..isReferencedAt('(); // C1', true, length: 0);
+    assertThat(constA_named)
+      ..isReferencedAt('.named(); // B2', true, length: 6)
+      ..isReferencedAt('.named(); // C2', true, length: 6);
+  }
+
+  test_isReferencedBy_ConstructorElement_classTypeAlias_cycle() async {
+    await _indexTestUnit('''
+class M {}
+class A = B with M;
+class B = A with M;
+main() {
+  new A();
+  new B();
+}
+''');
+    // No additional validation, but it should not fail with stack overflow.
+  }
+
+  test_isReferencedBy_ConstructorElement_namedOnlyWithDot() async {
+    await _indexTestUnit('''
+class A {
+  A.named() {}
+}
+main() {
+  new A.named();
+}
+''');
+    // has ".named()", but does not have "named()"
+    int offsetWithoutDot = findOffset('named();');
+    int offsetWithDot = findOffset('.named();');
+    expect(index.usedElementOffsets, isNot(contains(offsetWithoutDot)));
+    expect(index.usedElementOffsets, contains(offsetWithDot));
+  }
+
+  test_isReferencedBy_ConstructorElement_redirection() async {
+    await _indexTestUnit('''
+class A {
+  A() : this.bar(); // 1
+  A.foo() : this(); // 2
+  A.bar();
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    ConstructorElement constA_bar = classA.constructors[2];
+    assertThat(constA).isReferencedAt('(); // 2', true, length: 0);
+    assertThat(constA_bar).isReferencedAt('.bar(); // 1', true, length: 4);
+  }
+
+  test_isReferencedBy_ConstructorElement_synthetic() async {
+    await _indexTestUnit('''
+class A {}
+main() {
+  new A(); // 1
+}
+''');
+    ClassElement classA = findElement('A');
+    ConstructorElement constA = classA.constructors[0];
+    // A()
+    assertThat(constA)..isReferencedAt('(); // 1', true, length: 0);
+  }
+
+  test_isReferencedBy_DynamicElement() async {
+    await _indexTestUnit('''
+dynamic f() {
+}''');
+    expect(index.usedElementOffsets, isEmpty);
+  }
+
+  test_isReferencedBy_FieldElement() async {
+    await _indexTestUnit('''
+class A {
+  var field;
+  A({this.field});
+  m() {
+    field = 2; // nq
+    print(field); // nq
+  }
+}
+main(A a) {
+  a.field = 3; // q
+  print(a.field); // q
+  new A(field: 4);
+}
+''');
+    FieldElement field = findElement('field', ElementKind.FIELD);
+    PropertyAccessorElement getter = field.getter;
+    PropertyAccessorElement setter = field.setter;
+    // A()
+    assertThat(field)..isWrittenAt('field});', true);
+    // m()
+    assertThat(setter)..isReferencedAt('field = 2; // nq', false);
+    assertThat(getter)..isReferencedAt('field); // nq', false);
+    // main()
+    assertThat(setter)..isReferencedAt('field = 3; // q', true);
+    assertThat(getter)..isReferencedAt('field); // q', true);
+    assertThat(field)..isReferencedAt('field: 4', true);
+  }
+
+  test_isReferencedBy_FieldElement_multiple() async {
+    await _indexTestUnit('''
+class A {
+  var aaa;
+  var bbb;
+  A(this.aaa, this.bbb) {}
+  m() {
+    print(aaa);
+    aaa = 1;
+    print(bbb);
+    bbb = 2;
+  }
+}
+''');
+    // aaa
+    {
+      FieldElement field = findElement('aaa', ElementKind.FIELD);
+      PropertyAccessorElement getter = field.getter;
+      PropertyAccessorElement setter = field.setter;
+      assertThat(field)..isWrittenAt('aaa, ', true);
+      assertThat(getter)..isReferencedAt('aaa);', false);
+      assertThat(setter)..isReferencedAt('aaa = 1;', false);
+    }
+    // bbb
+    {
+      FieldElement field = findElement('bbb', ElementKind.FIELD);
+      PropertyAccessorElement getter = field.getter;
+      PropertyAccessorElement setter = field.setter;
+      assertThat(field)..isWrittenAt('bbb) {}', true);
+      assertThat(getter)..isReferencedAt('bbb);', false);
+      assertThat(setter)..isReferencedAt('bbb = 2;', false);
+    }
+  }
+
+  test_isReferencedBy_FieldElement_ofEnum() async {
+    await _indexTestUnit('''
+enum MyEnum {
+  A, B, C
+}
+main() {
+  print(MyEnum.values);
+  print(MyEnum.A.index);
+  print(MyEnum.A);
+  print(MyEnum.B);
+}
+''');
+    ClassElement enumElement = findElement('MyEnum');
+    assertThat(enumElement.getGetter('values'))
+      ..isReferencedAt('values);', true);
+    assertThat(enumElement.getGetter('index'))..isReferencedAt('index);', true);
+    assertThat(enumElement.getGetter('A'))..isReferencedAt('A);', true);
+    assertThat(enumElement.getGetter('B'))..isReferencedAt('B);', true);
+  }
+
+  test_isReferencedBy_FieldElement_synthetic_hasGetter() async {
+    await _indexTestUnit('''
+class A {
+  A() : f = 42;
+  int get f => 0;
+}
+''');
+    ClassElement element2 = findElement('A');
+    assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+  }
+
+  test_isReferencedBy_FieldElement_synthetic_hasGetterSetter() async {
+    await _indexTestUnit('''
+class A {
+  A() : f = 42;
+  int get f => 0;
+  set f(_) {}
+}
+''');
+    ClassElement element2 = findElement('A');
+    assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+  }
+
+  test_isReferencedBy_FieldElement_synthetic_hasSetter() async {
+    await _indexTestUnit('''
+class A {
+  A() : f = 42;
+  set f(_) {}
+}
+''');
+    ClassElement element2 = findElement('A');
+    assertThat(element2.getField('f')).isWrittenAt('f = 42', true);
+  }
+
+  test_isReferencedBy_FunctionElement() async {
+    await _indexTestUnit('''
+foo() {}
+main() {
+  print(foo);
+  print(foo());
+}
+''');
+    FunctionElement element = findElement('foo');
+    assertThat(element)
+      ..isReferencedAt('foo);', false)
+      ..isInvokedAt('foo());', false);
+  }
+
+  test_isReferencedBy_FunctionElement_with_LibraryElement() async {
+    provider.newFile(
+        _p('$testProject/foo.dart'),
+        r'''
+bar() {}
+''');
+    await _indexTestUnit('''
+import "foo.dart";
+main() {
+  bar();
+}
+''');
+    LibraryElement fooLibrary = testLibraryElement.imports[0].importedLibrary;
+    assertThat(fooLibrary)..isReferencedAt('"foo.dart";', true, length: 10);
+    {
+      FunctionElement bar = fooLibrary.definingCompilationUnit.functions[0];
+      assertThat(bar)..isInvokedAt('bar();', false);
+    }
+  }
+
+  test_isReferencedBy_FunctionTypeAliasElement() async {
+    await _indexTestUnit('''
+typedef A();
+main(A p) {
+}
+''');
+    Element element = findElement('A');
+    assertThat(element)..isReferencedAt('A p) {', false);
+  }
+
+  /**
+   * There was a bug in the AST structure, when single [Comment] was cloned and
+   * assigned to both [FieldDeclaration] and [VariableDeclaration].
+   *
+   * This caused duplicate indexing.
+   * Here we test that the problem is fixed one way or another.
+   */
+  test_isReferencedBy_identifierInComment() async {
+    await _indexTestUnit('''
+class A {}
+/// [A] text
+var myVariable = null;
+''');
+    Element element = findElement('A');
+    assertThat(element)..isReferencedAt('A] text', false);
+  }
+
+  test_isReferencedBy_MethodElement() async {
+    await _indexTestUnit('''
+class A {
+  method() {}
+  main() {
+    print(this.method); // q
+    print(method); // nq
+  }
+}''');
+    MethodElement element = findElement('method');
+    assertThat(element)
+      ..isReferencedAt('method); // q', true)
+      ..isReferencedAt('method); // nq', false);
+  }
+
+  test_isReferencedBy_ParameterElement() async {
+    await _indexTestUnit('''
+foo({var p}) {}
+main() {
+  foo(p: 1);
+}
+''');
+    Element element = findElement('p');
+    assertThat(element)..isReferencedAt('p: 1', true);
+  }
+
+  test_isReferencedBy_TopLevelVariableElement() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+library lib;
+var V;
+''');
+    await _indexTestUnit('''
+import 'lib.dart' show V; // imp
+import 'lib.dart' as pref;
+main() {
+  pref.V = 5; // q
+  print(pref.V); // q
+  V = 5; // nq
+  print(V); // nq
+}''');
+    TopLevelVariableElement variable = importedUnit().topLevelVariables[0];
+    assertThat(variable)..isReferencedAt('V; // imp', true);
+    assertThat(variable.getter)
+      ..isReferencedAt('V); // q', true)
+      ..isReferencedAt('V); // nq', false);
+    assertThat(variable.setter)
+      ..isReferencedAt('V = 5; // q', true)
+      ..isReferencedAt('V = 5; // nq', false);
+  }
+
+  test_isReferencedBy_TopLevelVariableElement_synthetic_hasGetterSetter() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+int get V => 0;
+void set V(_) {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' show V;
+''');
+    TopLevelVariableElement element = importedUnit().topLevelVariables[0];
+    assertThat(element).isReferencedAt('V;', true);
+  }
+
+  test_isReferencedBy_TopLevelVariableElement_synthetic_hasSetter() async {
+    provider.newFile(
+        _p('$testProject/lib.dart'),
+        '''
+void set V(_) {}
+''');
+    await _indexTestUnit('''
+import 'lib.dart' show V;
+''');
+    TopLevelVariableElement element = importedUnit().topLevelVariables[0];
+    assertThat(element).isReferencedAt('V;', true);
+  }
+
+  test_isReferencedBy_typeInVariableList() async {
+    await _indexTestUnit('''
+class A {}
+A myVariable = null;
+''');
+    Element element = findElement('A');
+    assertThat(element).isReferencedAt('A myVariable', false);
+  }
+
+  test_isWrittenBy_FieldElement() async {
+    await _indexTestUnit('''
+class A {
+  int field;
+  A.foo({this.field});
+  A.bar() : field = 5;
+}
+''');
+    FieldElement element = findElement('field', ElementKind.FIELD);
+    assertThat(element)
+      ..isWrittenAt('field})', true)
+      ..isWrittenAt('field = 5', true);
+  }
+
+  test_usedName_inLibraryIdentifier() async {
+    await _indexTestUnit('''
+library aaa.bbb.ccc;
+class C {
+  var bbb;
+}
+main(p) {
+  p.bbb = 1;
+}
+''');
+    assertThatName('bbb')
+      ..isNotUsed('bbb.ccc', IndexRelationKind.IS_READ_BY)
+      ..isUsedQ('bbb = 1;', IndexRelationKind.IS_WRITTEN_BY);
+  }
+
+  test_usedName_qualified_resolved() async {
+    await _indexTestUnit('''
+class C {
+  var x;
+}
+main(C c) {
+  c.x;
+  c.x = 1;
+  c.x += 2;
+  c.x();
+}
+''');
+    assertThatName('x')
+      ..isNotUsedQ('x;', IndexRelationKind.IS_READ_BY)
+      ..isNotUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+      ..isNotUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+      ..isNotUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+  }
+
+  test_usedName_qualified_unresolved() async {
+    await _indexTestUnit('''
+main(p) {
+  p.x;
+  p.x = 1;
+  p.x += 2;
+  p.x();
+}
+''');
+    assertThatName('x')
+      ..isUsedQ('x;', IndexRelationKind.IS_READ_BY)
+      ..isUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+      ..isUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+      ..isUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+  }
+
+  test_usedName_unqualified_resolved() async {
+    await _indexTestUnit('''
+class C {
+  var x;
+  m() {
+    x;
+    x = 1;
+    x += 2;
+    x();
+  }
+}
+''');
+    assertThatName('x')
+      ..isNotUsedQ('x;', IndexRelationKind.IS_READ_BY)
+      ..isNotUsedQ('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+      ..isNotUsedQ('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+      ..isNotUsedQ('x();', IndexRelationKind.IS_INVOKED_BY);
+  }
+
+  test_usedName_unqualified_unresolved() async {
+    await _indexTestUnit('''
+main() {
+  x;
+  x = 1;
+  x += 2;
+  x();
+}
+''');
+    assertThatName('x')
+      ..isUsed('x;', IndexRelationKind.IS_READ_BY)
+      ..isUsed('x = 1;', IndexRelationKind.IS_WRITTEN_BY)
+      ..isUsed('x += 2;', IndexRelationKind.IS_READ_WRITTEN_BY)
+      ..isUsed('x();', IndexRelationKind.IS_INVOKED_BY);
+  }
+
+  /**
+   * Asserts that [index] has an item with the expected properties.
+   */
+  void _assertHasRelation(
+      Element element,
+      List<_Relation> relations,
+      IndexRelationKind expectedRelationKind,
+      ExpectedLocation expectedLocation) {
+    for (_Relation relation in relations) {
+      if (relation.kind == expectedRelationKind &&
+          relation.offset == expectedLocation.offset &&
+          relation.length == expectedLocation.length &&
+          relation.isQualified == expectedLocation.isQualified) {
+        return;
+      }
+    }
+    _failWithIndexDump(
+        'not found\n$element $expectedRelationKind at $expectedLocation');
+  }
+
+  void _assertUsedName(String name, IndexRelationKind kind,
+      ExpectedLocation expectedLocation, bool isNot) {
+    int nameId = _getStringId(name);
+    for (int i = 0; i < index.usedNames.length; i++) {
+      if (index.usedNames[i] == nameId &&
+          index.usedNameKinds[i] == kind &&
+          index.usedNameOffsets[i] == expectedLocation.offset &&
+          index.usedNameIsQualifiedFlags[i] == expectedLocation.isQualified) {
+        if (isNot) {
+          _failWithIndexDump('Unexpected $name $kind at $expectedLocation');
+        }
+        return;
+      }
+    }
+    if (isNot) {
+      return;
+    }
+    _failWithIndexDump('Not found $name $kind at $expectedLocation');
+  }
+
+  ExpectedLocation _expectedLocation(String search, bool isQualified,
+      {int length}) {
+    int offset = findOffset(search);
+    if (length == null) {
+      length = getLeadingIdentifierLength(search);
+    }
+    return new ExpectedLocation(testUnitElement, offset, length, isQualified);
+  }
+
+  void _failWithIndexDump(String msg) {
+    String packageIndexJsonString =
+        new JsonEncoder.withIndent('  ').convert(index.toJson());
+    fail('$msg in\n' + packageIndexJsonString);
+  }
+
+  /**
+   * Return the [element] identifier in [index] or fail.
+   */
+  int _findElementId(Element element) {
+    int unitId = _getUnitId(element);
+    // Prepare the element that was put into the index.
+    IndexElementInfo info = new IndexElementInfo(element);
+    element = info.element;
+    // Prepare element's name components.
+    int unitMemberId = index.nullStringId;
+    int classMemberId = index.nullStringId;
+    int parameterId = index.nullStringId;
+    for (Element e = element; e != null; e = e.enclosingElement) {
+      if (e.enclosingElement is CompilationUnitElement) {
+        unitMemberId = _getStringId(e.name);
+        break;
+      }
+    }
+    for (Element e = element; e != null; e = e.enclosingElement) {
+      if (e.enclosingElement is ClassElement) {
+        classMemberId = _getStringId(e.name);
+        break;
+      }
+    }
+    if (element is ParameterElement) {
+      parameterId = _getStringId(element.name);
+    }
+    // Find the element's id.
+    for (int elementId = 0;
+        elementId < index.elementUnits.length;
+        elementId++) {
+      if (index.elementUnits[elementId] == unitId &&
+          index.elementNameUnitMemberIds[elementId] == unitMemberId &&
+          index.elementNameClassMemberIds[elementId] == classMemberId &&
+          index.elementNameParameterIds[elementId] == parameterId &&
+          index.elementKinds[elementId] == info.kind) {
+        return elementId;
+      }
+    }
+    _failWithIndexDump('Element $element is not referenced');
+    return 0;
+  }
+
+  /**
+   * Return all relations with [element] in [index].
+   */
+  List<_Relation> _getElementRelations(Element element) {
+    int elementId = _findElementId(element);
+    List<_Relation> relations = <_Relation>[];
+    for (int i = 0; i < index.usedElementOffsets.length; i++) {
+      if (index.usedElements[i] == elementId) {
+        relations.add(new _Relation(
+            index.usedElementKinds[i],
+            index.usedElementOffsets[i],
+            index.usedElementLengths[i],
+            index.usedElementIsQualifiedFlags[i]));
+      }
+    }
+    return relations;
+  }
+
+  int _getStringId(String str) {
+    int id = index.strings.indexOf(str);
+    if (id < 0) {
+      _failWithIndexDump('String "$str" is not referenced');
+    }
+    return id;
+  }
+
+  int _getUnitId(Element element) {
+    CompilationUnitElement unitElement = getUnitElement(element);
+    int libraryUriId = _getUriId(unitElement.library.source.uri);
+    int unitUriId = _getUriId(unitElement.source.uri);
+    expect(index.unitLibraryUris, hasLength(index.unitUnitUris.length));
+    for (int i = 0; i < index.unitLibraryUris.length; i++) {
+      if (index.unitLibraryUris[i] == libraryUriId &&
+          index.unitUnitUris[i] == unitUriId) {
+        return i;
+      }
+    }
+    _failWithIndexDump('Unit $unitElement of $element is not referenced');
+    return -1;
+  }
+
+  int _getUriId(Uri uri) {
+    String str = uri.toString();
+    return _getStringId(str);
+  }
+
+  Future<Null> _indexTestUnit(String code) async {
+    addTestFile(code);
+
+    AnalysisResult result = await driver.getResult(testFile);
+    testUnit = result.unit;
+    testUnitElement = testUnit.element;
+    testLibraryElement = testUnitElement.library;
+
+    AnalysisDriverUnitIndexBuilder indexBuilder = indexUnit(testUnit);
+    List<int> indexBytes = indexBuilder.toBuffer();
+    index = new AnalysisDriverUnitIndex.fromBuffer(indexBytes);
+  }
+
+  String _p(String path) => provider.convertPath(path);
+}
+
+class _ElementIndexAssert {
+  final IndexTest test;
+  final Element element;
+  final List<_Relation> relations;
+
+  _ElementIndexAssert(this.test, this.element, this.relations);
+
+  void hasRelationCount(int expectedCount) {
+    expect(relations, hasLength(expectedCount));
+  }
+
+  void isAncestorOf(String search, {int length}) {
+    test._assertHasRelation(
+        element,
+        relations,
+        IndexRelationKind.IS_ANCESTOR_OF,
+        test._expectedLocation(search, false, length: length));
+  }
+
+  void isExtendedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(
+        element,
+        relations,
+        IndexRelationKind.IS_EXTENDED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isImplementedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(
+        element,
+        relations,
+        IndexRelationKind.IS_IMPLEMENTED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isInvokedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, relations, IndexRelationKind.IS_INVOKED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isMixedInAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(
+        element,
+        relations,
+        IndexRelationKind.IS_MIXED_IN_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isReferencedAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(
+        element,
+        relations,
+        IndexRelationKind.IS_REFERENCED_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+
+  void isWrittenAt(String search, bool isQualified, {int length}) {
+    test._assertHasRelation(element, relations, IndexRelationKind.IS_WRITTEN_BY,
+        test._expectedLocation(search, isQualified, length: length));
+  }
+}
+
+/**
+ * Wraps an [_ElementVisitorFunction] into a [GeneralizingElementVisitor].
+ */
+class _ElementVisitorFunctionWrapper extends GeneralizingElementVisitor {
+  final _ElementVisitorFunction function;
+
+  _ElementVisitorFunctionWrapper(this.function);
+
+  visitElement(Element element) {
+    function(element);
+    super.visitElement(element);
+  }
+}
+
+class _NameIndexAssert {
+  final IndexTest test;
+  final String name;
+
+  _NameIndexAssert(this.test, this.name);
+
+  void isNotUsed(String search, IndexRelationKind kind) {
+    test._assertUsedName(
+        name, kind, test._expectedLocation(search, false), true);
+  }
+
+  void isNotUsedQ(String search, IndexRelationKind kind) {
+    test._assertUsedName(
+        name, kind, test._expectedLocation(search, true), true);
+  }
+
+  void isUsed(String search, IndexRelationKind kind) {
+    test._assertUsedName(
+        name, kind, test._expectedLocation(search, false), false);
+  }
+
+  void isUsedQ(String search, IndexRelationKind kind) {
+    test._assertUsedName(
+        name, kind, test._expectedLocation(search, true), false);
+  }
+}
+
+class _Relation {
+  final IndexRelationKind kind;
+  final int offset;
+  final int length;
+  final bool isQualified;
+
+  _Relation(this.kind, this.offset, this.length, this.isQualified);
+
+  @override
+  String toString() {
+    return '_Relation{kind: $kind, offset: $offset, length: $length, '
+        'isQualified: $isQualified}lified)';
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
new file mode 100644
index 0000000..03a2a53
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -0,0 +1,168 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/search.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'base.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SearchTest);
+  });
+}
+
+class ExpectedResult {
+  final List<String> enclosingComponents;
+  final SearchResultKind kind;
+  final int offset;
+  final int length;
+  final bool isResolved;
+  final bool isQualified;
+
+  ExpectedResult(this.enclosingComponents, this.kind, this.offset, this.length,
+      {this.isResolved: true, this.isQualified: false});
+
+  bool operator ==(Object result) {
+    return result is SearchResult &&
+        result.kind == this.kind &&
+        result.isResolved == this.isResolved &&
+        result.isQualified == this.isQualified &&
+        result.offset == this.offset &&
+        hasExpectedComponents(result.enclosingElement);
+  }
+
+  bool hasExpectedComponents(Element element) {
+    for (int i = enclosingComponents.length - 1; i >= 0; i--) {
+      if (element == null) {
+        return false;
+      }
+      if (element is CompilationUnitElement) {
+        if (element.source.uri.toString() != enclosingComponents[0]) {
+          return false;
+        }
+      } else if (element.name != enclosingComponents[i]) {
+        return false;
+      }
+      element = element.enclosingElement;
+    }
+    return true;
+  }
+
+  @override
+  String toString() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.write("ExpectedResult(kind=");
+    buffer.write(kind);
+    buffer.write(", enclosingComponents=");
+    buffer.write(enclosingComponents);
+    buffer.write(", offset=");
+    buffer.write(offset);
+    buffer.write(", length=");
+    buffer.write(length);
+    buffer.write(", isResolved=");
+    buffer.write(isResolved);
+    buffer.write(", isQualified=");
+    buffer.write(isQualified);
+    buffer.write(")");
+    return buffer.toString();
+  }
+}
+
+@reflectiveTest
+class SearchTest extends BaseAnalysisDriverTest {
+  static const testUri = 'package:test/test.dart';
+
+  test_searchReferences_Label() async {
+    addTestFile('''
+main() {
+label:
+  while (true) {
+    if (true) {
+      break label; // 1
+    }
+    break label; // 2
+  }
+}
+''');
+    int offset = findOffset('label:');
+    List<String> main = [testUri, 'main'];
+    var expected = [
+      _expectId(main, SearchResultKind.REFERENCE, 'label; // 1'),
+      _expectId(main, SearchResultKind.REFERENCE, 'label; // 2')
+    ];
+    await _verifyReferences(offset, expected);
+  }
+
+  test_searchReferences_localVariable() async {
+    addTestFile(r'''
+main() {
+  var v;
+  v = 1;
+  v += 2;
+  print(v);
+  v();
+}
+''');
+    int offset = findOffset('v;');
+    List<String> main = [testUri, 'main'];
+    var expected = [
+      _expectId(main, SearchResultKind.WRITE, 'v = 1;'),
+      _expectId(main, SearchResultKind.READ_WRITE, 'v += 2;'),
+      _expectId(main, SearchResultKind.READ, 'v);'),
+      _expectId(main, SearchResultKind.INVOCATION, 'v();')
+    ];
+    await _verifyReferences(offset, expected);
+  }
+
+  test_searchReferences_localVariable_inForEachLoop() async {
+    addTestFile('''
+main() {
+  for (var v in []) {
+    v = 1;
+    v += 2;
+    print(v);
+    v();
+  }
+}
+''');
+    int offset = findOffset('v in []');
+    List<String> main = [testUri, 'main'];
+    var expected = [
+      _expectId(main, SearchResultKind.WRITE, 'v = 1;'),
+      _expectId(main, SearchResultKind.READ_WRITE, 'v += 2;'),
+      _expectId(main, SearchResultKind.READ, 'v);'),
+      _expectId(main, SearchResultKind.INVOCATION, 'v();')
+    ];
+    await _verifyReferences(offset, expected);
+  }
+
+  ExpectedResult _expectId(
+      List<String> enclosingComponents, SearchResultKind kind, String search,
+      {int length, bool isResolved: true, bool isQualified: false}) {
+    int offset = findOffset(search);
+    if (length == null) {
+      length = getLeadingIdentifierLength(search);
+    }
+    return new ExpectedResult(enclosingComponents, kind, offset, length,
+        isResolved: isResolved, isQualified: isQualified);
+  }
+
+  Future _verifyReferences(
+      int offset, List<ExpectedResult> expectedMatches) async {
+    List<SearchResult> results =
+        await driver.search.references(testFile, offset);
+    _assertResults(results, expectedMatches);
+    expect(results, hasLength(expectedMatches.length));
+  }
+
+  static void _assertResults(
+      List<SearchResult> matches, List<ExpectedResult> expectedMatches) {
+    expect(matches, unorderedEquals(expectedMatches));
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/analysis/test_all.dart b/pkg/analyzer/test/src/dart/analysis/test_all.dart
index 0ba933e..9abcfca 100644
--- a/pkg/analyzer/test/src/dart/analysis/test_all.dart
+++ b/pkg/analyzer/test/src/dart/analysis/test_all.dart
@@ -9,7 +9,9 @@
 import 'byte_store_test.dart' as byte_store;
 import 'driver_test.dart' as driver;
 import 'file_state_test.dart' as file_state;
+import 'index_test.dart' as index;
 import 'referenced_names_test.dart' as referenced_names;
+import 'search_test.dart' as search_test;
 
 /// Utility for manually running all tests.
 main() {
@@ -17,6 +19,8 @@
     byte_store.main();
     driver.main();
     file_state.main();
+    index.main();
     referenced_names.main();
+    search_test.main();
   }, name: 'analysis');
 }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 664882b..be1ba73 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -3433,6 +3433,12 @@
     expect(resynthesized.imports[1].importedLibrary.isDartCore, true);
   }
 
+  test_import_short_absolute() {
+    testFile = '/my/project/bin/test.dart';
+    addLibrarySource('/a.dart', 'class C {}');
+    checkLibrary('import "/a.dart"; C c;');
+  }
+
   test_import_show() {
     addLibrary('dart:async');
     checkLibrary('''
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 f38f362..ae546d5 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -4608,6 +4608,37 @@
     expect(v.name, 'v');
     expect(v.type.toString(), 'double');
   }
+
+  void test_voidReturnTypeSubtypesDynamic() {
+    var unit = checkFile(r'''
+/*=T*/ run/*<T>*/(/*=T*/ f()) {
+  print("running");
+  var t = f();
+  print("done running");
+  return t;
+}
+
+
+void printRunning() { print("running"); }
+var x = run/*<dynamic>*/(printRunning);
+var y = run(printRunning);
+
+main() {
+  void printRunning() { print("running"); }
+  var x = run/*<dynamic>*/(printRunning);
+  var y = run(printRunning);
+  x = 123;
+  x = 'hi';
+  y = 123;
+  y = 'hi';
+}
+    ''');
+
+    var x = unit.topLevelVariables[0];
+    var y = unit.topLevelVariables[1];
+    expect(x.type.toString(), 'dynamic');
+    expect(y.type.toString(), 'dynamic');
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/util/fast_uri_test.dart b/pkg/analyzer/test/src/util/fast_uri_test.dart
index 8ed7be6..f04dcb4 100644
--- a/pkg/analyzer/test/src/util/fast_uri_test.dart
+++ b/pkg/analyzer/test/src/util/fast_uri_test.dart
@@ -117,6 +117,17 @@
     _compareUris(uri3, Uri.parse('package:analyzer/aaa/bbbb/dd/eeee.dart'));
   }
 
+  void test_resolveUri_short_absolute() {
+    // Check the case where the URI being resolved is a "short absolute" uri
+    // (starts with a "/" but doesn't start with "file://").  Such URIs are not
+    // actually valid URIs but we still want to handle them in a way that's
+    // consistent with the behavior of Uri.
+    String containing = 'file:///foo/bar';
+    String relative = '/a.dart';
+    String expectedResult = Uri.parse(containing).resolve(relative).toString();
+    _checkResolveUri(containing, relative, expectedResult);
+  }
+
   void _checkResolveUri(String srcText, String relText, String targetText) {
     Uri src = FastUri.parse(srcText);
     Uri rel = FastUri.parse(relText);
diff --git a/pkg/analyzer_cli/BUILD.gn b/pkg/analyzer_cli/BUILD.gn
new file mode 100644
index 0000000..69993f0
--- /dev/null
+++ b/pkg/analyzer_cli/BUILD.gn
@@ -0,0 +1,23 @@
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import("//build/dart/dart_package.gni")
+
+dart_package("analyzer_cli") {
+  package_name = "analyzer_cli"
+
+  source_dir = "lib"
+
+  deps = [
+    "//dart/pkg/analyzer",
+    "//third_party/dart-pkg/pub/args",
+    "//third_party/dart-pkg/pub/bazel_worker",
+    "//third_party/dart-pkg/pub/cli_util",
+    "//third_party/dart-pkg/pub/linter",
+    "//third_party/dart-pkg/pub/package_config",
+    "//third_party/dart-pkg/pub/plugin",
+    "//third_party/dart-pkg/pub/protobuf",
+    "//third_party/dart-pkg/pub/yaml",
+  ]
+}
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 94a751c..8d7b735 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -51,11 +51,17 @@
 
   static const String conditionalDirectives = '--conditional-directives';
 
-  // Experimental flags.
-
-  // Considerations about this feature (esp. locations where generalizations
-  // or changes are required for full support of generic methods) are marked
-  // with 'GENERIC_METHODS'. The approach taken is to parse generic methods,
+  // The syntax-only level of support for generic methods is included in the
+  // 1.50 milestone for Dart. It is not experimental, but also not permanent:
+  // a full implementation is expected in the future. Hence, the
+  // 'GENERIC_METHODS' comments which were added when this feature was
+  // experimental have been preserved, such that it will be easy to find the
+  // relevant locations to update when generic methods are implemented fully.
+  //
+  // The option is still accepted, but it has no effect: The feature is enabled
+  // by default and it cannot be disabled.
+  //
+  // The approach taken in the implementation is to parse generic methods,
   // introduce AST nodes for them, generate corresponding types (such that
   // front end treatment is consistent with the code that programmers wrote),
   // but considering all method type variables to have bound `dynamic` no
@@ -63,7 +69,12 @@
   // is unchecked), and then replacing method type variables by a `DynamicType`
   // (such that the backend does not need to take method type arguments into
   // account).
+  //
+  // The feature has an informal specification which is available at
+  // https://gist.github.com/eernstg/4353d7b4f669745bed3a5423e04a453c.
   static const String genericMethodSyntax = '--generic-method-syntax';
+
+  // Experimental flags.
   static const String resolveOnly = '--resolve-only';
   static const String initializingFormalAccess = '--initializing-formal-access';
 }
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index a5e4003..a65c6ef 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -1221,7 +1221,6 @@
       MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED: const MessageTemplate(
           MessageKind.TYPE_VARIABLE_FROM_METHOD_NOT_REIFIED,
           "Method type variables do not have a runtime value.",
-          options: const ["--generic-method-syntax"],
           howToFix: "Try using the upper bound of the type variable, "
               "or refactor the code to avoid needing this runtime value.",
           examples: const [
@@ -1243,7 +1242,6 @@
       const MessageTemplate(
           MessageKind.TYPE_VARIABLE_FROM_METHOD_CONSIDERED_DYNAMIC,
           "Method type variables are treated as `dynamic` in `as` expressions.",
-          options: const ["--generic-method-syntax"],
           howToFix: "Try using the upper bound of the type variable, or check "
               "that the blind success of the test does not introduce bugs.",
           examples: const [
diff --git a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
index 93344f6..c66c8f1 100644
--- a/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/mirrors_analysis.dart
@@ -4,6 +4,7 @@
 
 library dart2js.mirrors_handler;
 
+import '../common.dart';
 import '../common/resolution.dart';
 import '../diagnostics/diagnostic_listener.dart';
 import '../elements/elements.dart';
@@ -189,8 +190,13 @@
     lib.forEachLocalMember((Element member) {
       if (member.isInjected) return;
       if (member.isClass) {
-        _enqueueReflectiveElementsInClass(member, recents,
-            enclosingWasIncluded: includeLibrary);
+        ClassElement cls = member;
+        cls.ensureResolved(_resolution);
+        do {
+          _enqueueReflectiveElementsInClass(cls, recents,
+              enclosingWasIncluded: includeLibrary);
+          cls = cls.superclass;
+        } while (cls != null && cls.isUnnamedMixinApplication);
       } else {
         _enqueueReflectiveMember(member, includeLibrary);
       }
diff --git a/pkg/compiler/lib/src/kernel/kernel.dart b/pkg/compiler/lib/src/kernel/kernel.dart
index a4da817..3b403b7 100644
--- a/pkg/compiler/lib/src/kernel/kernel.dart
+++ b/pkg/compiler/lib/src/kernel/kernel.dart
@@ -192,11 +192,11 @@
           fields: null);
       addWork(cls, () {
         if (cls.supertype != null) {
-          classNode.supertype = interfaceTypeToIr(cls.supertype);
+          classNode.supertype = supertypeToIr(cls.supertype);
         }
         if (cls.isMixinApplication) {
           MixinApplicationElement mixinApplication = cls;
-          classNode.mixedInType = interfaceTypeToIr(mixinApplication.mixinType);
+          classNode.mixedInType = supertypeToIr(mixinApplication.mixinType);
         }
         classNode.parent = libraryToIr(cls.library);
         if (cls.isUnnamedMixinApplication) {
@@ -222,10 +222,10 @@
           }
         });
         classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
-        for (ir.InterfaceType interface
-            in typesToIr(cls.interfaces.reverse().toList())) {
-          if (interface != classNode.mixedInType) {
-            classNode.implementedTypes.add(interface);
+        for (ir.Supertype supertype
+            in supertypesToIr(cls.interfaces.reverse().toList())) {
+          if (supertype != classNode.mixedInType) {
+            classNode.implementedTypes.add(supertype);
           }
         }
         addWork(cls, () {
@@ -284,6 +284,15 @@
     }
   }
 
+  ir.Supertype supertypeToIr(InterfaceType type) {
+    ir.Class cls = classToIr(type.element);
+    if (type.typeArguments.isEmpty) {
+      return cls.asRawSupertype;
+    } else {
+      return new ir.Supertype(cls, typesToIr(type.typeArguments));
+    }
+  }
+
   // TODO(ahe): Remove this method when dart2js support generic type arguments.
   List<ir.TypeParameter> typeParametersNotImplemented() {
     return const <ir.TypeParameter>[];
@@ -295,11 +304,10 @@
     List<ir.DartType> positionalParameters =
         new List<ir.DartType>.from(typesToIr(type.parameterTypes))
           ..addAll(typesToIr(type.optionalParameterTypes));
-    Map<String, ir.DartType> namedParameters = <String, ir.DartType>{};
-    for (int i = 0; i < type.namedParameters.length; i++) {
-      namedParameters[type.namedParameters[i]] =
-          typeToIr(type.namedParameterTypes[i]);
-    }
+    List<ir.NamedType> namedParameters = new List<ir.NamedType>.generate(
+        type.namedParameters.length,
+        (i) => new ir.NamedType(
+            type.namedParameters[i], typeToIr(type.namedParameterTypes[i])));
     ir.DartType returnType = typeToIr(type.returnType);
 
     return new ir.FunctionType(positionalParameters, returnType,
@@ -320,6 +328,14 @@
     return result;
   }
 
+  List<ir.Supertype> supertypesToIr(List<DartType> types) {
+    List<ir.Supertype> result = new List<ir.Supertype>(types.length);
+    for (int i = 0; i < types.length; i++) {
+      result[i] = supertypeToIr(types[i]);
+    }
+    return result;
+  }
+
   ir.DartType typeToIr(DartType type) {
     switch (type.kind) {
       case TypeKind.FUNCTION:
diff --git a/pkg/compiler/lib/src/kernel/kernel_visitor.dart b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
index 39a1a8d..d4d6216 100644
--- a/pkg/compiler/lib/src/kernel/kernel_visitor.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
@@ -710,7 +710,8 @@
     return new ir.ConditionalExpression(
         visitForValue(node.condition),
         visitWithCurrentContext(node.thenExpression),
-        visitWithCurrentContext(node.elseExpression));
+        visitWithCurrentContext(node.elseExpression),
+        null);
   }
 
   @override
@@ -1312,7 +1313,7 @@
     Accessor accessor = (receiver == null)
         ? new ThisPropertyAccessor(irName, null, null)
         : PropertyAccessor.make(visitForValue(receiver), irName, null, null);
-    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+    return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -1504,7 +1505,7 @@
 
   Accessor buildNullAwarePropertyAccessor(Node receiver, Name name) {
     return new NullAwarePropertyAccessor(
-        visitForValue(receiver), nameToIrName(name), null, null);
+        visitForValue(receiver), nameToIrName(name), null, null, null);
   }
 
   @override
@@ -1524,7 +1525,8 @@
             buildIsNull(new ir.VariableGet(receiver)),
             new ir.NullLiteral(),
             buildInvokeSelector(new ir.VariableGet(receiver), selector,
-                buildArguments(arguments))));
+                buildArguments(arguments)),
+            null));
   }
 
   @override
@@ -1538,7 +1540,7 @@
   ir.Expression visitIfNotNullDynamicPropertySetIfNull(
       Send node, Node receiver, Name name, Node rhs, _) {
     return buildNullAwarePropertyAccessor(receiver, name)
-        .buildNullAwareAssignment(visitForValue(rhs),
+        .buildNullAwareAssignment(visitForValue(rhs), null,
             voidContext: isVoidContext);
   }
 
@@ -1549,8 +1551,12 @@
   }
 
   @override
-  ir.LogicalExpression visitIfNull(Send node, Node left, Node right, _) {
-    return buildLogicalExpression(left, node.selector, right);
+  ir.Expression visitIfNull(Send node, Node left, Node right, _) {
+    var leftValue = new ir.VariableDeclaration.forValue(visitForValue(left));
+    return new ir.Let(
+        leftValue,
+        new ir.ConditionalExpression(buildIsNull(new ir.VariableGet(leftValue)),
+            visitForValue(right), new ir.VariableGet(leftValue), null));
   }
 
   @override
@@ -1837,7 +1843,7 @@
       SendSet node, LocalElement local, Node rhs, _,
       {bool isSetterValid}) {
     return new VariableAccessor(getLocal(local)).buildNullAwareAssignment(
-        visitForValue(rhs),
+        visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -1925,7 +1931,7 @@
 
   @override
   ir.Expression handleStaticFieldGet(Send node, FieldElement field, _) {
-    return buildStaticGet(field);
+    return associateNode(buildStaticGet(field), node);
   }
 
   @override
@@ -1954,7 +1960,7 @@
       setter = null;
     }
     return buildStaticAccessor(getter, setter).buildNullAwareAssignment(
-        visitForValue(rhs),
+        visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -1991,6 +1997,7 @@
           positionalParameters.add(variable);
         }
       });
+      namedParameters.sort();
       signature.forEachParameter((ParameterElement parameter) {
         if (!parameter.isOptional) return;
         ir.Expression initializer = visitForValue(parameter.initializer);
@@ -2132,7 +2139,8 @@
       NodeList arguments,
       CallStructure callStructure,
       _) {
-    return buildStaticInvoke(function, arguments, isConst: false);
+    return associateNode(
+        buildStaticInvoke(function, arguments, isConst: false), node);
   }
 
   @override
@@ -2394,7 +2402,7 @@
       setter = null;
     }
     return buildSuperPropertyAccessor(getter, setter).buildNullAwareAssignment(
-        visitForValue(rhs),
+        visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -2623,7 +2631,7 @@
   ir.Expression visitTypeVariableTypeLiteralSetIfNull(
       Send node, TypeVariableElement element, Node rhs, _) {
     return new ReadOnlyAccessor(buildTypeVariable(element))
-        .buildNullAwareAssignment(visitForValue(rhs),
+        .buildNullAwareAssignment(visitForValue(rhs), null,
             voidContext: isVoidContext);
   }
 
@@ -2689,7 +2697,7 @@
   ir.Expression visitIndexSetIfNull(
       SendSet node, Node receiver, Node index, Node rhs, _) {
     return buildIndexAccessor(receiver, index).buildNullAwareAssignment(
-        visitForValue(rhs),
+        visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -2697,7 +2705,7 @@
   ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter,
       MethodElement setter, Node index, Node rhs, _) {
     return buildSuperIndexAccessor(index, getter, setter)
-        .buildNullAwareAssignment(visitForValue(rhs),
+        .buildNullAwareAssignment(visitForValue(rhs), null,
             voidContext: isVoidContext);
   }
 
@@ -2757,7 +2765,7 @@
       FieldElement field = currentElement;
       return field.isMalformed
           ? new ir.InvalidExpression()
-          : visitForValue(field.initializer);
+          : associateNode(visitForValue(field.initializer), field.initializer);
     });
   }
 }
diff --git a/pkg/compiler/lib/src/kernel/unresolved.dart b/pkg/compiler/lib/src/kernel/unresolved.dart
index c1e332d..04632b7 100644
--- a/pkg/compiler/lib/src/kernel/unresolved.dart
+++ b/pkg/compiler/lib/src/kernel/unresolved.dart
@@ -272,7 +272,7 @@
       Send node, MethodElement getter, Element element, Node rhs, _) {
     var accessor = new ClassStaticAccessor(
         this, getter.name, possiblyErroneousFunctionToIr(getter), null);
-    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+    return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
@@ -457,7 +457,7 @@
   ir.Expression visitUnresolvedSuperSetterSetIfNull(
       Send node, MethodElement getter, Element element, Node rhs, _) {
     return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
-        .buildNullAwareAssignment(visitForValue(rhs));
+        .buildNullAwareAssignment(visitForValue(rhs), null);
   }
 
   ir.Expression visitUnresolvedSuperUnary(
@@ -533,26 +533,26 @@
       Send node, MethodElement getter, Element element, Node rhs, _) {
     var accessor = new TopLevelStaticAccessor(
         this, getter.name, possiblyErroneousFunctionToIr(getter), null);
-    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+    return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
         voidContext: isVoidContext);
   }
 
   ir.Expression visitUnresolvedSuperGetterIndexSetIfNull(Send node,
       Element element, MethodElement setter, Node index, Node rhs, _) {
     return buildUnresolvedSuperIndexAccessor(index, element)
-        .buildNullAwareAssignment(visitForValue(rhs));
+        .buildNullAwareAssignment(visitForValue(rhs), null);
   }
 
   ir.Expression visitUnresolvedSuperSetterIndexSetIfNull(Send node,
       MethodElement getter, Element element, Node index, Node rhs, _) {
     return buildUnresolvedSuperIndexAccessor(index, element)
-        .buildNullAwareAssignment(visitForValue(rhs));
+        .buildNullAwareAssignment(visitForValue(rhs), null);
   }
 
   ir.Expression visitUnresolvedSuperIndexSetIfNull(
       Send node, Element element, Node index, Node rhs, _) {
     return buildUnresolvedSuperIndexAccessor(index, element)
-        .buildNullAwareAssignment(visitForValue(rhs));
+        .buildNullAwareAssignment(visitForValue(rhs), null);
   }
 
   ir.Expression visitUnresolvedSuperSet(
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 65ea1b8..f490329 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -289,7 +289,7 @@
         dumpInfo: _hasOption(options, Flags.dumpInfo),
         enableAssertMessage: _hasOption(options, Flags.enableAssertMessage),
         enableGenericMethodSyntax:
-            _hasOption(options, Flags.genericMethodSyntax),
+            true, // No check for `Flags.genericMethodSyntax`: always enabled.
         enableInitializingFormalAccess:
             _hasOption(options, Flags.initializingFormalAccess),
         enableExperimentalMirrors:
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 16843b3..27f164f 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -1310,6 +1310,8 @@
     Node right = node.arguments.head;
     visitExpression(left);
     visitExpression(right);
+    registry.registerConstantLiteral(new NullConstantExpression());
+    registry.registerDynamicUse(new DynamicUse(Selectors.equals, null));
     registry.registerSendStructure(node, const IfNullStructure());
     return const NoneResult();
   }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 1c922e5..8ea98e3 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -9,11 +9,14 @@
 import '../common/names.dart';
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart';
+import '../constants/values.dart' show StringConstantValue;
 import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../io/source_information.dart';
+import '../js/js.dart' as js;
 import '../js_backend/backend.dart' show JavaScriptBackend;
 import '../kernel/kernel.dart';
+import '../native/native.dart' as native;
 import '../resolution/tree_elements.dart';
 import '../tree/dartstring.dart';
 import '../tree/nodes.dart' show FunctionExpression, Node;
@@ -21,6 +24,7 @@
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart';
 import '../universe/use.dart' show TypeUse;
+import '../universe/side_effects.dart' show SideEffects;
 import 'graph_builder.dart';
 import 'kernel_ast_adapter.dart';
 import 'kernel_string_builder.dart';
@@ -865,12 +869,16 @@
 
   @override
   void visitStaticGet(ir.StaticGet staticGet) {
-    var staticTarget = staticGet.target;
+    ir.Member staticTarget = staticGet.target;
     if (staticTarget is ir.Procedure &&
         staticTarget.kind == ir.ProcedureKind.Getter) {
       // Invoke the getter
       _pushStaticInvocation(staticTarget, const <HInstruction>[],
           astAdapter.returnTypeOf(staticTarget));
+    } else if (staticTarget is ir.Field && staticTarget.isConst) {
+      assert(staticTarget.initializer != null);
+      stack.add(graph.addConstant(
+          astAdapter.getConstantFor(staticTarget.initializer), compiler));
     } else {
       push(new HStatic(astAdapter.getMember(staticTarget),
           astAdapter.inferredTypeOf(staticTarget)));
@@ -973,6 +981,10 @@
   @override
   void visitStaticInvocation(ir.StaticInvocation invocation) {
     ir.Procedure target = invocation.target;
+    if (astAdapter.isInForeignLibrary(target)) {
+      handleInvokeStaticForeign(invocation, target);
+      return;
+    }
     TypeMask typeMask = astAdapter.returnTypeOf(target);
 
     List<HInstruction> arguments = _visitArguments(invocation.arguments);
@@ -980,6 +992,378 @@
     _pushStaticInvocation(target, arguments, typeMask);
   }
 
+  void handleInvokeStaticForeign(
+      ir.StaticInvocation invocation, ir.Procedure target) {
+    String name = target.name.name;
+    if (name == 'JS') {
+      handleForeignJs(invocation);
+    } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
+      handleForeignJsCurrentIsolateContext(invocation);
+    } else if (name == 'JS_CALL_IN_ISOLATE') {
+      handleForeignJsCallInIsolate(invocation);
+    } else if (name == 'DART_CLOSURE_TO_JS') {
+      handleForeignDartClosureToJs(invocation, 'DART_CLOSURE_TO_JS');
+    } else if (name == 'RAW_DART_FUNCTION_REF') {
+      handleForeignRawFunctionRef(invocation, 'RAW_DART_FUNCTION_REF');
+    } else if (name == 'JS_SET_STATIC_STATE') {
+      handleForeignJsSetStaticState(invocation);
+    } else if (name == 'JS_GET_STATIC_STATE') {
+      handleForeignJsGetStaticState(invocation);
+    } else if (name == 'JS_GET_NAME') {
+      handleForeignJsGetName(invocation);
+    } else if (name == 'JS_EMBEDDED_GLOBAL') {
+      handleForeignJsEmbeddedGlobal(invocation);
+    } else if (name == 'JS_BUILTIN') {
+      handleForeignJsBuiltin(invocation);
+    } else if (name == 'JS_GET_FLAG') {
+      handleForeignJsGetFlag(invocation);
+    } else if (name == 'JS_EFFECT') {
+      stack.add(graph.addConstantNull(compiler));
+    } else if (name == 'JS_INTERCEPTOR_CONSTANT') {
+      handleJsInterceptorConstant(invocation);
+    } else if (name == 'JS_STRING_CONCAT') {
+      handleJsStringConcat(invocation);
+    } else {
+      compiler.reporter.internalError(
+          astAdapter.getNode(invocation), "Unknown foreign: ${name}");
+    }
+  }
+
+  bool _unexpectedForeignArguments(
+      ir.StaticInvocation invocation, int minPositional,
+      [int maxPositional]) {
+    String pluralizeArguments(int count) {
+      if (count == 0) return 'no arguments';
+      if (count == 1) return 'one argument';
+      if (count == 2) return 'two arguments';
+      return '$count arguments';
+    }
+
+    String name() => invocation.target.name.name;
+
+    ir.Arguments arguments = invocation.arguments;
+    bool bad = false;
+    if (arguments.types.isNotEmpty) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation),
+          MessageKind.GENERIC,
+          {'text': "Error: '${name()}' does not take type arguments."});
+      bad = true;
+    }
+    if (arguments.positional.length < minPositional) {
+      String phrase = pluralizeArguments(minPositional);
+      if (maxPositional != minPositional) phrase = 'at least $phrase';
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation),
+          MessageKind.GENERIC,
+          {'text': "Error: Too few arguments. '${name()}' takes $phrase."});
+      bad = true;
+    }
+    if (maxPositional != null && arguments.positional.length > maxPositional) {
+      String phrase = pluralizeArguments(maxPositional);
+      if (maxPositional != minPositional) phrase = 'at most $phrase';
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation),
+          MessageKind.GENERIC,
+          {'text': "Error: Too many arguments. '${name()}' takes $phrase."});
+      bad = true;
+    }
+    if (arguments.named.isNotEmpty) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation),
+          MessageKind.GENERIC,
+          {'text': "Error: '${name()}' does not take named arguments."});
+      bad = true;
+    }
+    return bad;
+  }
+
+  /// Returns the value of the string argument. The argument must evaluate to a
+  /// constant.  If there is an error, the error is reported and `null` is
+  /// returned.
+  String _foreignConstantStringArgument(
+      ir.StaticInvocation invocation, int position, String methodName,
+      [String adjective = '']) {
+    ir.Expression argument = invocation.arguments.positional[position];
+    argument.accept(this);
+    HInstruction instruction = pop();
+
+    if (!instruction.isConstantString()) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(argument), MessageKind.GENERIC, {
+        'text': "Error: Expected String constant as ${adjective}argument "
+            "to '$methodName'."
+      });
+      return null;
+    }
+
+    HConstant hConstant = instruction;
+    StringConstantValue stringConstant = hConstant.constant;
+    return stringConstant.primitiveValue.slowToString();
+  }
+
+  // TODO(sra): Remove when handleInvokeStaticForeign fully implemented.
+  void unhandledForeign(ir.StaticInvocation invocation) {
+    ir.Procedure target = invocation.target;
+    TypeMask typeMask = astAdapter.returnTypeOf(target);
+    List<HInstruction> arguments = _visitArguments(invocation.arguments);
+    _pushStaticInvocation(target, arguments, typeMask);
+  }
+
+  void handleForeignJsCurrentIsolateContext(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 0, 0)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    if (!compiler.hasIsolateSupport) {
+      // If the isolate library is not used, we just generate code
+      // to fetch the static state.
+      String name = backend.namer.staticStateHolder;
+      push(new HForeignCode(
+          js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
+          nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+    } else {
+      // Call a helper method from the isolate library. The isolate library uses
+      // its own isolate structure that encapsulates the isolate structure used
+      // for binding to methods.
+      ir.Procedure target = astAdapter.currentIsolate;
+      if (target == null) {
+        compiler.reporter.internalError(astAdapter.getNode(invocation),
+            'Isolate library and compiler mismatch.');
+      }
+      _pushStaticInvocation(target, <HInstruction>[], backend.dynamicType);
+    }
+
+    /*
+    if (!node.arguments.isEmpty) {
+      reporter.internalError(
+          node, 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT.');
+    }
+
+    if (!compiler.hasIsolateSupport) {
+      // If the isolate library is not used, we just generate code
+      // to fetch the static state.
+      String name = backend.namer.staticStateHolder;
+      push(new HForeignCode(
+          js.js.parseForeignJS(name), backend.dynamicType, <HInstruction>[],
+          nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+    } else {
+      // Call a helper method from the isolate library. The isolate
+      // library uses its own isolate structure, that encapsulates
+      // Leg's isolate.
+      Element element = helpers.currentIsolate;
+      if (element == null) {
+        reporter.internalError(node, 'Isolate library and compiler mismatch.');
+      }
+      pushInvokeStatic(null, element, [], typeMask: backend.dynamicType);
+    }
+    */
+  }
+
+  void handleForeignJsCallInIsolate(ir.StaticInvocation invocation) {
+    unhandledForeign(invocation);
+  }
+
+  void handleForeignDartClosureToJs(
+      ir.StaticInvocation invocation, String name) {
+    unhandledForeign(invocation);
+  }
+
+  void handleForeignRawFunctionRef(
+      ir.StaticInvocation invocation, String name) {
+    unhandledForeign(invocation);
+  }
+
+  void handleForeignJsSetStaticState(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 0, 0)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+    _visitArguments(invocation.arguments);
+    String isolateName = backend.namer.staticStateHolder;
+    SideEffects sideEffects = new SideEffects.empty();
+    sideEffects.setAllSideEffects();
+    push(new HForeignCode(js.js.parseForeignJS("$isolateName = #"),
+        backend.dynamicType, <HInstruction>[pop()],
+        nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
+        effects: sideEffects));
+  }
+
+  void handleForeignJsGetStaticState(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 0, 0)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
+        backend.dynamicType, <HInstruction>[],
+        nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
+  }
+
+  void handleForeignJsGetName(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 1, 1)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    ir.Node argument = invocation.arguments.positional.first;
+    argument.accept(this);
+    HInstruction instruction = pop();
+
+    if (instruction is HConstant) {
+      js.Name name =
+          astAdapter.getNameForJsGetName(argument, instruction.constant);
+      stack.add(graph.addConstantStringFromName(name, compiler));
+      return;
+    }
+
+    compiler.reporter.reportErrorMessage(
+        astAdapter.getNode(argument),
+        MessageKind.GENERIC,
+        {'text': 'Error: Expected a JsGetName enum value.'});
+    stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+  }
+
+  void handleForeignJsEmbeddedGlobal(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 2, 2)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+    String globalName = _foreignConstantStringArgument(
+        invocation, 1, 'JS_EMBEDDED_GLOBAL', 'second ');
+    js.Template expr = js.js.expressionTemplateYielding(
+        backend.emitter.generateEmbeddedGlobalAccess(globalName));
+
+    native.NativeBehavior nativeBehavior =
+        astAdapter.getNativeBehavior(invocation);
+    assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+        message: "No NativeBehavior for $invocation"));
+
+    TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+    push(new HForeignCode(expr, ssaType, const <HInstruction>[],
+        nativeBehavior: nativeBehavior));
+  }
+
+  void handleForeignJsBuiltin(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 2)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    List<ir.Expression> arguments = invocation.arguments.positional;
+    ir.Expression nameArgument = arguments[1];
+
+    nameArgument.accept(this);
+    HInstruction instruction = pop();
+
+    js.Template template;
+    if (instruction is HConstant) {
+      template = astAdapter.getJsBuiltinTemplate(instruction.constant);
+    }
+    if (template == null) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(nameArgument),
+          MessageKind.GENERIC,
+          {'text': 'Error: Expected a JsBuiltin enum value.'});
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    List<HInstruction> inputs = <HInstruction>[];
+    for (ir.Expression argument in arguments.skip(2)) {
+      argument.accept(this);
+      inputs.add(pop());
+    }
+
+    native.NativeBehavior nativeBehavior =
+        astAdapter.getNativeBehavior(invocation);
+    assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+        message: "No NativeBehavior for $invocation"));
+
+    TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+    push(new HForeignCode(template, ssaType, inputs,
+        nativeBehavior: nativeBehavior));
+  }
+
+  void handleForeignJsGetFlag(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 1, 1)) {
+      stack.add(
+          graph.addConstantBool(false, compiler)); // Result expected on stack.
+      return;
+    }
+    String name = _foreignConstantStringArgument(invocation, 0, 'JS_GET_FLAG');
+    bool value = false;
+    switch (name) {
+      case 'MUST_RETAIN_METADATA':
+        value = backend.mustRetainMetadata;
+        break;
+      case 'USE_CONTENT_SECURITY_POLICY':
+        value = compiler.options.useContentSecurityPolicy;
+        break;
+      default:
+        compiler.reporter.reportErrorMessage(
+            astAdapter.getNode(invocation),
+            MessageKind.GENERIC,
+            {'text': 'Error: Unknown internal flag "$name".'});
+    }
+    stack.add(graph.addConstantBool(value, compiler));
+  }
+
+  void handleJsInterceptorConstant(ir.StaticInvocation invocation) {
+    unhandledForeign(invocation);
+  }
+
+  void handleForeignJs(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 2)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    native.NativeBehavior nativeBehavior =
+        astAdapter.getNativeBehavior(invocation);
+    assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null,
+        message: "No NativeBehavior for $invocation"));
+
+    List<HInstruction> inputs = <HInstruction>[];
+    for (ir.Expression argument in invocation.arguments.positional.skip(2)) {
+      argument.accept(this);
+      inputs.add(pop());
+    }
+
+    if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation), MessageKind.GENERIC, {
+        'text': 'Mismatch between number of placeholders'
+            ' and number of arguments.'
+      });
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+
+    if (native.HasCapturedPlaceholders.check(nativeBehavior.codeTemplate.ast)) {
+      compiler.reporter.reportErrorMessage(
+          astAdapter.getNode(invocation), MessageKind.JS_PLACEHOLDER_CAPTURE);
+    }
+
+    TypeMask ssaType = astAdapter.typeFromNativeBehavior(nativeBehavior);
+
+    SourceInformation sourceInformation = null;
+    push(new HForeignCode(nativeBehavior.codeTemplate, ssaType, inputs,
+        isStatement: !nativeBehavior.codeTemplate.isExpression,
+        effects: nativeBehavior.sideEffects,
+        nativeBehavior: nativeBehavior)..sourceInformation = sourceInformation);
+  }
+
+  void handleJsStringConcat(ir.StaticInvocation invocation) {
+    if (_unexpectedForeignArguments(invocation, 2, 2)) {
+      stack.add(graph.addConstantNull(compiler)); // Result expected on stack.
+      return;
+    }
+    List<HInstruction> inputs = _visitArguments(invocation.arguments);
+    push(new HStringConcat(inputs[0], inputs[1], backend.stringType));
+  }
+
   void _pushStaticInvocation(
       ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
     HInvokeStatic instruction = new HInvokeStatic(
diff --git a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
index cf58dce..028b7a8 100644
--- a/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
+++ b/pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:js_runtime/shared/embedded_names.dart';
 import 'package:kernel/ast.dart' as ir;
 
 import '../constants/expressions.dart';
@@ -11,11 +12,12 @@
 import '../constants/values.dart';
 import '../dart_types.dart';
 import '../elements/elements.dart';
+import '../js/js.dart' as js;
 import '../js_backend/backend_helpers.dart';
 import '../js_backend/js_backend.dart';
 import '../kernel/kernel.dart';
 import '../kernel/kernel_debug.dart';
-import '../native/native.dart' show NativeBehavior, TypeLookup;
+import '../native/native.dart' as native;
 import '../resolution/tree_elements.dart';
 import '../tree/tree.dart' as ast;
 import '../types/masks.dart';
@@ -241,6 +243,10 @@
     return TypeMaskFactory.inferredTypeForSelector(selector, mask, _compiler);
   }
 
+  TypeMask typeFromNativeBehavior(native.NativeBehavior nativeBehavior) {
+    return TypeMaskFactory.fromNativeBehavior(nativeBehavior, _compiler);
+  }
+
   ConstantValue getConstantFor(ir.Node node) {
     ConstantValue constantValue =
         _backend.constants.getConstantValueForNode(getNode(node), elements);
@@ -309,6 +315,45 @@
 
   ir.Class get objectClass => kernel.classes[_compiler.coreClasses.objectClass];
 
+  ir.Procedure get currentIsolate =>
+      kernel.functions[_backend.helpers.currentIsolate];
+
+  bool isInForeignLibrary(ir.Member member) =>
+      _backend.isForeign(getElement(member));
+
+  native.NativeBehavior getNativeBehavior(ir.Node node) {
+    return elements.getNativeData(getNode(node));
+  }
+
+  js.Name getNameForJsGetName(ir.Node argument, ConstantValue constant) {
+    int index = _extractEnumIndexFromConstantValue(
+        constant, _backend.helpers.jsGetNameEnum);
+    if (index == null) return null;
+    return _backend.namer
+        .getNameForJsGetName(getNode(argument), JsGetName.values[index]);
+  }
+
+  js.Template getJsBuiltinTemplate(ConstantValue constant) {
+    int index = _extractEnumIndexFromConstantValue(
+        constant, _backend.helpers.jsBuiltinEnum);
+    if (index == null) return null;
+    return _backend.emitter.builtinTemplateFor(JsBuiltin.values[index]);
+  }
+
+  int _extractEnumIndexFromConstantValue(
+      ConstantValue constant, Element classElement) {
+    if (constant is ConstructedConstantValue) {
+      if (constant.type.element == classElement) {
+        assert(constant.fields.length == 1);
+        ConstantValue indexConstant = constant.fields.values.single;
+        if (indexConstant is IntConstantValue) {
+          return indexConstant.primitiveValue;
+        }
+      }
+    }
+    return null;
+  }
+
   DartType getDartType(ir.DartType type) {
     return type.accept(_typeConverter);
   }
@@ -382,10 +427,10 @@
   }
 
   /// Looks up [typeName] for use in the spec-string of a `JS` called.
-  // TODO(johnniwinther): Use this in [NativeBehavior] instead of calling the
+  // TODO(johnniwinther): Use this in [native.NativeBehavior] instead of calling the
   // `ForeignResolver`.
   // TODO(johnniwinther): Cache the result to avoid redundant lookups?
-  TypeLookup _typeLookup({bool resolveAsRaw: true}) {
+  native.TypeLookup _typeLookup({bool resolveAsRaw: true}) {
     return (String typeName) {
       DartType findIn(Uri uri) {
         LibraryElement library = _compiler.libraryLoader.lookupLibrary(uri);
@@ -417,30 +462,30 @@
     return node.arguments.positional[index].accept(new Stringifier());
   }
 
-  /// Computes the [NativeBehavior] for a call to the [JS] function.
+  /// Computes the [native.NativeBehavior] for a call to the [JS] function.
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
+  native.NativeBehavior getNativeBehaviorForJsCall(ir.StaticInvocation node) {
     if (node.arguments.positional.length < 2 ||
         node.arguments.named.isNotEmpty) {
       reporter.reportErrorMessage(
           CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS);
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     String specString = _getStringArgument(node, 0);
     if (specString == null) {
       reporter.reportErrorMessage(
           CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_FIRST);
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
 
     String codeString = _getStringArgument(node, 1);
     if (codeString == null) {
       reporter.reportErrorMessage(
           CURRENT_ELEMENT_SPANNABLE, MessageKind.WRONG_ARGUMENT_FOR_JS_SECOND);
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
 
-    return NativeBehavior.ofJsCall(
+    return native.NativeBehavior.ofJsCall(
         specString,
         codeString,
         _typeLookup(resolveAsRaw: true),
@@ -449,26 +494,27 @@
         _compiler.coreTypes);
   }
 
-  /// Computes the [NativeBehavior] for a call to the [JS_BUILTIN] function.
+  /// Computes the [native.NativeBehavior] for a call to the [JS_BUILTIN] function.
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForJsBuiltinCall(ir.StaticInvocation node) {
+  native.NativeBehavior getNativeBehaviorForJsBuiltinCall(
+      ir.StaticInvocation node) {
     if (node.arguments.positional.length < 1) {
       reporter.internalError(
           CURRENT_ELEMENT_SPANNABLE, "JS builtin expression has no type.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     if (node.arguments.positional.length < 2) {
       reporter.internalError(
           CURRENT_ELEMENT_SPANNABLE, "JS builtin is missing name.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     String specString = _getStringArgument(node, 0);
     if (specString == null) {
       reporter.internalError(
           CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
-    return NativeBehavior.ofJsBuiltinCall(
+    return native.NativeBehavior.ofJsBuiltinCall(
         specString,
         _typeLookup(resolveAsRaw: true),
         CURRENT_ELEMENT_SPANNABLE,
@@ -476,34 +522,34 @@
         _compiler.coreTypes);
   }
 
-  /// Computes the [NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL]
+  /// Computes the [native.NativeBehavior] for a call to the [JS_EMBEDDED_GLOBAL]
   /// function.
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
+  native.NativeBehavior getNativeBehaviorForJsEmbeddedGlobalCall(
       ir.StaticInvocation node) {
     if (node.arguments.positional.length < 1) {
       reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
           "JS embedded global expression has no type.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     if (node.arguments.positional.length < 2) {
       reporter.internalError(
           CURRENT_ELEMENT_SPANNABLE, "JS embedded global is missing name.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     if (node.arguments.positional.length > 2 ||
         node.arguments.named.isNotEmpty) {
       reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
           "JS embedded global has more than 2 arguments.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
     String specString = _getStringArgument(node, 0);
     if (specString == null) {
       reporter.internalError(
           CURRENT_ELEMENT_SPANNABLE, "Unexpected first argument.");
-      return new NativeBehavior();
+      return new native.NativeBehavior();
     }
-    return NativeBehavior.ofJsEmbeddedGlobalCall(
+    return native.NativeBehavior.ofJsEmbeddedGlobalCall(
         specString,
         _typeLookup(resolveAsRaw: true),
         CURRENT_ELEMENT_SPANNABLE,
@@ -528,28 +574,28 @@
 
   /// Computes the native behavior for reading the native [field].
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
+  native.NativeBehavior getNativeBehaviorForFieldLoad(ir.Field field) {
     DartType type = getDartType(field.type);
     List<ConstantExpression> metadata = getMetadata(field.annotations);
-    return NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type, metadata,
-        _typeLookup(resolveAsRaw: false), _compiler,
+    return native.NativeBehavior.ofFieldLoad(CURRENT_ELEMENT_SPANNABLE, type,
+        metadata, _typeLookup(resolveAsRaw: false), _compiler,
         isJsInterop: false);
   }
 
   /// Computes the native behavior for writing to the native [field].
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
+  native.NativeBehavior getNativeBehaviorForFieldStore(ir.Field field) {
     DartType type = getDartType(field.type);
-    return NativeBehavior.ofFieldStore(type, _compiler.resolution);
+    return native.NativeBehavior.ofFieldStore(type, _compiler.resolution);
   }
 
   /// Computes the native behavior for calling [procedure].
   // TODO(johnniwinther): Cache this for later use.
-  NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
+  native.NativeBehavior getNativeBehaviorForMethod(ir.Procedure procedure) {
     DartType type = getFunctionType(procedure.function);
     List<ConstantExpression> metadata = getMetadata(procedure.annotations);
-    return NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type, metadata,
-        _typeLookup(resolveAsRaw: false), _compiler,
+    return native.NativeBehavior.ofMethod(CURRENT_ELEMENT_SPANNABLE, type,
+        metadata, _typeLookup(resolveAsRaw: false), _compiler,
         isJsInterop: false);
   }
 }
@@ -603,8 +649,8 @@
         visitTypes(node.positionalParameters
             .skip(node.requiredParameterCount)
             .toList()),
-        node.namedParameters.keys.toList(),
-        visitTypes(node.namedParameters.values.toList()));
+        node.namedParameters.map((n) => n.name).toList(),
+        node.namedParameters.map((n) => visitType(n.type)).toList());
   }
 
   @override
diff --git a/pkg/dev_compiler/lib/js/amd/dart_sdk.js b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
index 2ed8598..2b7e741 100644
--- a/pkg/dev_compiler/lib/js/amd/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/amd/dart_sdk.js
@@ -1420,24 +1420,31 @@
     return true;
   };
   dart.throwCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwUnimplementedError = function(message) {
+    debugger;
     dart.throw(new core.UnimplementedError(message));
   };
   dart.throwAssertionError = function() {
+    debugger;
     dart.throw(new core.AssertionError());
   };
   dart.throwNullValueError = function() {
+    debugger;
     dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
   };
   dart.syncStar = function(gen, E, ...args) {
@@ -1968,9 +1975,11 @@
     return Object.getOwnPropertySymbols(obj);
   };
   dart.throwStrongModeError = function(message) {
+    debugger;
     throw new _js_helper.StrongModeErrorImplementation(message);
   };
   dart.throwInternalError = function(message) {
+    debugger;
     throw Error(message);
   };
   dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/common/dart_sdk.js b/pkg/dev_compiler/lib/js/common/dart_sdk.js
index f853c40..274a113 100644
--- a/pkg/dev_compiler/lib/js/common/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/common/dart_sdk.js
@@ -1420,24 +1420,31 @@
     return true;
   };
   dart.throwCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwUnimplementedError = function(message) {
+    debugger;
     dart.throw(new core.UnimplementedError(message));
   };
   dart.throwAssertionError = function() {
+    debugger;
     dart.throw(new core.AssertionError());
   };
   dart.throwNullValueError = function() {
+    debugger;
     dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
   };
   dart.syncStar = function(gen, E, ...args) {
@@ -1968,9 +1975,11 @@
     return Object.getOwnPropertySymbols(obj);
   };
   dart.throwStrongModeError = function(message) {
+    debugger;
     throw new _js_helper.StrongModeErrorImplementation(message);
   };
   dart.throwInternalError = function(message) {
+    debugger;
     throw Error(message);
   };
   dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/es6/dart_sdk.js b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
index bb1cb35..17bea27 100644
--- a/pkg/dev_compiler/lib/js/es6/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/es6/dart_sdk.js
@@ -1418,24 +1418,31 @@
   return true;
 };
 dart.throwCastError = function(object, actual, type) {
+  debugger;
   dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
 };
 dart.throwTypeError = function(object, actual, type) {
+  debugger;
   dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
 };
 dart.throwStrongModeCastError = function(object, actual, type) {
+  debugger;
   dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
 };
 dart.throwStrongModeTypeError = function(object, actual, type) {
+  debugger;
   dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
 };
 dart.throwUnimplementedError = function(message) {
+  debugger;
   dart.throw(new core.UnimplementedError(message));
 };
 dart.throwAssertionError = function() {
+  debugger;
   dart.throw(new core.AssertionError());
 };
 dart.throwNullValueError = function() {
+  debugger;
   dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
 };
 dart.syncStar = function(gen, E, ...args) {
@@ -1966,9 +1973,11 @@
   return Object.getOwnPropertySymbols(obj);
 };
 dart.throwStrongModeError = function(message) {
+  debugger;
   throw new _js_helper.StrongModeErrorImplementation(message);
 };
 dart.throwInternalError = function(message) {
+  debugger;
   throw Error(message);
 };
 dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
index 09a7b16..8a6f13e 100644
--- a/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
+++ b/pkg/dev_compiler/lib/js/legacy/dart_sdk.js
@@ -1421,24 +1421,31 @@
     return true;
   };
   dart.throwCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.CastErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.TypeErrorImplementation(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeCastError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeCastError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwStrongModeTypeError = function(object, actual, type) {
+    debugger;
     dart.throw(new _js_helper.StrongModeTypeError(object, dart.typeName(actual), dart.typeName(type)));
   };
   dart.throwUnimplementedError = function(message) {
+    debugger;
     dart.throw(new core.UnimplementedError(message));
   };
   dart.throwAssertionError = function() {
+    debugger;
     dart.throw(new core.AssertionError());
   };
   dart.throwNullValueError = function() {
+    debugger;
     dart.throw(new core.NoSuchMethodError(null, new core.Symbol('<Unexpected Null Value>'), null, null, null));
   };
   dart.syncStar = function(gen, E, ...args) {
@@ -1969,9 +1976,11 @@
     return Object.getOwnPropertySymbols(obj);
   };
   dart.throwStrongModeError = function(message) {
+    debugger;
     throw new _js_helper.StrongModeErrorImplementation(message);
   };
   dart.throwInternalError = function(message) {
+    debugger;
     throw Error(message);
   };
   dart.getOwnNamesAndSymbols = function(obj) {
diff --git a/pkg/dev_compiler/test/codegen/language/void_subtype_test.dart b/pkg/dev_compiler/test/codegen/language/void_subtype_test.dart
new file mode 100644
index 0000000..f626232
--- /dev/null
+++ b/pkg/dev_compiler/test/codegen/language/void_subtype_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for type checks involving the void type.
+
+import "package:expect/expect.dart";
+
+var _str = new StringBuffer();
+
+/*=T*/ run/*<T>*/(/*=T*/ f()) {
+  _str.write("+");
+  var t = f();
+  _str.write("-");
+  return t;
+}
+
+void writeV() { _str.write("V"); }
+
+main() {
+  {
+    var x = run/*<dynamic>*/(writeV);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, x);
+    _str.clear();
+
+    var y = run(writeV);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, y);
+    _str.clear();
+  }
+
+  // implicit cast
+  {
+    dynamic d = writeV;
+    var x = run/*<dynamic>*/(d);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, x);
+    _str.clear();
+
+    var y = run(d);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, y);
+    _str.clear();
+  }
+
+  // dynamic dispatch
+  {
+    dynamic d = run;
+    var x = d/*<dynamic>*/(writeV);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, x);
+    _str.clear();
+
+    var y = d(writeV);
+    Expect.equals('+V-', _str.toString());
+    Expect.equals(null, y);
+    _str.clear();
+  }
+}
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
index 8b77035..244a603 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/errors.dart
@@ -4,34 +4,40 @@
 part of dart._runtime;
 
 throwCastError(object, actual, type) => JS('', '''(() => {
+  debugger;
   $throw_(new $CastErrorImplementation($object,
                                        $typeName($actual),
                                        $typeName($type)));
 })()''');
 
 throwTypeError(object, actual, type) => JS('', '''(() => {
+  debugger;
   $throw_(new $TypeErrorImplementation($object,
                                        $typeName($actual),
                                        $typeName($type)));
 })()''');
 
 throwStrongModeCastError(object, actual, type) => JS('', '''(() => {
+  debugger;
   $throw_(new $StrongModeCastError($object,
                                    $typeName($actual),
                                    $typeName($type)));
 })()''');
 
 throwStrongModeTypeError(object, actual, type) => JS('', '''(() => {
+  debugger;
   $throw_(new $StrongModeTypeError($object,
                                    $typeName($actual),
                                    $typeName($type)));
 })()''');
 
 throwUnimplementedError(message) => JS('', '''(() => {
+  debugger;
   $throw_(new $UnimplementedError($message));
 })()''');
 
 throwAssertionError() => JS('', '''(() => {
+  debugger;
   $throw_(new $AssertionError());
 })()''');
 
@@ -39,6 +45,7 @@
   // TODO(vsm): Per spec, we should throw an NSM here.  Technically, we ought
   // to thread through method info, but that uglifies the code and can't
   // actually be queried ... it only affects how the error is printed.
+  debugger;
   $throw_(new $NoSuchMethodError(null,
       new $Symbol('<Unexpected Null Value>'), null, null, null));
 })()''');
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
index 0a3e176..a604423 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/utils.dart
@@ -24,11 +24,13 @@
 /// This error indicates a strong mode specific failure, other than a type
 /// assertion failure (TypeError) or CastError.
 void throwStrongModeError(String message) {
+  JS('', 'debugger');
   JS('', 'throw new #(#);', StrongModeErrorImplementation, message);
 }
 
 /// This error indicates a bug in the runtime or the compiler.
 void throwInternalError(String message) {
+  JS('', 'debugger');
   JS('', 'throw Error(#)', message);
 }
 
diff --git a/runtime/observatory/tests/service/complex_reload_test.dart b/runtime/observatory/tests/service/complex_reload_test.dart
index 0b94084..f3fd806 100644
--- a/runtime/observatory/tests/service/complex_reload_test.dart
+++ b/runtime/observatory/tests/service/complex_reload_test.dart
@@ -46,6 +46,10 @@
   // Stop at 'debugger' statement.
   hasStoppedAtBreakpoint,
   (Isolate mainIsolate) async {
+    for (var i = 0; i < Platform.script.pathSegments.length; i++) {
+      print('segment $i: "${Platform.script.pathSegments[i]}"');
+    }
+    print('Directory: $directory');
     // Grab the VM.
     VM vm = mainIsolate.vm;
     await vm.reloadIsolates();
@@ -62,7 +66,10 @@
 
     // Reload to v2.
     var response = await slaveIsolate.reloadSources(
-       rootLibUri: '$directory/complex_reload/v2/main.dart',
+       rootLibUri: '$directory${Platform.pathSeparator}'
+                  'complex_reload${Platform.pathSeparator}'
+                  'v2${Platform.pathSeparator}'
+                  'main.dart',
     );
     expect(response['success'], isTrue);
 
@@ -72,7 +79,10 @@
 
     // Reload to v3.
     response = await slaveIsolate.reloadSources(
-      rootLibUri: '$directory/complex_reload/v3/main.dart',
+      rootLibUri: '$directory${Platform.pathSeparator}'
+                  'complex_reload${Platform.pathSeparator}'
+                  'v3${Platform.pathSeparator}'
+                  'main.dart',
     );
     expect(response['success'], isTrue);
 
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 52be6ac..bb0c433 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -45,6 +45,7 @@
 [ $runtime == dart_app ]
 address_mapper_test: CompileTimeError # Issue 27806
 capture_stdio_test: CompileTimeError # Issue 27806
+complex_reload_test: RuntimeError # Issue 27806
 debugger_location_second_test: RuntimeError # Issue 27806
 dev_fs_spawn_test: RuntimeError # Issue 27806
 developer_extension_test: RuntimeError # Issue 27806
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index a354ddc..84b528d 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -321,7 +321,7 @@
                                      const uint8_t* buffer,
                                      intptr_t buffer_size) {
   Zone* zone = thread->zone();
-  kernel::KernelReader reader(buffer, buffer_size, true);
+  kernel::KernelReader reader(buffer, buffer_size);
   kernel::Program* program = reader.ReadPrecompiledProgram();
   if (program == NULL) {
     const String& message =
diff --git a/runtime/vm/bootstrap_nocore.cc b/runtime/vm/bootstrap_nocore.cc
index 9fda4b3..cd49589 100644
--- a/runtime/vm/bootstrap_nocore.cc
+++ b/runtime/vm/bootstrap_nocore.cc
@@ -59,7 +59,7 @@
                               const uint8_t* buffer,
                               intptr_t buffer_length) {
   Zone* zone = thread->zone();
-  kernel::KernelReader reader(buffer, buffer_length, true);
+  kernel::KernelReader reader(buffer, buffer_length);
   kernel::Program* program = reader.ReadPrecompiledProgram();
   if (program == NULL) {
     const String& message =
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index c8683ee..61660f0 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1468,6 +1468,7 @@
                         /* is_native = */ false, cls, field.token_pos()));
           getter.set_result_type(type);
           getter.set_is_debuggable(false);
+          getter.set_kernel_function(field.kernel_field());
           cls.AddFunction(getter);
           field.SetStaticValue(Object::sentinel(), true);
         }
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 545e001..5c5628f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -1714,29 +1714,7 @@
       // Create a one-time-use function to evaluate the initializer and invoke
       // it immediately.
       if (field.kernel_field() != NULL) {
-        // kImplicitStaticFinalGetter is used for both implicit static getters
-        // and static initializers.  The Kernel graph builder will tell the
-        // difference by pattern matching on the name.
-        const String& name = String::Handle(
-            zone, Symbols::FromConcat(thread, Symbols::InitPrefix(),
-                                      String::Handle(zone, field.name())));
-        const Script& script = Script::Handle(zone, field.Script());
-        Object& owner = Object::Handle(zone, field.Owner());
-        owner = PatchClass::New(Class::Cast(owner), script);
-        const Function& function = Function::ZoneHandle(
-            zone, Function::New(name, RawFunction::kImplicitStaticFinalGetter,
-                                true,   // is_static
-                                false,  // is_const
-                                false,  // is_abstract
-                                false,  // is_external
-                                false,  // is_native
-                                owner, TokenPosition::kNoSource));
-        function.set_kernel_function(field.kernel_field());
-        function.set_result_type(AbstractType::Handle(zone, field.type()));
-        function.set_is_reflectable(false);
-        function.set_is_debuggable(false);
-        function.set_is_inlinable(false);
-        parsed_function = new (zone) ParsedFunction(thread, function);
+        parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
       } else {
         parsed_function = Parser::ParseStaticFieldInitializer(field);
         parsed_function->AllocateVariables();
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index beb0155..71610d2 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -173,6 +173,8 @@
     if (isolate_event_handler != NULL) {
       (*isolate_event_handler)(event->isolate_id(), kShutdown);
     }
+  } else if (event->kind() == ServiceEvent::kPausePostRequest) {
+    // Ignore.
   } else {
     UNIMPLEMENTED();
   }
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index f1334b8..71eb55a 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -204,18 +204,9 @@
 }
 
 
-static void JumpToExceptionHandler(Thread* thread,
-                                   uword program_counter,
-                                   uword stack_pointer,
-                                   uword frame_pointer,
-                                   const Object& exception_object,
-                                   const Object& stacktrace_object) {
-  // The no_gc StackResource is unwound through the tear down of
-  // stack resources below.
-  NoSafepointScope no_safepoint;
-  RawObject* raw_exception = exception_object.raw();
-  RawObject* raw_stacktrace = stacktrace_object.raw();
-
+static uword RemapExceptionPCForDeopt(Thread* thread,
+                                      uword program_counter,
+                                      uword frame_pointer) {
 #if !defined(TARGET_ARCH_DBC)
   MallocGrowableArray<PendingLazyDeopt>* pending_deopts =
       thread->isolate()->pending_deopts();
@@ -273,8 +264,31 @@
 #endif
   }
 #endif  // !DBC
+  return program_counter;
+}
 
 
+static void JumpToExceptionHandler(Thread* thread,
+                                   uword program_counter,
+                                   uword stack_pointer,
+                                   uword frame_pointer,
+                                   const Object& exception_object,
+                                   const Object& stacktrace_object) {
+  uword remapped_pc =
+      RemapExceptionPCForDeopt(thread, program_counter, frame_pointer);
+  thread->set_active_exception(exception_object);
+  thread->set_active_stacktrace(stacktrace_object);
+  thread->set_resume_pc(remapped_pc);
+  uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint();
+  Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer,
+                          frame_pointer);
+}
+
+
+void Exceptions::JumpToFrame(Thread* thread,
+                             uword program_counter,
+                             uword stack_pointer,
+                             uword frame_pointer) {
 #if defined(USING_SIMULATOR)
   // Unwinding of the C++ frames and destroying of their stack resources is done
   // by the simulator, because the target stack_pointer is a simulated stack
@@ -284,8 +298,8 @@
   // exception object in the kExceptionObjectReg register and the stacktrace
   // object (may be raw null) in the kStackTraceObjectReg register.
 
-  Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer,
-                                raw_exception, raw_stacktrace, thread);
+  Simulator::Current()->JumpToFrame(program_counter, stack_pointer,
+                                    frame_pointer, thread);
 #else
   // Prepare for unwinding frames by destroying all the stack resources
   // in the previous frames.
@@ -294,18 +308,16 @@
   // Call a stub to set up the exception object in kExceptionObjectReg,
   // to set up the stacktrace object in kStackTraceObjectReg, and to
   // continue execution at the given pc in the given frame.
-  typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*,
-                              Thread*);
+  typedef void (*ExcpHandler)(uword, uword, uword, Thread*);
   ExcpHandler func = reinterpret_cast<ExcpHandler>(
-      StubCode::JumpToExceptionHandler_entry()->EntryPoint());
+      StubCode::JumpToFrame_entry()->EntryPoint());
 
   // Unpoison the stack before we tear it down in the generated stub code.
   uword current_sp = Thread::GetCurrentStackPointer() - 1024;
   ASAN_UNPOISON(reinterpret_cast<void*>(current_sp),
                 stack_pointer - current_sp);
 
-  func(program_counter, stack_pointer, frame_pointer, raw_exception,
-       raw_stacktrace, thread);
+  func(program_counter, stack_pointer, frame_pointer, thread);
 #endif
   UNREACHABLE();
 }
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index eaf6194..c3fc408 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -80,6 +80,11 @@
   // otherwise returns a RawError.
   static RawObject* Create(ExceptionType type, const Array& arguments);
 
+  static void JumpToFrame(Thread* thread,
+                          uword program_counter,
+                          uword stack_pointer,
+                          uword frame_pointer);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Exceptions);
 };
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index a66bc10..4e61306 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -798,9 +798,6 @@
     }
     // Generate code handling each optional parameter in alphabetical order.
     __ ldr(NOTFP, FieldAddress(R4, ArgumentsDescriptor::count_offset()));
-    __ ldr(R6,
-           FieldAddress(R4, ArgumentsDescriptor::positional_count_offset()));
-    __ SmiUntag(R6);
     // Let NOTFP point to the first passed argument, i.e. to
     // fp[kParamEndSlotFromFp + num_args - 0]; num_args (NOTFP) is Smi.
     __ add(NOTFP, FP, Operand(NOTFP, LSL, 1));
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 862221e..85c0a76f 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -791,9 +791,6 @@
     }
     // Generate code handling each optional parameter in alphabetical order.
     __ LoadFieldFromOffset(R7, R4, ArgumentsDescriptor::count_offset());
-    __ LoadFieldFromOffset(R8, R4,
-                           ArgumentsDescriptor::positional_count_offset());
-    __ SmiUntag(R8);
     // Let R7 point to the first passed argument, i.e. to
     // fp[kParamEndSlotFromFp + num_args - 0]; num_args (R7) is Smi.
     __ add(R7, FP, Operand(R7, LSL, 2));
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 729608f..fbc891e 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -809,9 +809,6 @@
     }
     // Generate code handling each optional parameter in alphabetical order.
     __ movl(EBX, FieldAddress(EDX, ArgumentsDescriptor::count_offset()));
-    __ movl(ECX,
-            FieldAddress(EDX, ArgumentsDescriptor::positional_count_offset()));
-    __ SmiUntag(ECX);
     // Let EBX point to the first passed argument, i.e. to
     // fp[kParamEndSlotFromFp + num_args - 0]; num_args (EBX) is Smi.
     __ leal(EBX, Address(EBP, EBX, TIMES_2, kParamEndSlotFromFp * kWordSize));
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index ef95a0e..fddc901 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -808,8 +808,6 @@
     }
     // Generate code handling each optional parameter in alphabetical order.
     __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
-    __ lw(T2, FieldAddress(S4, ArgumentsDescriptor::positional_count_offset()));
-    __ SmiUntag(T2);
     // Let T1 point to the first passed argument, i.e. to
     // fp[kParamEndSlotFromFp + num_args - 0]; num_args (T1) is Smi.
     __ sll(T3, T1, 1);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index a4b1288..0944b5e 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -800,9 +800,6 @@
     }
     // Generate code handling each optional parameter in alphabetical order.
     __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-    __ movq(RCX,
-            FieldAddress(R10, ArgumentsDescriptor::positional_count_offset()));
-    __ SmiUntag(RCX);
     // Let RBX point to the first passed argument, i.e. to
     // fp[kParamEndSlotFromFp + num_args]; num_args (RBX) is Smi.
     __ leaq(RBX, Address(RBP, RBX, TIMES_4, kParamEndSlotFromFp * kWordSize));
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 8e96941..15bf633 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -126,6 +126,10 @@
 
 namespace dart {
 
+class Field;
+class ParsedFunction;
+class Zone;
+
 namespace kernel {
 
 
@@ -3237,6 +3241,9 @@
   return IT::Cast(member);
 }
 
+ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
+                                            const dart::Field& field);
+
 }  // namespace kernel
 
 kernel::Program* ReadPrecompiledKernelFromBuffer(const uint8_t* buffer,
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index a870dd9..25b8899 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -294,25 +294,43 @@
 };
 
 
+// Unlike other scopes, labels from enclosing functions are not visible in
+// nested functions.  The LabelScope class is used to hide outer labels.
+template <typename Builder, typename Block>
+class LabelScope {
+ public:
+  explicit LabelScope(Builder* builder) : builder_(builder) {
+    outer_block_ = builder_->labels();
+    builder_->set_labels(&block_);
+  }
+  ~LabelScope() { builder_->set_labels(outer_block_); }
+
+ private:
+  Builder* builder_;
+  Block block_;
+  Block* outer_block_;
+};
+
 class ReaderHelper {
  public:
-  ReaderHelper() : program_(NULL) {}
-  ~ReaderHelper() {}
+  ReaderHelper() : program_(NULL), labels_(NULL) {}
 
   Program* program() { return program_; }
   void set_program(Program* program) { program_ = program; }
 
   BlockStack<VariableDeclaration>& variables() { return scope_; }
   BlockStack<TypeParameter>& type_parameters() { return type_parameters_; }
-  BlockStack<LabeledStatement>& lables() { return labels_; }
   BlockStack<SwitchCase>& switch_cases() { return switch_cases_; }
 
+  BlockStack<LabeledStatement>* labels() { return labels_; }
+  void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; }
+
  private:
   Program* program_;
   BlockStack<VariableDeclaration> scope_;
   BlockStack<TypeParameter> type_parameters_;
-  BlockStack<LabeledStatement> labels_;
   BlockStack<SwitchCase> switch_cases_;
+  BlockStack<LabeledStatement>* labels_;
 };
 
 
@@ -430,6 +448,8 @@
 
 class WriterHelper {
  public:
+  WriterHelper() : labels_(NULL) {}
+
   void SetProgram(Program* program) {
     program_ = program;
     for (int i = 0; i < program->libraries().length(); i++) {
@@ -477,9 +497,11 @@
 
   BlockMap<VariableDeclaration>& variables() { return scope_; }
   BlockMap<TypeParameter>& type_parameters() { return type_parameters_; }
-  BlockMap<LabeledStatement>& lables() { return labels_; }
   BlockMap<SwitchCase>& switch_cases() { return switch_cases_; }
 
+  BlockMap<LabeledStatement>* labels() { return labels_; }
+  void set_labels(BlockMap<LabeledStatement>* labels) { labels_ = labels; }
+
  private:
   Program* program_;
 
@@ -492,8 +514,8 @@
 
   BlockMap<VariableDeclaration> scope_;
   BlockMap<TypeParameter> type_parameters_;
-  BlockMap<LabeledStatement> labels_;
   BlockMap<SwitchCase> switch_cases_;
+  BlockMap<LabeledStatement>* labels_;
 };
 
 
@@ -2253,9 +2275,9 @@
 LabeledStatement* LabeledStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   LabeledStatement* stmt = new LabeledStatement();
-  reader->helper()->lables().Push(stmt);
+  reader->helper()->labels()->Push(stmt);
   stmt->body_ = Statement::ReadFrom(reader);
-  reader->helper()->lables().Pop(stmt);
+  reader->helper()->labels()->Pop(stmt);
   return stmt;
 }
 
@@ -2263,16 +2285,16 @@
 void LabeledStatement::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kLabeledStatement);
-  writer->helper()->lables().Push(this);
+  writer->helper()->labels()->Push(this);
   body_->WriteTo(writer);
-  writer->helper()->lables().Pop(this);
+  writer->helper()->labels()->Pop(this);
 }
 
 
 BreakStatement* BreakStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   BreakStatement* stmt = new BreakStatement();
-  stmt->target_ = reader->helper()->lables().Lookup(reader->ReadUInt());
+  stmt->target_ = reader->helper()->labels()->Lookup(reader->ReadUInt());
   return stmt;
 }
 
@@ -2280,7 +2302,7 @@
 void BreakStatement::WriteTo(Writer* writer) {
   TRACE_WRITE_OFFSET();
   writer->WriteTag(kBreakStatement);
-  writer->WriteUInt(writer->helper()->lables().Lookup(target_));
+  writer->WriteUInt(writer->helper()->labels()->Lookup(target_));
 }
 
 
@@ -2853,6 +2875,8 @@
   function->return_type_ = DartType::ReadFrom(reader);
   function->inferred_return_value_ = reader->ReadOptional<InferredValue>();
 
+  LabelScope<ReaderHelper, BlockStack<LabeledStatement> > labels(
+      reader->helper());
   VariableScope<ReaderHelper> vars(reader->helper());
   function->body_ = reader->ReadOptional<Statement>();
   return function;
@@ -2871,6 +2895,8 @@
   return_type_->WriteTo(writer);
   writer->WriteOptional<InferredValue>(inferred_return_value_);
 
+  LabelScope<WriterHelper, BlockMap<LabeledStatement> > labels(
+      writer->helper());
   VariableScope<WriterHelper> vars(writer->helper());
   writer->WriteOptional<Statement>(body_);
 }
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 356d19c..22f5568 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -103,7 +103,6 @@
 }
 
 Object& KernelReader::ReadProgram() {
-  ASSERT(!bootstrapping_);
   Program* program = ReadPrecompiledProgram();
   if (program == NULL) {
     const dart::String& error = H.DartString("Failed to read .kernell file");
@@ -174,10 +173,6 @@
                           TokenPosition::kNoSource));
   toplevel_class.set_is_cycle_free();
   library.set_toplevel_class(toplevel_class);
-  if (bootstrapping_) {
-    GrowableObjectArray::Handle(Z, I->object_store()->pending_classes())
-        .Add(toplevel_class, Heap::kOld);
-  }
 
   ActiveClassScope active_class_scope(&active_class_, NULL, &toplevel_class);
   // Load toplevel fields.
@@ -215,6 +210,8 @@
     Class* kernel_klass = kernel_library->classes()[i];
     classes.Add(ReadClass(library, kernel_klass), Heap::kOld);
   }
+
+  classes.Add(toplevel_class, Heap::kOld);
 }
 
 
@@ -350,10 +347,8 @@
     ReadProcedure(library, klass, kernel_procedure, kernel_klass);
   }
 
-  if (bootstrapping_ && !klass.is_marked_for_parsing()) {
+  if (!klass.is_marked_for_parsing()) {
     klass.set_is_marked_for_parsing();
-    GrowableObjectArray::Handle(Z, I->object_store()->pending_classes())
-        .Add(klass, Heap::kOld);
   }
 
   return klass;
@@ -581,8 +576,8 @@
   }
   for (intptr_t i = 0; i < node->positional_parameters().length(); i++, pos++) {
     VariableDeclaration* kernel_variable = node->positional_parameters()[i];
-    const AbstractType& type =
-        type_translator.TranslateType(kernel_variable->type());
+    const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
+        kernel_variable->type());
     function.SetParameterTypeAt(
         pos, type.IsMalformed() ? Type::dynamic_type() : type);
     function.SetParameterNameAt(
@@ -590,18 +585,21 @@
   }
   for (intptr_t i = 0; i < node->named_parameters().length(); i++, pos++) {
     VariableDeclaration* named_expression = node->named_parameters()[i];
-    const AbstractType& type =
-        type_translator.TranslateType(named_expression->type());
+    const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
+        named_expression->type());
     function.SetParameterTypeAt(
         pos, type.IsMalformed() ? Type::dynamic_type() : type);
     function.SetParameterNameAt(
         pos, translation_helper.DartSymbol(named_expression->name()));
   }
 
-  const AbstractType& return_type =
-      type_translator.TranslateType(node->return_type());
-  function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type()
-                                                     : return_type);
+  // The result type for generative constructors has already been set.
+  if (!function.IsGenerativeConstructor()) {
+    const AbstractType& return_type =
+        type_translator.TranslateTypeWithoutFinalization(node->return_type());
+    function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type()
+                                                       : return_type);
+  }
 }
 
 
@@ -672,7 +670,7 @@
     // we do not risk allocating the class again by calling LookupClass
     // recursively from ReadPreliminaryClass for the same class.
     classes_.Insert(klass, handle);
-    if (!handle->is_type_finalized()) {
+    if (!handle->is_cycle_free()) {
       ReadPreliminaryClass(handle, klass);
     }
   }
@@ -698,6 +696,35 @@
 }
 
 
+ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
+                                            const dart::Field& field) {
+  Thread* thread = Thread::Current();
+  kernel::Field* kernel_field = kernel::Field::Cast(
+      reinterpret_cast<kernel::Node*>(field.kernel_field()));
+
+  dart::String& init_name = dart::String::Handle(zone, field.name());
+  init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name);
+
+  // Create a static initializer.
+  const dart::Class& owner = dart::Class::Handle(zone, field.Owner());
+  const Function& initializer_fun = Function::ZoneHandle(
+      zone,
+      dart::Function::New(init_name, RawFunction::kImplicitStaticFinalGetter,
+                          true,   // is_static
+                          false,  // is_const
+                          false,  // is_abstract
+                          false,  // is_external
+                          false,  // is_native
+                          owner, TokenPosition::kNoSource));
+  initializer_fun.set_kernel_function(kernel_field);
+  initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
+  initializer_fun.set_is_debuggable(false);
+  initializer_fun.set_is_reflectable(false);
+  initializer_fun.set_is_inlinable(false);
+  return new (zone) ParsedFunction(thread, initializer_fun);
+}
+
+
 }  // namespace kernel
 }  // namespace dart
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/kernel_reader.h b/runtime/vm/kernel_reader.h
index a361c14..60c8de9 100644
--- a/runtime/vm/kernel_reader.h
+++ b/runtime/vm/kernel_reader.h
@@ -54,7 +54,7 @@
 
 class KernelReader {
  public:
-  KernelReader(const uint8_t* buffer, intptr_t len, bool bootstrapping = false)
+  KernelReader(const uint8_t* buffer, intptr_t len)
       : thread_(dart::Thread::Current()),
         zone_(thread_->zone()),
         isolate_(thread_->isolate()),
@@ -64,7 +64,6 @@
         type_translator_(&translation_helper_,
                          &active_class_,
                          /*finalize=*/false),
-        bootstrapping_(bootstrapping),
         buffer_(buffer),
         buffer_length_(len) {}
 
@@ -122,8 +121,6 @@
   BuildingTranslationHelper translation_helper_;
   DartTypeTranslator type_translator_;
 
-  bool bootstrapping_;
-
   const uint8_t* buffer_;
   intptr_t buffer_length_;
 
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index 9ebcfc1..ff7c1cd 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -4154,6 +4154,11 @@
   }
   type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
                    klass.token_pos());
+  if (klass.is_type_finalized()) {
+    type ^= ClassFinalizer::FinalizeType(
+        klass, type, ClassFinalizer::kCanonicalizeWellFormed);
+    klass.SetCanonicalType(type);
+  }
   return type;
 }
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 0cfa413..920b9bd 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -545,6 +545,7 @@
     cls.set_state_bits(0);
     cls.set_is_finalized();
     cls.set_is_type_finalized();
+    cls.set_is_cycle_free();
     cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments);
     cls.set_num_type_arguments(0);
     cls.set_num_own_type_arguments(0);
@@ -565,6 +566,7 @@
   cls.set_num_own_type_arguments(0);
   cls.set_is_finalized();
   cls.set_is_type_finalized();
+  cls.set_is_cycle_free();
 
   // Allocate and initialize the forwarding corpse class.
   cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse);
@@ -572,6 +574,7 @@
   cls.set_num_own_type_arguments(0);
   cls.set_is_finalized();
   cls.set_is_type_finalized();
+  cls.set_is_cycle_free();
 
   // Allocate and initialize the sentinel values of Null class.
   {
@@ -824,20 +827,23 @@
   cls.set_is_abstract();
   cls.set_num_type_arguments(0);
   cls.set_num_own_type_arguments(0);
-  cls.set_is_type_finalized();
   cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  cls.set_is_cycle_free();
   dynamic_class_ = cls.raw();
 
   cls = Class::New<Instance>(kVoidCid);
   cls.set_num_type_arguments(0);
   cls.set_num_own_type_arguments(0);
-  cls.set_is_type_finalized();
   cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  cls.set_is_cycle_free();
   void_class_ = cls.raw();
 
   cls = Class::New<Type>();
-  cls.set_is_type_finalized();
   cls.set_is_finalized();
+  cls.set_is_type_finalized();
+  cls.set_is_cycle_free();
 
   cls = dynamic_class_;
   *dynamic_type_ = Type::NewNonParameterizedType(cls);
@@ -3187,6 +3193,7 @@
     cls.set_is_finalized();
     cls.set_is_type_finalized();
     cls.set_is_synthesized_class();
+    cls.set_is_cycle_free();
     library.AddClass(cls);
     return cls.raw();
   } else {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 4bad386..7829fd6 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -52,7 +52,7 @@
             conditional_directives,
             true,
             "Enable conditional directives");
-DEFINE_FLAG(bool, generic_method_syntax, false, "Enable generic functions.");
+DEFINE_FLAG(bool, generic_method_syntax, true, "Enable generic functions.");
 DEFINE_FLAG(bool,
             initializing_formal_access,
             false,
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 5c50458..8d72d929a 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -1118,12 +1118,20 @@
                                                    bool compute_type) {
   ASSERT(field.is_static());
   Thread* thread = Thread::Current();
-  StackZone zone(thread);
+  StackZone stack_zone(thread);
+  Zone* zone = stack_zone.GetZone();
 
-  ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
+  ParsedFunction* parsed_function;
+  // Check if this field is comming from the Kernel binary.
+  if (field.kernel_field() != NULL) {
+    parsed_function = kernel::ParseStaticFieldInitializer(zone, field);
+  } else {
+    parsed_function = Parser::ParseStaticFieldInitializer(field);
+    parsed_function->AllocateVariables();
+  }
 
-  parsed_function->AllocateVariables();
-  DartPrecompilationPipeline pipeline(zone.GetZone());
+
+  DartPrecompilationPipeline pipeline(zone);
   PrecompileParsedFunctionHelper helper(/* precompiler = */ NULL,
                                         parsed_function,
                                         /* optimized = */ true);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 05f8302..22febb0 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -1104,11 +1104,10 @@
     return;
   }
 
-  if (StubCode::HasBeenInitialized() &&
-      StubCode::InJumpToExceptionHandlerStub(state.pc)) {
-    // The JumpToExceptionHandler stub manually adjusts the stack pointer,
-    // frame pointer, and some isolate state before jumping to a catch entry.
-    // It is not safe to walk the stack when executing this stub.
+  if (StubCode::HasBeenInitialized() && StubCode::InJumpToFrameStub(state.pc)) {
+    // The JumpToFrame stub manually adjusts the stack pointer, frame
+    // pointer, and some isolate state.  It is not safe to walk the
+    // stack when executing this stub.
     AtomicOperations::IncrementInt64By(
         &counters_.bail_out_jump_to_exception_handler, 1);
     return;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 232b1a4..2b64e48 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -3891,12 +3891,7 @@
 }
 
 
-void Simulator::Longjmp(uword pc,
-                        uword sp,
-                        uword fp,
-                        RawObject* raw_exception,
-                        RawObject* raw_stacktrace,
-                        Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
   // Walk over all setjmp buffers (simulated --> C++ transitions)
   // and try to find the setjmp associated with the simulated stack pointer.
   SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3919,10 +3914,6 @@
   thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   thread->set_top_exit_frame_info(0);
-
-  ASSERT(raw_exception != Object::null());
-  set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
-  set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
   // Restore pool pointer.
   int32_t code =
       *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index 605ccec..5a59f5bc 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -127,12 +127,7 @@
 
   static uword FunctionForRedirect(uword redirect);
 
-  void Longjmp(uword pc,
-               uword sp,
-               uword fp,
-               RawObject* raw_exception,
-               RawObject* raw_stacktrace,
-               Thread* thread);
+  void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
 
  private:
   // Known bad pc value to ensure that the simulator does not execute
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index a055567..65a2034 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3602,12 +3602,7 @@
 }
 
 
-void Simulator::Longjmp(uword pc,
-                        uword sp,
-                        uword fp,
-                        RawObject* raw_exception,
-                        RawObject* raw_stacktrace,
-                        Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
   // Walk over all setjmp buffers (simulated --> C++ transitions)
   // and try to find the setjmp associated with the simulated stack pointer.
   SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3630,10 +3625,6 @@
   thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   thread->set_top_exit_frame_info(0);
-
-  ASSERT(raw_exception != Object::null());
-  set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception));
-  set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace));
   // Restore pool pointer.
   int64_t code =
       *reinterpret_cast<int64_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index 79f9ced..43c0571 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -124,12 +124,7 @@
 
   static uword FunctionForRedirect(uword redirect);
 
-  void Longjmp(uword pc,
-               uword sp,
-               uword fp,
-               RawObject* raw_exception,
-               RawObject* raw_stacktrace,
-               Thread* thread);
+  void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
 
  private:
   // Known bad pc value to ensure that the simulator does not execute
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index ae9eaf8..8febf13 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -3691,12 +3691,7 @@
 }
 
 
-void Simulator::Longjmp(uword pc,
-                        uword sp,
-                        uword fp,
-                        RawObject* raw_exception,
-                        RawObject* raw_stacktrace,
-                        Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
   // Walk over all setjmp buffers (simulated --> C++ transitions)
   // and try to find the setjmp associated with the simulated stack pointer.
   SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -3716,12 +3711,22 @@
   // Clear top exit frame.
   thread->set_top_exit_frame_info(0);
 
-  ASSERT(raw_exception != Object::null());
   sp_ = reinterpret_cast<RawObject**>(sp);
   fp_ = reinterpret_cast<RawObject**>(fp);
-  pc_ = pc;
-  special_[kExceptionSpecialIndex] = raw_exception;
-  special_[kStacktraceSpecialIndex] = raw_stacktrace;
+
+  if (pc == StubCode::RunExceptionHandler_entry()->EntryPoint()) {
+    // Instead of executing the RunException stub, we implement its
+    // behavior here.
+    RawObject* raw_exception = thread->active_exception();
+    RawObject* raw_stacktrace = thread->active_stacktrace();
+    ASSERT(raw_exception != Object::null());
+    special_[kExceptionSpecialIndex] = raw_exception;
+    special_[kStacktraceSpecialIndex] = raw_stacktrace;
+    pc_ = thread->resume_pc();
+  } else {
+    pc_ = pc;
+  }
+
   buf->Longjmp();
   UNREACHABLE();
 }
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
index 8acdbce..e0570b7 100644
--- a/runtime/vm/simulator_dbc.h
+++ b/runtime/vm/simulator_dbc.h
@@ -64,12 +64,7 @@
                   const Array& arguments,
                   Thread* thread);
 
-  void Longjmp(uword pc,
-               uword sp,
-               uword fp,
-               RawObject* raw_exception,
-               RawObject* raw_stacktrace,
-               Thread* thread);
+  void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
 
   uword get_sp() const { return reinterpret_cast<uword>(sp_); }
   uword get_fp() const { return reinterpret_cast<uword>(fp_); }
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index f65b9ed..f3c325f 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -2479,12 +2479,7 @@
 }
 
 
-void Simulator::Longjmp(uword pc,
-                        uword sp,
-                        uword fp,
-                        RawObject* raw_exception,
-                        RawObject* raw_stacktrace,
-                        Thread* thread) {
+void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
   // Walk over all setjmp buffers (simulated --> C++ transitions)
   // and try to find the setjmp associated with the simulated stack pointer.
   SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@@ -2507,10 +2502,6 @@
   thread->set_vm_tag(VMTag::kDartTagId);
   // Clear top exit frame.
   thread->set_top_exit_frame_info(0);
-
-  ASSERT(raw_exception != Object::null());
-  set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
-  set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
   // Restore pool pointer.
   int32_t code =
       *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index d6b5323..00d93ec 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -139,12 +139,7 @@
 
   static uword FunctionForRedirect(uword redirect);
 
-  void Longjmp(uword pc,
-               uword sp,
-               uword fp,
-               RawObject* raw_exception,
-               RawObject* raw_stacktrace,
-               Thread* thread);
+  void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
 
  private:
   // A pc value used to signal the simulator to stop execution.  Generally
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 0418da8..5b6a5f5 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -91,8 +91,8 @@
 
 bool StubCode::HasBeenInitialized() {
 #if !defined(TARGET_ARCH_DBC)
-  // Use JumpToExceptionHandler and InvokeDart as canaries.
-  const StubEntry* entry_1 = StubCode::JumpToExceptionHandler_entry();
+  // Use JumpToHandler and InvokeDart as canaries.
+  const StubEntry* entry_1 = StubCode::JumpToFrame_entry();
   const StubEntry* entry_2 = StubCode::InvokeDartCode_entry();
   return (entry_1 != NULL) && (entry_2 != NULL);
 #else
@@ -115,11 +115,11 @@
 }
 
 
-bool StubCode::InJumpToExceptionHandlerStub(uword pc) {
+bool StubCode::InJumpToFrameStub(uword pc) {
 #if !defined(TARGET_ARCH_DBC)
   ASSERT(HasBeenInitialized());
-  uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
-  uword size = StubCode::JumpToExceptionHandlerSize();
+  uword entry = StubCode::JumpToFrame_entry()->EntryPoint();
+  uword size = StubCode::JumpToFrameSize();
   return (pc >= entry) && (pc < (entry + size));
 #else
   // This stub does not exist on DBC.
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index 7d0dd14..3a2cea0 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -25,7 +25,8 @@
 #if !defined(TARGET_ARCH_DBC)
 #define VM_STUB_CODE_LIST(V)                                                   \
   V(GetStackPointer)                                                           \
-  V(JumpToExceptionHandler)                                                    \
+  V(JumpToFrame)                                                               \
+  V(RunExceptionHandler)                                                       \
   V(UpdateStoreBuffer)                                                         \
   V(PrintStopMessage)                                                          \
   V(CallToRuntime)                                                             \
@@ -73,6 +74,7 @@
 #define VM_STUB_CODE_LIST(V)                                                   \
   V(LazyCompile)                                                               \
   V(OptimizeFunction)                                                          \
+  V(RunExceptionHandler)                                                       \
   V(FixCallersTarget)                                                          \
   V(Deoptimize)                                                                \
   V(DeoptimizeLazyFromReturn)                                                  \
@@ -138,8 +140,8 @@
   // transitioning into dart code.
   static bool InInvocationStub(uword pc);
 
-  // Check if the specified pc is in the jump to exception handler stub.
-  static bool InJumpToExceptionHandlerStub(uword pc);
+  // Check if the specified pc is in the jump to frame stub.
+  static bool InJumpToFrameStub(uword pc);
 
   // Returns NULL if no stub found.
   static const char* NameOfStub(uword entry_point);
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 10722cc..87b054d 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1850,23 +1850,19 @@
 }
 
 
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
 // LR: return address.
 // R0: program_counter.
 // R1: stack_pointer.
 // R2: frame_pointer.
-// R3: error object.
-// SP + 0: address of stacktrace object.
-// SP + 4: thread.
+// R3: thread.
 // Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
   ASSERT(kExceptionObjectReg == R0);
   ASSERT(kStackTraceObjectReg == R1);
   __ mov(IP, Operand(R1));      // Copy Stack pointer into IP.
   __ mov(LR, Operand(R0));      // Program counter.
-  __ mov(R0, Operand(R3));      // Exception object.
-  __ ldr(R1, Address(SP, 0));   // StackTrace object.
-  __ ldr(THR, Address(SP, 4));  // Thread.
+  __ mov(THR, Operand(R3));     // Thread.
   __ mov(FP, Operand(R2));      // Frame_pointer.
   __ mov(SP, Operand(IP));      // Set Stack pointer.
   // Set the tag.
@@ -1878,6 +1874,27 @@
   // Restore the pool pointer.
   __ RestoreCodePointer();
   __ LoadPoolPointer();
+  __ bx(LR);  // Jump to continuation point.
+}
+
+
+// Run an exception handler.  Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  __ LoadFromOffset(kWord, LR, THR, Thread::resume_pc_offset());
+  __ LoadImmediate(R2, 0);
+
+  // Exception object.
+  __ LoadFromOffset(kWord, R0, THR, Thread::active_exception_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::active_exception_offset());
+
+  // Stacktrace object.
+  __ LoadFromOffset(kWord, R1, THR, Thread::active_stacktrace_offset());
+  __ StoreToOffset(kWord, R2, THR, Thread::active_stacktrace_offset());
+
   __ bx(LR);  // Jump to the exception handler code.
 }
 
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 71dae4b..5a5a156 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1902,24 +1902,20 @@
 }
 
 
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
 // LR: return address.
 // R0: program_counter.
 // R1: stack_pointer.
 // R2: frame_pointer.
-// R3: error object.
-// R4: address of stacktrace object.
-// R5: thread.
+// R3: thread.
 // Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
   ASSERT(kExceptionObjectReg == R0);
   ASSERT(kStackTraceObjectReg == R1);
   __ mov(LR, R0);  // Program counter.
   __ mov(SP, R1);  // Stack pointer.
   __ mov(FP, R2);  // Frame_pointer.
-  __ mov(R0, R3);  // Exception object.
-  __ mov(R1, R4);  // StackTrace object.
-  __ mov(THR, R5);
+  __ mov(THR, R3);
   // Set the tag.
   __ LoadImmediate(R2, VMTag::kDartTagId);
   __ StoreToOffset(R2, THR, Thread::vm_tag_offset());
@@ -1928,6 +1924,27 @@
   // Restore the pool pointer.
   __ RestoreCodePointer();
   __ LoadPoolPointer();
+  __ ret();  // Jump to continuation point.
+}
+
+
+// Run an exception handler.  Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  __ LoadFromOffset(LR, THR, Thread::resume_pc_offset());
+  __ LoadImmediate(R2, 0);
+
+  // Exception object.
+  __ LoadFromOffset(R0, THR, Thread::active_exception_offset());
+  __ StoreToOffset(R2, THR, Thread::active_exception_offset());
+
+  // Stacktrace object.
+  __ LoadFromOffset(R1, THR, Thread::active_stacktrace_offset());
+  __ StoreToOffset(R2, THR, Thread::active_stacktrace_offset());
+
   __ ret();  // Jump to the exception handler code.
 }
 
diff --git a/runtime/vm/stub_code_dbc.cc b/runtime/vm/stub_code_dbc.cc
index 54711516..da24e19 100644
--- a/runtime/vm/stub_code_dbc.cc
+++ b/runtime/vm/stub_code_dbc.cc
@@ -41,6 +41,12 @@
 }
 
 
+// Not executed, but used as a sentinel in Simulator::JumpToFrame.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  __ Trap();
+}
+
+
 // TODO(vegorov) Don't generate this stub.
 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
   __ Trap();
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 1de178a8..ca70617 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1792,21 +1792,15 @@
 }
 
 
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
 // TOS + 0: return address
 // TOS + 1: program_counter
 // TOS + 2: stack_pointer
 // TOS + 3: frame_pointer
-// TOS + 4: exception object
-// TOS + 5: stacktrace object
-// TOS + 6: thread
+// TOS + 4: thread
 // No Result.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
-  ASSERT(kExceptionObjectReg == EAX);
-  ASSERT(kStackTraceObjectReg == EDX);
-  __ movl(THR, Address(ESP, 6 * kWordSize));  // Load target thread.
-  __ movl(kStackTraceObjectReg, Address(ESP, 5 * kWordSize));
-  __ movl(kExceptionObjectReg, Address(ESP, 4 * kWordSize));
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
+  __ movl(THR, Address(ESP, 4 * kWordSize));  // Load target thread.
   __ movl(EBP, Address(ESP, 3 * kWordSize));  // Load target frame_pointer.
   __ movl(EBX, Address(ESP, 1 * kWordSize));  // Load target PC into EBX.
   __ movl(ESP, Address(ESP, 2 * kWordSize));  // Load target stack_pointer.
@@ -1818,6 +1812,29 @@
 }
 
 
+// Run an exception handler.  Execution comes from JumpToFrame stub.
+//
+// The arguments are stored in the Thread object.
+// No result.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  ASSERT(kExceptionObjectReg == EAX);
+  ASSERT(kStackTraceObjectReg == EDX);
+  __ movl(EBX, Address(THR, Thread::resume_pc_offset()));
+
+  // Load the exception from the current thread.
+  Address exception_addr(THR, Thread::active_exception_offset());
+  __ movl(kExceptionObjectReg, exception_addr);
+  __ movl(exception_addr, Immediate(0));
+
+  // Load the stacktrace from the current thread.
+  Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+  __ movl(kStackTraceObjectReg, stacktrace_addr);
+  __ movl(stacktrace_addr, Immediate(0));
+
+  __ jmp(EBX);  // Jump to continuation point.
+}
+
+
 // Calls to the runtime to optimize the given function.
 // EBX: function to be reoptimized.
 // EDX: argument descriptor (preserved).
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 40c8bb8..d52e6cc 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1985,19 +1985,13 @@
 // A0: program_counter.
 // A1: stack_pointer.
 // A2: frame_pointer.
-// A3: error object.
-// SP + 4*kWordSize: address of stacktrace object.
-// SP + 5*kWordSize: address of thread.
+// A3: thread.
 // Does not return.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
   ASSERT(kExceptionObjectReg == V0);
   ASSERT(kStackTraceObjectReg == V1);
-  __ mov(V0, A3);  // Exception object.
-  // MIPS ABI reserves stack space for all arguments. The StackTrace object is
-  // the last of five arguments, so it is first pushed on the stack.
-  __ lw(V1, Address(SP, 4 * kWordSize));   // StackTrace object.
-  __ mov(FP, A2);                          // Frame_pointer.
-  __ lw(THR, Address(SP, 5 * kWordSize));  // Thread.
+  __ mov(FP, A2);   // Frame_pointer.
+  __ mov(THR, A3);  // Thread.
   // Set tag.
   __ LoadImmediate(A2, VMTag::kDartTagId);
   __ sw(A2, Assembler::VMTagAddress());
@@ -2006,11 +2000,34 @@
   // Restore pool pointer.
   __ RestoreCodePointer();
   __ LoadPoolPointer();
-  __ jr(A0);                     // Jump to the exception handler code.
+  __ jr(A0);                     // Jump to the program counter.
   __ delay_slot()->mov(SP, A1);  // Stack pointer.
 }
 
 
+// Run an exception handler.  Execution comes from JumpToFrame
+// stub or from the simulator.
+//
+// The arguments are stored in the Thread object.
+// Does not return.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  __ lw(A0, Address(THR, Thread::resume_pc_offset()));
+  __ LoadImmediate(A2, 0);
+
+  // Load the exception from the current thread.
+  Address exception_addr(THR, Thread::active_exception_offset());
+  __ lw(V0, exception_addr);
+  __ sw(A2, exception_addr);
+
+  // Load the stacktrace from the current thread.
+  Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+  __ lw(V1, stacktrace_addr);
+
+  __ jr(A0);  // Jump to continuation point.
+  __ delay_slot()->sw(A2, stacktrace_addr);
+}
+
+
 // Calls to the runtime to optimize the given function.
 // T0: function to be reoptimized.
 // S4: argument descriptor (preserved).
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 9ca6a6e2..167154b 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -1845,33 +1845,17 @@
 }
 
 
-// Jump to the exception or error handler.
+// Jump to a frame on the call stack.
 // TOS + 0: return address
 // Arg1: program counter
 // Arg2: stack pointer
 // Arg3: frame_pointer
-// Arg4: exception object
-// Arg5: stacktrace object
-// Arg6: thread
+// Arg4: thread
 // No Result.
-void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
-  ASSERT(kExceptionObjectReg == RAX);
-  ASSERT(kStackTraceObjectReg == RDX);
-  ASSERT(CallingConventions::kArg4Reg != kStackTraceObjectReg);
-  ASSERT(CallingConventions::kArg1Reg != kStackTraceObjectReg);
-
-#if defined(_WIN64)
-  Register stacktrace_reg = RBX;
-  __ movq(stacktrace_reg, Address(RSP, 5 * kWordSize));
-  __ movq(THR, Address(RSP, 6 * kWordSize));
-#else
-  Register stacktrace_reg = CallingConventions::kArg5Reg;
-  __ movq(THR, CallingConventions::kArg6Reg);
-#endif
+void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
+  __ movq(THR, CallingConventions::kArg4Reg);
   __ movq(RBP, CallingConventions::kArg3Reg);
   __ movq(RSP, CallingConventions::kArg2Reg);
-  __ movq(kStackTraceObjectReg, stacktrace_reg);
-  __ movq(kExceptionObjectReg, CallingConventions::kArg4Reg);
   // Set the tag.
   __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
   // Clear top exit frame.
@@ -1879,7 +1863,31 @@
   // Restore the pool pointer.
   __ RestoreCodePointer();
   __ LoadPoolPointer(PP);
-  __ jmp(CallingConventions::kArg1Reg);  // Jump to the exception handler code.
+  __ jmp(CallingConventions::kArg1Reg);  // Jump to program counter.
+}
+
+
+// Run an exception handler.  Execution comes from JumpToFrame stub.
+//
+// The arguments are stored in the Thread object.
+// No result.
+void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
+  ASSERT(kExceptionObjectReg == RAX);
+  ASSERT(kStackTraceObjectReg == RDX);
+  __ movq(CallingConventions::kArg1Reg,
+          Address(THR, Thread::resume_pc_offset()));
+
+  // Load the exception from the current thread.
+  Address exception_addr(THR, Thread::active_exception_offset());
+  __ movq(kExceptionObjectReg, exception_addr);
+  __ movq(exception_addr, Immediate(0));
+
+  // Load the stacktrace from the current thread.
+  Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
+  __ movq(kStackTraceObjectReg, stacktrace_addr);
+  __ movq(stacktrace_addr, Immediate(0));
+
+  __ jmp(CallingConventions::kArg1Reg);  // Jump to continuation point.
 }
 
 
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index dc4e1ca..709d735 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -93,6 +93,9 @@
       type_range_cache_(NULL),
       deopt_id_(0),
       pending_functions_(GrowableObjectArray::null()),
+      active_exception_(Object::null()),
+      active_stacktrace_(Object::null()),
+      resume_pc_(0),
       sticky_error_(Error::null()),
       compiler_stats_(NULL),
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
@@ -215,6 +218,17 @@
 }
 
 
+void Thread::set_active_exception(const Object& value) {
+  ASSERT(!value.IsNull());
+  active_exception_ = value.raw();
+}
+
+
+void Thread::set_active_stacktrace(const Object& value) {
+  active_stacktrace_ = value.raw();
+}
+
+
 RawError* Thread::sticky_error() const {
   return sticky_error_;
 }
@@ -606,6 +620,8 @@
   reusable_handles_.VisitObjectPointers(visitor);
 
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&pending_functions_));
+  visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_exception_));
+  visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_stacktrace_));
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
 
   // Visit the api local scope as it has all the api local handles.
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 95d04b2..a9fb55f 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -471,6 +471,22 @@
   RawGrowableObjectArray* pending_functions();
   void clear_pending_functions();
 
+  RawObject* active_exception() const { return active_exception_; }
+  void set_active_exception(const Object& value);
+  static intptr_t active_exception_offset() {
+    return OFFSET_OF(Thread, active_exception_);
+  }
+
+  RawObject* active_stacktrace() const { return active_stacktrace_; }
+  void set_active_stacktrace(const Object& value);
+  static intptr_t active_stacktrace_offset() {
+    return OFFSET_OF(Thread, active_stacktrace_);
+  }
+
+  uword resume_pc() const { return resume_pc_; }
+  void set_resume_pc(uword value) { resume_pc_ = value; }
+  static uword resume_pc_offset() { return OFFSET_OF(Thread, resume_pc_); }
+
   RawError* sticky_error() const;
   void set_sticky_error(const Error& value);
   void clear_sticky_error();
@@ -684,6 +700,11 @@
   intptr_t deopt_id_;  // Compilation specific counter.
   RawGrowableObjectArray* pending_functions_;
 
+  // JumpToExceptionHandler state:
+  RawObject* active_exception_;
+  RawObject* active_stacktrace_;
+  uword resume_pc_;
+
   RawError* sticky_error_;
 
   CompilerStats* compiler_stats_;
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 49a7ba9..722e628 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -11,6 +11,7 @@
 # Override tests marked as failing elsewhere.
 [ $compiler == dartk || $compiler == dartkp ]
 Language/Libraries_and_Scripts/Exports/reexport_t01: Pass
+Language/Functions/Formal_Parameters/Optional_Formals/syntax_t14: Pass
 
 # dartk: JIT failures
 [ $compiler == dartk && $runtime == vm ]
@@ -36,9 +37,6 @@
 Language/Enums/declaration_equivalent_t01: RuntimeError
 Language/Enums/syntax_t08: MissingCompileTimeError
 Language/Enums/syntax_t09: MissingCompileTimeError
-Language/Expressions/Await_Expressions/syntax_t01: RuntimeError
-Language/Expressions/Await_Expressions/syntax_t02: RuntimeError
-Language/Expressions/Await_Expressions/syntax_t10: RuntimeError
 Language/Expressions/Constants/exception_t01: MissingCompileTimeError
 Language/Expressions/Constants/exception_t02: MissingCompileTimeError
 Language/Expressions/Constants/string_length_t01: Crash
@@ -49,15 +47,11 @@
 Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t03: MissingCompileTimeError
 Language/Expressions/Function_Invocation/Unqualified_Invocation/instance_context_invocation_t04: MissingCompileTimeError
 Language/Expressions/Function_Invocation/Unqualified_Invocation/static_method_invocation_t02: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t01: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t02: RuntimeError
-Language/Expressions/Function_Invocation/async_cleanup_t04: Crash
 Language/Expressions/Function_Invocation/async_cleanup_t07: Fail
 Language/Expressions/Function_Invocation/async_cleanup_t08: Fail
 Language/Expressions/Function_Invocation/async_generator_invokation_t05: RuntimeError
 Language/Expressions/Function_Invocation/async_generator_invokation_t06: RuntimeError
 Language/Expressions/Function_Invocation/async_generator_invokation_t09: RuntimeError
-Language/Expressions/Function_Invocation/async_invokation_t05: RuntimeError
 Language/Expressions/Identifier_Reference/built_in_identifier_t35: Pass
 Language/Expressions/Identifier_Reference/built_in_identifier_t36: Pass
 Language/Expressions/Identifier_Reference/built_in_identifier_t37: Pass
@@ -327,6 +321,19 @@
 Language/Libraries_and_Scripts/Imports/static_type_t01/03: Pass
 Language/Libraries_and_Scripts/Imports/static_type_t01/07: Pass
 Language/Libraries_and_Scripts/Imports/static_type_t01/02: Pass
+LibTest/core/Match/operator_subscript_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A02_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Assertion_A03_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A03_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Atom_A06_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClass_A02_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Disjunction_A01_t01: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t02: RuntimeError
+LibTest/core/RegExp/Pattern_semantics/firstMatch_Quantifier_A03_t01: RuntimeError
+LibTest/core/RegExp/firstMatch_A02_t01: RuntimeError
+LibTest/core/RegExp/hasMatch_A01_t02: RuntimeError
+LibTest/core/RegExp/stringMatch_A01_t01: RuntimeError
 
 # dartk: JIT failures (debug)
 [ $compiler == dartk && $runtime == vm && $mode == debug ]
@@ -638,4 +645,4 @@
 LibTest/core/Invocation/isSetter_A01_t02: Crash
 LibTest/core/Invocation/memberName_A01_t01: RuntimeError
 LibTest/core/Invocation/namedArguments_A01_t01: Crash
-LibTest/core/Invocation/positionalArguments_A01_t01: Crash
+LibTest/core/Invocation/positionalArguments_A01_t01: Crash
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
index 8ece3d4..89d1ff7 100644
--- a/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
+++ b/tests/compiler/dart2js/sourcemaps/stacktrace_test.dart
@@ -116,7 +116,8 @@
   '''
 import 'package:expect/expect.dart';
 main() {
-  test(); // This call is no longer on the stack when the error is thrown.
+  // This call is no longer on the stack when the error is thrown.
+  @{:main}test();
 }
 @NoInline()
 test() async {
@@ -131,7 +132,7 @@
 @NoInline()
 test1() async {
   // This call is no longer on the stack when the error is thrown.
-  await test2();
+  await @{:test1}test2();
 }
 @NoInline()
 test2() async {
@@ -152,13 +153,30 @@
   @{2:test2}throw '$EXCEPTION_MARKER';
 }
 ''',
+  '''
+import 'package:expect/expect.dart';
+main() {
+  // This call is no longer on the stack when the error is thrown.
+  @{:main}test();
+}
+test() async {
+  var c = @{1:test}new Class();
+}
+class Class {
+  @NoInline()
+  Class() {
+    @{2:Class}throw '$EXCEPTION_MARKER';
+  }
+}
+''',
 ];
 
 class Test {
   final String code;
   final List<StackTraceLine> expectedLines;
+  final List<StackTraceLine> unexpectedLines;
 
-  Test(this.code, this.expectedLines);
+  Test(this.code, this.expectedLines, this.unexpectedLines);
 }
 
 const int _LF = 0x0A;
@@ -168,6 +186,7 @@
 Test processTestCode(String code) {
   StringBuffer codeBuffer = new StringBuffer();
   Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
+  List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
   int index = 0;
   int lineNo = 1;
   int columnNo = 1;
@@ -191,12 +210,17 @@
         if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LBRACE) {
           int colonIndex = code.indexOf(':', index);
           int endIndex = code.indexOf('}', index);
-          int stackTraceIndex =
-              int.parse(code.substring(index + 2, colonIndex));
           String methodName = code.substring(colonIndex + 1, endIndex);
-          assert(!stackTraceMap.containsKey(stackTraceIndex));
-          stackTraceMap[stackTraceIndex] =
+          String indexText = code.substring(index + 2, colonIndex);
+          StackTraceLine stackTraceLine =
               new StackTraceLine(methodName, INPUT_FILE_NAME, lineNo, columnNo);
+          if (indexText == '') {
+            unexpectedLines.add(stackTraceLine);
+          } else {
+            int stackTraceIndex = int.parse(indexText);
+            assert(!stackTraceMap.containsKey(stackTraceIndex));
+            stackTraceMap[stackTraceIndex] = stackTraceLine;
+          }
           index = endIndex;
         } else {
           codeBuffer.writeCharCode(charCode);
@@ -213,18 +237,43 @@
   for (int stackTraceIndex in (stackTraceMap.keys.toList()..sort()).reversed) {
     expectedLines.add(stackTraceMap[stackTraceIndex]);
   }
-  return new Test(codeBuffer.toString(), expectedLines);
+  return new Test(codeBuffer.toString(), expectedLines, unexpectedLines);
 }
 
 void main(List<String> arguments) {
+  bool verbose = false;
+  bool printJs = false;
+  List<int> indices;
+  for (String arg in arguments) {
+    if (arg == '-v') {
+      verbose = true;
+    } else if (arg == '--print-js') {
+      printJs = true;
+    } else {
+      int index = int.parse(arg, onError: (_) => null);
+      if (index != null) {
+        indices ??= <int>[];
+        if (index < 0 || index >= TESTS.length) {
+          print('Index $index out of bounds: [0;${TESTS.length - 1}]');
+        } else {
+          indices.add(index);
+        }
+      }
+    }
+  }
+  if (indices == null) {
+    indices = new List<int>.generate(TESTS.length, (i) => i);
+  }
   asyncTest(() async {
-    for (String code in TESTS) {
-      await runTest(processTestCode(code), verbose: arguments.contains('-v'));
+    for (int index in indices) {
+      await runTest(index, processTestCode(TESTS[index]),
+          printJs: printJs, verbose: verbose);
     }
   });
 }
 
-Future runTest(Test test, {bool verbose: false}) async {
+Future runTest(int index, Test test,
+    {bool printJs: false, bool verbose: false}) async {
   Directory tmpDir = await createTempDir();
   String input = '${tmpDir.path}/$INPUT_FILE_NAME';
   new File(input).writeAsStringSync(test.code);
@@ -236,7 +285,7 @@
     Flags.useNewSourceInfo,
     input,
   ];
-  print("--------------------------------------------------------------------");
+  print("--$index------------------------------------------------------------");
   print("Compiling dart2js ${arguments.join(' ')}\n${test.code}");
   CompilationResult compilationResult = await entry.internalMain(arguments);
   Expect.isTrue(compilationResult.isSuccess,
@@ -245,6 +294,10 @@
   SingleMapping sourceMap = new SingleMapping.fromJson(
       JSON.decode(new File('$output.map').readAsStringSync()));
 
+  if (printJs) {
+    print('JavaScript output:');
+    print(new File(output).readAsStringSync());
+  }
   print("Running d8 $output");
   ProcessResult runResult = Process.runSync(d8executable,
       ['sdk/lib/_internal/js_runtime/lib/preambles/d8.js', output]);
@@ -288,6 +341,7 @@
   }
 
   int expectedIndex = 0;
+  List<StackTraceLine> unexpectedLines = <StackTraceLine>[];
   for (StackTraceLine line in dartStackTrace) {
     if (expectedIndex < test.expectedLines.length) {
       StackTraceLine expectedLine = test.expectedLines[expectedIndex];
@@ -297,6 +351,13 @@
         expectedIndex++;
       }
     }
+    for (StackTraceLine unexpectedLine in test.unexpectedLines) {
+      if (line.methodName == unexpectedLine.methodName &&
+          line.lineNo == unexpectedLine.lineNo &&
+          line.columnNo == unexpectedLine.columnNo) {
+        unexpectedLines.add(line);
+      }
+    }
   }
   if (verbose) {
     print('JavaScript stacktrace:');
@@ -310,6 +371,11 @@
       "Missing stack trace lines for test:\n${test.code}\n"
       "Actual:\n${dartStackTrace.join('\n')}\n"
       "Expected:\n${test.expectedLines.join('\n')}\n");
+  Expect.isTrue(
+      unexpectedLines.isEmpty,
+      "Unexpected stack trace lines for test:\n${test.code}\n"
+      "Actual:\n${dartStackTrace.join('\n')}\n"
+      "Unexpected:\n${test.unexpectedLines.join('\n')}\n");
 
   print("Deleting '${tmpDir.path}'.");
   tmpDir.deleteSync(recursive: true);
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index 0e6d5b3..f7ae6bb 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 1b363d1..7b85297 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_methods_function_type_test.dart b/tests/language/generic_methods_function_type_test.dart
index 23c1992..d82a0b4 100644
--- a/tests/language/generic_methods_function_type_test.dart
+++ b/tests/language/generic_methods_function_type_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in a function typed
diff --git a/tests/language/generic_methods_generic_function_parameter_test.dart b/tests/language/generic_methods_generic_function_parameter_test.dart
index 81eeade..45014c4 100644
--- a/tests/language/generic_methods_generic_function_parameter_test.dart
+++ b/tests/language/generic_methods_generic_function_parameter_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 import "package:expect/expect.dart";
diff --git a/tests/language/generic_methods_new_test.dart b/tests/language/generic_methods_new_test.dart
index 0836fd5..83359f1 100644
--- a/tests/language/generic_methods_new_test.dart
+++ b/tests/language/generic_methods_new_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in object creation. With
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index ec7d488..e32526a 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
diff --git a/tests/language/generic_methods_type_expression_test.dart b/tests/language/generic_methods_type_expression_test.dart
index fadd7e9..ccf24bc 100644
--- a/tests/language/generic_methods_type_expression_test.dart
+++ b/tests/language/generic_methods_type_expression_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in type expressions. With
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 75c7dc9..68e50fe 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 //
-// DartOptions=--generic-method-syntax
 // VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle certain cases where
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 5891891..7a10bf8 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -80,16 +80,6 @@
 [ $compiler == dart2js && $browser ]
 config_import_test: Fail # Test flag is not passed to the compiler.
 
-# Experimental feature: Syntactic support for generic methods.
-generic_functions_test: CompileTimeError # DartOptions not passed to compiler.
-generic_local_functions_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_test: CompileTimeError # DartOptions not passed to compiler.
-generic_sends_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_new_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_function_type_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_type_expression_test: CompileTimeError # DartOptions not passed to compiler.
-generic_methods_generic_function_parameter_test: CompileTimeError # DartOptions not passed to compiler.
-
 # Experimental feature: Use initializing formals in initializers and constructor body.
 initializing_formal_access_test: CompileTimeError # DartOptions not passed to compiler.
 initializing_formal_capture_test: CompileTimeError # DartOptions not passed to compiler.
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index 3d87904..133e4c0 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -17,24 +17,17 @@
 accessor_conflict_import_prefixed_test: RuntimeError
 accessor_conflict_import_test: RuntimeError
 assertion_test: RuntimeError
-async_await_test: Crash
-async_break_in_finally_test: RuntimeError
-async_control_structures_test: RuntimeError
+async_await_test: RuntimeError
 async_star_cancel_and_throw_in_finally_test: RuntimeError
 async_star_cancel_while_paused_test: RuntimeError
 async_star_pause_test: RuntimeError
-async_star_regression_fisk_test: RuntimeError
+async_star_regression_fisk_test: Timeout
 async_star_stream_take_test: Timeout
 async_star_take_reyield_test: Timeout
 async_star_test: Timeout
-async_throw_in_catch_test/forceAwait: RuntimeError
-async_throw_in_catch_test/none: RuntimeError
 asyncstar_throw_in_catch_test: Timeout
 asyncstar_yield_test: Timeout
 asyncstar_yieldstar_test: Timeout
-await_exceptions_test: RuntimeError
-await_future_test: RuntimeError
-await_regression_test: RuntimeError
 bad_constructor_test/05: CompileTimeError
 bad_raw_string_negative_test: Fail
 cha_deopt1_test: RuntimeError
@@ -331,7 +324,6 @@
 try_finally_regress_25654_test: RuntimeError
 type_checks_in_factory_method_test: RuntimeError
 type_parameter_literal_test: RuntimeError
-type_parameter_test/04: Crash
 type_variable_conflict2_test/02: MissingCompileTimeError
 type_variable_conflict2_test/06: MissingCompileTimeError
 type_variable_conflict2_test/08: MissingCompileTimeError
@@ -697,11 +689,10 @@
 try_finally_regress_25654_test: RuntimeError
 type_checks_in_factory_method_test: RuntimeError
 type_parameter_literal_test: RuntimeError
-type_parameter_test/04: Crash
 type_variable_conflict2_test/02: MissingCompileTimeError
 type_variable_function_type_test: RuntimeError
 vm/debug_break_enabled_vm_test/01: CompileTimeError
 vm/debug_break_enabled_vm_test/none: CompileTimeError
 vm/reflect_core_vm_test: CompileTimeError
 vm/type_cast_vm_test: RuntimeError
-vm/type_vm_test: RuntimeError
+vm/type_vm_test: RuntimeError
\ No newline at end of file
diff --git a/tests/lib/mirrors/unnamed_mixin_application_test.dart b/tests/lib/mirrors/unnamed_mixin_application_test.dart
new file mode 100644
index 0000000..782774b
--- /dev/null
+++ b/tests/lib/mirrors/unnamed_mixin_application_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test that the forwarding constructors of unnamed mixin applications are 
+/// included for reflection.
+
+import 'dart:mirrors';
+
+class S {
+  S();
+  S.anUnusedName();
+}
+class M {}
+class C extends S with M {
+  C();
+}
+
+main() {
+  // Use 'C#', 'S+M#' and 'S#' but not 'S#anUnusedName' nor 'S+M#anUnusedName'.
+  new C();
+  // Disable tree shaking making 'S+M#anUnusedName' live.
+  reflectClass(C);
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index b4d1f0b..6f94e01 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,5 +28,5 @@
 MAJOR 1
 MINOR 21
 PATCH 0
-PRERELEASE 8
+PRERELEASE 9
 PRERELEASE_PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 25c7aba..160844c 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -54,6 +54,7 @@
 # ......collection/
 # ......convert/
 # ......core/
+# ......front_end/
 # ......html/
 # ......internal/
 # ......io/
@@ -145,7 +146,7 @@
              join(sdk_root, 'bin', 'snapshots', snapshot))
 
 def CopyAnalyzerSources(home, lib_dir):
-  for library in ['analyzer', 'analysis_server']:
+  for library in ['analyzer', 'analysis_server', 'front_end']:
     copytree(join(home, 'pkg', library), join(lib_dir, library),
              ignore=ignore_patterns('*.svn', 'doc', '*.py', '*.gypi', '*.sh',
                                     '.gitignore', 'packages'))
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index bee1a2c..e9802e9 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -83,8 +83,16 @@
    dartkp: Compiler the Dart source into Kernel and then Kernel into AOT
    snapshot before running the test.''',
           ['-c', '--compiler'],
-          ['none', 'precompiler', 'dart2js', 'dart2analyzer', 'dart2app',
-           'dart2appjit', 'dartk', 'dartkp'],
+          [
+            'none',
+            'precompiler',
+            'dart2js',
+            'dart2analyzer',
+            'dart2app',
+            'dart2appjit',
+            'dartk',
+            'dartkp'
+          ],
           'none'),
       // TODO(antonm): fix the option drt.
       new _TestOptionSpecification(
@@ -198,21 +206,29 @@
           'noopt', 'Run an in-place precompilation', ['--noopt'], [], false,
           type: 'bool'),
       new _TestOptionSpecification(
-          'fast_startup', 'Pass the --fast-startup flag to dart2js',
-          ['--fast-startup'], [], false,
+          'fast_startup',
+          'Pass the --fast-startup flag to dart2js',
+          ['--fast-startup'],
+          [],
+          false,
+          type: 'bool'),
+      new _TestOptionSpecification('hot_reload', 'Run hot reload stress tests',
+          ['--hot-reload'], [], false,
           type: 'bool'),
       new _TestOptionSpecification(
-          'hot_reload', 'Run hot reload stress tests', ['--hot-reload'], [],
-          false, type: 'bool'),
-      new _TestOptionSpecification(
           'hot_reload_rollback',
-          'Run hot reload rollback stress tests', ['--hot-reload-rollback'],
+          'Run hot reload rollback stress tests',
+          ['--hot-reload-rollback'],
           [],
-          false, type: 'bool'),
+          false,
+          type: 'bool'),
       new _TestOptionSpecification(
           'use_blobs',
           'Use mmap instead of shared libraries for precompilation',
-          ['--use-blobs'], [], false, type: 'bool'),
+          ['--use-blobs'],
+          [],
+          false,
+          type: 'bool'),
       new _TestOptionSpecification(
           'timeout', 'Timeout in seconds', ['-t', '--timeout'], [], -1,
           type: 'int'),
@@ -611,34 +627,30 @@
 
   List<String> _constructReproducingCommandArguments(Map config) {
     var arguments = new List<String>();
-    for (var configKey in config.keys) {
-      if (!_blacklistedOptions.contains(configKey)) {
-        for (var option in _options) {
-          var configValue = config[configKey];
-          // We only include entries of [conf] if we find an option for it.
-          if (configKey == option.name && configValue != option.defaultValue) {
-            var isBooleanOption = option.type == 'bool';
-            // Sort by length, so we get the shortest variant.
-            var possibleOptions = new List.from(option.keys);
-            possibleOptions.sort((a, b) => (a.length < b.length ? -1 : 1));
-            var key = possibleOptions[0];
-            if (key.startsWith('--')) {
-              // long version
-              arguments.add(key);
-              if (!isBooleanOption) {
-                arguments.add("$configValue");
-              }
-            } else {
-              // short version
-              assert(key.startsWith('-'));
-              if (!isBooleanOption) {
-                arguments.add("$key$configValue");
-              } else {
-                arguments.add(key);
-              }
-            }
-          }
-        }
+    for (var option in _options) {
+      var name = option.name;
+      if (!config.containsKey(name) || _blacklistedOptions.contains(name)) {
+        continue;
+      }
+      var value = config[name];
+      if (config[name] == option.defaultValue ||
+          (name == 'packages' &&
+              value ==
+                  TestUtils.dartDirUri.resolve('.packages').toFilePath())) {
+        continue;
+      }
+      shortest(String a, String b) => a.length <= b.length ? a : b;
+      var key = option.keys.reduce(shortest);
+      if (option.type == 'bool') {
+        arguments.add(key);
+      } else if (key.startsWith('--')) {
+        // long version
+        arguments.add(key);
+        arguments.add("$value");
+      } else {
+        // short version
+        assert(key.startsWith('-'));
+        arguments.add("$key$value");
       }
     }
     return arguments;
@@ -826,20 +838,23 @@
     if (selectors.containsKey('observatory_ui')) {
       if (selectors.length == 1) {
         configuration['packages'] = TestUtils.dartDirUri
-          .resolve('runtime/observatory/.packages').toFilePath();
+            .resolve('runtime/observatory/.packages')
+            .toFilePath();
       } else {
         // Make a new configuration whose selectors map only contains
         // observatory_ui, and remove the key from the original selectors.
         // The only mutable value in the map is the selectors, so a
         // shallow copy is safe.
         var observatoryConfiguration = new Map.from(configuration);
-        observatoryConfiguration['selectors'] =
-          {'observatory_ui': selectors['observatory_ui']};
+        observatoryConfiguration['selectors'] = {
+          'observatory_ui': selectors['observatory_ui']
+        };
         selectors.remove('observatory_ui');
 
         // Set the packages flag.
         observatoryConfiguration['packages'] = TestUtils.dartDirUri
-          .resolve('runtime/observatory/.packages').toFilePath();
+            .resolve('runtime/observatory/.packages')
+            .toFilePath();
 
         // Return the expansions of both configurations. Neither will reach
         // this line in the recursive call to _expandConfigurations.
@@ -851,7 +866,7 @@
     if (configuration['package_root'] == null &&
         configuration['packages'] == null) {
       configuration['packages'] =
-        TestUtils.dartDirUri.resolve('.packages').toFilePath();
+          TestUtils.dartDirUri.resolve('.packages').toFilePath();
     }
 
     // Expand the architectures.
@@ -883,8 +898,8 @@
 
     // Adjust default timeout based on mode, compiler, and sometimes runtime.
     if (configuration['timeout'] == -1) {
-      var isReload = configuration['hot_reload'] ||
-                     configuration['hot_reload_rollback'];
+      var isReload =
+          configuration['hot_reload'] || configuration['hot_reload_rollback'];
       int compilerMulitiplier =
           new CompilerConfiguration(configuration).computeTimeoutMultiplier();
       int runtimeMultiplier = new RuntimeConfiguration(configuration)