Version 1.6.0-dev.5.0

svn merge -r 38367:38486 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@38487 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/driver.dart b/pkg/analysis_server/lib/driver.dart
index c3c6f24..e210777 100644
--- a/pkg/analysis_server/lib/driver.dart
+++ b/pkg/analysis_server/lib/driver.dart
@@ -9,6 +9,9 @@
 import 'package:analysis_server/http_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analysis_server/stdio_server.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:args/args.dart';
 import 'package:logging/logging.dart';
 
@@ -39,15 +42,20 @@
    */
   static const String LOG_FILE_OPTION = "log";
 
-  SocketServer socketServer = new SocketServer();
+  /**
+   * The path to the SDK.
+   * TODO(paulberry): get rid of this once the 'analysis.updateSdks' request is
+   * operational.
+   */
+  static const String SDK_OPTION = 'sdk';
+
+  SocketServer socketServer;
 
   HttpAnalysisServer httpServer;
 
   StdioAnalysisServer stdioServer;
 
   Driver() {
-    httpServer = new HttpAnalysisServer(socketServer);
-    stdioServer = new StdioAnalysisServer(socketServer);
   }
 
   /**
@@ -62,6 +70,8 @@
         "[port] the port on which the server will listen");
     parser.addOption(LOG_FILE_OPTION, help:
         "[path] file to log debugging messages to");
+    parser.addOption(SDK_OPTION, help:
+        "[path] path to the sdk");
 
     ArgResults results = parser.parse(args);
     if (results[HELP_OPTION]) {
@@ -95,6 +105,18 @@
         return;
       }
     }
+    DartSdk defaultSdk;
+    if (results[SDK_OPTION] != null) {
+      defaultSdk = new DirectoryBasedDartSdk(new JavaFile(results[SDK_OPTION]));
+    } else {
+      // No path to the SDK provided; use DirectoryBasedDartSdk.defaultSdk,
+      // which will make a guess.
+      defaultSdk = DirectoryBasedDartSdk.defaultSdk;
+    }
+
+    socketServer = new SocketServer(defaultSdk);
+    httpServer = new HttpAnalysisServer(socketServer);
+    stdioServer = new StdioAnalysisServer(socketServer);
 
     if (serve_http) {
       httpServer.serveHttp(port);
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 975a911..285e82f 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -24,7 +24,6 @@
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analysis_services/index/index.dart';
@@ -32,12 +31,6 @@
 import 'package:analyzer/src/generated/element.dart';
 
 
-/**
- * An instance of [DirectoryBasedDartSdk] that is shared between
- * [AnalysisServer] instances to improve performance.
- */
-final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk;
-
 class AnalysisServerContextDirectoryManager extends ContextDirectoryManager {
   final AnalysisServer analysisServer;
 
@@ -143,7 +136,7 @@
   /**
    * The current default [DartSdk].
    */
-  DartSdk defaultSdk = SHARED_SDK;
+  final DartSdk defaultSdk;
 
   /**
    * A table mapping [Folder]s to the [AnalysisContext]s associated with them.
@@ -173,6 +166,13 @@
       new HashMap<AnalysisService, Set<String>>();
 
   /**
+   * A table mapping [AnalysisContext]s to the completers that should be
+   * completed when analysis of this context is finished.
+   */
+  Map<AnalysisContext, Completer> contextAnalysisDoneCompleters =
+      new HashMap<AnalysisContext, Completer>();
+
+  /**
    * True if any exceptions thrown by analysis should be propagated up the call
    * stack.
    */
@@ -188,7 +188,7 @@
    * running a full analysis server.
    */
   AnalysisServer(this.channel, ResourceProvider resourceProvider,
-      PackageMapProvider packageMapProvider, this.index,
+      PackageMapProvider packageMapProvider, this.index, this.defaultSdk,
       {this.rethrowExceptions: true}) {
     searchEngine = createSearchEngine(index);
     operationQueue = new ServerOperationQueue(this);
@@ -227,6 +227,13 @@
   }
 
   /**
+   * Send the given [response] to the client.
+   */
+  void sendResponse(Response response) {
+    channel.sendResponse(response);
+  }
+
+  /**
    * Set the priority files to the given [files].
    */
   void setPriorityFiles(Request request, List<String> files) {
@@ -334,6 +341,9 @@
     for (int i = 0; i < count; i++) {
       try {
         Response response = handlers[i].handleRequest(request);
+        if (response == Response.DELAYED_RESPONSE) {
+          return;
+        }
         if (response != null) {
           channel.sendResponse(response);
           return;
@@ -562,6 +572,24 @@
   }
 
   /**
+   * Returns all the [AnalysisErrorInfo] for [file].
+   * It does not wait for all errors to be computed, and returns just the
+   * current state.
+   *
+   * May return `null`.
+   */
+  AnalysisErrorInfo getErrors(String file) {
+    // prepare AnalysisContext
+    AnalysisContext context = getAnalysisContext(file);
+    if (context == null) {
+      return null;
+    }
+    // get errors for the file
+    Source source = getSource(file);
+    return context.getErrors(source);
+  }
+
+  /**
    * Returns resolved [CompilationUnit]s of the Dart file with the given [path].
    *
    * May be empty, but not `null`.
@@ -606,6 +634,51 @@
   }
 
   /**
+   * Returns a [Future] completing when [file] has been completely analyzed, in
+   * particular, all its errors have been computed.
+   *
+   * TODO(scheglov) this method should be improved.
+   *
+   * 1. The analysis context should be told to analyze this particular file ASAP.
+   *
+   * 2. We should complete the future as soon as the file is analyzed (not wait
+   *    until the context is completely finished)
+   *
+   * 3. Since contexts can be created and deleted asynchronously as a result of
+   *    changes to the filesystem, there's a danger that the future might never
+   *    get completed. We should add a mechanism to make sure that we return an
+   *    error for any getErrors request that is unsatisfiable due to its context
+   *    being deleted.
+   */
+  Future onFileAnalysisComplete(String file) {
+    // prepare AnalysisContext
+    AnalysisContext context = getAnalysisContext(file);
+    if (context == null) {
+      return new Future.value();
+    }
+    // schedule context analysis
+    schedulePerformAnalysisOperation(context);
+    // associate with the context completer
+    Completer completer = contextAnalysisDoneCompleters[context];
+    if (completer == null) {
+      completer = new Completer();
+      contextAnalysisDoneCompleters[context] = completer;
+    }
+    return completer.future;
+  }
+
+  /**
+   * This method is called when analysis of the given [AnalysisContext] is
+   * done.
+   */
+  void sendContextAnalysisDoneNotifications(AnalysisContext context) {
+    Completer completer = contextAnalysisDoneCompleters[context];
+    if (completer != null) {
+      completer.complete();
+    }
+  }
+
+  /**
    * Return the [CompilationUnit] of the Dart file with the given [path].
    * Return `null` if the file is not a part of any context.
    */
diff --git a/pkg/analysis_server/lib/src/collections.dart b/pkg/analysis_server/lib/src/collections.dart
index 1c5fefc..f85bc97 100644
--- a/pkg/analysis_server/lib/src/collections.dart
+++ b/pkg/analysis_server/lib/src/collections.dart
@@ -16,15 +16,3 @@
  * Returns the concatentation of the input iterables as a [List].
  */
 List concatToList(Iterable<Iterable> iterables) => concat(iterables).toList();
-
-
-/**
- * Instances of the class [HasToJson] implement [toJson] method that returns
- * a JSON presentation.
- */
-abstract class HasToJson {
-  /**
-   * Returns a JSON presentation of the object.
-   */
-  Map<String, Object> toJson();
-}
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 9a16c80..4d71907 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -4,8 +4,8 @@
 
 library computer.highlights;
 
-import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 79215d3..960129f 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -6,8 +6,8 @@
 
 import 'dart:collection';
 
-import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
index 768622b..98c2280 100644
--- a/pkg/analysis_server/lib/src/computer/computer_navigation.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
@@ -4,7 +4,7 @@
 
 library computer.navigation;
 
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
index 86427f8..0a87298 100644
--- a/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_occurrences.dart
@@ -6,9 +6,9 @@
 
 import 'dart:collection';
 
-import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/element.dart' as server;
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index 6414c32..4e58235 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -4,9 +4,9 @@
 
 library computer.outline;
 
-import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart' as engine;
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index a0cf035..429c778 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -4,9 +4,9 @@
 
 library computer.overrides;
 
-import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart' as engine;
 
diff --git a/pkg/analysis_server/lib/src/computer/element.dart b/pkg/analysis_server/lib/src/computer/element.dart
index 5ceac10..fb9943a 100644
--- a/pkg/analysis_server/lib/src/computer/element.dart
+++ b/pkg/analysis_server/lib/src/computer/element.dart
@@ -4,7 +4,7 @@
 
 library computer.element;
 
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analyzer/src/generated/element.dart' as engine;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
diff --git a/pkg/analysis_server/lib/src/computer/error.dart b/pkg/analysis_server/lib/src/computer/error.dart
new file mode 100644
index 0000000..5db2e2a
--- /dev/null
+++ b/pkg/analysis_server/lib/src/computer/error.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library computer.error;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/source.dart' as engine;
+
+
+/**
+ * An indication of an error, warning, or hint that was produced by the
+ * analysis. 
+ */
+class AnalysisError implements HasToJson {
+  final String severity;
+  final String type;
+  final Location location;
+  final String message;
+  final String correction;
+
+  AnalysisError(this.severity, this.type, this.location, this.message,
+      this.correction);
+
+  factory AnalysisError.fromEngine(engine.LineInfo lineInfo,
+      engine.AnalysisError error) {
+    engine.ErrorCode errorCode = error.errorCode;
+    // prepare location
+    Location location;
+    {
+      String file = error.source.fullName;
+      int offset = error.offset;
+      int length = error.length;
+      int startLine = -1;
+      int startColumn = -1;
+      if (lineInfo != null) {
+        engine.LineInfo_Location lineLocation = lineInfo.getLocation(offset);
+        if (lineLocation != null) {
+          startLine = lineLocation.lineNumber;
+          startColumn = lineLocation.columnNumber;
+        }
+      }
+      location = new Location(file, offset, length, startLine, startColumn);
+    }
+    // done
+    String severity = errorCode.errorSeverity.toString();
+    String type = errorCode.type.toString();
+    String message = error.message;
+    String correction = errorCode.correction;
+    return new AnalysisError(severity, type, location, message, correction);
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> json = {
+      SEVERITY: severity,
+      TYPE: type,
+      LOCATION: location.toJson(),
+      MESSAGE: message
+    };
+    if (correction != null) {
+      json[CORRECTION] = correction;
+    }
+    return json;
+  }
+
+  @override
+  String toString() {
+    return 'AnalysisError(location=$location message=$message; '
+        'severity=$severity; type=$type; correction=$correction';
+  }
+
+  static AnalysisError fromJson(Map<String, Object> json) {
+    return new AnalysisError(
+        json[SEVERITY],
+        json[TYPE],
+        new Location.fromJson(json[LOCATION]),
+        json[MESSAGE],
+        json[CORRECTION]);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 735d384..0285b10 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library constants;
+library server.constants;
 
 //
 // Server methods
@@ -21,6 +21,7 @@
 //
 // Analysis methods
 //
+const String ANALYSIS_GET_ERRORS = 'analysis.getErrors';
 const String ANALYSIS_GET_HOVER = 'analysis.getHover';
 const String ANALYSIS_SET_ANALYSIS_ROOTS = 'analysis.setAnalysisRoots';
 const String ANALYSIS_SET_PRIORITY_FILES = 'analysis.setPriorityFiles';
@@ -75,69 +76,6 @@
 const String EDIT_SET_REFACTORING_OPTIONS = 'edit.setRefactoringOptions';
 
 //
-// Property names
-//
-const String ADDED = 'added';
-const String CHILDREN = 'children';
-const String COMPLETION = 'completion';
-const String CONTAINING_LIBRARY_NAME = 'containingLibraryName';
-const String CONTAINING_LIBRARY_PATH = 'containingLibraryPath';
-const String CONTENT = 'content';
-const String CORRECTION = 'correction';
-const String DART_DOC = 'dartdoc';
-const String DEFAULT = 'default';
-const String ELEMENT = 'element';
-const String ELEMENT_DESCRIPTION = 'elementDescription';
-const String ELEMENT_KIND = 'elementKind';
-const String EXCLUDED = 'excluded';
-const String ERRORS = 'errors';
-const String FILE = 'file';
-const String FILES = 'files';
-const String FIXES = 'fixes';
-const String FLAGS = 'flags';
-const String HOVERS = 'hovers';
-const String ID = 'id';
-const String INCLUDE_POTENTIAL = 'includePotential';
-const String INCLUDED = 'included';
-const String INTERFACE_ELEMENTS = 'interfaceElements';
-const String IS_ABSTRACT = 'isAbstract';
-const String IS_POTENTIAL = 'isPotential';
-const String IS_STATIC = 'isStatic';
-const String KIND = 'kind';
-const String LAST = 'last';
-const String LENGTH = 'length';
-const String LOCATION = 'location';
-const String MESSAGE = 'message';
-const String NAME = 'name';
-const String NEW_LENGTH = 'newLength';
-const String OCCURRENCES = 'occurrences';
-const String OFFSET = 'offset';
-const String OFFSETS = 'offsets';
-const String OLD_LENGTH = 'oldLength';
-const String OPTIONS = 'options';
-const String OUTLINE = 'outline';
-const String OVERRIDES = 'overrides';
-const String PARAMETER = 'parameter';
-const String PARAMETERS = 'parameters';
-const String PATH = 'path';
-const String PATTERN = 'pattern';
-const String PROPAGATED_TYPE = 'propagatedType';
-const String REFACTORINGS = 'refactorings';
-const String REGIONS = 'regions';
-const String REMOVED = 'removed';
-const String RETURN_TYPE = 'returnType';
-const String RESULTS = 'results';
-const String SEVERITY = 'severity';
-const String START_COLUMN = 'startColumn';
-const String START_LINE = 'startLine';
-const String STATIC_TYPE = 'staticType';
-const String SUBSCRIPTIONS = 'subscriptions';
-const String SUPER_CLASS_ELEMENT = 'superclassElement';
-const String TARGETS = 'targets';
-const String TYPE = 'type';
-const String VERSION = 'version';
-
-//
 // Analysis option names
 //
 const String ANALYZE_ANGULAR = 'analyzeAngular'; // boolean
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index d26aead..ef166c8 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -7,11 +7,14 @@
 import 'dart:collection';
 
 import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analysis_server/src/computer/computer_hover.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/operation/operation_analysis.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
 
 /**
  * Instances of the class [AnalysisDomainHandler] implement a [RequestHandler]
@@ -29,9 +32,30 @@
   AnalysisDomainHandler(this.server);
 
   /**
+   * Implement the `analysis.getErrors` request.
+   */
+  Response getErrors(Request request) {
+    String file = request.getRequiredParameter(FILE).asString();
+    server.onFileAnalysisComplete(file).then((_) {
+      Response response = new Response(request.id);
+      AnalysisErrorInfo errorInfo = server.getErrors(file);
+      if (errorInfo == null) {
+        response.setResult(ERRORS, []);
+      } else {
+        response.setResult(ERRORS, errorInfo.errors.map((AnalysisError error) {
+          return errorToJson(errorInfo.lineInfo, error);
+        }).toList());
+      }
+      server.sendResponse(response);
+    });
+    // delay response
+    return Response.DELAYED_RESPONSE;
+  }
+
+  /**
    * Implement the `analysis.getHover` request.
    */
-  Response getAnalysisHover(Request request) {
+  Response getHover(Request request) {
     // prepare parameters
     String file = request.getRequiredParameter(FILE).asString();
     int offset = request.getRequiredParameter(OFFSET).asInt();
@@ -39,7 +63,8 @@
     List<Hover> hovers = <Hover>[];
     List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
     for (CompilationUnit unit in units) {
-      Hover hoverInformation = new DartUnitHoverComputer(unit, offset).compute();
+      Hover hoverInformation =
+          new DartUnitHoverComputer(unit, offset).compute();
       if (hoverInformation != null) {
         hovers.add(hoverInformation);
       }
@@ -54,8 +79,10 @@
   Response handleRequest(Request request) {
     try {
       String requestName = request.method;
-      if (requestName == ANALYSIS_GET_HOVER) {
-        return getAnalysisHover(request);
+      if (requestName == ANALYSIS_GET_ERRORS) {
+        return getErrors(request);
+      } else if (requestName == ANALYSIS_GET_HOVER) {
+        return getHover(request);
       } else if (requestName == ANALYSIS_SET_ANALYSIS_ROOTS) {
         return setAnalysisRoots(request);
       } else if (requestName == ANALYSIS_SET_PRIORITY_FILES) {
@@ -112,11 +139,11 @@
       Map<String, List<String>> subStringMap = subDatum.asStringListMap();
       subMap = new HashMap<AnalysisService, Set<String>>();
       subStringMap.forEach((String serviceName, List<String> paths) {
-        AnalysisService service = Enum2.valueOf(AnalysisService.VALUES,
-            serviceName);
+        AnalysisService service =
+            Enum2.valueOf(AnalysisService.VALUES, serviceName);
         if (service == null) {
-          throw new RequestFailure(new Response.unknownAnalysisService(request,
-              serviceName));
+          throw new RequestFailure(
+              new Response.unknownAnalysisService(request, serviceName));
         }
         subMap[service] = new HashSet.from(paths);
       });
@@ -133,7 +160,8 @@
     RequestDatum filesDatum = request.getRequiredParameter(FILES);
     filesDatum.forEachMap((file, changeDatum) {
       var change = new ContentChange();
-      change.content = changeDatum[CONTENT].isNull ? null :
+      change.content = changeDatum[CONTENT].isNull ?
+          null :
           changeDatum[CONTENT].asString();
       if (changeDatum.hasKey(OFFSET)) {
         change.offset = changeDatum[OFFSET].asInt();
@@ -192,8 +220,8 @@
           options.hint = optionValue;
         });
       } else {
-        throw new RequestFailure(new Response.unknownOptionName(request,
-            optionName));
+        throw new RequestFailure(
+            new Response.unknownOptionName(request, optionName));
       }
     });
     server.updateOptions(updaters);
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index d3ab0d0..5196d67a 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -9,8 +9,10 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/completion/completion_suggestion.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/search/search_engine.dart';
-import 'package:analysis_server/src/collections.dart';
+import 'package:analyzer/src/generated/element.dart';
 
 /**
  * Instances of the class [CompletionDomainHandler] implement a [RequestHandler]
@@ -90,28 +92,18 @@
     var future = searchEngine.searchTopLevelDeclarations('');
     return future.then((List<SearchMatch> matches) {
       return matches.map((SearchMatch match) {
-        return new CompletionSuggestion(match.element.displayName);
+        Element element = match.element;
+        String completion = element.displayName;
+        return new CompletionSuggestion(
+            CompletionSuggestionKind.fromElementKind(element.kind),
+            CompletionRelevance.DEFAULT,
+            completion,
+            completion.length,
+            0,
+            element.isDeprecated,
+            false // isPotential
+            );
       }).toList();
     });
   }
 }
-
-/**
- * A single completion suggestion.
- */
-class CompletionSuggestion implements HasToJson {
-  final String completion;
-
-  CompletionSuggestion(this.completion);
-
-  factory CompletionSuggestion.fromJson(Map<String, Object> json) {
-    return new CompletionSuggestion(json[COMPLETION]);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    return {
-      COMPLETION: completion
-    };
-  }
-}
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index 6c0126c..cfa7588 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 
 /**
  * Instances of the class [ServerDomainHandler] implement a [RequestHandler]
diff --git a/pkg/analysis_server/lib/src/domain_edit.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
similarity index 69%
rename from pkg/analysis_server/lib/src/domain_edit.dart
rename to pkg/analysis_server/lib/src/edit/edit_domain.dart
index fbca9d6..68a3dbc 100644
--- a/pkg/analysis_server/lib/src/domain_edit.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -2,11 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library domain.edit;
+library edit.domain;
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/search/search_engine.dart';
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+
 
 /**
  * Instances of the class [EditDomainHandler] implement a [RequestHandler]
@@ -19,33 +28,15 @@
   final AnalysisServer server;
 
   /**
+   * The [SearchEngine] for this server.
+   */
+  SearchEngine searchEngine;
+
+  /**
    * Initialize a newly created handler to handle requests for the given [server].
    */
-  EditDomainHandler(this.server);
-
-  @override
-  Response handleRequest(Request request) {
-    try {
-      String requestName = request.method;
-      if (requestName == EDIT_APPLY_REFACTORING) {
-        return applyRefactoring(request);
-      } else if (requestName == EDIT_CREATE_REFACTORING) {
-        return createRefactoring(request);
-      } else if (requestName == EDIT_DELETE_REFACTORING) {
-        return deleteRefactoring(request);
-      } else if (requestName == EDIT_GET_ASSISTS) {
-        return getAssists(request);
-      } else if (requestName == EDIT_GET_FIXES) {
-        return getFixes(request);
-      } else if (requestName == EDIT_GET_REFACTORINGS) {
-        return getRefactorings(request);
-      } else if (requestName == EDIT_SET_REFACTORING_OPTIONS) {
-        return setRefactoringOptions(request);
-      }
-    } on RequestFailure catch (exception) {
-      return exception.response;
-    }
-    return null;
+  EditDomainHandler(this.server) {
+    searchEngine = server.searchEngine;
   }
 
   Response applyRefactoring(Request request) {
@@ -96,19 +87,29 @@
   }
 
   Response getFixes(Request request) {
-    // errors
-    RequestDatum errorsDatum = request.getRequiredParameter(ERRORS);
-    // TODO(paulberry): the API for edit.getFixes should be changed to so that
-    // it doesn't use AnalysisError as an input type.  This is necessary
-    // because the JSON protocol for an AnalysisError doesn't contain the
-    // errorCode, so we don't have enough information to reconstitute the error
-    // object.
-    // List<AnalysisError> errors = errorsDatum.asList((RequestDatum datum) {
-    //   return _createAnalysisError(request, datum);
-    // });
-
-    // TODO(brianwilkerson) implement
-    return null;
+    String file = request.getRequiredParameter(FILE).asString();
+    int offset = request.getRequiredParameter(OFFSET).asInt();
+    List<ErrorFixes> errorFixesList = <ErrorFixes>[];
+    List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
+    for (CompilationUnit unit in units) {
+      engine.AnalysisErrorInfo errorInfo = server.getErrors(file);
+      if (errorInfo != null) {
+        for (engine.AnalysisError error in errorInfo.errors) {
+          List<Fix> fixes = computeFixes(searchEngine, file, unit, error);
+          if (fixes.isNotEmpty) {
+            AnalysisError serverError =
+                new AnalysisError.fromEngine(errorInfo.lineInfo, error);
+            ErrorFixes errorFixes = new ErrorFixes(serverError);
+            errorFixesList.add(errorFixes);
+            fixes.forEach((fix) {
+              return errorFixes.addFix(fix);
+            });
+          }
+        }
+      }
+    }
+    // respond
+    return new Response(request.id)..setResult(FIXES, errorFixesList);
   }
 
   Response getRefactorings(Request request) {
@@ -125,6 +126,31 @@
     return null;
   }
 
+  @override
+  Response handleRequest(Request request) {
+    try {
+      String requestName = request.method;
+      if (requestName == EDIT_APPLY_REFACTORING) {
+        return applyRefactoring(request);
+      } else if (requestName == EDIT_CREATE_REFACTORING) {
+        return createRefactoring(request);
+      } else if (requestName == EDIT_DELETE_REFACTORING) {
+        return deleteRefactoring(request);
+      } else if (requestName == EDIT_GET_ASSISTS) {
+        return getAssists(request);
+      } else if (requestName == EDIT_GET_FIXES) {
+        return getFixes(request);
+      } else if (requestName == EDIT_GET_REFACTORINGS) {
+        return getRefactorings(request);
+      } else if (requestName == EDIT_SET_REFACTORING_OPTIONS) {
+        return setRefactoringOptions(request);
+      }
+    } on RequestFailure catch (exception) {
+      return exception.response;
+    }
+    return null;
+  }
+
   Response setRefactoringOptions(Request request) {
     // id
     RequestDatum idDatum = request.getRequiredParameter(ID);
diff --git a/pkg/analysis_server/lib/src/edit/fix.dart b/pkg/analysis_server/lib/src/edit/fix.dart
new file mode 100644
index 0000000..5e765d4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/fix.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library edit.fix;
+
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/json.dart';
+
+
+class ErrorFixes implements HasToJson {
+  final AnalysisError error;
+  final List<Change> fixes = <Change>[];
+
+  ErrorFixes(this.error);
+
+  void addFix(Fix fix) {
+    Change change = fix.change;
+    fixes.add(change);
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    return {
+      ERROR: error.toJson(),
+      FIXES: objectToJson(fixes)
+    };
+  }
+
+  @override
+  String toString() => 'ErrorFixes(error=$error, fixes=$fixes)';
+
+  static ErrorFixes fromJson(Map<String, Object> json) {
+    AnalysisError error = AnalysisError.fromJson(json[ERROR]);
+    ErrorFixes errorFixes = new ErrorFixes(error);
+    errorFixes.fixes.addAll((json[FIXES] as List).map((json) {
+      return Change.fromJson(json);
+    }));
+    return errorFixes;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 27e2e8e..c4ccdc2 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/index/index.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -146,6 +147,7 @@
     AnalysisResult result = context.performAnalysisTask();
     List<ChangeNotice> notices = result.changeNotices;
     if (notices == null) {
+      server.sendContextAnalysisDoneNotifications(context);
       return;
     }
     // process results
diff --git a/pkg/analysis_server/lib/src/package_map_provider.dart b/pkg/analysis_server/lib/src/package_map_provider.dart
index bf031c4..a345bf2 100644
--- a/pkg/analysis_server/lib/src/package_map_provider.dart
+++ b/pkg/analysis_server/lib/src/package_map_provider.dart
@@ -8,9 +8,9 @@
 import 'dart:convert';
 import 'dart:io' as io;
 
-import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:path/path.dart';
 
 /**
@@ -68,14 +68,19 @@
    */
   final ResourceProvider resourceProvider;
 
-  PubPackageMapProvider(this.resourceProvider);
+  /**
+   * Sdk that we use to find the pub executable.
+   */
+  final DirectoryBasedDartSdk sdk;
+
+  PubPackageMapProvider(this.resourceProvider, this.sdk);
 
   @override
   PackageMapInfo computePackageMap(Folder folder) {
     // TODO(paulberry) make this asynchronous so that we can (a) do other
     // analysis while it's in progress, and (b) time out if it takes too long
     // to respond.
-    String executable = SHARED_SDK.pubExecutable.getAbsolutePath();
+    String executable = sdk.pubExecutable.getAbsolutePath();
     io.ProcessResult result;
     try {
       result = io.Process.runSync(
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index ee53942..fdfdba9 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -7,7 +7,7 @@
 import 'dart:collection';
 import 'dart:convert' show JsonDecoder;
 
-import 'package:analysis_server/src/collections.dart';
+import 'package:analysis_services/json.dart';
 
 /**
  * An abstract enumeration.
@@ -462,6 +462,12 @@
  */
 class Response {
   /**
+   * The [Response] instance that is returned when a real [Response] cannot
+   * be provided at the moment.
+   */
+  static final Response DELAYED_RESPONSE = new Response('DELAYED_RESPONSE');
+
+  /**
    * The name of the JSON attribute containing the id of the request for which
    * this is a response.
    */
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 1a7ff06..53572e1 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/element_references.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/search/search_engine.dart';
 import 'package:analyzer/src/generated/element.dart';
 
diff --git a/pkg/analysis_server/lib/src/search/search_result.dart b/pkg/analysis_server/lib/src/search/search_result.dart
index cc366d0..8170e8f 100644
--- a/pkg/analysis_server/lib/src/search/search_result.dart
+++ b/pkg/analysis_server/lib/src/search/search_result.dart
@@ -4,9 +4,9 @@
 
 library search.search_result;
 
-import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analysis_services/search/search_engine.dart';
 import 'package:analyzer/src/generated/element.dart' as engine;
 
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index f5ea822..16fd27b 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -10,12 +10,13 @@
 import 'package:analysis_server/src/channel.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/domain_edit.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/package_map_provider.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:path/path.dart' as pathos;
 import 'package:analysis_services/index/index.dart';
 import 'package:analysis_services/index/local_file_index.dart';
@@ -53,6 +54,10 @@
    */
   AnalysisServer analysisServer;
 
+  final DirectoryBasedDartSdk defaultSdk;
+
+  SocketServer(this.defaultSdk);
+
   /**
    * Create an analysis server which will communicate with the client using the
    * given serverChannel.
@@ -70,8 +75,9 @@
     analysisServer = new AnalysisServer(
         serverChannel,
         resourceProvider,
-        new PubPackageMapProvider(resourceProvider),
+        new PubPackageMapProvider(resourceProvider, defaultSdk),
         _createIndex(),
+        defaultSdk,
         rethrowExceptions: false);
     _initializeHandlers(analysisServer);
   }
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
new file mode 100644
index 0000000..2c261e5
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.analysis.get_errors;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+import '../analysis_abstract.dart';
+
+
+main() {
+  group('notification.hover', () {
+    runReflectiveTests(GetErrorsTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class GetErrorsTest extends AbstractAnalysisTest {
+  Future<List<AnalysisError>> getErrors() {
+    return getErrorsForFile(testFile);
+  }
+
+  Future<List<AnalysisError>> getErrorsForFile(String file) {
+    return waitForTasksFinished().then((_) {
+      String requestId = 'test-getError';
+      // send the Request
+      Request request = new Request(requestId, ANALYSIS_GET_ERRORS);
+      request.setParameter(FILE, file);
+      server.handleRequest(request);
+      // wait for the Response
+      waitForResponse() {
+        for (Response response in serverChannel.responsesReceived) {
+          if (response.id == requestId) {
+            List errorsJsons = response.getResult(ERRORS);
+            return errorsJsons.map(AnalysisError.fromJson).toList();
+          }
+        }
+        return new Future(waitForResponse);
+      }
+      return new Future(waitForResponse);
+    });
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    server.handlers = [new AnalysisDomainHandler(server),];
+    createProject();
+  }
+
+  test_hasErrors() {
+    addTestFile('''
+main() {
+  print(42)
+}
+''');
+    return getErrors().then((List<AnalysisError> errors) {
+      expect(errors, hasLength(1));
+      {
+        AnalysisError error = errors[0];
+        expect(error.severity, 'ERROR');
+        expect(error.type, 'SYNTACTIC_ERROR');
+        expect(error.location.file, testFile);
+        expect(error.location.startLine, 2);
+      }
+    });
+  }
+
+  test_noErrors() {
+    addTestFile('''
+main() {
+  print(42);
+}
+''');
+    return getErrors().then((List<AnalysisError> errors) {
+      expect(errors, isEmpty);
+    });
+  }
+
+  test_fileWithoutContext() {
+    String file = '/outside.dart';
+    addFile(file, '''
+main() {
+  print(42);
+}
+''');
+    return getErrorsForFile(file).then((List<AnalysisError> errors) {
+      expect(errors, isEmpty);
+    });
+  }
+}
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
new file mode 100644
index 0000000..92917cb
--- /dev/null
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library test.analysis;
+
+import 'package:unittest/unittest.dart';
+
+import 'get_errors_test.dart' as get_errors_test;
+
+/**
+ * Utility for manually running all tests.
+ */
+main() {
+  groupSep = ' | ';
+  group('search', () {
+    get_errors_test.main();
+  });
+}
\ No newline at end of file
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index a6e006c..0cf7558 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/index/index.dart';
 import 'package:analysis_testing/mock_sdk.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -227,8 +228,8 @@
     packageMapProvider = new MockPackageMapProvider();
     Index index = createIndex();
     server = new AnalysisServer(
-        serverChannel, resourceProvider, packageMapProvider, index);
-    server.defaultSdk = new MockSdk();
+        serverChannel, resourceProvider, packageMapProvider, index,
+        new MockSdk());
     handler = new AnalysisDomainHandler(server);
     // listen for notifications
     Stream<Notification> notificationStream = serverChannel.notificationController.stream;
@@ -260,21 +261,3 @@
     return code as String;
   }
 }
-
-
-class AnalysisError {
-  final String file;
-  final String errorCode;
-  final int offset;
-  final int length;
-  final String message;
-  final String correction;
-  AnalysisError(this.file, this.errorCode, this.offset, this.length,
-      this.message, this.correction);
-
-  @override
-  String toString() {
-    return 'NotificationError(file=$file; errorCode=$errorCode; '
-        'offset=$offset; length=$length; message=$message)';
-  }
-}
diff --git a/pkg/analysis_server/test/analysis_hover_test.dart b/pkg/analysis_server/test/analysis_hover_test.dart
index 6b09ce1..1b53eb2 100644
--- a/pkg/analysis_server/test/analysis_hover_test.dart
+++ b/pkg/analysis_server/test/analysis_hover_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/computer/computer_hover.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/analysis_notification_highlights_test.dart b/pkg/analysis_server/test/analysis_notification_highlights_test.dart
index 496b941..0d2a202 100644
--- a/pkg/analysis_server/test/analysis_notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_highlights_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/computer/computer_highlights.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
@@ -32,13 +33,15 @@
 
   void assertHasRawRegion(HighlightType type, int offset, int length) {
     for (HighlightRegion region in regions) {
-      if (region.offset == offset && region.length == length && region.type ==
-          type) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
         return;
       }
     }
-    fail('Expected to find (offset=$offset; length=$length; type=$type) in\n'
-        '${regions.join('\n')}');
+    fail(
+        'Expected to find (offset=$offset; length=$length; type=$type) in\n'
+            '${regions.join('\n')}');
   }
 
   void assertHasRegion(HighlightType type, String search, [int length = -1]) {
@@ -49,11 +52,12 @@
 
   void assertNoRawRegion(HighlightType type, int offset, int length) {
     for (HighlightRegion region in regions) {
-      if (region.offset == offset && region.length == length && region.type ==
-          type) {
+      if (region.offset == offset &&
+          region.length == length &&
+          region.type == type) {
         fail(
             'Not expected to find (offset=$offset; length=$length; type=$type) in\n'
-            '${regions.join('\n')}');
+                '${regions.join('\n')}');
       }
     }
   }
@@ -74,9 +78,9 @@
           length++;
           continue;
         }
-        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) || c >=
-            'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) || c >= '0'.codeUnitAt(0) && c <=
-            '9'.codeUnitAt(0))) {
+        if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
+            c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
+            c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
           break;
         }
         length++;
@@ -85,11 +89,9 @@
     return length;
   }
 
-  Future prepareHighlights(then()) {
+  Future prepareHighlights() {
     addAnalysisSubscription(AnalysisService.HIGHLIGHTS, testFile);
-    return waitForTasksFinished().then((_) {
-      then();
-    });
+    return waitForTasksFinished();
   }
 
   void processNotification(Notification notification) {
@@ -97,8 +99,8 @@
       String file = notification.getParameter(FILE);
       if (file == testFile) {
         regions = [];
-        List<Map<String, Object>> regionsJson = notification.getParameter(
-            REGIONS);
+        List<Map<String, Object>> regionsJson =
+            notification.getParameter(REGIONS);
         for (Map<String, Object> regionJson in regionsJson) {
           regions.add(new HighlightRegion.fromJson(regionJson));
         }
@@ -119,7 +121,7 @@
 }
 @AAA(1, 2, 3) main() {}
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.ANNOTATION, '@AAA(', '@AAA('.length);
       assertHasRegion(HighlightType.ANNOTATION, ') main', ')'.length);
     });
@@ -130,7 +132,7 @@
 const AAA = 42;
 @AAA main() {}
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.ANNOTATION, '@AAA');
     });
   }
@@ -141,7 +143,7 @@
 main() {
   var abstract = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'abstract class');
       assertNoRegion(HighlightType.BUILT_IN, 'abstract = 42');
     });
@@ -154,7 +156,7 @@
   p as int;
   var as = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'as math');
       assertHasRegion(HighlightType.BUILT_IN, 'as int');
       assertNoRegion(HighlightType.BUILT_IN, 'as = 42');
@@ -167,7 +169,7 @@
 main() {
   var deferred = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'deferred as math');
       assertNoRegion(HighlightType.BUILT_IN, 'deferred = 42');
     });
@@ -179,7 +181,7 @@
 main() {
   var export = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'export "dart:');
       assertNoRegion(HighlightType.BUILT_IN, 'export = 42');
     });
@@ -194,7 +196,7 @@
 external main() {
   var external = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'external A()');
       assertHasRegion(HighlightType.BUILT_IN, 'external aaa()');
       assertHasRegion(HighlightType.BUILT_IN, 'external main()');
@@ -210,7 +212,7 @@
 main() {
   var factory = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'factory A()');
       assertNoRegion(HighlightType.BUILT_IN, 'factory = 42');
     });
@@ -225,7 +227,7 @@
 main() {
   var get = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'get aaa =>');
       assertHasRegion(HighlightType.BUILT_IN, 'get bbb =>');
       assertNoRegion(HighlightType.BUILT_IN, 'get = 42');
@@ -238,7 +240,7 @@
 main() {
   var hide = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'hide Foo');
       assertNoRegion(HighlightType.BUILT_IN, 'hide = 42');
     });
@@ -251,7 +253,7 @@
 main() {
   var implements = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'implements A {}');
       assertNoRegion(HighlightType.BUILT_IN, 'implements = 42');
     });
@@ -263,7 +265,7 @@
 main() {
   var import = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'import "');
       assertNoRegion(HighlightType.BUILT_IN, 'import = 42');
     });
@@ -275,7 +277,7 @@
 main() {
   var library = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'library lib;');
       assertNoRegion(HighlightType.BUILT_IN, 'library = 42');
     });
@@ -290,7 +292,7 @@
 main() {
   var native = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'native "A_');
       assertHasRegion(HighlightType.BUILT_IN, 'native "bbb_');
       assertNoRegion(HighlightType.BUILT_IN, 'native = 42');
@@ -305,7 +307,7 @@
   }
   var on = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'on int');
       assertNoRegion(HighlightType.BUILT_IN, 'on = 42');
     });
@@ -319,7 +321,7 @@
 main() {
   var operator = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'operator +(');
       assertNoRegion(HighlightType.BUILT_IN, 'operator = 42');
     });
@@ -332,7 +334,7 @@
   var part = 42;
 }''');
     addFile('/project/bin/my_part.dart', 'part of lib;');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'part "my_');
       assertNoRegion(HighlightType.BUILT_IN, 'part = 42');
     });
@@ -349,7 +351,7 @@
 library lib;
 part 'test.dart';
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'part of', 'part of'.length);
       assertNoRegion(HighlightType.BUILT_IN, 'part = 1');
       assertNoRegion(HighlightType.BUILT_IN, 'of = 2');
@@ -365,7 +367,7 @@
 main() {
   var set = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'set aaa(');
       assertHasRegion(HighlightType.BUILT_IN, 'set bbb(');
       assertNoRegion(HighlightType.BUILT_IN, 'set = 42');
@@ -378,7 +380,7 @@
 main() {
   var show = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'show Foo');
       assertNoRegion(HighlightType.BUILT_IN, 'show = 42');
     });
@@ -393,7 +395,7 @@
 main() {
   var static = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'static aaa;');
       assertHasRegion(HighlightType.BUILT_IN, 'static bbb()');
       assertNoRegion(HighlightType.BUILT_IN, 'static = 42');
@@ -406,7 +408,7 @@
 main() {
   var typedef = 42;
 }''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.BUILT_IN, 'typedef A();');
       assertNoRegion(HighlightType.BUILT_IN, 'typedef = 42');
     });
@@ -417,7 +419,7 @@
 class AAA {}
 AAA aaa;
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.CLASS, 'AAA {}');
       assertHasRegion(HighlightType.CLASS, 'AAA aaa');
     });
@@ -427,7 +429,7 @@
     addTestFile('''
 dynamic f() {}
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertNoRegion(HighlightType.CLASS, 'dynamic f()');
     });
   }
@@ -436,7 +438,7 @@
     addTestFile('''
 void f() {}
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertNoRegion(HighlightType.CLASS, 'void f()');
     });
   }
@@ -455,7 +457,7 @@
  /* block comment */
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.COMMENT_DOCUMENTATION, '/**', 32);
       assertHasRegion(HighlightType.COMMENT_END_OF_LINE, '//', 22);
       assertHasRegion(HighlightType.COMMENT_BLOCK, '/* b', 19);
@@ -473,7 +475,7 @@
   new AAA.name(42);
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.CONSTRUCTOR, 'name(p)');
       assertHasRegion(HighlightType.CONSTRUCTOR, 'name(42)');
       assertNoRegion(HighlightType.CONSTRUCTOR, 'AAA() {}');
@@ -491,7 +493,7 @@
   var v3 = v2;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.DYNAMIC_TYPE, 'p)');
       assertHasRegion(HighlightType.DYNAMIC_TYPE, 'v1 =');
       assertNoRegion(HighlightType.DYNAMIC_TYPE, 'v2;');
@@ -511,7 +513,7 @@
   a.bbb = 5;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.FIELD, 'aaa = 1');
       assertHasRegion(HighlightType.FIELD, 'bbb = 2');
       assertHasRegion(HighlightType.FIELD, 'bbb = 3');
@@ -533,7 +535,7 @@
   A.ccc = 3;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 1');
       assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 2');
       assertHasRegion(HighlightType.FIELD_STATIC, 'bbb;');
@@ -548,7 +550,7 @@
   fff(42);
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.FUNCTION_DECLARATION, 'fff(p) {}');
       assertHasRegion(HighlightType.FUNCTION, 'fff(42)');
     });
@@ -560,7 +562,7 @@
 main(FFF fff) {
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
       assertHasRegion(HighlightType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
     });
@@ -577,7 +579,7 @@
   a.bbb;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.GETTER_DECLARATION, 'aaa => null');
       assertHasRegion(HighlightType.GETTER_DECLARATION, 'bbb => null');
       assertHasRegion(HighlightType.FIELD_STATIC, 'aaa;');
@@ -593,7 +595,7 @@
   CCC ccc;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'aaa = 42');
       assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'bbb(84)');
       assertHasRegion(HighlightType.IDENTIFIER_DEFAULT, 'CCC ccc');
@@ -607,7 +609,7 @@
   ma.max(1, 2);
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.IMPORT_PREFIX, 'ma;');
       assertHasRegion(HighlightType.IMPORT_PREFIX, 'ma.max');
     });
@@ -618,35 +620,35 @@
 void main() {
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.KEYWORD, 'void main()');
     });
   }
 
   test_LITERAL_BOOLEAN() {
     addTestFile('var V = true;');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.LITERAL_BOOLEAN, 'true;');
     });
   }
 
   test_LITERAL_DOUBLE() {
     addTestFile('var V = 4.2;');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
     });
   }
 
   test_LITERAL_INTEGER() {
     addTestFile('var V = 42;');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.LITERAL_INTEGER, '42;');
     });
   }
 
   test_LITERAL_STRING() {
     addTestFile('var V = "abc";');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.LITERAL_STRING, '"abc";', '"abc"'.length);
     });
   }
@@ -659,7 +661,7 @@
   vvv = 1;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
       assertHasRegion(HighlightType.LOCAL_VARIABLE, 'vvv;');
       assertHasRegion(HighlightType.LOCAL_VARIABLE, 'vvv = 1;');
@@ -679,7 +681,7 @@
   A.bbb;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.METHOD_DECLARATION, 'aaa() {}');
       assertHasRegion(HighlightType.METHOD_DECLARATION_STATIC, 'bbb() {}');
       assertHasRegion(HighlightType.METHOD, 'aaa();');
@@ -697,7 +699,7 @@
   }
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.METHOD, 'add(null)');
     });
   }
@@ -709,7 +711,7 @@
   p = 42;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.PARAMETER, 'p) {');
       assertHasRegion(HighlightType.PARAMETER, 'p;');
       assertHasRegion(HighlightType.PARAMETER, 'p = 42');
@@ -727,7 +729,7 @@
   a.bbb = 2;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.SETTER_DECLARATION, 'aaa(x)');
       assertHasRegion(HighlightType.SETTER_DECLARATION, 'bbb(x)');
       assertHasRegion(HighlightType.FIELD_STATIC, 'aaa = 1');
@@ -743,7 +745,7 @@
   VVV = 1;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.TOP_LEVEL_VARIABLE, 'VVV = 0');
       assertHasRegion(HighlightType.FIELD_STATIC, 'VVV);');
       assertHasRegion(HighlightType.FIELD_STATIC, 'VVV = 1');
@@ -756,7 +758,7 @@
   dynamic = 42;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.TYPE_NAME_DYNAMIC, 'dynamic main()');
       assertNoRegion(HighlightType.IDENTIFIER_DEFAULT, 'dynamic main()');
       assertNoRegion(HighlightType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
@@ -770,7 +772,7 @@
   T mmm(T p) => null;
 }
 ''');
-    return prepareHighlights(() {
+    return prepareHighlights().then((_) {
       assertHasRegion(HighlightType.TYPE_PARAMETER, 'T> {');
       assertHasRegion(HighlightType.TYPE_PARAMETER, 'T fff;');
       assertHasRegion(HighlightType.TYPE_PARAMETER, 'T mmm(');
@@ -787,8 +789,9 @@
   }
 
   void test_valueOf() {
-    expect(HighlightType.CLASS, HighlightType.valueOf(
-        HighlightType.CLASS.name));
+    expect(
+        HighlightType.CLASS,
+        HighlightType.valueOf(HighlightType.CLASS.name));
   }
 
   void test_valueOf_unknown() {
diff --git a/pkg/analysis_server/test/analysis_notification_navigation_test.dart b/pkg/analysis_server/test/analysis_notification_navigation_test.dart
index 188cb39c..df89aea 100644
--- a/pkg/analysis_server/test/analysis_notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_navigation_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/computer/element.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
@@ -37,15 +38,16 @@
   void assertHasFileTarget(String file, int offset, int length) {
     for (Element target in testTargets) {
       Location location = target.location;
-      if (location.file == file && location.offset == offset && location.length ==
-          length) {
+      if (location.file == file &&
+          location.offset == offset &&
+          location.length == length) {
         testTarget = target;
         return;
       }
     }
     fail(
         'Expected to find target (file=$file; offset=$offset; length=$length) in\n'
-        '${testRegion} in\n' '${regions.join('\n')}');
+            '${testRegion} in\n' '${regions.join('\n')}');
   }
 
   void assertHasOperatorRegion(String regionSearch, int regionLength,
@@ -137,11 +139,12 @@
    */
   void findRegion(int offset, int length, [bool exists]) {
     for (NavigationRegion region in regions) {
-      if (region.offset == offset && (length == -1 || region.length == length))
-          {
+      if (region.offset == offset &&
+          (length == -1 || region.length == length)) {
         if (exists == false) {
-          fail('Not expected to find (offset=$offset; length=$length) in\n'
-              '${regions.join('\n')}');
+          fail(
+              'Not expected to find (offset=$offset; length=$length) in\n'
+                  '${regions.join('\n')}');
         }
         testRegion = region;
         testTargets = region.targets;
@@ -149,16 +152,15 @@
       }
     }
     if (exists == true) {
-      fail('Expected to find (offset=$offset; length=$length) in\n'
-          '${regions.join('\n')}');
+      fail(
+          'Expected to find (offset=$offset; length=$length) in\n'
+              '${regions.join('\n')}');
     }
   }
 
-  Future prepareNavigation(then()) {
+  Future prepareNavigation() {
     addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
-    return waitForTasksFinished().then((_) {
-      then();
-    });
+    return waitForTasksFinished();
   }
 
   void processNotification(Notification notification) {
@@ -166,8 +168,8 @@
       String file = notification.getParameter(FILE);
       if (file == testFile) {
         regions = <NavigationRegion>[];
-        List<Map<String, Object>> regionsJson = notification.getParameter(
-            REGIONS);
+        List<Map<String, Object>> regionsJson =
+            notification.getParameter(REGIONS);
         for (Map<String, Object> regionJson in regionsJson) {
           var regionOffset = regionJson[OFFSET];
           var regionLength = regionJson[LENGTH];
@@ -175,8 +177,8 @@
           for (Map<String, Object> targetJson in regionJson[TARGETS]) {
             targets.add(new Element.fromJson(targetJson));
           }
-          var region = new NavigationRegion(regionOffset, regionLength,
-              targets);
+          var region =
+              new NavigationRegion(regionOffset, regionLength, targets);
           regions.add(region);
         }
       }
@@ -195,7 +197,7 @@
 AAA aaa;
 ''');
     return waitForTasksFinished().then((_) {
-      return prepareNavigation(() {
+      return prepareNavigation().then((_) {
         assertHasRegionTarget('AAA aaa;', 'AAA {}');
       });
     });
@@ -208,7 +210,7 @@
 }
 class BBB {}
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       // has region for complete "A.named"
       assertHasRegionString('A.named');
       assertHasTarget('named(BBB');
@@ -227,7 +229,7 @@
 }
 class BBB {}
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       // has region for complete "A.named"
       assertHasRegion("A(BBB");
       assertHasTarget("A(BBB", 0);
@@ -243,7 +245,7 @@
   AAA(this.fff);
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionTarget('fff);', 'fff = 123');
     });
   }
@@ -256,7 +258,7 @@
   print(aaa);
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionTarget('AAA aaa', 'AAA {}');
       assertHasRegionTarget('aaa);', 'aaa = null');
       assertHasRegionTarget('main() {', 'main() {');
@@ -269,7 +271,7 @@
   print(vvv);
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertNoRegionString('vvv');
     });
   }
@@ -282,7 +284,7 @@
   new A();
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('new A');
       assertHasTarget('A {');
     });
@@ -297,7 +299,7 @@
   new A.named();
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('new A.named');
       assertHasTarget('named() {}');
     });
@@ -312,7 +314,7 @@
   new A();
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('new A');
       assertHasTarget("A() {}", 0);
     });
@@ -342,7 +344,7 @@
   a /= 6;
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
       assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
       assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
@@ -373,7 +375,7 @@
   b[2] += 2;
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasOperatorRegion('] // []', 1, '[](index)', 2);
       assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
       assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
@@ -385,7 +387,7 @@
     var libCode = 'library lib; part "test.dart";';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('part of lib;');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('part of lib');
       assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
     });
@@ -395,7 +397,7 @@
     var libCode = 'library lib;';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('export "lib.dart";');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('export "lib.dart"');
       assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
     });
@@ -403,7 +405,7 @@
 
   test_string_export_unresolvedUri() {
     addTestFile('export "no.dart";');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertNoRegionString('export "no.dart"');
     });
   }
@@ -412,7 +414,7 @@
     var libCode = 'library lib;';
     var libFile = addFile('$projectPath/bin/lib.dart', libCode);
     addTestFile('import "lib.dart";');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('import "lib.dart"');
       assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
     });
@@ -420,14 +422,14 @@
 
   test_string_import_noUri() {
     addTestFile('import ;');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertNoRegionAt('import ;');
     });
   }
 
   test_string_import_unresolvedUri() {
     addTestFile('import "no.dart";');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertNoRegionString('import "no.dart"');
     });
   }
@@ -439,7 +441,7 @@
 library lib;
 part "test_unit.dart";
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionString('part "test_unit.dart"');
       assertHasFileTarget(unitFile, 0, 0);
     });
@@ -450,7 +452,7 @@
 library lib;
 part "test_unit.dart";
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertNoRegionString('part "test_unit.dart"');
     });
   }
@@ -462,7 +464,7 @@
   AAA aaa = null;
 }
 ''');
-    return prepareNavigation(() {
+    return prepareNavigation().then((_) {
       assertHasRegionTarget('AAA aaa', 'AAA {}');
       expect(testTarget.kind, ElementKind.CLASS);
       expect(testTarget.name, 'AAA');
diff --git a/pkg/analysis_server/test/analysis_notification_occurrences_test.dart b/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
index 8f65214..46dd37f 100644
--- a/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_occurrences_test.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/computer/element.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
@@ -82,11 +83,9 @@
     }
   }
 
-  Future prepareOccurrences(then()) {
+  Future prepareOccurrences() {
     addAnalysisSubscription(AnalysisService.OCCURRENCES, testFile);
-    return waitForTasksFinished().then((_) {
-      then();
-    });
+    return waitForTasksFinished();
   }
 
   void processNotification(Notification notification) {
@@ -117,7 +116,7 @@
 }
 ''');
     return waitForTasksFinished().then((_) {
-      return prepareOccurrences(() {
+      return prepareOccurrences().then((_) {
         assertHasRegion('vvv =');
         expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
         expect(testOccurences.element.name, 'vvv');
@@ -136,7 +135,7 @@
 }
 int VVV = 4;
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('int a');
       expect(testOccurences.element.kind, ElementKind.CLASS);
       expect(testOccurences.element.name, 'int');
@@ -158,7 +157,7 @@
   }
 }
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('fff;');
       expect(testOccurences.element.kind, ElementKind.FIELD);
       assertHasOffset('fff); // constructor');
@@ -175,7 +174,7 @@
   print(vvv);
 }
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('vvv =');
       expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
       expect(testOccurences.element.name, 'vvv');
@@ -197,7 +196,7 @@
   b.fff = 2;
 }
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('fff;');
       expect(testOccurences.element.kind, ElementKind.FIELD);
       assertHasOffset('fff = 1;');
@@ -217,7 +216,7 @@
   b.mmm(); // b
 }
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('mmm() {}');
       expect(testOccurences.element.kind, ElementKind.METHOD);
       assertHasOffset('mmm(); // a');
@@ -233,7 +232,7 @@
   print(VVV);
 }
 ''');
-    return prepareOccurrences(() {
+    return prepareOccurrences().then((_) {
       assertHasRegion('VVV = 1;');
       expect(testOccurences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
       assertHasOffset('VVV = 2;');
diff --git a/pkg/analysis_server/test/analysis_notification_outline_test.dart b/pkg/analysis_server/test/analysis_notification_outline_test.dart
index caa3f12..f8909d4 100644
--- a/pkg/analysis_server/test/analysis_notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_outline_test.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/computer/element.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
@@ -28,11 +29,9 @@
 class _AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
   Outline outline;
 
-  Future prepareOutline(then()) {
+  Future prepareOutline() {
     addAnalysisSubscription(AnalysisService.OUTLINE, testFile);
-    return waitForTasksFinished().then((_) {
-      then();
-    });
+    return waitForTasksFinished();
   }
 
   void processNotification(Notification notification) {
@@ -60,7 +59,7 @@
 ''');
     return waitForTasksFinished().then((_) {
       expect(outline, isNull);
-      return prepareOutline(() {
+      return prepareOutline().then((_) {
         Outline unitOutline = outline;
         List<Outline> outlines = unitOutline.children;
         expect(outlines, hasLength(2));
@@ -85,7 +84,7 @@
   B(int p);
 }");
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> topOutlines = unitOutline.children;
       expect(topOutlines, hasLength(2));
@@ -281,7 +280,7 @@
   }
 }
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> topOutlines = unitOutline.children;
       expect(topOutlines, hasLength(2));
@@ -429,7 +428,7 @@
   int methodB() {} // endB
 }
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> outlines = unitOutline.children[0].children;
       expect(outlines, hasLength(2));
@@ -469,7 +468,7 @@
   int fieldD; // marker2
 }
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> outlines = unitOutline.children[0].children;
       expect(outlines, hasLength(4));
@@ -535,7 +534,7 @@
 class B {
 } // endB
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> topOutlines = unitOutline.children;
       expect(topOutlines, hasLength(2));
@@ -573,7 +572,7 @@
 int fieldA, fieldB, fieldC; // marker
 int fieldD; // marker2
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> outlines = unitOutline.children;
       expect(outlines, hasLength(4));
@@ -644,7 +643,7 @@
 String get propA => null;
 set propB(int v) {}
 ''');
-    return prepareOutline(() {
+    return prepareOutline().then((_) {
       Outline unitOutline = outline;
       List<Outline> topOutlines = unitOutline.children;
       expect(topOutlines, hasLength(9));
diff --git a/pkg/analysis_server/test/analysis_notification_overrides_test.dart b/pkg/analysis_server/test/analysis_notification_overrides_test.dart
index 34ca127..34888f0 100644
--- a/pkg/analysis_server/test/analysis_notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis_notification_overrides_test.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/computer/element.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
@@ -40,8 +41,9 @@
         return;
       }
     }
-    fail('Expect to find an overridden interface elements at $offset in '
-        '${override.interfaceElements.join('\n')}');
+    fail(
+        'Expect to find an overridden interface elements at $offset in '
+            '${override.interfaceElements.join('\n')}');
   }
 
   /**
@@ -94,24 +96,24 @@
     for (Override override in overridesList) {
       if (override.offset == offset && override.length == length) {
         if (exists == false) {
-          fail('Not expected to find (offset=$offset; length=$length) in\n'
-              '${overridesList.join('\n')}');
+          fail(
+              'Not expected to find (offset=$offset; length=$length) in\n'
+                  '${overridesList.join('\n')}');
         }
         this.override = override;
         return;
       }
     }
     if (exists == true) {
-      fail('Expected to find (offset=$offset; length=$length) in\n'
-          '${overridesList.join('\n')}');
+      fail(
+          'Expected to find (offset=$offset; length=$length) in\n'
+              '${overridesList.join('\n')}');
     }
   }
 
-  Future prepareOverrides(then()) {
+  Future prepareOverrides() {
     addAnalysisSubscription(AnalysisService.OVERRIDES, testFile);
-    return waitForTasksFinished().then((_) {
-      then();
-    });
+    return waitForTasksFinished();
   }
 
   void processNotification(Notification notification) {
@@ -119,8 +121,8 @@
       String file = notification.getParameter(FILE);
       if (file == testFile) {
         overridesList = <Override>[];
-        List<Map<String, Object>> jsonList = notification.getParameter(
-            OVERRIDES);
+        List<Map<String, Object>> jsonList =
+            notification.getParameter(OVERRIDES);
         for (Map<String, Object> json in jsonList) {
           overridesList.add(new Override.fromJson(json));
         }
@@ -143,7 +145,7 @@
 }
 ''');
     return waitForTasksFinished().then((_) {
-      return prepareOverrides(() {
+      return prepareOverrides().then((_) {
         assertHasOverride('m() {} // in B');
         assertNoSuperElement();
         assertHasInterfaceElement('m() {} // in A');
@@ -163,7 +165,7 @@
   m() {} // in A
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('m() {} // in A');
       assertNoSuperElement();
       assertHasInterfaceElement('m() {} // in IA');
@@ -180,7 +182,7 @@
   m() {} // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('m() {} // in B');
       assertNoSuperElement();
       assertHasInterfaceElement('m() {} // in A');
@@ -198,7 +200,7 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('m() {} // in C');
       assertNoSuperElement();
       assertHasInterfaceElement('m() {} // in A');
@@ -214,7 +216,7 @@
   int fff; // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff; // in B');
       assertHasSuperElement('fff; // in A');
       assertNoInterfaceElements();
@@ -230,7 +232,7 @@
   get fff => 0; // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff => 0; // in B');
       assertHasSuperElement('fff; // in A');
       assertNoInterfaceElements();
@@ -246,7 +248,7 @@
   fff() {} // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff() {} // in B');
       assertHasSuperElement('fff; // in A');
       assertNoInterfaceElements();
@@ -262,7 +264,7 @@
   set fff(x) {} // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff(x) {} // in B');
       assertHasSuperElement('fff; // in A');
       assertNoInterfaceElements();
@@ -279,7 +281,7 @@
   int fff; // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff; // in B');
       assertHasSuperElement('fff => 0; // in A');
       assertNoInterfaceElements();
@@ -295,7 +297,7 @@
   get fff => 0; // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff => 0; // in B');
       assertHasSuperElement('fff => 0; // in A');
       assertNoInterfaceElements();
@@ -311,7 +313,7 @@
   m() {} // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('m() {} // in B');
       assertHasSuperElement('m() {} // in A');
       assertNoInterfaceElements();
@@ -329,7 +331,7 @@
   m() {} // in C
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('m() {} // in C');
       assertHasSuperElement('m() {} // in A');
       assertNoInterfaceElements();
@@ -345,7 +347,7 @@
   set fff(x) {} // in B
 }
 ''');
-    return prepareOverrides(() {
+    return prepareOverrides().then((_) {
       assertHasOverride('fff(x) {} // in B');
       assertHasSuperElement('fff(x) {} // in A');
       assertNoInterfaceElements();
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 57a2e1d..2df3b59 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_testing/mock_sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -110,7 +111,7 @@
   AnalysisServerTestHelper({bool rethrowExceptions: true}) {
     channel = new MockServerChannel();
     server = new AnalysisServer(channel, PhysicalResourceProvider.INSTANCE,
-        new MockPackageMapProvider(), null,
+        new MockPackageMapProvider(), null, new MockSdk(),
         rethrowExceptions: rethrowExceptions);
   }
 }
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index f43b9d5..a78605c 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -9,6 +9,8 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/completion/completion_suggestion.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/index/index.dart' show Index;
 import 'package:analysis_services/index/local_memory_index.dart';
 import 'package:analysis_testing/reflective_tests.dart';
@@ -39,11 +41,19 @@
         + content.substring(completionOffset + 1));
   }
 
-  void assertHasResult(String completion) {
+  void assertHasResult(CompletionSuggestionKind kind,
+      CompletionRelevance relevance, String completion,
+      bool isDeprecated, bool isPotential) {
     var cs = suggestions.firstWhere((cs) => cs.completion == completion, orElse: () {
       var completions = suggestions.map((s) => s.completion).toList();
       fail('expected "$completion" but found\n $completions');
     });
+    expect(cs.kind, equals(kind));
+    expect(cs.relevance, equals(relevance));
+    expect(cs.selectionOffset, equals(completion.length));
+    expect(cs.selectionLength, equals(0));
+    expect(cs.isDeprecated, equals(isDeprecated));
+    expect(cs.isPotential, equals(isPotential));
   }
 
   void assertValidId(String id) {
@@ -104,8 +114,10 @@
       main() {^}
     ''');
     return getSuggestions().then((_) {
-      assertHasResult('Object');
-      assertHasResult('HtmlElement');
+      assertHasResult(CompletionSuggestionKind.CLASS,
+          CompletionRelevance.DEFAULT, 'Object', false, false);
+      assertHasResult(CompletionSuggestionKind.CLASS,
+          CompletionRelevance.DEFAULT, 'HtmlElement', false, false);
     });
   }
 }
diff --git a/pkg/analysis_server/test/computer/element_test.dart b/pkg/analysis_server/test/computer/element_test.dart
index 0ca2bfe..9dfb2c5 100644
--- a/pkg/analysis_server/test/computer/element_test.dart
+++ b/pkg/analysis_server/test/computer/element_test.dart
@@ -5,7 +5,7 @@
 library test.computer.element;
 
 import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/abstract_context.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/ast.dart';
diff --git a/pkg/analysis_server/test/computer/error_test.dart b/pkg/analysis_server/test/computer/error_test.dart
new file mode 100644
index 0000000..10848ba
--- /dev/null
+++ b/pkg/analysis_server/test/computer/error_test.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.computer.error;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/element.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
+import 'package:unittest/unittest.dart';
+
+
+
+main() {
+  groupSep = ' | ';
+  group('AnalysisError', () {
+    runReflectiveTests(AnalysisErrorTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class AnalysisErrorTest extends AbstractSingleUnitTest {
+  void test_fromEngine() {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  print(42)
+}
+''');
+    engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+    engine.AnalysisError engineError = errors.errors[0];
+    AnalysisError error =
+        new AnalysisError.fromEngine(errors.lineInfo, engineError);
+    {
+      Location location = error.location;
+      expect(location.file, testFile);
+      expect(location.offset, 19);
+      expect(location.length, 1);
+      expect(location.startLine, 2);
+      expect(location.startColumn, 11);
+    }
+    expect(error.message, "Expected to find ';'");
+    expect(error.severity, "ERROR");
+    expect(error.type, "SYNTACTIC_ERROR");
+    expect(
+        error.toString(),
+        'AnalysisError(location=Location(file=/test.dart; offset=19; '
+            'length=1; startLine=2; startColumn=11) '
+            'message=Expected to find \';\'; severity=ERROR; '
+            'type=SYNTACTIC_ERROR; correction=null');
+  }
+
+  void test_fromJson() {
+    var json = {
+      SEVERITY: 'ERROR',
+      TYPE: 'SYNTACTIC_ERROR',
+      LOCATION: {
+        FILE: '/test.dart',
+        OFFSET: 19,
+        LENGTH: 1,
+        START_LINE: 2,
+        START_COLUMN: 11
+      },
+      MESSAGE: 'Expected to find \';\''
+    };
+    AnalysisError error = AnalysisError.fromJson(json);
+    {
+      Location location = error.location;
+      expect(location.file, testFile);
+      expect(location.offset, 19);
+      expect(location.length, 1);
+      expect(location.startLine, 2);
+      expect(location.startColumn, 11);
+    }
+    expect(error.message, "Expected to find ';'");
+    expect(error.severity, "ERROR");
+    expect(error.type, "SYNTACTIC_ERROR");
+  }
+
+  void test_toJson() {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  print(42)
+}
+''');
+    engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+    engine.AnalysisError engineError = errors.errors[0];
+    AnalysisError error =
+        new AnalysisError.fromEngine(errors.lineInfo, engineError);
+    expect(error.toJson(), {
+      SEVERITY: 'ERROR',
+      TYPE: 'SYNTACTIC_ERROR',
+      LOCATION: {
+        FILE: '/test.dart',
+        OFFSET: 19,
+        LENGTH: 1,
+        START_LINE: 2,
+        START_COLUMN: 11
+      },
+      MESSAGE: 'Expected to find \';\''
+    });
+  }
+}
diff --git a/pkg/analysis_server/test/computer/test_all.dart b/pkg/analysis_server/test/computer/test_all.dart
index 2badfdf..9122f14 100644
--- a/pkg/analysis_server/test/computer/test_all.dart
+++ b/pkg/analysis_server/test/computer/test_all.dart
@@ -7,6 +7,7 @@
 import 'package:unittest/unittest.dart';
 
 import 'element_test.dart' as element_test;
+import 'error_test.dart' as error_test;
 
 
 /**
@@ -14,7 +15,8 @@
  */
 main() {
   groupSep = ' | ';
-  group('index', () {
+  group('computer', () {
     element_test.main();
+    error_test.main();
   });
 }
\ No newline at end of file
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 8b80cd7..58c04db 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -7,10 +7,11 @@
 import 'dart:async';
 
 import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/mock_sdk.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
@@ -22,16 +23,6 @@
 import 'mocks.dart';
 
 
-AnalysisError jsonToAnalysisError(Map<String, Object> json) {
-  Map<String, Object> jsonLocation = json[LOCATION];
-  Location location = new Location(jsonLocation[FILE], _getSafeInt(jsonLocation,
-      OFFSET, -1), _getSafeInt(jsonLocation, LENGTH, -1), _getSafeInt(jsonLocation,
-      START_LINE, -1), _getSafeInt(jsonLocation, START_COLUMN, -1));
-  return new AnalysisError('unknown error code', json[SEVERITY], json[TYPE], location,
-      json['message'], json['correction']);
-}
-
-
 main() {
   groupSep = ' | ';
 
@@ -46,8 +37,7 @@
     serverChannel = new MockServerChannel();
     resourceProvider = new MemoryResourceProvider();
     server = new AnalysisServer(serverChannel, resourceProvider,
-        new MockPackageMapProvider(), null);
-    server.defaultSdk = new MockSdk();
+        new MockPackageMapProvider(), null, new MockSdk());
     handler = new AnalysisDomainHandler(server);
   });
 
@@ -358,7 +348,7 @@
     if (notification.event == ANALYSIS_ERRORS) {
       String file = notification.getParameter(FILE);
       List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
-      filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
+      filesErrors[file] = errorMaps.map(AnalysisError.fromJson).toList();
     }
   }
 
@@ -420,23 +410,6 @@
   }
 }
 
-class AnalysisError {
-  final String errorCode;
-  final String severity;
-  final String type;
-  final Location location;
-  final String message;
-  final String correction;
-  AnalysisError(this.errorCode, this.severity, this.type, this.location,
-      this.message, this.correction);
-
-  @override
-  String toString() {
-    return 'AnalysisError(location=$location message=$message); '
-        'errorCode=$errorCode; severity=$separator type=$type';
-  }
-}
-
 
 /**
  * A helper to test 'analysis.*' requests.
@@ -460,8 +433,7 @@
     serverChannel = new MockServerChannel();
     resourceProvider = new MemoryResourceProvider();
     server = new AnalysisServer(serverChannel, resourceProvider,
-        new MockPackageMapProvider(), null);
-    server.defaultSdk = new MockSdk();
+        new MockPackageMapProvider(), null, new MockSdk());
     handler = new AnalysisDomainHandler(server);
     // listen for notifications
     Stream<Notification> notificationStream =
@@ -470,7 +442,7 @@
       if (notification.event == ANALYSIS_ERRORS) {
         String file = notification.getParameter(FILE);
         List<Map<String, Object>> errorMaps = notification.getParameter(ERRORS);
-        filesErrors[file] = errorMaps.map(jsonToAnalysisError).toList();
+        filesErrors[file] = errorMaps.map(AnalysisError.fromJson).toList();
       }
       if (notification.event == ANALYSIS_HIGHLIGHTS) {
         String file = notification.getParameter(FILE);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
deleted file mode 100644
index c45db47..0000000
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.domain.completion;
-
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/protocol.dart';
-import 'package:analysis_testing/mock_sdk.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:unittest/unittest.dart';
-
-import 'mocks.dart';
-
-main() {
-  groupSep = ' | ';
-
-  MockServerChannel serverChannel;
-  MemoryResourceProvider resourceProvider;
-  AnalysisServer server;
-  CompletionDomainHandler handler;
-
-  setUp(() {
-    serverChannel = new MockServerChannel();
-    resourceProvider = new MemoryResourceProvider();
-    server = new AnalysisServer(
-        serverChannel, resourceProvider, new MockPackageMapProvider(), null);
-    server.defaultSdk = new MockSdk();
-    handler = new CompletionDomainHandler(server);
-  });
-
-  group('CompletionDomainHandler', () {
-    test('getSuggestions', () {
-      var request = new Request('0', COMPLETION_GET_SUGGESTIONS);
-      request.setParameter(FILE, null);
-      request.setParameter(OFFSET, null);
-      var response = handler.handleRequest(request);
-      // TODO(brianwilkerson) implement
-      //expect(response, isNull);
-    });
-  });
-}
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 90f36e6..71088dd 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -9,6 +9,8 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_testing/mock_sdk.dart';
 import 'package:unittest/unittest.dart';
 
 import 'mocks.dart';
@@ -21,7 +23,8 @@
     var serverChannel = new MockServerChannel();
     var resourceProvider = PhysicalResourceProvider.INSTANCE;
     server = new AnalysisServer(
-        serverChannel, resourceProvider, new MockPackageMapProvider(), null);
+        serverChannel, resourceProvider, new MockPackageMapProvider(), null,
+        new MockSdk());
     handler = new ServerDomainHandler(server);
   });
 
diff --git a/pkg/analysis_server/test/domain_edit_test.dart b/pkg/analysis_server/test/edit/edit_domain_test.dart
similarity index 94%
rename from pkg/analysis_server/test/domain_edit_test.dart
rename to pkg/analysis_server/test/edit/edit_domain_test.dart
index d9dd424..6e0b421 100644
--- a/pkg/analysis_server/test/domain_edit_test.dart
+++ b/pkg/analysis_server/test/edit/edit_domain_test.dart
@@ -6,13 +6,14 @@
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/domain_edit.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/mock_sdk.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:unittest/unittest.dart';
 
-import 'mocks.dart';
+import '../mocks.dart';
 
 main() {
   groupSep = ' | ';
@@ -26,8 +27,8 @@
     serverChannel = new MockServerChannel();
     resourceProvider = new MemoryResourceProvider();
     server = new AnalysisServer(
-        serverChannel, resourceProvider, new MockPackageMapProvider(), null);
-    server.defaultSdk = new MockSdk();
+        serverChannel, resourceProvider, new MockPackageMapProvider(), null,
+        new MockSdk());
     handler = new EditDomainHandler(server);
   });
 
diff --git a/pkg/analysis_server/test/edit/fix_test.dart b/pkg/analysis_server/test/edit/fix_test.dart
new file mode 100644
index 0000000..879efcf
--- /dev/null
+++ b/pkg/analysis_server/test/edit/fix_test.dart
@@ -0,0 +1,154 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.fix;
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart' as services;
+import 'package:analysis_services/index/index.dart' hide Location;
+import 'package:analysis_services/index/local_memory_index.dart';
+import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/element.dart' as engine;
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/generated/error.dart' as engine;
+import 'package:analyzer/src/generated/utilities_dart.dart' as engine;
+import 'package:unittest/unittest.dart' hide ERROR;
+
+
+
+main() {
+  groupSep = ' | ';
+  group('ErrorFixes', () {
+    runReflectiveTests(ErrorFixesTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class ErrorFixesTest extends AbstractSingleUnitTest {
+  Index index;
+  SearchEngineImpl searchEngine;
+
+  void setUp() {
+    super.setUp();
+    index = createLocalMemoryIndex();
+    searchEngine = new SearchEngineImpl(index);
+    verifyNoTestUnitErrors = false;
+  }
+
+  void test_fromJson() {
+    var json = {
+      ERROR: {
+        SEVERITY: 'ERROR',
+        TYPE: 'SYNTACTIC_ERROR',
+        LOCATION: {
+          FILE: '/test.dart',
+          OFFSET: 19,
+          LENGTH: 1,
+          START_LINE: 2,
+          START_COLUMN: 11
+        },
+        MESSAGE: 'Expected to find \';\''
+      },
+      FIXES: [{
+          MESSAGE: 'Insert \';\'',
+          EDITS: [{
+              FILE: '/test.dart',
+              EDITS: [{
+                  OFFSET: 20,
+                  LENGTH: 0,
+                  REPLACEMENT: ';'
+                }]
+            }],
+          LINKED_POSITION_GROUPS: []
+        }]
+    };
+    ErrorFixes errorFixes = ErrorFixes.fromJson(json);
+    {
+      AnalysisError error = errorFixes.error;
+      expect(error.severity, 'ERROR');
+      expect(error.type, 'SYNTACTIC_ERROR');
+      expect(error.message, "Expected to find ';'");
+      {
+        Location location = error.location;
+        expect(location.file, testFile);
+        expect(location.offset, 19);
+        expect(location.length, 1);
+        expect(location.startLine, 2);
+        expect(location.startColumn, 11);
+      }
+    }
+    expect(errorFixes.fixes, hasLength(1));
+    {
+      Change change = errorFixes.fixes[0];
+      expect(change.message, "Insert ';'");
+      expect(change.edits, hasLength(1));
+      {
+        FileEdit fileEdit = change.edits[0];
+        expect(fileEdit.file, testFile);
+        expect(
+            fileEdit.edits.toString(),
+            "[Edit(offset=20, length=0, replacement=:>;<:)]");
+      }
+    }
+    expect(
+        errorFixes.toString(),
+        'ErrorFixes(error=AnalysisError('
+            'location=Location(file=/test.dart; offset=19; length=1; '
+            'startLine=2; startColumn=11) message=Expected to find \';\'; '
+            'severity=ERROR; type=SYNTACTIC_ERROR; correction=null, '
+            'fixes=[Change(message=Insert \';\', '
+            'edits=[FileEdit(file=/test.dart, edits=[Edit(offset=20, length=0, '
+            'replacement=:>;<:)])], linkedPositionGroups=[])])');
+  }
+
+  void test_fromService() {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+main() {
+  print(42)
+}
+''');
+    engine.AnalysisErrorInfo errors = context.getErrors(testSource);
+    engine.AnalysisError engineError = errors.errors[0];
+    List<services.Fix> servicesFixes =
+        services.computeFixes(searchEngine, testFile, testUnit, engineError);
+    AnalysisError error =
+        new AnalysisError.fromEngine(errors.lineInfo, engineError);
+    ErrorFixes fixes = new ErrorFixes(error);
+    servicesFixes.forEach((fix) => fixes.addFix(fix));
+    expect(fixes.toJson(), {
+      ERROR: {
+        SEVERITY: 'ERROR',
+        TYPE: 'SYNTACTIC_ERROR',
+        LOCATION: {
+          FILE: '/test.dart',
+          OFFSET: 19,
+          LENGTH: 1,
+          START_LINE: 2,
+          START_COLUMN: 11
+        },
+        MESSAGE: 'Expected to find \';\''
+      },
+      FIXES: [{
+          MESSAGE: 'Insert \';\'',
+          EDITS: [{
+              FILE: '/test.dart',
+              EDITS: [{
+                  OFFSET: 20,
+                  LENGTH: 0,
+                  REPLACEMENT: ';'
+                }]
+            }],
+          LINKED_POSITION_GROUPS: []
+        }]
+    });
+  }
+}
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
new file mode 100644
index 0000000..2a8a96e
--- /dev/null
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.fixes;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/computer/element.dart';
+import 'package:analysis_server/src/computer/error.dart';
+import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/edit/edit_domain.dart';
+import 'package:analysis_server/src/edit/fix.dart';
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+import '../analysis_abstract.dart';
+
+
+main() {
+  groupSep = ' | ';
+  group('getFixes', () {
+    runReflectiveTests(FixesTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class FixesTest extends AbstractAnalysisTest {
+  @override
+  void setUp() {
+    super.setUp();
+    createProject();
+    handler = new EditDomainHandler(server);
+  }
+
+  Future test_hasFixes() {
+    addTestFile('''
+main() {
+  print(42)
+}
+''');
+    return waitForTasksFinished().then((_) {
+      Request request = new Request('0', EDIT_GET_FIXES);
+      request.setParameter(FILE, testFile);
+      request.setParameter(OFFSET, findOffset('print'));
+      Response response = handleSuccessfulRequest(request);
+      List<Map<String, Object>> errorFixesJsonList = response.getResult(FIXES);
+      List<ErrorFixes> errorFixesList = errorFixesJsonList.map(ErrorFixes.fromJson).toList();
+      expect(errorFixesList, hasLength(1));
+      {
+         ErrorFixes errorFixes = errorFixesList[0];
+         {
+           AnalysisError error = errorFixes.error;
+           expect(error.severity, 'ERROR');
+           expect(error.type, 'SYNTACTIC_ERROR');
+           expect(error.message, "Expected to find ';'");
+           {
+             Location location = error.location;
+             expect(location.file, testFile);
+             expect(location.offset, 19);
+             expect(location.length, 1);
+             expect(location.startLine, 2);
+             expect(location.startColumn, 11);
+           }
+         }
+         expect(errorFixes.fixes, hasLength(1));
+         {
+           Change change = errorFixes.fixes[0];
+           expect(change.message, "Insert ';'");
+           expect(change.edits, hasLength(1));
+           {
+             FileEdit fileEdit = change.edits[0];
+             expect(fileEdit.file, testFile);
+             expect(
+                 fileEdit.edits.toString(),
+                 "[Edit(offset=20, length=0, replacement=:>;<:)]");
+           }
+         }
+      }
+    });
+  }
+}
diff --git a/pkg/analysis_server/test/edit/test_all.dart b/pkg/analysis_server/test/edit/test_all.dart
new file mode 100644
index 0000000..7c513b6
--- /dev/null
+++ b/pkg/analysis_server/test/edit/test_all.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.edit.all;
+
+import 'package:unittest/unittest.dart';
+
+import 'edit_domain_test.dart' as domain_edit_test;
+import 'fix_test.dart' as fix_test;
+
+/**
+ * Utility for manually running all tests.
+ */
+main() {
+  groupSep = ' | ';
+  group('edit', () {
+    domain_edit_test.main();
+    fix_test.main();
+  });
+}
\ No newline at end of file
diff --git a/pkg/analysis_server/test/operation/operation_analysis_test.dart b/pkg/analysis_server/test/operation/operation_analysis_test.dart
index aad7147..0619238 100644
--- a/pkg/analysis_server/test/operation/operation_analysis_test.dart
+++ b/pkg/analysis_server/test/operation/operation_analysis_test.dart
@@ -4,8 +4,8 @@
 
 library test.operation.analysis;
 
-import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/operation/operation_analysis.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/mocks.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/error.dart';
diff --git a/pkg/analysis_server/test/package_map_provider_test.dart b/pkg/analysis_server/test/package_map_provider_test.dart
index 52708c0..cec1e2c 100644
--- a/pkg/analysis_server/test/package_map_provider_test.dart
+++ b/pkg/analysis_server/test/package_map_provider_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/package_map_provider.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:unittest/unittest.dart';
 
 main() {
@@ -23,7 +24,7 @@
 
       setUp(() {
         resourceProvider = new MemoryResourceProvider();
-        packageMapProvider = new PubPackageMapProvider(resourceProvider);
+        packageMapProvider = new PubPackageMapProvider(resourceProvider, DirectoryBasedDartSdk.defaultSdk);
         projectFolder = resourceProvider.newFolder(projectPath);
       });
 
diff --git a/pkg/analysis_server/test/protocol_test.dart b/pkg/analysis_server/test/protocol_test.dart
index 8813a68..8d69c6d 100644
--- a/pkg/analysis_server/test/protocol_test.dart
+++ b/pkg/analysis_server/test/protocol_test.dart
@@ -7,9 +7,9 @@
 import 'dart:convert';
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_services/json.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
-import 'package:analysis_server/src/collections.dart';
 
 
 Matcher _throwsRequestFailure = throwsA(new isInstanceOf<RequestFailure>());
diff --git a/pkg/analysis_server/test/search/abstract_search_domain.dart b/pkg/analysis_server/test/search/abstract_search_domain.dart
index 5464311..2e33967 100644
--- a/pkg/analysis_server/test/search/abstract_search_domain.dart
+++ b/pkg/analysis_server/test/search/abstract_search_domain.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/index/index.dart' show Index;
 import 'package:analysis_services/index/local_memory_index.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index e60eab7..3d35469 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/search/member_declarations_test.dart b/pkg/analysis_server/test/search/member_declarations_test.dart
index bad6bc5..9f349a7 100644
--- a/pkg/analysis_server/test/search/member_declarations_test.dart
+++ b/pkg/analysis_server/test/search/member_declarations_test.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/search/member_references_test.dart b/pkg/analysis_server/test/search/member_references_test.dart
index c09fe13..e247ad5 100644
--- a/pkg/analysis_server/test/search/member_references_test.dart
+++ b/pkg/analysis_server/test/search/member_references_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/search/search_domain_test.dart b/pkg/analysis_server/test/search/search_domain_test.dart
index d97ccd7..c8409b8 100644
--- a/pkg/analysis_server/test/search/search_domain_test.dart
+++ b/pkg/analysis_server/test/search/search_domain_test.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/mock_sdk.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:unittest/unittest.dart';
@@ -30,8 +31,8 @@
         serverChannel,
         resourceProvider,
         new MockPackageMapProvider(),
-        null);
-    server.defaultSdk = new MockSdk();
+        null,
+        new MockSdk());
     handler = new SearchDomainHandler(server);
   });
 
diff --git a/pkg/analysis_server/test/search/search_result_test.dart b/pkg/analysis_server/test/search/search_result_test.dart
index ea2dc8c..f8100f1 100644
--- a/pkg/analysis_server/test/search/search_result_test.dart
+++ b/pkg/analysis_server/test/search/search_result_test.dart
@@ -5,8 +5,8 @@
 library test.search.search_result;
 
 import 'package:analysis_server/src/computer/element.dart';
-import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_services/search/search_engine.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/search/top_level_declarations_test.dart b/pkg/analysis_server/test/search/top_level_declarations_test.dart
index 6c1fb83..7931ae1 100644
--- a/pkg/analysis_server/test/search/top_level_declarations_test.dart
+++ b/pkg/analysis_server/test/search/top_level_declarations_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_result.dart';
+import 'package:analysis_services/constants.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 67c6c2e..4f39c6a 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/socket_server.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:unittest/unittest.dart';
 
 main() {
@@ -24,7 +25,7 @@
 
 class SocketServerTest {
   static Future createAnalysisServer_successful() {
-    SocketServer server = new SocketServer();
+    SocketServer server = new SocketServer(DirectoryBasedDartSdk.defaultSdk);
     MockServerChannel channel = new MockServerChannel();
     server.createAnalysisServer(channel);
     channel.expectMsgCount(notificationCount: 1);
@@ -40,7 +41,7 @@
   }
 
   static void createAnalysisServer_alreadyStarted() {
-    SocketServer server = new SocketServer();
+    SocketServer server = new SocketServer(DirectoryBasedDartSdk.defaultSdk);
     MockServerChannel channel1 = new MockServerChannel();
     MockServerChannel channel2 = new MockServerChannel();
     server.createAnalysisServer(channel1);
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index 6871fba..42730f9 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -4,6 +4,7 @@
 
 import 'package:unittest/unittest.dart';
 
+import 'analysis/test_all.dart' as analysis_all;
 import 'analysis_hover_test.dart' as analysis_hover_test;
 import 'analysis_notification_highlights_test.dart' as analysis_notification_highlights_test;
 import 'analysis_notification_navigation_test.dart' as analysis_notification_navigation_test;
@@ -16,9 +17,8 @@
 import 'computer/test_all.dart' as computer_test_all;
 import 'context_directory_manager_test.dart' as context_directory_manager_test;
 import 'domain_analysis_test.dart' as domain_analysis_test;
-import 'domain_completion_test.dart' as domain_completion_test;
-import 'domain_edit_test.dart' as domain_edit_test;
 import 'domain_server_test.dart' as domain_server_test;
+import 'edit/test_all.dart' as edit_all;
 import 'operation/test_all.dart' as operation_test_all;
 import 'package_map_provider_test.dart' as package_map_provider_test;
 import 'package_uri_resolver_test.dart' as package_uri_resolver_test;
@@ -32,6 +32,7 @@
 main() {
   groupSep = ' | ';
   group('analysis_server', () {
+    analysis_all.main();
     analysis_hover_test.main();
     analysis_notification_highlights_test.main();
     analysis_notification_navigation_test.main();
@@ -44,9 +45,8 @@
     computer_test_all.main();
     context_directory_manager_test.main();
     domain_analysis_test.main();
-    domain_completion_test.main();
-    domain_edit_test.main();
     domain_server_test.main();
+    edit_all.main();
     operation_test_all.main();
     package_map_provider_test.main();
     package_uri_resolver_test.main();
diff --git a/pkg/analysis_services/lib/completion/completion_suggestion.dart b/pkg/analysis_services/lib/completion/completion_suggestion.dart
new file mode 100644
index 0000000..14e9fcb
--- /dev/null
+++ b/pkg/analysis_services/lib/completion/completion_suggestion.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.suggestion;
+
+import 'package:analysis_services/json.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+/**
+ * A single completion suggestion.
+ */
+class CompletionSuggestion implements HasToJson {
+  final CompletionSuggestionKind kind;
+  final CompletionRelevance relevance;
+  final String completion;
+  final int selectionOffset;
+  final int selectionLength;
+  final bool isDeprecated;
+  final bool isPotential;
+
+  CompletionSuggestion(this.kind, this.relevance, this.completion,
+      this.selectionOffset, this.selectionLength, this.isDeprecated,
+      this.isPotential);
+
+  factory CompletionSuggestion.fromJson(Map<String, Object> json) {
+    return new CompletionSuggestion(
+        CompletionSuggestionKind.valueOf(json[KIND]),
+        CompletionRelevance.value(json[RELEVANCE]),
+        json[COMPLETION],
+        json[SELECTION_OFFSET],
+        json[SELECTION_LENGTH],
+        json[IS_DEPRECATED],
+        json[IS_POTENTIAL]);
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    return {
+      KIND: kind.name,
+      RELEVANCE: relevance.name,
+      COMPLETION: completion,
+      SELECTION_OFFSET: selectionOffset,
+      SELECTION_LENGTH: selectionLength,
+      IS_DEPRECATED: isDeprecated,
+      IS_POTENTIAL: isPotential
+    };
+  }
+}
+
+/**
+ * An enumeration of the kinds of elements that can be included
+ * in a completion suggestion.
+ */
+class CompletionSuggestionKind {
+  static const CompletionSuggestionKind CLASS =
+      const CompletionSuggestionKind('CLASS');
+  static const CompletionSuggestionKind CLASS_ALIAS =
+      const CompletionSuggestionKind('CLASS_ALIAS');
+  static const CompletionSuggestionKind CONSTRUCTOR =
+      const CompletionSuggestionKind('CONSTRUCTOR');
+  static const CompletionSuggestionKind FIELD =
+      const CompletionSuggestionKind('FIELD');
+  static const CompletionSuggestionKind FUNCTION =
+      const CompletionSuggestionKind('FUNCTION');
+  static const CompletionSuggestionKind FUNCTION_ALIAS =
+      const CompletionSuggestionKind('FUNCTION_ALIAS');
+  static const CompletionSuggestionKind GETTER =
+      const CompletionSuggestionKind('GETTER');
+  static const CompletionSuggestionKind IMPORT =
+      const CompletionSuggestionKind('IMPORT');
+  static const CompletionSuggestionKind LIBRARY_PREFIX =
+      const CompletionSuggestionKind('LIBRARY_PREFIX');
+  static const CompletionSuggestionKind METHOD =
+      const CompletionSuggestionKind('METHOD');
+  static const CompletionSuggestionKind METHOD_NAME =
+      const CompletionSuggestionKind('METHOD_NAME');
+  static const CompletionSuggestionKind PARAMETER =
+      const CompletionSuggestionKind('PARAMETER');
+  static const CompletionSuggestionKind SETTER =
+      const CompletionSuggestionKind('SETTER');
+  static const CompletionSuggestionKind VARIABLE =
+      const CompletionSuggestionKind('VARIABLE');
+  static const CompletionSuggestionKind TYPE_PARAMETER =
+      const CompletionSuggestionKind('TYPE_PARAMETER');
+  static const CompletionSuggestionKind ARGUMENT_LIST =
+      const CompletionSuggestionKind('ARGUMENT_LIST');
+  static const CompletionSuggestionKind OPTIONAL_ARGUMENT =
+      const CompletionSuggestionKind('OPTIONAL_ARGUMENT');
+  static const CompletionSuggestionKind NAMED_ARGUMENT =
+      const CompletionSuggestionKind('NAMED_ARGUMENT');
+  static const CompletionSuggestionKind TOP_LEVEL_VARIABLE =
+      const CompletionSuggestionKind('TOP_LEVEL_VARIABLE');
+
+  final String name;
+
+  const CompletionSuggestionKind(this.name);
+
+  @override
+  String toString() => name;
+
+  static CompletionSuggestionKind valueOf(String name) {
+    if (CLASS.name == name) return CLASS;
+    if (CLASS_ALIAS.name == name) return CLASS_ALIAS;
+    if (CONSTRUCTOR.name == name) return CONSTRUCTOR;
+    if (FIELD.name == name) return FIELD;
+    if (FUNCTION.name == name) return FUNCTION;
+    if (FUNCTION_ALIAS.name == name) return FUNCTION_ALIAS;
+    if (GETTER.name == name) return GETTER;
+    if (IMPORT.name == name) return IMPORT;
+    if (LIBRARY_PREFIX.name == name) return LIBRARY_PREFIX;
+    if (METHOD.name == name) return METHOD;
+    if (METHOD_NAME.name == name) return METHOD_NAME;
+    if (PARAMETER.name == name) return PARAMETER;
+    if (SETTER.name == name) return SETTER;
+    if (VARIABLE.name == name) return VARIABLE;
+    if (TYPE_PARAMETER.name == name) return TYPE_PARAMETER;
+    if (ARGUMENT_LIST.name == name) return ARGUMENT_LIST;
+    if (OPTIONAL_ARGUMENT.name == name) return OPTIONAL_ARGUMENT;
+    if (NAMED_ARGUMENT.name == name) return NAMED_ARGUMENT;
+    if (TOP_LEVEL_VARIABLE.name == name) return TOP_LEVEL_VARIABLE;
+    throw new ArgumentError('Unknown CompletionSuggestionKind: $name');
+  }
+
+  static CompletionSuggestionKind fromElementKind(ElementKind kind) {
+    //    ElementKind.ANGULAR_FORMATTER,
+    //    ElementKind.ANGULAR_COMPONENT,
+    //    ElementKind.ANGULAR_CONTROLLER,
+    //    ElementKind.ANGULAR_DIRECTIVE,
+    //    ElementKind.ANGULAR_PROPERTY,
+    //    ElementKind.ANGULAR_SCOPE_PROPERTY,
+    //    ElementKind.ANGULAR_SELECTOR,
+    //    ElementKind.ANGULAR_VIEW,
+    if (kind == ElementKind.CLASS) return CLASS;
+    //    ElementKind.COMPILATION_UNIT,
+    if (kind == ElementKind.CONSTRUCTOR) return CONSTRUCTOR;
+    //    ElementKind.DYNAMIC,
+    //    ElementKind.EMBEDDED_HTML_SCRIPT,
+    //    ElementKind.ERROR,
+    //    ElementKind.EXPORT,
+    //    ElementKind.EXTERNAL_HTML_SCRIPT,
+    if (kind == ElementKind.FIELD) return FIELD;
+    if (kind == ElementKind.FUNCTION) return FUNCTION;
+    if (kind == ElementKind.GETTER) return GETTER;
+    //    ElementKind.HTML,
+    if (kind == ElementKind.IMPORT) return IMPORT;
+    //    ElementKind.LABEL,
+    //    ElementKind.LIBRARY,
+    //    ElementKind.LOCAL_VARIABLE,
+    if (kind == ElementKind.METHOD) return METHOD;
+    //    ElementKind.METHOD,
+    //    ElementKind.NAME,
+    if (kind == ElementKind.PARAMETER) return PARAMETER;
+    //    ElementKind.POLYMER_ATTRIBUTE,
+    //    ElementKind.POLYMER_TAG_DART,
+    //    ElementKind.POLYMER_TAG_HTML,
+    //    ElementKind.PREFIX,
+    if (kind == ElementKind.SETTER) return SETTER;
+    if (kind == ElementKind.TOP_LEVEL_VARIABLE) return TOP_LEVEL_VARIABLE;
+    //    ElementKind.FUNCTION_TYPE_ALIAS,
+    //    ElementKind.TYPE_PARAMETER,
+    //    ElementKind.UNIVERSE
+    throw new ArgumentError('Unknown CompletionSuggestionKind for: $kind');
+  }
+}
+
+/**
+ * An enumeration of the relevance of a completion suggestion.
+ */
+class CompletionRelevance {
+  static const CompletionRelevance LOW = const CompletionRelevance('LOW');
+  static const CompletionRelevance DEFAULT =
+      const CompletionRelevance('DEFAULT');
+  static const CompletionRelevance HIGH = const CompletionRelevance('HIGH');
+
+  final String name;
+
+  const CompletionRelevance(this.name);
+
+  static CompletionRelevance value(String name) {
+    if (LOW.name == name) return LOW;
+    if (DEFAULT.name == name) return DEFAULT;
+    if (HIGH.name == name) return HIGH;
+    throw new ArgumentError('Unknown CompletionRelevance: $name');
+  }
+}
diff --git a/pkg/analysis_services/lib/constants.dart b/pkg/analysis_services/lib/constants.dart
new file mode 100644
index 0000000..dab2e6e
--- /dev/null
+++ b/pkg/analysis_services/lib/constants.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.constants;
+
+//
+// Property names
+//
+const String ADDED = 'added';
+const String CHILDREN = 'children';
+const String COMPLETION = 'completion';
+const String CONTAINING_LIBRARY_NAME = 'containingLibraryName';
+const String CONTAINING_LIBRARY_PATH = 'containingLibraryPath';
+const String CONTENT = 'content';
+const String CORRECTION = 'correction';
+const String DART_DOC = 'dartdoc';
+const String DEFAULT = 'default';
+const String EDITS = 'edits';
+const String ELEMENT = 'element';
+const String ELEMENT_DESCRIPTION = 'elementDescription';
+const String ELEMENT_KIND = 'elementKind';
+const String EXCLUDED = 'excluded';
+const String ERROR = 'error';
+const String ERRORS = 'errors';
+const String FILE = 'file';
+const String FILES = 'files';
+const String FIXES = 'fixes';
+const String FLAGS = 'flags';
+const String HOVERS = 'hovers';
+const String ID = 'id';
+const String INCLUDE_POTENTIAL = 'includePotential';
+const String INCLUDED = 'included';
+const String INTERFACE_ELEMENTS = 'interfaceElements';
+const String IS_ABSTRACT = 'isAbstract';
+const String IS_DEPRECATED = 'isDeprecated';
+const String IS_POTENTIAL = 'isPotential';
+const String IS_STATIC = 'isStatic';
+const String KIND = 'kind';
+const String LAST = 'last';
+const String LENGTH = 'length';
+const String LINKED_POSITION_GROUPS = 'linkedPositionGroups';
+const String LOCATION = 'location';
+const String MESSAGE = 'message';
+const String NAME = 'name';
+const String NEW_LENGTH = 'newLength';
+const String OCCURRENCES = 'occurrences';
+const String OFFSET = 'offset';
+const String OFFSETS = 'offsets';
+const String OLD_LENGTH = 'oldLength';
+const String OPTIONS = 'options';
+const String OUTLINE = 'outline';
+const String OVERRIDES = 'overrides';
+const String PARAMETER = 'parameter';
+const String PARAMETERS = 'parameters';
+const String PATH = 'path';
+const String PATTERN = 'pattern';
+const String POSITIONS = 'positions';
+const String PROPAGATED_TYPE = 'propagatedType';
+const String REFACTORINGS = 'refactorings';
+const String REGIONS = 'regions';
+const String RELEVANCE = 'relevance';
+const String REMOVED = 'removed';
+const String REPLACEMENT = 'relacement';
+const String RETURN_TYPE = 'returnType';
+const String RESULTS = 'results';
+const String SEVERITY = 'severity';
+const String SELECTION_LENGTH = 'selectionLength';
+const String SELECTION_OFFSET = 'selectionOffset';
+const String START_COLUMN = 'startColumn';
+const String START_LINE = 'startLine';
+const String STATIC_TYPE = 'staticType';
+const String SUBSCRIPTIONS = 'subscriptions';
+const String SUPER_CLASS_ELEMENT = 'superclassElement';
+const String TARGETS = 'targets';
+const String TYPE = 'type';
+const String VERSION = 'version';
diff --git a/pkg/analysis_services/lib/correction/change.dart b/pkg/analysis_services/lib/correction/change.dart
index aead362..a352855 100644
--- a/pkg/analysis_services/lib/correction/change.dart
+++ b/pkg/analysis_services/lib/correction/change.dart
@@ -7,13 +7,20 @@
 
 library services.correction.change;
 
-import 'package:analyzer/src/generated/source.dart';
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/json.dart';
+
+
+_fromJsonList(List target, List<Map<String, Object>> jsonList,
+    decoder(Map<String, Object> json)) {
+  target.addAll(jsonList.map(decoder));
+}
 
 
 /**
  * A description of a single change to one or more files. 
  */
-class Change {
+class Change implements HasToJson {
   /**
    * A textual description of the change to be applied. 
    */
@@ -24,24 +31,59 @@
    */
   final List<FileEdit> edits = <FileEdit>[];
 
+  /**
+   * A list of the [LinkedPositionGroup]s in the change. 
+   */
+  final List<LinkedPositionGroup> linkedPositionGroups = <LinkedPositionGroup>[
+      ];
+
   Change(this.message);
 
   /**
-   * Adds the given [FileEdit] to the list.
+   * Adds the given [FileEdit].
    */
   void add(FileEdit edit) {
     edits.add(edit);
   }
 
+  /**
+   * Adds the given [LinkedPositionGroup].
+   */
+  void addLinkedPositionGroup(LinkedPositionGroup linkedPositionGroup) {
+    linkedPositionGroups.add(linkedPositionGroup);
+  }
+
   @override
-  String toString() => "Change(message=$message, edits=${edits.join(' ')})";
+  Map<String, Object> toJson() {
+    return {
+      MESSAGE: message,
+      EDITS: objectToJson(edits),
+      LINKED_POSITION_GROUPS: objectToJson(linkedPositionGroups)
+    };
+  }
+
+  @override
+  String toString() =>
+      'Change(message=$message, edits=$edits, '
+          'linkedPositionGroups=$linkedPositionGroups)';
+
+  static Change fromJson(Map<String, Object> json) {
+    String message = json[MESSAGE];
+    Change change = new Change(message);
+    _fromJsonList(change.edits, json[EDITS], FileEdit.fromJson);
+    _fromJsonList(
+        change.linkedPositionGroups,
+        json[LINKED_POSITION_GROUPS],
+        LinkedPositionGroup.fromJson);
+    return change;
+  }
 }
 
 
 /**
  * A description of a single change to a single file. 
  */
-class Edit {
+class Edit implements HasToJson {
   /**
    * The offset of the region to be modified. 
    */
@@ -59,26 +101,46 @@
 
   Edit(this.offset, this.length, this.replacement);
 
-  Edit.range(SourceRange range, String replacement) : this(
-      range.offset,
-      range.length,
-      replacement);
-
   /**
    * The offset of a character immediately after the region to be modified. 
    */
   int get end => offset + length;
 
+  bool operator ==(other) {
+    if (other is Edit) {
+      return other.offset == offset &&
+          other.length == length &&
+          other.replacement == replacement;
+    }
+    return false;
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    return {
+      OFFSET: offset,
+      LENGTH: length,
+      REPLACEMENT: replacement
+    };
+  }
+
   @override
   String toString() =>
-      "(offset=$offset, length=$length, replacement=:>$replacement<:)";
+      "Edit(offset=$offset, length=$length, replacement=:>$replacement<:)";
+
+  static Edit fromJson(Map<String, Object> json) {
+    int offset = json[OFFSET];
+    int length = json[LENGTH];
+    String replacement = json[REPLACEMENT];
+    return new Edit(offset, length, replacement);
+  }
 }
 
 
 /**
  * A description of a set of changes to a single file. 
  */
-class FileEdit {
+class FileEdit implements HasToJson {
   /**
    * The file to be modified.
    */
@@ -99,5 +161,107 @@
   }
 
   @override
-  String toString() => "FileEdit(file=$file, edits=${edits.join(' ')})";
+  Map<String, Object> toJson() {
+    return {
+      FILE: file,
+      EDITS: objectToJson(edits)
+    };
+  }
+
+  @override
+  String toString() => "FileEdit(file=$file, edits=$edits)";
+
+  static FileEdit fromJson(Map<String, Object> json) {
+    String file = json[FILE];
+    FileEdit fileEdit = new FileEdit(file);
+    _fromJsonList(fileEdit.edits, json[EDITS], Edit.fromJson);
+    return fileEdit;
+  }
+}
+
+
+/**
+ * A group of linked [Position]s in multiple files that are simultaneously
+ * modified - if one gets edited, all other positions in a group are edited the
+ * same way. All linked positions in a group have the same content.
+ */
+class LinkedPositionGroup implements HasToJson {
+  final String id;
+  final List<Position> positions = <Position>[];
+
+  LinkedPositionGroup(this.id);
+
+  void add(Position position) {
+    if (positions.isNotEmpty && position.length != positions[0].length) {
+      throw new ArgumentError(
+          'All positions should have the same length. '
+              'Was: ${positions[0].length}. New: ${position.length}');
+    }
+    positions.add(position);
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    return {
+      ID: id,
+      POSITIONS: objectToJson(positions)
+    };
+  }
+
+  @override
+  String toString() => 'LinkedPositionGroup(id=$id, positions=$positions)';
+
+  static LinkedPositionGroup fromJson(Map<String, Object> json) {
+    String id = json[ID];
+    LinkedPositionGroup group = new LinkedPositionGroup(id);
+    _fromJsonList(group.positions, json[POSITIONS], Position.fromJson);
+    return group;
+  }
+}
+
+
+/**
+ * A position in a file.
+ */
+class Position implements HasToJson {
+  final String file;
+  final int offset;
+  final int length;
+
+  Position(this.file, this.offset, this.length);
+
+  int get hashCode {
+    int hash = file.hashCode;
+    hash = hash * 31 + offset;
+    hash = hash * 31 + length;
+    return hash;
+  }
+
+  bool operator ==(other) {
+    if (other is Position) {
+      return other.file == file &&
+          other.offset == offset &&
+          other.length == length;
+    }
+    return false;
+  }
+
+  @override
+  Map<String, Object> toJson() {
+    return {
+      FILE: file,
+      OFFSET: offset,
+      LENGTH: length
+    };
+  }
+
+  @override
+  String toString() => 'Position(file=$file, offset=$offset, length=$length)';
+
+  static Position fromJson(Map<String, Object> json) {
+    String file = json[FILE];
+    int offset = json[OFFSET];
+    int length = json[LENGTH];
+    return new Position(file, offset, length);
+  }
 }
diff --git a/pkg/analysis_services/lib/correction/fix.dart b/pkg/analysis_services/lib/correction/fix.dart
index 7ff90d2..f165213 100644
--- a/pkg/analysis_services/lib/correction/fix.dart
+++ b/pkg/analysis_services/lib/correction/fix.dart
@@ -5,12 +5,10 @@
 library services.correction.fix;
 
 import 'package:analysis_services/correction/change.dart';
-import 'package:analysis_services/correction/source_range_factory.dart' as rf;
 import 'package:analysis_services/search/search_engine.dart';
+import 'package:analysis_services/src/correction/fix.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/source.dart';
 
 
 /**
@@ -20,7 +18,7 @@
  */
 List<Fix> computeFixes(SearchEngine searchEngine, String file,
     CompilationUnit unit, AnalysisError error) {
-  var processor = new _FixProcessor(searchEngine, file, unit, error);
+  var processor = new FixProcessor(searchEngine, file, unit, error);
   return processor.compute();
 }
 
@@ -46,145 +44,84 @@
  */
 class FixKind {
   static const ADD_PACKAGE_DEPENDENCY =
-      const FixKind(
-          'QF_ADD_PACKAGE_DEPENDENCY',
-          50,
-          "Add dependency on package '%s'");
+      const FixKind('ADD_PACKAGE_DEPENDENCY', 50, "Add dependency on package '%s'");
   static const ADD_SUPER_CONSTRUCTOR_INVOCATION =
       const FixKind(
-          'QF_ADD_SUPER_CONSTRUCTOR_INVOCATION',
+          'ADD_SUPER_CONSTRUCTOR_INVOCATION',
           50,
           "Add super constructor %s invocation");
-  static const CHANGE_TO = const FixKind('QF_CHANGE_TO', 51, "Change to '%s'");
+  static const CHANGE_TO = const FixKind('CHANGE_TO', 51, "Change to '%s'");
   static const CHANGE_TO_STATIC_ACCESS =
       const FixKind(
-          'QF_CHANGE_TO_STATIC_ACCESS',
+          'CHANGE_TO_STATIC_ACCESS',
           50,
           "Change access to static using '%s'");
   static const CREATE_CLASS =
-      const FixKind('QF_CREATE_CLASS', 50, "Create class '%s'");
+      const FixKind('CREATE_CLASS', 50, "Create class '%s'");
   static const CREATE_CONSTRUCTOR =
-      const FixKind('QF_CREATE_CONSTRUCTOR', 50, "Create constructor '%s'");
+      const FixKind('CREATE_CONSTRUCTOR', 50, "Create constructor '%s'");
   static const CREATE_CONSTRUCTOR_SUPER =
-      const FixKind(
-          'QF_CREATE_CONSTRUCTOR_SUPER',
-          50,
-          "Create constructor to call %s");
+      const FixKind('CREATE_CONSTRUCTOR_SUPER', 50, "Create constructor to call %s");
   static const CREATE_FUNCTION =
-      const FixKind('QF_CREATE_FUNCTION', 49, "Create function '%s'");
+      const FixKind('CREATE_FUNCTION', 49, "Create function '%s'");
   static const CREATE_METHOD =
-      const FixKind('QF_CREATE_METHOD', 50, "Create method '%s'");
+      const FixKind('CREATE_METHOD', 50, "Create method '%s'");
   static const CREATE_MISSING_OVERRIDES =
-      const FixKind(
-          'QF_CREATE_MISSING_OVERRIDES',
-          50,
-          "Create %d missing override(s)");
+      const FixKind('CREATE_MISSING_OVERRIDES', 50, "Create %d missing override(s)");
   static const CREATE_NO_SUCH_METHOD =
-      const FixKind('QF_CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
+      const FixKind('CREATE_NO_SUCH_METHOD', 49, "Create 'noSuchMethod' method");
   static const CREATE_PART =
-      const FixKind('QF_CREATE_PART', 50, "Create part '%s'");
+      const FixKind('CREATE_PART', 50, "Create part '%s'");
   static const IMPORT_LIBRARY_PREFIX =
       const FixKind(
-          'QF_IMPORT_LIBRARY_PREFIX',
+          'IMPORT_LIBRARY_PREFIX',
           51,
           "Use imported library '%s' with prefix '%s'");
   static const IMPORT_LIBRARY_PROJECT =
-      const FixKind('QF_IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'");
+      const FixKind('IMPORT_LIBRARY_PROJECT', 51, "Import library '%s'");
   static const IMPORT_LIBRARY_SDK =
-      const FixKind('QF_IMPORT_LIBRARY_SDK', 51, "Import library '%s'");
+      const FixKind('IMPORT_LIBRARY_SDK', 51, "Import library '%s'");
   static const IMPORT_LIBRARY_SHOW =
-      const FixKind('QF_IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import");
+      const FixKind('IMPORT_LIBRARY_SHOW', 51, "Update library '%s' import");
   static const INSERT_SEMICOLON =
-      const FixKind('QF_INSERT_SEMICOLON', 50, "Insert ';'");
+      const FixKind('INSERT_SEMICOLON', 50, "Insert ';'");
   static const MAKE_CLASS_ABSTRACT =
-      const FixKind('QF_MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract");
+      const FixKind('MAKE_CLASS_ABSTRACT', 50, "Make class '%s' abstract");
   static const REMOVE_PARAMETERS_IN_GETTER_DECLARATION =
       const FixKind(
-          'QF_REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
+          'REMOVE_PARAMETERS_IN_GETTER_DECLARATION',
           50,
           "Remove parameters in getter declaration");
   static const REMOVE_PARENTHESIS_IN_GETTER_INVOCATION =
       const FixKind(
-          'QF_REMOVE_PARENTHESIS_IN_GETTER_INVOCATION',
+          'REMOVE_PARENTHESIS_IN_GETTER_INVOCATION',
           50,
           "Remove parentheses in getter invocation");
   static const REMOVE_UNNECASSARY_CAST =
-      const FixKind('QF_REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast");
+      const FixKind('REMOVE_UNNECASSARY_CAST', 50, "Remove unnecessary cast");
   static const REMOVE_UNUSED_IMPORT =
-      const FixKind('QF_REMOVE_UNUSED_IMPORT', 50, "Remove unused import");
+      const FixKind('REMOVE_UNUSED_IMPORT', 50, "Remove unused import");
   static const REPLACE_BOOLEAN_WITH_BOOL =
-      const FixKind(
-          'QF_REPLACE_BOOLEAN_WITH_BOOL',
-          50,
-          "Replace 'boolean' with 'bool'");
-  static const USE_CONST =
-      const FixKind('QF_USE_CONST', 50, "Change to constant");
+      const FixKind('REPLACE_BOOLEAN_WITH_BOOL', 50, "Replace 'boolean' with 'bool'");
+  static const USE_CONST = const FixKind('USE_CONST', 50, "Change to constant");
   static const USE_EFFECTIVE_INTEGER_DIVISION =
       const FixKind(
-          'QF_USE_EFFECTIVE_INTEGER_DIVISION',
+          'USE_EFFECTIVE_INTEGER_DIVISION',
           50,
           "Use effective integer division ~/");
   static const USE_EQ_EQ_NULL =
-      const FixKind('QF_USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'");
+      const FixKind('USE_EQ_EQ_NULL', 50, "Use == null instead of 'is Null'");
   static const USE_NOT_EQ_NULL =
-      const FixKind('QF_USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
+      const FixKind('USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
 
   final name;
   final int relevance;
   final String message;
 
   const FixKind(this.name, this.relevance, this.message);
-}
 
-
-/**
- * The computer for Dart fixes.
- */
-class _FixProcessor {
-  final SearchEngine searchEngine;
-  final String file;
-  final CompilationUnit unit;
-  final AnalysisError error;
-
-  final List<Fix> fixes = <Fix>[];
-  final List<Edit> edits = <Edit>[];
-
-
-  _FixProcessor(this.searchEngine, this.file, this.unit, this.error);
-
-  List<Fix> compute() {
-    ErrorCode errorCode = error.errorCode;
-    if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
-      _addFix_boolInsteadOfBoolean();
-    }
-    return fixes;
-  }
-
-  void _addFix(FixKind kind, List args) {
-    FileEdit fileEdit = new FileEdit(file);
-    edits.forEach((edit) => fileEdit.add(edit));
-    // prepare Change
-    String message = JavaString.format(kind.message, args);
-    Change change = new Change(message);
-    change.add(fileEdit);
-    // add Fix
-    var fix = new Fix(kind, change);
-    fixes.add(fix);
-  }
-
-  void _addFix_boolInsteadOfBoolean() {
-    SourceRange range = rf.rangeError(error);
-    _addReplaceEdit(range, "bool");
-    _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []);
-  }
-
-  /**
-   * Adds a new [Edit] to [edits].
-   */
-  void _addReplaceEdit(SourceRange range, String text) {
-    Edit edit = new Edit.range(range, text);
-    edits.add(edit);
-  }
+  @override
+  String toString() => name;
 }
 
 
diff --git a/pkg/analysis_services/lib/json.dart b/pkg/analysis_services/lib/json.dart
new file mode 100644
index 0000000..1727d5e
--- /dev/null
+++ b/pkg/analysis_services/lib/json.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.json;
+
+/**
+ * Instances of the class [HasToJson] implement [toJson] method that returns
+ * a JSON presentation.
+ */
+abstract class HasToJson {
+  /**
+   * Returns a JSON presentation of the object.
+   */
+  Map<String, Object> toJson();
+}
+
+
+/**
+ * Returns a JSON presention of [value].
+ */
+objectToJson(Object value) {
+  if (value is HasToJson) {
+    return value.toJson();
+  }
+  if (value is Iterable) {
+    return value.map((item) => objectToJson(item)).toList();
+  }
+  return value;
+}
diff --git a/pkg/analysis_services/lib/src/correction/fix.dart b/pkg/analysis_services/lib/src/correction/fix.dart
new file mode 100644
index 0000000..fe24a14
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/fix.dart
@@ -0,0 +1,1738 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.fix;
+
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_services/correction/fix.dart';
+import 'package:analysis_services/search/search_engine.dart';
+import 'package:analysis_services/src/correction/name_suggestion.dart';
+import 'package:analysis_services/src/correction/source_buffer.dart';
+import 'package:analysis_services/src/correction/source_range.dart' as rf;
+import 'package:analysis_services/src/correction/util.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+
+/**
+ * The computer for Dart fixes.
+ */
+class FixProcessor {
+  final SearchEngine searchEngine;
+  final String file;
+  final CompilationUnit unit;
+  final AnalysisError error;
+
+  final List<Edit> edits = <Edit>[];
+  final Map<String, LinkedPositionGroup> linkedPositionGroups = <String,
+      LinkedPositionGroup>{};
+  final List<Fix> fixes = <Fix>[];
+
+  CorrectionUtils utils;
+  int errorOffset;
+  int errorLength;
+  int errorEnd;
+  AstNode node;
+  AstNode coveredNode;
+
+
+  FixProcessor(this.searchEngine, this.file, this.unit, this.error);
+
+  List<Fix> compute() {
+    utils = new CorrectionUtils(unit);
+    errorOffset = error.offset;
+    errorLength = error.length;
+    errorEnd = errorOffset + errorLength;
+    node = new NodeLocator.con1(errorOffset).searchWithin(unit);
+    coveredNode = new NodeLocator.con2(
+        errorOffset,
+        errorOffset + errorLength).searchWithin(unit);
+    // analyze ErrorCode
+    ErrorCode errorCode = error.errorCode;
+    if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
+      _addFix_boolInsteadOfBoolean();
+    }
+    if (errorCode ==
+        CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE) {
+      _addFix_replaceWithConstInstanceCreation();
+    }
+    if (errorCode ==
+        CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT) {
+      _addFix_createConstructorSuperExplicit();
+    }
+//    if (identical(
+//        errorCode,
+//        CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_IMPLICIT)) {
+//      _addFix_createConstructorSuperImplicit();
+//    }
+    if (errorCode ==
+        CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT) {
+      _addFix_createConstructorSuperExplicit();
+    }
+//    if (identical(errorCode, CompileTimeErrorCode.URI_DOES_NOT_EXIST)) {
+//      _addFix_createPart();
+//      _addFix_addPackageDependency();
+//    }
+    if (errorCode == HintCode.DIVISION_OPTIMIZATION) {
+      _addFix_useEffectiveIntegerDivision();
+    }
+    if (errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL) {
+      _addFix_isNotNull();
+    }
+    if (errorCode == HintCode.TYPE_CHECK_IS_NULL) {
+      _addFix_isNull();
+    }
+    if (errorCode == HintCode.UNNECESSARY_CAST) {
+      _addFix_removeUnnecessaryCast();
+    }
+    if (errorCode == HintCode.UNUSED_IMPORT) {
+      _addFix_removeUnusedImport();
+    }
+    if (errorCode == ParserErrorCode.EXPECTED_TOKEN) {
+      _addFix_insertSemicolon();
+    }
+    if (errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS) {
+      _addFix_removeParameters_inGetterDeclaration();
+    }
+    if (errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER) {
+      _addFix_makeEnclosingClassAbstract();
+    }
+    if (errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) {
+      _addFix_createConstructor_insteadOfSyntheticDefault();
+    }
+    if (errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR) {
+      _addFix_createConstructor_named();
+    }
+    if (errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+        errorCode ==
+            StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
+        errorCode ==
+            StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
+        errorCode ==
+            StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
+        errorCode ==
+            StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS) {
+      // make class abstract
+      _addFix_makeEnclosingClassAbstract();
+      // implement methods
+      AnalysisErrorWithProperties errorWithProperties =
+          error as AnalysisErrorWithProperties;
+      Object property =
+          errorWithProperties.getProperty(ErrorProperty.UNIMPLEMENTED_METHODS);
+      List<ExecutableElement> missingOverrides =
+          property as List<ExecutableElement>;
+      _addFix_createMissingOverrides(missingOverrides);
+      _addFix_createNoSuchMethod();
+    }
+    if (errorCode == StaticWarningCode.UNDEFINED_CLASS) {
+      _addFix_importLibrary_withType();
+      _addFix_createClass();
+      _addFix_undefinedClass_useSimilar();
+    }
+//    if (identical(errorCode, StaticWarningCode.UNDEFINED_IDENTIFIER)) {
+//      _addFix_createFunction_forFunctionType();
+//      _addFix_importLibrary_withType();
+//      _addFix_importLibrary_withTopLevelVariable();
+//    }
+    if (errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER) {
+      _addFix_useStaticAccess_method();
+      _addFix_useStaticAccess_property();
+    }
+    if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
+      _addFix_removeParentheses_inGetterInvocation();
+    }
+//    if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_FUNCTION)) {
+//      _addFix_importLibrary_withFunction();
+//      _addFix_undefinedFunction_useSimilar();
+//      _addFix_undefinedFunction_create();
+//    }
+//    if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_GETTER)) {
+//      _addFix_createFunction_forFunctionType();
+//    }
+//    if (identical(errorCode, HintCode.UNDEFINED_METHOD) ||
+//        identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
+//      _addFix_undefinedMethod_useSimilar();
+//      _addFix_undefinedMethod_create();
+//      _addFix_undefinedFunction_create();
+//    }
+    // done
+    return fixes;
+  }
+
+  void _addFix(FixKind kind, List args, {String fixFile}) {
+    if (fixFile == null) {
+      fixFile = file;
+    }
+    FileEdit fileEdit = new FileEdit(file);
+    edits.forEach((edit) => fileEdit.add(edit));
+    // prepare Change
+    String message = JavaString.format(kind.message, args);
+    Change change = new Change(message);
+    change.add(fileEdit);
+    linkedPositionGroups.values.forEach(
+        (group) => change.addLinkedPositionGroup(group));
+    // add Fix
+    Fix fix = new Fix(kind, change);
+    fixes.add(fix);
+  }
+
+  void _addFix_addPackageDependency() {
+    // TODO(scheglov) implement
+//    if (node is SimpleStringLiteral && node.parent is NamespaceDirective) {
+//      SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
+//      String uriString = uriLiteral.value;
+//      // we need package: import
+//      if (!uriString.startsWith("package:")) {
+//        return;
+//      }
+//      // prepare package name
+//      String packageName = StringUtils.removeStart(uriString, "package:");
+//      packageName = StringUtils.substringBefore(packageName, "/");
+//      // add proposal
+//      _proposals.add(
+//          new AddDependencyCorrectionProposal(
+//              _unitFile,
+//              packageName,
+//              FixKind.ADD_PACKAGE_DEPENDENCY,
+//              [packageName]));
+//    }
+  }
+
+  void _addFix_boolInsteadOfBoolean() {
+    SourceRange range = rf.rangeError(error);
+    _addReplaceEdit(range, "bool");
+    _addFix(FixKind.REPLACE_BOOLEAN_WITH_BOOL, []);
+  }
+
+
+  void _addFix_createClass() {
+    if (_mayBeTypeIdentifier(node)) {
+      String name = (node as SimpleIdentifier).name;
+      // prepare environment
+      String eol = utils.endOfLine;
+      CompilationUnitMember enclosingMember =
+          node.getAncestor((node) => node is CompilationUnitMember);
+      int offset = enclosingMember.end;
+      String prefix = "";
+      // prepare source
+      SourceBuilder sb = new SourceBuilder(file, offset);
+      {
+        sb.append("${eol}${eol}");
+        sb.append(prefix);
+        // "class"
+        sb.append("class ");
+        // append name
+        {
+          sb.startPosition("NAME");
+          sb.append(name);
+          sb.endPosition();
+        }
+        // no members
+        sb.append(" {");
+        sb.append(eol);
+        sb.append("}");
+      }
+      // insert source
+      _insertBuilder(sb);
+      _addLinkedPosition("NAME", rf.rangeNode(node));
+      // add proposal
+      _addFix(FixKind.CREATE_CLASS, [name]);
+    }
+  }
+
+
+  void _addFix_createConstructorSuperExplicit() {
+    ConstructorDeclaration targetConstructor =
+        node.parent as ConstructorDeclaration;
+    ClassDeclaration targetClassNode =
+        targetConstructor.parent as ClassDeclaration;
+    ClassElement targetClassElement = targetClassNode.element;
+    ClassElement superClassElement = targetClassElement.supertype.element;
+    // add proposals for all super constructors
+    List<ConstructorElement> superConstructors = superClassElement.constructors;
+    for (ConstructorElement superConstructor in superConstructors) {
+      String constructorName = superConstructor.name;
+      // skip private
+      if (Identifier.isPrivateName(constructorName)) {
+        continue;
+      }
+      // prepare SourceBuilder
+      SourceBuilder sb;
+      {
+        List<ConstructorInitializer> initializers =
+            targetConstructor.initializers;
+        if (initializers.isEmpty) {
+          int insertOffset = targetConstructor.parameters.end;
+          sb = new SourceBuilder(file, insertOffset);
+          sb.append(" : ");
+        } else {
+          ConstructorInitializer lastInitializer =
+              initializers[initializers.length - 1];
+          int insertOffset = lastInitializer.end;
+          sb = new SourceBuilder(file, insertOffset);
+          sb.append(", ");
+        }
+      }
+      // add super constructor name
+      sb.append("super");
+      if (!StringUtils.isEmpty(constructorName)) {
+        sb.append(".");
+        sb.append(constructorName);
+      }
+      // add arguments
+      sb.append("(");
+      bool firstParameter = true;
+      for (ParameterElement parameter in superConstructor.parameters) {
+        // skip non-required parameters
+        if (parameter.parameterKind != ParameterKind.REQUIRED) {
+          break;
+        }
+        // comma
+        if (firstParameter) {
+          firstParameter = false;
+        } else {
+          sb.append(", ");
+        }
+        // default value
+        DartType parameterType = parameter.type;
+        sb.startPosition(parameter.name);
+        sb.append(getDefaultValueCode(parameterType));
+        sb.endPosition();
+      }
+      sb.append(")");
+      // insert proposal
+      _insertBuilder(sb);
+      // add proposal
+      String proposalName = _getConstructorProposalName(superConstructor);
+      _addFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, [proposalName]);
+    }
+  }
+
+  void _addFix_createConstructorSuperImplicit() {
+    // TODO(scheglov) implement
+//    ClassDeclaration targetClassNode = node.parent as ClassDeclaration;
+//    ClassElement targetClassElement = targetClassNode.element;
+//    ClassElement superClassElement = targetClassElement.supertype.element;
+//    String targetClassName = targetClassElement.name;
+//    // add proposals for all super constructors
+//    List<ConstructorElement> superConstructors = superClassElement.constructors;
+//    for (ConstructorElement superConstructor in superConstructors) {
+//      String constructorName = superConstructor.name;
+//      // skip private
+//      if (Identifier.isPrivateName(constructorName)) {
+//        continue;
+//      }
+//      // prepare parameters and arguments
+//      JavaStringBuilder parametersBuffer = new JavaStringBuilder();
+//      JavaStringBuilder argumentsBuffer = new JavaStringBuilder();
+//      bool firstParameter = true;
+//      for (ParameterElement parameter in superConstructor.parameters) {
+//        // skip non-required parameters
+//        if (parameter.parameterKind != ParameterKind.REQUIRED) {
+//          break;
+//        }
+//        // comma
+//        if (firstParameter) {
+//          firstParameter = false;
+//        } else {
+//          parametersBuffer.append(", ");
+//          argumentsBuffer.append(", ");
+//        }
+//        // name
+//        String parameterName = parameter.displayName;
+//        if (parameterName.length > 1 && parameterName.startsWith("_")) {
+//          parameterName = parameterName.substring(1);
+//        }
+//        // parameter & argument
+//        _appendParameterSource(parametersBuffer, parameter.type, parameterName);
+//        argumentsBuffer.append(parameterName);
+//      }
+//      // add proposal
+//      String eol = utils.endOfLine;
+//      QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+//          _prepareNewConstructorLocation(targetClassNode, eol);
+//      SourceBuilder sb = new SourceBuilder.con1(targetLocation._offset);
+//      {
+//        String indent = utils.getIndent(1);
+//        sb.append(targetLocation._prefix);
+//        sb.append(indent);
+//        sb.append(targetClassName);
+//        if (!constructorName.isEmpty) {
+//          sb.startPosition("NAME");
+//          sb.append(".");
+//          sb.append(constructorName);
+//          sb.endPosition();
+//        }
+//        sb.append("(");
+//        sb.append(parametersBuffer.toString());
+//        sb.append(") : super");
+//        if (!constructorName.isEmpty) {
+//          sb.append(".");
+//          sb.append(constructorName);
+//        }
+//        sb.append("(");
+//        sb.append(argumentsBuffer.toString());
+//        sb.append(");");
+//        sb.append(targetLocation._suffix);
+//      }
+//      _addInsertEdit3(sb);
+//      // add proposal
+//      String proposalName = _getConstructorProposalName(superConstructor);
+//      _addFix(
+//          FixKind.CREATE_CONSTRUCTOR_SUPER,
+//          [proposalName]);
+//    }
+  }
+
+  void _addFix_createConstructor_insteadOfSyntheticDefault() {
+    TypeName typeName = null;
+    ConstructorName constructorName = null;
+    InstanceCreationExpression instanceCreation = null;
+    if (node is SimpleIdentifier) {
+      if (node.parent is TypeName) {
+        typeName = node.parent as TypeName;
+        if (typeName.name == node && typeName.parent is ConstructorName) {
+          constructorName = typeName.parent as ConstructorName;
+          // should be synthetic default constructor
+          {
+            ConstructorElement constructorElement =
+                constructorName.staticElement;
+            if (constructorElement == null ||
+                !constructorElement.isDefaultConstructor ||
+                !constructorElement.isSynthetic) {
+              return;
+            }
+          }
+          // prepare InstanceCreationExpression
+          if (constructorName.parent is InstanceCreationExpression) {
+            instanceCreation = constructorName.parent as
+                InstanceCreationExpression;
+            if (instanceCreation.constructorName != constructorName) {
+              return;
+            }
+          }
+        }
+      }
+    }
+    // do we have enough information?
+    if (instanceCreation == null) {
+      return;
+    }
+    // prepare environment
+    String eol = utils.endOfLine;
+    // prepare target
+    DartType targetType = typeName.type;
+    if (targetType is! InterfaceType) {
+      return;
+    }
+    ClassElement targetElement = targetType.element as ClassElement;
+    String targetFile = targetElement.source.fullName;
+    ClassDeclaration targetClass = targetElement.node;
+    QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+        _prepareNewConstructorLocation(targetClass, eol);
+    // build method source
+    SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
+    {
+      String indent = "  ";
+      sb.append(targetLocation._prefix);
+      sb.append(indent);
+      sb.append(targetElement.name);
+      _addFix_undefinedMethod_create_parameters(
+          sb,
+          instanceCreation.argumentList);
+      sb.append(") {${eol}${indent}}");
+      sb.append(targetLocation._suffix);
+    }
+    // insert source
+    _insertBuilder(sb);
+    // add proposal
+    _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
+  }
+
+  void _addFix_createConstructor_named() {
+    SimpleIdentifier name = null;
+    ConstructorName constructorName = null;
+    InstanceCreationExpression instanceCreation = null;
+    if (node is SimpleIdentifier) {
+      // name
+      name = node as SimpleIdentifier;
+      if (name.parent is ConstructorName) {
+        constructorName = name.parent as ConstructorName;
+        if (constructorName.name == name) {
+          // Type.name
+          if (constructorName.parent is InstanceCreationExpression) {
+            instanceCreation = constructorName.parent as
+                InstanceCreationExpression;
+            // new Type.name()
+            if (instanceCreation.constructorName != constructorName) {
+              return;
+            }
+          }
+        }
+      }
+    }
+    // do we have enough information?
+    if (instanceCreation == null) {
+      return;
+    }
+    // prepare environment
+    String eol = utils.endOfLine;
+    // prepare target interface type
+    DartType targetType = constructorName.type.type;
+    if (targetType is! InterfaceType) {
+      return;
+    }
+    ClassElement targetElement = targetType.element as ClassElement;
+    String targetFile = targetElement.source.fullName;
+    ClassDeclaration targetClass = targetElement.node;
+    QuickFixProcessorImpl_NewConstructorLocation targetLocation =
+        _prepareNewConstructorLocation(targetClass, eol);
+    // build method source
+    SourceBuilder sb = new SourceBuilder(targetFile, targetLocation._offset);
+    {
+      String indent = "  ";
+      sb.append(targetLocation._prefix);
+      sb.append(indent);
+      sb.append(targetElement.name);
+      sb.append(".");
+      // append name
+      {
+        sb.startPosition("NAME");
+        sb.append(name.name);
+        sb.endPosition();
+      }
+      _addFix_undefinedMethod_create_parameters(
+          sb,
+          instanceCreation.argumentList);
+      sb.append(") {${eol}${indent}}");
+      sb.append(targetLocation._suffix);
+    }
+    // insert source
+    _insertBuilder(sb);
+    if (targetFile == file) {
+      _addLinkedPosition("NAME", rf.rangeNode(name));
+    }
+    // add proposal
+    _addFix(FixKind.CREATE_CONSTRUCTOR, [constructorName], fixFile: targetFile);
+  }
+
+  void _addFix_createFunction_forFunctionType() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier) {
+//      SimpleIdentifier nameNode = node as SimpleIdentifier;
+//      // prepare argument expression (to get parameter)
+//      ClassElement targetElement;
+//      Expression argument;
+//      {
+//        Expression target = CorrectionUtils.getQualifiedPropertyTarget(node);
+//        if (target != null) {
+//          DartType targetType = target.bestType;
+//          if (targetType != null && targetType.element is ClassElement) {
+//            targetElement = targetType.element as ClassElement;
+//            argument = target.parent as Expression;
+//          } else {
+//            return;
+//          }
+//        } else {
+//          ClassDeclaration enclosingClass =
+//              node.getAncestor((node) => node is ClassDeclaration);
+//          targetElement = enclosingClass != null ?
+//              enclosingClass.element :
+//              null;
+//          argument = nameNode;
+//        }
+//      }
+//      // should be argument of some invocation
+//      ParameterElement parameterElement = argument.bestParameterElement;
+//      if (parameterElement == null) {
+//        return;
+//      }
+//      // should be parameter of function type
+//      DartType parameterType = parameterElement.type;
+//      if (parameterType is! FunctionType) {
+//        return;
+//      }
+//      FunctionType functionType = parameterType as FunctionType;
+//      // add proposal
+//      if (targetElement != null) {
+//        _addProposal_createFunction_method(targetElement, functionType);
+//      } else {
+//        _addProposal_createFunction_function(functionType);
+//      }
+//    }
+  }
+
+  void
+      _addFix_createMissingOverrides(List<ExecutableElement> missingOverrides) {
+    // TODO(scheglov) implement
+//    // sort by name
+//    missingOverrides.sort(
+//        (Element firstElement, Element secondElement) =>
+//            ObjectUtils.compare(firstElement.displayName, secondElement.displayName));
+//    // add elements
+//    ClassDeclaration targetClass = node.parent as ClassDeclaration;
+//    bool isFirst = true;
+//    for (ExecutableElement missingOverride in missingOverrides) {
+//      _addFix_createMissingOverrides_single(
+//          targetClass,
+//          missingOverride,
+//          isFirst);
+//      isFirst = false;
+//    }
+//    // add proposal
+//    _addFix(
+//        FixKind.CREATE_MISSING_OVERRIDES,
+//        [missingOverrides.length]);
+  }
+
+  void _addFix_createMissingOverrides_single(ClassDeclaration targetClass,
+      ExecutableElement missingOverride, bool isFirst) {
+    // TODO(scheglov) implement
+//    // prepare environment
+//    String eol = utils.endOfLine;
+//    String prefix = utils.getIndent(1);
+//    String prefix2 = utils.getIndent(2);
+//    int insertOffset = targetClass.end - 1;
+//    // prepare source
+//    JavaStringBuilder sb = new JavaStringBuilder();
+//    // may be empty line
+//    if (!isFirst || !targetClass.members.isEmpty) {
+//      sb.append(eol);
+//    }
+//    // may be property
+//    ElementKind elementKind = missingOverride.kind;
+//    bool isGetter = elementKind == ElementKind.GETTER;
+//    bool isSetter = elementKind == ElementKind.SETTER;
+//    bool isMethod = elementKind == ElementKind.METHOD;
+//    bool isOperator = isMethod && (missingOverride as MethodElement).isOperator;
+//    sb.append(prefix);
+//    if (isGetter) {
+//      sb.append("// TODO: implement ${missingOverride.displayName}");
+//      sb.append(eol);
+//      sb.append(prefix);
+//    }
+//    // @override
+//    {
+//      sb.append("@override");
+//      sb.append(eol);
+//      sb.append(prefix);
+//    }
+//    // return type
+//    _appendType(sb, missingOverride.type.returnType);
+//    if (isGetter) {
+//      sb.append("get ");
+//    } else if (isSetter) {
+//      sb.append("set ");
+//    } else if (isOperator) {
+//      sb.append("operator ");
+//    }
+//    // name
+//    sb.append(missingOverride.displayName);
+//    // parameters + body
+//    if (isGetter) {
+//      sb.append(" => null;");
+//    } else if (isMethod || isSetter) {
+//      List<ParameterElement> parameters = missingOverride.parameters;
+//      _appendParameters(sb, parameters);
+//      sb.append(" {");
+//      // TO-DO
+//      sb.append(eol);
+//      sb.append(prefix2);
+//      if (isMethod) {
+//        sb.append("// TODO: implement ${missingOverride.displayName}");
+//      } else {
+//        sb.append("// TODO: implement ${missingOverride.displayName}");
+//      }
+//      sb.append(eol);
+//      // close method
+//      sb.append(prefix);
+//      sb.append("}");
+//    }
+//    sb.append(eol);
+//    // done
+//    _addInsertEdit(insertOffset, sb.toString());
+//    // maybe set end range
+//    if (_endRange == null) {
+//      _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
+//    }
+  }
+
+  void _addFix_createNoSuchMethod() {
+    // TODO(scheglov) implement
+//    ClassDeclaration targetClass = node.parent as ClassDeclaration;
+//    // prepare environment
+//    String eol = utils.endOfLine;
+//    String prefix = utils.getIndent(1);
+//    int insertOffset = targetClass.end - 1;
+//    // prepare source
+//    SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+//    {
+//      // insert empty line before existing member
+//      if (!targetClass.members.isEmpty) {
+//        sb.append(eol);
+//      }
+//      // append method
+//      sb.append(prefix);
+//      sb.append(
+//          "noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);");
+//      sb.append(eol);
+//    }
+//    // done
+//    _addInsertEdit3(sb);
+//    _endRange = SourceRangeFactory.rangeStartLength(insertOffset, 0);
+//    // add proposal
+//    _addFix(FixKind.CREATE_NO_SUCH_METHOD, []);
+  }
+
+  void _addFix_createPart() {
+    // TODO(scheglov) implement
+//    if (node is SimpleStringLiteral && node.parent is PartDirective) {
+//      SimpleStringLiteral uriLiteral = node as SimpleStringLiteral;
+//      String uriString = uriLiteral.value;
+//      // prepare referenced File
+//      JavaFile newFile;
+//      {
+//        Uri uri = parseUriWithException(uriString);
+//        if (uri.isAbsolute) {
+//          return;
+//        }
+//        newFile = new JavaFile.relative(_unitLibraryFolder, uriString);
+//      }
+//      if (!newFile.exists()) {
+//        // prepare new source
+//        String source;
+//        {
+//          String eol = utils.endOfLine;
+//          String libraryName = _unitLibraryElement.displayName;
+//          source = "part of ${libraryName};${eol}${eol}";
+//        }
+//        // add proposal
+//        _proposals.add(
+//            new CreateFileCorrectionProposal(
+//                newFile,
+//                source,
+//                FixKind.CREATE_PART,
+//                [uriString]));
+//      }
+//    }
+  }
+
+  void _addFix_importLibrary(FixKind kind, String importPath) {
+    // TODO(scheglov) implement
+//    CompilationUnitElement libraryUnitElement =
+//        _unitLibraryElement.definingCompilationUnit;
+//    CompilationUnit libraryUnit = libraryUnitElement.node;
+//    // prepare new import location
+//    int offset = 0;
+//    String prefix;
+//    String suffix;
+//    {
+//      String eol = utils.endOfLine;
+//      // if no directives
+//      prefix = "";
+//      suffix = eol;
+//      CorrectionUtils libraryUtils = new CorrectionUtils(libraryUnit);
+//      // after last directive in library
+//      for (Directive directive in libraryUnit.directives) {
+//        if (directive is LibraryDirective || directive is ImportDirective) {
+//          offset = directive.end;
+//          prefix = eol;
+//          suffix = "";
+//        }
+//      }
+//      // if still beginning of file, skip shebang and line comments
+//      if (offset == 0) {
+//        CorrectionUtils_InsertDesc desc = libraryUtils.insertDescTop;
+//        offset = desc.offset;
+//        prefix = desc.prefix;
+//        suffix = "${desc.suffix}${eol}";
+//      }
+//    }
+//    // insert new import
+//    String importSource = "${prefix}import '${importPath}';${suffix}";
+//    _addInsertEdit(offset, importSource);
+//    // add proposal
+//    _addUnitCorrectionProposal2(libraryUnitElement.source, kind, [importPath]);
+  }
+
+  void _addFix_importLibrary_withElement(String name, ElementKind kind) {
+    // TODO(scheglov) implement
+//    // ignore if private
+//    if (name.startsWith("_")) {
+//      return;
+//    }
+//    // may be there is an existing import, but it is with prefix and we don't use this prefix
+//    for (ImportElement imp in _unitLibraryElement.imports) {
+//      // prepare element
+//      LibraryElement libraryElement = imp.importedLibrary;
+//      Element element =
+//          CorrectionUtils.getExportedElement(libraryElement, name);
+//      if (element == null) {
+//        continue;
+//      }
+//      if (element is PropertyAccessorElement) {
+//        element = (element as PropertyAccessorElement).variable;
+//      }
+//      if (element.kind != kind) {
+//        continue;
+//      }
+//      // may be apply prefix
+//      PrefixElement prefix = imp.prefix;
+//      if (prefix != null) {
+//        SourceRange range = SourceRangeFactory.rangeStartLength(node, 0);
+//        _addReplaceEdit(range, "${prefix.displayName}.");
+//        _addFix(
+//            FixKind.IMPORT_LIBRARY_PREFIX,
+//            [libraryElement.displayName, prefix.displayName]);
+//        continue;
+//      }
+//      // may be update "show" directive
+//      List<NamespaceCombinator> combinators = imp.combinators;
+//      if (combinators.length == 1 && combinators[0] is ShowElementCombinator) {
+//        ShowElementCombinator showCombinator =
+//            combinators[0] as ShowElementCombinator;
+//        // prepare new set of names to show
+//        Set<String> showNames = new Set<String>();
+//        showNames.addAll(showCombinator.shownNames);
+//        showNames.add(name);
+//        // prepare library name - unit name or 'dart:name' for SDK library
+//        String libraryName = libraryElement.definingCompilationUnit.displayName;
+//        if (libraryElement.isInSdk) {
+//          libraryName = imp.uri;
+//        }
+//        // update library
+//        String newShowCode = "show ${StringUtils.join(showNames, ", ")}";
+//        // TODO(scheglov)
+//        _addReplaceEdit(
+//            SourceRangeFactory.rangeShowCombinator(showCombinator),
+//            newShowCode);
+//        _addUnitCorrectionProposal2(
+//            _unitLibraryElement.source,
+//            FixKind.IMPORT_LIBRARY_SHOW,
+//            [libraryName]);
+//        // we support only one import without prefix
+//        return;
+//      }
+//    }
+//    // check SDK libraries
+//    AnalysisContext context = _unitLibraryElement.context;
+//    {
+//      DartSdk sdk = context.sourceFactory.dartSdk;
+//      List<SdkLibrary> sdkLibraries = sdk.sdkLibraries;
+//      for (SdkLibrary sdkLibrary in sdkLibraries) {
+//        SourceFactory sdkSourceFactory = context.sourceFactory;
+//        String libraryUri = sdkLibrary.shortName;
+//        Source librarySource = sdkSourceFactory.resolveUri(null, libraryUri);
+//        // prepare LibraryElement
+//        LibraryElement libraryElement =
+//            context.getLibraryElement(librarySource);
+//        if (libraryElement == null) {
+//          continue;
+//        }
+//        // prepare exported Element
+//        Element element =
+//            CorrectionUtils.getExportedElement(libraryElement, name);
+//        if (element == null) {
+//          continue;
+//        }
+//        if (element is PropertyAccessorElement) {
+//          element = (element as PropertyAccessorElement).variable;
+//        }
+//        if (element.kind != kind) {
+//          continue;
+//        }
+//        // add import
+//        _addFix_importLibrary(FixKind.IMPORT_LIBRARY_SDK, libraryUri);
+//      }
+//    }
+//    // check project libraries
+//    {
+//      List<Source> librarySources = context.librarySources;
+//      for (Source librarySource in librarySources) {
+//        // we don't need SDK libraries here
+//        if (librarySource.isInSystemLibrary) {
+//          continue;
+//        }
+//        // prepare LibraryElement
+//        LibraryElement libraryElement =
+//            context.getLibraryElement(librarySource);
+//        if (libraryElement == null) {
+//          continue;
+//        }
+//        // prepare exported Element
+//        Element element =
+//            CorrectionUtils.getExportedElement(libraryElement, name);
+//        if (element == null) {
+//          continue;
+//        }
+//        if (element.kind != kind) {
+//          continue;
+//        }
+//        // prepare "library" file
+//        JavaFile libraryFile = getSourceFile(librarySource);
+//        if (libraryFile == null) {
+//          continue;
+//        }
+//        // may be "package:" URI
+//        {
+//          Uri libraryPackageUri = _findPackageUri(context, libraryFile);
+//          if (libraryPackageUri != null) {
+//            _addFix_importLibrary(
+//                FixKind.IMPORT_LIBRARY_PROJECT,
+//                libraryPackageUri.toString());
+//            continue;
+//          }
+//        }
+//        // relative URI
+//        String relative =
+//            URIUtils.computeRelativePath(
+//                _unitLibraryFolder.getAbsolutePath(),
+//                libraryFile.getAbsolutePath());
+//        _addFix_importLibrary(
+//            FixKind.IMPORT_LIBRARY_PROJECT,
+//            relative);
+//      }
+//    }
+  }
+
+  void _addFix_importLibrary_withFunction() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+//      MethodInvocation invocation = node.parent as MethodInvocation;
+//      if (invocation.realTarget == null &&
+//          identical(invocation.methodName, node)) {
+//        String name = (node as SimpleIdentifier).name;
+//        _addFix_importLibrary_withElement(name, ElementKind.FUNCTION);
+//      }
+//    }
+  }
+
+  void _addFix_importLibrary_withTopLevelVariable() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier) {
+//      String name = (node as SimpleIdentifier).name;
+//      _addFix_importLibrary_withElement(name, ElementKind.TOP_LEVEL_VARIABLE);
+//    }
+  }
+
+  void _addFix_importLibrary_withType() {
+    // TODO(scheglov) implement
+//    if (_mayBeTypeIdentifier(node)) {
+//      String typeName = (node as SimpleIdentifier).name;
+//      _addFix_importLibrary_withElement(typeName, ElementKind.CLASS);
+//    }
+  }
+
+  void _addFix_insertSemicolon() {
+    if (error.message.contains("';'")) {
+      int insertOffset = error.offset + error.length;
+      _addInsertEdit(insertOffset, ";");
+      _addFix(FixKind.INSERT_SEMICOLON, []);
+    }
+  }
+
+  void _addFix_isNotNull() {
+    if (coveredNode is IsExpression) {
+      IsExpression isExpression = coveredNode as IsExpression;
+      _addReplaceEdit(
+          rf.rangeEndEnd(isExpression.expression, isExpression),
+          " != null");
+      _addFix(FixKind.USE_NOT_EQ_NULL, []);
+    }
+  }
+
+  void _addFix_isNull() {
+    if (coveredNode is IsExpression) {
+      IsExpression isExpression = coveredNode as IsExpression;
+      _addReplaceEdit(
+          rf.rangeEndEnd(isExpression.expression, isExpression),
+          " == null");
+      _addFix(FixKind.USE_EQ_EQ_NULL, []);
+    }
+  }
+
+  void _addFix_makeEnclosingClassAbstract() {
+    ClassDeclaration enclosingClass =
+        node.getAncestor((node) => node is ClassDeclaration);
+    String className = enclosingClass.name.name;
+    _addInsertEdit(enclosingClass.classKeyword.offset, "abstract ");
+    _addFix(FixKind.MAKE_CLASS_ABSTRACT, [className]);
+  }
+
+  void _addFix_removeParameters_inGetterDeclaration() {
+    if (node is SimpleIdentifier && node.parent is MethodDeclaration) {
+      MethodDeclaration method = node.parent as MethodDeclaration;
+      FunctionBody body = method.body;
+      if (method.name == node && body != null) {
+        _addReplaceEdit(rf.rangeEndStart(node, body), " ");
+        _addFix(FixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, []);
+      }
+    }
+  }
+
+  void _addFix_removeParentheses_inGetterInvocation() {
+    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+      MethodInvocation invocation = node.parent as MethodInvocation;
+      if (invocation.methodName == node && invocation.target != null) {
+        _addRemoveEdit(rf.rangeEndEnd(node, invocation));
+        _addFix(FixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, []);
+      }
+    }
+  }
+
+  void _addFix_removeUnnecessaryCast() {
+    if (coveredNode is! AsExpression) {
+      return;
+    }
+    AsExpression asExpression = coveredNode as AsExpression;
+    Expression expression = asExpression.expression;
+    int expressionPrecedence = getExpressionPrecedence(expression);
+    // remove 'as T' from 'e as T'
+    _addRemoveEdit(rf.rangeEndEnd(expression, asExpression));
+    _removeEnclosingParentheses(asExpression, expressionPrecedence);
+    // done
+    _addFix(FixKind.REMOVE_UNNECASSARY_CAST, []);
+  }
+
+  void _addFix_removeUnusedImport() {
+    // prepare ImportDirective
+    ImportDirective importDirective =
+        node.getAncestor((node) => node is ImportDirective);
+    if (importDirective == null) {
+      return;
+    }
+    // remove the whole line with import
+    _addRemoveEdit(utils.getLinesRange(rf.rangeNode(importDirective)));
+    // done
+    _addFix(FixKind.REMOVE_UNUSED_IMPORT, []);
+  }
+
+  void _addFix_replaceWithConstInstanceCreation() {
+    if (coveredNode is InstanceCreationExpression) {
+      var instanceCreation = coveredNode as InstanceCreationExpression;
+      _addReplaceEdit(rf.rangeToken(instanceCreation.keyword), "const");
+      _addFix(FixKind.USE_CONST, []);
+    }
+  }
+
+  void _addFix_undefinedClass_useSimilar() {
+    // TODO(scheglov) implement
+//    if (_mayBeTypeIdentifier(node)) {
+//      String name = (node as SimpleIdentifier).name;
+//      QuickFixProcessorImpl_ClosestElementFinder finder =
+//          new QuickFixProcessorImpl_ClosestElementFinder(
+//              name,
+//              new Predicate_QuickFixProcessorImpl_addFix_undefinedClass_useSimilar());
+//      // find closest element
+//      {
+//        // elements of this library
+//        _unitLibraryElement.accept(
+//            new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedClass_useSimilar(
+//                finder));
+//        // elements from imports
+//        for (ImportElement importElement in _unitLibraryElement.imports) {
+//          if (importElement.prefix == null) {
+//            Map<String, Element> namespace =
+//                CorrectionUtils.getImportNamespace(importElement);
+//            finder._update2(namespace.values);
+//          }
+//        }
+//      }
+//      // if we have close enough element, suggest to use it
+//      if (finder != null && finder._distance < 5) {
+//        String closestName = finder._element.name;
+//        _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+//        // add proposal
+//        if (closestName != null) {
+//          _addFix(
+//              FixKind.CHANGE_TO,
+//              [closestName]);
+//        }
+//      }
+//    }
+  }
+
+  void _addFix_undefinedFunction_create() {
+    // TODO(scheglov) implement
+//    // should be the name of the invocation
+//    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+//    } else {
+//      return;
+//    }
+//    String name = (node as SimpleIdentifier).name;
+//    MethodInvocation invocation = node.parent as MethodInvocation;
+//    // function invocation has no target
+//    Expression target = invocation.realTarget;
+//    if (target != null) {
+//      return;
+//    }
+//    // prepare environment
+//    String eol = utils.endOfLine;
+//    int insertOffset;
+//    String sourcePrefix;
+//    AstNode enclosingMember =
+//        node.getAncestor((node) => node is CompilationUnitMember);
+//    insertOffset = enclosingMember.end;
+//    sourcePrefix = "${eol}${eol}";
+//    // build method source
+//    SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+//    {
+//      sb.append(sourcePrefix);
+//      // may be return type
+//      {
+//        DartType type =
+//            _addFix_undefinedMethod_create_getReturnType(invocation);
+//        if (type != null) {
+//          String typeSource = utils.getTypeSource2(type);
+//          if (typeSource != "dynamic") {
+//            sb.startPosition("RETURN_TYPE");
+//            sb.append(typeSource);
+//            sb.endPosition();
+//            sb.append(" ");
+//          }
+//        }
+//      }
+//      // append name
+//      {
+//        sb.startPosition("NAME");
+//        sb.append(name);
+//        sb.endPosition();
+//      }
+//      _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList);
+//      sb.append(") {${eol}}");
+//    }
+//    // insert source
+//    _addInsertEdit(insertOffset, sb.toString());
+//    // add linked positions
+//    _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
+//    _addLinkedPositions(sb);
+//    // add proposal
+//    _addFix(FixKind.CREATE_FUNCTION, [name]);
+  }
+
+  void _addFix_undefinedFunction_useSimilar() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier) {
+//      String name = (node as SimpleIdentifier).name;
+//      QuickFixProcessorImpl_ClosestElementFinder finder =
+//          new QuickFixProcessorImpl_ClosestElementFinder(
+//              name,
+//              new Predicate_QuickFixProcessorImpl_addFix_undefinedFunction_useSimilar());
+//      // this library
+//      _unitLibraryElement.accept(
+//          new RecursiveElementVisitor_QuickFixProcessorImpl_addFix_undefinedFunction_useSimilar(
+//              finder));
+//      // imports
+//      for (ImportElement importElement in _unitLibraryElement.imports) {
+//        if (importElement.prefix == null) {
+//          Map<String, Element> namespace =
+//              CorrectionUtils.getImportNamespace(importElement);
+//          finder._update2(namespace.values);
+//        }
+//      }
+//      // if we have close enough element, suggest to use it
+//      String closestName = null;
+//      if (finder != null && finder._distance < 5) {
+//        closestName = finder._element.name;
+//        _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+//        _addFix(FixKind.CHANGE_TO, [closestName]);
+//      }
+//    }
+  }
+
+  void _addFix_undefinedMethod_create() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+//      String name = (node as SimpleIdentifier).name;
+//      MethodInvocation invocation = node.parent as MethodInvocation;
+//      // prepare environment
+//      String eol = utils.endOfLine;
+//      Source targetSource;
+//      String prefix;
+//      int insertOffset;
+//      String sourcePrefix;
+//      String sourceSuffix;
+//      bool staticModifier = false;
+//      Expression target = invocation.realTarget;
+//      if (target == null) {
+//        targetSource = _source;
+//        ClassMember enclosingMember =
+//            node.getAncestor((node) => node is ClassMember);
+//        staticModifier = _inStaticMemberContext2(enclosingMember);
+//        prefix = utils.getNodePrefix(enclosingMember);
+//        insertOffset = enclosingMember.end;
+//        sourcePrefix = "${eol}${prefix}${eol}";
+//        sourceSuffix = "";
+//      } else {
+//        // prepare target interface type
+//        DartType targetType = target.bestType;
+//        if (targetType is! InterfaceType) {
+//          return;
+//        }
+//        ClassElement targetElement = targetType.element as ClassElement;
+//        targetSource = targetElement.source;
+//        // may be static
+//        if (target is Identifier) {
+//          staticModifier = target.bestElement.kind == ElementKind.CLASS;
+//        }
+//        // prepare insert offset
+//        ClassDeclaration targetClass = targetElement.node;
+//        prefix = "  ";
+//        insertOffset = targetClass.end - 1;
+//        if (targetClass.members.isEmpty) {
+//          sourcePrefix = "";
+//        } else {
+//          sourcePrefix = "${prefix}${eol}";
+//        }
+//        sourceSuffix = eol;
+//      }
+//      // build method source
+//      SourceBuilder sb = new SourceBuilder.con1(insertOffset);
+//      {
+//        sb.append(sourcePrefix);
+//        sb.append(prefix);
+//        // may be "static"
+//        if (staticModifier) {
+//          sb.append("static ");
+//        }
+//        // may be return type
+//        {
+//          DartType type =
+//              _addFix_undefinedMethod_create_getReturnType(invocation);
+//          if (type != null) {
+//            String typeSource = utils.getTypeSource2(type);
+//            if (typeSource != "dynamic") {
+//              sb.startPosition("RETURN_TYPE");
+//              sb.append(typeSource);
+//              sb.endPosition();
+//              sb.append(" ");
+//            }
+//          }
+//        }
+//        // append name
+//        {
+//          sb.startPosition("NAME");
+//          sb.append(name);
+//          sb.endPosition();
+//        }
+//        _addFix_undefinedMethod_create_parameters(sb, invocation.argumentList);
+//        sb.append(") {${eol}${prefix}}");
+//        sb.append(sourceSuffix);
+//      }
+//      // insert source
+//      _addInsertEdit(insertOffset, sb.toString());
+//      // add linked positions
+//      if (targetSource == _source) {
+//        _addLinkedPosition("NAME", sb, SourceRangeFactory.rangeNode(node));
+//      }
+//      _addLinkedPositions(sb);
+//      // add proposal
+//      _addUnitCorrectionProposal2(
+//          targetSource,
+//          FixKind.CREATE_METHOD,
+//          [name]);
+//    }
+  }
+
+  /**
+   * @return the possible return [Type], may be <code>null</code> if can not be identified.
+   */
+  DartType
+      _addFix_undefinedMethod_create_getReturnType(MethodInvocation invocation) {
+    // TODO(scheglov) implement
+//    AstNode parent = invocation.parent;
+//    // myFunction();
+//    if (parent is ExpressionStatement) {
+//      return VoidTypeImpl.instance;
+//    }
+//    // return myFunction();
+//    if (parent is ReturnStatement) {
+//      ExecutableElement executable =
+//          CorrectionUtils.getEnclosingExecutableElement(invocation);
+//      return executable != null ? executable.returnType : null;
+//    }
+//    // int v = myFunction();
+//    if (parent is VariableDeclaration) {
+//      VariableDeclaration variableDeclaration = parent;
+//      if (identical(variableDeclaration.initializer, invocation)) {
+//        VariableElement variableElement = variableDeclaration.element;
+//        if (variableElement != null) {
+//          return variableElement.type;
+//        }
+//      }
+//    }
+//    // v = myFunction();
+//    if (parent is AssignmentExpression) {
+//      AssignmentExpression assignment = parent;
+//      if (identical(assignment.rightHandSide, invocation)) {
+//        if (assignment.operator.type == TokenType.EQ) {
+//          // v = myFunction();
+//          Expression lhs = assignment.leftHandSide;
+//          if (lhs != null) {
+//            return lhs.bestType;
+//          }
+//        } else {
+//          // v += myFunction();
+//          MethodElement method = assignment.bestElement;
+//          if (method != null) {
+//            List<ParameterElement> parameters = method.parameters;
+//            if (parameters.length == 1) {
+//              return parameters[0].type;
+//            }
+//          }
+//        }
+//      }
+//    }
+//    // v + myFunction();
+//    if (parent is BinaryExpression) {
+//      BinaryExpression binary = parent;
+//      MethodElement method = binary.bestElement;
+//      if (method != null) {
+//        if (identical(binary.rightOperand, invocation)) {
+//          List<ParameterElement> parameters = method.parameters;
+//          return parameters.length == 1 ? parameters[0].type : null;
+//        }
+//      }
+//    }
+//    // foo( myFunction() );
+//    if (parent is ArgumentList) {
+//      ParameterElement parameter = invocation.bestParameterElement;
+//      return parameter != null ? parameter.type : null;
+//    }
+//    // bool
+//    {
+//      // assert( myFunction() );
+//      if (parent is AssertStatement) {
+//        AssertStatement statement = parent;
+//        if (identical(statement.condition, invocation)) {
+//          return coreTypeBool;
+//        }
+//      }
+//      // if ( myFunction() ) {}
+//      if (parent is IfStatement) {
+//        IfStatement statement = parent;
+//        if (identical(statement.condition, invocation)) {
+//          return coreTypeBool;
+//        }
+//      }
+//      // while ( myFunction() ) {}
+//      if (parent is WhileStatement) {
+//        WhileStatement statement = parent;
+//        if (identical(statement.condition, invocation)) {
+//          return coreTypeBool;
+//        }
+//      }
+//      // do {} while ( myFunction() );
+//      if (parent is DoStatement) {
+//        DoStatement statement = parent;
+//        if (identical(statement.condition, invocation)) {
+//          return coreTypeBool;
+//        }
+//      }
+//      // !myFunction()
+//      if (parent is PrefixExpression) {
+//        PrefixExpression prefixExpression = parent;
+//        if (prefixExpression.operator.type == TokenType.BANG) {
+//          return coreTypeBool;
+//        }
+//      }
+//      // binary expression '&&' or '||'
+//      if (parent is BinaryExpression) {
+//        BinaryExpression binaryExpression = parent;
+//        TokenType operatorType = binaryExpression.operator.type;
+//        if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
+//            operatorType == TokenType.BAR_BAR) {
+//          return coreTypeBool;
+//        }
+//      }
+//    }
+    // we don't know
+    return null;
+  }
+
+  void _addFix_undefinedMethod_create_parameters(SourceBuilder sb,
+      ArgumentList argumentList) {
+    // append parameters
+    sb.append("(");
+    Set<String> excluded = new Set();
+    List<Expression> arguments = argumentList.arguments;
+    for (int i = 0; i < arguments.length; i++) {
+      Expression argument = arguments[i];
+      // append separator
+      if (i != 0) {
+        sb.append(", ");
+      }
+      // append type name
+      DartType type = argument.bestType;
+      String typeSource = utils.getTypeSource(type);
+      {
+        sb.startPosition("TYPE${i}");
+        sb.append(typeSource);
+        _addSuperTypeProposals(sb, new Set(), type);
+        sb.endPosition();
+      }
+      sb.append(" ");
+      // append parameter name
+      {
+        List<String> suggestions =
+            _getArgumentNameSuggestions(excluded, type, argument, i);
+        String favorite = suggestions[0];
+        excluded.add(favorite);
+        sb.startPosition("ARG${i}");
+        sb.append(favorite);
+        sb.addProposals(suggestions);
+        sb.endPosition();
+      }
+    }
+  }
+
+  void _addFix_undefinedMethod_useSimilar() {
+    // TODO(scheglov) implement
+//    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+//      MethodInvocation invocation = node.parent as MethodInvocation;
+//      String name = (node as SimpleIdentifier).name;
+//      QuickFixProcessorImpl_ClosestElementFinder finder =
+//          new QuickFixProcessorImpl_ClosestElementFinder(
+//              name,
+//              new Predicate_QuickFixProcessorImpl_addFix_undefinedMethod_useSimilar());
+//      // unqualified invocation
+//      Expression target = invocation.realTarget;
+//      if (target == null) {
+//        ClassDeclaration clazz =
+//            invocation.getAncestor((node) => node is ClassDeclaration);
+//        if (clazz != null) {
+//          ClassElement classElement = clazz.element;
+//          _updateFinderWithClassMembers(finder, classElement);
+//        }
+//      } else {
+//        DartType type = target.bestType;
+//        if (type is InterfaceType) {
+//          ClassElement classElement = type.element;
+//          _updateFinderWithClassMembers(finder, classElement);
+//        }
+//      }
+//      // if we have close enough element, suggest to use it
+//      String closestName = null;
+//      if (finder != null && finder._distance < 5) {
+//        closestName = finder._element.name;
+//        _addReplaceEdit(SourceRangeFactory.rangeNode(node), closestName);
+//        _addFix(FixKind.CHANGE_TO, [closestName]);
+//      }
+//    }
+  }
+
+  void _addFix_useEffectiveIntegerDivision() {
+    for (AstNode n = node; n != null; n = n.parent) {
+      if (n is MethodInvocation &&
+          n.offset == errorOffset &&
+          n.length == errorLength) {
+        MethodInvocation invocation = n as MethodInvocation;
+        Expression target = invocation.target;
+        while (target is ParenthesizedExpression) {
+          target = (target as ParenthesizedExpression).expression;
+        }
+        // replace "/" with "~/"
+        BinaryExpression binary = target as BinaryExpression;
+        _addReplaceEdit(rf.rangeToken(binary.operator), "~/");
+        // remove everything before and after
+        _addRemoveEdit(rf.rangeStartStart(invocation, binary.leftOperand));
+        _addRemoveEdit(rf.rangeEndEnd(binary.rightOperand, invocation));
+        // add proposal
+        _addFix(FixKind.USE_EFFECTIVE_INTEGER_DIVISION, []);
+        // done
+        break;
+      }
+    }
+  }
+
+  void _addFix_useStaticAccess_method() {
+    if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+      MethodInvocation invocation = node.parent as MethodInvocation;
+      if (invocation.methodName == node) {
+        Expression target = invocation.target;
+        String targetType = utils.getExpressionTypeSource(target);
+        // replace "target" with class name
+        SourceRange range = rf.rangeNode(target);
+        _addReplaceEdit(range, targetType);
+        // add proposal
+        _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
+      }
+    }
+  }
+
+  void _addFix_useStaticAccess_property() {
+    if (node is SimpleIdentifier) {
+      if (node.parent is PrefixedIdentifier) {
+        PrefixedIdentifier prefixed = node.parent as PrefixedIdentifier;
+        if (prefixed.identifier == node) {
+          Expression target = prefixed.prefix;
+          String targetType = utils.getExpressionTypeSource(target);
+          // replace "target" with class name
+          SourceRange range = rf.rangeNode(target);
+          _addReplaceEdit(range, targetType);
+          // add proposal
+          _addFix(FixKind.CHANGE_TO_STATIC_ACCESS, [targetType]);
+        }
+      }
+    }
+  }
+
+  /**
+   * Adds a new [Edit] to [edits].
+   */
+  void _addInsertEdit(int offset, String text) {
+    Edit edit = new Edit(offset, 0, text);
+    edits.add(edit);
+  }
+
+  /**
+   * Adds a single linked position to [groupId].
+   */
+  void _addLinkedPosition(String groupId, SourceRange range) {
+    _addLinkedPosition2(
+        groupId,
+        new Position(file, range.offset, range.length));
+  }
+
+  /**
+   * Adds a single linked position to [groupId].
+   */
+  void _addLinkedPosition2(String groupId, Position position) {
+    LinkedPositionGroup group = linkedPositionGroups[groupId];
+    if (group == null) {
+      group = new LinkedPositionGroup(groupId);
+      linkedPositionGroups[groupId] = group;
+    }
+    group.add(position);
+  }
+
+  /**
+   * Adds a new [Edit] to [edits].
+   */
+  void _addRemoveEdit(SourceRange range) {
+    _addReplaceEdit(range, '');
+  }
+
+  /**
+   * Adds a new [Edit] to [edits].
+   */
+  void _addReplaceEdit(SourceRange range, String text) {
+    Edit edit = new Edit(range.offset, range.length, text);
+    edits.add(edit);
+  }
+
+  void _appendParameterSource(StringBuffer sb, DartType type, String name) {
+    String parameterSource = utils.getParameterSource(type, name);
+    sb.write(parameterSource);
+  }
+
+  void _appendParameters(StringBuffer sb, List<ParameterElement> parameters,
+      Map<ParameterElement, String> defaultValueMap) {
+    sb.write("(");
+    bool firstParameter = true;
+    bool sawNamed = false;
+    bool sawPositional = false;
+    for (ParameterElement parameter in parameters) {
+      if (!firstParameter) {
+        sb.write(", ");
+      } else {
+        firstParameter = false;
+      }
+      // may be optional
+      ParameterKind parameterKind = parameter.parameterKind;
+      if (parameterKind == ParameterKind.NAMED) {
+        if (!sawNamed) {
+          sb.write("{");
+          sawNamed = true;
+        }
+      }
+      if (parameterKind == ParameterKind.POSITIONAL) {
+        if (!sawPositional) {
+          sb.write("[");
+          sawPositional = true;
+        }
+      }
+      // parameter
+      _appendParameterSource(sb, parameter.type, parameter.name);
+      // default value
+      if (defaultValueMap != null) {
+        String defaultSource = defaultValueMap[parameter];
+        if (defaultSource != null) {
+          if (sawPositional) {
+            sb.write(" = ");
+          } else {
+            sb.write(": ");
+          }
+          sb.write(defaultSource);
+        }
+      }
+    }
+    // close parameters
+    if (sawNamed) {
+      sb.write("}");
+    }
+    if (sawPositional) {
+      sb.write("]");
+    }
+    sb.write(")");
+  }
+
+//  void _addLinkedPositionProposal(String group,
+//      LinkedPositionProposal proposal) {
+//    List<LinkedPositionProposal> nodeProposals = linkedPositionProposals[group];
+//    if (nodeProposals == null) {
+//      nodeProposals = <LinkedPositionProposal>[];
+//      linkedPositionProposals[group] = nodeProposals;
+//    }
+//    nodeProposals.add(proposal);
+//  }
+
+  /**
+   * @return the string to display as the name of the given constructor in a proposal name.
+   */
+  String _getConstructorProposalName(ConstructorElement constructor) {
+    StringBuffer proposalNameBuffer = new StringBuffer();
+    proposalNameBuffer.write("super");
+    // may be named
+    String constructorName = constructor.displayName;
+    if (!constructorName.isEmpty) {
+      proposalNameBuffer.write(".");
+      proposalNameBuffer.write(constructorName);
+    }
+    // parameters
+    _appendParameters(proposalNameBuffer, constructor.parameters, null);
+    // done
+    return proposalNameBuffer.toString();
+  }
+
+  /**
+   * Inserts the given [SourceBuilder] at its offset.
+   */
+  void _insertBuilder(SourceBuilder builder) {
+    String text = builder.toString();
+    _addInsertEdit(builder.offset, text);
+    // add linked positions
+    builder.linkedPositionGroups.forEach((LinkedPositionGroup group) {
+      group.positions.forEach((Position position) {
+        _addLinkedPosition2(group.id, position);
+      });
+    });
+  }
+
+  QuickFixProcessorImpl_NewConstructorLocation
+      _prepareNewConstructorLocation(ClassDeclaration classDeclaration, String eol) {
+    List<ClassMember> members = classDeclaration.members;
+    // find the last field/constructor
+    ClassMember lastFieldOrConstructor = null;
+    for (ClassMember member in members) {
+      if (member is FieldDeclaration || member is ConstructorDeclaration) {
+        lastFieldOrConstructor = member;
+      } else {
+        break;
+      }
+    }
+    // after the field/constructor
+    if (lastFieldOrConstructor != null) {
+      return new QuickFixProcessorImpl_NewConstructorLocation(
+          "${eol}${eol}",
+          lastFieldOrConstructor.end,
+          "");
+    }
+    // at the beginning of the class
+    String suffix = members.isEmpty ? "" : eol;
+    return new QuickFixProcessorImpl_NewConstructorLocation(
+        eol,
+        classDeclaration.leftBracket.end,
+        suffix);
+  }
+
+  /**
+   * Removes any [ParenthesizedExpression] enclosing [expr].
+   *
+   * [exprPrecedence] - the effective precedence of [expr].
+   */
+  void _removeEnclosingParentheses(Expression expr, int exprPrecedence) {
+    while (expr.parent is ParenthesizedExpression) {
+      ParenthesizedExpression parenthesized =
+          expr.parent as ParenthesizedExpression;
+      if (getExpressionParentPrecedence(parenthesized) > exprPrecedence) {
+        break;
+      }
+      _addRemoveEdit(rf.rangeToken(parenthesized.leftParenthesis));
+      _addRemoveEdit(rf.rangeToken(parenthesized.rightParenthesis));
+      expr = parenthesized;
+    }
+  }
+
+  static void _addSuperTypeProposals(SourceBuilder sb,
+      Set<DartType> alreadyAdded, DartType type) {
+    if (type != null &&
+        !alreadyAdded.contains(type) &&
+        type.element is ClassElement) {
+      alreadyAdded.add(type);
+      ClassElement element = type.element as ClassElement;
+      sb.addProposal(element.name);
+      _addSuperTypeProposals(sb, alreadyAdded, element.supertype);
+      for (InterfaceType interfaceType in element.interfaces) {
+        _addSuperTypeProposals(sb, alreadyAdded, interfaceType);
+      }
+    }
+  }
+
+  /**
+   * @return the suggestions for given [Type] and [DartExpression], not empty.
+   */
+  static List<String> _getArgumentNameSuggestions(Set<String> excluded,
+      DartType type, Expression expression, int index) {
+    List<String> suggestions =
+        getVariableNameSuggestionsForExpression(type, expression, excluded);
+    if (suggestions.length != 0) {
+      return suggestions;
+    }
+    return <String>["arg${index}"];
+  }
+
+  /**
+   * Returns `true` if [node] is a type name.
+   */
+  static bool _mayBeTypeIdentifier(AstNode node) {
+    if (node is SimpleIdentifier) {
+      AstNode parent = node.parent;
+      if (parent is TypeName) {
+        return true;
+      }
+      if (parent is MethodInvocation) {
+        return parent.realTarget == node;
+      }
+      if (parent is PrefixedIdentifier) {
+        return parent.prefix == node;
+      }
+    }
+    return false;
+  }
+}
+
+
+/**
+ * Describes the location for a newly created [ConstructorDeclaration].
+ *
+ * TODO(scheglov) rename
+ */
+class QuickFixProcessorImpl_NewConstructorLocation {
+  final String _prefix;
+  final int _offset;
+  final String _suffix;
+
+  QuickFixProcessorImpl_NewConstructorLocation(this._prefix, this._offset,
+      this._suffix);
+}
diff --git a/pkg/analysis_services/lib/src/correction/name_suggestion.dart b/pkg/analysis_services/lib/src/correction/name_suggestion.dart
new file mode 100644
index 0000000..7440be1
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/name_suggestion.dart
@@ -0,0 +1,258 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.name_suggestion;
+
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+
+List<String> _KNOWN_METHOD_NAME_PREFIXES = ['get', 'is', 'to'];
+
+/**
+ * Returns a list of words for the given camel case string.
+ *
+ * 'getCamelWords' => ['get', 'Camel', 'Words']
+ * 'getHTMLText' => ['get', 'HTML', 'Text']
+ */
+List<String> getCamelWords(String str) {
+  if (str == null || str.isEmpty) {
+    return <String>[];
+  }
+  List<String> parts = <String>[];
+  bool wasLowerCase = false;
+  bool wasUpperCase = false;
+  int wordStart = 0;
+  for (int i = 0; i < str.length; i++) {
+    int c = str.codeUnitAt(i);
+    var newLowerCase = isLowerCase(c);
+    var newUpperCase = isUpperCase(c);
+    // myWord
+    // | ^
+    if (wasLowerCase && newUpperCase) {
+      parts.add(str.substring(wordStart, i));
+      wordStart = i;
+    }
+    // myHTMLText
+    //   |   ^
+    if (wasUpperCase &&
+        newUpperCase &&
+        i + 1 < str.length &&
+        isLowerCase(str.codeUnitAt(i + 1))) {
+      parts.add(str.substring(wordStart, i));
+      wordStart = i;
+    }
+    wasLowerCase = newLowerCase;
+    wasUpperCase = newUpperCase;
+  }
+  parts.add(str.substring(wordStart));
+  return parts;
+}
+
+/**
+ * Returns possible names for a [String] variable with [text] value.
+ */
+List<String> getVariableNameSuggestionsForText(String text,
+    Set<String> excluded) {
+  // filter out everything except of letters and white spaces
+  {
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < text.length; i++) {
+      int c = text.codeUnitAt(i);
+      if (isLetter(c) || isWhitespace(c)) {
+        sb.writeCharCode(c);
+      }
+    }
+    text = sb.toString();
+  }
+  // make single camel-case text
+  {
+    List<String> words = text.split(' ');
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < words.length; i++) {
+      String word = words[i];
+      if (i > 0) {
+        word = capitalize(word);
+      }
+      sb.write(word);
+    }
+    text = sb.toString();
+  }
+  // split camel-case into separate suggested names
+  Set<String> res = new Set();
+  _addAll(excluded, res, _getCamelWordCombinations(text));
+  return new List.from(res);
+}
+
+/**
+ * Returns possible names for a variable with the given expected type and
+ * expression assigned.
+ */
+List<String> getVariableNameSuggestionsForExpression(DartType expectedType,
+    Expression assignedExpression, Set<String> excluded) {
+  Set<String> res = new Set();
+  // use expression
+  if (assignedExpression != null) {
+    String nameFromExpression = _getBaseNameFromExpression(assignedExpression);
+    if (nameFromExpression != null) {
+      nameFromExpression = removeStart(nameFromExpression, '_');
+      _addAll(excluded, res, _getCamelWordCombinations(nameFromExpression));
+    }
+    String nameFromParent =
+        _getBaseNameFromLocationInParent(assignedExpression);
+    if (nameFromParent != null) {
+      _addAll(excluded, res, _getCamelWordCombinations(nameFromParent));
+    }
+  }
+  // use type
+  if (expectedType != null && !expectedType.isDynamic) {
+    String typeName = expectedType.name;
+    if ('int' == typeName) {
+      _addSingleCharacterName(excluded, res, 0x69);
+    } else if ('double' == typeName) {
+      _addSingleCharacterName(excluded, res, 0x64);
+    } else if ('String' == typeName) {
+      _addSingleCharacterName(excluded, res, 0x73);
+    } else {
+      _addAll(excluded, res, _getCamelWordCombinations(typeName));
+    }
+    res.remove(typeName);
+  }
+  // done
+  return new List.from(res);
+}
+
+/**
+ * Adds [toAdd] items which are not excluded.
+ */
+void _addAll(Set<String> excluded, Set<String> result, Iterable<String> toAdd) {
+  for (String item in toAdd) {
+    // add name based on "item", but not "excluded"
+    for (int suffix = 1; ; suffix++) {
+      // prepare name, just "item" or "item2", "item3", etc
+      String name = item;
+      if (suffix > 1) {
+        name += suffix.toString();
+      }
+      // add once found not excluded
+      if (!excluded.contains(name)) {
+        result.add(name);
+        break;
+      }
+    }
+  }
+}
+
+/**
+ * Adds to [result] either [c] or the first ASCII character after it.
+ */
+void _addSingleCharacterName(Set<String> excluded, Set<String> result, int c) {
+  while (c < 0x7A) {
+    String name = new String.fromCharCode(c);
+    // may be done
+    if (!excluded.contains(name)) {
+      result.add(name);
+      break;
+    }
+    // next character
+    c = c + 1;
+  }
+}
+
+String _getBaseNameFromExpression(Expression expression) {
+  String name = null;
+  // e as Type
+  if (expression is AsExpression) {
+    AsExpression asExpression = expression as AsExpression;
+    expression = asExpression.expression;
+  }
+  // analyze expressions
+  if (expression is SimpleIdentifier) {
+    SimpleIdentifier node = expression;
+    return node.name;
+  } else if (expression is PrefixedIdentifier) {
+    PrefixedIdentifier node = expression;
+    return node.identifier.name;
+  } else if (expression is MethodInvocation) {
+    name = expression.methodName.name;
+  } else if (expression is InstanceCreationExpression) {
+    InstanceCreationExpression creation = expression;
+    ConstructorName constructorName = creation.constructorName;
+    TypeName typeName = constructorName.type;
+    if (typeName != null) {
+      Identifier typeNameIdentifier = typeName.name;
+      // new ClassName()
+      if (typeNameIdentifier is SimpleIdentifier) {
+        return typeNameIdentifier.name;
+      }
+      // new prefix.name();
+      if (typeNameIdentifier is PrefixedIdentifier) {
+        PrefixedIdentifier prefixed = typeNameIdentifier;
+        // new prefix.ClassName()
+        if (prefixed.prefix.staticElement is PrefixElement) {
+          return prefixed.identifier.name;
+        }
+        // new ClassName.constructorName()
+        return prefixed.prefix.name;
+      }
+    }
+  }
+  // strip known prefixes
+  if (name != null) {
+    for (int i = 0; i < _KNOWN_METHOD_NAME_PREFIXES.length; i++) {
+      String curr = _KNOWN_METHOD_NAME_PREFIXES[i];
+      if (name.startsWith(curr)) {
+        if (name == curr) {
+          return null;
+        } else if (isUpperCase(name.codeUnitAt(curr.length))) {
+          return name.substring(curr.length);
+        }
+      }
+    }
+  }
+  // done
+  return name;
+}
+
+
+String _getBaseNameFromLocationInParent(Expression expression) {
+  // value in named expression
+  if (expression.parent is NamedExpression) {
+    NamedExpression namedExpression = expression.parent as NamedExpression;
+    if (identical(namedExpression.expression, expression)) {
+      return namedExpression.name.label.name;
+    }
+  }
+  // positional argument
+  {
+    ParameterElement parameter = expression.propagatedParameterElement;
+    if (parameter == null) {
+      parameter = expression.staticParameterElement;
+    }
+    if (parameter != null) {
+      return parameter.displayName;
+    }
+  }
+  // unknown
+  return null;
+}
+
+/**
+ * Returns all variants of names by removing leading words one by one.
+ */
+List<String> _getCamelWordCombinations(String name) {
+  List<String> result = [];
+  List<String> parts = getCamelWords(name);
+  for (int i = 0; i < parts.length; i++) {
+    var s1 = parts[i].toLowerCase();
+    var s2 = parts.skip(i + 1).join();
+    String suggestion = '$s1$s2';
+    result.add(suggestion);
+  }
+  return result;
+}
diff --git a/pkg/analysis_services/lib/src/correction/source_buffer.dart b/pkg/analysis_services/lib/src/correction/source_buffer.dart
new file mode 100644
index 0000000..fb9e204
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/source_buffer.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.source_buffer;
+
+import 'package:analysis_services/correction/change.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+
+/**
+ * Helper for building Dart source with linked positions.
+ */
+class SourceBuilder {
+  final String file;
+  final int offset;
+  final StringBuffer _buffer = new StringBuffer();
+
+  final List<LinkedPositionGroup> linkedPositionGroups = <LinkedPositionGroup>[
+      ];
+  LinkedPositionGroup _currentLinkedPositionGroup;
+  int _currentPositionStart;
+
+  SourceBuilder(this.file, this.offset);
+
+  void addProposal(String proposal) {
+    // TODO(scheglov) implement
+//    _currentPositionGroup.addProposal();
+  }
+
+  void addProposals(List<String> proposals) {
+    proposals.forEach((proposal) => addProposal(proposal));
+  }
+
+  /**
+   * Appends [s] to the buffer.
+   */
+  SourceBuilder append(String s) {
+    _buffer.write(s);
+    return this;
+  }
+
+  /**
+   * Ends position started using [startPosition].
+   */
+  void endPosition() {
+    assert(_currentLinkedPositionGroup != null);
+    _addPosition();
+    _currentLinkedPositionGroup = null;
+  }
+
+  /**
+   * Marks start of a new linked position for the group with the given ID.
+   */
+  void startPosition(String groupId) {
+    assert(_currentLinkedPositionGroup == null);
+    for (LinkedPositionGroup position in linkedPositionGroups) {
+      if (position.id == groupId) {
+        _currentLinkedPositionGroup = position;
+        break;
+      }
+    }
+    if (_currentLinkedPositionGroup == null) {
+      _currentLinkedPositionGroup = new LinkedPositionGroup(groupId);
+      linkedPositionGroups.add(_currentLinkedPositionGroup);
+    }
+    _currentPositionStart = _buffer.length;
+  }
+
+  @override
+  String toString() => _buffer.toString();
+
+  /**
+   * Adds position location [SourceRange] using current fields.
+   */
+  void _addPosition() {
+    int start = offset + _currentPositionStart;
+    int end = offset + _buffer.length;
+    Position position = new Position(file, start, end - start);
+    _currentLinkedPositionGroup.add(position);
+  }
+}
diff --git a/pkg/analysis_services/lib/correction/source_range_factory.dart b/pkg/analysis_services/lib/src/correction/source_range.dart
similarity index 81%
rename from pkg/analysis_services/lib/correction/source_range_factory.dart
rename to pkg/analysis_services/lib/src/correction/source_range.dart
index 4637ed8..433d5e6 100644
--- a/pkg/analysis_services/lib/correction/source_range_factory.dart
+++ b/pkg/analysis_services/lib/src/correction/source_range.dart
@@ -5,7 +5,7 @@
 // This code was auto-generated, is not intended to be edited, and is subject to
 // significant change. Please see the README file for more information.
 
-library services.correction.source_range_factory;
+library services.src.correction.source_range_factory;
 
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
@@ -24,10 +24,6 @@
   return new SourceRange(offset, length);
 }
 
-SourceRange rangeEndLength(a, int length) {
-  return new SourceRange(a.nameOffset, length);
-}
-
 SourceRange rangeEndStart(a, b) {
   int offset = a.end;
   var length = b.offset - offset;
@@ -52,22 +48,23 @@
 }
 
 SourceRange rangeStartEnd(a, b) {
-  int offset = a.offset;
-  var length = b.end - offset;
+  int offset = a is int ? a : a.offset;
+  int end = b is int ? b : b.end;
+  var length = end - offset;
   return new SourceRange(offset, length);
 }
 
 SourceRange rangeStartLength(a, int length) {
-  int offset = a.offset;
+  int offset = a is int ? a : a.offset;
   return new SourceRange(offset, length);
 }
 
 SourceRange rangeStartStart(a, b) {
-  int offset = a.offset;
-  var length = b.offset - offset;
+  int offset = a is int ? a : a.offset;
+  var length = (b is int ? b : b.offset) - offset;
   return new SourceRange(offset, length);
 }
 
-SourceRange rangeToken(Token node) {
-  return new SourceRange(node.offset, node.length);
+SourceRange rangeToken(Token token) {
+  return new SourceRange(token.offset, token.length);
 }
diff --git a/pkg/analysis_services/lib/src/correction/strings.dart b/pkg/analysis_services/lib/src/correction/strings.dart
new file mode 100644
index 0000000..14887cc
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/strings.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.strings;
+
+
+String capitalize(String str) {
+  if (isEmpty(str)) {
+    return str;
+  }
+  return str.substring(0, 1).toUpperCase() + str.substring(1);
+}
+
+bool isDigit(int c) {
+  return c >= 0x30 && c <= 0x39;
+}
+
+bool isEmpty(String str) {
+  return str == null || str.isEmpty;
+}
+
+bool isLetter(int c) {
+  return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
+}
+
+bool isLowerCase(int c) {
+  return c >= 0x61 && c <= 0x7A;
+}
+
+bool isSpace(int c) => c == 0x20 || c == 0x09;
+
+bool isUpperCase(int c) {
+  return c >= 0x41 && c <= 0x5A;
+}
+
+bool isWhitespace(int c) {
+  return isSpace(c) || c == 0x0D || c == 0x0A;
+}
+
+String remove(String str, String remove) {
+  if (isEmpty(str) || isEmpty(remove)) {
+    return str;
+  }
+  return str.replaceAll(remove, '');
+}
+
+String removeStart(String str, String remove) {
+  if (isEmpty(str) || isEmpty(remove)) {
+    return str;
+  }
+  if (str.startsWith(remove)) {
+    return str.substring(remove.length);
+  }
+  return str;
+}
+
+String repeat(String s, int n) {
+  StringBuffer sb = new StringBuffer();
+  for (int i = 0; i < n; i++) {
+    sb.write(s);
+  }
+  return sb.toString();
+}
diff --git a/pkg/analysis_services/lib/src/correction/util.dart b/pkg/analysis_services/lib/src/correction/util.dart
new file mode 100644
index 0000000..e868a0f
--- /dev/null
+++ b/pkg/analysis_services/lib/src/correction/util.dart
@@ -0,0 +1,282 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library services.src.correction.util;
+
+import 'package:analysis_services/src/correction/source_range.dart';
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+
+String getDefaultValueCode(DartType type) {
+  if (type != null) {
+    String typeName = type.displayName;
+    if (typeName == "bool") {
+      return "false";
+    }
+    if (typeName == "int") {
+      return "0";
+    }
+    if (typeName == "double") {
+      return "0.0";
+    }
+    if (typeName == "String") {
+      return "''";
+    }
+  }
+  // no better guess
+  return "null";
+}
+
+
+/**
+ * Returns [getExpressionPrecedence] for the parent of [node],
+ * or `0` if the parent node is [ParenthesizedExpression].
+ *
+ * The reason is that `(expr)` is always executed after `expr`.
+ */
+int getExpressionParentPrecedence(AstNode node) {
+  AstNode parent = node.parent;
+  if (parent is ParenthesizedExpression) {
+    return 0;
+  }
+  return getExpressionPrecedence(parent);
+}
+
+
+/**
+ * Returns the precedence of [node] it is an [Expression], negative otherwise.
+ */
+int getExpressionPrecedence(AstNode node) {
+  if (node is Expression) {
+    return node.precedence;
+  }
+  return -1000;
+}
+
+
+/**
+ * Returns the namespace of the given [ImportElement].
+ */
+Map<String, Element> getImportNamespace(ImportElement imp) {
+  NamespaceBuilder builder = new NamespaceBuilder();
+  Namespace namespace = builder.createImportNamespaceForDirective(imp);
+  return namespace.definedNames;
+}
+
+
+class CorrectionUtils {
+  final CompilationUnit unit;
+
+  LibraryElement _library;
+  String _buffer;
+  String _endOfLine;
+
+  CorrectionUtils(this.unit) {
+    CompilationUnitElement unitElement = unit.element;
+    this._library = unitElement.library;
+    this._buffer = unitElement.context.getContents(unitElement.source).data;
+  }
+
+  /**
+   * Returns the EOL to use for this [CompilationUnit].
+   */
+  String get endOfLine {
+    if (_endOfLine == null) {
+      if (_buffer.contains("\r\n")) {
+        _endOfLine = "\r\n";
+      } else {
+        _endOfLine = "\n";
+      }
+    }
+    return _endOfLine;
+  }
+
+  /**
+   * Skips whitespace characters and single EOL on the right from [index].
+   *
+   * If [index] the end of a statement or method, then in the most cases it is
+   * a start of the next line.
+   */
+  int getLineContentEnd(int index) {
+    int length = _buffer.length;
+    // skip whitespace characters
+    while (index < length) {
+      int c = _buffer.codeUnitAt(index);
+      if (!isWhitespace(c) || c == 0x0D || c == 0x0A) {
+        break;
+      }
+      index++;
+    }
+    // skip single \r
+    if (index < length && _buffer.codeUnitAt(index) == 0x0D) {
+      index++;
+    }
+    // skip single \n
+    if (index < length && _buffer.codeUnitAt(index) == 0x0A) {
+      index++;
+    }
+    // done
+    return index;
+  }
+
+  /**
+   * Skips spaces and tabs on the left from [index].
+   *
+   * If [index] is the start or a statement, then in the most cases it is a
+   * start on its line.
+   */
+  int getLineContentStart(int index) {
+    while (index > 0) {
+      int c = _buffer.codeUnitAt(index - 1);
+      if (!isSpace(c)) {
+        break;
+      }
+      index--;
+    }
+    return index;
+  }
+
+  /**
+   * Returns a [SourceRange] that covers [range] and extends (if possible) to
+   * cover whole lines.
+   */
+  SourceRange getLinesRange(SourceRange range) {
+    // start
+    int startOffset = range.offset;
+    int startLineOffset = getLineContentStart(startOffset);
+    // end
+    int endOffset = range.end;
+    int afterEndLineOffset = getLineContentEnd(endOffset);
+    // range
+    return rangeStartEnd(startLineOffset, afterEndLineOffset);
+  }
+
+  /**
+   * @return the source for the parameter with the given type and name.
+   */
+  String getParameterSource(DartType type, String name) {
+    // no type
+    if (type == null || type.isDynamic) {
+      return name;
+    }
+    // function type
+    if (type is FunctionType) {
+      FunctionType functionType = type;
+      StringBuffer sb = new StringBuffer();
+      // return type
+      DartType returnType = functionType.returnType;
+      if (returnType != null && !returnType.isDynamic) {
+        sb.write(getTypeSource(returnType));
+        sb.write(' ');
+      }
+      // parameter name
+      sb.write(name);
+      // parameters
+      sb.write('(');
+      List<ParameterElement> fParameters = functionType.parameters;
+      for (int i = 0; i < fParameters.length; i++) {
+        ParameterElement fParameter = fParameters[i];
+        if (i != 0) {
+          sb.write(", ");
+        }
+        sb.write(getParameterSource(fParameter.type, fParameter.name));
+      }
+      sb.write(')');
+      // done
+      return sb.toString();
+    }
+    // simple type
+    return "${getTypeSource(type)} ${name}";
+  }
+
+  /**
+   * Returns the actual type source of the given [Expression], may be `null`
+   * if can not be resolved, should be treated as the `dynamic` type.
+   */
+  String getExpressionTypeSource(Expression expression) {
+    if (expression == null) {
+      return null;
+    }
+    DartType type = expression.bestType;
+    String typeSource = getTypeSource(type);
+    if ("dynamic" == typeSource) {
+      return null;
+    }
+    return typeSource;
+  }
+
+  /**
+   * Returns the source to reference [type] in this [CompilationUnit].
+   */
+  String getTypeSource(DartType type) {
+    StringBuffer sb = new StringBuffer();
+    // prepare element
+    Element element = type.element;
+    if (element == null) {
+      String source = type.toString();
+      source = source.replaceAll('<dynamic>', '');
+      source = source.replaceAll('<dynamic, dynamic>', '');
+      return source;
+    }
+    // append prefix
+    {
+      ImportElement imp = _getImportElement(element);
+      if (imp != null && imp.prefix != null) {
+        sb.write(imp.prefix.displayName);
+        sb.write(".");
+      }
+    }
+    // append simple name
+    String name = element.displayName;
+    sb.write(name);
+    // may be type arguments
+    if (type is InterfaceType) {
+      InterfaceType interfaceType = type;
+      List<DartType> arguments = interfaceType.typeArguments;
+      // check if has arguments
+      bool hasArguments = false;
+      for (DartType argument in arguments) {
+        if (!argument.isDynamic) {
+          hasArguments = true;
+          break;
+        }
+      }
+      // append type arguments
+      if (hasArguments) {
+        sb.write("<");
+        for (int i = 0; i < arguments.length; i++) {
+          DartType argument = arguments[i];
+          if (i != 0) {
+            sb.write(", ");
+          }
+          sb.write(getTypeSource(argument));
+        }
+        sb.write(">");
+      }
+    }
+    // done
+    return sb.toString();
+  }
+
+  /**
+   * @return the [ImportElement] used to import given [Element] into [library].
+   *         May be `null` if was not imported, i.e. declared in the same library.
+   */
+  ImportElement _getImportElement(Element element) {
+    for (ImportElement imp in _library.imports) {
+      Map<String, Element> definedNames = getImportNamespace(imp);
+      if (definedNames.containsValue(element)) {
+        return imp;
+      }
+    }
+    return null;
+  }
+}
diff --git a/pkg/analysis_services/lib/src/generated/completion.dart b/pkg/analysis_services/lib/src/generated/completion.dart
index a49b805..513fe14 100644
--- a/pkg/analysis_services/lib/src/generated/completion.dart
+++ b/pkg/analysis_services/lib/src/generated/completion.dart
@@ -23,6 +23,8 @@
 import 'stubs.dart';
 import 'util.dart';
 
+import '../../completion/completion_suggestion.dart';
+
 class AstNodeClassifier_CompletionEngine_typeOf extends CompletionEngine_AstNodeClassifier {
   final CompletionEngine CompletionEngine_this;
 
@@ -159,7 +161,7 @@
     VariableDeclarationList varList = varDecl.parent as VariableDeclarationList;
     TypeName type = varList.type;
     if (identifier.length > 0) {
-      _pName3(identifier.name, ProposalKind.VARIABLE);
+      _pName3(identifier.name, CompletionSuggestionKind.VARIABLE);
     }
     if (type == null) {
       if (varList.keyword == null) {
@@ -189,7 +191,7 @@
     ClassDeclaration classDecl = fieldName.getAncestor((node) => node is ClassDeclaration);
     ClassElement classElement = classDecl.element;
     for (FieldElement field in classElement.fields) {
-      _pName3(field.displayName, ProposalKind.FIELD);
+      _pName3(field.displayName, CompletionSuggestionKind.FIELD);
     }
   }
 
@@ -269,7 +271,7 @@
         continue;
       }
       // OK, add proposal
-      CompletionProposal prop = _createProposal4(ProposalKind.NAMED_ARGUMENT);
+      CompletionProposal prop = _createProposal4(CompletionSuggestionKind.NAMED_ARGUMENT);
       prop.setCompletion(parameterName);
       prop.setParameterName(parameterName);
       prop.setParameterType(parameterElement.type.displayName);
@@ -319,7 +321,7 @@
       ParameterElement parameter = parameters[argIndex];
       if (parameter.parameterKind != ParameterKind.NAMED) {
         String parameterName = parameter.displayName;
-        CompletionProposal prop = _createProposal4(ProposalKind.OPTIONAL_ARGUMENT);
+        CompletionProposal prop = _createProposal4(CompletionSuggestionKind.OPTIONAL_ARGUMENT);
         prop.setCompletion(parameterName);
         prop.setParameterName(parameterName);
         prop.setParameterType(parameter.type.displayName);
@@ -587,7 +589,7 @@
       if (_filterDisallows2(uri)) {
         continue;
       }
-      CompletionProposal prop = _createProposal4(ProposalKind.IMPORT);
+      CompletionProposal prop = _createProposal4(CompletionSuggestionKind.IMPORT);
       prop.setCompletion(uri);
       // put "lib" before "lib/src"
       if (!uri.contains("/src/")) {
@@ -668,7 +670,7 @@
         continue;
       }
       // add with "dart:" prefix
-      _pName3("dart:${name}", ProposalKind.IMPORT);
+      _pName3("dart:${name}", CompletionSuggestionKind.IMPORT);
     }
   }
 
@@ -770,7 +772,7 @@
   }
 
   CompletionProposal _createProposal3(Element element, String completion) {
-    ProposalKind kind = _proposalKindOf(element);
+    CompletionSuggestionKind kind = _proposalKindOf(element);
     CompletionProposal prop = _createProposal4(kind);
     prop.setElement(element);
     prop.setCompletion(completion);
@@ -784,7 +786,7 @@
     return prop;
   }
 
-  CompletionProposal _createProposal4(ProposalKind kind) => _factory.createCompletionProposal(kind, _completionTokenOffset());
+  CompletionProposal _createProposal4(CompletionSuggestionKind kind) => _factory.createCompletionProposal(kind, _completionTokenOffset());
 
   List<LibraryElement> _currentLibraryList() {
     Set<LibraryElement> libraries = new Set<LibraryElement>();
@@ -1007,7 +1009,7 @@
       return;
     }
     // fill arguments proposal
-    CompletionProposal prop = _createProposal4(ProposalKind.ARGUMENT_LIST);
+    CompletionProposal prop = _createProposal4(CompletionSuggestionKind.ARGUMENT_LIST);
     prop.setElement(proposal.element);
     prop.setCompletion(proposal.completion).setReturnType(proposal.returnType);
     prop.setParameterNames(parameterNames);
@@ -1019,7 +1021,7 @@
   }
 
   void _pDynamic() {
-    _pWord(_C_DYNAMIC, ProposalKind.VARIABLE);
+    _pWord(_C_DYNAMIC, CompletionSuggestionKind.VARIABLE);
   }
 
   void _pExecutable(Element element, FunctionType functionType, SimpleIdentifier identifier, bool isPotentialMatch) {
@@ -1039,7 +1041,7 @@
       DartType parameterType = _state._targetParameter.type;
       if (parameterType is FunctionType) {
         if (functionType.isAssignableTo(parameterType)) {
-          _pName2(name, element, CompletionProposal.RELEVANCE_HIGH, ProposalKind.METHOD_NAME);
+          _pName2(name, element, CompletionProposal.RELEVANCE_HIGH, CompletionSuggestionKind.METHOD_NAME);
         }
       }
     }
@@ -1052,7 +1054,7 @@
     prop.setCompletion(name).setReturnType(functionType.returnType.displayName);
     // If there is already argument list, then update only method name.
     if (identifier.parent is MethodInvocation && (identifier.parent as MethodInvocation).argumentList != null) {
-      prop.setKind(ProposalKind.METHOD_NAME);
+      prop.setKind(CompletionSuggestionKind.METHOD_NAME);
     }
     Element container = element.enclosingElement;
     if (container != null) {
@@ -1086,7 +1088,7 @@
   }
 
   void _pFalse() {
-    _pWord(_C_FALSE, ProposalKind.VARIABLE);
+    _pWord(_C_FALSE, CompletionSuggestionKind.VARIABLE);
   }
 
   void _pField(FieldElement element, SimpleIdentifier identifier, ClassElement classElement) {
@@ -1114,7 +1116,7 @@
     if (_context.selectionOffset == node.keyword.end) {
       newUri = " ${newUri}";
     }
-    _pName3(newUri, ProposalKind.IMPORT);
+    _pName3(newUri, CompletionSuggestionKind.IMPORT);
   }
 
   void _pKeyword(Token keyword) {
@@ -1122,7 +1124,7 @@
     // This isn't as useful as it might seem. It only works in the case that completion
     // is requested on an existing recognizable keyword.
     // TODO: Add keyword proposal kind
-    CompletionProposal prop = _createProposal4(ProposalKind.LIBRARY_PREFIX);
+    CompletionProposal prop = _createProposal4(CompletionSuggestionKind.LIBRARY_PREFIX);
     prop.setCompletion(keyword.lexeme);
     _requestor.accept(prop);
   }
@@ -1134,7 +1136,7 @@
     }
   }
 
-  void _pName2(String name, Element element, int relevance, ProposalKind kind) {
+  void _pName2(String name, Element element, int relevance, CompletionSuggestionKind kind) {
     if (_filterDisallows2(name)) {
       return;
     }
@@ -1145,7 +1147,7 @@
     _requestor.accept(prop);
   }
 
-  void _pName3(String name, ProposalKind kind) {
+  void _pName3(String name, CompletionSuggestionKind kind) {
     if (_filterDisallows2(name)) {
       return;
     }
@@ -1175,47 +1177,47 @@
   }
 
   void _pNull() {
-    _pWord(_C_NULL, ProposalKind.VARIABLE);
+    _pWord(_C_NULL, CompletionSuggestionKind.VARIABLE);
   }
 
   void _pParamName(String name) {
     if (_filterDisallows2(name)) {
       return;
     }
-    CompletionProposal prop = _createProposal4(ProposalKind.PARAMETER);
+    CompletionProposal prop = _createProposal4(CompletionSuggestionKind.PARAMETER);
     prop.setCompletion(name);
     _requestor.accept(prop);
   }
 
-  ProposalKind _proposalKindOf(Element element) {
-    ProposalKind kind;
+  CompletionSuggestionKind _proposalKindOf(Element element) {
+    CompletionSuggestionKind kind;
     while (true) {
       if (element.kind == ElementKind.CONSTRUCTOR) {
-        kind = ProposalKind.CONSTRUCTOR;
+        kind = CompletionSuggestionKind.CONSTRUCTOR;
       } else if (element.kind == ElementKind.FUNCTION) {
-        kind = ProposalKind.FUNCTION;
+        kind = CompletionSuggestionKind.FUNCTION;
       } else if (element.kind == ElementKind.METHOD) {
-        kind = ProposalKind.METHOD;
+        kind = CompletionSuggestionKind.METHOD;
       } else if (element.kind == ElementKind.GETTER) {
-        kind = ProposalKind.GETTER;
+        kind = CompletionSuggestionKind.GETTER;
       } else if (element.kind == ElementKind.SETTER) {
-        kind = ProposalKind.SETTER;
+        kind = CompletionSuggestionKind.SETTER;
       } else if (element.kind == ElementKind.CLASS) {
-        kind = ProposalKind.CLASS;
+        kind = CompletionSuggestionKind.CLASS;
       } else if (element.kind == ElementKind.FIELD) {
-        kind = ProposalKind.FIELD;
+        kind = CompletionSuggestionKind.FIELD;
       } else if (element.kind == ElementKind.IMPORT) {
-        kind = ProposalKind.IMPORT;
+        kind = CompletionSuggestionKind.IMPORT;
       } else if (element.kind == ElementKind.PARAMETER) {
-        kind = ProposalKind.PARAMETER;
+        kind = CompletionSuggestionKind.PARAMETER;
       } else if (element.kind == ElementKind.PREFIX) {
-        kind = ProposalKind.LIBRARY_PREFIX;
+        kind = CompletionSuggestionKind.LIBRARY_PREFIX;
       } else if (element.kind == ElementKind.FUNCTION_TYPE_ALIAS) {
-        kind = ProposalKind.CLASS_ALIAS;
+        kind = CompletionSuggestionKind.CLASS_ALIAS;
       } else if (element.kind == ElementKind.TYPE_PARAMETER) {
-        kind = ProposalKind.TYPE_PARAMETER;
+        kind = CompletionSuggestionKind.TYPE_PARAMETER;
       } else if (element.kind == ElementKind.LOCAL_VARIABLE || element.kind == ElementKind.TOP_LEVEL_VARIABLE) {
-        kind = ProposalKind.VARIABLE;
+        kind = CompletionSuggestionKind.VARIABLE;
       } else {
         throw new IllegalArgumentException();
       }
@@ -1241,8 +1243,8 @@
       // propose each Element
       for (Element element in nameCollector.uniqueElements) {
         CompletionProposal proposal = _createProposal(element);
-        if (proposal.kind == ProposalKind.FUNCTION) {
-          proposal.setKind(ProposalKind.METHOD_NAME);
+        if (proposal.kind == CompletionSuggestionKind.FUNCTION) {
+          proposal.setKind(CompletionSuggestionKind.METHOD_NAME);
         }
         _requestor.accept(proposal);
       }
@@ -1277,18 +1279,18 @@
   }
 
   void _pTrue() {
-    _pWord(_C_TRUE, ProposalKind.VARIABLE);
+    _pWord(_C_TRUE, CompletionSuggestionKind.VARIABLE);
   }
 
   void _pVar() {
-    _pWord(_C_VAR, ProposalKind.VARIABLE);
+    _pWord(_C_VAR, CompletionSuggestionKind.VARIABLE);
   }
 
   void _pVoid() {
-    _pWord(_C_VOID, ProposalKind.VARIABLE);
+    _pWord(_C_VOID, CompletionSuggestionKind.VARIABLE);
   }
 
-  void _pWord(String word, ProposalKind kind) {
+  void _pWord(String word, CompletionSuggestionKind kind) {
     if (_filterDisallows2(word)) {
       return;
     }
@@ -1473,7 +1475,7 @@
       if (proposal != null) {
         // we don't want to add arguments, just names
         if (element is MethodElement || element is FunctionElement) {
-          proposal.setKind(ProposalKind.METHOD_NAME);
+          proposal.setKind(CompletionSuggestionKind.METHOD_NAME);
         }
         // elevate priority for local elements
         if (_enclosingElements.contains(element.enclosingElement)) {
@@ -1590,7 +1592,7 @@
   Object visitConstructorDeclaration(ConstructorDeclaration node) {
     if (identical(node.returnType, _completionNode)) {
       CompletionEngine_this._filter = CompletionEngine_this._createFilter(_completionNode);
-      CompletionEngine_this._pName3(_completionNode.name, ProposalKind.CONSTRUCTOR);
+      CompletionEngine_this._pName3(_completionNode.name, CompletionSuggestionKind.CONSTRUCTOR);
     }
     return null;
   }
@@ -2849,7 +2851,7 @@
   /**
    * Create a completion proposal of the given kind.
    */
-  CompletionProposal createCompletionProposal(ProposalKind kind, int insertionPoint) {
+  CompletionProposal createCompletionProposal(CompletionSuggestionKind kind, int insertionPoint) {
     CompletionProposalImpl prop = new CompletionProposalImpl();
     prop.setKind(kind);
     prop.setLocation(insertionPoint);
@@ -2877,7 +2879,7 @@
 
   Element get element;
 
-  ProposalKind get kind;
+  CompletionSuggestionKind get kind;
 
   int get location;
 
@@ -2917,7 +2919,7 @@
 
   CompletionProposal setElement(Element element);
 
-  CompletionProposal setKind(ProposalKind x);
+  CompletionProposal setKind(CompletionSuggestionKind x);
 
   CompletionProposal setLocation(int x);
 
@@ -2959,7 +2961,7 @@
 
   String _parameterType;
 
-  ProposalKind _kind = ProposalKind.NONE;
+  CompletionSuggestionKind _kind = null;
 
   int _location = 0;
 
@@ -2994,7 +2996,7 @@
   Element get element => _element;
 
   @override
-  ProposalKind get kind => _kind;
+  CompletionSuggestionKind get kind => _kind;
 
   @override
   int get location => _location;
@@ -3072,7 +3074,7 @@
   }
 
   @override
-  CompletionProposal setKind(ProposalKind x) {
+  CompletionProposal setKind(CompletionSuggestionKind x) {
     _kind = x;
     return this;
   }
@@ -3667,73 +3669,6 @@
   List<CompletionProposal> get proposals => _proposals;
 }
 
-/**
- * The various kinds of completion proposals. Each specifies the kind of completion to be created,
- * corresponding to different syntactical elements.
- */
-class ProposalKind extends Enum<ProposalKind> {
-  static const ProposalKind NONE = const ProposalKind('NONE', 0);
-
-  static const ProposalKind CLASS = const ProposalKind('CLASS', 1);
-
-  static const ProposalKind CLASS_ALIAS = const ProposalKind('CLASS_ALIAS', 2);
-
-  static const ProposalKind CONSTRUCTOR = const ProposalKind('CONSTRUCTOR', 3);
-
-  static const ProposalKind FIELD = const ProposalKind('FIELD', 4);
-
-  static const ProposalKind FUNCTION = const ProposalKind('FUNCTION', 5);
-
-  static const ProposalKind FUNCTION_ALIAS = const ProposalKind('FUNCTION_ALIAS', 6);
-
-  static const ProposalKind GETTER = const ProposalKind('GETTER', 7);
-
-  static const ProposalKind IMPORT = const ProposalKind('IMPORT', 8);
-
-  static const ProposalKind LIBRARY_PREFIX = const ProposalKind('LIBRARY_PREFIX', 9);
-
-  static const ProposalKind METHOD = const ProposalKind('METHOD', 10);
-
-  static const ProposalKind METHOD_NAME = const ProposalKind('METHOD_NAME', 11);
-
-  static const ProposalKind PARAMETER = const ProposalKind('PARAMETER', 12);
-
-  static const ProposalKind SETTER = const ProposalKind('SETTER', 13);
-
-  static const ProposalKind VARIABLE = const ProposalKind('VARIABLE', 14);
-
-  static const ProposalKind TYPE_PARAMETER = const ProposalKind('TYPE_PARAMETER', 15);
-
-  static const ProposalKind ARGUMENT_LIST = const ProposalKind('ARGUMENT_LIST', 16);
-
-  static const ProposalKind OPTIONAL_ARGUMENT = const ProposalKind('OPTIONAL_ARGUMENT', 17);
-
-  static const ProposalKind NAMED_ARGUMENT = const ProposalKind('NAMED_ARGUMENT', 18);
-
-  static const List<ProposalKind> values = const [
-      NONE,
-      CLASS,
-      CLASS_ALIAS,
-      CONSTRUCTOR,
-      FIELD,
-      FUNCTION,
-      FUNCTION_ALIAS,
-      GETTER,
-      IMPORT,
-      LIBRARY_PREFIX,
-      METHOD,
-      METHOD_NAME,
-      PARAMETER,
-      SETTER,
-      VARIABLE,
-      TYPE_PARAMETER,
-      ARGUMENT_LIST,
-      OPTIONAL_ARGUMENT,
-      NAMED_ARGUMENT];
-
-  const ProposalKind(String name, int ordinal) : super(name, ordinal);
-}
-
 class SearchFilter_CompletionEngine_allSubtypes implements SearchFilter {
   ClassElement classElement;
 
diff --git a/pkg/analysis_services/test/correction/change_test.dart b/pkg/analysis_services/test/correction/change_test.dart
new file mode 100644
index 0000000..d0fd91e
--- /dev/null
+++ b/pkg/analysis_services/test/correction/change_test.dart
@@ -0,0 +1,447 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.change;
+
+import 'package:analysis_services/constants.dart';
+import 'package:analysis_services/correction/change.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart';
+
+
+main() {
+  groupSep = ' | ';
+  group('ChangeTest', () {
+    runReflectiveTests(ChangeTest);
+  });
+  group('EditTest', () {
+    runReflectiveTests(EditTest);
+  });
+  group('FileEditTest', () {
+    runReflectiveTests(FileEditTest);
+  });
+  group('LinkedPositionGroupTest', () {
+    runReflectiveTests(LinkedPositionGroupTest);
+  });
+  group('PositionTest', () {
+    runReflectiveTests(PositionTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class ChangeTest {
+//  void test_fromJson() {
+//    var json = {
+//      OFFSET: 1,
+//      LENGTH: 2,
+//      REPLACEMENT: 'foo'
+//    };
+//    Edit edit = Edit.fromJson(json);
+//    expect(edit.offset, 1);
+//    expect(edit.length, 2);
+//    expect(edit.replacement, 'foo');
+//  }
+
+  void test_fromJson() {
+    var json = {
+      MESSAGE: 'msg',
+      EDITS: [{
+          FILE: '/a.dart',
+          EDITS: [{
+              OFFSET: 1,
+              LENGTH: 2,
+              REPLACEMENT: 'aaa'
+            }, {
+              OFFSET: 10,
+              LENGTH: 20,
+              REPLACEMENT: 'bbb'
+            }]
+        }, {
+          FILE: '/b.dart',
+          EDITS: [{
+              OFFSET: 21,
+              LENGTH: 22,
+              REPLACEMENT: 'xxx'
+            }, {
+              OFFSET: 210,
+              LENGTH: 220,
+              REPLACEMENT: 'yyy'
+            }]
+        }],
+      LINKED_POSITION_GROUPS: [{
+          ID: 'id-a',
+          POSITIONS: [{
+              FILE: '/ga.dart',
+              OFFSET: 1,
+              LENGTH: 2
+            }, {
+              FILE: '/ga.dart',
+              OFFSET: 10,
+              LENGTH: 2
+            }]
+        }, {
+          ID: 'id-b',
+          POSITIONS: [{
+              FILE: '/gb.dart',
+              OFFSET: 10,
+              LENGTH: 5
+            }, {
+              FILE: '/gb.dart',
+              OFFSET: 100,
+              LENGTH: 5
+            }]
+        }]
+    };
+    Change change = Change.fromJson(json);
+    expect(change.message, 'msg');
+    // edits
+    expect(change.edits, hasLength(2));
+    {
+      FileEdit fileEdit = change.edits[0];
+      expect(fileEdit.file, '/a.dart');
+      expect(fileEdit.edits, hasLength(2));
+      expect(fileEdit.edits[0], new Edit(1, 2, 'aaa'));
+      expect(fileEdit.edits[1], new Edit(10, 20, 'bbb'));
+    }
+    {
+      FileEdit fileEdit = change.edits[1];
+      expect(fileEdit.file, '/b.dart');
+      expect(fileEdit.edits, hasLength(2));
+      expect(fileEdit.edits[0], new Edit(21, 22, 'xxx'));
+      expect(fileEdit.edits[1], new Edit(210, 220, 'yyy'));
+    }
+    // linked position groups
+    expect(change.linkedPositionGroups, hasLength(2));
+    {
+      LinkedPositionGroup group = change.linkedPositionGroups[0];
+      expect(group.id, 'id-a');
+      expect(group.positions, hasLength(2));
+      expect(group.positions[0], new Position('/ga.dart', 1, 2));
+      expect(group.positions[1], new Position('/ga.dart', 10, 2));
+    }
+    {
+      LinkedPositionGroup group = change.linkedPositionGroups[1];
+      expect(group.id, 'id-b');
+      expect(group.positions, hasLength(2));
+      expect(group.positions[0], new Position('/gb.dart', 10, 5));
+      expect(group.positions[1], new Position('/gb.dart', 100, 5));
+    }
+  }
+
+  void test_new() {
+    Change change = new Change('msg');
+    change.add(new FileEdit('/a.dart')
+        ..add(new Edit(1, 2, 'aaa'))
+        ..add(new Edit(10, 20, 'bbb')));
+    change.add(new FileEdit('/b.dart')
+        ..add(new Edit(21, 22, 'xxx'))
+        ..add(new Edit(210, 220, 'yyy')));
+    change.addLinkedPositionGroup(new LinkedPositionGroup('id-a')
+        ..add(new Position('/ga.dart', 1, 2))
+        ..add(new Position('/ga.dart', 10, 2)));
+    change.addLinkedPositionGroup(new LinkedPositionGroup('id-b')
+        ..add(new Position('/gb.dart', 10, 5))
+        ..add(new Position('/gb.dart', 100, 5)));
+    expect(
+        change.toString(),
+        'Change(message=msg, edits=[FileEdit(file=/a.dart, edits=['
+            'Edit(offset=1, length=2, replacement=:>aaa<:), '
+            'Edit(offset=10, length=20, replacement=:>bbb<:)]), '
+            'FileEdit(file=/b.dart, edits=['
+            'Edit(offset=21, length=22, replacement=:>xxx<:), '
+            'Edit(offset=210, length=220, replacement=:>yyy<:)])], '
+            'linkedPositionGroups=[' 'LinkedPositionGroup(id=id-a, positions=['
+            'Position(file=/ga.dart, offset=1, length=2), '
+            'Position(file=/ga.dart, offset=10, length=2)]), '
+            'LinkedPositionGroup(id=id-b, positions=['
+            'Position(file=/gb.dart, offset=10, length=5), '
+            'Position(file=/gb.dart, offset=100, length=5)])])');
+  }
+
+  void test_toJson() {
+    Change change = new Change('msg');
+    change.add(new FileEdit('/a.dart')
+        ..add(new Edit(1, 2, 'aaa'))
+        ..add(new Edit(10, 20, 'bbb')));
+    change.add(new FileEdit('/b.dart')
+        ..add(new Edit(21, 22, 'xxx'))
+        ..add(new Edit(210, 220, 'yyy')));
+    change.addLinkedPositionGroup(new LinkedPositionGroup('id-a')
+        ..add(new Position('/ga.dart', 1, 2))
+        ..add(new Position('/ga.dart', 10, 2)));
+    change.addLinkedPositionGroup(new LinkedPositionGroup('id-b')
+        ..add(new Position('/gb.dart', 10, 5))
+        ..add(new Position('/gb.dart', 100, 5)));
+    var expectedJson = {
+      MESSAGE: 'msg',
+      EDITS: [{
+          FILE: '/a.dart',
+          EDITS: [{
+              OFFSET: 1,
+              LENGTH: 2,
+              REPLACEMENT: 'aaa'
+            }, {
+              OFFSET: 10,
+              LENGTH: 20,
+              REPLACEMENT: 'bbb'
+            }]
+        }, {
+          FILE: '/b.dart',
+          EDITS: [{
+              OFFSET: 21,
+              LENGTH: 22,
+              REPLACEMENT: 'xxx'
+            }, {
+              OFFSET: 210,
+              LENGTH: 220,
+              REPLACEMENT: 'yyy'
+            }]
+        }],
+      LINKED_POSITION_GROUPS: [{
+          ID: 'id-a',
+          POSITIONS: [{
+              FILE: '/ga.dart',
+              OFFSET: 1,
+              LENGTH: 2
+            }, {
+              FILE: '/ga.dart',
+              OFFSET: 10,
+              LENGTH: 2
+            }]
+        }, {
+          ID: 'id-b',
+          POSITIONS: [{
+              FILE: '/gb.dart',
+              OFFSET: 10,
+              LENGTH: 5
+            }, {
+              FILE: '/gb.dart',
+              OFFSET: 100,
+              LENGTH: 5
+            }]
+        }]
+    };
+    expect(change.toJson(), expectedJson);
+  }
+}
+
+
+@ReflectiveTestCase()
+class EditTest {
+  void test_end() {
+    Edit edit = new Edit(1, 2, 'foo');
+    expect(edit.end, 3);
+  }
+
+  void test_fromJson() {
+    var json = {
+      OFFSET: 1,
+      LENGTH: 2,
+      REPLACEMENT: 'foo'
+    };
+    Edit edit = Edit.fromJson(json);
+    expect(edit.offset, 1);
+    expect(edit.length, 2);
+    expect(edit.replacement, 'foo');
+  }
+
+  void test_new() {
+    Edit edit = new Edit(1, 2, 'foo');
+    expect(edit.offset, 1);
+    expect(edit.length, 2);
+    expect(edit.replacement, 'foo');
+    expect(edit.toString(), 'Edit(offset=1, length=2, replacement=:>foo<:)');
+  }
+
+  void test_toJson() {
+    Edit edit = new Edit(1, 2, 'foo');
+    var expectedJson = {
+      OFFSET: 1,
+      LENGTH: 2,
+      REPLACEMENT: 'foo'
+    };
+    expect(edit.toJson(), expectedJson);
+  }
+  void test_eqEq() {
+    Edit a = new Edit(1, 2, 'aaa');
+    Edit a2 = new Edit(1, 2, 'aaa');
+    Edit b = new Edit(1, 2, 'aaa');
+    expect(a == a, isTrue);
+    expect(a == new Edit(1, 2, 'aaa'), isTrue);
+    expect(a == this, isFalse);
+    expect(a == new Edit(1, 2, 'bbb'), isFalse);
+    expect(a == new Edit(10, 2, 'aaa'), isFalse);
+  }
+
+}
+
+
+@ReflectiveTestCase()
+class FileEditTest {
+  void test_fromJson() {
+    var json = {
+      FILE: '/test.dart',
+      EDITS: [{
+          OFFSET: 1,
+          LENGTH: 2,
+          REPLACEMENT: 'aaa'
+        }, {
+          OFFSET: 10,
+          LENGTH: 20,
+          REPLACEMENT: 'bbb'
+        },]
+    };
+    var fileEdit = FileEdit.fromJson(json);
+    expect(fileEdit.file, '/test.dart');
+    expect(fileEdit.edits, hasLength(2));
+    expect(fileEdit.edits[0], new Edit(1, 2, 'aaa'));
+    expect(fileEdit.edits[1], new Edit(10, 20, 'bbb'));
+  }
+
+  void test_new() {
+    FileEdit fileEdit = new FileEdit('/test.dart');
+    fileEdit.add(new Edit(1, 2, 'aaa'));
+    fileEdit.add(new Edit(10, 20, 'bbb'));
+    expect(
+        fileEdit.toString(),
+        'FileEdit(file=/test.dart, edits=['
+            'Edit(offset=1, length=2, replacement=:>aaa<:), '
+            'Edit(offset=10, length=20, replacement=:>bbb<:)])');
+  }
+
+  void test_toJson() {
+    FileEdit fileEdit = new FileEdit('/test.dart');
+    fileEdit.add(new Edit(1, 2, 'aaa'));
+    fileEdit.add(new Edit(10, 20, 'bbb'));
+    expect(fileEdit.toJson(), {
+      FILE: '/test.dart',
+      EDITS: [{
+          OFFSET: 1,
+          LENGTH: 2,
+          REPLACEMENT: 'aaa'
+        }, {
+          OFFSET: 10,
+          LENGTH: 20,
+          REPLACEMENT: 'bbb'
+        },]
+    });
+  }
+}
+
+
+@ReflectiveTestCase()
+class LinkedPositionGroupTest {
+  void test_addWrongLength() {
+    LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+    group.add(new Position('/a.dart', 1, 2));
+    expect(() {
+      group.add(new Position('/b.dart', 10, 20));
+    }, throws);
+  }
+
+  void test_fromJson() {
+    var json = {
+      ID: 'my-id',
+      POSITIONS: [{
+          FILE: '/a.dart',
+          OFFSET: 1,
+          LENGTH: 2
+        }, {
+          FILE: '/b.dart',
+          OFFSET: 10,
+          LENGTH: 2
+        }]
+    };
+    LinkedPositionGroup group = LinkedPositionGroup.fromJson(json);
+    expect(group.id, 'my-id');
+    expect(group.positions, hasLength(2));
+    expect(group.positions[0], new Position('/a.dart', 1, 2));
+    expect(group.positions[1], new Position('/b.dart', 10, 2));
+  }
+
+  void test_new() {
+    LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+    group.add(new Position('/a.dart', 1, 2));
+    group.add(new Position('/b.dart', 10, 2));
+    expect(
+        group.toString(),
+        'LinkedPositionGroup(id=my-id, positions=['
+            'Position(file=/a.dart, offset=1, length=2), '
+            'Position(file=/b.dart, offset=10, length=2)])');
+  }
+
+  void test_toJson() {
+    LinkedPositionGroup group = new LinkedPositionGroup('my-id');
+    group.add(new Position('/a.dart', 1, 2));
+    group.add(new Position('/b.dart', 10, 2));
+    var expectedJson = {
+      ID: 'my-id',
+      POSITIONS: [{
+          FILE: '/a.dart',
+          OFFSET: 1,
+          LENGTH: 2
+        }, {
+          FILE: '/b.dart',
+          OFFSET: 10,
+          LENGTH: 2
+        }]
+    };
+    expect(group.toJson(), expectedJson);
+  }
+}
+
+
+@ReflectiveTestCase()
+class PositionTest {
+  void test_eqEq() {
+    Position a = new Position('/a.dart', 1, 2);
+    Position a2 = new Position('/a.dart', 1, 2);
+    Position b = new Position('/b.dart', 1, 2);
+    expect(a == a, isTrue);
+    expect(a == a2, isTrue);
+    expect(a == b, isFalse);
+    expect(a == this, isFalse);
+  }
+
+  void test_fromJson() {
+    var json = {
+      FILE: '/test.dart',
+      OFFSET: 1,
+      LENGTH: 2
+    };
+    Position position = Position.fromJson(json);
+    expect(position.file, '/test.dart');
+    expect(position.offset, 1);
+    expect(position.length, 2);
+  }
+
+  void test_hashCode() {
+    Position position = new Position('/test.dart', 1, 2);
+    position.hashCode;
+  }
+
+  void test_new() {
+    Position position = new Position('/test.dart', 1, 2);
+    expect(position.file, '/test.dart');
+    expect(position.offset, 1);
+    expect(position.length, 2);
+    expect(
+        position.toString(),
+        'Position(file=/test.dart, offset=1, length=2)');
+  }
+
+  void test_toJson() {
+    Position position = new Position('/test.dart', 1, 2);
+    var expectedJson = {
+      FILE: '/test.dart',
+      OFFSET: 1,
+      LENGTH: 2
+    };
+    expect(position.toJson(), expectedJson);
+  }
+}
diff --git a/pkg/analysis_services/test/correction/fix_test.dart b/pkg/analysis_services/test/correction/fix_test.dart
index f7f6005..31f926a 100644
--- a/pkg/analysis_services/test/correction/fix_test.dart
+++ b/pkg/analysis_services/test/correction/fix_test.dart
@@ -12,12 +12,11 @@
 import 'package:analysis_services/index/index.dart';
 import 'package:analysis_services/index/local_memory_index.dart';
 import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:unittest/unittest.dart';
 
-import '../index/abstract_single_unit.dart';
-
 
 main() {
   groupSep = ' | ';
@@ -32,15 +31,56 @@
   Index index;
   SearchEngineImpl searchEngine;
 
+  Fix fix;
+  Change change;
+  String resultCode;
+
   void assertHasFix(FixKind kind, String expected) {
     AnalysisError error = _findErrorToFix();
-    Fix fix = _computeFix(kind, error);
+    fix = _assertHasFix(kind, error);
+    change = fix.change;
     // apply to "file"
-    List<FileEdit> fileEdits = fix.change.edits;
+    List<FileEdit> fileEdits = change.edits;
     expect(fileEdits, hasLength(1));
-    String actualCode = _applyEdits(testCode, fix.change.edits[0].edits);
+    resultCode = _applyEdits(testCode, change.edits[0].edits);
     // verify
-    expect(expected, actualCode);
+    expect(resultCode, expected);
+  }
+
+  void assertHasPositionGroup(String id, List<Position> expectedPositions) {
+    List<LinkedPositionGroup> linkedPositionGroups =
+        change.linkedPositionGroups;
+    for (LinkedPositionGroup group in linkedPositionGroups) {
+      if (group.id == id) {
+        expect(group.positions, unorderedEquals(expectedPositions));
+        return;
+      }
+    }
+    fail('No PositionGroup with id=$id found in $linkedPositionGroups');
+  }
+
+  void assertNoFix(FixKind kind) {
+    AnalysisError error = _findErrorToFix();
+    List<Fix> fixes = computeFixes(searchEngine, testFile, testUnit, error);
+    for (Fix fix in fixes) {
+      if (fix.kind == kind) {
+        throw fail('Unexpected fix $kind in\n${fixes.join('\n')}');
+      }
+    }
+  }
+
+  Position expectedPosition(String search) {
+    int offset = resultCode.indexOf(search);
+    int length = getLeadingIdentifierLength(search);
+    return new Position(testFile, offset, length);
+  }
+
+  List<Position> expectedPositions(List<String> patterns) {
+    List<Position> positions = <Position>[];
+    patterns.forEach((String search) {
+      positions.add(expectedPosition(search));
+    });
+    return positions;
   }
 
   void setUp() {
@@ -63,6 +103,387 @@
 ''');
   }
 
+  void test_changeToStaticAccess_method() {
+    _indexTestUnit('''
+class A {
+  static foo() {}
+}
+main(A a) {
+  a.foo();
+}
+''');
+    assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+class A {
+  static foo() {}
+}
+main(A a) {
+  A.foo();
+}
+''');
+  }
+
+  void test_changeToStaticAccess_method_prefixLibrary() {
+    _indexTestUnit('''
+import 'dart:async' as pref;
+main(pref.Future f) {
+  f.wait([]);
+}
+''');
+    assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+import 'dart:async' as pref;
+main(pref.Future f) {
+  pref.Future.wait([]);
+}
+''');
+  }
+
+  void test_changeToStaticAccess_property() {
+    _indexTestUnit('''
+class A {
+  static get foo => 42;
+}
+main(A a) {
+  a.foo;
+}
+''');
+    assertHasFix(FixKind.CHANGE_TO_STATIC_ACCESS, '''
+class A {
+  static get foo => 42;
+}
+main(A a) {
+  A.foo;
+}
+''');
+  }
+
+  void test_createClass() {
+    _indexTestUnit('''
+main() {
+  Test v = null;
+}
+''');
+    assertHasFix(FixKind.CREATE_CLASS, '''
+main() {
+  Test v = null;
+}
+
+class Test {
+}
+''');
+    assertHasPositionGroup('NAME', expectedPositions(['Test v =', 'Test {']));
+  }
+
+  void test_createConstructorSuperExplicit() {
+    _indexTestUnit('''
+class A {
+  A(bool p1, int p2, double p3, String p4, {p5});
+}
+class B extends A {
+  B() {}
+}
+''');
+    assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+  A(bool p1, int p2, double p3, String p4, {p5});
+}
+class B extends A {
+  B() : super(false, 0, 0.0, '') {}
+}
+''');
+  }
+
+  void test_createConstructorSuperExplicit_hasInitializers() {
+    _indexTestUnit('''
+class A {
+  A(int p);
+}
+class B extends A {
+  int field;
+  B() : field = 42 {}
+}
+''');
+    assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+  A(int p);
+}
+class B extends A {
+  int field;
+  B() : field = 42, super(0) {}
+}
+''');
+  }
+
+  void test_createConstructorSuperExplicit_named() {
+    _indexTestUnit('''
+class A {
+  A.named(int p);
+}
+class B extends A {
+  B() {}
+}
+''');
+    assertHasFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION, '''
+class A {
+  A.named(int p);
+}
+class B extends A {
+  B() : super.named(0) {}
+}
+''');
+  }
+
+  void test_createConstructorSuperExplicit_named_private() {
+    _indexTestUnit('''
+class A {
+  A._named(int p);
+}
+class B extends A {
+  B() {}
+}
+''');
+    assertNoFix(FixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
+  }
+
+  void test_createConstructor_insteadOfSyntheticDefault() {
+    _indexTestUnit('''
+class A {
+  int field;
+
+  method() {}
+}
+main() {
+  new A(1, 2.0);
+}
+''');
+    assertHasFix(FixKind.CREATE_CONSTRUCTOR, '''
+class A {
+  int field;
+
+  A(int i, double d) {
+  }
+
+  method() {}
+}
+main() {
+  new A(1, 2.0);
+}
+''');
+  }
+
+  void test_createConstructor_named() {
+    _indexTestUnit('''
+class A {
+  method() {}
+}
+main() {
+  new A.named(1, 2.0);
+}
+''');
+    assertHasFix(FixKind.CREATE_CONSTRUCTOR, '''
+class A {
+  A.named(int i, double d) {
+  }
+
+  method() {}
+}
+main() {
+  new A.named(1, 2.0);
+}
+''');
+  }
+
+  void test_expectedToken_semicolon() {
+    _indexTestUnit('''
+main() {
+  print(0)
+}
+''');
+    assertHasFix(FixKind.INSERT_SEMICOLON, '''
+main() {
+  print(0);
+}
+''');
+  }
+
+  void test_isNotNull() {
+    _indexTestUnit('''
+main(p) {
+  p is! Null;
+}
+''');
+    assertHasFix(FixKind.USE_NOT_EQ_NULL, '''
+main(p) {
+  p != null;
+}
+''');
+  }
+
+  void test_isNull() {
+    _indexTestUnit('''
+main(p) {
+  p is Null;
+}
+''');
+    assertHasFix(FixKind.USE_EQ_EQ_NULL, '''
+main(p) {
+  p == null;
+}
+''');
+  }
+
+  void test_makeEnclosingClassAbstract_declaresAbstractMethod() {
+    _indexTestUnit('''
+class A {
+  m();
+}
+''');
+    assertHasFix(FixKind.MAKE_CLASS_ABSTRACT, '''
+abstract class A {
+  m();
+}
+''');
+  }
+
+  void test_makeEnclosingClassAbstract_inheritsAbstractMethod() {
+    _indexTestUnit('''
+abstract class A {
+  m();
+}
+class B extends A {
+}
+''');
+    assertHasFix(FixKind.MAKE_CLASS_ABSTRACT, '''
+abstract class A {
+  m();
+}
+abstract class B extends A {
+}
+''');
+  }
+
+  void test_removeParentheses_inGetterDeclaration() {
+    _indexTestUnit('''
+class A {
+  int get foo() => 0;
+}
+''');
+    assertHasFix(FixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, '''
+class A {
+  int get foo => 0;
+}
+''');
+  }
+
+  void test_removeParentheses_inGetterInvocation() {
+    _indexTestUnit('''
+class A {
+  int get foo => 0;
+}
+main(A a) {
+  a.foo();
+}
+''');
+    assertHasFix(FixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION, '''
+class A {
+  int get foo => 0;
+}
+main(A a) {
+  a.foo;
+}
+''');
+  }
+
+  void test_removeUnnecessaryCast_assignment() {
+    _indexTestUnit('''
+main(Object p) {
+  if (p is String) {
+    String v = ((p as String));
+  }
+}
+''');
+    assertHasFix(FixKind.REMOVE_UNNECASSARY_CAST, '''
+main(Object p) {
+  if (p is String) {
+    String v = p;
+  }
+}
+''');
+  }
+
+  void test_removeUnusedImport() {
+    _indexTestUnit('''
+import 'dart:math';
+main() {
+}
+''');
+    assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+main() {
+}
+''');
+  }
+
+  void test_removeUnusedImport_anotherImportOnLine() {
+    _indexTestUnit('''
+import 'dart:math'; import 'dart:async';
+
+main() {
+  Future f;
+}
+''');
+    assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+import 'dart:async';
+
+main() {
+  Future f;
+}
+''');
+  }
+
+  void test_removeUnusedImport_severalLines() {
+    _indexTestUnit('''
+import
+  'dart:math';
+main() {
+}
+''');
+    assertHasFix(FixKind.REMOVE_UNUSED_IMPORT, '''
+main() {
+}
+''');
+  }
+
+  void test_replaceWithConstInstanceCreation() {
+    _indexTestUnit('''
+class A {
+  const A();
+}
+const a = new A();
+''');
+    assertHasFix(FixKind.USE_CONST, '''
+class A {
+  const A();
+}
+const a = const A();
+''');
+  }
+
+  void test_useEffectiveIntegerDivision() {
+    _indexTestUnit('''
+main() {
+  var a = 5;
+  var b = 2;
+  print((a / b).toInt());
+}
+''');
+    assertHasFix(FixKind.USE_EFFECTIVE_INTEGER_DIVISION, '''
+main() {
+  var a = 5;
+  var b = 2;
+  print(a ~/ b);
+}
+''');
+  }
+
   String _applyEdits(String code, List<Edit> edits) {
     edits.sort((a, b) => b.offset - a.offset);
     edits.forEach((Edit edit) {
@@ -73,7 +494,10 @@
     return code;
   }
 
-  Fix _computeFix(FixKind kind, AnalysisError error) {
+  /**
+   * Computes fixes and verifies that there is a fix of the given kind.
+   */
+  Fix _assertHasFix(FixKind kind, AnalysisError error) {
     List<Fix> fixes = computeFixes(searchEngine, testFile, testUnit, error);
     for (Fix fix in fixes) {
       if (fix.kind == kind) {
@@ -84,7 +508,7 @@
   }
 
   AnalysisError _findErrorToFix() {
-    List<AnalysisError> errors = context.getErrors(testSource).errors;
+    List<AnalysisError> errors = context.computeErrors(testSource);
     expect(
         errors,
         hasLength(1),
diff --git a/pkg/analysis_services/test/correction/name_suggestion_test.dart b/pkg/analysis_services/test/correction/name_suggestion_test.dart
new file mode 100644
index 0000000..c3fb487
--- /dev/null
+++ b/pkg/analysis_services/test/correction/name_suggestion_test.dart
@@ -0,0 +1,381 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.name_suggestion;
+
+import 'package:analysis_services/src/correction/name_suggestion.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+main() {
+  groupSep = ' | ';
+  group('source_range', () {
+    runReflectiveTests(VariableNameSuggestionTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class VariableNameSuggestionTest extends AbstractSingleUnitTest {
+  void test_forExpression_cast() {
+    resolveTestUnit('''
+main() {
+  var sortedNodes;
+  var res = sortedNodes as String;
+}
+''');
+    var excluded = new Set.from([]);
+    var expr = findNodeAtString('as String', (node) => node is AsExpression);
+    expect(
+        getVariableNameSuggestionsForExpression(null, expr, excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forExpression_expectedType() {
+    resolveTestUnit('''
+class TreeNode {}
+main() {
+  TreeNode node = null;
+}
+''');
+    Set excluded = new Set.from([]);
+    DartType expectedType = (findElement('node') as LocalVariableElement).type;
+    Expression assignedExpression =
+        findNodeAtString('null;', (node) => node is NullLiteral);
+    List<String> suggestions =
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            excluded);
+    expect(suggestions, unorderedEquals(['treeNode', 'node']));
+  }
+
+  void test_forExpression_expectedType_String() {
+    resolveTestUnit('''
+main() {
+  String res = 'abc';
+}
+''');
+    DartType expectedType = (findElement('res') as LocalVariableElement).type;
+    Expression assignedExpression = findNodeAtString("'abc';");
+    // first choice for "String" is "s"
+    expect(
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            new Set.from([])),
+        unorderedEquals(['s']));
+  }
+
+  void test_forExpression_expectedType_double() {
+    resolveTestUnit('''
+main() {
+  double res = 0.0;
+}
+''');
+    DartType expectedType = (findElement('res') as LocalVariableElement).type;
+    Expression assignedExpression = findNodeAtString('0.0;');
+    // first choice for "double" is "d"
+    expect(
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            new Set.from([])),
+        unorderedEquals(['d']));
+    // if "d" is used, try "e", "f", etc
+    expect(
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            new Set.from(['d', 'e'])),
+        unorderedEquals(['f']));
+  }
+
+  void test_forExpression_expectedType_int() {
+    resolveTestUnit('''
+main() {
+  int res = 0;
+}
+''');
+    DartType expectedType = (findElement('res') as LocalVariableElement).type;
+    Expression assignedExpression = findNodeAtString('0;');
+    // first choice for "int" is "i"
+    expect(
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            new Set.from([])),
+        unorderedEquals(['i']));
+    // if "i" is used, try "j", "k", etc
+    expect(
+        getVariableNameSuggestionsForExpression(
+            expectedType,
+            assignedExpression,
+            new Set.from(['i', 'j'])),
+        unorderedEquals(['k']));
+  }
+
+  void test_forExpression_instanceCreation() {
+    verifyNoTestUnitErrors = false;
+    resolveTestUnit('''
+import 'dart:math' as p;
+main(p) {
+  new NoSuchClass();
+  new p.NoSuchClass();
+  new NoSuchClass.named();
+}
+''');
+    var excluded = new Set.from([]);
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('new NoSuchClass()'),
+            excluded),
+        unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('new NoSuchClass.named()'),
+            excluded),
+        unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+    // TODO(scheglov) This test does not work.
+    // In "p.NoSuchClass" the identifier "p" is not resolved to a PrefixElement.
+//    expect(
+//        getVariableNameSuggestionsForExpression(
+//            null,
+//            findNodeAtString('new p.NoSuchClass()'),
+//            excluded),
+//        unorderedEquals(['noSuchClass', 'suchClass', 'class']));
+  }
+
+  void test_forExpression_invocationArgument_named() {
+    resolveTestUnit('''
+foo({a, b, c}) {}
+main() {
+  foo(a: 111, c: 333, b: 222);
+}
+''');
+    var excluded = new Set.from([]);
+    {
+      var expr = findNodeAtString('111');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['a']));
+    }
+    {
+      var expr = findNodeAtString('222');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['b']));
+    }
+    {
+      var expr = findNodeAtString('333');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['c']));
+    }
+  }
+
+  void test_forExpression_invocationArgument_optional() {
+    resolveTestUnit('''
+foo(a, [b = 2, c = 3]) {}
+main() {
+  foo(111, 222, 333);
+}
+''');
+    var excluded = new Set.from([]);
+    {
+      var expr = findNodeAtString('111');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['a']));
+    }
+    {
+      var expr = findNodeAtString('222');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['b']));
+    }
+    {
+      var expr = findNodeAtString('333');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['c']));
+    }
+  }
+
+  void test_forExpression_invocationArgument_positional() {
+    resolveTestUnit('''
+foo(a, b) {}
+main() {
+  foo(111, 222);
+}
+''');
+    var excluded = new Set.from([]);
+    {
+      var expr = findNodeAtString('111');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['a']));
+    }
+    {
+      var expr = findNodeAtString('222');
+      expect(
+          getVariableNameSuggestionsForExpression(null, expr, excluded),
+          unorderedEquals(['b']));
+    }
+  }
+
+  void test_forExpression_methodInvocation() {
+    resolveTestUnit('''
+main(p) {
+  var res = p.getSortedNodes();
+}
+''');
+    var excluded = new Set.from([]);
+    var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
+    expect(
+        getVariableNameSuggestionsForExpression(null, expr, excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forExpression_methodInvocation_noPrefix() {
+    resolveTestUnit('''
+main(p) {
+  var res = p.sortedNodes();
+}
+''');
+    var excluded = new Set.from([]);
+    var expr = findNodeAtString('p.sorted', (node) => node is MethodInvocation);
+    expect(
+        getVariableNameSuggestionsForExpression(null, expr, excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forExpression_name_get() {
+    resolveTestUnit('''
+main(p) {
+  var res = p.get();
+}
+''');
+    var excluded = new Set.from([]);
+    var expr = findNodeAtString('p.get', (node) => node is MethodInvocation);
+    expect(
+        getVariableNameSuggestionsForExpression(null, expr, excluded),
+        unorderedEquals([]));
+  }
+
+  void test_forExpression_privateName() {
+    resolveTestUnit('''
+main(p) {
+  p._name;
+  p._computeSuffix();
+}
+''');
+    var excluded = new Set.from([]);
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('p._name', (node) => node is PrefixedIdentifier),
+            excluded),
+        unorderedEquals(['name']));
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('p._compute', (node) => node is MethodInvocation),
+            excluded),
+        unorderedEquals(['computeSuffix', 'suffix']));
+  }
+
+  void test_forExpression_propertyAccess() {
+    resolveTestUnit('''
+main(p) {
+  var res = p.sortedNodes;
+}
+''');
+    var excluded = new Set.from([]);
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('p.sorted', (node) => node is PrefixedIdentifier),
+            excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forExpression_simpleName() {
+    resolveTestUnit('''
+main(p) {
+  var sortedNodes = null;
+  var res = sortedNodes;
+}
+''');
+    var excluded = new Set.from([]);
+    var expr = findNodeAtString('sortedNodes;');
+    expect(
+        getVariableNameSuggestionsForExpression(null, expr, excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forExpression_unqualifiedInvocation() {
+    resolveTestUnit('''
+getSortedNodes() => [];
+main(p) {
+  var res = getSortedNodes();
+}
+''');
+    var excluded = new Set.from([]);
+    expect(
+        getVariableNameSuggestionsForExpression(
+            null,
+            findNodeAtString('getSortedNodes();', (node) => node is MethodInvocation),
+            excluded),
+        unorderedEquals(['sortedNodes', 'nodes']));
+  }
+
+  void test_forText() {
+    {
+      Set excluded = new Set.from([]);
+      List<String> suggestions =
+          getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
+      expect(
+          suggestions,
+          unorderedEquals(['goodbyeCruelWorld', 'cruelWorld', 'world']));
+    }
+    {
+      Set excluded = new Set.from(['world']);
+      List<String> suggestions =
+          getVariableNameSuggestionsForText('Goodbye, cruel world!', excluded);
+      expect(
+          suggestions,
+          unorderedEquals(['goodbyeCruelWorld', 'cruelWorld', 'world2']));
+    }
+  }
+
+  void test_getCamelWords_empty() {
+    expect(getCamelWords(''), unorderedEquals([]));
+  }
+
+  void test_getCamelWords_multipleUpper() {
+    expect(
+        getCamelWords('sortedHTMLNodes'),
+        unorderedEquals(['sorted', 'HTML', 'Nodes']));
+  }
+
+  void test_getCamelWords_simpleCamel() {
+    expect(
+        getCamelWords('mySimpleText'),
+        unorderedEquals(['my', 'Simple', 'Text']));
+  }
+
+  void test_getCamelWords_simpleName() {
+    expect(getCamelWords('name'), unorderedEquals(['name']));
+  }
+}
diff --git a/pkg/analysis_services/test/correction/source_range_test.dart b/pkg/analysis_services/test/correction/source_range_test.dart
new file mode 100644
index 0000000..419d523
--- /dev/null
+++ b/pkg/analysis_services/test/correction/source_range_test.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.source_range;
+
+import 'package:analysis_services/src/correction/source_range.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+main() {
+  groupSep = ' | ';
+  group('source_range', () {
+    runReflectiveTests(SourceRangesTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class SourceRangesTest extends AbstractSingleUnitTest {
+  void test_rangeElementName() {
+    resolveTestUnit('class ABC {}');
+    Element element = findElement('ABC');
+    expect(rangeElementName(element), new SourceRange(6, 3));
+  }
+
+  void test_rangeEndEnd_nodeNode() {
+    resolveTestUnit('main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeEndEnd(mainName, mainBody), new SourceRange(4, 5));
+  }
+
+  void test_rangeEndStart_nodeNode() {
+    resolveTestUnit('main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeEndStart(mainName, mainBody), new SourceRange(4, 3));
+  }
+
+  void test_rangeError() {
+    AnalysisError error =
+        new AnalysisError.con2(null, 10, 5, ParserErrorCode.CONST_CLASS, []);
+    expect(rangeError(error), new SourceRange(10, 5));
+  }
+
+  void test_rangeNode() {
+    resolveTestUnit('main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    expect(rangeNode(mainName), new SourceRange(0, 4));
+  }
+
+  void test_rangeNodes() {
+    resolveTestUnit(' main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeNodes([mainName, mainBody]), new SourceRange(1, 9));
+  }
+
+  void test_rangeNodes_empty() {
+    resolveTestUnit('main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeNodes([]), new SourceRange(0, 0));
+  }
+
+  void test_rangeStartEnd_intInt() {
+    expect(rangeStartEnd(10, 25), new SourceRange(10, 15));
+  }
+
+  void test_rangeStartEnd_nodeNode() {
+    resolveTestUnit(' main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeStartEnd(mainName, mainBody), new SourceRange(1, 9));
+  }
+
+  void test_rangeStartLength_int() {
+    expect(rangeStartLength(5, 10), new SourceRange(5, 10));
+  }
+
+  void test_rangeStartLength_node() {
+    resolveTestUnit(' main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    expect(rangeStartLength(mainName, 10), new SourceRange(1, 10));
+  }
+
+  void test_rangeStartStart_intInt() {
+    expect(rangeStartStart(10, 25), new SourceRange(10, 15));
+  }
+
+  void test_rangeStartStart_nodeNode() {
+    resolveTestUnit('main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    FunctionBody mainBody = mainFunction.functionExpression.body;
+    expect(rangeStartStart(mainName, mainBody), new SourceRange(0, 7));
+  }
+
+  void test_rangeToken() {
+    resolveTestUnit(' main() {}');
+    FunctionDeclaration mainFunction = testUnit.declarations[0];
+    SimpleIdentifier mainName = mainFunction.name;
+    expect(rangeToken(mainName.beginToken), new SourceRange(1, 4));
+  }
+}
diff --git a/pkg/analysis_services/test/correction/strings_test.dart b/pkg/analysis_services/test/correction/strings_test.dart
new file mode 100644
index 0000000..a02f164
--- /dev/null
+++ b/pkg/analysis_services/test/correction/strings_test.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+library test.services.correction.strings;
+
+import 'package:analysis_services/src/correction/strings.dart';
+import 'package:analysis_testing/reflective_tests.dart';
+import 'package:unittest/unittest.dart' hide isEmpty;
+
+
+
+main() {
+  groupSep = ' | ';
+  group('strings', () {
+    runReflectiveTests(StringsTest);
+  });
+}
+
+
+@ReflectiveTestCase()
+class StringsTest {
+  void test_capitalize() {
+    expect(capitalize(null), null);
+    expect(capitalize(''), '');
+    expect(capitalize('a'), 'A');
+    expect(capitalize('abc'), 'Abc');
+    expect(capitalize('abc def'), 'Abc def');
+    expect(capitalize('ABC'), 'ABC');
+  }
+
+  void test_isDigit() {
+    for (int c in '0123456789'.codeUnits) {
+      expect(isDigit(c), isTrue);
+    }
+    expect(isDigit(' '.codeUnitAt(0)), isFalse);
+    expect(isDigit('A'.codeUnitAt(0)), isFalse);
+  }
+
+  void test_isEmpty() {
+    expect(isEmpty(null), isTrue);
+    expect(isEmpty(''), isTrue);
+    expect(isEmpty('X'), isFalse);
+    expect(isEmpty(' '), isFalse);
+  }
+
+  void test_isLetter() {
+    for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
+      expect(isLetter(c), isTrue);
+    }
+    for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
+      expect(isLetter(c), isTrue);
+    }
+    expect(isLetter(' '.codeUnitAt(0)), isFalse);
+    expect(isLetter('0'.codeUnitAt(0)), isFalse);
+  }
+
+  void test_isSpace() {
+    expect(isSpace(' '.codeUnitAt(0)), isTrue);
+    expect(isSpace('\t'.codeUnitAt(0)), isTrue);
+    expect(isSpace('\r'.codeUnitAt(0)), isFalse);
+    expect(isSpace('\n'.codeUnitAt(0)), isFalse);
+    expect(isSpace('0'.codeUnitAt(0)), isFalse);
+    expect(isSpace('A'.codeUnitAt(0)), isFalse);
+  }
+
+  void test_isUpperCase() {
+    for (int c in 'abcdefghijklmnopqrstuvwxyz'.codeUnits) {
+      expect(isUpperCase(c), isFalse);
+    }
+    for (int c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.codeUnits) {
+      expect(isUpperCase(c), isTrue);
+    }
+    expect(isUpperCase(' '.codeUnitAt(0)), isFalse);
+    expect(isUpperCase('0'.codeUnitAt(0)), isFalse);
+  }
+
+  void test_isWhitespace() {
+    expect(isWhitespace(' '.codeUnitAt(0)), isTrue);
+    expect(isWhitespace('\t'.codeUnitAt(0)), isTrue);
+    expect(isWhitespace('\r'.codeUnitAt(0)), isTrue);
+    expect(isWhitespace('\n'.codeUnitAt(0)), isTrue);
+    expect(isWhitespace('0'.codeUnitAt(0)), isFalse);
+    expect(isWhitespace('A'.codeUnitAt(0)), isFalse);
+  }
+
+  void test_remove() {
+    expect(remove(null, 'x'), null);
+    expect(remove('abc', null), 'abc');
+    expect(remove('abc abbc abbbc', 'b'), 'ac ac ac');
+    expect(remove('abc abbc abbbc', 'bc'), 'a ab abb');
+  }
+
+  void test_removeStart() {
+    expect(removeStart(null, 'x'), null);
+    expect(removeStart('abc', null), 'abc');
+    expect(removeStart('abcTest', 'abc'), 'Test');
+    expect(removeStart('my abcTest', 'abc'), 'my abcTest');
+  }
+
+  void test_repeat() {
+    expect(repeat('x', 0), '');
+    expect(repeat('x', 5), 'xxxxx');
+    expect(repeat('abc', 3), 'abcabcabc');
+  }
+}
diff --git a/pkg/analysis_services/test/correction/test_all.dart b/pkg/analysis_services/test/correction/test_all.dart
index 169f143..a092de11 100644
--- a/pkg/analysis_services/test/correction/test_all.dart
+++ b/pkg/analysis_services/test/correction/test_all.dart
@@ -6,12 +6,20 @@
 
 import 'package:unittest/unittest.dart';
 
-import 'fix_test.dart' as fix_processor_test;
+import 'change_test.dart' as change_test;
+import 'fix_test.dart' as fix_test;
+import 'name_suggestion_test.dart' as name_suggestion_test;
+import 'source_range_test.dart' as source_range_test;
+import 'strings_test.dart' as strings_test;
 
 /// Utility for manually running all tests.
 main() {
   groupSep = ' | ';
   group('correction', () {
-    fix_processor_test.main();
+    change_test.main();
+    fix_test.main();
+    name_suggestion_test.main();
+    source_range_test.main();
+    strings_test.main();
   });
 }
\ No newline at end of file
diff --git a/pkg/analysis_services/test/index/dart_index_contributor_test.dart b/pkg/analysis_services/test/index/dart_index_contributor_test.dart
index 9912459..f6d7e20 100644
--- a/pkg/analysis_services/test/index/dart_index_contributor_test.dart
+++ b/pkg/analysis_services/test/index/dart_index_contributor_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_services/index/index.dart';
 import 'package:analysis_services/index/index_store.dart';
 import 'package:analysis_services/src/index/index_contributor.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
@@ -14,8 +15,6 @@
 import 'package:typed_mock/typed_mock.dart';
 import 'package:unittest/unittest.dart';
 
-import 'abstract_single_unit.dart';
-
 
 main() {
   groupSep = ' | ';
@@ -123,6 +122,26 @@
         _expectedLocation(mainElement, 'field); // not a member'));
   }
 
+  void test_NameElement_isDefinedBy_localVariable_inForEach() {
+    _indexTestUnit('''
+class A {
+  main() {
+    for (int test in []) {
+    }
+  }
+}
+''');
+    // prepare elements
+    Element mainElement = findElement('main');
+    LocalVariableElement testElement = findElement('test');
+    Element nameElement = new NameElement('test');
+    // verify
+    _assertRecordedRelation(
+        nameElement,
+        IndexConstants.NAME_IS_DEFINED_BY,
+        _expectedLocation(testElement, 'test in []'));
+  }
+
   void test_NameElement_method() {
     _indexTestUnit('''
 class A {
@@ -152,26 +171,6 @@
         _expectedLocationQU(mainElement, 'method(); // ur'));
   }
 
-  void test_NameElement_isDefinedBy_localVariable_inForEach() {
-    _indexTestUnit('''
-class A {
-  main() {
-    for (int test in []) {
-    }
-  }
-}
-''');
-    // prepare elements
-    Element mainElement = findElement('main');
-    LocalVariableElement testElement = findElement('test');
-    Element nameElement = new NameElement('test');
-    // verify
-    _assertRecordedRelation(
-        nameElement,
-        IndexConstants.NAME_IS_DEFINED_BY,
-        _expectedLocation(testElement, 'test in []'));
-  }
-
   void test_NameElement_operator_resolved() {
     _indexTestUnit('''
 class A {
diff --git a/pkg/analysis_services/test/index/store/codec_test.dart b/pkg/analysis_services/test/index/store/codec_test.dart
index 6664b90..141c1cb 100644
--- a/pkg/analysis_services/test/index/store/codec_test.dart
+++ b/pkg/analysis_services/test/index/store/codec_test.dart
@@ -6,14 +6,13 @@
 
 import 'package:analysis_services/index/index.dart';
 import 'package:analysis_services/src/index/store/codec.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
 import 'package:analysis_testing/mocks.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:unittest/unittest.dart';
 
-import '../abstract_single_unit.dart';
-
 
 main() {
   groupSep = ' | ';
@@ -82,29 +81,6 @@
     codec = new ElementCodec(stringCodec);
   }
 
-  void test_field() {
-    resolveTestUnit('''
-class A {
-  int field;
-}
-''');
-    FieldElement field = findElement('field', ElementKind.FIELD);
-    PropertyAccessorElement getter = field.getter;
-    PropertyAccessorElement setter = field.setter;
-    {
-      int id = codec.encode(getter);
-      expect(codec.decode(context, id), getter);
-    }
-    {
-      int id = codec.encode(setter);
-      expect(codec.decode(context, id), setter);
-    }
-    {
-      int id = codec.encode(field);
-      expect(codec.decode(context, id), field);
-    }
-  }
-
   void test_encodeHash_notLocal() {
     resolveTestUnit('''
 class A {
@@ -129,6 +105,29 @@
     expect(id_fooA == id_bar, isFalse);
   }
 
+  void test_field() {
+    resolveTestUnit('''
+class A {
+  int field;
+}
+''');
+    FieldElement field = findElement('field', ElementKind.FIELD);
+    PropertyAccessorElement getter = field.getter;
+    PropertyAccessorElement setter = field.setter;
+    {
+      int id = codec.encode(getter);
+      expect(codec.decode(context, id), getter);
+    }
+    {
+      int id = codec.encode(setter);
+      expect(codec.decode(context, id), setter);
+    }
+    {
+      int id = codec.encode(field);
+      expect(codec.decode(context, id), field);
+    }
+  }
+
   void test_localLocalVariable() {
     resolveTestUnit('''
 main() {
diff --git a/pkg/analysis_services/test/search/hierarchy_test.dart b/pkg/analysis_services/test/search/hierarchy_test.dart
index a83312c..c9a0c1d 100644
--- a/pkg/analysis_services/test/search/hierarchy_test.dart
+++ b/pkg/analysis_services/test/search/hierarchy_test.dart
@@ -13,12 +13,11 @@
 import 'package:analysis_services/index/local_memory_index.dart';
 import 'package:analysis_services/search/hierarchy.dart';
 import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:unittest/unittest.dart';
 
-import '../index/abstract_single_unit.dart';
-
 
 main() {
   groupSep = ' | ';
diff --git a/pkg/analysis_services/test/search/search_engine_test.dart b/pkg/analysis_services/test/search/search_engine_test.dart
index df96e48..0445c24 100644
--- a/pkg/analysis_services/test/search/search_engine_test.dart
+++ b/pkg/analysis_services/test/search/search_engine_test.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_services/index/local_memory_index.dart';
 import 'package:analysis_services/search/search_engine.dart';
 import 'package:analysis_services/src/search/search_engine.dart';
+import 'package:analysis_testing/abstract_single_unit.dart';
 import 'package:analysis_testing/mocks.dart';
 import 'package:analysis_testing/reflective_tests.dart';
 import 'package:analyzer/src/generated/element.dart';
@@ -20,8 +21,6 @@
 import 'package:typed_mock/typed_mock.dart';
 import 'package:unittest/unittest.dart';
 
-import '../index/abstract_single_unit.dart';
-
 
 main() {
   groupSep = ' | ';
diff --git a/pkg/analysis_services/test/index/abstract_single_unit.dart b/pkg/analysis_testing/lib/abstract_single_unit.dart
similarity index 100%
rename from pkg/analysis_services/test/index/abstract_single_unit.dart
rename to pkg/analysis_testing/lib/abstract_single_unit.dart
diff --git a/pkg/analysis_testing/lib/mock_sdk.dart b/pkg/analysis_testing/lib/mock_sdk.dart
index 89de9b6..99cf23c 100644
--- a/pkg/analysis_testing/lib/mock_sdk.dart
+++ b/pkg/analysis_testing/lib/mock_sdk.dart
@@ -33,6 +33,7 @@
             num operator -(num other);
             num operator *(num other);
             num operator /(num other);
+            int toInt();
           }
           abstract class int extends num {
             int operator -();
@@ -62,6 +63,13 @@
           class HtmlElement {}
           ''',
 
+      "/lib/async/async.dart": '''
+          library dart.async;
+          class Future {
+            static Future wait(List<Future> futures) => null;
+          }
+          ''',
+
       "/lib/math/math.dart": '''
           library dart.math;
           const double E = 2.718281828459045;
@@ -114,6 +122,7 @@
     const Map<String, String> uriToPath = const {
       "dart:core": "/lib/core/core.dart",
       "dart:html": "/lib/html/dartium/html_dartium.dart",
+      "dart:async": "/lib/async/async.dart",
       "dart:math": "/lib/math/math.dart"
     };
 
diff --git a/pkg/docgen/lib/src/generator.dart b/pkg/docgen/lib/src/generator.dart
index 42c2e3b..1258d20 100644
--- a/pkg/docgen/lib/src/generator.dart
+++ b/pkg/docgen/lib/src/generator.dart
@@ -423,18 +423,20 @@
 /// from a snapshot and using --parse-sdk or --include-sdk, then use this
 /// hard-coded version. This should be updated to be consistent with the text
 /// in docgen/doc/sdk-introduction.md
+// TODO(alanknight): It would be better if we could resolve the references to
+// dart:core etc. at load-time in the viewer. dartbug.com/20112
 const _DEFAULT_SDK_INTRODUCTION =
     """
 Welcome to the Dart API reference documentation,
 covering the official Dart API libraries.
 Some of the most fundamental Dart libraries include:
 
-* [dart:core](#dart:core):
+* [dart:core](./dart:core):
   Core functionality such as strings, numbers, collections, errors,
   dates, and URIs.
-* [dart:html](#dart:html):
+* [dart:html](./dart:html):
   DOM manipulation for web apps.
-* [dart:io](#dart:io):
+* [dart:io](./dart:io):
   I/O for command-line apps.
 
 Except for dart:core, you must import a library before you can use it.
diff --git a/pkg/intl/README.md b/pkg/intl/README.md
index 74594b9..18951c7 100644
--- a/pkg/intl/README.md
+++ b/pkg/intl/README.md
@@ -45,10 +45,7 @@
 to make
 sure the data is available. This reduces the size of the application by only
 loading the
-data that is actually required. However, deferred loading does not yet work for
-multiple
-libraries, so currently all the code will be included anyay, increasing the code
-size in the short term.
+data that is actually required.
 
 Each different area of internationalization (messages, dates, numbers) requires
 a separate initialization process. That way, if the application only needs to
@@ -153,36 +150,33 @@
           examples: {{'userGender': 'male', 'userName': 'Fred'},
               {'userGender': 'female', 'userName' : 'Alice'}});
 
+It's recommended to use complete sentences in the sub-messages to keep
+the structure as simple as possible for the translators.
+
 ## Extracting And Using Translated Messages
 
 When your program contains messages that need translation, these must
 be extracted from the program source, sent to human translators, and the
-results need to be incorporated. This is still work in progress, and
-the extraction is done to a custom JSON format that is not supported
-by translation tools. We intend to support one or more actual
-translation file formats.
+results need to be incorporated. 
 
-To extract messages, run the `pkg/intl/test/extract_to_json.dart` program.
+To extract messages, run the `extract_to_arb.dart` program.
 
-      dart extract_to_json.dart --output-dir=target/directory
+      pub run intl:extract_to_arb --output-dir=target/directory
           my_program.dart more_of_my_program.dart
 
-This will produce a file `intl_messages.json` with the messages from
-all of these programs. This is in a simple JSON format with a map from
-message names to message strings.
+This will produce a file `intl_messages.arb` with the messages from
+all of these programs. an [ARB]
+(https://code.google.com/p/arb/wiki/ApplicationResourceBundleSpecification)
+format file which can be used for input to translation tools like
+[Google Translator Toolkit](https://translate.google.com/toolkit/) 
+The resulting translations can be used to generate a set of libraries
+using the `generate_from_arb.dart` program.
 
-The reverse step expects to receive a series of files, one per
-locale. These consist of a map with the entry for "_locale" indicating
-the locale, and with the function name mapped to the translated
-string. However, plurals and genders are currently represented in an
-opaque form, by serializing the internal objects that represent
-them. You can see the generation of this code in the
-`make_hardcoded_translation.dart` test file.
+This expects to receive a series of files, one per
+locale. 
 
-If you manage to create such a set of input files, then you can run
-
-      dart generate_from_json.dart --generated_file_prefix=<prefix> 
-          <my dart files> <translated json files>
+      pub run intl:generate_from_arb --generated_file_prefix=<prefix> 
+          <my_dart_files> <translated_ARB_files>
 
 This will generate Dart libraries, one per locale, which contain the
 translated versions. Your Dart libraries can import the primary file,
@@ -291,16 +285,16 @@
         new BidiFormatter.RTL().wrapWithUnicode('xyz');
         new BidiFormatter.RTL().wrapWithSpan('xyz');
 
-[intl_lib]: https://api.dartlang.org/docs/channels/stable/latest/intl.html
-[Intl]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html
-[DateFormat]: https://api.dartlang.org/docs/channels/stable/latest/intl/DateFormat.html
-[NumberFormat]: https://api.dartlang.org/docs/channels/stable/latest/intl/NumberFormat.html
-[withLocale]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#withLocale
-[defaultLocale]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#defaultLocale
-[Intl.message]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#message
-[Intl.plural]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#plural
-[Intl.gender]: https://api.dartlang.org/docs/channels/stable/latest/intl/Intl.html#gender
-[DateTime]: https://api.dartlang.org/docs/channels/stable/latest/dart_core/DateTime.html
-[BidiFormatter]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html
-[BidiFormatter.RTL]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html#RTL
-[BidiFormatter.LTR]: https://api.dartlang.org/docs/channels/stable/latest/intl/BidiFormatter.html#LTR
+[intl_lib]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl
+[Intl]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl
+[DateFormat]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.DateFormat
+[NumberFormat]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.NumberFormat
+[withLocale]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_withLocale
+[defaultLocale]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_defaultLocale
+[Intl.message]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_message
+[Intl.plural]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_plural
+[Intl.gender]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.Intl#id_gender
+[DateTime]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:core.DateTime
+[BidiFormatter]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter
+[BidiFormatter.RTL]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter#id_BidiFormatter-RTL
+[BidiFormatter.LTR]: https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/intl/intl.BidiFormatter#id_BidiFormatter-LTR
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index d2889ec..4b29df9 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -233,6 +233,8 @@
   }
 
   /**
+   * NOT YET IMPLEMENTED.
+   * 
    * Returns a date string indicating how long ago (3 hours, 2 minutes)
    * something has happened or how long in the future something will happen
    * given a [reference] DateTime relative to the current time.
@@ -240,6 +242,8 @@
   String formatDuration(DateTime reference) => '';
 
   /**
+   * NOT YET IMPLEMENTED.
+   * 
    * Formats a string indicating how long ago (negative [duration]) or how far
    * in the future (positive [duration]) some time is with respect to a
    * reference [date].
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index a7213d0..0ce6c44 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -8,7 +8,7 @@
  * and utilities for working with Bidirectional text.
  *
  * This is part of the [intl package]
- * (http://pub.dartlang.org/packages/intl).
+ * (https://pub.dartlang.org/packages/intl).
  *
  * For things that require locale or other data, there are multiple different
  * ways of making that data available, which may require importing different
@@ -43,13 +43,7 @@
  * and used to create a date format via `anIntl.date()`. Static methods
  * on this class are also used in message formatting.
  *
- * Message example:
- *     '''I see ${Intl.plural(num_people,
- *               {'0': 'no one at all',
- *                '1': 'one other person',
- *                'other': '$num_people other people'})} in $place.''''
- *
- * Usage examples:
+ * Examples:
  *      today(date) => Intl.message(
  *          "Today's date is $date",
  *          name: 'today',
@@ -58,18 +52,22 @@
  *          examples: {'date' : 'June 8, 2012'});
  *      print(today(new DateTime.now().toString());
  *
- *      msg(num_people, place) => Intl.message(
- *           '''I see ${Intl.plural(num_people,
- *             {'0': 'no one at all',
- *              '1': 'one other person',
- *              'other': '$num_people other people'})} in $place.''',
+ *      howManyPeople(numberOfPeople, place) => Intl.plural(
+ *            zero: 'I see no one at all',
+ *            one: 'I see one other person',
+ *            other: 'I see $numberOfPeople other people')} in $place.''',
  *          name: 'msg',
- *          args: [num_people, place],
- *          desc: 'Description of how many people are seen as program start.',
- *          examples: {'num_people': 3, 'place': 'London'});
+ *          args: [numberOfPeople, place],
+ *          desc: 'Description of how many people are seen in a place.',
+ *          examples: {'numberOfPeople': 3, 'place': 'London'});
  *
- * Calling `msg(2, 'Athens');` would
+ * Calling `howManyPeople(2, 'Athens');` would
  * produce "I see 2 other people in Athens." as output in the default locale.
+ * If run in a different locale it would produce appropriately translated
+ * output.
+ * 
+ * For more detailed information on messages and localizing them see
+ * the main [package documentation](https://pub.dartlang.org/packages/intl)
  *
  * You can set the default locale.
  *       Intl.defaultLocale = "pt_BR";
@@ -148,8 +146,10 @@
    * be a valid const literal map. Similarly, the [desc] argument must
    * be a single, simple string. These two arguments will not be used at runtime
    * but will be extracted from
-   * the source code and used as additional data for translators.
-   *
+   * the source code and used as additional data for translators. For more
+   * information see the "Messages" section of the main [package documentation]
+   * (https://pub.dartlang.org/packages/intl).
+   * 
    * The [name] and [args] arguments are required, and are used at runtime
    * to look up the localized version and pass the appropriate arguments to it.
    * We may in the future modify the code during compilation to make manually
diff --git a/pkg/intl/pubspec.yaml b/pkg/intl/pubspec.yaml
index fdd984f..a38f52c 100644
--- a/pkg/intl/pubspec.yaml
+++ b/pkg/intl/pubspec.yaml
@@ -5,7 +5,6 @@
 homepage: http://www.dartlang.org
 environment:
   sdk: '>=1.4.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/intl
 dependencies:
   analyzer: '>=0.13.2 <0.16.0'
   path: '>=0.9.0 <2.0.0'
diff --git a/pkg/matcher/CHANGELOG.md b/pkg/matcher/CHANGELOG.md
index af9ce95..e175d94 100644
--- a/pkg/matcher/CHANGELOG.md
+++ b/pkg/matcher/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.11.0
+
+* Removed deprecated matchers.
+
 ## 0.10.1+1
 
 * Get the tests passing when run on dart2js in minified mode.
diff --git a/pkg/matcher/lib/src/error_matchers.dart b/pkg/matcher/lib/src/error_matchers.dart
index cb716f5..dca1759 100644
--- a/pkg/matcher/lib/src/error_matchers.dart
+++ b/pkg/matcher/lib/src/error_matchers.dart
@@ -7,28 +7,6 @@
 import 'core_matchers.dart';
 import 'interfaces.dart';
 
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher isAbstractClassInstantiationError =
-  const _AbstractClassInstantiationError();
-
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher throwsAbstractClassInstantiationError =
-  const Throws(isAbstractClassInstantiationError);
-
-class _AbstractClassInstantiationError extends TypeMatcher {
-  const _AbstractClassInstantiationError() :
-  super("AbstractClassInstantiationError");
-  bool matches(item, Map matchState) => item is AbstractClassInstantiationError;
-}
-
 /// A matcher for ArgumentErrors.
 const Matcher isArgumentError = const _ArgumentError();
 
@@ -76,20 +54,6 @@
   bool matches(item, Map matchState) => item is Exception;
 }
 
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher isFallThroughError = const _FallThroughError();
-
-/// **DEPRECATED**
-///
-/// Will be removed in the next major release.
-// TODO(kevmoo): re-deprecate once 19173 is resolved
-//@deprecated
-const Matcher throwsFallThroughError = const Throws(isFallThroughError);
-
 class _FallThroughError extends TypeMatcher {
   const _FallThroughError(): super("FallThroughError");
   bool matches(item, Map matchState) => item is FallThroughError;
diff --git a/pkg/matcher/pubspec.yaml b/pkg/matcher/pubspec.yaml
index 6f6f277..4612c58 100644
--- a/pkg/matcher/pubspec.yaml
+++ b/pkg/matcher/pubspec.yaml
@@ -1,10 +1,9 @@
 name: matcher
-version: 0.10.1+1
+version: 0.11.0
 author: Dart Team <misc@dartlang.org>
 description: Support for specifying test expectations
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/matcher
 environment:
   sdk: '>=1.0.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/matcher
 dev_dependencies:
   unittest: '>=0.10.0 <0.12.0'
diff --git a/pkg/matcher/test/deprecated_matchers_test.dart b/pkg/matcher/test/deprecated_matchers_test.dart
deleted file mode 100644
index b6acc1c..0000000
--- a/pkg/matcher/test/deprecated_matchers_test.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library matcher.deprecated_matchers_test;
-
-import 'package:matcher/matcher.dart';
-import 'package:unittest/unittest.dart' show test, group;
-
-import 'test_utils.dart';
-
-void main() {
-  initUtils();
-
-  test('throwsAbstractClassInstantiationError', () {
-    expect(() => new _AbstractClass(), throwsAbstractClassInstantiationError);
-  });
-
-  test('throwsFallThroughError', () {
-    expect(() {
-      var a = 0;
-      switch (a) {
-        case 0:
-          a += 1;
-        case 1:
-          return;
-      }
-    }, throwsFallThroughError);
-  });
-}
-
-abstract class _AbstractClass {
-}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 76bf1a2..fff2bfb 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -249,6 +249,11 @@
 
 third_party/angular_tests/browser_test: StaticWarning # Issue 15890
 
+[ $compiler == dartanalyzer ]
+# This test uses third_party/pkg/perf_api/lib/perf_api.dart, which
+# contains illegal constant constructors.
+third_party/angular_tests/browser_test: CompileTimeError
+
 [ $compiler == dart2js && $runtime == none]
 polymer/e2e_test/canonicalization: Skip
 polymer/e2e_test/experimental_boot: Skip
diff --git a/pkg/polymer/lib/src/build/import_inliner.dart b/pkg/polymer/lib/src/build/import_inliner.dart
index dc181c3..675db29 100644
--- a/pkg/polymer/lib/src/build/import_inliner.dart
+++ b/pkg/polymer/lib/src/build/import_inliner.dart
@@ -144,7 +144,12 @@
   /// Loads an asset identified by [id], visits its imports and collects its
   /// html imports. Then inlines it into the main document.
   Future _inlineImport(AssetId id, Element link) {
-    return readAsHtml(id, transform).then((doc) {
+    return readAsHtml(id, transform).catchError((error) {
+      transform.logger.error(
+          "Failed to inline html import: $error", asset: id,
+          span: link.sourceSpan);
+    }).then((doc) {
+      if (doc == null) return false;
       new _UrlNormalizer(transform, id).visit(doc);
       return _visitImports(doc).then((_) {
         // _UrlNormalizer already ensures there is a library name.
@@ -160,7 +165,15 @@
   }
 
   Future _inlineStylesheet(AssetId id, Element link) {
-    return transform.readInputAsString(id).then((css) {
+    return transform.readInputAsString(id).catchError((error) {
+      // TODO(jakemac): Move this warning to the linter once we can make it run
+      // always (see http://dartbug.com/17199). Then hide this error and replace
+      // with a comment pointing to the linter error (so we don't double warn).
+      transform.logger.warning(
+          "Failed to inline stylesheet: $error", asset: id,
+          span: link.sourceSpan);
+    }).then((css) {
+      if (css == null) return;
       css = new _UrlNormalizer(transform, id).visitCss(css);
       var styleElement = new Element.tag('style')..text = css;
       // Copy over the extra attributes from the link tag to the style tag.
@@ -324,7 +337,7 @@
     if (!isCustomTagName(node.localName)) {
       node.attributes.forEach((name, value) {
         if (_urlAttributes.contains(name)) {
-          if (value != '' && !value.trim().startsWith('{{')) {
+          if (value != '' && !value.trim().startsWith(_BINDINGS)) {
             node.attributes[name] = _newUrl(value, node.sourceSpan);
             changed = changed || value != node.attributes[name];
           }
@@ -347,6 +360,7 @@
 
   static final _URL = new RegExp(r'url\(([^)]*)\)', multiLine: true);
   static final _QUOTE = new RegExp('["\']', multiLine: true);
+  static final _BINDINGS = new RegExp(r'({{)|(\[\[)');
 
   /// Visit the CSS text and replace any relative URLs so we can inline it.
   // Ported from:
@@ -403,7 +417,10 @@
   }
 
   String _newUrl(String href, Span span) {
-    var uri = Uri.parse(href);
+    // Uri.parse blows up on invalid characters (like {{). Encoding the uri
+    // allows it to be parsed, which does the correct thing in the general case.
+    // This uri not used to build the new uri, so it never needs to be decoded.
+    var uri = Uri.parse(Uri.encodeFull(href));
     if (uri.isAbsolute) return href;
     if (!uri.scheme.isEmpty) return href;
     if (!uri.host.isEmpty) return href;
diff --git a/pkg/polymer/test/build/import_inliner_test.dart b/pkg/polymer/test/build/import_inliner_test.dart
index 023bf4d..f6daa40 100644
--- a/pkg/polymer/test/build/import_inliner_test.dart
+++ b/pkg/polymer/test/build/import_inliner_test.dart
@@ -612,6 +612,31 @@
           '</head><body>'
           '<polymer-element>3</polymer-element></body></html>',
     });
+
+  testPhases("missing styles don't throw errors and are not inlined", phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="stylesheet" href="foo.css">'
+          '</head></html>',
+    }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<link rel="stylesheet" href="foo.css">'
+          '</body></html>',
+    }, [
+      'warning: Failed to inline stylesheet: '
+          'Could not find asset a|web/foo.css. (web/test.html 0 27)',
+    ]);
+
+  testPhases("missing html imports throw errors", phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="foo.html">'
+          '</head></html>',
+    }, {}, [
+      'error: Failed to inline html import: '
+          'Could not find asset a|web/foo.html. (web/test.html 0 27)',
+    ]);
 }
 
 void stylesheetTests() {
@@ -823,6 +848,41 @@
       'a|web/foo/test_2.html':
           '<foo-element src="baz.jpg"></foo-element>',
     });
+
+  testPhases('paths with a binding prefix are not normalized', phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="foo/test.html">'
+          '</head></html>',
+      'a|web/foo/test.html':
+          '<img src="{{bar}}">'
+          '<img src="[[bar]]">',
+  }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<img src="{{bar}}">'
+          '<img src="[[bar]]">'
+          '</body></html>',
+      'a|web/foo/test.html':
+          '<img src="{{bar}}">'
+          '<img src="[[bar]]">',
+  });
+
+  testPhases('relative paths followed by bindings are normalized', phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="foo/test.html">'
+          '</head></html>',
+      'a|web/foo/test.html':
+          '<img src="baz/{{bar}}">'
+          '<img src="./{{bar}}">',
+    }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<img src="foo/baz/{{bar}}">'
+          '<img src="foo/{{bar}}">'
+          '</body></html>',
+    });
 }
 
 void entryPointTests() {
diff --git a/pkg/serialization/README.md b/pkg/serialization/README.md
index d35ebc8..aaa7165 100644
--- a/pkg/serialization/README.md
+++ b/pkg/serialization/README.md
@@ -1,6 +1,3 @@
-Serialization
-=============
-
 A general-purpose serialization facility for Dart Objects.
 
 This provides the ability to save and restore objects to pluggable
@@ -13,8 +10,3 @@
 APIs using JSON to pass acyclic structures without class information,
 and is fairly heavweight and expensive for doing that compared to simpler
 approaches.
- 
-For more detailed descriptions and examples of use, see the comment on
-the [serialization][serialization] library.
-
-[serialization]: https://api.dartlang.org/docs/channels/stable/latest/serialization.html
diff --git a/pkg/serialization/pubspec.yaml b/pkg/serialization/pubspec.yaml
index 2a8d9b2..3e11f26 100644
--- a/pkg/serialization/pubspec.yaml
+++ b/pkg/serialization/pubspec.yaml
@@ -1,11 +1,9 @@
 name: serialization
-version: 0.9.1
-author: "Dart Team <misc@dartlang.org>"
-homepage: http://www.dartlang.org
-documentation: http://api.dartlang.org/docs/pkg/serialization
-description: >
-  Provide a serialization facility for Dart objects.
-dev_dependencies:
-  unittest: ">=0.9.0 <0.10.0"
+version: 0.9.1+1
+author: Dart Team <misc@dartlang.org>
+description: Provide a serialization facility for Dart objects.
+homepage: https://pub.dartlang.org/packages/serialization
 environment:
-  sdk: ">=1.0.0 <2.0.0"
+  sdk: '>=1.0.0 <2.0.0'
+dev_dependencies:
+  unittest: '>=0.9.0 <0.12.0'
diff --git a/pkg/source_maps/CHANGELOG.md b/pkg/source_maps/CHANGELOG.md
index 7767fc1..c52d585 100644
--- a/pkg/source_maps/CHANGELOG.md
+++ b/pkg/source_maps/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.9.4
+
+* Update `SpanFormatException` with `source` and `offset`.
+
 ## 0.9.3
 
 * Support writing SingleMapping objects to source map version 3 format.
diff --git a/pkg/source_maps/lib/span.dart b/pkg/source_maps/lib/span.dart
index 771e9e0..b546a97 100644
--- a/pkg/source_maps/lib/span.dart
+++ b/pkg/source_maps/lib/span.dart
@@ -385,9 +385,10 @@
 
 /// A [SpanException] that's also a [FormatException].
 class SpanFormatException extends SpanException implements FormatException {
-  SpanFormatException(String message, Span span)
+  final source;
+
+  SpanFormatException(String message, Span span, [this.source])
       : super(message, span);
 
-  get source => null;
-  int get position => null;
+  int get offset => span == null ? null : span.start.offset;
 }
diff --git a/pkg/source_maps/pubspec.yaml b/pkg/source_maps/pubspec.yaml
index ae0323d..c5029e2 100644
--- a/pkg/source_maps/pubspec.yaml
+++ b/pkg/source_maps/pubspec.yaml
@@ -7,7 +7,7 @@
 #
 # When the minor version is upgraded, you *must* update that version constraint
 # in pub to stay in sync with this.
-version: 0.9.3
+version: 0.9.4
 author: Dart Team <misc@dartlang.org>
 description: Library to programmatically manipulate source map files.
 homepage: http://www.dartlang.org
diff --git a/pkg/source_span/lib/src/span_exception.dart b/pkg/source_span/lib/src/span_exception.dart
index af64241..36f2488 100644
--- a/pkg/source_span/lib/src/span_exception.dart
+++ b/pkg/source_span/lib/src/span_exception.dart
@@ -36,7 +36,7 @@
     implements FormatException {
   final source;
 
-  int get position => span == null ? null : span.start.offset;
+  int get offset => span == null ? null : span.start.offset;
 
   SourceSpanFormatException(String message, SourceSpan span, [this.source])
       : super(message, span);
diff --git a/pkg/unittest/CHANGELOG.md b/pkg/unittest/CHANGELOG.md
index d8171f9..b913589 100644
--- a/pkg/unittest/CHANGELOG.md
+++ b/pkg/unittest/CHANGELOG.md
@@ -1,3 +1,7 @@
+##0.11.0+3
+
+* Updated maximum `matcher` version.
+
 ##0.11.0+2
 
 *  Removed unused files from tests and standardized remaining test file names.
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index c5b04ca..6d9e4a6 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,11 +1,10 @@
 name: unittest
-version: 0.11.0+2
+version: 0.11.0+3
 author: Dart Team <misc@dartlang.org>
 description: A library for writing dart unit tests.
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/unittest
 environment:
   sdk: '>=1.0.0 <2.0.0'
-documentation: http://api.dartlang.org/docs/pkg/unittest
 dependencies:
-  matcher: '>=0.10.0 <0.11.0'
+  matcher: '>=0.10.0 <0.12.0'
   stack_trace: '>=0.9.0 <2.0.0'
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index c8cf522..5582f35 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -744,7 +744,7 @@
 // Callback function that gets called from dartutils when there are
 // no more outstanding load requests.
 void FUNCTION_NAME(Builtin_DoneLoading)(Dart_NativeArguments args) {
-  Dart_Handle res = Dart_FinalizeLoading();
+  Dart_Handle res = Dart_FinalizeLoading(true);
   if (Dart_IsError(res)) {
     Dart_PropagateError(res);
   }
@@ -799,6 +799,12 @@
   Dart_Handle async_lib = Dart_LookupLibrary(url);
   DART_CHECK_VALID(async_lib);
   Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
+
+  // We need to ensure that all the scripts loaded so far are finalized
+  // as we are about to invoke some Dart code below to setup closures.
+  result = Dart_FinalizeLoading(false);
+  DART_CHECK_VALID(result);
+
   Dart_Handle timer_closure =
       Dart_Invoke(io_lib, NewString("_getTimerFactoryClosure"), 0, NULL);
   Dart_Handle args[1];
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 06f3884..8284c67 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -468,6 +468,14 @@
 
   Dart_Handle library = LoadGenericSnapshotCreationScript(Builtin::kIOLibrary);
   VerifyLoaded(library);
+  Dart_Handle result = Dart_FinalizeLoading(false);
+  if (Dart_IsError(result)) {
+    const char* err_msg = Dart_GetError(library);
+    Log::PrintErr("Errors encountered while loading: %s\n", err_msg);
+    Dart_ExitScope();
+    Dart_ShutdownIsolate();
+    exit(255);
+  }
 }
 
 
@@ -532,6 +540,10 @@
         Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
     CHECK_RESULT(builtin_lib);
 
+    // Ensure that we mark all libraries as loaded.
+    result = Dart_FinalizeLoading(false);
+    CHECK_RESULT(result);
+
     // Prepare for script loading by setting up the 'print' and 'timer'
     // closures and setting up 'package root' for URI resolution.
     result = DartUtils::PrepareForScriptLoading(package_root, builtin_lib);
@@ -556,6 +568,9 @@
     // Load the specified script.
     library = LoadSnapshotCreationScript(app_script_name);
     VerifyLoaded(library);
+    // Ensure that we mark all libraries as loaded.
+    result = Dart_FinalizeLoading(false);
+    CHECK_RESULT(result);
     CreateAndWriteSnapshot();
 
     Dart_EnterIsolate(UriResolverIsolateScope::isolate);
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 32edb0c..ff95402 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -115,6 +115,8 @@
   // Expect a library.
   ASSERT(library != Dart_Null());
   SHUTDOWN_ON_ERROR(library);
+  result = Dart_FinalizeLoading(false);
+  ASSERT(!Dart_IsError(result));
   Dart_ExitScope();
   Dart_ExitIsolate();
   bool retval = Dart_IsolateMakeRunnable(isolate);
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4788997..471d2cd 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2670,15 +2670,19 @@
 
 
 /**
- * Indicates that all outstanding load requests have been satisfied,
- * finalizing classes and completing deferred library futures.
+ * Indicates that all outstanding load requests have been satisfied.
+ * This finalizes all the new classes loaded and optionally completes
+ * deferred library futures.
  *
  * Requires there to be a current isolate.
  *
- * \return Success if all deferred library futures are completed.
- *   Otherwise, returns an error.
+ * \param complete_futures Specify true if all deferred library
+ *  futures should be completed, false otherwise.
+ *
+ * \return Success if all classes have been finalized and deferred library
+ *   futures are completed. Otherwise, returns an error.
  */
-DART_EXPORT Dart_Handle Dart_FinalizeLoading();
+DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures);
 
 
 /*
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 60c2b6a..78d30f7 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -53,7 +53,7 @@
   }
 
   Iterable<E> getRange(int start, [int end]) {
-    return IterableMixinWorkaround.getRangeList(this, start, end);
+    return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
   }
 
   // List interface.
@@ -136,7 +136,7 @@
   }
 
   Iterable<E> where(bool f(E element)) {
-    return IterableMixinWorkaround.where(this, f);
+    return new IterableMixinWorkaround<E>().where(this, f);
   }
 
   Iterable expand(Iterable f(E element)) {
@@ -144,19 +144,19 @@
   }
 
   Iterable<E> take(int n) {
-    return IterableMixinWorkaround.takeList(this, n);
+    return new IterableMixinWorkaround<E>().takeList(this, n);
   }
 
   Iterable<E> takeWhile(bool test(E value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
+    return new IterableMixinWorkaround<E>().takeWhile(this, test);
   }
 
   Iterable<E> skip(int n) {
-    return IterableMixinWorkaround.skipList(this, n);
+    return new IterableMixinWorkaround<E>().skipList(this, n);
   }
 
   Iterable<E> skipWhile(bool test(E value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
+    return new IterableMixinWorkaround<E>().skipWhile(this, test);
   }
 
   bool every(bool f(E element)) {
@@ -189,7 +189,8 @@
 
   bool get isNotEmpty => !isEmpty;
 
-  Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+  Iterable<E> get reversed =>
+      new IterableMixinWorkaround<E>().reversedList(this);
 
   void sort([int compare(E a, E b)]) {
     IterableMixinWorkaround.sortList(this, compare);
@@ -257,7 +258,7 @@
   }
 
   Map<int, E> asMap() {
-    return IterableMixinWorkaround.asMapList(this);
+    return new IterableMixinWorkaround<E>().asMapList(this);
   }
 }
 
@@ -347,7 +348,7 @@
   }
 
   Iterable<E> getRange(int start, int end) {
-    return IterableMixinWorkaround.getRangeList(this, start, end);
+    return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
   }
 
   // Collection interface.
@@ -377,7 +378,7 @@
   }
 
   Iterable<E> where(bool f(E element)) {
-    return IterableMixinWorkaround.where(this, f);
+    return new IterableMixinWorkaround<E>().where(this, f);
   }
 
   Iterable expand(Iterable f(E element)) {
@@ -385,19 +386,19 @@
   }
 
   Iterable<E> take(int n) {
-    return IterableMixinWorkaround.takeList(this, n);
+    return new IterableMixinWorkaround<E>().takeList(this, n);
   }
 
   Iterable<E> takeWhile(bool test(E value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
+    return new IterableMixinWorkaround<E>().takeWhile(this, test);
   }
 
   Iterable<E> skip(int n) {
-    return IterableMixinWorkaround.skipList(this, n);
+    return new IterableMixinWorkaround<E>().skipList(this, n);
   }
 
   Iterable<E> skipWhile(bool test(E value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
+    return new IterableMixinWorkaround<E>().skipWhile(this, test);
   }
 
   bool every(bool f(E element)) {
@@ -430,7 +431,8 @@
 
   bool get isNotEmpty => !isEmpty;
 
-  Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+  Iterable<E> get reversed =>
+      new IterableMixinWorkaround<E>().reversedList(this);
 
   void sort([int compare(E a, E b)]) {
     throw UnmodifiableListError.change();
@@ -502,7 +504,7 @@
   }
 
   Map<int, E> asMap() {
-    return IterableMixinWorkaround.asMapList(this);
+    return new IterableMixinWorkaround<E>().asMapList(this);
   }
 }
 
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index aae3197..1a7b882 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -77,7 +77,7 @@
   }
 
   Iterable<T> getRange(int start, int end) {
-    return IterableMixinWorkaround.getRangeList(this, start, end);
+    return new IterableMixinWorkaround<T>().getRangeList(this, start, end);
   }
 
   void setRange(int start, int end, Iterable<T> iterable, [int skipCount = 0]) {
@@ -216,7 +216,7 @@
     _setData(new_data);
   }
 
-  // Collection interface.
+  // Iterable interface.
 
   bool contains(Object element) {
     return IterableMixinWorkaround.contains(this, element);
@@ -261,7 +261,7 @@
   }
 
   Iterable<T> where(bool f(T element)) {
-    return IterableMixinWorkaround.where(this, f);
+    return new IterableMixinWorkaround<T>().where(this, f);
   }
 
   Iterable expand(Iterable f(T element)) {
@@ -269,19 +269,19 @@
   }
 
   Iterable<T> take(int n) {
-    return IterableMixinWorkaround.takeList(this, n);
+    return new IterableMixinWorkaround<T>().takeList(this, n);
   }
 
   Iterable<T> takeWhile(bool test(T value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
+    return new IterableMixinWorkaround<T>().takeWhile(this, test);
   }
 
   Iterable<T> skip(int n) {
-    return IterableMixinWorkaround.skipList(this, n);
+    return new IterableMixinWorkaround<T>().skipList(this, n);
   }
 
   Iterable<T> skipWhile(bool test(T value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
+    return new IterableMixinWorkaround<T>().skipWhile(this, test);
   }
 
   bool every(bool f(T element)) {
@@ -318,7 +318,8 @@
     this.length = 0;
   }
 
-  Iterable<T> get reversed => IterableMixinWorkaround.reversedList(this);
+  Iterable<T> get reversed =>
+      new IterableMixinWorkaround<T>().reversedList(this);
 
   void sort([int compare(T a, T b)]) {
     IterableMixinWorkaround.sortList(this, compare);
@@ -343,6 +344,6 @@
   }
 
   Map<int, T> asMap() {
-    return IterableMixinWorkaround.asMapList(this);
+    return new IterableMixinWorkaround<T>().asMapList(this);
   }
 }
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 370b5ca..51a9d80 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -241,7 +241,7 @@
 
 // Based class for _TypedList that provides common methods for implementing
 // the collection and list interfaces.
-
+// TODO(13647): Make this extends ListBase<T>
 abstract class _TypedListBase {
 
   // Method(s) implementing the Collection interface.
@@ -254,10 +254,6 @@
     }
   }
 
-  Iterable map(f(element)) {
-    return IterableMixinWorkaround.mapList(this, f);
-  }
-
   String join([String separator = ""]) {
     return IterableMixinWorkaround.join(this, separator);
   }
@@ -271,30 +267,48 @@
     return IterableMixinWorkaround.fold(this, initialValue, combine);
   }
 
-  Iterable where(bool f(element)) {
-    return IterableMixinWorkaround.where(this, f);
+  Iterable map(f(element)) {
+    return IterableMixinWorkaround.mapList(this, f);
   }
 
   Iterable expand(Iterable f(element)) {
     return IterableMixinWorkaround.expand(this, f);
   }
 
+  // The following methods need to know the element type (int or double).
+  Iterable where(bool f(element)) {
+    return new IterableMixinWorkaround().where(this, f);
+  }
+
   Iterable take(int n) {
-    return IterableMixinWorkaround.takeList(this, n);
+    return new IterableMixinWorkaround().takeList(this, n);
   }
 
   Iterable takeWhile(bool test(element)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
+    return new IterableMixinWorkaround().takeWhile(this, test);
   }
 
   Iterable skip(int n) {
-    return IterableMixinWorkaround.skipList(this, n);
+    return new IterableMixinWorkaround().skipList(this, n);
   }
 
   Iterable skipWhile(bool test(element)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
+    return new IterableMixinWorkaround().skipWhile(this, test);
   }
 
+  Iterable<dynamic> get reversed {
+    return new IterableMixinWorkaround().reversedList(this);
+  }
+
+  Map<int, dynamic> asMap() {
+    return new IterableMixinWorkaround().asMapList(this);
+  }
+
+  Iterable getRange(int start, [int end]) {
+    return new IterableMixinWorkaround().getRangeList(this, start, end);
+  }
+  // End of methods returning incorrectly parameterized types.
+
   bool every(bool f(element)) {
     return IterableMixinWorkaround.every(this, f);
   }
@@ -315,10 +329,6 @@
     return IterableMixinWorkaround.singleWhere(this, test);
   }
 
-  Iterable<dynamic> get reversed {
-    return IterableMixinWorkaround.reversedList(this);
-  }
-
   dynamic elementAt(int index) {
     return this[index];
   }
@@ -436,10 +446,6 @@
     return new Set.from(this);
   }
 
-  Map<int, dynamic> asMap() {
-    return IterableMixinWorkaround.asMapList(this);
-  }
-
   List sublist(int start, [int end]) {
     if (end == null) end = this.length;
     int length = end - start;
@@ -449,10 +455,6 @@
     return result;
   }
 
-  Iterable getRange(int start, [int end]) {
-    return IterableMixinWorkaround.getRangeList(this, start, end);
-  }
-
   void setRange(int start, int end, Iterable from, [int skipCount = 0]) {
     // Check ranges.
     if ((start < 0) || (start > length)) {
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index c8e859d..2ddf07c 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -2183,6 +2183,17 @@
 }
 
 
+bool Address::CanHoldImmediateOffset(
+    bool is_load, intptr_t cid, int64_t offset) {
+  int32_t offset_mask = 0;
+  if (is_load) {
+    return CanHoldLoadOffset(OperandSizeFor(cid), offset, &offset_mask);
+  } else {
+    return CanHoldStoreOffset(OperandSizeFor(cid), offset, &offset_mask);
+  }
+}
+
+
 void Assembler::Push(Register rd, Condition cond) {
   str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
 }
@@ -3224,6 +3235,73 @@
 }
 
 
+Address Assembler::ElementAddressForIntIndex(bool is_load,
+                                             bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             intptr_t index,
+                                             Register temp) {
+  const int64_t offset_base =
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  const int64_t offset = offset_base +
+      static_cast<int64_t>(index) * index_scale;
+  ASSERT(Utils::IsInt(32, offset));
+
+  if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
+    return Address(array, static_cast<int32_t>(offset));
+  } else {
+    ASSERT(Address::CanHoldImmediateOffset(is_load, cid, offset - offset_base));
+    AddImmediate(temp, array, static_cast<int32_t>(offset_base));
+    return Address(temp, static_cast<int32_t>(offset - offset_base));
+  }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+                                             bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  const OperandSize size = Address::OperandSizeFor(cid);
+  ASSERT(array != IP);
+  ASSERT(index != IP);
+  const Register base = is_load ? IP : index;
+  if ((offset != 0) ||
+      (size == kSWord) || (size == kDWord) || (size == kRegList)) {
+    if (shift < 0) {
+      ASSERT(shift == -1);
+      add(base, array, Operand(index, ASR, 1));
+    } else {
+      add(base, array, Operand(index, LSL, shift));
+    }
+  } else {
+    if (shift < 0) {
+      ASSERT(shift == -1);
+      return Address(array, index, ASR, 1);
+    } else {
+      return Address(array, index, LSL, shift);
+    }
+  }
+  int32_t offset_mask = 0;
+  if ((is_load && !Address::CanHoldLoadOffset(size,
+                                              offset,
+                                              &offset_mask)) ||
+      (!is_load && !Address::CanHoldStoreOffset(size,
+                                                offset,
+                                                &offset_mask))) {
+    AddImmediate(base, offset & ~offset_mask);
+    offset = offset & offset_mask;
+  }
+  return Address(base, offset);
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
   "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 5af7c66..a09145a 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -250,6 +250,9 @@
   static bool CanHoldStoreOffset(OperandSize size,
                                  int32_t offset,
                                  int32_t* offset_mask);
+  static bool CanHoldImmediateOffset(bool is_load,
+                                     intptr_t cid,
+                                     int64_t offset);
 
  private:
   uint32_t encoding() const { return encoding_; }
@@ -781,6 +784,21 @@
                                      Register temp_reg,
                                      Heap::Space space = Heap::kNew);
 
+  Address ElementAddressForIntIndex(bool is_load,
+                                    bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    intptr_t index,
+                                    Register temp);
+
+  Address ElementAddressForRegIndex(bool is_load,
+                                    bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    Register index);
+
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
   // Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 4766040..6da9770 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -1413,6 +1413,47 @@
   }
 }
 
+
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             intptr_t index) const {
+  const int64_t offset = index * index_scale +
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  ASSERT(Utils::IsInt(32, offset));
+  const OperandSize size = Address::OperandSizeFor(cid);
+  ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
+  return Address(array, static_cast<int32_t>(offset), Address::Offset, size);
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+                                             bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  const int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  ASSERT(array != TMP);
+  ASSERT(index != TMP);
+  const Register base = is_load ? TMP : index;
+  if ((offset == 0) && (shift == 0)) {
+    return Address(array, index, UXTX, Address::Unscaled);
+  } else if (shift < 0) {
+    ASSERT(shift == -1);
+    add(base, array, Operand(index, ASR, 1));
+  } else {
+    add(base, array, Operand(index, LSL, shift));
+  }
+  const OperandSize size = Address::OperandSizeFor(cid);
+  ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
+  return Address(base, offset, Address::Offset, size);
+}
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index fa76634..03224f6 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1219,6 +1219,18 @@
                    Register instance_reg,
                    Register pp);
 
+  Address ElementAddressForIntIndex(bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    intptr_t index) const;
+  Address ElementAddressForRegIndex(bool is_load,
+                                    bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    Register index);
+
  private:
   AssemblerBuffer buffer_;  // Contains position independent code.
 
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index f76403c..1491cf3 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2741,6 +2741,56 @@
 }
 
 
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             intptr_t index) {
+  if (is_external) {
+    return Address(array, index * index_scale);
+  } else {
+    const int64_t disp = static_cast<int64_t>(index) * index_scale +
+        Instance::DataOffsetFor(cid);
+    ASSERT(Utils::IsInt(32, disp));
+    return FieldAddress(array, static_cast<int32_t>(disp));
+  }
+}
+
+
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+  // expected to be untagged before accessing.
+  ASSERT(kSmiTagShift == 1);
+  switch (index_scale) {
+    case 1: return TIMES_1;
+    case 2: return TIMES_1;
+    case 4: return TIMES_2;
+    case 8: return TIMES_4;
+    case 16: return TIMES_8;
+    default:
+      UNREACHABLE();
+      return TIMES_1;
+  }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_external,
+                                            intptr_t cid,
+                                            intptr_t index_scale,
+                                            Register array,
+                                            Register index) {
+  if (is_external) {
+    return Address(array, index, ToScaleFactor(index_scale), 0);
+  } else {
+    return FieldAddress(array,
+                        index,
+                        ToScaleFactor(index_scale),
+                        Instance::DataOffsetFor(cid));
+  }
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
 };
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 4e3fefb..bd11704 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -697,6 +697,18 @@
   void LoadTaggedClassIdMayBeSmi(Register result,
                                  Register object);
 
+  static Address ElementAddressForIntIndex(bool is_external,
+                                           intptr_t cid,
+                                           intptr_t index_scale,
+                                           Register array,
+                                           intptr_t index);
+
+  static Address ElementAddressForRegIndex(bool is_external,
+                                           intptr_t cid,
+                                           intptr_t index_scale,
+                                           Register array,
+                                           Register index);
+
   /*
    * Misc. functionality
    */
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 647ec7f..3cfcdea 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -1095,6 +1095,47 @@
 }
 
 
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             intptr_t index) const {
+  const int64_t offset = index * index_scale +
+      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
+  ASSERT(Utils::IsInt(32, offset));
+  ASSERT(Address::CanHoldOffset(offset));
+  return Address(array, static_cast<int32_t>(offset));
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_load,
+                                             bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             Register index) {
+  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
+  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
+  const int32_t offset =
+      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
+  ASSERT(array != TMP);
+  ASSERT(index != TMP);
+  const Register base = is_load ? TMP : index;
+  if (shift < 0) {
+    ASSERT(shift == -1);
+    sra(TMP, index, 1);
+    addu(base, array, TMP);
+  } else if (shift == 0) {
+    addu(base, array, index);
+  } else {
+    sll(TMP, index, shift);
+    addu(base, array, TMP);
+  }
+  ASSERT(Address::CanHoldOffset(offset));
+  return Address(base, offset);
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "zr", "tmp", "v0", "v1", "a0", "a1", "a2", "a3",
   "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 2f7c38f..d5ee12e 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1222,6 +1222,18 @@
   // up on entry (it is the frame of the unoptimized code).
   void EnterOsrFrame(intptr_t extra_size);
 
+  Address ElementAddressForIntIndex(bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    intptr_t index) const;
+  Address ElementAddressForRegIndex(bool is_load,
+                                    bool is_external,
+                                    intptr_t cid,
+                                    intptr_t index_scale,
+                                    Register array,
+                                    Register index);
+
   // On some other platforms, we draw a distinction between safe and unsafe
   // smis.
   static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 3b08240..1a4a376 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -3411,6 +3411,56 @@
 }
 
 
+Address Assembler::ElementAddressForIntIndex(bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             intptr_t index) {
+  if (is_external) {
+    return Address(array, index * index_scale);
+  } else {
+    const int64_t disp = static_cast<int64_t>(index) * index_scale +
+        Instance::DataOffsetFor(cid);
+    ASSERT(Utils::IsInt(32, disp));
+    return FieldAddress(array, static_cast<int32_t>(disp));
+  }
+}
+
+
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+  // expected to be untagged before accessing.
+  ASSERT(kSmiTagShift == 1);
+  switch (index_scale) {
+    case 1: return TIMES_1;
+    case 2: return TIMES_1;
+    case 4: return TIMES_2;
+    case 8: return TIMES_4;
+    case 16: return TIMES_8;
+    default:
+      UNREACHABLE();
+      return TIMES_1;
+  }
+}
+
+
+Address Assembler::ElementAddressForRegIndex(bool is_external,
+                                             intptr_t cid,
+                                             intptr_t index_scale,
+                                             Register array,
+                                             Register index) {
+  if (is_external) {
+    return Address(array, index, ToScaleFactor(index_scale), 0);
+  } else {
+    return FieldAddress(array,
+                        index,
+                        ToScaleFactor(index_scale),
+                        Instance::DataOffsetFor(cid));
+  }
+}
+
+
 static const char* cpu_reg_names[kNumberOfCpuRegisters] = {
   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 3323b73..6644ae1 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -884,6 +884,17 @@
 
   static const char* FpuRegisterName(FpuRegister reg);
 
+  static Address ElementAddressForIntIndex(bool is_external,
+                                           intptr_t cid,
+                                           intptr_t index_scale,
+                                           Register array,
+                                           intptr_t index);
+  static Address ElementAddressForRegIndex(bool is_external,
+                                           intptr_t cid,
+                                           intptr_t index_scale,
+                                           Register array,
+                                           Register index);
+
   // On some other platforms, we draw a distinction between safe and unsafe
   // smis.
   static bool IsSafe(const Object& object) { return true; }
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index cd8dc78..8e58da5 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -153,12 +153,16 @@
 
   Dart_Handle lib = TestCase::LoadTestScript(
       kScriptChars,
-      reinterpret_cast<Dart_NativeEntryResolver>(bm_uda_lookup));
+      reinterpret_cast<Dart_NativeEntryResolver>(bm_uda_lookup),
+      USER_TEST_URI,
+      false);
 
   // Create a native wrapper class with native fields.
   Dart_Handle result = Dart_CreateNativeWrapperClass(
       lib, NewString("NativeFieldsWrapper"), 1);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   Dart_Handle args[1];
   args[0] = Dart_NewInteger(kNumIterations);
@@ -411,7 +415,7 @@
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
-  Api::CheckIsolateState(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(Isolate::Current());
 
   // Write snapshot with object content.
   FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -442,7 +446,7 @@
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
-  Api::CheckIsolateState(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(Isolate::Current());
 
   // Write snapshot with object content.
   FullSnapshotWriter writer(&buffer, &malloc_allocator);
@@ -478,7 +482,7 @@
       "\n";
   const intptr_t kLoopCount = 1000000;
   TestCase::LoadTestScript(kScriptChars, NULL);
-  Api::CheckIsolateState(Isolate::Current());
+  Api::CheckAndFinalizePendingClasses(Isolate::Current());
   Dart_Isolate isolate = Dart_CurrentIsolate();
   Timer timer(true, "Enter and Exit isolate");
   timer.Start();
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 937286e..20cce5c 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -7,6 +7,7 @@
 #include "include/dart_api.h"
 
 #include "vm/bootstrap_natives.h"
+#include "vm/class_finalizer.h"
 #include "vm/compiler.h"
 #include "vm/dart_api_impl.h"
 #include "vm/object.h"
@@ -311,6 +312,7 @@
   }
   if (error.IsNull()) {
     SetupNativeResolver();
+    ClassFinalizer::ProcessPendingClasses();
   }
 
   // Restore the library tag handler for the isolate.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 5d39333..283a260 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1458,8 +1458,14 @@
                     name.ToCString(),
                     super_class_name.ToCString());
       }
-      // The function may be a still unresolved redirecting factory. Do not yet
-      // try to resolve it in order to avoid cycles in class finalization.
+      if (function.IsRedirectingFactory()) {
+        // The function may be a still unresolved redirecting factory. Do not
+        // yet try to resolve it in order to avoid cycles in class finalization.
+        // However, the redirection type should be finalized.
+        Type& type = Type::Handle(function.RedirectionType());
+        type ^= FinalizeType(cls, type, kCanonicalize);
+        function.SetRedirectionType(type);
+      }
     } else if (function.IsGetterFunction() ||
                function.IsImplicitGetterFunction()) {
       super_class = FindSuperOwnerOfFunction(cls, name);
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 5592f67..7de90df 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -258,9 +258,8 @@
       PcDescriptors::Handle(code.pc_descriptors());
   int call_count = 0;
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall);
-  while (iter.HasNext()) {
-    const uword pc = iter.NextPc();
-    stackmap_table_builder->AddEntry(pc - code.EntryPoint(),
+  while (iter.MoveNext()) {
+    stackmap_table_builder->AddEntry(iter.Pc() - code.EntryPoint(),
                                      stack_bitmap,
                                      0);
     ++call_count;
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 60a66ab..557d61c 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -479,6 +479,10 @@
         DeadCodeElimination::EliminateDeadPhis(flow_graph);
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
+        if (optimizer.Canonicalize()) {
+          optimizer.Canonicalize();
+        }
+
         // Attempt to sink allocations of temporary non-escaping objects to
         // the deoptimization path.
         AllocationSinking* sinking = NULL;
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index f4ee0fe..7344761 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -93,13 +93,11 @@
   // Only IC based calls have counting.
   PcDescriptors::Iterator iter(descriptors,
       RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall);
-  while (iter.HasNext()) {
+  while (iter.MoveNext()) {
     HANDLESCOPE(isolate);
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    const ICData* ic_data = (*ic_data_array)[rec.deopt_id()];
+    const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
     if (!ic_data->IsNull()) {
-      const intptr_t token_pos = rec.token_pos();
+      const intptr_t token_pos = iter.TokenPos();
       // Filter out descriptors that do not map to tokens in the source code.
       if ((token_pos < begin_pos) || (token_pos > end_pos)) {
         continue;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index d418d12..3570912 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -371,7 +371,7 @@
 }
 
 
-Dart_Handle Api::CheckIsolateState(Isolate* isolate) {
+Dart_Handle Api::CheckAndFinalizePendingClasses(Isolate* isolate) {
   if (!isolate->AllowClassFinalization()) {
     // Class finalization is blocked for the isolate. Do nothing.
     return Api::Success();
@@ -1400,7 +1400,8 @@
   if (size == NULL) {
     RETURN_NULL_ERROR(size);
   }
-  Dart_Handle state = Api::CheckIsolateState(isolate);
+  // Finalize all classes if needed.
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -1424,7 +1425,8 @@
   if (size == NULL) {
     RETURN_NULL_ERROR(size);
   }
-  Dart_Handle state = Api::CheckIsolateState(isolate);
+  // Finalize all classes if needed.
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -1715,6 +1717,11 @@
     *value = false;
     RETURN_TYPE_ERROR(isolate, type, Type);
   }
+  if (!type_obj.IsFinalized()) {
+    return Api::NewError(
+        "%s expects argument 'type' to be a fully resolved type.",
+        CURRENT_FUNC);
+  }
   if (object == Api::Null()) {
     *value = false;
     return Api::Success();
@@ -1724,12 +1731,6 @@
     *value = false;
     RETURN_TYPE_ERROR(isolate, object, Instance);
   }
-  // Finalize all classes.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    *value = false;
-    return state;
-  }
   CHECK_CALLBACK_STATE(isolate);
   Error& malformed_type_error = Error::Handle(isolate);
   *value = instance.IsInstanceOf(type_obj,
@@ -3506,6 +3507,11 @@
   }
   Type& type_obj = Type::Handle();
   type_obj ^= unchecked_type.raw();
+  if (!type_obj.IsFinalized()) {
+    return Api::NewError(
+        "%s expects argument 'type' to be a fully resolved type.",
+        CURRENT_FUNC);
+  }
   Class& cls = Class::Handle(isolate, type_obj.type_class());
   TypeArguments& type_arguments =
       TypeArguments::Handle(isolate, type_obj.arguments());
@@ -3522,10 +3528,6 @@
   } else {
     RETURN_TYPE_ERROR(isolate, constructor_name, String);
   }
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
 
   // Resolve the constructor.
   String& constr_name =
@@ -3753,9 +3755,8 @@
     RETURN_TYPE_ERROR(isolate, object, Instance);
   }
 
-  // Since we have allocated an object it would mean that all classes
-  // are finalized and hence it is not necessary to call
-  // Api::CheckIsolateState.
+  // Since we have allocated an object it would mean that the type
+  // is finalized.
   // TODO(asiva): How do we ensure that a constructor is not called more than
   // once for the same object.
 
@@ -3841,10 +3842,10 @@
   Dart_Handle result;
   Array& args = Array::Handle(isolate);
   if (obj.IsType()) {
-    // Finalize all classes.
-    Dart_Handle state = Api::CheckIsolateState(isolate);
-    if (::Dart_IsError(state)) {
-      return state;
+    if (!Type::Cast(obj).IsFinalized()) {
+      return Api::NewError(
+          "%s expects argument 'target' to be a fully resolved type.",
+          CURRENT_FUNC);
     }
 
     const Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -3869,9 +3870,9 @@
     }
     return result;
   } else if (obj.IsNull() || obj.IsInstance()) {
-    // Since we have allocated an object it would mean that all classes
-    // are finalized and hence it is not necessary to call
-    // Api::CheckIsolateState.
+    // Since we have allocated an object it would mean that the type of the
+    // receiver is already resolved and finalized, hence it is not necessary
+    // to check here.
     Instance& instance = Instance::Handle(isolate);
     instance ^= obj.raw();
     ArgumentsDescriptor args_desc(
@@ -3910,10 +3911,11 @@
     // Check whether class finalization is needed.
     const Library& lib = Library::Cast(obj);
 
-    // Finalize all classes if needed.
-    Dart_Handle state = Api::CheckIsolateState(isolate);
-    if (::Dart_IsError(state)) {
-      return state;
+    // Check that the library is loaded.
+    if (!lib.Loaded()) {
+      return Api::NewError(
+          "%s expects library argument 'target' to be loaded.",
+          CURRENT_FUNC);
     }
 
     const Function& function =
@@ -3994,12 +3996,6 @@
     RETURN_TYPE_ERROR(isolate, name, String);
   }
 
-  // Finalize all classes.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
-
   Field& field = Field::Handle(isolate);
   Function& getter = Function::Handle(isolate);
   const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
@@ -4007,6 +4003,11 @@
     return Api::NewError("%s expects argument 'container' to be non-null.",
                          CURRENT_FUNC);
   } else if (obj.IsType()) {
+    if (!Type::Cast(obj).IsFinalized()) {
+      return Api::NewError(
+          "%s expects argument 'container' to be a fully resolved type.",
+          CURRENT_FUNC);
+    }
     // To access a static field we may need to use the Field or the
     // getter Function.
     Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -4065,6 +4066,12 @@
     // getter Function.  The getter function may either be in the
     // library or in the field's owner class, depending.
     const Library& lib = Library::Cast(obj);
+    // Check that the library is loaded.
+    if (!lib.Loaded()) {
+      return Api::NewError(
+          "%s expects library argument 'container' to be loaded.",
+          CURRENT_FUNC);
+    }
     field = lib.LookupFieldAllowPrivate(field_name);
     if (field.IsNull()) {
       // No field found and no ambiguity error.  Check for a getter in the lib.
@@ -4120,11 +4127,6 @@
   Instance& value_instance = Instance::Handle(isolate);
   value_instance ^= value_obj.raw();
 
-  // Finalize all classes.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
   Field& field = Field::Handle(isolate);
   Function& setter = Function::Handle(isolate);
   const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
@@ -4132,6 +4134,12 @@
     return Api::NewError("%s expects argument 'container' to be non-null.",
                          CURRENT_FUNC);
   } else if (obj.IsType()) {
+    if (!Type::Cast(obj).IsFinalized()) {
+      return Api::NewError(
+          "%s expects argument 'container' to be a fully resolved type.",
+          CURRENT_FUNC);
+    }
+
     // To access a static field we may need to use the Field or the
     // setter Function.
     Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
@@ -4210,6 +4218,12 @@
     // setter Function.  The setter function may either be in the
     // library or in the field's owner class, depending.
     const Library& lib = Library::Cast(obj);
+    // Check that the library is loaded.
+    if (!lib.Loaded()) {
+      return Api::NewError(
+          "%s expects library argument 'container' to be loaded.",
+          CURRENT_FUNC);
+    }
     field = lib.LookupFieldAllowPrivate(field_name);
     if (field.IsNull()) {
       const String& setter_name =
@@ -4920,15 +4934,15 @@
   if (lib.IsNull()) {
     RETURN_TYPE_ERROR(isolate, library, Library);
   }
+  if (!lib.Loaded()) {
+    return Api::NewError(
+        "%s expects library argument 'library' to be loaded.",
+        CURRENT_FUNC);
+  }
   const String& name_str = Api::UnwrapStringHandle(isolate, class_name);
   if (name_str.IsNull()) {
     RETURN_TYPE_ERROR(isolate, class_name, String);
   }
-  // Ensure all classes are finalized.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
   const Class& cls =
       Class::Handle(isolate, lib.LookupClassAllowPrivate(name_str));
   if (cls.IsNull()) {
@@ -5055,7 +5069,7 @@
   // If this is the dart:_builtin library, register it with the VM.
   if (url_str.Equals("dart:_builtin")) {
     isolate->object_store()->set_builtin_library(library);
-    Dart_Handle state = Api::CheckIsolateState(isolate);
+    Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
     if (::Dart_IsError(state)) {
       return state;
     }
@@ -5170,7 +5184,7 @@
 
 // Finalizes classes and invokes Dart core library function that completes
 // futures of loadLibrary calls (deferred library loading).
-DART_EXPORT Dart_Handle Dart_FinalizeLoading() {
+DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
   CHECK_CALLBACK_STATE(isolate);
@@ -5181,24 +5195,26 @@
   // invoing of _completeDeferredLoads) into Isolate::DoneLoading().
 
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckIsolateState(isolate);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
   if (::Dart_IsError(state)) {
     return state;
   }
 
-  const Library& corelib = Library::Handle(isolate, Library::CoreLibrary());
-  const String& function_name =
-      String::Handle(isolate, String::New("_completeDeferredLoads"));
-  const Function& function =
-      Function::Handle(isolate,
-                       corelib.LookupFunctionAllowPrivate(function_name));
-  ASSERT(!function.IsNull());
-  const Array& args = Array::empty_array();
+  if (complete_futures) {
+    const Library& corelib = Library::Handle(isolate, Library::CoreLibrary());
+    const String& function_name =
+        String::Handle(isolate, String::New("_completeDeferredLoads"));
+    const Function& function =
+        Function::Handle(isolate,
+                         corelib.LookupFunctionAllowPrivate(function_name));
+    ASSERT(!function.IsNull());
+    const Array& args = Array::empty_array();
 
-  const Object& res =
-      Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
-  if (res.IsError() || res.IsUnhandledException()) {
-    return Api::NewHandle(isolate, res.raw());
+    const Object& res =
+        Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
+    if (res.IsError() || res.IsUnhandledException()) {
+      return Api::NewHandle(isolate, res.raw());
+    }
   }
   return Api::Success();
 }
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 213590e..f659b8a 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -142,9 +142,10 @@
   static const Instance& UnwrapInstanceHandle(
       const ReusableObjectHandleScope& reused, Dart_Handle object);
 
-  // Returns an Error handle if isolate is in an inconsistent state.
+  // Returns an Error handle if isolate is in an inconsistent state
+  // or there was an error while finalizing classes.
   // Returns a Success handle when no error condition exists.
-  static Dart_Handle CheckIsolateState(Isolate *isolate);
+  static Dart_Handle CheckAndFinalizePendingClasses(Isolate *isolate);
 
   // Casts the internal Isolate* type to the external Dart_Isolate type.
   static Dart_Isolate CastIsolate(Isolate* isolate);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 90ac918..6032692 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3875,6 +3875,8 @@
   EXPECT_VALID(imported_lib);
   Dart_Handle result = Dart_LibraryImportLibrary(lib, imported_lib, prefix);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
   result = Dart_Invoke(imported_lib, NewString("test2"), 0, NULL);
   EXPECT_VALID(result);
 
@@ -4091,14 +4093,17 @@
   const int kNumNativeFields = 4;
 
   // Create a test library.
-  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
-                                             native_field_lookup);
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL,
+                                             USER_TEST_URI, false);
 
   // Create a native wrapper class with native fields.
   result = Dart_CreateNativeWrapperClass(
       lib,
       NewString("NativeFieldsWrapper"),
       kNumNativeFields);
+  EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Load up a test script in the test library.
 
@@ -4138,7 +4143,8 @@
       "}\n";
   Dart_Handle result;
   // Create a test library and Load up a test script in it.
-  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL,
+                                             USER_TEST_URI, false);
 
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
@@ -4437,7 +4443,9 @@
 
   // Create a test library.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars,
-                                             native_field_lookup);
+                                             native_field_lookup,
+                                             USER_TEST_URI,
+                                             false);
 
   // Create a native wrapper class with native fields.
   Dart_Handle result = Dart_CreateNativeWrapperClass(
@@ -4445,6 +4453,8 @@
       NewString("NativeFieldsWrapper"),
       kNumNativeFields);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Load up a test script in it.
 
@@ -5229,6 +5239,8 @@
   // Import lib2 from lib1
   Dart_Handle result = Dart_LibraryImportLibrary(lib1, lib2, Dart_Null());
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // We can invoke both private and non-private local functions.
   EXPECT_VALID(Dart_Invoke(lib1, NewString("local"), 0, NULL));
@@ -5772,6 +5784,7 @@
   // Load a script successfully.
   result = Dart_LoadScript(url, source, 0, 0);
   EXPECT_VALID(result);
+  Dart_FinalizeLoading(false);
 
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
@@ -6039,6 +6052,8 @@
   Dart_Handle source = NewString(kLibraryChars);
   Dart_Handle lib = Dart_LoadLibrary(url, source);
   EXPECT_VALID(lib);
+  Dart_Handle result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   Dart_Handle list = Dart_LibraryGetClassNames(lib);
   EXPECT_VALID(list);
@@ -6090,6 +6105,8 @@
   Dart_Handle source = NewString(kLibraryChars);
   Dart_Handle lib = Dart_LoadLibrary(url, source);
   EXPECT_VALID(lib);
+  Dart_Handle result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   Dart_Handle list = Dart_GetFunctionNames(lib);
   EXPECT_VALID(list);
@@ -6205,6 +6222,8 @@
   Dart_Handle prefix = NewString("foo");
   Dart_Handle result = Dart_LibraryImportLibrary(lib2, lib1, prefix);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Lib1 is imported under a library prefix and therefore 'foo' should
   // not be found directly in lib2.
@@ -6387,12 +6406,14 @@
   Dart_Handle lib = Dart_LoadLibrary(url, source);
   EXPECT_VALID(lib);
   EXPECT(Dart_IsLibrary(lib));
+  Dart_Handle result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Call a dynamic function on OldClass.
   Dart_Handle type = Dart_GetType(lib, NewString("OldClass"), 0, NULL);
   EXPECT_VALID(type);
   Dart_Handle recv = Dart_New(type, Dart_Null(), 0, NULL);
-  Dart_Handle result = Dart_Invoke(recv, NewString("foo"), 0, NULL);
+  result = Dart_Invoke(recv, NewString("foo"), 0, NULL);
   EXPECT_VALID(result);
   EXPECT(Dart_IsString(result));
   const char* result_cstr = "";
@@ -6403,6 +6424,8 @@
   url = NewString("source_url");
   source = NewString(kSourceChars);
   EXPECT_VALID(Dart_LoadSource(lib, url, source));
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Call a dynamic function on NewClass in the updated library.
   type = Dart_GetType(lib, NewString("NewClass"), 0, NULL);
@@ -6444,6 +6467,8 @@
 
   result = Dart_LibraryLoadPatch(lib, url, source);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
   EXPECT_VALID(result);
@@ -6591,6 +6616,8 @@
   source = NewString(kScriptChars);
   Dart_Handle test_script = Dart_LoadScript(script_url, source, 0, 0);
   EXPECT_VALID(test_script);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   // Make sure that we can compile all of the patched code.
   result = Dart_CompileAll();
@@ -6693,6 +6720,8 @@
   EXPECT_VALID(result);
   Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
   EXPECT_VALID(lib);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
   EXPECT(Dart_IsLibrary(lib));
   Dart_Handle type = Dart_GetType(lib, NewString("Test"), 0, NULL);
   EXPECT_VALID(type);
@@ -6785,6 +6814,8 @@
   source = NewString(kLibrary2Chars);
   Dart_LoadLibrary(url, source);
 
+  Dart_FinalizeLoading(false);
+
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
 }
@@ -6821,6 +6852,8 @@
   url = NewString("library1_dart");
   source = NewString(kLibrary1Chars);
   Dart_LoadLibrary(url, source);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT(Dart_IsError(result));
@@ -6858,6 +6891,7 @@
   url = NewString("library1_dart");
   source = NewString(kLibrary1Chars);
   Dart_LoadLibrary(url, source);
+  Dart_FinalizeLoading(false);
 
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
@@ -6888,6 +6922,7 @@
   url = NewString("lib.dart");
   source = NewString(kLibraryChars);
   Dart_LoadLibrary(url, source);
+  Dart_FinalizeLoading(false);
 
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
@@ -7027,6 +7062,8 @@
   EXPECT_VALID(result);
   Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
   EXPECT_VALID(lib);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
   Dart_ExitScope();
   Dart_ExitIsolate();
   bool retval = Dart_IsolateMakeRunnable(isolate);
@@ -7168,6 +7205,8 @@
     EXPECT_VALID(result);
     lib = Dart_LoadScript(url, source, 0, 0);
     EXPECT_VALID(lib);
+    result = Dart_FinalizeLoading(false);
+    EXPECT_VALID(result);
     result =
         Dart_SetNativeResolver(lib, &IsolateInterruptTestNativeLookup, NULL);
     DART_CHECK_VALID(result);
@@ -7353,6 +7392,8 @@
     EXPECT_VALID(result);
     Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
     EXPECT_VALID(lib);
+    result = Dart_FinalizeLoading(false);
+    EXPECT_VALID(result);
     result = Dart_Invoke(lib, NewString("main"), 0, NULL);
     EXPECT_VALID(result);
     Dart_ExitScope();
@@ -7533,6 +7574,8 @@
   EXPECT(Dart_IsLibrary(lib));
   result = Dart_SetNativeResolver(lib, &MyNativeClosureResolver, NULL);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
@@ -7680,6 +7723,8 @@
   EXPECT(Dart_IsLibrary(lib));
   result = Dart_SetNativeResolver(lib, &MyStaticNativeClosureResolver, NULL);
   EXPECT_VALID(result);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
@@ -8356,6 +8401,8 @@
   Dart_Handle source = NewString(kLoadSecond);
   Dart_Handle url = NewString(TestCase::url());
   Dart_LoadSource(TestCase::lib(), url, source);
+  result = Dart_FinalizeLoading(false);
+  EXPECT_VALID(result);
 
   dart_args[0] = Dart_NewInteger(1);
   result = Dart_Invoke(lib1, NewString("start"), 1, dart_args);
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 6fd0c2a..c1391a5 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -362,12 +362,10 @@
     token_pos_ = Scanner::kNoSourcePos;
     GetPcDescriptors();
     PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
-    while (iter.HasNext()) {
-      RawPcDescriptors::PcDescriptorRec rec;
-      iter.NextRec(&rec);
-      if (rec.pc() == pc_) {
-        try_index_ = rec.try_index();
-        token_pos_ = rec.token_pos();
+    while (iter.MoveNext()) {
+      if (iter.Pc() == pc_) {
+        try_index_ = iter.TryIndex();
+        token_pos_ = iter.TokenPos();
         break;
       }
     }
@@ -931,21 +929,18 @@
     RawPcDescriptors::kRuntimeCall;
 
 
-static bool HasTokenPos(const RawPcDescriptors::PcDescriptorRec& rec) {
-  return rec.token_pos() != Scanner::kNoSourcePos;
-}
-
-
 CodeBreakpoint::CodeBreakpoint(const Code& code,
-                               const RawPcDescriptors::PcDescriptorRec& rec)
+                               intptr_t token_pos,
+                               uword pc,
+                               RawPcDescriptors::Kind kind)
     : code_(code.raw()),
-      token_pos_(rec.token_pos()),
-      pc_(rec.pc()),
+      token_pos_(token_pos),
+      pc_(pc),
       line_number_(-1),
       is_enabled_(false),
       src_bpt_(NULL),
       next_(NULL),
-      breakpoint_kind_(rec.kind()),
+      breakpoint_kind_(kind),
       saved_value_(0) {
   ASSERT(!code.IsNull());
   ASSERT(token_pos_ > 0);
@@ -1204,18 +1199,17 @@
   ASSERT(!target_function.HasOptimizedCode());
   PcDescriptors& desc = PcDescriptors::Handle(isolate, code.pc_descriptors());
   PcDescriptors::Iterator iter(desc, kSafepointKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (HasTokenPos(rec)) {
-      CodeBreakpoint* bpt = GetCodeBreakpoint(rec.pc());
+  while (iter.MoveNext()) {
+    if (iter.TokenPos() != Scanner::kNoSourcePos) {
+      CodeBreakpoint* bpt = GetCodeBreakpoint(iter.Pc());
       if (bpt != NULL) {
         // There is already a breakpoint for this address. Make sure
         // it is enabled.
         bpt->Enable();
         continue;
       }
-      bpt = new CodeBreakpoint(code, rec);
+      bpt = new CodeBreakpoint(code, iter.TokenPos(),
+                               iter.Pc(), iter.Kind());
       RegisterCodeBreakpoint(bpt);
       bpt->Enable();
     }
@@ -1256,9 +1250,8 @@
   const PcDescriptors& pc_desc =
       PcDescriptors::Handle(isolate, code.pc_descriptors());
   PcDescriptors::Iterator iter(pc_desc, RawPcDescriptors::kClosureCall);
-  while (iter.HasNext()) {
-    const uword rec_pc = iter.NextPc();
-    if (rec_pc == pc) {
+  while (iter.MoveNext()) {
+    if (iter.Pc() == pc) {
       is_closure_call = true;
       break;
     }
@@ -1552,12 +1545,10 @@
   uword lowest_pc = kUwordMax;
   intptr_t lowest_pc_token_pos = INT_MAX;
   PcDescriptors::Iterator iter(desc, kSafepointKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    intptr_t desc_token_pos = rec.token_pos();
+  while (iter.MoveNext()) {
+    const intptr_t desc_token_pos = iter.TokenPos();
     ASSERT(desc_token_pos >= 0);
-    if (HasTokenPos(rec)) {
+    if (desc_token_pos != Scanner::kNoSourcePos) {
       if ((desc_token_pos < requested_token_pos) ||
           (desc_token_pos > last_token_pos)) {
         // This descriptor is outside the desired token range.
@@ -1568,9 +1559,9 @@
         // the first acceptable token position.
         best_fit_pos = desc_token_pos;
       }
-      if (rec.pc() < lowest_pc) {
+      if (iter.Pc() < lowest_pc) {
         // This descriptor so far has the lowest code address.
-        lowest_pc = rec.pc();
+        lowest_pc = iter.Pc();
         lowest_pc_token_pos = desc_token_pos;
       }
     }
@@ -1596,34 +1587,33 @@
 
 void Debugger::MakeCodeBreakpointAt(const Function& func,
                                     SourceBreakpoint* bpt) {
+  ASSERT(bpt->token_pos_ != Scanner::kNoSourcePos);
   ASSERT((bpt != NULL) && bpt->IsResolved());
   ASSERT(!func.HasOptimizedCode());
   Code& code = Code::Handle(func.unoptimized_code());
   ASSERT(!code.IsNull());
   PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
   uword lowest_pc = kUwordMax;
+  RawPcDescriptors::Kind lowest_kind = RawPcDescriptors::kAnyKind;
   // Find the safe point with the lowest compiled code address
   // that maps to the token position of the source breakpoint.
   PcDescriptors::Iterator iter(desc, kSafepointKind);
-  RawPcDescriptors::PcDescriptorRec lowest_rec;
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    intptr_t desc_token_pos = rec.token_pos();
-    if ((desc_token_pos == bpt->token_pos_) && HasTokenPos(rec)) {
-      if (rec.pc() < lowest_pc) {
-        lowest_pc = rec.pc();
-        lowest_rec = rec;
+  while (iter.MoveNext()) {
+    if (iter.TokenPos() == bpt->token_pos_) {
+      if (iter.Pc() < lowest_pc) {
+        lowest_pc = iter.Pc();
+        lowest_kind = iter.Kind();
       }
     }
   }
   if (lowest_pc == kUwordMax) {
     return;
   }
-  CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_rec.pc());
+  CodeBreakpoint* code_bpt = GetCodeBreakpoint(lowest_pc);
   if (code_bpt == NULL) {
     // No code breakpoint for this code exists; create one.
-    code_bpt = new CodeBreakpoint(code, lowest_rec);
+    code_bpt = new CodeBreakpoint(code, bpt->token_pos_,
+                                  lowest_pc, lowest_kind);
     RegisterCodeBreakpoint(code_bpt);
   }
   code_bpt->set_src_bpt(bpt);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index e193e48..51b1ddb 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -80,7 +80,9 @@
 class CodeBreakpoint {
  public:
   CodeBreakpoint(const Code& code,
-                 const RawPcDescriptors::PcDescriptorRec& rec);
+                 intptr_t token_pos,
+                 uword pc,
+                 RawPcDescriptors::Kind kind);
   ~CodeBreakpoint();
 
   RawFunction* function() const;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 05ee325..bba0434 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -314,11 +314,6 @@
   DARTSCOPE(isolate);
   UNWRAP_AND_CHECK_PARAM(Function, function, function_in);
 
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
-
   const Class& cls = Class::Handle(function.origin());
   if (!cls.IsTopLevel()) {
     return Dart_NewInteger(cls.id());
@@ -343,11 +338,6 @@
   DARTSCOPE(isolate);
   UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
 
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
-  }
-
   Debugger* debugger = isolate->debugger();
   ASSERT(debugger != NULL);
   SourceBreakpoint* bpt =
@@ -400,9 +390,11 @@
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
 
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
+  // Ensure that the library is loaded.
+  if (!library.Loaded()) {
+    return Api::NewError(
+        "%s expects library argument 'library_in' to be loaded.",
+        CURRENT_FUNC);
   }
 
   // Resolve the breakpoint target function.
@@ -438,9 +430,11 @@
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
 
-  Dart_Handle state = Api::CheckIsolateState(isolate);
-  if (::Dart_IsError(state)) {
-    return state;
+  // Ensure that the library is loaded.
+  if (!library.Loaded()) {
+    return Api::NewError(
+        "%s expects library argument 'library_in' to be loaded.",
+        CURRENT_FUNC);
   }
 
   // Resolve the breakpoint target function.
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 5868293..c79e586 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -2016,7 +2016,7 @@
       "  get r => sqrt(x*x + y*y);       \n"
       "}                                 \n";
   LoadScript(kScriptChars);
-  Dart_FinalizeLoading();
+  Dart_FinalizeLoading(false);
 
   Dart_SetExceptionThrownHandler(&EvaluateInActivationOfEvaluateHandler);
   Dart_SetExceptionPauseInfo(kPauseOnAllExceptions);
@@ -2050,7 +2050,7 @@
       "}                               \n";
 
   LoadScript(kScriptChars);
-  Dart_FinalizeLoading();
+  Dart_FinalizeLoading(false);
   Dart_SetExceptionThrownHandler(&UnhandledExceptionHandler);
   breakpoint_hit_counter = 0;
 
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index d0efc36..a275a5c 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -97,13 +97,17 @@
 
 RawInstance* DeferredObject::object() {
   if (object_ == NULL) {
-    Materialize();
+    Create();
   }
   return object_->raw();
 }
 
 
-void DeferredObject::Materialize() {
+void DeferredObject::Create() {
+  if (object_ != NULL) {
+    return;
+  }
+
   Class& cls = Class::Handle();
   cls ^= GetClass();
 
@@ -114,7 +118,17 @@
                  field_count_);
   }
 
-  const Instance& obj = Instance::ZoneHandle(Instance::New(cls));
+  object_ = &Instance::ZoneHandle(Instance::New(cls));
+}
+
+
+void DeferredObject::Fill() {
+  Create();  // Ensure instance is created.
+
+  Class& cls = Class::Handle();
+  cls ^= GetClass();
+
+  const Instance& obj = *object_;
 
   Smi& offset = Smi::Handle();
   Field& field = Field::Handle();
@@ -143,8 +157,6 @@
       }
     }
   }
-
-  object_ = &obj;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/deferred_objects.h b/runtime/vm/deferred_objects.h
index 9619d16..cfb8d94 100644
--- a/runtime/vm/deferred_objects.h
+++ b/runtime/vm/deferred_objects.h
@@ -157,6 +157,9 @@
 
   RawInstance* object();
 
+  // Fill object with actual field values.
+  void Fill();
+
  private:
   enum {
     kClassIndex = 0,
@@ -169,10 +172,11 @@
     kFieldEntrySize,
   };
 
-  // Materializes the object. Returns amount of values that were consumed
-  // and should be removed from the expression stack at the very end of
-  // deoptimization.
-  void Materialize();
+  // Allocate the object but keep its fields null-initialized. Actual field
+  // values will be filled later by the Fill method. This separation between
+  // allocation and filling is needed because dematerialized objects form
+  // a graph which can contain cycles.
+  void Create();
 
   RawObject* GetClass() const {
     return args_[kClassIndex];
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index ba12b63..99aac37 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -38,8 +38,7 @@
       num_args_(0),
       deopt_reason_(ICData::kDeoptUnknown),
       isolate_(Isolate::Current()),
-      deferred_boxes_(NULL),
-      deferred_object_refs_(NULL),
+      deferred_slots_(NULL),
       deferred_objects_count_(0),
       deferred_objects_(NULL) {
   object_table_ = code.object_table();
@@ -323,18 +322,16 @@
 // Materializes all deferred objects.  Returns the total number of
 // artificial arguments used during deoptimization.
 intptr_t DeoptContext::MaterializeDeferredObjects() {
-  // First materialize all unboxed "primitive" values (doubles, mints, simd)
-  // then materialize objects. The order is important: objects might be
-  // referencing boxes allocated on the first step. At the same time
-  // objects can't be referencing other deferred objects because storing
-  // an object into a field is always conservatively treated as escaping by
-  // allocation sinking and load forwarding.
-  FillDeferredSlots(this, &deferred_boxes_);
-  FillDeferredSlots(this, &deferred_object_refs_);
+  // Populate slots with references to all unboxed "primitive" values (doubles,
+  // mints, simd) and deferred objects. Deferred objects are only allocated
+  // but not filled with data. This is done later because deferred objects
+  // can references each other.
+  FillDeferredSlots(this, &deferred_slots_);
 
   // Compute total number of artificial arguments used during deoptimization.
   intptr_t deopt_arg_count = 0;
   for (intptr_t i = 0; i < DeferredObjectsCount(); i++) {
+    GetDeferredObject(i)->Fill();
     deopt_arg_count += GetDeferredObject(i)->ArgumentCount();
   }
 
@@ -1633,6 +1630,14 @@
 
   instructions_.Add(
       new(isolate()) DeoptMaterializeObjectInstr(non_null_fields));
+
+  for (intptr_t i = 0; i < mat->InputCount(); i++) {
+    MaterializeObjectInstr* nested_mat = mat->InputAt(i)->definition()->
+        AsMaterializeObject();
+    if (nested_mat != NULL) {
+      AddMaterialization(nested_mat);
+    }
+  }
 }
 
 
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 9fcda82..93def97 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -114,48 +114,48 @@
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
   void DeferMaterializedObjectRef(intptr_t idx, intptr_t* slot) {
-    deferred_object_refs_ = new DeferredObjectRef(
+    deferred_slots_ = new DeferredObjectRef(
         idx,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_object_refs_);
+        deferred_slots_);
   }
 
   void DeferDoubleMaterialization(double value, RawDouble** slot) {
-    deferred_boxes_ = new DeferredDouble(
+    deferred_slots_ = new DeferredDouble(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_boxes_);
+        deferred_slots_);
   }
 
   void DeferMintMaterialization(int64_t value, RawMint** slot) {
-    deferred_boxes_ = new DeferredMint(
+    deferred_slots_ = new DeferredMint(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_boxes_);
+        deferred_slots_);
   }
 
   void DeferFloat32x4Materialization(simd128_value_t value,
                                      RawFloat32x4** slot) {
-    deferred_boxes_ = new DeferredFloat32x4(
+    deferred_slots_ = new DeferredFloat32x4(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_boxes_);
+        deferred_slots_);
   }
 
   void DeferFloat64x2Materialization(simd128_value_t value,
                                      RawFloat64x2** slot) {
-    deferred_boxes_ = new DeferredFloat64x2(
+    deferred_slots_ = new DeferredFloat64x2(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_boxes_);
+        deferred_slots_);
   }
 
   void DeferInt32x4Materialization(simd128_value_t value,
                                     RawInt32x4** slot) {
-    deferred_boxes_ = new DeferredInt32x4(
+    deferred_slots_ = new DeferredInt32x4(
         value,
         reinterpret_cast<RawInstance**>(slot),
-        deferred_boxes_);
+        deferred_slots_);
   }
 
   DeferredObject* GetDeferredObject(intptr_t idx) const {
@@ -203,8 +203,7 @@
   intptr_t caller_fp_;
   Isolate* isolate_;
 
-  DeferredSlot* deferred_boxes_;
-  DeferredSlot* deferred_object_refs_;
+  DeferredSlot* deferred_slots_;
 
   intptr_t deferred_objects_count_;
   DeferredObject** deferred_objects_;
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index d2d0d11..3c710e5 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -193,7 +193,9 @@
   for (intptr_t i = 0; i < instr->InputCount(); ++i) {
     Value* use = instr->InputAt(i);
     ASSERT(use->definition() != NULL);
-    ASSERT((use->definition() != instr) || use->definition()->IsPhi());
+    ASSERT((use->definition() != instr) ||
+           use->definition()->IsPhi() ||
+           use->definition()->IsMaterializeObject());
     ASSERT(use->instruction() == instr);
     ASSERT(use->use_index() == i);
     ASSERT(!FLAG_verify_compiler ||
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index e5f0865..0971696 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -122,6 +122,27 @@
 }
 
 
+static void DeepLiveness(MaterializeObjectInstr* mat, BitVector* live_in) {
+  if (mat->was_visited_for_liveness()) {
+    return;
+  }
+  mat->mark_visited_for_liveness();
+
+  for (intptr_t i = 0; i < mat->InputCount(); i++) {
+    if (!mat->InputAt(i)->BindsToConstant()) {
+      Definition* defn = mat->InputAt(i)->definition();
+      MaterializeObjectInstr* inner_mat = defn->AsMaterializeObject();
+      if (inner_mat != NULL) {
+        DeepLiveness(inner_mat, live_in);
+      } else {
+        intptr_t idx = defn->ssa_temp_index();
+        live_in->Add(idx);
+      }
+    }
+  }
+}
+
+
 void SSALivenessAnalysis::ComputeInitialSets() {
   const intptr_t block_count = postorder_.length();
   for (intptr_t i = 0; i < block_count; i++) {
@@ -173,12 +194,7 @@
           if (defn->IsMaterializeObject()) {
             // MaterializeObject instruction is not in the graph.
             // Treat its inputs as part of the environment.
-            for (intptr_t i = 0; i < defn->InputCount(); i++) {
-              if (!defn->InputAt(i)->BindsToConstant()) {
-                intptr_t idx = defn->InputAt(i)->definition()->ssa_temp_index();
-                live_in->Add(idx);
-              }
-            }
+            DeepLiveness(defn->AsMaterializeObject(), live_in);
           } else if (!defn->IsPushArgument() && !defn->IsConstant()) {
             live_in->Add(defn->ssa_temp_index());
             if (defn->HasPairRepresentation()) {
@@ -889,6 +905,7 @@
   // Initialize location for every input of the MaterializeObject instruction.
   Location* locations =
       Isolate::Current()->current_zone()->Alloc<Location>(mat->InputCount());
+  mat->set_locations(locations);
 
   for (intptr_t i = 0; i < mat->InputCount(); ++i) {
     Definition* def = mat->InputAt(i)->definition();
@@ -915,6 +932,10 @@
         range->AddUseInterval(block_start_pos, use_pos);
         range->AddUse(use_pos, location_pair->SlotAt(1));
       }
+    } else if (def->IsMaterializeObject()) {
+      locations[i] = Location::NoLocation();
+      ProcessMaterializationUses(
+          block, block_start_pos, use_pos, def->AsMaterializeObject());
     } else {
       locations[i] = Location::Any();
       LiveRange* range = GetLiveRange(def->ssa_temp_index());
@@ -922,8 +943,6 @@
       range->AddUse(use_pos, &locations[i]);
     }
   }
-
-  mat->set_locations(locations);
 }
 
 
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 4eab3f0..0de5492 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -731,23 +731,28 @@
       function.HasOptionalParameters() ? 0 : function.num_fixed_parameters();
   DeoptInfoBuilder builder(isolate(), incoming_arg_count);
 
-  const Array& array =
-      Array::Handle(Array::New(DeoptTable::SizeFor(deopt_infos_.length()),
-                               Heap::kOld));
-  Smi& offset = Smi::Handle();
-  DeoptInfo& info = DeoptInfo::Handle();
-  Smi& reason = Smi::Handle();
-  for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
-    offset = Smi::New(deopt_infos_[i]->pc_offset());
-    info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array);
-    reason = Smi::New(deopt_infos_[i]->reason());
-    DeoptTable::SetEntry(array, i, offset, info, reason);
+  intptr_t deopt_info_table_size = DeoptTable::SizeFor(deopt_infos_.length());
+  if (deopt_info_table_size == 0) {
+    code.set_deopt_info_array(Object::empty_array());
+    code.set_object_table(Object::empty_array());
+  } else {
+    const Array& array =
+        Array::Handle(Array::New(deopt_info_table_size, Heap::kOld));
+    Smi& offset = Smi::Handle();
+    DeoptInfo& info = DeoptInfo::Handle();
+    Smi& reason = Smi::Handle();
+    for (intptr_t i = 0; i < deopt_infos_.length(); i++) {
+      offset = Smi::New(deopt_infos_[i]->pc_offset());
+      info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array);
+      reason = Smi::New(deopt_infos_[i]->reason());
+      DeoptTable::SetEntry(array, i, offset, info, reason);
+    }
+    code.set_deopt_info_array(array);
+    const Array& object_array =
+        Array::Handle(Array::MakeArray(builder.object_table()));
+    ASSERT(code.object_table() == Array::null());
+    code.set_object_table(object_array);
   }
-  code.set_deopt_info_array(array);
-  const Array& object_array =
-      Array::Handle(Array::MakeArray(builder.object_table()));
-  ASSERT(code.object_table() == Array::null());
-  code.set_object_table(object_array);
 }
 
 
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 215eee7..b7b0cb6 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -165,6 +165,16 @@
   // Implementation is in architecture specific file.
   virtual void GenerateCode(FlowGraphCompiler* compiler, intptr_t stub_ix);
 
+  const char* Name() const {
+    const char* kFormat = "Deopt stub for id %d, reason: %s";
+    const intptr_t len = OS::SNPrint(NULL, 0, kFormat,
+        deopt_id(), DeoptReasonToCString(reason())) + 1;
+    char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+    OS::SNPrint(chars, len, kFormat,
+        deopt_id(), DeoptReasonToCString(reason()));
+    return chars;
+  }
+
  private:
   Label entry_label_;
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 118093e..929485f 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -163,7 +163,7 @@
   ASSERT(reason() != ICData::kDeoptAtCall);
   Assembler* assem = compiler->assembler();
 #define __ assem->
-  __ Comment("Deopt stub for id %" Pd "", deopt_id());
+  __ Comment("%s", Name());
   __ Bind(entry_label());
   if (FLAG_trap_on_deoptimization) {
     __ bkpt(0);
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 8162630..72c14bd 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -155,7 +155,7 @@
   ASSERT(reason() != ICData::kDeoptAtCall);
   Assembler* assem = compiler->assembler();
 #define __ assem->
-  __ Comment("Deopt stub for id %" Pd "", deopt_id());
+  __ Comment("%s", Name());
   __ Bind(entry_label());
   if (FLAG_trap_on_deoptimization) {
     __ brk(0);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index bf43fde..419f293 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -159,7 +159,7 @@
   ASSERT(reason() != ICData::kDeoptAtCall);
   Assembler* assem = compiler->assembler();
 #define __ assem->
-  __ Comment("Deopt stub for id %" Pd "", deopt_id());
+  __ Comment("%s", Name());
   __ Bind(entry_label());
   if (FLAG_trap_on_deoptimization) {
     __ int3();
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 319a8dd..537a0dd 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -159,7 +159,7 @@
   ASSERT(reason() != ICData::kDeoptAtCall);
   Assembler* assem = compiler->assembler();
 #define __ assem->
-  __ Comment("Deopt stub for id %" Pd "", deopt_id());
+  __ Comment("%s", Name());
   __ Bind(entry_label());
   if (FLAG_trap_on_deoptimization) {
     __ break_(0);
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 289414e..37e6aab 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -157,7 +157,7 @@
   ASSERT(reason() != ICData::kDeoptAtCall);
   Assembler* assem = compiler->assembler();
 #define __ assem->
-  __ Comment("Deopt stub for id %" Pd "", deopt_id());
+  __ Comment("%s", Name());
   __ Bind(entry_label());
   if (FLAG_trap_on_deoptimization) {
     __ int3();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index fa5db4d..10bbbad 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -2020,6 +2020,7 @@
   switch (op_kind) {
     case Token::kADD:
     case Token::kSUB:
+    case Token::kMUL:
       if (HasOnlyTwoOf(ic_data, kSmiCid)) {
         // Don't generate smi code if the IC data is marked because
         // of an overflow.
@@ -2037,6 +2038,7 @@
       } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
         operands_type = kFloat32x4Cid;
       } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+        ASSERT(op_kind != Token::kMUL);  // Int32x4 doesn't have a multiply op.
         operands_type = kInt32x4Cid;
       } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
         operands_type = kFloat64x2Cid;
@@ -2044,23 +2046,6 @@
         return false;
       }
       break;
-    case Token::kMUL:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        // Don't generate smi code if the IC data is marked because of an
-        // overflow.
-        // TODO(fschneider): Add unboxed mint multiplication.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) return false;
-        operands_type = kSmiCid;
-      } else if (ShouldSpecializeForDouble(ic_data)) {
-        operands_type = kDoubleCid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
-        operands_type = kFloat32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
-        operands_type = kFloat64x2Cid;
-      } else {
-        return false;
-      }
-      break;
     case Token::kDIV:
       if (ShouldSpecializeForDouble(ic_data) ||
           HasOnlyTwoOf(ic_data, kSmiCid)) {
@@ -4412,7 +4397,7 @@
     bool result = !getter.IsNull()
                && !setter.IsNull()
                && (setter.usage_counter() > 0)
-               && (FLAG_getter_setter_ratio * setter.usage_counter() >
+               && (FLAG_getter_setter_ratio * setter.usage_counter() >=
                    getter.usage_counter());
     if (!result) {
       if (FLAG_trace_optimization) {
@@ -5667,103 +5652,38 @@
 }
 
 
-// Alias represents a family of locations. It is used to capture aliasing
-// between stores and loads. Store can alias another load or store if and only
-// if they have the same alias.
-class Alias : public ValueObject {
- public:
-  Alias(const Alias& other) : ValueObject(), alias_(other.alias_) { }
-
-  // All indexed load/stores alias each other.
-  // TODO(vegorov): incorporate type of array into alias to disambiguate
-  // different typed data and normal arrays.
-  static Alias UnknownIndex(intptr_t id) {
-    return Alias(kUnknownIndexAlias, id);
-  }
-
-  static Alias ConstantIndex(intptr_t id) {
-    ASSERT(id != 0);
-    return Alias(kConstantIndex, id);
-  }
-
-  // Field load/stores alias each other only when they access the same field.
-  // AliasedSet assigns ids to a combination of instance and field during
-  // the optimization phase.
-  static Alias Field(intptr_t id) {
-    ASSERT(id != 0);
-    return Alias(kFieldAlias, id);
-  }
-
-  // VMField load/stores alias each other when field offset matches.
-  // TODO(vegorov) storing a context variable does not alias loading array
-  // length.
-  static Alias VMField(intptr_t id) {
-    ASSERT(id != 0);
-    return Alias(kVMFieldAlias, id);
-  }
-
-  // Current context load/stores alias each other.
-  static Alias CurrentContext() {
-    return Alias(kCurrentContextAlias, 0);
-  }
-
-  // Operation does not alias anything.
-  static Alias None() {
-    return Alias(kNoneAlias);
-  }
-
-  bool IsNone() const {
-    return alias_ == kNoneAlias;
-  }
-
-  // Convert this alias to a positive array index.
-  intptr_t ToIndex() const {
-    ASSERT(!IsNone());
-    return alias_;
-  }
-
- private:
-  enum {
-    // Number of bits required to encode Kind value.
-    // The payload occupies the rest of the bits, but leaves the MSB (sign bit)
-    // empty so that the resulting encoded value is always a positive integer.
-    kBitsForKind = 3,
-    kBitsForPayload = kWordSize * kBitsPerByte - kBitsForKind - 1,
-  };
-
-  enum Kind {
-    kNoneAlias = -1,
-    kCurrentContextAlias = 0,
-    kUnknownIndexAlias = 1,
-    kFieldAlias = 2,
-    kVMFieldAlias = 3,
-    kConstantIndex = 4,
-    kNumKinds = kConstantIndex + 1
-  };
-  COMPILE_ASSERT(kNumKinds < ((1 << kBitsForKind) - 1));
-
-  explicit Alias(intptr_t alias) : alias_(alias) { }
-
-  Alias(Kind kind, uword payload)
-      : alias_(KindField::encode(kind) | PayloadField::encode(payload)) { }
-
-  uword payload() const {
-    return PayloadField::decode(alias_);
-  }
-
-  Kind kind() const {
-    return IsNone() ? kNoneAlias : KindField::decode(alias_);
-  }
-
-  typedef BitField<Kind, 0, kBitsForKind> KindField;
-  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
-
-  const intptr_t alias_;
-};
-
-
 // Place describes an abstract location (e.g. field) that IR can load
 // from or store to.
+//
+// Places are also used to describe wild-card locations also known as aliases,
+// that essentially represent sets of places that alias each other. Places A
+// and B are said to alias each other if store into A can affect load from B.
+//
+// We distinguish the following aliases:
+//
+//   - for fields
+//     - *.f, *.@offs - field inside some object;
+//     - X.f, X.@offs - field inside an allocated object X;
+//   - for indexed accesses
+//     - *[*] - non-constant index inside some object;
+//     - *[C] - constant index inside some object;
+//     - X[*] - non-constant index inside an allocated object X;
+//     - X[C] - constant index inside an allocated object X.
+//
+// Separating allocations from other objects improves precision of the
+// load forwarding pass because of the following two properties:
+//
+//   - if X can be proven to have no aliases itself (i.e. there is no other SSA
+//     variable that points to X) then no place inside X can be aliased with any
+//     wildcard dependent place (*.f, *.@offs, *[*], *[C]);
+//   - given allocations X and Y no place inside X can be aliased with any place
+//     inside Y even if any of them or both escape.
+//
+// It important to realize that single place can belong to multiple aliases.
+// For example place X.f with aliased allocation X belongs both to X.f and *.f
+// aliases. Likewise X[C] with non-aliased allocation X belongs to X[C] and X[*]
+// aliases.
+//
 class Place : public ValueObject {
  public:
   enum Kind {
@@ -5778,9 +5698,12 @@
     // being accessed and offset to the field.
     kVMField,
 
-    // Indexed location.
+    // Indexed location with a non-constant index.
     kIndexed,
 
+    // Indexed location with a constant index.
+    kConstantIndexed,
+
     // Current context.
     kContext
   };
@@ -5852,21 +5775,19 @@
 
       case Instruction::kLoadIndexed: {
         LoadIndexedInstr* load_indexed = instr->AsLoadIndexed();
-        kind_ = kIndexed;
         representation_ = load_indexed->representation();
         instance_ = load_indexed->array()->definition()->OriginalDefinition();
-        index_ = load_indexed->index()->definition();
+        SetIndex(load_indexed->index()->definition());
         *is_load = true;
         break;
       }
 
       case Instruction::kStoreIndexed: {
         StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
-        kind_ = kIndexed;
         representation_ = store_indexed->
             RequiredInputRepresentation(StoreIndexedInstr::kValuePos);
         instance_ = store_indexed->array()->definition()->OriginalDefinition();
-        index_ = store_indexed->index()->definition();
+        SetIndex(store_indexed->index()->definition());
         *is_store = true;
         break;
       }
@@ -5891,20 +5812,75 @@
     }
   }
 
+  // Create object representing *[*] alias.
+  static Place* CreateAnyInstanceAnyIndexAlias(Isolate* isolate,
+                                               intptr_t id) {
+    return Wrap(isolate, Place(kIndexed, NULL, 0), id);
+  }
+
+  // Return least generic alias for this place. Given that aliases are
+  // essentially sets of places we define least generic alias as a smallest
+  // alias that contains this place.
+  //
+  // We obtain such alias by a simple transformation:
+  //
+  //    - for places that depend on an instance X.f, X.@offs, X[i], X[C]
+  //      we drop X if X is not an allocation because in this case X does not
+  //      posess an identity obtaining aliases *.f, *.@offs, *[i] and *[C]
+  //      respectively;
+  //    - for non-constant indexed places X[i] we drop information about the
+  //      index obtaining alias X[*].
+  //
+  Place ToAlias() const {
+    return Place(
+        kind_,
+        (DependsOnInstance() && IsAllocation(instance())) ? instance() : NULL,
+        (kind() == kIndexed) ? 0 : raw_selector_);
+  }
+
+  bool DependsOnInstance() const {
+    switch (kind()) {
+      case kField:
+      case kVMField:
+      case kIndexed:
+      case kConstantIndexed:
+        return true;
+
+      case kContext:
+      case kNone:
+        return false;
+    }
+
+    UNREACHABLE();
+    return false;
+  }
+
+  // Given instance dependent alias X.f, X.@offs, X[C], X[*] return
+  // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively.
+  Place CopyWithoutInstance() const {
+    ASSERT(DependsOnInstance());
+    return Place(kind_, NULL, raw_selector_);
+  }
+
+  // Given alias X[C] or *[C] return X[*] and *[*] respectively.
+  Place CopyWithoutIndex() const {
+    ASSERT(kind_ == kConstantIndexed);
+    return Place(kIndexed, instance_, 0);
+  }
+
   intptr_t id() const { return id_; }
-  void set_id(intptr_t id) { id_ = id; }
 
   Kind kind() const { return kind_; }
 
   Representation representation() const { return representation_; }
 
   Definition* instance() const {
-    ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed));
+    ASSERT(DependsOnInstance());
     return instance_;
   }
 
   void set_instance(Definition* def) {
-    ASSERT((kind_ == kField) || (kind_ == kVMField) || (kind_ == kIndexed));
+    ASSERT(DependsOnInstance());
     instance_ = def->OriginalDefinition();
   }
 
@@ -5923,6 +5899,20 @@
     return index_;
   }
 
+  intptr_t index_constant() const {
+    ASSERT(kind_ == kConstantIndexed);
+    return index_constant_;
+  }
+
+  static const char* DefinitionName(Definition* def) {
+    if (def == NULL) {
+      return "*";
+    } else {
+      return Isolate::Current()->current_zone()->PrintToString(
+            "v%" Pd, def->ssa_temp_index());
+    }
+  }
+
   const char* ToCString() const {
     switch (kind_) {
       case kNone:
@@ -5930,25 +5920,32 @@
 
       case kField: {
         const char* field_name = String::Handle(field().name()).ToCString();
-        if (instance() == NULL) {
-          return field_name;
+        if (field().is_static()) {
+          return Isolate::Current()->current_zone()->PrintToString(
+              "<%s>", field_name);
+        } else {
+          return Isolate::Current()->current_zone()->PrintToString(
+              "<%s.%s>", DefinitionName(instance()), field_name);
         }
-        return Isolate::Current()->current_zone()->PrintToString(
-            "<v%" Pd ".%s>", instance()->ssa_temp_index(), field_name);
       }
 
-      case kVMField: {
+      case kVMField:
         return Isolate::Current()->current_zone()->PrintToString(
-            "<v%" Pd "@%" Pd ">",
-            instance()->ssa_temp_index(), offset_in_bytes());
-      }
+            "<%s.@%" Pd ">",
+            DefinitionName(instance()),
+            offset_in_bytes());
 
-      case kIndexed: {
+      case kIndexed:
         return Isolate::Current()->current_zone()->PrintToString(
-            "<v%" Pd "[v%" Pd "]>",
-            instance()->ssa_temp_index(),
-            index()->ssa_temp_index());
-      }
+            "<%s[%s]>",
+            DefinitionName(instance()),
+            DefinitionName(index()));
+
+      case kConstantIndexed:
+        return Isolate::Current()->current_zone()->PrintToString(
+            "<%s[%" Pd "]>",
+            DefinitionName(instance()),
+            index_constant());
 
       case kContext:
         return "<context>";
@@ -5966,18 +5963,35 @@
         representation_ * 15 + FieldHashcode();
   }
 
-  bool Equals(Place* other) const {
+  bool Equals(const Place* other) const {
     return (kind_ == other->kind_) &&
         (representation_ == other->representation_) &&
         (instance_ == other->instance_) &&
         SameField(other);
   }
 
-  // Create a zone allocated copy of this place.
-  static Place* Wrap(Isolate* isolate, const Place& place);
+  // Create a zone allocated copy of this place and assign given id to it.
+  static Place* Wrap(Isolate* isolate, const Place& place, intptr_t id);
+
+  static bool IsAllocation(Definition* defn) {
+    // TODO(vegorov): add CreateContext to this list.
+    return (defn != NULL) &&
+        (defn->IsAllocateObject() ||
+         defn->IsCreateArray() ||
+         (defn->IsStaticCall() &&
+          defn->AsStaticCall()->IsRecognizedFactory()));
+  }
 
  private:
-  bool SameField(Place* other) const {
+  Place(Kind kind, Definition* instance, intptr_t selector)
+      : kind_(kind),
+        representation_(kNoRepresentation),
+        instance_(instance),
+        raw_selector_(selector),
+        id_(0) {
+  }
+
+  bool SameField(const Place* other) const {
     return (kind_ == kField) ? (field().raw() == other->field().raw())
                              : (offset_in_bytes_ == other->offset_in_bytes_);
   }
@@ -5987,6 +6001,17 @@
                              : offset_in_bytes_;
   }
 
+  void SetIndex(Definition* index) {
+    ConstantInstr* index_constant = index->AsConstant();
+    if ((index_constant != NULL) && index_constant->value().IsSmi()) {
+      kind_ = kConstantIndexed;
+      index_constant_ = Smi::Cast(index_constant->value()).Value();
+    } else {
+      kind_ = kIndexed;
+      index_ = index;
+    }
+  }
+
   Kind kind_;
   Representation representation_;
   Definition* instance_;
@@ -5994,6 +6019,7 @@
     intptr_t raw_selector_;
     const Field* field_;
     intptr_t offset_in_bytes_;
+    intptr_t index_constant_;
     Definition* index_;
   };
 
@@ -6012,8 +6038,10 @@
 };
 
 
-Place* Place::Wrap(Isolate* isolate, const Place& place) {
-  return (new(isolate) ZonePlace(place))->place();
+Place* Place::Wrap(Isolate* isolate, const Place& place, intptr_t id) {
+  Place* wrapped = (new(isolate) ZonePlace(place))->place();
+  wrapped->id_ = id;
+  return wrapped;
 }
 
 
@@ -6073,141 +6101,38 @@
       : isolate_(isolate),
         places_(*places),
         phi_moves_(phi_moves),
-        sets_(),
-        aliased_by_effects_(new(isolate) BitVector(places->length())),
-        max_field_id_(0),
-        field_ids_(),
-        max_index_id_(0),
-        index_ids_(),
-        max_unknown_index_id_(0),
-        unknown_index_ids_(),
-        max_vm_field_id_(0),
-        vm_field_ids_() { }
-
-  Alias ComputeAlias(Place* place) {
-    switch (place->kind()) {
-      case Place::kIndexed:
-        if (place->index()->IsConstant()) {
-          const Object& index = place->index()->AsConstant()->value();
-          if (index.IsSmi()) {
-            return Alias::ConstantIndex(
-                GetInstanceIndexId(place->instance(),
-                                   Smi::Cast(index).Value()));
-          }
-        }
-        return Alias::UnknownIndex(GetUnknownIndexId(place->instance()));
-      case Place::kField:
-        return Alias::Field(
-            GetInstanceFieldId(place->instance(), place->field()));
-      case Place::kVMField:
-        return Alias::VMField(
-            GetInstanceVMFieldId(place->instance(), place->offset_in_bytes()));
-      case Place::kContext:
-        return Alias::CurrentContext();
-      case Place::kNone:
-        UNREACHABLE();
+        aliases_(5),
+        aliases_map_(),
+        representatives_(),
+        killed_(),
+        aliased_by_effects_(new(isolate) BitVector(places->length())) {
+    InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(isolate_,
+        kAnyInstanceAnyIndexAlias));
+    for (intptr_t i = 0; i < places_.length(); i++) {
+      AddRepresentative(places_[i]);
     }
-
-    UNREACHABLE();
-    return Alias::None();
+    ComputeKillSets();
   }
 
-  Alias ComputeAliasForStore(Instruction* instr) {
-    StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
-    if (store_indexed != NULL) {
-      Definition* instance = store_indexed->array()->definition();
-      if (store_indexed->index()->definition()->IsConstant()) {
-        const Object& index =
-            store_indexed->index()->definition()->AsConstant()->value();
-        if (index.IsSmi()) {
-          return Alias::ConstantIndex(
-              GetInstanceIndexId(instance, Smi::Cast(index).Value()));
-        }
-      }
-      return Alias::UnknownIndex(GetUnknownIndexId(instance));
-    }
-
-    StoreInstanceFieldInstr* store_instance_field =
-        instr->AsStoreInstanceField();
-    if (store_instance_field != NULL) {
-      Definition* instance = store_instance_field->instance()->definition();
-      if (!store_instance_field->field().IsNull()) {
-        return Alias::Field(
-            GetInstanceFieldId(instance, store_instance_field->field()));
-      }
-      return Alias::VMField(
-          GetInstanceVMFieldId(instance,
-                               store_instance_field->offset_in_bytes()));
-    }
-
-    if (instr->IsStoreContext()) {
-      return Alias::CurrentContext();
-    }
-
-    StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
-    if (store_static_field != NULL) {
-      return Alias::Field(GetStaticFieldId(store_static_field->field()));
-    }
-
-    return Alias::None();
+  intptr_t LookupAliasId(const Place& alias) {
+    const Place* result = aliases_map_.Lookup(&alias);
+    return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias);
   }
 
-  BitVector* Get(const Alias alias) {
-    const intptr_t idx = alias.ToIndex();
-    BitVector* ret = (idx < sets_.length()) ? sets_[idx] : NULL;
-    return ret;
+  bool IsStore(Instruction* instr, BitVector** killed) {
+    bool is_load = false, is_store = false;
+    Place place(instr, &is_load, &is_store);
+    if (is_store && (place.kind() != Place::kNone)) {
+      const intptr_t alias_id = LookupAliasId(place.ToAlias());
+      if (alias_id != kNoAlias) {
+        *killed = GetKilledSet(alias_id);
+      }
+    }
+    return is_store;
   }
 
-  void AddRepresentative(Place* place) {
-    if (!place->IsFinalField()) {
-      AddIdForAlias(ComputeAlias(place), place->id());
-      if (!IsIndependentFromEffects(place)) {
-        aliased_by_effects_->Add(place->id());
-      }
-    }
-  }
-
-  void EnsureAliasingForUnknownIndices() {
-    // Ids start at 1 because the hash-map uses 0 for element not found.
-    for (intptr_t unknown_index_id = 1;
-         unknown_index_id <= max_unknown_index_id_;
-         unknown_index_id++) {
-      BitVector* unknown_index = Get(Alias::UnknownIndex(unknown_index_id));
-      if (unknown_index == NULL) {
-        return;
-      }
-
-      // Constant indexes alias all non-constant indexes.
-      // Non-constant indexes alias all constant indexes.
-      // First update alias set for const-indices, then
-      // update set for all indices. Ids start at 1.
-      for (intptr_t id = 1; id <= max_index_id_; id++) {
-        BitVector* const_indexes = Get(Alias::ConstantIndex(id));
-        if (const_indexes != NULL) {
-          const_indexes->AddAll(unknown_index);
-        }
-      }
-
-      for (intptr_t id = 1; id <= max_index_id_; id++) {
-        BitVector* const_indexes = Get(Alias::ConstantIndex(id));
-        if (const_indexes != NULL) {
-          unknown_index->AddAll(const_indexes);
-        }
-      }
-    }
-  }
-
-  void AddIdForAlias(const Alias alias, intptr_t place_id) {
-    const intptr_t idx = alias.ToIndex();
-    while (sets_.length() <= idx) {
-      sets_.Add(NULL);
-    }
-
-    if (sets_[idx] == NULL) {
-      sets_[idx] = new(isolate_) BitVector(max_place_id());
-    }
-
-    sets_[idx]->Add(place_id);
+  BitVector* GetKilledSet(intptr_t alias) {
+    return (alias < killed_.length()) ? killed_[alias] : NULL;
   }
 
   intptr_t max_place_id() const { return places().length(); }
@@ -6234,158 +6159,209 @@
 
   const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
 
-  // Returns true if the result of an allocation instruction can be aliased by
-  // some other SSA variable and false otherwise. Currently simply checks if
-  // this value is stored in a field, escapes to another function or
-  // participates in a phi.
-  static bool CanBeAliased(Definition* alloc) {
-    ASSERT(alloc->IsAllocateObject() ||
-           alloc->IsCreateArray() ||
-           (alloc->IsStaticCall() &&
-            alloc->AsStaticCall()->IsRecognizedFactory()));
-    if (alloc->Identity() == kIdentityUnknown) {
-      bool escapes = false;
-      for (Value* use = alloc->input_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        Instruction* instr = use->instruction();
-        if (instr->IsPushArgument() ||
-            (instr->IsStoreInstanceField()
-             && (use->use_index() != StoreInstanceFieldInstr::kInstancePos)) ||
-            (instr->IsStoreIndexed()
-             && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
-            instr->IsStoreStaticField() ||
-            instr->IsPhi() ||
-            instr->IsAssertAssignable() ||
-            instr->IsRedefinition()) {
-          escapes = true;
-          break;
-        }
-      }
+  void RollbackAliasedIdentites() {
+    for (intptr_t i = 0; i < identity_rollback_.length(); ++i) {
+      identity_rollback_[i]->SetIdentity(AliasIdentity::Unknown());
+    }
+  }
 
-      alloc->SetIdentity(escapes ? kIdentityAliased : kIdentityNotAliased);
+  // Returns false if the result of an allocation instruction can't be aliased
+  // by another SSA variable and true otherwise.
+  bool CanBeAliased(Definition* alloc) {
+    if (!Place::IsAllocation(alloc)) {
+      return true;
     }
 
-    return alloc->Identity() != kIdentityNotAliased;
+    if (alloc->Identity().IsUnknown()) {
+      ComputeAliasing(alloc);
+    }
+
+    return !alloc->Identity().IsNotAliased();
   }
 
  private:
-  // Get id assigned to the given field. Assign a new id if the field is seen
-  // for the first time.
-  intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
-    intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
-    if (id == 0) {
-      id = ++max_field_id_;
-      field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
-    }
-    return id;
-  }
-
-  intptr_t GetIndexId(intptr_t instance_id, intptr_t index) {
-    intptr_t id = index_ids_.Lookup(
-        ConstantIndexIdPair::Key(instance_id, index));
-    if (id == 0) {
-      // Zero is used to indicate element not found. The first id is one.
-      id = ++max_index_id_;
-      index_ids_.Insert(ConstantIndexIdPair(
-          ConstantIndexIdPair::Key(instance_id, index), id));
-    }
-    return id;
-  }
-
   enum {
-    kAnyInstance = -1
+    kNoAlias = 0,
+
+    // Artificial alias that is used to collect all representatives of the
+    // *[C], X[C] aliases for arbitrary C.
+    kAnyConstantIndexedAlias = 1,
+
+    // Artificial alias that is used to collect all representatives of
+    // *[C] alias for arbitrary C.
+    kUnknownInstanceConstantIndexedAlias = 2,
+
+    // Artificial alias that is used to collect all representatives of
+    // X[*] alias for all X.
+    kAnyAllocationIndexedAlias = 3,
+
+    // *[*] alias.
+    kAnyInstanceAnyIndexAlias = 4
   };
 
-  // Get or create an identifier for an instance field belonging to the
-  // given instance.
-  // The space of identifiers assigned to instance fields is split into
-  // parts based on the instance that contains the field.
-  // If compiler can prove that instance has a single SSA name in the compiled
-  // function then we use that SSA name to distinguish fields of this object
-  // from the same fields in other objects.
-  // If multiple SSA names can point to the same object then we use
-  // kAnyInstance instead of a concrete SSA name.
-  intptr_t GetInstanceFieldId(Definition* defn, const Field& field) {
-    ASSERT(field.is_static() == (defn == NULL));
+  // Compute least generic alias for the place and assign alias id to it.
+  void AddRepresentative(Place* place) {
+    if (!place->IsFinalField()) {
+      const Place* alias = CanonicalizeAlias(place->ToAlias());
+      EnsureSet(&representatives_, alias->id())->Add(place->id());
 
-    intptr_t instance_id = kAnyInstance;
+      // Update cumulative representative sets that are used during
+      // killed sets computation.
+      if (alias->kind() == Place::kConstantIndexed) {
+        if (CanBeAliased(alias->instance())) {
+          EnsureSet(&representatives_, kAnyConstantIndexedAlias)->
+              Add(place->id());
+        }
 
-    if (defn != NULL) {
-      AllocateObjectInstr* alloc = defn->AsAllocateObject();
-      if ((alloc != NULL) && !CanBeAliased(alloc)) {
-        instance_id = alloc->ssa_temp_index();
-        ASSERT(instance_id != kAnyInstance);
+        if (alias->instance() == NULL) {
+          EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias)->
+              Add(place->id());
+        }
+      } else if ((alias->kind() == Place::kIndexed) &&
+                 CanBeAliased(place->instance())) {
+        EnsureSet(&representatives_, kAnyAllocationIndexedAlias)->
+            Add(place->id());
+      }
+
+      if (!IsIndependentFromEffects(place)) {
+        aliased_by_effects_->Add(place->id());
       }
     }
-
-    return GetFieldId(instance_id, field);
   }
 
-  intptr_t GetInstanceVMFieldId(Definition* defn, intptr_t offset) {
-    intptr_t instance_id = kAnyInstance;
-
-    ASSERT(defn != NULL);
-    if ((defn->IsAllocateObject() ||
-         defn->IsCreateArray() ||
-         (defn->IsStaticCall() &&
-          defn->AsStaticCall()->IsRecognizedFactory())) &&
-        !CanBeAliased(defn)) {
-      instance_id = defn->ssa_temp_index();
-      ASSERT(instance_id != kAnyInstance);
+  void ComputeKillSets() {
+    for (intptr_t i = 0; i < aliases_.length(); ++i) {
+      const Place* alias = aliases_[i];
+      // Add all representatives to the kill set.
+      AddAllRepresentatives(alias->id(), alias->id());
+      ComputeKillSet(alias);
     }
 
-    intptr_t id = vm_field_ids_.Lookup(VMFieldIdPair::Key(instance_id, offset));
-    if (id == 0) {
-      id = ++max_vm_field_id_;
-      vm_field_ids_.Insert(
-          VMFieldIdPair(VMFieldIdPair::Key(instance_id, offset), id));
+    if (FLAG_trace_load_optimization) {
+      OS::Print("Aliases KILL sets:\n");
+      for (intptr_t i = 0; i < aliases_.length(); ++i) {
+        const Place* alias = aliases_[i];
+        BitVector* kill = GetKilledSet(alias->id());
+
+        OS::Print("%s: ", alias->ToCString());
+        if (kill != NULL) {
+          PrintSet(kill);
+        }
+        OS::Print("\n");
+      }
     }
-    return id;
   }
 
-  intptr_t GetInstanceIndexId(Definition* defn, intptr_t index) {
-    intptr_t instance_id = kAnyInstance;
-
-    ASSERT(defn != NULL);
-    if ((defn->IsCreateArray() ||
-         (defn->IsStaticCall() &&
-          defn->AsStaticCall()->IsRecognizedFactory())) &&
-        !CanBeAliased(defn)) {
-      instance_id = defn->ssa_temp_index();
-      ASSERT(instance_id != kAnyInstance);
-    }
-
-    return GetIndexId(instance_id, index);
+  void InsertAlias(const Place* alias) {
+    aliases_map_.Insert(alias);
+    aliases_.Add(alias);
   }
 
-  intptr_t GetUnknownIndexId(Definition* defn) {
-    intptr_t instance_id = kAnyInstance;
-
-    ASSERT(defn != NULL);
-    if ((defn->IsCreateArray() ||
-         (defn->IsStaticCall() &&
-          defn->AsStaticCall()->IsRecognizedFactory())) &&
-        !CanBeAliased(defn)) {
-      instance_id = defn->ssa_temp_index();
-      ASSERT(instance_id != kAnyInstance);
+  const Place* CanonicalizeAlias(const Place& alias) {
+    const Place* canonical = aliases_map_.Lookup(&alias);
+    if (canonical == NULL) {
+      canonical = Place::Wrap(isolate_,
+                              alias,
+                              kAnyInstanceAnyIndexAlias + aliases_.length());
+      InsertAlias(canonical);
     }
-
-    intptr_t id = unknown_index_ids_.Lookup(
-        UnknownIndexIdPair::Key(instance_id));
-    if (id == 0) {
-      // Zero is used to indicate element not found. The first id is one.
-      id = ++max_unknown_index_id_;
-      unknown_index_ids_.Insert(
-          UnknownIndexIdPair(UnknownIndexIdPair::Key(instance_id), id));
-    }
-    return id;
+    return canonical;
   }
 
-  // Get or create an identifier for a static field.
-  intptr_t GetStaticFieldId(const Field& field) {
-    ASSERT(field.is_static());
-    return GetFieldId(kAnyInstance, field);
+  BitVector* GetRepresentativesSet(intptr_t alias) {
+    return (alias < representatives_.length()) ? representatives_[alias] : NULL;
+  }
+
+  BitVector* EnsureSet(GrowableArray<BitVector*>* sets,
+                       intptr_t alias) {
+    while (sets->length() <= alias) {
+      sets->Add(NULL);
+    }
+
+    BitVector* set = (*sets)[alias];
+    if (set == NULL) {
+      (*sets)[alias] = set = new(isolate_) BitVector(max_place_id());
+    }
+    return set;
+  }
+
+  void AddAllRepresentatives(const Place* to, intptr_t from) {
+    AddAllRepresentatives(to->id(), from);
+  }
+
+  void AddAllRepresentatives(intptr_t to, intptr_t from) {
+    BitVector* from_set = GetRepresentativesSet(from);
+    if (from_set != NULL) {
+      EnsureSet(&killed_, to)->AddAll(from_set);
+    }
+  }
+
+  void CrossAlias(const Place* to, const Place& from) {
+    const intptr_t from_id = LookupAliasId(from);
+    if (from_id == kNoAlias) {
+      return;
+    }
+    CrossAlias(to, from_id);
+  }
+
+  void CrossAlias(const Place* to, intptr_t from) {
+    AddAllRepresentatives(to->id(), from);
+    AddAllRepresentatives(from, to->id());
+  }
+
+  // When computing kill sets we let less generic alias insert its
+  // representatives into more generic alias'es kill set. For example
+  // when visiting alias X[*] instead of searching for all aliases X[C]
+  // and inserting their representatives into kill set for X[*] we update
+  // kill set for X[*] each time we visit new X[C] for some C.
+  // There is an exception however: if both aliases are parametric like *[C]
+  // and X[*] which cross alias when X is an aliased allocation then we use
+  // artificial aliases that contain all possible representatives for the given
+  // alias for any value of the parameter to compute resulting kill set.
+  void ComputeKillSet(const Place* alias) {
+    switch (alias->kind()) {
+      case Place::kIndexed:  // Either *[*] or X[*] alias.
+        if (alias->instance() == NULL) {
+          // *[*] aliases with X[*], X[C], *[C].
+          AddAllRepresentatives(alias, kAnyConstantIndexedAlias);
+          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+        } else if (CanBeAliased(alias->instance())) {
+          // X[*] aliases with X[C].
+          // If X can be aliased then X[*] also aliases with *[C], *[*].
+          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+          AddAllRepresentatives(alias, kUnknownInstanceConstantIndexedAlias);
+        }
+        break;
+
+      case Place::kConstantIndexed:  // Either X[C] or *[C] alias.
+        if (alias->instance() == NULL) {
+          // *[C] aliases with X[C], X[*], *[*].
+          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+        } else {
+          // X[C] aliases with X[*].
+          // If X can be aliased then X[C] also aliases with *[C], *[*].
+          CrossAlias(alias, alias->CopyWithoutIndex());
+          if (CanBeAliased(alias->instance())) {
+            CrossAlias(alias, alias->CopyWithoutInstance());
+            CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+          }
+        }
+        break;
+
+      case Place::kField:
+      case Place::kVMField:
+        if (CanBeAliased(alias->instance())) {
+          // X.f or X.@offs alias with *.f and *.@offs respectively.
+          CrossAlias(alias, alias->CopyWithoutInstance());
+        }
+
+      case Place::kContext:
+        return;
+
+      case Place::kNone:
+        UNREACHABLE();
+    }
   }
 
   // Returns true if the given load is unaffected by external side-effects.
@@ -6408,154 +6384,127 @@
       return true;
     }
 
-    if (((place->kind() == Place::kField) ||
+    return ((place->kind() == Place::kField) ||
          (place->kind() == Place::kVMField)) &&
-        (place->instance() != NULL)) {
-      AllocateObjectInstr* alloc = place->instance()->AsAllocateObject();
-      return (alloc != NULL) && !CanBeAliased(alloc);
+        !CanBeAliased(place->instance());
+  }
+
+  // Returns true if there are direct loads from the given place.
+  bool HasLoadsFromPlace(Definition* defn, const Place* place) {
+    ASSERT((place->kind() == Place::kField) ||
+           (place->kind() == Place::kVMField));
+    ASSERT(place->instance() == defn);
+
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      bool is_load = false, is_store;
+      Place load_place(use->instruction(), &is_load, &is_store);
+
+      if (is_load && load_place.Equals(place)) {
+        return true;
+      }
     }
 
     return false;
   }
 
-  class FieldIdPair {
-   public:
-    struct Key {
-      Key(intptr_t instance_id, const Field* field)
-          : instance_id_(instance_id), field_(field) { }
+  // Check if any use of the definition can create an alias.
+  // Can add more objects into aliasing_worklist_.
+  bool AnyUseCreatesAlias(Definition* defn) {
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      Instruction* instr = use->instruction();
+      if (instr->IsPushArgument() ||
+          (instr->IsStoreIndexed()
+           && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
+          instr->IsStoreStaticField() ||
+          instr->IsPhi() ||
+          instr->IsAssertAssignable() ||
+          instr->IsRedefinition()) {
+        return true;
+      } else if ((instr->IsStoreInstanceField()
+           && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) {
+        ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos);
+        // If we store this value into an object that is not aliased itself
+        // and we never load again then the store does not create an alias.
+        StoreInstanceFieldInstr* store = instr->AsStoreInstanceField();
+        Definition* instance = store->instance()->definition();
+        if (instance->IsAllocateObject() && !instance->Identity().IsAliased()) {
+          bool is_load, is_store;
+          Place store_place(instr, &is_load, &is_store);
 
-      intptr_t instance_id_;
-      const Field* field_;
-    };
+          if (!HasLoadsFromPlace(instance, &store_place)) {
+            // No loads found that match this store. If it is yet unknown if
+            // the object is not aliased then optimistically assume this but
+            // add it to the worklist to check its uses transitively.
+            if (instance->Identity().IsUnknown()) {
+              instance->SetIdentity(AliasIdentity::NotAliased());
+              aliasing_worklist_.Add(instance);
+            }
+            continue;
+          }
+        }
 
-    typedef intptr_t Value;
-    typedef FieldIdPair Pair;
+        return true;
+      }
+    }
+    return false;
+  }
 
-    FieldIdPair(Key key, Value value) : key_(key), value_(value) { }
-
-    static Key KeyOf(Pair kv) {
-      return kv.key_;
+  // Mark any value stored into the given object as potentially aliased.
+  void MarkStoredValuesEscaping(Definition* defn) {
+    if (!defn->IsAllocateObject()) {
+      return;
     }
 
-    static Value ValueOf(Pair kv) {
-      return kv.value_;
+    // Find all stores into this object.
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) &&
+          use->instruction()->IsStoreInstanceField()) {
+        StoreInstanceFieldInstr* store =
+            use->instruction()->AsStoreInstanceField();
+        Definition* value = store->value()->definition();
+        if (value->Identity().IsNotAliased()) {
+          value->SetIdentity(AliasIdentity::Aliased());
+          identity_rollback_.Add(value);
+
+          // Add to worklist to propagate the mark transitively.
+          aliasing_worklist_.Add(value);
+        }
+      }
     }
+  }
 
-    static intptr_t Hashcode(Key key) {
-      return String::Handle(key.field_->name()).Hash();
+  // Determine if the given definition can't be aliased.
+  void ComputeAliasing(Definition* alloc) {
+    ASSERT(alloc->Identity().IsUnknown());
+    ASSERT(aliasing_worklist_.is_empty());
+
+    alloc->SetIdentity(AliasIdentity::NotAliased());
+    aliasing_worklist_.Add(alloc);
+
+    while (!aliasing_worklist_.is_empty()) {
+      Definition* defn = aliasing_worklist_.RemoveLast();
+
+      // If the definition in the worklist was optimistically marked as
+      // not-aliased check that optimistic assumption still holds: check if
+      // any of its uses can create an alias.
+      if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) {
+        defn->SetIdentity(AliasIdentity::Aliased());
+        identity_rollback_.Add(defn);
+      }
+
+      // If the allocation site is marked as aliased conservatively mark
+      // any values stored into the object aliased too.
+      if (defn->Identity().IsAliased()) {
+        MarkStoredValuesEscaping(defn);
+      }
     }
-
-    static inline bool IsKeyEqual(Pair kv, Key key) {
-      return (KeyOf(kv).field_->raw() == key.field_->raw()) &&
-          (KeyOf(kv).instance_id_ == key.instance_id_);
-    }
-
-   private:
-    Key key_;
-    Value value_;
-  };
-
-  class ConstantIndexIdPair {
-   public:
-    struct Key {
-      Key(intptr_t instance_id, intptr_t index)
-          : instance_id_(instance_id), index_(index) { }
-
-      intptr_t instance_id_;
-      intptr_t index_;
-    };
-    typedef intptr_t Value;
-    typedef ConstantIndexIdPair Pair;
-
-    ConstantIndexIdPair(Key key, Value value) : key_(key), value_(value) { }
-
-    static Key KeyOf(ConstantIndexIdPair kv) {
-      return kv.key_;
-    }
-
-    static Value ValueOf(ConstantIndexIdPair kv) {
-      return kv.value_;
-    }
-
-    static intptr_t Hashcode(Key key) {
-      return (key.instance_id_ + 1) * 1024 + key.index_;
-    }
-
-    static inline bool IsKeyEqual(ConstantIndexIdPair kv, Key key) {
-      return (KeyOf(kv).index_ == key.index_)
-          && (KeyOf(kv).instance_id_ == key.instance_id_);
-    }
-
-   private:
-    Key key_;
-    Value value_;
-  };
-
-  class UnknownIndexIdPair {
-   public:
-    typedef intptr_t Key;
-    typedef intptr_t Value;
-    typedef UnknownIndexIdPair Pair;
-
-    UnknownIndexIdPair(Key key, Value value) : key_(key), value_(value) { }
-
-    static Key KeyOf(UnknownIndexIdPair kv) {
-      return kv.key_;
-    }
-
-    static Value ValueOf(UnknownIndexIdPair kv) {
-      return kv.value_;
-    }
-
-    static intptr_t Hashcode(Key key) {
-      return key + 1;
-    }
-
-    static inline bool IsKeyEqual(UnknownIndexIdPair kv, Key key) {
-      return KeyOf(kv) == key;
-    }
-
-   private:
-    Key key_;
-    Value value_;
-  };
-
-  class VMFieldIdPair {
-   public:
-    struct Key {
-      Key(intptr_t instance_id, intptr_t offset)
-          : instance_id_(instance_id), offset_(offset) { }
-
-      intptr_t instance_id_;
-      intptr_t offset_;
-    };
-
-    typedef intptr_t Value;
-    typedef VMFieldIdPair Pair;
-
-    VMFieldIdPair(Key key, Value value) : key_(key), value_(value) { }
-
-    static Key KeyOf(Pair kv) {
-      return kv.key_;
-    }
-
-    static Value ValueOf(Pair kv) {
-      return kv.value_;
-    }
-
-    static intptr_t Hashcode(Key key) {
-      return (key.instance_id_ + 1) * 1024 + key.offset_;
-    }
-
-    static inline bool IsKeyEqual(Pair kv, Key key) {
-      return (KeyOf(kv).offset_ == key.offset_) &&
-          (KeyOf(kv).instance_id_ == key.instance_id_);
-    }
-
-   private:
-    Key key_;
-    Value value_;
-  };
+  }
 
   Isolate* isolate_;
 
@@ -6563,24 +6512,33 @@
 
   const PhiPlaceMoves* phi_moves_;
 
-  // Maps alias index to a set of ssa indexes corresponding to loads with the
-  // given alias.
-  GrowableArray<BitVector*> sets_;
+  // A list of all seen aliases and a map that allows looking up canonical
+  // alias object.
+  GrowableArray<const Place*> aliases_;
+  DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_;
 
+  // Maps alias id to set of ids of places representing the alias.
+  // Place represents an alias if this alias is least generic alias for
+  // the place.
+  // (see ToAlias for the definition of least generic alias).
+  GrowableArray<BitVector*> representatives_;
+
+  // Maps alias id to set of ids of places aliased.
+  GrowableArray<BitVector*> killed_;
+
+  // Set of ids of places that can be affected by side-effects other than
+  // explicit stores (i.e. through calls).
   BitVector* aliased_by_effects_;
 
-  // Table mapping static field to their id used during optimization pass.
-  intptr_t max_field_id_;
-  DirectChainedHashMap<FieldIdPair> field_ids_;
+  // Worklist used during alias analysis.
+  GrowableArray<Definition*> aliasing_worklist_;
 
-  intptr_t max_index_id_;
-  DirectChainedHashMap<ConstantIndexIdPair> index_ids_;
-
-  intptr_t max_unknown_index_id_;
-  DirectChainedHashMap<UnknownIndexIdPair> unknown_index_ids_;
-
-  intptr_t max_vm_field_id_;
-  DirectChainedHashMap<VMFieldIdPair> vm_field_ids_;
+  // List of definitions that had their identity set to Aliased. At the end
+  // of load optimization their identity will be rolled back to Unknown to
+  // avoid treating them as Aliased at later stages without checking first
+  // as optimizations can potentially eliminate instructions leading to
+  // aliasing.
+  GrowableArray<Definition*> identity_rollback_;
 };
 
 
@@ -6643,8 +6601,7 @@
 
         Place* result = map->Lookup(&input_place);
         if (result == NULL) {
-          input_place.set_id(places->length());
-          result = Place::Wrap(isolate, input_place);
+          result = Place::Wrap(isolate, input_place, places->length());
           map->Insert(result);
           places->Add(result);
           if (FLAG_trace_optimization) {
@@ -6698,8 +6655,7 @@
 
       Place* result = map->Lookup(&place);
       if (result == NULL) {
-        place.set_id(places->length());
-        result = Place::Wrap(isolate, place);
+        result = Place::Wrap(isolate, place, places->length());
         map->Insert(result);
         places->Add(result);
 
@@ -6724,15 +6680,7 @@
   PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places);
 
   // Build aliasing sets mapping aliases to loads.
-  AliasedSet* aliased_set = new(isolate) AliasedSet(isolate, places, phi_moves);
-  for (intptr_t i = 0; i < places->length(); i++) {
-    Place* place = (*places)[i];
-    aliased_set->AddRepresentative(place);
-  }
-
-  aliased_set->EnsureAliasingForUnknownIndices();
-
-  return aliased_set;
+  return new(isolate) AliasedSet(isolate, places, phi_moves);
 }
 
 
@@ -6766,6 +6714,10 @@
     }
   }
 
+  ~LoadOptimizer() {
+    aliased_set_->RollbackAliasedIdentites();
+  }
+
   Isolate* isolate() const { return graph_->isolate(); }
 
   static bool OptimizeGraph(FlowGraph* graph) {
@@ -6831,11 +6783,8 @@
            instr_it.Advance()) {
         Instruction* instr = instr_it.Current();
 
-        const Alias alias = aliased_set_->ComputeAliasForStore(instr);
-        if (!alias.IsNone()) {
-          // Interfering stores kill only loads from the same offset.
-          BitVector* killed = aliased_set_->Get(alias);
-
+        BitVector* killed = NULL;
+        if (aliased_set_->IsStore(instr, &killed)) {
           if (killed != NULL) {
             kill->AddAll(killed);
             // There is no need to clear out_values when clearing GEN set
@@ -6899,7 +6848,7 @@
         // TODO(vegorov): record null-values at least for not final fields of
         // escaping object.
         AllocateObjectInstr* alloc = instr->AsAllocateObject();
-        if ((alloc != NULL) && !AliasedSet::CanBeAliased(alloc)) {
+        if ((alloc != NULL) && !aliased_set_->CanBeAliased(alloc)) {
           for (Value* use = alloc->input_use_list();
                use != NULL;
                use = use->next_use()) {
@@ -7691,8 +7640,8 @@
         // Handle loads.
         Definition* defn = instr->AsDefinition();
         if ((defn != NULL) && IsLoadEliminationCandidate(defn)) {
-          const Alias alias = aliased_set_->ComputeAlias(&place);
-          live_in->AddAll(aliased_set_->Get(alias));
+          const intptr_t alias = aliased_set_->LookupAliasId(place.ToAlias());
+          live_in->AddAll(aliased_set_->GetKilledSet(alias));
           continue;
         }
       }
@@ -9883,16 +9832,63 @@
 }
 
 
+enum SafeUseCheck { kOptimisticCheck, kStrictCheck };
+
+// Check if the use is safe for allocation sinking. Allocation sinking
+// candidates can only be used at store instructions:
+//
+//     - any store into the allocation candidate itself is unconditionally safe
+//       as it just changes the rematerialization state of this candidate;
+//     - store into another object is only safe if another object is allocation
+//       candidate.
+//
+// We use a simple fix-point algorithm to discover the set of valid candidates
+// (see CollectCandidates method), that's why this IsSafeUse can operate in two
+// modes:
+//
+//     - optimistic, when every allocation is assumed to be an allocation
+//       sinking candidate;
+//     - strict, when only marked allocations are assumed to be allocation
+//       sinking candidates.
+//
+// Fix-point algorithm in CollectCandiates first collects a set of allocations
+// optimistically and then checks each collected candidate strictly and unmarks
+// invalid candidates transitively until only strictly valid ones remain.
+static bool IsSafeUse(Value* use, SafeUseCheck check_type) {
+  if (use->instruction()->IsMaterializeObject()) {
+    return true;
+  }
+
+  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+  if (store != NULL) {
+    if (use == store->value()) {
+      Definition* instance = store->instance()->definition();
+      return instance->IsAllocateObject() &&
+          ((check_type == kOptimisticCheck) ||
+           instance->Identity().IsAllocationSinkingCandidate());
+    }
+    return true;
+  }
+
+  return false;
+}
+
+
 // Right now we are attempting to sink allocation only into
 // deoptimization exit. So candidate should only be used in StoreInstanceField
 // instructions that write into fields of the allocated object.
 // We do not support materialization of the object that has type arguments.
-static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc) {
+static bool IsAllocationSinkingCandidate(AllocateObjectInstr* alloc,
+                                         SafeUseCheck check_type) {
   for (Value* use = alloc->input_use_list();
        use != NULL;
        use = use->next_use()) {
-    if (!(use->instruction()->IsStoreInstanceField() &&
-          (use->use_index() == 0))) {
+    if (!IsSafeUse(use, check_type)) {
+      if (FLAG_trace_optimization) {
+        OS::Print("use of %s at %s is unsafe for allocation sinking\n",
+                  alloc->ToCString(),
+                  use->instruction()->ToCString());
+      }
       return false;
     }
   }
@@ -9901,10 +9897,22 @@
 }
 
 
+// If the given use is a store into an object then return an object we are
+// storing into.
+static Definition* StoreInto(Value* use) {
+  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+  if (store != NULL) {
+    return store->instance()->definition();
+  }
+
+  return NULL;
+}
+
+
 // Remove the given allocation from the graph. It is not observable.
 // If deoptimization occurs the object will be materialized.
-static void EliminateAllocation(AllocateObjectInstr* alloc) {
-  ASSERT(IsAllocationSinkingCandidate(alloc));
+void AllocationSinking::EliminateAllocation(AllocateObjectInstr* alloc) {
+  ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck));
 
   if (FLAG_trace_optimization) {
     OS::Print("removing allocation from the graph: v%" Pd "\n",
@@ -9921,7 +9929,13 @@
 
   // There should be no environment uses. The pass replaced them with
   // MaterializeObject instructions.
-  ASSERT(alloc->env_use_list() == NULL);
+#ifdef DEBUG
+  for (Value* use = alloc->env_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    ASSERT(use->instruction()->IsMaterializeObject());
+  }
+#endif
   ASSERT(alloc->input_use_list() == NULL);
   alloc->RemoveFromGraph();
   if (alloc->ArgumentCount() > 0) {
@@ -9933,31 +9947,205 @@
 }
 
 
-void AllocationSinking::Optimize() {
-  GrowableArray<AllocateObjectInstr*> candidates(5);
-
-  // Collect sinking candidates.
-  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder();
-  for (BlockIterator block_it(postorder);
+// Find allocation instructions that can be potentially eliminated and
+// rematerialized at deoptimization exits if needed. See IsSafeUse
+// for the description of algorithm used below.
+void AllocationSinking::CollectCandidates() {
+  // Optimistically collect all potential candidates.
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
        !block_it.Done();
        block_it.Advance()) {
     BlockEntryInstr* block = block_it.Current();
     for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
       AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
-      if ((alloc != NULL) && IsAllocationSinkingCandidate(alloc)) {
-        if (FLAG_trace_optimization) {
-          OS::Print("discovered allocation sinking candidate: v%" Pd "\n",
-                    alloc->ssa_temp_index());
-        }
-
-        // All sinking candidate are known to be not aliased.
-        alloc->SetIdentity(kIdentityNotAliased);
-
-        candidates.Add(alloc);
+      if ((alloc != NULL) &&
+          IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
+        alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
+        candidates_.Add(alloc);
       }
     }
   }
 
+  // Transitively unmark all candidates that are not strictly valid.
+  bool changed;
+  do {
+    changed = false;
+    for (intptr_t i = 0; i < candidates_.length(); i++) {
+      AllocateObjectInstr* alloc = candidates_[i];
+      if (alloc->Identity().IsAllocationSinkingCandidate()) {
+        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+          alloc->SetIdentity(AliasIdentity::Unknown());
+          changed = true;
+        }
+      }
+    }
+  } while (changed);
+
+  // Shrink the list of candidates removing all unmarked ones.
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    AllocateObjectInstr* alloc = candidates_[i];
+    if (alloc->Identity().IsAllocationSinkingCandidate()) {
+      if (FLAG_trace_optimization) {
+        OS::Print("discovered allocation sinking candidate: v%" Pd "\n",
+                  alloc->ssa_temp_index());
+      }
+
+      if (j != i) {
+        candidates_[j] = alloc;
+      }
+      j++;
+    }
+  }
+  candidates_.TruncateTo(j);
+}
+
+
+// If materialization references an allocation sinking candidate then replace
+// this reference with a materialization which should have been computed for
+// this side-exit. CollectAllExits should have collected this exit.
+void AllocationSinking::NormalizeMaterializations() {
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    Definition* alloc = candidates_[i];
+
+    Value* next_use;
+    for (Value* use = alloc->input_use_list();
+         use != NULL;
+         use = next_use) {
+      next_use = use->next_use();
+      if (use->instruction()->IsMaterializeObject()) {
+        use->BindTo(MaterializationFor(alloc, use->instruction()));
+      }
+    }
+  }
+}
+
+
+// We transitively insert materializations at each deoptimization exit that
+// might see the given allocation (see ExitsCollector). Some of this
+// materializations are not actually used and some fail to compute because
+// they are inserted in the block that is not dominated by the allocation.
+// Remove them unused materializations from the graph.
+void AllocationSinking::RemoveUnusedMaterializations() {
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    MaterializeObjectInstr* mat = materializations_[i];
+    if ((mat->input_use_list() == NULL) && (mat->env_use_list() == NULL)) {
+      // Check if this materialization failed to compute and remove any
+      // unforwarded loads. There were no loads from any allocation sinking
+      // candidate in the beggining so it is safe to assume that any encountered
+      // load was inserted by CreateMaterializationAt.
+      for (intptr_t i = 0; i < mat->InputCount(); i++) {
+        LoadFieldInstr* load = mat->InputAt(i)->definition()->AsLoadField();
+        if ((load != NULL) &&
+            (load->instance()->definition() == mat->allocation())) {
+          load->ReplaceUsesWith(flow_graph_->constant_null());
+          load->RemoveFromGraph();
+        }
+      }
+      mat->RemoveFromGraph();
+    } else {
+      if (j != i) {
+        materializations_[j] = mat;
+      }
+      j++;
+    }
+  }
+  materializations_.TruncateTo(j);
+}
+
+
+// Some candidates might stop being eligible for allocation sinking after
+// the load forwarding because they flow into phis that load forwarding
+// inserts. Discover such allocations and remove them from the list
+// of allocation sinking candidates undoing all changes that we did
+// in preparation for sinking these allocations.
+void AllocationSinking::DiscoverFailedCandidates() {
+  // Transitively unmark all candidates that are not strictly valid.
+  bool changed;
+  do {
+    changed = false;
+    for (intptr_t i = 0; i < candidates_.length(); i++) {
+      AllocateObjectInstr* alloc = candidates_[i];
+      if (alloc->Identity().IsAllocationSinkingCandidate()) {
+        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+          alloc->SetIdentity(AliasIdentity::Unknown());
+          changed = true;
+        }
+      }
+    }
+  } while (changed);
+
+  // Remove all failed candidates from the candidates list.
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    AllocateObjectInstr* alloc = candidates_[i];
+    if (!alloc->Identity().IsAllocationSinkingCandidate()) {
+      if (FLAG_trace_optimization) {
+        OS::Print("allocation v%" Pd " can't be eliminated\n",
+                  alloc->ssa_temp_index());
+      }
+
+#ifdef DEBUG
+      for (Value* use = alloc->env_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        ASSERT(use->instruction()->IsMaterializeObject());
+      }
+#endif
+
+      // All materializations will be removed from the graph. Remove inserted
+      // loads first and detach materializations from allocation's environment
+      // use list: we will reconstruct it when we start removing
+      // materializations.
+      alloc->set_env_use_list(NULL);
+      for (Value* use = alloc->input_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        if (use->instruction()->IsLoadField()) {
+          LoadFieldInstr* load = use->instruction()->AsLoadField();
+          load->ReplaceUsesWith(flow_graph_->constant_null());
+          load->RemoveFromGraph();
+        } else {
+          ASSERT(use->instruction()->IsMaterializeObject() ||
+                 use->instruction()->IsPhi() ||
+                 use->instruction()->IsStoreInstanceField());
+        }
+      }
+    } else {
+      if (j != i) {
+        candidates_[j] = alloc;
+      }
+      j++;
+    }
+  }
+
+  if (j != candidates_.length()) {  // Something was removed from candidates.
+    intptr_t k = 0;
+    for (intptr_t i = 0; i < materializations_.length(); i++) {
+      MaterializeObjectInstr* mat = materializations_[i];
+      if (!mat->allocation()->Identity().IsAllocationSinkingCandidate()) {
+        // Restore environment uses of the allocation that were replaced
+        // by this materialization and drop materialization.
+        mat->ReplaceUsesWith(mat->allocation());
+        mat->RemoveFromGraph();
+      } else {
+        if (k != i) {
+          materializations_[k] = mat;
+        }
+        k++;
+      }
+    }
+    materializations_.TruncateTo(k);
+  }
+
+  candidates_.TruncateTo(j);
+}
+
+
+void AllocationSinking::Optimize() {
+  CollectCandidates();
+
   // Insert MaterializeObject instructions that will describe the state of the
   // object at all deoptimization points. Each inserted materialization looks
   // like this (where v_0 is allocation that we are going to eliminate):
@@ -9965,8 +10153,8 @@
   //           ...
   //   v_N     <- LoadField(v_0, field_N)
   //   v_{N+1} <- MaterializeObject(field_1 = v_1, ..., field_N = v_{N})
-  for (intptr_t i = 0; i < candidates.length(); i++) {
-    InsertMaterializations(candidates[i]);
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    InsertMaterializations(candidates_[i]);
   }
 
   // Run load forwarding to eliminate LoadField instructions inserted above.
@@ -9977,15 +10165,19 @@
   //      external effects from calls.
   LoadOptimizer::OptimizeGraph(flow_graph_);
 
-  if (FLAG_trace_optimization) {
-    FlowGraphPrinter::PrintGraph("Sinking", flow_graph_);
-  }
+  NormalizeMaterializations();
+
+  RemoveUnusedMaterializations();
+
+  // If any candidates are no longer eligible for allocation sinking abort
+  // the optimization for them and undo any changes we did in preparation.
+  DiscoverFailedCandidates();
 
   // At this point we have computed the state of object at each deoptimization
   // point and we can eliminate it. Loads inserted above were forwarded so there
   // are no uses of the allocation just as in the begging of the pass.
-  for (intptr_t i = 0; i < candidates.length(); i++) {
-    EliminateAllocation(candidates[i]);
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    EliminateAllocation(candidates_[i]);
   }
 
   // Process materializations and unbox their arguments: materializations
@@ -10010,35 +10202,62 @@
 // as part of the environment not as a real instruction.
 void AllocationSinking::DetachMaterializations() {
   for (intptr_t i = 0; i < materializations_.length(); i++) {
-    ASSERT(materializations_[i]->input_use_list() == NULL);
     materializations_[i]->previous()->LinkTo(materializations_[i]->next());
   }
 }
 
 
 // Add a field/offset to the list of fields if it is not yet present there.
-static void AddSlot(ZoneGrowableArray<const Object*>* slots,
+static bool AddSlot(ZoneGrowableArray<const Object*>* slots,
                     const Object& slot) {
   for (intptr_t i = 0; i < slots->length(); i++) {
     if ((*slots)[i]->raw() == slot.raw()) {
-      return;
+      return false;
     }
   }
   slots->Add(&slot);
+  return true;
 }
 
 
-// Add given instruction to the list of the instructions if it is not yet
-// present there.
-static void AddInstruction(GrowableArray<Instruction*>* exits,
-                           Instruction* exit) {
-  ASSERT(!exit->IsGraphEntry());
-  for (intptr_t i = 0; i < exits->length(); i++) {
-    if ((*exits)[i] == exit) {
-      return;
+// Find deoptimization exit for the given materialization assuming that all
+// materializations are emitted right before the instruction which is a
+// deoptimization exit.
+static Instruction* ExitForMaterialization(MaterializeObjectInstr* mat) {
+  while (mat->next()->IsMaterializeObject()) {
+    mat = mat->next()->AsMaterializeObject();
+  }
+  return mat->next();
+}
+
+
+// Given the deoptimization exit find first materialization that was inserted
+// before it.
+static Instruction* FirstMaterializationAt(Instruction* exit) {
+  while (exit->previous()->IsMaterializeObject()) {
+    exit = exit->previous();
+  }
+  return exit;
+}
+
+
+// Given the allocation and deoptimization exit try to find MaterializeObject
+// instruction corresponding to this allocation at this exit.
+MaterializeObjectInstr* AllocationSinking::MaterializationFor(
+    Definition* alloc, Instruction* exit) {
+  if (exit->IsMaterializeObject()) {
+    exit = ExitForMaterialization(exit->AsMaterializeObject());
+  }
+
+  for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject();
+       mat != NULL;
+       mat = mat->previous()->AsMaterializeObject()) {
+    if (mat->allocation() == alloc) {
+      return mat;
     }
   }
-  exits->Add(exit);
+
+  return NULL;
 }
 
 
@@ -10052,6 +10271,11 @@
   ZoneGrowableArray<Value*>* values =
       new(I) ZoneGrowableArray<Value*>(slots.length());
 
+  // All loads should be inserted before the first materialization so that
+  // IR follows the following pattern: loads, materializations, deoptimizing
+  // instruction.
+  Instruction* load_point = FirstMaterializationAt(exit);
+
   // Insert load instruction for every field.
   for (intptr_t i = 0; i < slots.length(); i++) {
     LoadFieldInstr* load = slots[i]->IsField()
@@ -10066,12 +10290,12 @@
             AbstractType::ZoneHandle(I),
             alloc->token_pos());
     flow_graph_->InsertBefore(
-        exit, load, NULL, FlowGraph::kValue);
+        load_point, load, NULL, FlowGraph::kValue);
     values->Add(new(I) Value(load));
   }
 
   MaterializeObjectInstr* mat =
-      new(I) MaterializeObjectInstr(cls, slots, values);
+      new(I) MaterializeObjectInstr(alloc, cls, slots, values);
   flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue);
 
   // Replace all mentions of this allocation with a newly inserted
@@ -10089,11 +10313,81 @@
     }
   }
 
+  // Mark MaterializeObject as an environment use of this allocation.
+  // This will allow us to discover it when we are looking for deoptimization
+  // exits for another allocation that potentially flows into this one.
+  Value* val = new(I) Value(alloc);
+  val->set_instruction(mat);
+  alloc->AddEnvUse(val);
+
   // Record inserted materialization.
   materializations_.Add(mat);
 }
 
 
+// Add given instruction to the list of the instructions if it is not yet
+// present there.
+template<typename T>
+void AddInstruction(GrowableArray<T*>* list, T* value) {
+  ASSERT(!value->IsGraphEntry());
+  for (intptr_t i = 0; i < list->length(); i++) {
+    if ((*list)[i] == value) {
+      return;
+    }
+  }
+  list->Add(value);
+}
+
+
+// Transitively collect all deoptimization exits that might need this allocation
+// rematerialized. It is not enough to collect only environment uses of this
+// allocation because it can flow into other objects that will be
+// dematerialized and that are referenced by deopt environments that
+// don't contain this allocation explicitly.
+void AllocationSinking::ExitsCollector::Collect(Definition* alloc) {
+  for (Value* use = alloc->env_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    if (use->instruction()->IsMaterializeObject()) {
+      AddInstruction(&exits_, ExitForMaterialization(
+          use->instruction()->AsMaterializeObject()));
+    } else {
+      AddInstruction(&exits_, use->instruction());
+    }
+  }
+
+  // Check if this allocation is stored into any other allocation sinking
+  // candidate and put it on worklist so that we conservatively collect all
+  // exits for that candidate as well because they potentially might see
+  // this object.
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    Definition* obj = StoreInto(use);
+    if ((obj != NULL) && (obj != alloc)) {
+      AddInstruction(&worklist_, obj);
+    }
+  }
+}
+
+
+void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) {
+  exits_.TruncateTo(0);
+  worklist_.TruncateTo(0);
+
+  worklist_.Add(alloc);
+
+  // Note: worklist potentially will grow while we are iterating over it.
+  // We are not removing allocations from the worklist not to waste space on
+  // the side maintaining BitVector of already processed allocations: worklist
+  // is expected to be very small thus linear search in it is just as effecient
+  // as a bitvector.
+  for (intptr_t i = 0; i < worklist_.length(); i++) {
+    Collect(worklist_[i]);
+  }
+}
+
+
 void AllocationSinking::InsertMaterializations(AllocateObjectInstr* alloc) {
   // Collect all fields that are written for this instance.
   ZoneGrowableArray<const Object*>* slots =
@@ -10103,10 +10397,12 @@
        use != NULL;
        use = use->next_use()) {
     StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
-    if (!store->field().IsNull()) {
-      AddSlot(slots, store->field());
-    } else {
-      AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes())));
+    if ((store != NULL) && (store->instance()->definition() == alloc)) {
+      if (!store->field().IsNull()) {
+        AddSlot(slots, store->field());
+      } else {
+        AddSlot(slots, Smi::ZoneHandle(I, Smi::New(store->offset_in_bytes())));
+      }
     }
   }
 
@@ -10117,16 +10413,12 @@
   }
 
   // Collect all instructions that mention this object in the environment.
-  GrowableArray<Instruction*> exits(10);
-  for (Value* use = alloc->env_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    AddInstruction(&exits, use->instruction());
-  }
+  exits_collector_.CollectTransitively(alloc);
 
   // Insert materializations at environment uses.
-  for (intptr_t i = 0; i < exits.length(); i++) {
-    CreateMaterializationAt(exits[i], alloc, alloc->cls(), *slots);
+  for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
+    CreateMaterializationAt(
+        exits_collector_.exits()[i], alloc, alloc->cls(), *slots);
   }
 }
 
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 3aecb91..e9a7482 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -429,13 +429,54 @@
  public:
   explicit AllocationSinking(FlowGraph* flow_graph)
       : flow_graph_(flow_graph),
+        candidates_(5),
         materializations_(5) { }
 
+  const GrowableArray<AllocateObjectInstr*>& candidates() const {
+    return candidates_;
+  }
+
+  // Find the materialization insterted for the given allocation
+  // at the given exit.
+  MaterializeObjectInstr* MaterializationFor(Definition* alloc,
+                                             Instruction* exit);
+
   void Optimize();
 
   void DetachMaterializations();
 
  private:
+  // Helper class to collect deoptimization exits that might need to
+  // rematerialize an object: that is either instructions that reference
+  // this object explicitly in their deoptimization environment or
+  // reference some other allocation sinking candidate that points to
+  // this object.
+  class ExitsCollector : public ValueObject {
+   public:
+    ExitsCollector() : exits_(10), worklist_(3) { }
+
+    const GrowableArray<Instruction*>& exits() const { return exits_; }
+
+    void CollectTransitively(Definition* alloc);
+
+   private:
+    // Collect immediate uses of this object in the environments.
+    // If this object is stored into other allocation sinking candidates
+    // put them onto worklist so that CollectTransitively will process them.
+    void Collect(Definition* alloc);
+
+    GrowableArray<Instruction*> exits_;
+    GrowableArray<Definition*> worklist_;
+  };
+
+  void CollectCandidates();
+
+  void NormalizeMaterializations();
+
+  void RemoveUnusedMaterializations();
+
+  void DiscoverFailedCandidates();
+
   void InsertMaterializations(AllocateObjectInstr* alloc);
 
   void CreateMaterializationAt(
@@ -444,11 +485,16 @@
       const Class& cls,
       const ZoneGrowableArray<const Object*>& fields);
 
+  void EliminateAllocation(AllocateObjectInstr* alloc);
+
   Isolate* isolate() const { return flow_graph_->isolate(); }
 
   FlowGraph* flow_graph_;
 
+  GrowableArray<AllocateObjectInstr*> candidates_;
   GrowableArray<MaterializeObjectInstr*> materializations_;
+
+  ExitsCollector exits_collector_;
 };
 
 
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 01f345c..b8664dc 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -507,6 +507,10 @@
     f->Print(", ");
     PushArgumentAt(i)->value()->PrintTo(f);
   }
+
+  if (Identity().IsNotAliased()) {
+    f->Print(" <not-aliased>");
+  }
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index e23603f..6bb00cf 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2281,6 +2281,11 @@
 // FlowGraphCompiler::SlowPathEnvironmentFor().
 void MaterializeObjectInstr::RemapRegisters(intptr_t* fpu_reg_slots,
                                             intptr_t* cpu_reg_slots) {
+  if (registers_remapped_) {
+    return;
+  }
+  registers_remapped_ = true;
+
   for (intptr_t i = 0; i < InputCount(); i++) {
     Location loc = LocationAt(i);
     if (loc.IsRegister()) {
@@ -2305,11 +2310,10 @@
       }
     } else if (loc.IsPairLocation()) {
       UNREACHABLE();
-    } else if (loc.IsInvalid()) {
-      // We currently only perform one iteration of allocation
-      // sinking, so we do not expect to find materialized objects
-      // here.
-      ASSERT(!InputAt(i)->definition()->IsMaterializeObject());
+    } else if (loc.IsInvalid() &&
+               InputAt(i)->definition()->IsMaterializeObject()) {
+      InputAt(i)->definition()->AsMaterializeObject()->RemapRegisters(
+          fpu_reg_slots, cpu_reg_slots);
     }
   }
 }
@@ -2732,7 +2736,7 @@
       ((limit > 0) && (Utils::IsInt(limit, value)))) {
     // Result stays in 64 bit range.
     int64_t result = value << shift_count;
-    return Smi::IsValid(result) ? RangeBoundary(result) : overflow;
+    return RangeBoundary(result);
   }
 
   return overflow;
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 1606207..1e59e79 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -1763,10 +1763,54 @@
 // If the result of the allocation is not stored into any field, passed
 // as an argument or used in a phi then it can't alias with any other
 // SSA value.
-enum AliasIdentity {
-  kIdentityUnknown,
-  kIdentityAliased,
-  kIdentityNotAliased
+class AliasIdentity : public ValueObject {
+ public:
+  // It is unknown if value has aliases.
+  static AliasIdentity Unknown() { return AliasIdentity(kUnknown); }
+
+  // It is known that value can have aliases.
+  static AliasIdentity Aliased() { return AliasIdentity(kAliased); }
+
+  // It is known that value has no aliases.
+  static AliasIdentity NotAliased() { return AliasIdentity(kNotAliased); }
+
+  // It is known that value has no aliases and it was selected by
+  // allocation sinking pass as a candidate.
+  static AliasIdentity AllocationSinkingCandidate() {
+    return AliasIdentity(kAllocationSinkingCandidate);
+  }
+
+  bool IsUnknown() const { return value_ == kUnknown; }
+  bool IsAliased() const { return value_ == kAliased; }
+  bool IsNotAliased() const { return (value_ & kNotAliased) != 0; }
+  bool IsAllocationSinkingCandidate() const {
+    return value_ == kAllocationSinkingCandidate;
+  }
+
+  AliasIdentity(const AliasIdentity& other)
+      : ValueObject(), value_(other.value_) {
+  }
+
+  AliasIdentity& operator=(const AliasIdentity& other) {
+    value_ = other.value_;
+    return *this;
+  }
+
+ private:
+  explicit AliasIdentity(intptr_t value) : value_(value) { }
+
+  enum {
+    kUnknown = 0,
+    kNotAliased = 1,
+    kAliased = 2,
+    kAllocationSinkingCandidate = 3,
+  };
+
+  COMPILE_ASSERT((kUnknown & kNotAliased) == 0);
+  COMPILE_ASSERT((kAliased & kNotAliased) == 0);
+  COMPILE_ASSERT((kAllocationSinkingCandidate & kNotAliased) != 0);
+
+  intptr_t value_;
 };
 
 
@@ -1927,9 +1971,7 @@
   }
 
   virtual AliasIdentity Identity() const {
-    // Only implemented for allocation instructions.
-    UNREACHABLE();
-    return kIdentityUnknown;
+    return AliasIdentity::Unknown();
   }
 
   virtual void SetIdentity(AliasIdentity identity) {
@@ -3629,7 +3671,7 @@
         result_cid_(kDynamicCid),
         is_known_list_constructor_(false),
         is_native_list_factory_(false),
-        identity_(kIdentityUnknown) {
+        identity_(AliasIdentity::Unknown()) {
     ASSERT(function.IsZoneHandle());
     ASSERT(argument_names.IsZoneHandle() ||  argument_names.InVMHeap());
   }
@@ -4474,7 +4516,7 @@
       : token_pos_(token_pos),
         cls_(cls),
         arguments_(arguments),
-        identity_(kIdentityUnknown),
+        identity_(AliasIdentity::Unknown()),
         closure_function_(Function::ZoneHandle()) {
     // Either no arguments or one type-argument and one instantiator.
     ASSERT(arguments->is_empty() || (arguments->length() == 1));
@@ -4523,10 +4565,17 @@
 // It does not produce any real code only deoptimization information.
 class MaterializeObjectInstr : public Definition {
  public:
-  MaterializeObjectInstr(const Class& cls,
+  MaterializeObjectInstr(AllocateObjectInstr* allocation,
+                         const Class& cls,
                          const ZoneGrowableArray<const Object*>& slots,
                          ZoneGrowableArray<Value*>* values)
-      : cls_(cls), slots_(slots), values_(values), locations_(NULL) {
+      : allocation_(allocation),
+        cls_(cls),
+        slots_(slots),
+        values_(values),
+        locations_(NULL),
+        visited_for_liveness_(false),
+        registers_remapped_(false) {
     ASSERT(slots_.length() == values_->length());
     for (intptr_t i = 0; i < InputCount(); i++) {
       InputAt(i)->set_instruction(this);
@@ -4534,6 +4583,7 @@
     }
   }
 
+  AllocateObjectInstr* allocation() const { return allocation_; }
   const Class& cls() const { return cls_; }
   intptr_t FieldOffsetAt(intptr_t i) const {
     return slots_[i]->IsField()
@@ -4576,16 +4626,25 @@
   void RemapRegisters(intptr_t* fpu_reg_slots,
                       intptr_t* cpu_reg_slots);
 
+  bool was_visited_for_liveness() const { return visited_for_liveness_; }
+  void mark_visited_for_liveness() {
+    visited_for_liveness_ = true;
+  }
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*values_)[i] = value;
   }
 
+  AllocateObjectInstr* allocation_;
   const Class& cls_;
   const ZoneGrowableArray<const Object*>& slots_;
   ZoneGrowableArray<Value*>* values_;
   Location* locations_;
 
+  bool visited_for_liveness_;
+  bool registers_remapped_;
+
   DISALLOW_COPY_AND_ASSIGN(MaterializeObjectInstr);
 };
 
@@ -4595,7 +4654,7 @@
   CreateArrayInstr(intptr_t token_pos,
                    Value* element_type,
                    Value* num_elements)
-      : token_pos_(token_pos), identity_(kIdentityUnknown)  {
+      : token_pos_(token_pos), identity_(AliasIdentity::Unknown())  {
     SetInputAt(kElementTypePos, element_type);
     SetInputAt(kLengthPos, num_elements);
   }
@@ -4698,8 +4757,6 @@
 };
 
 
-
-
 class LoadFieldInstr : public TemplateDefinition<1> {
  public:
   LoadFieldInstr(Value* instance,
@@ -7086,7 +7143,8 @@
   virtual bool CanDeoptimize() const {
     return FLAG_throw_on_javascript_int_overflow
         || (can_overflow() && ((op_kind() == Token::kADD) ||
-                               (op_kind() == Token::kSUB)));
+                               (op_kind() == Token::kSUB)))
+        || (op_kind() == Token::kMUL);  // Deopt if inputs are not int32.
   }
 
   virtual Representation representation() const {
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 643f692..81cbe5f 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1140,19 +1140,6 @@
 }
 
 
-static bool CanHoldImmediateOffset(bool is_load, intptr_t cid, int64_t offset) {
-  int32_t offset_mask = 0;
-  if (is_load) {
-    return Address::CanHoldLoadOffset(Address::OperandSizeFor(cid),
-                                      offset,
-                                      &offset_mask);
-  } else {
-    return Address::CanHoldStoreOffset(Address::OperandSizeFor(cid),
-                                       offset,
-                                       &offset_mask);
-  }
-}
-
 static bool CanBeImmediateIndex(Value* value,
                                 intptr_t cid,
                                 bool is_external,
@@ -1177,12 +1164,12 @@
   if (!Utils::IsAbsoluteUint(12, offset)) {
     return false;
   }
-  if (CanHoldImmediateOffset(is_load, cid, offset)) {
+  if (Address::CanHoldImmediateOffset(is_load, cid, offset)) {
     *needs_base = false;
     return true;
   }
 
-  if (CanHoldImmediateOffset(is_load, cid, offset - base_offset)) {
+  if (Address::CanHoldImmediateOffset(is_load, cid, offset - base_offset)) {
     *needs_base = true;
     return true;
   }
@@ -1230,91 +1217,20 @@
 }
 
 
-static Address ElementAddressForIntIndex(Assembler* assembler,
-                                         bool is_load,
-                                         bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         intptr_t index,
-                                         Register temp) {
-  const int64_t offset_base =
-      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
-  const int64_t offset = offset_base +
-      static_cast<int64_t>(index) * index_scale;
-  ASSERT(Utils::IsInt(32, offset));
-
-  if (CanHoldImmediateOffset(is_load, cid, offset)) {
-    return Address(array, static_cast<int32_t>(offset));
-  } else {
-    ASSERT(CanHoldImmediateOffset(is_load, cid, offset - offset_base));
-    assembler->AddImmediate(
-        temp, array, static_cast<int32_t>(offset_base));
-    return Address(temp, static_cast<int32_t>(offset - offset_base));
-  }
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
-                                         bool is_load,
-                                         bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         Register index) {
-  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
-  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
-  int32_t offset =
-      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
-  const OperandSize size = Address::OperandSizeFor(cid);
-  ASSERT(array != IP);
-  ASSERT(index != IP);
-  const Register base = is_load ? IP : index;
-  if ((offset != 0) ||
-      (size == kSWord) || (size == kDWord) || (size == kRegList)) {
-    if (shift < 0) {
-      ASSERT(shift == -1);
-      assembler->add(base, array, Operand(index, ASR, 1));
-    } else {
-      assembler->add(base, array, Operand(index, LSL, shift));
-    }
-  } else {
-    if (shift < 0) {
-      ASSERT(shift == -1);
-      return Address(array, index, ASR, 1);
-    } else {
-      return Address(array, index, LSL, shift);
-    }
-  }
-  int32_t offset_mask = 0;
-  if ((is_load && !Address::CanHoldLoadOffset(size,
-                                              offset,
-                                              &offset_mask)) ||
-      (!is_load && !Address::CanHoldStoreOffset(size,
-                                                offset,
-                                                &offset_mask))) {
-    assembler->AddImmediate(base, offset & ~offset_mask);
-    offset = offset & offset_mask;
-  }
-  return Address(base, offset);
-}
-
-
 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  true,  // Load.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(compiler->assembler(),
-                                  true,  // Load.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value(),
-                                  IP);  // Temp register.
+      ? __ ElementAddressForRegIndex(true,  // Load.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array,
+                                     index.reg())
+      : __ ElementAddressForIntIndex(true,  // Load.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, Smi::Cast(index.constant()).Value(),
+                                     IP);  // Temp register.
   // Warning: element_address may use register IP as base.
 
   if ((representation() == kUnboxedDouble)    ||
@@ -1542,15 +1458,14 @@
       (locs()->temp_count() > 0) ? locs()->temp(0).reg() : kNoRegister;
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  false,  // Store.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(compiler->assembler(),
-                                  false,  // Store.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value(),
-                                  temp);
+      ? __ ElementAddressForRegIndex(false,  // Store.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array,
+                                     index.reg())
+      : __ ElementAddressForIntIndex(false,  // Store.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, Smi::Cast(index.constant()).Value(),
+                                     temp);
 
   switch (class_id()) {
     case kArrayCid:
@@ -6102,18 +6017,18 @@
     case Token::kBIT_AND: {
       __ and_(out_lo, left_lo, Operand(right_lo));
       __ and_(out_hi, left_hi, Operand(right_hi));
+      break;
     }
-    break;
     case Token::kBIT_OR: {
       __ orr(out_lo, left_lo, Operand(right_lo));
       __ orr(out_hi, left_hi, Operand(right_hi));
+      break;
     }
-    break;
     case Token::kBIT_XOR: {
      __ eor(out_lo, left_lo, Operand(right_lo));
      __ eor(out_hi, left_hi, Operand(right_hi));
+     break;
     }
-    break;
     case Token::kADD:
     case Token::kSUB: {
       if (op_kind() == Token::kADD) {
@@ -6130,9 +6045,23 @@
       }
       break;
     }
+    case Token::kMUL: {
+      // The product of two signed 32-bit integers fits in a signed 64-bit
+      // result without causing overflow.
+      // We deopt on larger inputs.
+      // TODO(regis): Range analysis may eliminate the deopt check.
+      if (TargetCPUFeatures::arm_version() == ARMv7) {
+        __ cmp(left_hi, Operand(left_lo, ASR, 31));
+        __ cmp(right_hi, Operand(right_lo, ASR, 31), EQ);
+        __ b(deopt, NE);
+        __ smull(out_lo, out_hi, left_lo, right_lo);
+      } else {
+        __ b(deopt);
+      }
+      break;
+    }
     default:
       UNREACHABLE();
-    break;
   }
   if (FLAG_throw_on_javascript_int_overflow) {
     EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
@@ -6375,19 +6304,22 @@
   switch (op_kind()) {
     case Token::kBIT_AND:
       __ and_(out, left, Operand(right));
-    break;
+      break;
     case Token::kBIT_OR:
       __ orr(out, left, Operand(right));
-    break;
+      break;
     case Token::kBIT_XOR:
       __ eor(out, left, Operand(right));
-    break;
+      break;
     case Token::kADD:
       __ add(out, left, Operand(right));
-    break;
+      break;
     case Token::kSUB:
       __ sub(out, left, Operand(right));
-    break;
+      break;
+    case Token::kMUL:
+      __ mul(out, left, right);
+      break;
     default:
       UNREACHABLE();
   }
@@ -6441,10 +6373,10 @@
       switch (op_kind()) {
         case Token::kSHR:
           __ Lsr(out, left, shift_value);
-        break;
+          break;
         case Token::kSHL:
           __ Lsl(out, left, shift_value);
-        break;
+          break;
         default:
           UNREACHABLE();
       }
@@ -6468,10 +6400,10 @@
   switch (op_kind()) {
     case Token::kSHR:
       __ Lsr(out, left, temp, LS);
-    break;
+      break;
     case Token::kSHL:
       __ Lsl(out, left, temp, LS);
-    break;
+      break;
     default:
       UNREACHABLE();
   }
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 6bcc36d..16a4162 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -1027,60 +1027,18 @@
 }
 
 
-static Address ElementAddressForIntIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         intptr_t index) {
-  const int64_t offset = index * index_scale +
-      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
-  ASSERT(Utils::IsInt(32, offset));
-  const OperandSize size = Address::OperandSizeFor(cid);
-  ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
-  return Address(array, static_cast<int32_t>(offset), Address::Offset, size);
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
-                                         bool is_load,
-                                         bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         Register index) {
-  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
-  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
-  const int32_t offset =
-      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
-  ASSERT(array != TMP);
-  ASSERT(index != TMP);
-  const Register base = is_load ? TMP : index;
-  if ((offset == 0) && (shift == 0)) {
-    return Address(array, index, UXTX, Address::Unscaled);
-  } else if (shift < 0) {
-    ASSERT(shift == -1);
-    assembler->add(base, array, Operand(index, ASR, 1));
-  } else {
-    assembler->add(base, array, Operand(index, LSL, shift));
-  }
-  const OperandSize size = Address::OperandSizeFor(cid);
-  ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
-  return Address(base, offset, Address::Offset, size);
-}
-
-
 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  true,  // Load.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? __ ElementAddressForRegIndex(true,  // Load.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, index.reg())
+      : __ ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
   // Warning: element_address may use register TMP as base.
 
   if ((representation() == kUnboxedDouble)    ||
@@ -1237,12 +1195,12 @@
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  false,  // Store.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? __ ElementAddressForRegIndex(false,  // Store.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, index.reg())
+      : __ ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   switch (class_id()) {
     case kArrayCid:
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index b3069b3..03d75b2 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -651,7 +651,7 @@
   Register cid_reg = locs()->temp(0).reg();
 
   Label* deopt = CanDeoptimize() ?
-  compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
+      compiler->AddDeoptStub(deopt_id(), ICData::kDeoptTestCids) : NULL;
 
   const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
   const ZoneGrowableArray<intptr_t>& data = cid_results();
@@ -1077,66 +1077,17 @@
 }
 
 
-static Address ElementAddressForIntIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         intptr_t index) {
-  if (is_external) {
-    return Address(array, index * index_scale);
-  } else {
-    const int64_t disp = static_cast<int64_t>(index) * index_scale +
-        Instance::DataOffsetFor(cid);
-    ASSERT(Utils::IsInt(32, disp));
-    return FieldAddress(array, static_cast<int32_t>(disp));
-  }
-}
-
-
-static ScaleFactor ToScaleFactor(intptr_t index_scale) {
-  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
-  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
-  // expected to be untagged before accessing.
-  ASSERT(kSmiTagShift == 1);
-  switch (index_scale) {
-    case 1: return TIMES_1;
-    case 2: return TIMES_1;
-    case 4: return TIMES_2;
-    case 8: return TIMES_4;
-    case 16: return TIMES_8;
-    default:
-      UNREACHABLE();
-      return TIMES_1;
-  }
-}
-
-
-static Address ElementAddressForRegIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         Register index) {
-  if (is_external) {
-    return Address(array, index, ToScaleFactor(index_scale), 0);
-  } else {
-    return FieldAddress(array,
-                        index,
-                        ToScaleFactor(index_scale),
-                        Instance::DataOffsetFor(cid));
-  }
-}
-
-
 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? Assembler::ElementAddressForRegIndex(
+            IsExternal(), class_id(), index_scale(), array, index.reg())
+      : Assembler::ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   if ((representation() == kUnboxedDouble) ||
       (representation() == kUnboxedFloat32x4) ||
@@ -1358,10 +1309,11 @@
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? Assembler::ElementAddressForRegIndex(
+            IsExternal(), class_id(), index_scale(), array, index.reg())
+      : Assembler::ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   if ((index_scale() == 1) && index.IsRegister()) {
     __ SmiUntag(index.reg());
@@ -5846,27 +5798,24 @@
   switch (op_kind()) {
     case Token::kBIT_AND:
     case Token::kBIT_OR:
-    case Token::kBIT_XOR: {
-      const intptr_t kNumTemps = 0;
-      LocationSummary* summary = new(isolate) LocationSummary(
-          isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-      summary->set_in(0, Location::Pair(Location::RequiresRegister(),
-                                        Location::RequiresRegister()));
-      summary->set_in(1, Location::Pair(Location::RequiresRegister(),
-                                        Location::RequiresRegister()));
-      summary->set_out(0, Location::SameAsFirstInput());
-      return summary;
-    }
+    case Token::kBIT_XOR:
     case Token::kADD:
-    case Token::kSUB: {
-      const intptr_t kNumTemps = 0;
+    case Token::kSUB:
+    case Token::kMUL: {
+      const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
       LocationSummary* summary = new(isolate) LocationSummary(
           isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-      summary->set_in(0, Location::Pair(Location::RequiresRegister(),
-                                        Location::RequiresRegister()));
+      summary->set_in(0, (op_kind() == Token::kMUL)
+          ? Location::Pair(Location::RegisterLocation(EAX),
+                           Location::RegisterLocation(EDX))
+          : Location::Pair(Location::RequiresRegister(),
+                           Location::RequiresRegister()));
       summary->set_in(1, Location::Pair(Location::RequiresRegister(),
                                         Location::RequiresRegister()));
       summary->set_out(0, Location::SameAsFirstInput());
+      if (kNumTemps > 0) {
+        summary->set_temp(0, Location::RequiresRegister());
+      }
       return summary;
     }
     default:
@@ -5920,7 +5869,28 @@
       }
       break;
     }
-    default: UNREACHABLE();
+    case Token::kMUL: {
+      // The product of two signed 32-bit integers fits in a signed 64-bit
+      // result without causing overflow.
+      // We deopt on larger inputs.
+      // TODO(regis): Range analysis may eliminate the deopt check.
+      Register temp = locs()->temp(0).reg();
+      __ movl(temp, left_lo);
+      __ sarl(temp, Immediate(31));
+      __ cmpl(temp, left_hi);
+      __ j(NOT_EQUAL, deopt);
+      __ movl(temp, right_lo);
+      __ sarl(temp, Immediate(31));
+      __ cmpl(temp, right_hi);
+      __ j(NOT_EQUAL, deopt);
+      ASSERT(left_lo == EAX);
+      __ imull(right_lo);  // Result in EDX:EAX.
+      ASSERT(out_lo == EAX);
+      ASSERT(out_hi == EDX);
+      break;
+    }
+    default:
+      UNREACHABLE();
   }
   if (FLAG_throw_on_javascript_int_overflow) {
     EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
@@ -6113,7 +6083,6 @@
       }
       default:
         UNREACHABLE();
-        break;
     }
     __ Bind(&done);
   }
@@ -6192,10 +6161,15 @@
 LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
                                                           bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = 0;
+  const intptr_t kNumTemps = (op_kind() == Token::kMUL) ? 1 : 0;
   LocationSummary* summary = new(isolate) LocationSummary(
       isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  summary->set_in(0, Location::RequiresRegister());
+  if (op_kind() == Token::kMUL) {
+    summary->set_in(0, Location::RegisterLocation(EAX));
+    summary->set_temp(0, Location::RegisterLocation(EDX));
+  } else {
+    summary->set_in(0, Location::RequiresRegister());
+  }
   summary->set_in(1, Location::RequiresRegister());
   summary->set_out(0, Location::SameAsFirstInput());
   return summary;
@@ -6210,19 +6184,24 @@
   switch (op_kind()) {
     case Token::kBIT_AND:
       __ andl(out, right);
-    break;
+      break;
     case Token::kBIT_OR:
       __ orl(out, right);
-    break;
+      break;
     case Token::kBIT_XOR:
       __ xorl(out, right);
-    break;
+      break;
     case Token::kADD:
       __ addl(out, right);
-    break;
+      break;
     case Token::kSUB:
       __ subl(out, right);
-    break;
+      break;
+    case Token::kMUL:
+      __ mull(right);  // Result in EDX:EAX.
+      ASSERT(out == EAX);
+      ASSERT(locs()->temp(0).reg() == EDX);
+      break;
     default:
       UNREACHABLE();
   }
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 668a1fd..ebf3a54 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1141,48 +1141,6 @@
 }
 
 
-static Address ElementAddressForIntIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         intptr_t index) {
-  const int64_t offset = index * index_scale +
-      (is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag));
-  ASSERT(Utils::IsInt(32, offset));
-  ASSERT(Address::CanHoldOffset(offset));
-  return Address(array, static_cast<int32_t>(offset));
-}
-
-
-static Address ElementAddressForRegIndex(Assembler* assembler,
-                                         bool is_load,
-                                         bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         Register index) {
-  // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
-  const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
-  const int32_t offset =
-      is_external ? 0 : (Instance::DataOffsetFor(cid) - kHeapObjectTag);
-  ASSERT(array != TMP);
-  ASSERT(index != TMP);
-  const Register base = is_load ? TMP : index;
-  if (shift < 0) {
-    ASSERT(shift == -1);
-    assembler->sra(TMP, index, 1);
-    assembler->addu(base, array, TMP);
-  } else if (shift == 0) {
-    assembler->addu(base, array, index);
-  } else {
-    assembler->sll(TMP, index, shift);
-    assembler->addu(base, array, TMP);
-  }
-  ASSERT(Address::CanHoldOffset(offset));
-  return Address(base, offset);
-}
-
-
 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ TraceSimMsg("LoadIndexedInstr");
   // The array register points to the backing store for external arrays.
@@ -1190,12 +1148,12 @@
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  true,  // Load.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? __ ElementAddressForRegIndex(true,  // Load.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, index.reg())
+      : __ ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
   // Warning: element_address may use register TMP as base.
 
   if ((representation() == kUnboxedDouble) ||
@@ -1364,12 +1322,12 @@
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(compiler->assembler(),
-                                  false,  // Store.
-                                  IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? __ ElementAddressForRegIndex(false,  // Store.
+                                     IsExternal(), class_id(), index_scale(),
+                                     array, index.reg())
+      : __ ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   switch (class_id()) {
     case kArrayCid:
diff --git a/runtime/vm/intermediate_language_test.cc b/runtime/vm/intermediate_language_test.cc
index 918849b..67f304e 100644
--- a/runtime/vm/intermediate_language_test.cc
+++ b/runtime/vm/intermediate_language_test.cc
@@ -62,7 +62,7 @@
   EXPECT(!range_x->IsWithin(-15, 99));
   EXPECT(!range_x->IsWithin(-14, 100));
 
-#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max)  \
+#define TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max, Clamp, res_min, res_max)\
   {                                                                            \
     RangeBoundary min, max;                                                    \
     Range* left_range = new Range(                                             \
@@ -72,12 +72,24 @@
       RangeBoundary::FromConstant(r_min),                                      \
       RangeBoundary::FromConstant(r_max));                                     \
     Op(left_range, shift_range, &min, &max);                                   \
-    EXPECT(min.Equals(result_min));                                            \
-    if (!min.Equals(result_min)) OS::Print("%s\n", min.ToCString());           \
-    EXPECT(max.Equals(result_max));                                            \
-    if (!max.Equals(result_max)) OS::Print("%s\n", max.ToCString());           \
+    min = Clamp(min);                                                          \
+    max = Clamp(max);                                                          \
+    EXPECT(min.Equals(res_min));                                               \
+    if (!min.Equals(res_min)) OS::Print("%s\n", min.ToCString());              \
+    EXPECT(max.Equals(res_max));                                               \
+    if (!max.Equals(res_max)) OS::Print("%s\n", max.ToCString());              \
   }
 
+#define NO_CLAMP(b) (b)
+#define TEST_RANGE_OP(Op, l_min, l_max, r_min, r_max, result_min, result_max)  \
+  TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max,                               \
+                 NO_CLAMP, result_min, result_max)
+
+#define CLAMP_TO_SMI(b) (b.Clamp(RangeBoundary::kRangeBoundarySmi))
+#define TEST_RANGE_OP_SMI(Op, l_min, l_max, r_min, r_max, res_min, res_max)    \
+  TEST_RANGE_OP_(Op, l_min, l_max, r_min, r_max,                               \
+                 CLAMP_TO_SMI, res_min, res_max)
+
   TEST_RANGE_OP(Range::Shl, -15, 100, 0, 2,
                 RangeBoundary(-60), RangeBoundary(400));
   TEST_RANGE_OP(Range::Shl, -15, 100, -2, 2,
@@ -90,22 +102,22 @@
                 RangeBoundary::NegativeInfinity(),
                 RangeBoundary::PositiveInfinity());
   TEST_RANGE_OP(Range::Shl, -1, 1, 63, 63,
-                RangeBoundary::NegativeInfinity(),
+                RangeBoundary(kMinInt64),
                 RangeBoundary::PositiveInfinity());
   if (kBitsPerWord == 64) {
-    TEST_RANGE_OP(Range::Shl, -1, 1, 62, 62,
+    TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
                   RangeBoundary(kSmiMin),
-                  RangeBoundary::PositiveInfinity());
-    TEST_RANGE_OP(Range::Shl, -1, 1, 30, 30,
+                  RangeBoundary(kSmiMax));
+    TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
                   RangeBoundary(-1 << 30),
                   RangeBoundary(1 << 30));
   } else {
-    TEST_RANGE_OP(Range::Shl, -1, 1, 30, 30,
+    TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 30, 30,
                   RangeBoundary(kSmiMin),
-                  RangeBoundary::PositiveInfinity());
-    TEST_RANGE_OP(Range::Shl, -1, 1, 62, 62,
-                  RangeBoundary::NegativeInfinity(),
-                  RangeBoundary::PositiveInfinity());
+                  RangeBoundary(kSmiMax));
+    TEST_RANGE_OP_SMI(Range::Shl, -1, 1, 62, 62,
+                  RangeBoundary(kSmiMin),
+                  RangeBoundary(kSmiMax));
   }
   TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64,
                 RangeBoundary(0), RangeBoundary::PositiveInfinity());
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 3ec1f4d..19bf864 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -990,66 +990,17 @@
 }
 
 
-static Address ElementAddressForIntIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         intptr_t index) {
-  if (is_external) {
-    return Address(array, index * index_scale);
-  } else {
-    const int64_t disp = static_cast<int64_t>(index) * index_scale +
-        Instance::DataOffsetFor(cid);
-    ASSERT(Utils::IsInt(32, disp));
-    return FieldAddress(array, static_cast<int32_t>(disp));
-  }
-}
-
-
-static ScaleFactor ToScaleFactor(intptr_t index_scale) {
-  // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
-  // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
-  // expected to be untagged before accessing.
-  ASSERT(kSmiTagShift == 1);
-  switch (index_scale) {
-    case 1: return TIMES_1;
-    case 2: return TIMES_1;
-    case 4: return TIMES_2;
-    case 8: return TIMES_4;
-    case 16: return TIMES_8;
-    default:
-      UNREACHABLE();
-      return TIMES_1;
-  }
-}
-
-
-static Address ElementAddressForRegIndex(bool is_external,
-                                         intptr_t cid,
-                                         intptr_t index_scale,
-                                         Register array,
-                                         Register index) {
-  if (is_external) {
-    return Address(array, index, ToScaleFactor(index_scale), 0);
-  } else {
-    return FieldAddress(array,
-                        index,
-                        ToScaleFactor(index_scale),
-                        Instance::DataOffsetFor(cid));
-  }
-}
-
-
 void LoadIndexedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? Assembler::ElementAddressForRegIndex(
+            IsExternal(), class_id(), index_scale(), array, index.reg())
+      : Assembler::ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   if ((representation() == kUnboxedDouble)    ||
       (representation() == kUnboxedFloat32x4) ||
@@ -1217,10 +1168,11 @@
   const Location index = locs()->in(1);
 
   Address element_address = index.IsRegister()
-      ? ElementAddressForRegIndex(IsExternal(), class_id(), index_scale(),
-                                  array, index.reg())
-      : ElementAddressForIntIndex(IsExternal(), class_id(), index_scale(),
-                                  array, Smi::Cast(index.constant()).Value());
+      ? Assembler::ElementAddressForRegIndex(
+            IsExternal(), class_id(), index_scale(), array, index.reg())
+      : Assembler::ElementAddressForIntIndex(
+            IsExternal(), class_id(), index_scale(),
+            array, Smi::Cast(index.constant()).Value());
 
   if ((index_scale() == 1) && index.IsRegister()) {
     __ SmiUntag(index.reg());
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 183540b..fe0aa2a 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -133,6 +133,8 @@
   V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 611308575)           \
   V(_Uint8Array, [], Uint8Array_getIndexed, 16125140)                          \
   V(_ExternalUint8Array, [], ExternalUint8Array_getIndexed, 1678777951)        \
+  V(_Float64Array, [], Float64Array_getIndexed, 1779054297)                    \
+  V(_Float64Array, []=, Float64Array_setIndexed, 243929230)                    \
 
 
 #define PROFILER_LIB_INTRINSIC_LIST(V)                                         \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 11ac497..c026751 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -475,6 +475,76 @@
 }
 
 
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ ldr(R0, Address(SP, + 0 * kWordSize));  // Index.
+  __ ldr(R1, Address(SP, + 1 * kWordSize));  // Array.
+  __ tst(R0, Operand(kSmiTagMask));
+  __ b(&fall_through, NE);  // Index is not a smi, fall through.
+
+  // Range check.
+  __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+  __ cmp(R0, Operand(R6));
+  __ b(&fall_through, CS);
+
+
+  Address element_address =
+      __ ElementAddressForRegIndex(true,  // Load.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   R1,  // Array.
+                                   R0);  // Index.
+
+  __ vldrd(D0, element_address);
+
+  const Class& double_class = Class::Handle(
+      Isolate::Current()->object_store()->double_class());
+  __ TryAllocate(double_class,
+                 &fall_through,
+                 R0,  // Result register.
+                 R1);
+  __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
+  __ Ret();
+  __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ ldr(R0, Address(SP, + 1 * kWordSize));  // Index.
+  __ ldr(R1, Address(SP, + 2 * kWordSize));  // Array.
+  __ tst(R0, Operand(kSmiTagMask));
+  __ b(&fall_through, NE);  // Index is not a smi, fall through.
+
+  // Range check.
+  __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+  __ cmp(R0, Operand(R6));
+  __ b(&fall_through, CS);
+
+  __ ldr(R2, Address(SP, + 0 * kWordSize));  // Value.
+  __ tst(R2, Operand(kSmiTagMask));
+  __ b(&fall_through, EQ);  // Value is Smi, fall through.
+
+  __ LoadClassId(R3, R2);
+  __ CompareImmediate(R3, kDoubleCid);
+  __ b(&fall_through, NE);  // Not a Double, fall through.
+
+  __ LoadDFromOffset(D0, R2, Double::value_offset() - kHeapObjectTag);
+
+  Address element_address =
+      __ ElementAddressForRegIndex(false,  // Store.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   R1,  // Array.
+                                   R0);  // Index.
+  __ vstrd(D0, element_address);
+  __ Ret();
+  __ Bind(&fall_through);
+}
+
+
 static int GetScaleFactor(intptr_t size) {
   switch (size) {
     case 1: return 0;
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index e8a5ee4..6e26b2e 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -400,6 +400,75 @@
 }
 
 
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ ldr(R0, Address(SP, + 0 * kWordSize));  // Index.
+  __ ldr(R1, Address(SP, + 1 * kWordSize));  // Array.
+  __ tsti(R0, kSmiTagMask);
+  __ b(&fall_through, NE);  // Index is not a smi, fall through.
+
+  // Range check.
+  __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+  __ cmp(R0, Operand(R6));
+  __ b(&fall_through, CS);
+
+  Address element_address =
+      __ ElementAddressForRegIndex(true,  // Load.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   R1,  // Array.
+                                   R0);  // Index.
+
+  __ fldrd(V0, element_address);
+
+  const Class& double_class = Class::Handle(
+      Isolate::Current()->object_store()->double_class());
+  __ TryAllocate(double_class,
+                 &fall_through,
+                 R0,  // Result register.
+                 kNoPP);
+  __ StoreDFieldToOffset(V0, R0, Double::value_offset(), kNoPP);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ ldr(R0, Address(SP, + 1 * kWordSize));  // Index.
+  __ ldr(R1, Address(SP, + 2 * kWordSize));  // Array.
+  __ tsti(R0, kSmiTagMask);
+  __ b(&fall_through, NE);  // Index is not a smi, fall through.
+
+  // Range check.
+  __ ldr(R6, FieldAddress(R1, TypedData::length_offset()));
+  __ cmp(R0, Operand(R6));
+  __ b(&fall_through, CS);
+
+  __ ldr(R2, Address(SP, + 0 * kWordSize));  // Value.
+  __ tsti(R2, kSmiTagMask);
+  __ b(&fall_through, EQ);  // Value is Smi, fall through.
+
+  __ LoadClassId(R3, R2, kNoPP);
+  __ CompareImmediate(R3, kDoubleCid, kNoPP);
+  __ b(&fall_through, NE);  // Not a Double, fall through.
+
+  __ LoadDFieldFromOffset(V0, R2, Double::value_offset(), kNoPP);
+
+  Address element_address =
+      __ ElementAddressForRegIndex(false,  // Store.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   R1,  // Array.
+                                   R0);  // Index.
+  __ fstrd(V0, element_address);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
 static int GetScaleFactor(intptr_t size) {
   switch (size) {
     case 1: return 0;
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index ab3948d..288373a 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -481,6 +481,73 @@
 }
 
 
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ movl(EBX, Address(ESP, + 1 * kWordSize));  // Index.
+  __ movl(EAX, Address(ESP, + 2 * kWordSize));  // Array.
+  __ testl(EBX, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);  // Non-smi index.
+  // Range check.
+  __ cmpl(EBX, FieldAddress(EAX, TypedData::length_offset()));
+  // Runtime throws exception.
+  __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+  Address element_address =
+      Assembler::ElementAddressForRegIndex(false,  // Not external
+                                           kTypedDataFloat64ArrayCid,  // Cid.
+                                           8,  // Index scale.
+                                           EAX,  // Array.
+                                           EBX);  // Index.
+
+  __ movsd(XMM0, element_address);
+
+  const Class& double_class = Class::Handle(
+      Isolate::Current()->object_store()->double_class());
+  __ TryAllocate(double_class,
+                 &fall_through,
+                 Assembler::kNearJump,
+                 EAX,  // Result register.
+                 EBX);
+  __ movsd(FieldAddress(EAX, Double::value_offset()), XMM0);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ movl(EBX, Address(ESP, + 2 * kWordSize));  // Index.
+  __ movl(EAX, Address(ESP, + 3 * kWordSize));  // Array.
+  __ testl(EBX, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);  // Non-smi index.
+  // Range check.
+  __ cmpl(EBX, FieldAddress(EAX, TypedData::length_offset()));
+  // Runtime throws exception.
+  __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ movl(ECX, Address(ESP, + 1 * kWordSize));  // Value.
+  __ testl(ECX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through, Assembler::kNearJump);  // Value is Smi.
+  __ LoadClassId(EDI, ECX);
+
+  __ cmpl(EDI, Immediate(kDoubleCid));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);  // Not a Double.
+
+  __ movsd(XMM0, FieldAddress(ECX, Double::value_offset()));
+
+  Address element_address =
+      Assembler::ElementAddressForRegIndex(false,  // Not external
+                                           kTypedDataFloat64ArrayCid,  // Cid.
+                                           8,  // Index scale.
+                                           EAX,  // Array.
+                                           EBX);  // Index.
+
+  __ movsd(element_address, XMM0);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
 static ScaleFactor GetScaleFactor(intptr_t size) {
   switch (size) {
     case 1: return TIMES_1;
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index d1f7e35..de67175 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -484,6 +484,76 @@
 }
 
 
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+  Label fall_through;
+
+  __ lw(T0, Address(SP, + 0 * kWordSize));  // Index.
+
+  __ andi(CMPRES1, T0, Immediate(kSmiTagMask));
+  __ bne(CMPRES1, ZR, &fall_through);  // Index is not an smi, fall through.
+  __ delay_slot()->lw(T1, Address(SP, + 1 * kWordSize));  // Array.
+
+  // Range check.
+  __ lw(T2, FieldAddress(T1, TypedData::length_offset()));
+  __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
+
+  Address element_address =
+      __ ElementAddressForRegIndex(true,  // Load.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   T1,  // Array.
+                                   T0);  // Index.
+
+  __ LoadDFromOffset(D0, element_address.base(), element_address.offset());
+
+  const Class& double_class = Class::Handle(
+      Isolate::Current()->object_store()->double_class());
+  __ TryAllocate(double_class,
+                 &fall_through,
+                 V0,  // Result register.
+                 T1);
+  __ StoreDToOffset(D0, V0, Double::value_offset() - kHeapObjectTag);
+  __ Ret();
+  __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+  Label fall_through;
+
+  __ lw(T0, Address(SP, + 1 * kWordSize));  // Index.
+
+  __ andi(CMPRES1, T0, Immediate(kSmiTagMask));
+  __ bne(CMPRES1, ZR, &fall_through);  // Index is not an smi, fall through.
+  __ delay_slot()->lw(T1, Address(SP, + 2 * kWordSize));  // Array.
+
+  // Range check.
+  __ lw(T2, FieldAddress(T1, TypedData::length_offset()));
+  __ BranchUnsignedGreaterEqual(T0, T2, &fall_through);
+
+  __ lw(T2, Address(SP, + 0 * kWordSize));  // Value.
+  __ andi(CMPRES1, T2, Immediate(kSmiTagMask));
+  __ beq(CMPRES1, ZR, &fall_through);  // Value is a Smi. Fall through.
+
+  __ LoadClassId(T3, T2);
+  __ BranchNotEqual(T3, kDoubleCid, &fall_through);  // Not a Double.
+
+  __ LoadDFromOffset(D0, T2, Double::value_offset() - kHeapObjectTag);
+
+  Address element_address =
+      __ ElementAddressForRegIndex(false,  // Store.
+                                   false,  // Not external.
+                                   kTypedDataFloat64ArrayCid,  // Cid.
+                                   8,  // Index scale.
+                                   T1,  // Array.
+                                   T0);  // Index.
+  __ StoreDToOffset(D0, element_address.base(), element_address.offset());
+  __ Ret();
+  __ Bind(&fall_through);
+}
+
+
 static int GetScaleFactor(intptr_t size) {
   switch (size) {
     case 1: return 0;
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index eb7ae29..b83522d 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -436,6 +436,73 @@
 }
 
 
+void Intrinsifier::Float64Array_getIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ movq(RCX, Address(RSP, + 1 * kWordSize));  // Index.
+  __ movq(RAX, Address(RSP, + 2 * kWordSize));  // Array.
+  __ testq(RCX, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);  // Non-smi index.
+  // Range check.
+  __ cmpq(RCX, FieldAddress(RAX, TypedData::length_offset()));
+  // Runtime throws exception.
+  __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+  Address element_address =
+      Assembler::ElementAddressForRegIndex(false,  // Not external.
+                                           kTypedDataFloat64ArrayCid,
+                                           8,  // Index scale.
+                                           RAX,  // Array.
+                                           RCX);  // Index.
+
+  __ movsd(XMM0, element_address);
+
+  const Class& double_class = Class::Handle(
+      Isolate::Current()->object_store()->double_class());
+  __ TryAllocate(double_class,
+                 &fall_through,
+                 Assembler::kNearJump,
+                 RAX,  // Result register.
+                 kNoRegister);
+  __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
+void Intrinsifier::Float64Array_setIndexed(Assembler* assembler) {
+  Label fall_through;
+  __ movq(RCX, Address(RSP, + 2 * kWordSize));  // Index.
+  __ movq(RAX, Address(RSP, + 3 * kWordSize));  // Array.
+  __ testq(RCX, Immediate(kSmiTagMask));
+  __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);  // Non-smi index.
+  // Range check.
+  __ cmpq(RCX, FieldAddress(RAX, TypedData::length_offset()));
+  // Runtime throws exception.
+  __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ movq(RDX, Address(RSP, + 1 * kWordSize));  // Value
+  __ testq(RDX, Immediate(kSmiTagMask));
+  __ j(ZERO, &fall_through, Assembler::kNearJump);  // Value is Smi.
+
+  __ LoadClassId(RDI, RDX);
+  __ cmpq(RDI, Immediate(kTypedDataFloat64ArrayCid));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ movsd(XMM0, FieldAddress(RDX, Double::value_offset()));
+
+  Address element_address =
+      Assembler::ElementAddressForRegIndex(false,  // Not external.
+                                           kTypedDataFloat64ArrayCid,
+                                           8,  // Index scale.
+                                           RAX,  // Array.
+                                           RCX);  // Index.
+
+  __ movsd(element_address, XMM0);
+  __ ret();
+  __ Bind(&fall_through);
+}
+
+
 static ScaleFactor GetScaleFactor(intptr_t size) {
   switch (size) {
     case 1: return TIMES_1;
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 60d2ba5..f7ff985 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -83,7 +83,7 @@
 DART_EXPORT Dart_Handle Dart_CompileAll() {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
-  Dart_Handle result = Api::CheckIsolateState(isolate);
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(isolate);
   if (::Dart_IsError(result)) {
     return result;
   }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index eec536b..1d4d290 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6511,15 +6511,18 @@
       count++;
     }
   }
-
-  const Array& a = Array::Handle(Array::New(count, Heap::kOld));
-  count = 0;
-  for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
-    if (deopt_id_to_ic_data[i] != NULL) {
-      a.SetAt(count++, *deopt_id_to_ic_data[i]);
+  if (count == 0) {
+    set_ic_data_array(Object::empty_array());
+  } else {
+    const Array& a = Array::Handle(Array::New(count, Heap::kOld));
+    count = 0;
+    for (intptr_t i = 0; i < deopt_id_to_ic_data.length(); i++) {
+      if (deopt_id_to_ic_data[i] != NULL) {
+        a.SetAt(count++, *deopt_id_to_ic_data[i]);
+      }
     }
+    set_ic_data_array(a);
   }
-  set_ic_data_array(a);
 }
 
 
@@ -10358,30 +10361,26 @@
   // First compute the buffer size required.
   intptr_t len = 1;  // Trailing '\0'.
   Iterator iter(*this, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
+  while (iter.MoveNext()) {
     len += OS::SNPrint(NULL, 0, kFormat, addr_width,
-                       rec.pc(),
-                       KindAsStr(rec.kind()),
-                       rec.deopt_id(),
-                       rec.token_pos(),
-                       rec.try_index());
+                       iter.Pc(),
+                       KindAsStr(iter.Kind()),
+                       iter.DeoptId(),
+                       iter.TokenPos(),
+                       iter.TryIndex());
   }
   // Allocate the buffer.
   char* buffer = Isolate::Current()->current_zone()->Alloc<char>(len);
   // Layout the fields in the buffer.
   intptr_t index = 0;
   Iterator iter2(*this, RawPcDescriptors::kAnyKind);
-  while (iter2.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter2.NextRec(&rec);
+  while (iter2.MoveNext()) {
     index += OS::SNPrint((buffer + index), (len - index), kFormat, addr_width,
-                         rec.pc(),
-                         KindAsStr(rec.kind()),
-                         rec.deopt_id(),
-                         rec.token_pos(),
-                         rec.try_index());
+                         iter.Pc(),
+                         KindAsStr(iter.Kind()),
+                         iter.DeoptId(),
+                         iter.TokenPos(),
+                         iter.TryIndex());
   }
   return buffer;
 }
@@ -10395,15 +10394,13 @@
   jsobj->AddProperty("id", "");
   JSONArray members(jsobj, "members");
   Iterator iter(*this, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
+  while (iter.MoveNext()) {
     JSONObject descriptor(&members);
-    descriptor.AddPropertyF("pc", "%" Px "", rec.pc());
-    descriptor.AddProperty("kind", KindAsStr(rec.kind()));
-    descriptor.AddProperty("deoptId",  static_cast<intptr_t>(rec.deopt_id()));
-    descriptor.AddProperty("tokenPos",  static_cast<intptr_t>(rec.token_pos()));
-    descriptor.AddProperty("tryIndex",  static_cast<intptr_t>(rec.try_index()));
+    descriptor.AddPropertyF("pc", "%" Px "", iter.Pc());
+    descriptor.AddProperty("kind", KindAsStr(iter.Kind()));
+    descriptor.AddProperty("deoptId", iter.DeoptId());
+    descriptor.AddProperty("tokenPos", iter.TokenPos());
+    descriptor.AddProperty("tryIndex", iter.TryIndex());
   }
 }
 
@@ -10434,12 +10431,9 @@
     return;
   }
   Iterator iter(*this, RawPcDescriptors::kDeopt | RawPcDescriptors::kIcCall);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
+  while (iter.MoveNext()) {
     // 'deopt_id' is set for kDeopt and kIcCall and must be unique for one kind.
-
-    if (Isolate::IsDeoptAfter(rec.deopt_id())) {
+    if (Isolate::IsDeoptAfter(iter.DeoptId())) {
       // TODO(vegorov): some instructions contain multiple calls and have
       // multiple "after" targets recorded. Right now it is benign but might
       // lead to issues in the future. Fix that and enable verification.
@@ -10447,11 +10441,9 @@
     }
 
     Iterator nested(iter);
-    while (nested.HasNext()) {
-      RawPcDescriptors::PcDescriptorRec nested_rec;
-      nested.NextRec(&nested_rec);
-      if (rec.kind() == nested_rec.kind()) {
-        ASSERT(nested_rec.deopt_id() != rec.deopt_id());
+    while (nested.MoveNext()) {
+      if (iter.Kind() == nested.Kind()) {
+        ASSERT(nested.DeoptId() != iter.DeoptId());
       }
     }
   }
@@ -10461,8 +10453,8 @@
 
 uword PcDescriptors::GetPcForKind(RawPcDescriptors::Kind kind) const {
   Iterator iter(*this, kind);
-  if (iter.HasNext()) {
-    return iter.NextPc();
+  if (iter.MoveNext()) {
+    return iter.Pc();
   }
   return 0;
 }
@@ -10710,7 +10702,8 @@
     result ^= raw;
     result.raw_ptr()->length_ = num_variables;
   }
-  const Array& names = Array::Handle(Array::New(num_variables, Heap::kOld));
+  const Array& names = (num_variables == 0) ? Object::empty_array() :
+      Array::Handle(Array::New(num_variables, Heap::kOld));
   result.raw_ptr()->names_ = names.raw();
   return result.raw();
 }
@@ -10811,7 +10804,9 @@
     result ^= raw;
     result.raw_ptr()->length_ = num_handlers;
   }
-  const Array& handled_types_data = Array::Handle(Array::New(num_handlers));
+  const Array& handled_types_data = (num_handlers == 0) ?
+      Object::empty_array() :
+      Array::Handle(Array::New(num_handlers));
   result.set_handled_types_data(handled_types_data);
   return result.raw();
 }
@@ -11960,11 +11955,9 @@
 intptr_t Code::GetTokenIndexOfPC(uword pc) const {
   const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (rec.pc() == pc) {
-      return rec.token_pos();
+  while (iter.MoveNext()) {
+    if (iter.Pc() == pc) {
+      return iter.TokenPos();
     }
   }
   return -1;
@@ -11975,11 +11968,9 @@
                             RawPcDescriptors::Kind kind) const {
   const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
   PcDescriptors::Iterator iter(descriptors, kind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (rec.deopt_id() == deopt_id) {
-      uword pc = rec.pc();
+  while (iter.MoveNext()) {
+    if (iter.DeoptId() == deopt_id) {
+      uword pc = iter.Pc();
       ASSERT(ContainsInstructionAt(pc));
       return pc;
     }
@@ -11991,11 +11982,9 @@
 intptr_t Code::GetDeoptIdForOsr(uword pc) const {
   const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kOsrEntry);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (rec.pc() == pc) {
-      return rec.deopt_id();
+  while (iter.MoveNext()) {
+    if (iter.Pc() == pc) {
+      return iter.DeoptId();
     }
   }
   return Isolate::kNoDeoptId;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d499f92..7dd070e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3047,59 +3047,66 @@
   class Iterator : ValueObject {
    public:
     Iterator(const PcDescriptors& descriptors, intptr_t kind_mask)
-        : descriptors_(descriptors), kind_mask_(kind_mask), current_ix_(0) {
+        : descriptors_(descriptors),
+          kind_mask_(kind_mask),
+          next_ix_(0),
+          current_ix_(-1) {
       MoveToMatching();
     }
 
-    bool HasNext() const { return current_ix_ < descriptors_.Length(); }
-
-    intptr_t NextDeoptId() {
-      ASSERT(HasNext());
-      const intptr_t res = descriptors_.recAt(current_ix_++)->deopt_id();
-      MoveToMatching();
-      return res;
+    bool MoveNext() {
+      if (HasNext()) {
+        current_ix_ = next_ix_++;
+        MoveToMatching();
+        return true;
+      } else {
+        return false;
+      }
     }
 
-    uword NextPc() {
-      ASSERT(HasNext());
-      const uword res = descriptors_.recAt(current_ix_++)->pc();
-      MoveToMatching();
-      return res;
+    uword Pc() const { return descriptors_.recAt(current_ix_)->pc(); }
+    intptr_t DeoptId() const {
+      return descriptors_.recAt(current_ix_)->deopt_id();
     }
-
-    void NextRec(RawPcDescriptors::PcDescriptorRec* result) {
-      ASSERT(HasNext());
-      const RawPcDescriptors::PcDescriptorRec* r =
-          descriptors_.recAt(current_ix_++);
-      r->CopyTo(result);
-      MoveToMatching();
+    intptr_t TokenPos() const {
+      return descriptors_.recAt(current_ix_)->token_pos();
+    }
+    intptr_t TryIndex() const {
+      return descriptors_.recAt(current_ix_)->try_index();
+    }
+    RawPcDescriptors::Kind Kind() const {
+      return descriptors_.recAt(current_ix_)->kind();
     }
 
    private:
     friend class PcDescriptors;
 
+    bool HasNext() const { return next_ix_ < descriptors_.Length(); }
+
     // For nested iterations, starting at element after.
     explicit Iterator(const Iterator& iter)
         : ValueObject(),
           descriptors_(iter.descriptors_),
           kind_mask_(iter.kind_mask_),
+          next_ix_(iter.next_ix_),
           current_ix_(iter.current_ix_) {}
 
     // Moves to record that matches kind_mask_.
     void MoveToMatching() {
-      while (current_ix_ < descriptors_.Length()) {
+      while (next_ix_ < descriptors_.Length()) {
         const RawPcDescriptors::PcDescriptorRec& rec =
-            *descriptors_.recAt(current_ix_);
+            *descriptors_.recAt(next_ix_);
         if ((rec.kind() & kind_mask_) != 0) {
           return;  // Current is valid.
         } else {
-          ++current_ix_;
+          ++next_ix_;
         }
       }
     }
 
     const PcDescriptors& descriptors_;
     const intptr_t kind_mask_;
+    intptr_t next_ix_;
     intptr_t current_ix_;
   };
 
@@ -3113,7 +3120,7 @@
   intptr_t RecordSizeInBytes() const;
 
   RawPcDescriptors::PcDescriptorRec* recAt(intptr_t ix) const {
-    ASSERT(ix < Length());
+    ASSERT((0 <= ix) && (ix < Length()));
     uint8_t* d = raw_ptr()->data() + (ix * RecordSizeInBytes());
     return reinterpret_cast<RawPcDescriptors::PcDescriptorRec*>(d);
   }
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 5a0f3f7..c8508cd 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2746,35 +2746,36 @@
   // Verify the PcDescriptor entries by accessing them.
   const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
-  RawPcDescriptors::PcDescriptorRec rec0;
-  RawPcDescriptors::PcDescriptorRec rec1;
-  RawPcDescriptors::PcDescriptorRec rec2;
-  RawPcDescriptors::PcDescriptorRec rec3;
-  RawPcDescriptors::PcDescriptorRec rec4;
-  RawPcDescriptors::PcDescriptorRec rec5;
-  iter.NextRec(&rec0);
-  iter.NextRec(&rec1);
-  iter.NextRec(&rec2);
-  iter.NextRec(&rec3);
-  iter.NextRec(&rec4);
-  iter.NextRec(&rec5);
-  ASSERT(!iter.HasNext());
 
-  EXPECT_EQ(1, rec0.try_index());
-  EXPECT_EQ(static_cast<uword>(10), rec0.pc());
-  EXPECT_EQ(1, rec0.deopt_id());
-  EXPECT_EQ(20, rec0.token_pos());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(20, iter.TokenPos());
+  EXPECT_EQ(1, iter.TryIndex());
+  EXPECT_EQ(static_cast<uword>(10), iter.Pc());
+  EXPECT_EQ(1, iter.DeoptId());
+  EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
-  EXPECT_EQ(3, rec5.try_index());
-  EXPECT_EQ(static_cast<uword>(80), rec5.pc());
-  EXPECT_EQ(150, rec5.token_pos());
-  EXPECT_EQ(RawPcDescriptors::kOther, rec0.kind());
-  EXPECT_EQ(RawPcDescriptors::kDeopt, rec1.kind());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(30, iter.TokenPos());
+  EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
 
-  EXPECT_EQ(30, rec1.token_pos());
-  EXPECT_EQ(40, rec2.token_pos());
-  EXPECT_EQ(40, rec3.token_pos());
-  EXPECT_EQ(80, rec4.token_pos());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(40, iter.TokenPos());
+
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(40, iter.TokenPos());
+
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(80, iter.TokenPos());
+
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(150, iter.TokenPos());
+
+  EXPECT_EQ(3, iter.TryIndex());
+  EXPECT_EQ(static_cast<uword>(80), iter.Pc());
+  EXPECT_EQ(150, iter.TokenPos());
+  EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
+
+  EXPECT_EQ(false, iter.MoveNext());
 }
 
 
@@ -2801,35 +2802,24 @@
   // Verify the PcDescriptor entries by accessing them.
   const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
-  RawPcDescriptors::PcDescriptorRec rec0;
-  RawPcDescriptors::PcDescriptorRec rec1;
-  RawPcDescriptors::PcDescriptorRec rec2;
-  RawPcDescriptors::PcDescriptorRec rec3;
-  RawPcDescriptors::PcDescriptorRec rec4;
-  RawPcDescriptors::PcDescriptorRec rec5;
-  iter.NextRec(&rec0);
-  iter.NextRec(&rec1);
-  iter.NextRec(&rec2);
-  iter.NextRec(&rec3);
-  iter.NextRec(&rec4);
-  iter.NextRec(&rec5);
-  ASSERT(!iter.HasNext());
 
-  EXPECT_EQ(-1, rec0.try_index());
-  EXPECT_EQ(static_cast<uword>(10), rec0.pc());
-  EXPECT_EQ(1, rec0.deopt_id());
-  EXPECT_EQ(20, rec0.token_pos());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(static_cast<uword>(10), iter.Pc());
+  EXPECT_EQ(-1, iter.TryIndex());
+  EXPECT_EQ(1, iter.DeoptId());
+  EXPECT_EQ(20, iter.TokenPos());
 
-  EXPECT_EQ(-1, rec5.try_index());
-  EXPECT_EQ(static_cast<uword>(80), rec5.pc());
-  EXPECT_EQ(150, rec5.token_pos());
-  EXPECT_EQ(RawPcDescriptors::kOther, rec0.kind());
-  EXPECT_EQ(RawPcDescriptors::kDeopt, rec1.kind());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(true, iter.MoveNext());
 
-  EXPECT_EQ(30, rec1.token_pos());
-  EXPECT_EQ(40, rec2.token_pos());
-  EXPECT_EQ(40, rec3.token_pos());
-  EXPECT_EQ(80, rec4.token_pos());
+  EXPECT_EQ(-1, iter.TryIndex());
+  EXPECT_EQ(static_cast<uword>(80), iter.Pc());
+  EXPECT_EQ(150, iter.TokenPos());
+
+  EXPECT_EQ(false, iter.MoveNext());
 }
 
 
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 1018cf4..a2dec35 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -34,8 +34,6 @@
             "Time between profiler samples in microseconds. Minimum 50.");
 DEFINE_FLAG(int, profile_depth, 8,
             "Maximum number stack frames walked. Minimum 1. Maximum 255.");
-DEFINE_FLAG(bool, profile_verify_stack_walk, false,
-            "Verify instruction addresses while walking the stack.");
 DEFINE_FLAG(bool, profile_vm, false,
             "Always collect native stack traces.");
 
@@ -1663,21 +1661,39 @@
 }
 
 
-class ProfilerDartStackWalker : public ValueObject {
+static void SetPCMarkerIfSafe(Sample* sample) {
+  ASSERT(sample != NULL);
+
+  uword* fp = reinterpret_cast<uword*>(sample->fp());
+  uword* sp = reinterpret_cast<uword*>(sample->sp());
+
+  // If FP == SP, the pc marker hasn't been pushed.
+  if (fp > sp) {
+#if defined(TARGET_OS_WINDOWS)
+    // If the fp is at the beginning of a page, it may be unsafe to access
+    // the pc marker, because we are reading it from a different thread on
+    // Windows. The next page may be a guard page.
+    const intptr_t kPageMask = VirtualMemory::PageSize() - 1;
+    if ((sample->fp() & kPageMask) == 0) {
+      return;
+    }
+#endif
+    const uword pc_marker = *(fp + kPcMarkerSlotFromFp);
+    sample->set_pc_marker(pc_marker);
+  }
+}
+
+
+// Given an exit frame, walk the Dart stack.
+class ProfilerDartExitStackWalker : public ValueObject {
  public:
-  ProfilerDartStackWalker(Isolate* isolate, Sample* sample)
+  ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample)
       : sample_(sample),
         frame_iterator_(isolate) {
     ASSERT(sample_ != NULL);
   }
 
-  ProfilerDartStackWalker(Isolate* isolate, Sample* sample, uword fp)
-      : sample_(sample),
-        frame_iterator_(fp, isolate) {
-    ASSERT(sample_ != NULL);
-  }
-
-  int walk() {
+  void walk() {
     intptr_t frame_index = 0;
     StackFrame* frame = frame_iterator_.NextFrame();
     while (frame != NULL) {
@@ -1688,7 +1704,6 @@
       }
       frame = frame_iterator_.NextFrame();
     }
-    return frame_index;
   }
 
  private:
@@ -1697,13 +1712,148 @@
 };
 
 
-// Notes on stack frame walking:
-//
-// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
-// The stack frame walking code uses the frame pointer to traverse the stack.
+// Executing Dart code, walk the stack.
+class ProfilerDartStackWalker : public ValueObject {
+ public:
+  ProfilerDartStackWalker(Isolate* isolate,
+                          Sample* sample,
+                          uword stack_lower,
+                          uword stack_upper,
+                          uword pc,
+                          uword fp,
+                          uword sp)
+      : isolate_(isolate),
+        sample_(sample),
+        stack_upper_(stack_upper),
+        stack_lower_(stack_lower) {
+    ASSERT(sample_ != NULL);
+    pc_ = reinterpret_cast<uword*>(pc);
+    fp_ = reinterpret_cast<uword*>(fp);
+    sp_ = reinterpret_cast<uword*>(sp);
+  }
+
+  void walk() {
+    if (!ValidFramePointer()) {
+      sample_->set_ignore_sample(true);
+      return;
+    }
+    ASSERT(ValidFramePointer());
+    uword return_pc = InitialReturnAddress();
+    if (StubCode::InInvocationStubForIsolate(isolate_, return_pc)) {
+      // Edge case- we have called out from the Invocation Stub but have not
+      // created the stack frame of the callee. Attempt to locate the exit
+      // frame before walking the stack.
+      if (!NextExit() || !ValidFramePointer()) {
+        // Nothing to sample.
+        sample_->set_ignore_sample(true);
+        return;
+      }
+    }
+    for (int i = 0; i < FLAG_profile_depth; i++) {
+      sample_->SetAt(i, reinterpret_cast<uword>(pc_));
+      if (!Next()) {
+        return;
+      }
+    }
+  }
+
+ private:
+  bool Next() {
+    if (!ValidFramePointer()) {
+      return false;
+    }
+    if (StubCode::InInvocationStubForIsolate(isolate_,
+                                             reinterpret_cast<uword>(pc_))) {
+      // In invocation stub.
+      return NextExit();
+    }
+    // In regular Dart frame.
+    uword* new_pc = CallerPC();
+    // Check if we've moved into the invocation stub.
+    if (StubCode::InInvocationStubForIsolate(isolate_,
+                                             reinterpret_cast<uword>(new_pc))) {
+      // New PC is inside invocation stub, skip.
+      return NextExit();
+    }
+    uword* new_fp = CallerFP();
+    if (new_fp <= fp_) {
+      // FP didn't move to a higher address.
+      return false;
+    }
+    // Success, update fp and pc.
+    fp_ = new_fp;
+    pc_ = new_pc;
+    return true;
+  }
+
+  bool NextExit() {
+    if (!ValidFramePointer()) {
+      return false;
+    }
+    uword* new_fp = ExitLink();
+    if (new_fp == NULL) {
+      // No exit link.
+      return false;
+    }
+    if (new_fp <= fp_) {
+      // FP didn't move to a higher address.
+      return false;
+    }
+    if (!ValidFramePointer(new_fp)) {
+      return false;
+    }
+    // Success, update fp and pc.
+    fp_ = new_fp;
+    pc_ = CallerPC();
+    return true;
+  }
+
+  uword InitialReturnAddress() const {
+    ASSERT(sp_ != NULL);
+    return *(sp_);
+  }
+
+  uword* CallerPC() const {
+    ASSERT(fp_ != NULL);
+    return reinterpret_cast<uword*>(*(fp_ + kSavedCallerPcSlotFromFp));
+  }
+
+  uword* CallerFP() const {
+    ASSERT(fp_ != NULL);
+    return reinterpret_cast<uword*>(*(fp_ + kSavedCallerFpSlotFromFp));
+  }
+
+  uword* ExitLink() const {
+    ASSERT(fp_ != NULL);
+    return reinterpret_cast<uword*>(*(fp_ + kExitLinkSlotFromEntryFp));
+  }
+
+  bool ValidFramePointer() const {
+    return ValidFramePointer(fp_);
+  }
+
+  bool ValidFramePointer(uword* fp) const {
+    if (fp == NULL) {
+      return false;
+    }
+    uword cursor = reinterpret_cast<uword>(fp);
+    cursor += sizeof(fp);
+    return (cursor >= stack_lower_) && (cursor < stack_upper_);
+  }
+
+  uword* pc_;
+  uword* fp_;
+  uword* sp_;
+  Isolate* isolate_;
+  Sample* sample_;
+  const uword stack_upper_;
+  uword stack_lower_;
+};
+
+
 // If the VM is compiled without frame pointers (which is the default on
 // recent GCC versions with optimizing enabled) the stack walking code may
-// fail (sometimes leading to a crash).
+// fail.
 //
 class ProfilerNativeStackWalker : public ValueObject {
  public:
@@ -1722,98 +1872,59 @@
     ASSERT(sample_ != NULL);
   }
 
-  int walk(Heap* heap) {
-    const intptr_t kMaxStep = 0x1000;  // 4K.
-    const bool kWalkStack = true;  // Walk the stack.
-    // Always store the exclusive PC.
+  void walk() {
+    const uword kMaxStep = VirtualMemory::PageSize();
+
     sample_->SetAt(0, original_pc_);
-    if (!kWalkStack) {
-      // Not walking the stack, only took exclusive sample.
-      return 1;
-    }
+
     uword* pc = reinterpret_cast<uword*>(original_pc_);
     uword* fp = reinterpret_cast<uword*>(original_fp_);
     uword* previous_fp = fp;
-    if (original_sp_ > original_fp_) {
-      // Stack pointer should not be above frame pointer.
-      return 1;
-    }
-    const intptr_t gap = original_fp_ - original_sp_;
+
+    uword gap = original_fp_ - original_sp_;
     if (gap >= kMaxStep) {
       // Gap between frame pointer and stack pointer is
       // too large.
-      return 1;
+      return;
     }
-    if (original_sp_ < lower_bound_) {
-      // The stack pointer gives us a better lower bound than
-      // the isolates stack limit.
-      lower_bound_ = original_sp_;
+
+    if (!ValidFramePointer(fp)) {
+      return;
     }
-#if defined(TARGET_OS_WINDOWS)
-    // If the original_fp_ is at the beginning of a page, it may be unsafe
-    // to access the pc marker, because we are reading it from a different
-    // thread on Windows. The next page may be a guard page.
-    const intptr_t kPageMask = kMaxStep - 1;
-    bool safe_to_read_pc_marker = (original_fp_ & kPageMask) != 0;
-#else
-    bool safe_to_read_pc_marker = true;
-#endif
-    if (safe_to_read_pc_marker && (gap > 0)) {
-      // Store the PC marker for the top frame.
-      sample_->set_pc_marker(GetCurrentFramePcMarker(fp));
-    }
-    int i = 0;
-    for (; i < FLAG_profile_depth; i++) {
-      if (FLAG_profile_verify_stack_walk) {
-        VerifyCodeAddress(heap, i, reinterpret_cast<uword>(pc));
-      }
+
+    for (int i = 0; i < FLAG_profile_depth; i++) {
       sample_->SetAt(i, reinterpret_cast<uword>(pc));
-      if (fp == NULL) {
-        return i + 1;
-      }
-      if (!ValidFramePointer(fp)) {
-        return i + 1;
-      }
+
       pc = CallerPC(fp);
       previous_fp = fp;
       fp = CallerFP(fp);
-      intptr_t step = fp - previous_fp;
+
       if (fp == NULL) {
-        return i + 1;
+        return;
       }
-      if ((step >= kMaxStep)) {
-        // Frame pointer step is too large.
-        return i + 1;
-      }
-      if ((fp <= previous_fp)) {
+
+      if (fp <= previous_fp) {
         // Frame pointer did not move to a higher address.
-        return i + 1;
+        return;
       }
+
+      gap = fp - previous_fp;
+      if (gap >= kMaxStep) {
+        // Frame pointer step is too large.
+        return;
+      }
+
       if (!ValidFramePointer(fp)) {
-        // Frame pointer is outside of isolate stack bounds.
-        return i + 1;
+        // Frame pointer is outside of isolate stack boundary.
+        return;
       }
+
       // Move the lower bound up.
       lower_bound_ = reinterpret_cast<uword>(fp);
     }
-    return i;
   }
 
  private:
-  void VerifyCodeAddress(Heap* heap, int i, uword pc) {
-    if (heap != NULL) {
-      if (heap->Contains(pc) && !heap->CodeContains(pc)) {
-        for (int j = 0; j < i; j++) {
-          OS::Print("%d %" Px "\n", j, sample_->At(j));
-        }
-        OS::Print("%d %" Px " <--\n", i, pc);
-        OS::Print("---ASSERT-FAILED---\n");
-        OS::Print("%" Px " %" Px "\n", original_pc_, original_fp_);
-        UNREACHABLE();
-      }
-    }
-  }
-
   uword* CallerPC(uword* fp) const {
     ASSERT(fp != NULL);
     return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp));
@@ -1824,20 +1935,13 @@
     return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
   }
 
-  uword GetCurrentFramePcMarker(uword* fp) const {
-    if (!ValidFramePointer(fp)) {
-      return 0;
-    }
-    return *(fp + kPcMarkerSlotFromFp);
-  }
-
   bool ValidFramePointer(uword* fp) const {
     if (fp == NULL) {
       return false;
     }
     uword cursor = reinterpret_cast<uword>(fp);
     cursor += sizeof(fp);
-    bool r = cursor >= lower_bound_ && cursor < stack_upper_;
+    bool r = (cursor >= lower_bound_) && (cursor < stack_upper_);
     return r;
   }
 
@@ -1855,57 +1959,127 @@
     void* data) {
   Isolate* isolate = reinterpret_cast<Isolate*>(data);
   if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) {
+    // No isolate.
     return;
   }
+
   ASSERT(isolate != Dart::vm_isolate());
+
+  IsolateProfilerData* profiler_data = isolate->profiler_data();
+  if (profiler_data == NULL) {
+    // Profiler not initialized.
+    return;
+  }
+
+  SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+  if (sample_buffer == NULL) {
+    // Profiler not initialized.
+    return;
+  }
+
+  if ((state.sp == 0) || (state.fp == 0) || (state.pc == 0)) {
+    // None of these registers should be zero.
+    return;
+  }
+
+  if (state.sp > state.fp) {
+    // Assuming the stack grows down, we should never have a stack pointer above
+    // the frame pointer.
+    return;
+  }
+
   if (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.
     return;
   }
+
+  uword stack_lower = 0;
+  uword stack_upper = 0;
+  isolate->GetStackBounds(&stack_lower, &stack_upper);
+  if ((stack_lower == 0) || (stack_upper == 0)) {
+    // Could not get stack boundary.
+    return;
+  }
+
+  if (state.sp > stack_lower) {
+    // The stack pointer gives us a tighter lower bound.
+    stack_lower = state.sp;
+  }
+
+  if (stack_lower >= stack_upper) {
+    // Stack boundary is invalid.
+    return;
+  }
+
+  if ((state.sp < stack_lower) || (state.sp >= stack_upper)) {
+    // Stack pointer is outside isolate stack boundary.
+    return;
+  }
+
+  if ((state.fp < stack_lower) || (state.fp >= stack_upper)) {
+    // Frame pointer is outside isolate stack boundary.
+    return;
+  }
+
+  // At this point we have a valid stack boundary for this isolate and
+  // know that our initial stack and frame pointers are within the boundary.
+
+  // Increment counter for vm tag.
   VMTagCounters* counters = isolate->vm_tag_counters();
   ASSERT(counters != NULL);
   counters->Increment(isolate->vm_tag());
-  IsolateProfilerData* profiler_data = isolate->profiler_data();
-  if (profiler_data == NULL) {
-    return;
-  }
-  SampleBuffer* sample_buffer = profiler_data->sample_buffer();
-  if (sample_buffer == NULL) {
-    return;
-  }
+
+  // Setup sample.
   Sample* sample = sample_buffer->ReserveSample();
   sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid);
   sample->set_vm_tag(isolate->vm_tag());
   sample->set_user_tag(isolate->user_tag());
   sample->set_sp(state.sp);
   sample->set_fp(state.fp);
+  SetPCMarkerIfSafe(sample);
 
-  uword stack_lower = 0;
-  uword stack_upper = 0;
-  isolate->GetStackBounds(&stack_lower, &stack_upper);
-  if ((stack_lower == 0) || (stack_upper == 0)) {
-    stack_lower = 0;
-    stack_upper = 0;
-  }
+  // Walk the call stack.
   if (FLAG_profile_vm) {
-    // Collect native and Dart frames.
-    ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper,
-                                          state.pc, state.fp, state.sp);
-    stackWalker.walk(isolate->heap());
+    // Always walk the native stack collecting both native and Dart frames.
+    ProfilerNativeStackWalker stackWalker(sample,
+                                          stack_lower,
+                                          stack_upper,
+                                          state.pc,
+                                          state.fp,
+                                          state.sp);
+    stackWalker.walk();
   } else {
+    // Attempt to walk only the Dart call stack, falling back to walking
+    // the native stack.
     if ((isolate->stub_code() != NULL) &&
         (isolate->top_exit_frame_info() != 0) &&
         (isolate->vm_tag() != VMTag::kScriptTagId)) {
       // We have a valid exit frame info, use the Dart stack walker.
-      ProfilerDartStackWalker stackWalker(isolate, sample);
+      ProfilerDartExitStackWalker stackWalker(isolate, sample);
+      stackWalker.walk();
+    } else if ((isolate->stub_code() != NULL) &&
+               (isolate->top_exit_frame_info() == 0) &&
+               (isolate->vm_tag() == VMTag::kScriptTagId)) {
+      // We are executing Dart code. We have frame pointers.
+      ProfilerDartStackWalker stackWalker(isolate,
+                                          sample,
+                                          stack_lower,
+                                          stack_upper,
+                                          state.pc,
+                                          state.fp,
+                                          state.sp);
       stackWalker.walk();
     } else {
-      // Collect native and Dart frames.
-      ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper,
-                                            state.pc, state.fp, state.sp);
-      stackWalker.walk(isolate->heap());
+      // Fall back to an extremely conservative stack walker.
+      ProfilerNativeStackWalker stackWalker(sample,
+                                            stack_lower,
+                                            stack_upper,
+                                            state.pc,
+                                            state.fp,
+                                            state.sp);
+      stackWalker.walk();
     }
   }
 }
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 871d9ec..0f629c6 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -233,6 +233,14 @@
     state_ = LeafFrameIsDart::update(leaf_frame_is_dart, state_);
   }
 
+  bool ignore_sample() const {
+    return IgnoreBit::decode(state_);
+  }
+
+  void set_ignore_sample(bool ignore_sample) {
+    state_ = IgnoreBit::update(ignore_sample, state_);
+  }
+
   static void InitOnce();
 
   static intptr_t instance_size() {
@@ -247,9 +255,11 @@
   enum StateBits {
     kProcessedBit = 0,
     kLeafFrameIsDartBit = 1,
+    kIgnoreBit = 2,
   };
   class ProcessedBit : public BitField<bool, kProcessedBit, 1> {};
   class LeafFrameIsDart : public BitField<bool, kLeafFrameIsDartBit, 1> {};
+  class IgnoreBit : public BitField<bool, kIgnoreBit, 1> {};
 
   int64_t timestamp_;
   ThreadId tid_;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 5d55742..5529293 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -921,11 +921,7 @@
   };
 
   // Compressed version assumes try_index is always -1 and does not store it.
-  class PcDescriptorRec {
-   public:
-    PcDescriptorRec()
-        : pc_(0), deopt_id_and_kind_(0), token_pos_(0), try_index_(0) {}
-
+  struct PcDescriptorRec {
     uword pc() const { return pc_; }
     void set_pc(uword value) { pc_ = value; }
 
@@ -957,14 +953,6 @@
       deopt_id_and_kind_ = (deopt_id_and_kind_ & 0xFF) | (value << 8);
     }
 
-    void CopyTo(PcDescriptorRec* other) const {
-      other->set_pc(pc());
-      other->set_deopt_id(deopt_id());
-      other->set_kind(kind());
-      other->set_token_pos(token_pos(), false);
-      other->set_try_index(try_index());
-    }
-
    private:
     bool is_compressed() const {
       return (token_pos_ & 0x1) == 1;
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 87ce4bc..5b7aee5f 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -442,8 +442,10 @@
     const Error& error = Error::Handle(isolate,
                                        Compiler::Compile(library, script));
     ASSERT(error.IsNull());
+    Dart_Handle result = Dart_FinalizeLoading(false);
+    ASSERT(!Dart_IsError(result));
     Dart_ExitScope();
-    library.SetLoaded();
+
     // Install embedder default library tag handler again.
     isolate->set_library_tag_handler(embedder_provided_handler_);
     embedder_provided_handler_ = NULL;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index f0e3af3..619fee2 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -270,13 +270,11 @@
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (rec.pc() == pc) {
-      return rec.token_pos();
-    } else if ((token_pos <= 0) && (rec.pc() > pc)) {
-      token_pos = rec.token_pos();
+  while (iter.MoveNext()) {
+    if (iter.Pc() == pc) {
+      return iter.TokenPos();
+    } else if ((token_pos <= 0) && (iter.Pc() > pc)) {
+      token_pos = iter.TokenPos();
     }
   }
   return token_pos;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 15086f4..666a853 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1039,7 +1039,7 @@
 
     // Create a test library and Load up a test script in it.
     TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckIsolateState(isolate));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1093,7 +1093,7 @@
 
     // Create a test library and Load up a test script in it.
     Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckIsolateState(isolate));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1214,7 +1214,7 @@
     EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
                                            import_lib,
                                            Dart_Null()));
-    EXPECT_VALID(Api::CheckIsolateState(Isolate::Current()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
 
     // Get list of library URLs loaded and save the count.
     Dart_Handle libs = Dart_GetLibraryIds();
@@ -1384,7 +1384,7 @@
     EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
                                            import_lib,
                                            Dart_Null()));
-    EXPECT_VALID(Api::CheckIsolateState(Isolate::Current()));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
 
     // Write out the script snapshot.
     result = Dart_CreateScriptSnapshot(&buffer, &size);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 9a44f6d..f33e0b4 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -225,12 +225,11 @@
   PcDescriptors& descriptors = reused_pc_descriptors_handle.Handle();
   descriptors = code.pc_descriptors();
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if ((rec.pc() == pc()) && (rec.try_index() != -1)) {
+  while (iter.MoveNext()) {
+    const intptr_t current_try_index = iter.TryIndex();
+    if ((iter.Pc() == pc()) && (current_try_index != -1)) {
       RawExceptionHandlers::HandlerInfo handler_info;
-      handlers.GetHandlerInfo(rec.try_index(), &handler_info);
+      handlers.GetHandlerInfo(current_try_index, &handler_info);
       *handler_pc = handler_info.handler_pc;
       *needs_stacktrace = handler_info.needs_stacktrace;
       *has_catch_all = handler_info.has_catch_all;
@@ -250,11 +249,9 @@
       PcDescriptors::Handle(code.pc_descriptors());
   ASSERT(!descriptors.IsNull());
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
-  while (iter.HasNext()) {
-    RawPcDescriptors::PcDescriptorRec rec;
-    iter.NextRec(&rec);
-    if (rec.pc() == pc()) {
-      return rec.token_pos();
+  while (iter.MoveNext()) {
+    if (iter.Pc() == pc()) {
+      return iter.TokenPos();
     }
   }
   return -1;
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 12f36ea..5c0a2c8 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -112,16 +112,20 @@
 
 Dart_Handle TestCase::LoadTestScript(const char* script,
                                      Dart_NativeEntryResolver resolver,
-                                     const char* lib_url) {
+                                     const char* lib_url,
+                                     bool finalize_classes) {
   Dart_Handle url = NewString(lib_url);
   Dart_Handle source = NewString(script);
   Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler);
   EXPECT_VALID(result);
-  EXPECT_VALID(result);
   Dart_Handle lib = Dart_LoadScript(url, source, 0, 0);
   DART_CHECK_VALID(lib);
   result = Dart_SetNativeResolver(lib, resolver, NULL);
   DART_CHECK_VALID(result);
+  if (finalize_classes) {
+    result = Dart_FinalizeLoading(false);
+    DART_CHECK_VALID(result);
+  }
   return lib;
 }
 
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index cfab41b..f73617a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -245,7 +245,8 @@
 
   static Dart_Handle LoadTestScript(const char* script,
                                     Dart_NativeEntryResolver resolver,
-                                    const char* lib_uri = USER_TEST_URI);
+                                    const char* lib_uri = USER_TEST_URI,
+                                    bool finalize = true);
 
   static Dart_Handle LoadCoreTestScript(const char* script,
                                         Dart_NativeEntryResolver resolver);
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 16713f1..54ad643 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -99,6 +99,8 @@
 
   ClosureClassElement get closureClass => super.enclosingElement;
 
+  MemberElement get memberContext => closureClass.methodElement.memberContext;
+
   bool get hasNode => false;
 
   Node get node {
@@ -123,8 +125,8 @@
   DartType computeType(Compiler compiler) => type;
 
   DartType get type {
-    if (local is TypedElement) {
-      TypedElement element = local;
+    if (local is LocalElement) {
+      LocalElement element = local;
       return element.type;
     }
     return const DynamicType();
@@ -146,15 +148,20 @@
   /// Node that corresponds to this closure, used for source position.
   final FunctionExpression node;
 
+  /**
+   * The element for the declaration of the function expression.
+   */
+  final LocalFunctionElement methodElement;
+
   final List<ClosureFieldElement> _closureFields = <ClosureFieldElement>[];
 
   ClosureClassElement(this.node,
                       String name,
                       Compiler compiler,
-                      this.methodElement,
-                      Element enclosingElement)
-      : super(name,
-              enclosingElement,
+                      LocalFunctionElement closure)
+      : this.methodElement = closure,
+        super(name,
+              closure.compilationUnit,
               // By assigning a fresh class-id we make sure that the hashcode
               // is unique, but also emit closure classes after all other
               // classes (since the emitter sorts classes by their id).
@@ -188,11 +195,6 @@
 
   Node parseNode(DiagnosticListener listener) => node;
 
-  /**
-   * The element for the declaration of the function expression.
-   */
-  final TypedElement methodElement;
-
   // A [ClosureClassElement] is nested inside a function or initializer in terms
   // of [enclosingElement], but still has to be treated as a top-level
   // element.
@@ -207,9 +209,9 @@
 /// fields.
 class BoxLocal extends Local {
   final String name;
-  final Element enclosingElement;
+  final ExecutableElement executableContext;
 
-  BoxLocal(String this.name, Element this.enclosingElement);
+  BoxLocal(this.name, this.executableContext);
 }
 
 // TODO(ngeoffray, ahe): These classes continuously cause problems.  We need to
@@ -220,7 +222,7 @@
 
   BoxFieldElement(String name, this.variableElement, BoxLocal box)
       : this.box = box,
-        super(name, ElementKind.FIELD, box.enclosingElement);
+        super(name, ElementKind.FIELD, box.executableContext);
 
   DartType computeType(Compiler compiler) => type;
 
@@ -233,22 +235,21 @@
 
 /// A local variable used encode the direct (uncaptured) references to [this].
 class ThisLocal extends Local {
-  final Element enclosingElement;
+  final ExecutableElement executableContext;
 
-  ThisLocal(Element enclosingElement)
-      : this.enclosingElement = enclosingElement;
+  ThisLocal(this.executableContext);
 
   String get name => 'this';
 
-  ClassElement get enclosingClass => enclosingElement.enclosingClass;
+  ClassElement get enclosingClass => executableContext.enclosingClass;
 }
 
 /// Call method of a closure class.
 class SynthesizedCallMethodElementX extends BaseFunctionElementX {
-  final FunctionElement expression;
+  final LocalFunctionElement expression;
 
   SynthesizedCallMethodElementX(String name,
-                                BaseFunctionElementX other,
+                                LocalFunctionElementX other,
                                 ClosureClassElement enclosing)
       : expression = other,
         super(name, other.kind, other.modifiers, enclosing, false) {
@@ -261,6 +262,10 @@
 
   ClosureClassElement get closureClass => super.enclosingElement;
 
+  MemberElement get memberContext {
+    return closureClass.methodElement.memberContext;
+  }
+
   bool get hasNode => expression.hasNode;
 
   FunctionExpression get node => expression.node;
@@ -293,7 +298,7 @@
     return _capturedVariableMapping.containsKey(variable);
   }
 
-  void forEachCapturedVariable(f(VariableElement variable,
+  void forEachCapturedVariable(f(LocalVariableElement variable,
                                  BoxFieldElement boxField)) {
     _capturedVariableMapping.forEach(f);
   }
@@ -301,7 +306,7 @@
 
 class ClosureClassMap {
   // The closure's element before any translation. Will be null for methods.
-  final FunctionElement closureElement;
+  final LocalFunctionElement closureElement;
   // The closureClassElement will be null for methods that are not local
   // closures.
   final ClosureClassElement closureClassElement;
@@ -406,7 +411,7 @@
     });
   }
 
-  void forEachBoxedVariable(void f(VariableElement local,
+  void forEachBoxedVariable(void f(LocalVariableElement local,
                                    BoxFieldElement field)) {
     _freeVariableMapping.forEach((variable, copy) {
       if (!isVariableBoxed(variable)) return;
@@ -442,8 +447,8 @@
   // non-mutated variables.
   Set<VariableElement> mutatedVariables = new Set<VariableElement>();
 
-  Element outermostElement;
-  Element currentElement;
+  MemberElement outermostElement;
+  ExecutableElement executableContext;
 
   // The closureData of the currentFunctionElement.
   ClosureClassMap closureData;
@@ -573,9 +578,9 @@
     // optimization: factories have type parameters as function
     // parameters, and type parameters are declared in the class, not
     // the factory.
-    bool inCurrentContext(var variable) {
-      return variable == currentElement ||
-             variable.enclosingElement == currentElement;
+    bool inCurrentContext(Local variable) {
+      return variable == executableContext ||
+             variable.executableContext == executableContext;
     }
 
     if (insideClosure && !inCurrentContext(variable)) {
@@ -592,6 +597,10 @@
     }
   }
 
+  void useTypeVariableAsLocal(TypeVariableType typeVariable) {
+    useLocal(new TypeVariableLocal(typeVariable, outermostElement));
+  }
+
   void declareLocal(Local element) {
     scopeVariables.add(element);
   }
@@ -614,9 +623,9 @@
          !link.isEmpty;
          link = link.tail) {
       Node definition = link.head;
-      VariableElement element = elements[definition];
+      LocalElement element = elements[definition];
       assert(element != null);
-      if (!element.isFieldParameter) {
+      if (!element.isInitializingFormal) {
         declareLocal(element);
       }
       // We still need to visit the right-hand sides of the init-assignments.
@@ -635,7 +644,7 @@
   }
 
   visitTypeAnnotation(TypeAnnotation node) {
-    Element member = currentElement.enclosingMember;
+    Element member = executableContext.enclosingMember;
     DartType type = elements.getType(node);
     // TODO(karlklose,johnniwinther): if the type is null, the annotation is
     // from a parameter which has been analyzed before the method has been
@@ -646,7 +655,9 @@
         // This is a closure in a factory constructor.  Since there is no
         // [:this:], we have to mark the type arguments as free variables to
         // capture them in the closure.
-        type.forEachTypeVariable((variable) => useLocal(variable.element));
+        type.forEachTypeVariable((TypeVariableType variable) {
+          useTypeVariableAsLocal(variable);
+        });
       }
       if (member.isInstanceMember && !member.isField) {
         // In checked mode, using a type variable in a type annotation may lead
@@ -667,7 +678,7 @@
       if (element != null && element.isTypeVariable) {
         if (outermostElement.isConstructor) {
           TypeVariableElement typeVariable = element;
-          useLocal(typeVariable);
+          useTypeVariableAsLocal(typeVariable.type);
         } else {
           registerNeedsThis();
         }
@@ -679,7 +690,7 @@
   visitSend(Send node) {
     Element element = elements[node];
     if (Elements.isLocal(element)) {
-      TypedElement localElement = element;
+      LocalElement localElement = element;
       useLocal(localElement);
     } else if (element != null && element.isTypeVariable) {
       TypeVariableElement variable = element;
@@ -731,7 +742,7 @@
           !outermostElement.isConstructor) {
         registerNeedsThis();
       } else {
-        useLocal(typeVariable.element);
+        useTypeVariableAsLocal(typeVariable);
       }
     });
   }
@@ -739,7 +750,7 @@
   void analyzeType(DartType type) {
     // TODO(johnniwinther): Find out why this can be null.
     if (type == null) return;
-    if (outermostElement.isMember &&
+    if (outermostElement.isClassMember &&
         compiler.backend.classNeedsRti(outermostElement.enclosingClass)) {
       if (outermostElement.isConstructor ||
           outermostElement.isField) {
@@ -758,16 +769,16 @@
   // The boxed variables are updated in the [capturedVariableMapping].
   void attachCapturedScopeVariables(Node node) {
     BoxLocal box = null;
-    Map<VariableElement, BoxFieldElement> scopeMapping =
-        new Map<VariableElement, BoxFieldElement>();
+    Map<LocalVariableElement, BoxFieldElement> scopeMapping =
+        new Map<LocalVariableElement, BoxFieldElement>();
 
-    void boxCapturedVariable(VariableElement variable) {
+    void boxCapturedVariable(LocalVariableElement variable) {
       if (isCapturedVariable(variable)) {
         if (box == null) {
           // TODO(floitsch): construct better box names.
           String boxName =
               namer.getClosureVariableName('box', closureFieldCounter++);
-          box = new BoxLocal(boxName, currentElement);
+          box = new BoxLocal(boxName, executableContext);
         }
         String elementName = variable.name;
         String boxedName =
@@ -821,12 +832,12 @@
     if (definitions == null) return;
     ClosureScope scopeData = closureData.capturingScopes[node];
     if (scopeData == null) return;
-    List<VariableElement> result = <VariableElement>[];
+    List<LocalVariableElement> result = <LocalVariableElement>[];
     for (Link<Node> link = definitions.definitions.nodes;
          !link.isEmpty;
          link = link.tail) {
       Node definition = link.head;
-      VariableElement element = elements[definition];
+      LocalVariableElement element = elements[definition];
       if (isCapturedVariable(element)) {
         result.add(element);
       }
@@ -873,15 +884,15 @@
   }
 
   ClosureClassMap globalizeClosure(FunctionExpression node,
-                                   FunctionElement element) {
+                                   LocalFunctionElement element) {
     String closureName = computeClosureName(element);
     ClosureClassElement globalizedElement = new ClosureClassElement(
-        node, closureName, compiler, element, element.compilationUnit);
+        node, closureName, compiler, element);
     FunctionElement callElement =
         new SynthesizedCallMethodElementX(Compiler.CALL_OPERATOR_NAME,
                                           element,
                                           globalizedElement);
-    ClosureContainer enclosing = element.enclosingElement;
+    MemberElement enclosing = element.memberContext;
     enclosing.nestedClosures.add(callElement);
     globalizedElement.addMember(callElement, compiler);
     globalizedElement.computeAllClassMembers(compiler);
@@ -893,14 +904,16 @@
                                callElement, thisElement);
   }
 
-  void visitInvokable(TypedElement element, Node node, void visitChildren()) {
+  void visitInvokable(ExecutableElement element,
+                      Node node,
+                      void visitChildren()) {
     bool oldInsideClosure = insideClosure;
-    Element oldFunctionElement = currentElement;
+    Element oldFunctionElement = executableContext;
     ClosureClassMap oldClosureData = closureData;
 
     insideClosure = outermostElement != null;
-    FunctionElement closure;
-    currentElement = element;
+    LocalFunctionElement closure;
+    executableContext = element;
     if (insideClosure) {
       closure = element;
       closures.add(node);
@@ -928,13 +941,13 @@
         declareLocal(closure);
       }
 
-      if (currentElement.isFactoryConstructor &&
-          compiler.backend.classNeedsRti(currentElement.enclosingElement)) {
+      if (executableContext.isFactoryConstructor &&
+          compiler.backend.classNeedsRti(executableContext.enclosingElement)) {
         // Declare the type parameters in the scope. Generative
         // constructors just use 'this'.
-        ClassElement cls = currentElement.enclosingElement;
+        ClassElement cls = executableContext.enclosingClass;
         cls.typeVariables.forEach((TypeVariableType typeVariable) {
-          declareLocal(typeVariable.element);
+          declareLocal(new TypeVariableLocal(typeVariable, executableContext));
         });
       }
 
@@ -957,7 +970,7 @@
     // Restore old values.
     insideClosure = oldInsideClosure;
     closureData = oldClosureData;
-    currentElement = oldFunctionElement;
+    executableContext = oldFunctionElement;
 
     // Mark all free variables as captured and use them in the outer function.
     Iterable<Local> freeVariables = savedClosureData.freeVariables;
@@ -989,7 +1002,7 @@
 
   visitFunctionDeclaration(FunctionDeclaration node) {
     node.visitChildren(this);
-    FunctionElement localFunction = elements[node];
+    LocalFunctionElement localFunction = elements[node];
     declareLocal(localFunction);
   }
 
@@ -1001,3 +1014,20 @@
     inTryStatement = oldInTryStatement;
   }
 }
+
+/// A type variable as a local variable.
+class TypeVariableLocal implements Local {
+  final TypeVariableType typeVariable;
+  final ExecutableElement executableContext;
+
+  TypeVariableLocal(this.typeVariable, this.executableContext);
+
+  String get name => typeVariable.name;
+
+  int get hashCode => typeVariable.hashCode;
+
+  bool operator ==(other) {
+    if (other is! TypeVariableLocal) return false;
+    return typeVariable == other.typeVariable;
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 8a21068..52e988e 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -816,9 +816,9 @@
       Node node = parameter.node;
       potentiallyCheckType(node, parameter, argument);
       definitions[parameter] = argument;
-      if (parameter.kind == ElementKind.FIELD_PARAMETER) {
-        FieldParameterElement fieldParameterElement = parameter;
-        updateFieldValue(node, fieldParameterElement.fieldElement, argument);
+      if (parameter.isInitializingFormal) {
+        InitializingFormalElement initializingFormal = parameter;
+        updateFieldValue(node, initializingFormal.fieldElement, argument);
       }
     });
   }
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index a08b609..3b3cdcd 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -391,6 +391,13 @@
         return compiler.patchParser.patchLibrary(loader, patchUri, library);
       }
     }
+    if (library.canUseNative) {
+      library.forEachLocalMember((Element element) {
+        if (element.isClass) {
+          checkNativeAnnotation(compiler, element);
+        }
+      });
+    }
     return new Future.value();
   }
 
@@ -730,6 +737,9 @@
   /// The constant for the [patch] variable defined in dart:_js_helper.
   Constant patchConstant;
 
+  // TODO(johnniwinther): Move this to the JavaScriptBackend.
+  ClassElement nativeAnnotationClass;
+
   // Initialized after symbolClass has been resolved.
   FunctionElement symbolConstructor;
 
@@ -1021,6 +1031,9 @@
     } else if (node is MetadataAnnotation) {
       Uri uri = node.annotatedElement.compilationUnit.script.readableUri;
       return spanFromTokens(node.beginToken, node.endToken, uri);
+    } else if (node is Local) {
+      Local local = node;
+      return spanFromElement(local.executableContext);
     } else {
       throw 'No error location.';
     }
@@ -1126,6 +1139,8 @@
       deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
     } else if (uri == DART_NATIVE_TYPED_DATA) {
       typedDataClass = findRequiredElement(library, 'NativeTypedData');
+    } else if (uri == js_backend.JavaScriptBackend.DART_JS_HELPER) {
+      nativeAnnotationClass = findRequiredElement(library, 'Native');
     }
     return backend.onLibraryScanned(library, loader);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
index af8e95e..0d92855 100644
--- a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes.dart
@@ -133,7 +133,7 @@
 /// Invoke a static function or static field getter/setter.
 class InvokeStatic extends Expression implements Invoke {
   /// [FunctionElement] or [FieldElement].
-  final Element target;
+  final Entity target;
 
   /**
    * The selector encodes how the function is invoked: number of positional
@@ -149,7 +149,7 @@
                List<Definition> args)
       : continuation = new Reference(cont),
         arguments = _referenceList(args) {
-    assert(target.isErroneous || selector.name == target.name);
+    assert(target is ErroneousElement || selector.name == target.name);
   }
 
   accept(Visitor visitor) => visitor.visitInvokeStatic(this);
@@ -546,165 +546,6 @@
   T visitIsTrue(IsTrue node) => visitCondition(node);
 }
 
-/// Generate a Lisp-like S-expression representation of an IR node as a string.
-/// The representation is not pretty-printed, but it can easily be quoted and
-/// dropped into the REPL of one's favorite Lisp or Scheme implementation to be
-/// pretty-printed.
-class SExpressionStringifier extends Visitor<String> {
-  final Map<Definition, String> names = <Definition, String>{};
-
-  int _valueCounter = 0;
-  int _continuationCounter = 0;
-
-  String newValueName() => 'v${_valueCounter++}';
-  String newContinuationName() => 'k${_continuationCounter++}';
-
-  String visitFunctionDefinition(FunctionDefinition node) {
-    names[node.returnContinuation] = 'return';
-    String parameters = node.parameters
-        .map((Parameter p) {
-          String name = p.hint.name;
-          names[p] = name;
-          return name;
-        })
-        .join(' ');
-    return '(FunctionDefinition ($parameters return) ${visit(node.body)})';
-  }
-
-  String visitLetPrim(LetPrim node) {
-    String name = newValueName();
-    names[node.primitive] = name;
-    String value = visit(node.primitive);
-    String body = visit(node.body);
-    return '(LetPrim $name $value) $body';
-  }
-
-  String visitLetCont(LetCont node) {
-    String cont = newContinuationName();
-    names[node.continuation] = cont;
-    String parameters = node.continuation.parameters
-        .map((Parameter p) {
-          String name = newValueName();
-          names[p] = name;
-          return ' $name';
-        })
-       .join('');
-    String contBody = visit(node.continuation.body);
-    String body = visit(node.body);
-    String op = node.continuation.isRecursive ? 'LetCont*' : 'LetCont';
-    return '($op ($cont$parameters) $contBody) $body';
-  }
-
-  String formatArguments(Invoke node) {
-    int positionalArgumentCount = node.selector.positionalArgumentCount;
-    List<String> args = new List<String>();
-    args.addAll(node.arguments.getRange(0, positionalArgumentCount)
-        .map((v) => names[v.definition]));
-    for (int i = 0; i < node.selector.namedArgumentCount; ++i) {
-      String name = node.selector.namedArguments[i];
-      Definition arg = node.arguments[positionalArgumentCount + i].definition;
-      args.add("($name: $arg)");
-    }
-    return args.join(' ');
-  }
-
-  String visitInvokeStatic(InvokeStatic node) {
-    String name = node.target.name;
-    String cont = names[node.continuation.definition];
-    String args = formatArguments(node);
-    return '(InvokeStatic $name $args $cont)';
-  }
-
-  String visitInvokeMethod(InvokeMethod node) {
-    String name = node.selector.name;
-    String rcv = names[node.receiver.definition];
-    String cont = names[node.continuation.definition];
-    String args = formatArguments(node);
-    return '(InvokeMethod $rcv $name $args $cont)';
-  }
-
-  String visitInvokeConstructor(InvokeConstructor node) {
-    String callName;
-    if (node.target.name.isEmpty) {
-      callName = '${node.type}';
-    } else {
-      callName = '${node.type}.${node.target.name}';
-    }
-    String cont = names[node.continuation.definition];
-    String args = formatArguments(node);
-    return '(InvokeConstructor $callName $args $cont)';
-  }
-
-  String visitConcatenateStrings(ConcatenateStrings node) {
-    String cont = names[node.continuation.definition];
-    String args = node.arguments.map((v) => names[v.definition]).join(' ');
-    return '(ConcatenateStrings $args $cont)';
-  }
-
-  String visitInvokeContinuation(InvokeContinuation node) {
-    String cont = names[node.continuation.definition];
-    String args = node.arguments.map((v) => names[v.definition]).join(' ');
-    String op =
-        node.isRecursive ? 'InvokeContinuation*' : 'InvokeContinuation';
-    return '($op $cont $args)';
-  }
-
-  String visitBranch(Branch node) {
-    String condition = visit(node.condition);
-    String trueCont = names[node.trueContinuation.definition];
-    String falseCont = names[node.falseContinuation.definition];
-    return '(Branch $condition $trueCont $falseCont)';
-  }
-
-  String visitConstant(Constant node) {
-    return '(Constant ${node.value})';
-  }
-
-  String visitThis(This node) {
-    return '(This)';
-  }
-
-  String visitReifyTypeVar(ReifyTypeVar node) {
-    return '(ReifyTypeVar ${node.typeVariable.name})';
-  }
-
-  String visitCreateFunction(CreateFunction node) {
-    String function = visit(node.definition);
-    return '(CreateFunction ${node.definition.element} $function)';
-  }
-
-  String visitParameter(Parameter node) {
-    // Parameters are visited directly in visitLetCont.
-    return '(Unexpected Parameter)';
-  }
-
-  String visitContinuation(Continuation node) {
-    // Continuations are visited directly in visitLetCont.
-    return '(Unexpected Continuation)';
-  }
-
-  String visitGetClosureVariable(GetClosureVariable node) {
-    return '(GetClosureVariable ${node.variable.name})';
-  }
-
-  String visitSetClosureVariable(SetClosureVariable node) {
-    String value = names[node.value.definition];
-    String body = visit(node.body);
-    return '(SetClosureVariable ${node.variable.name} $value $body)';
-  }
-
-  String visitDeclareFunction(DeclareFunction node) {
-    String function = visit(node.definition);
-    String body = visit(node.body);
-    return '(DeclareFunction ${node.variable} = $function in $body)';
-  }
-
-  String visitIsTrue(IsTrue node) {
-    String value = names[node.value.definition];
-    return '(IsTrue $value)';
-  }
-}
-
 /// Keeps track of currently unused register indices.
 class RegisterArray {
   int nextIndex = 0;
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart
new file mode 100644
index 0000000..c0af4ae
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.ir_nodes_sexpr;
+
+import 'cps_ir_nodes.dart';
+
+/// Generate a Lisp-like S-expression representation of an IR node as a string.
+/// The representation is not pretty-printed, but it can easily be quoted and
+/// dropped into the REPL of one's favorite Lisp or Scheme implementation to be
+/// pretty-printed.
+class SExpressionStringifier extends Visitor<String> {
+  final Map<Definition, String> names = <Definition, String>{};
+
+  int _valueCounter = 0;
+  int _continuationCounter = 0;
+
+  String newValueName() => 'v${_valueCounter++}';
+  String newContinuationName() => 'k${_continuationCounter++}';
+
+  String visitFunctionDefinition(FunctionDefinition node) {
+    names[node.returnContinuation] = 'return';
+    String parameters = node.parameters
+        .map((Parameter p) {
+          String name = p.hint.name;
+          names[p] = name;
+          return name;
+        })
+        .join(' ');
+    return '(FunctionDefinition ($parameters return) ${visit(node.body)})';
+  }
+
+  String visitLetPrim(LetPrim node) {
+    String name = newValueName();
+    names[node.primitive] = name;
+    String value = visit(node.primitive);
+    String body = visit(node.body);
+    return '(LetPrim $name $value) $body';
+  }
+
+  String visitLetCont(LetCont node) {
+    String cont = newContinuationName();
+    names[node.continuation] = cont;
+    String parameters = node.continuation.parameters
+        .map((Parameter p) {
+          String name = newValueName();
+          names[p] = name;
+          return ' $name';
+        })
+       .join('');
+    String contBody = visit(node.continuation.body);
+    String body = visit(node.body);
+    String op = node.continuation.isRecursive ? 'LetCont*' : 'LetCont';
+    return '($op ($cont$parameters) $contBody) $body';
+  }
+
+  String formatArguments(Invoke node) {
+    int positionalArgumentCount = node.selector.positionalArgumentCount;
+    List<String> args = new List<String>();
+    args.addAll(node.arguments.getRange(0, positionalArgumentCount)
+        .map((v) => names[v.definition]));
+    for (int i = 0; i < node.selector.namedArgumentCount; ++i) {
+      String name = node.selector.namedArguments[i];
+      Definition arg = node.arguments[positionalArgumentCount + i].definition;
+      args.add("($name: $arg)");
+    }
+    return args.join(' ');
+  }
+
+  String visitInvokeStatic(InvokeStatic node) {
+    String name = node.target.name;
+    String cont = names[node.continuation.definition];
+    String args = formatArguments(node);
+    return '(InvokeStatic $name $args $cont)';
+  }
+
+  String visitInvokeMethod(InvokeMethod node) {
+    String name = node.selector.name;
+    String rcv = names[node.receiver.definition];
+    String cont = names[node.continuation.definition];
+    String args = formatArguments(node);
+    return '(InvokeMethod $rcv $name $args $cont)';
+  }
+
+  String visitInvokeSuperMethod(InvokeSuperMethod node) {
+    String name = node.selector.name;
+    String cont = names[node.continuation.definition];
+    String args = formatArguments(node);
+    return '(InvokeSuperMethod $name $args $cont)';
+  }
+
+  String visitInvokeConstructor(InvokeConstructor node) {
+    String callName;
+    if (node.target.name.isEmpty) {
+      callName = '${node.type}';
+    } else {
+      callName = '${node.type}.${node.target.name}';
+    }
+    String cont = names[node.continuation.definition];
+    String args = formatArguments(node);
+    return '(InvokeConstructor $callName $args $cont)';
+  }
+
+  String visitConcatenateStrings(ConcatenateStrings node) {
+    String cont = names[node.continuation.definition];
+    String args = node.arguments.map((v) => names[v.definition]).join(' ');
+    return '(ConcatenateStrings $args $cont)';
+  }
+
+  String visitInvokeContinuation(InvokeContinuation node) {
+    String cont = names[node.continuation.definition];
+    String args = node.arguments.map((v) => names[v.definition]).join(' ');
+    String op =
+        node.isRecursive ? 'InvokeContinuation*' : 'InvokeContinuation';
+    return '($op $cont $args)';
+  }
+
+  String visitBranch(Branch node) {
+    String condition = visit(node.condition);
+    String trueCont = names[node.trueContinuation.definition];
+    String falseCont = names[node.falseContinuation.definition];
+    return '(Branch $condition $trueCont $falseCont)';
+  }
+
+  String visitConstant(Constant node) {
+    return '(Constant ${node.value})';
+  }
+
+  String visitThis(This node) {
+    return '(This)';
+  }
+
+  String visitReifyTypeVar(ReifyTypeVar node) {
+    return '(ReifyTypeVar ${node.typeVariable.name})';
+  }
+
+  String visitCreateFunction(CreateFunction node) {
+    String function = visit(node.definition);
+    return '(CreateFunction ${node.definition.element} $function)';
+  }
+
+  String visitParameter(Parameter node) {
+    // Parameters are visited directly in visitLetCont.
+    return '(Unexpected Parameter)';
+  }
+
+  String visitContinuation(Continuation node) {
+    // Continuations are visited directly in visitLetCont.
+    return '(Unexpected Continuation)';
+  }
+
+  String visitGetClosureVariable(GetClosureVariable node) {
+    return '(GetClosureVariable ${node.variable.name})';
+  }
+
+  String visitSetClosureVariable(SetClosureVariable node) {
+    String value = names[node.value.definition];
+    String body = visit(node.body);
+    return '(SetClosureVariable ${node.variable.name} $value $body)';
+  }
+
+  String visitTypeOperator(TypeOperator node) {
+    String receiver = names[node.receiver.definition];
+    String cont = names[node.continuation.definition];
+    return '(TypeOperator ${node.operator} $receiver ${node.type} $cont)';
+  }
+
+  String visitLiteralList(LiteralList node) {
+    String values = node.values.map((v) => names[v.definition]).join(' ');
+    return '(LiteralList ($values))';
+  }
+
+  String visitLiteralMap(LiteralMap node) {
+    String keys = node.keys.map((v) => names[v.definition]).join(' ');
+    String values = node.values.map((v) => names[v.definition]).join(' ');
+    return '(LiteralMap ($keys) ($values))';
+  }
+
+  String visitDeclareFunction(DeclareFunction node) {
+    String function = visit(node.definition);
+    String body = visit(node.body);
+    return '(DeclareFunction ${node.variable} = $function in $body)';
+  }
+
+  String visitIsTrue(IsTrue node) {
+    String value = names[node.value.definition];
+    return '(IsTrue $value)';
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 9c3c58b..e71cb71 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -205,7 +205,7 @@
       Link<Element> optionalParameters =
           element.functionSignature.optionalParameters;
       for (final optional in optionalParameters) {
-        if (optional.kind != ElementKind.FIELD_PARAMETER) continue;
+        if (!optional.isInitializingFormal) continue;
         fixedMemberNames.add(optional.name);
       }
     }
@@ -303,7 +303,7 @@
       }
       ElementAst elementAst = parse(element);
 
-      if (element.isMember) {
+      if (element.isClassMember) {
         ClassElement enclosingClass = element.enclosingClass;
         assert(enclosingClass.isClass);
         assert(enclosingClass.isTopLevel);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
index 8c18384..c2d2a33 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend_ast_emitter.dart
@@ -284,9 +284,9 @@
 
     // Synthesize an element for the variable
     if (variable.element == null || name != variable.element.name) {
-      variable.element = new modelx.VariableElementX(
+      // TODO(johnniwinther): Replace by synthetic [Entity].
+      variable.element = new modelx.LocalVariableElementX(
           name,
-          ElementKind.VARIABLE,
           functionElement,
           variableList,
           null);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index 9b62291..d7279d5 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -210,7 +210,7 @@
       // just to escape conflicts and that should be enough as we shouldn't
       // be able to resolve private identifiers for other libraries.
       makeElementPlaceholder(node.name, element);
-    } else if (element.isMember) {
+    } else if (element.isClassMember) {
       if (node.name is Identifier) {
         tryMakeMemberPlaceholder(node.name);
       } else {
@@ -407,7 +407,7 @@
         Identifier name = named.name;
         String nameAsString = name.source;
         for (final parameter in optionalParameters) {
-          if (identical(parameter.kind, ElementKind.FIELD_PARAMETER)) {
+          if (parameter.isInitializingFormal) {
             if (parameter.name == nameAsString) {
               tryMakeMemberPlaceholder(name);
               break;
@@ -501,14 +501,14 @@
         // May get FunctionExpression here in definition.selector
         // in case of A(int this.f());
         if (send.selector is Identifier) {
-          if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
+          if (definitionElement.isInitializingFormal) {
             tryMakeMemberPlaceholder(send.selector);
           } else {
             tryMakeLocalPlaceholder(definitionElement, send.selector);
           }
         } else {
           assert(send.selector is FunctionExpression);
-          if (identical(definitionElement.kind, ElementKind.FIELD_PARAMETER)) {
+          if (definitionElement.isInitializingFormal) {
             tryMakeMemberPlaceholder(
                 send.selector.asFunctionExpression().name);
           }
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
index 6096966..27acff6 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/tree_ir_nodes.dart
@@ -122,7 +122,7 @@
  * In contrast to the CPS-based IR, the arguments can be arbitrary expressions.
  */
 class InvokeStatic extends Expression implements Invoke {
-  final Element target;
+  final Entity target;
   final List<Expression> arguments;
   final Selector selector;
 
diff --git a/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
index 688ff66..87cd4ed 100644
--- a/sdk/lib/_internal/compiler/implementation/deferred_load.dart
+++ b/sdk/lib/_internal/compiler/implementation/deferred_load.dart
@@ -31,7 +31,6 @@
     MetadataAnnotation,
     ScopeContainerElement,
     PrefixElement,
-    ClosureContainer,
     VoidElement,
     TypedefElement,
     AstElement;
@@ -281,7 +280,7 @@
 
   /// Returns a [Link] of every [Import] that imports [element] into [library].
   Link<Import> _getImports(Element element, LibraryElement library) {
-    if (element.isMember) {
+    if (element.isClassMember) {
       element = element.enclosingClass;
     }
     if (element.isAccessor) {
diff --git a/sdk/lib/_internal/compiler/implementation/dump_info.dart b/sdk/lib/_internal/compiler/implementation/dump_info.dart
index 7360feb..6efb119 100644
--- a/sdk/lib/_internal/compiler/implementation/dump_info.dart
+++ b/sdk/lib/_internal/compiler/implementation/dump_info.dart
@@ -24,20 +24,6 @@
 import 'js/js.dart' as jsAst;
 import 'compilation_info.dart' show CompilationInformation;
 
-class CodeSizeCounter {
-  final Map<Element, int> generatedSize = new Map<Element, int>();
-
-  int getGeneratedSizeOf(Element element) {
-    int result = generatedSize[element];
-    return result == null ? 0: result;
-  }
-
-  void countCode(Element element, int added) {
-    int before = generatedSize.putIfAbsent(element, () => 0);
-    generatedSize[element] = before + added;
-  }
-}
-
 /// Maps elements to an id.  Supports lookups in
 /// both directions.
 class ElementMapper {
@@ -150,8 +136,7 @@
     String libname = element.getLibraryName();
     libname = libname == "" ? "<unnamed>" : libname;
 
-    int size =
-      compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
+    int size = compiler.dumpInfoTask.sizeOf(element);
 
     LibraryElement contentsOfLibrary = element.isPatched
       ? element.patch : element;
@@ -189,7 +174,7 @@
   Map<String, dynamic> visitFieldElement(FieldElement element) {
     String id = mapper._field.add(element);
     List<String> children = [];
-    CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
+    StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
 
     // If a field has an empty inferred type it is never used.
     TypeMask inferredType =
@@ -203,7 +188,7 @@
 
     if (emittedCode != null) {
       size += emittedCode.length;
-      code = emittedCode.getText();
+      code = emittedCode.toString();
     }
 
     for (Element closure in element.nestedClosures) {
@@ -232,7 +217,7 @@
     String id = mapper._class.add(element);
     List<String> children = [];
 
-    int size = compiler.dumpInfoTask.codeSizeCounter.getGeneratedSizeOf(element);
+    int size = compiler.dumpInfoTask.sizeOf(element);
 
     // Omit element if it is not needed.
     JavaScriptBackend backend = compiler.backend;
@@ -267,8 +252,8 @@
     String sideEffects = null;
     String code = "";
 
-    CodeBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
-    int size = 0;
+    StringBuffer emittedCode = compiler.dumpInfoTask.codeOf(element);
+    int size = compiler.dumpInfoTask.sizeOf(element);
 
     Map<String, dynamic> modifiers = {
       'static': element.isStatic,
@@ -308,15 +293,15 @@
       inferredReturnType = compiler.typesTask
         .getGuaranteedReturnTypeOfElement(element).toString();
       sideEffects = compiler.world.getSideEffectsOfElement(element).toString();
-      code = emittedCode.getText();
-      size += code.length;
+      code = emittedCode.toString();
     }
-
-    for (Element closure in element.nestedClosures) {
-      Map<String, dynamic> child = this.process(closure);
-      if (child != null) {
-        children.add(child['id']);
-        size += child['size'];
+    if (element is MethodElement) {
+      for (Element closure in element.nestedClosures) {
+        Map<String, dynamic> child = this.process(closure);
+        if (child != null) {
+          children.add(child['id']);
+          size += child['size'];
+        }
       }
     }
 
@@ -348,18 +333,104 @@
 
   String name = "Dump Info";
 
-  final CodeSizeCounter codeSizeCounter = new CodeSizeCounter();
-
   ElementToJsonVisitor infoCollector;
 
-  final Map<Element, jsAst.Expression> _generatedCode = {};
+  // A set of javascript AST nodes that we care about the size of.
+  // This set is automatically populated when registerElementAst()
+  // is called.
+  final Set<jsAst.Node> _tracking = new Set<jsAst.Node>();
+  // A mapping from Dart Elements to Javascript AST Nodes.
+  final Map<Element, List<jsAst.Node>> _elementToNodes =
+    <Element, List<jsAst.Node>>{};
+  // A mapping from Javascript AST Nodes to the size of their
+  // pretty-printed contents.
+  final Map<jsAst.Node, int> _nodeToSize = <jsAst.Node, int>{};
+  final Map<jsAst.Node, int> _nodeBeforeSize = <jsAst.Node, int>{};
 
-  void registerGeneratedCode(Element element, jsAst.Expression code) {
-    if (compiler.dumpInfo) {
-      _generatedCode[element] = code;
+  /**
+   * A callback that can be called before a jsAst [node] is
+   * pretty-printed. The size of the code buffer ([aftersize])
+   * is also passed.
+   */
+  void enteringAst(jsAst.Node node, int beforeSize) {
+    if (isTracking(node)) {
+      _nodeBeforeSize[node] = beforeSize;
     }
   }
 
+  /**
+   * A callback that can be called after a jsAst [node] is
+   * pretty-printed. The size of the code buffer ([aftersize])
+   * is also passed.
+   */
+  void exitingAst(jsAst.Node node, int afterSize) {
+    if (isTracking(node)) {
+      int diff = afterSize - _nodeBeforeSize[node];
+      recordAstSize(node, diff);
+    }
+  }
+
+  // Returns true if we care about tracking the size of
+  // this node.
+  bool isTracking(jsAst.Node code) {
+    if (compiler.dumpInfo) {
+      return _tracking.contains(code);
+    } else {
+      return false;
+    }
+  }
+
+  // Registers that a javascript AST node `code` was produced by the
+  // dart Element `element`.
+  void registerElementAst(Element element, jsAst.Node code) {
+    if (compiler.dumpInfo) {
+      _elementToNodes
+        .putIfAbsent(element, () => new List<jsAst.Node>())
+        .add(code);
+      _tracking.add(code);
+    }
+  }
+
+  // Records the size of a dart AST node after it has been
+  // pretty-printed into the output buffer.
+  void recordAstSize(jsAst.Node code, int size) {
+    if (compiler.dumpInfo) {
+      //TODO: should I be incrementing here instead?
+      _nodeToSize[code] = size;
+    }
+  }
+
+  // Returns the size of the source code that
+  // was generated for an element.  If no source
+  // code was produced, return 0.
+  int sizeOf(Element element) {
+    if (_elementToNodes.containsKey(element)) {
+      return _elementToNodes[element]
+        .map(sizeOfNode)
+        .fold(0, (a, b) => a + b);
+    } else {
+        return 0;
+    }
+  }
+
+  int sizeOfNode(jsAst.Node node) {
+    if (_nodeToSize.containsKey(node)) {
+      return _nodeToSize[node];
+    } else {
+      return 0;
+    }
+  }
+
+  StringBuffer codeOf(Element element) {
+    List<jsAst.Node> code = _elementToNodes[element];
+    if (code == null) return null;
+    // Concatenate rendered ASTs.
+    StringBuffer sb = new StringBuffer();
+    for (jsAst.Node ast in code) {
+      sb.writeln(jsAst.prettyPrint(ast, compiler).getText());
+    }
+    return sb;
+  }
 
   void collectInfo() {
     infoCollector = new ElementToJsonVisitor(compiler);
@@ -379,12 +450,6 @@
     });
   }
 
-  CodeBuffer codeOf(Element element) {
-    jsAst.Expression code = _generatedCode[element];
-    return code != null
-      ? jsAst.prettyPrint(code, compiler)
-      : compiler.backend.codeOf(element);
-  }
 
   void dumpInfoJson(StringSink buffer) {
     JsonEncoder encoder = const JsonEncoder();
@@ -418,20 +483,22 @@
       }
     });
 
-    Map<String, dynamic> outJson = {};
-    outJson['elements'] = infoCollector.toJson();
-    outJson['holding'] = holding;
-    outJson['dump_version'] = 1;
+    Map<String, dynamic> outJson = {
+      'elements': infoCollector.toJson(),
+      'holding': holding,
+      'dump_version': 1,
+    };
 
     Duration toJsonDuration = new DateTime.now().difference(startToJsonTime);
 
-    Map<String, dynamic> generalProgramInfo = <String, dynamic>{};
-    generalProgramInfo['size'] = infoCollector.programSize;
-    generalProgramInfo['dart2jsVersion'] = infoCollector.dart2jsVersion;
-    generalProgramInfo['compilationMoment'] = infoCollector.compilationMoment.toString();
-    generalProgramInfo['compilationDuration'] = infoCollector.compilationDuration.toString();
-    generalProgramInfo['toJsonDuration'] = toJsonDuration.toString();
-    generalProgramInfo['dumpInfoDuration'] = infoCollector.dumpInfoDuration.toString();
+    Map<String, dynamic> generalProgramInfo = <String, dynamic> {
+      'size': infoCollector.programSize,
+      'dart2jsVersion': infoCollector.dart2jsVersion,
+      'compilationMoment': infoCollector.compilationMoment.toString(),
+      'compilationDuration': infoCollector.compilationDuration.toString(),
+      'toJsonDuration': toJsonDuration.toString(),
+      'dumpInfoDuration': infoCollector.dumpInfoDuration.toString()
+    };
 
     outJson['program'] = generalProgramInfo;
 
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 9d416c9..8246b93 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -81,8 +81,8 @@
       const ElementKind('parameter', ElementCategory.VARIABLE);
   // Parameters in constructors that directly initialize fields. For example:
   // [:A(this.field):].
-  static const ElementKind FIELD_PARAMETER =
-      const ElementKind('field_parameter', ElementCategory.VARIABLE);
+  static const ElementKind INITIALIZING_FORMAL =
+      const ElementKind('initializing_formal', ElementCategory.VARIABLE);
   static const ElementKind FUNCTION =
       const ElementKind('function', ElementCategory.FUNCTION);
   static const ElementKind CLASS =
@@ -91,8 +91,6 @@
       const ElementKind('generative_constructor', ElementCategory.FACTORY);
   static const ElementKind FIELD =
       const ElementKind('field', ElementCategory.VARIABLE);
-  static const ElementKind VARIABLE_LIST =
-      const ElementKind('variable_list', ElementCategory.NONE);
   static const ElementKind FIELD_LIST =
       const ElementKind('field_list', ElementCategory.NONE);
   static const ElementKind GENERATIVE_CONSTRUCTOR_BODY =
@@ -142,17 +140,6 @@
   String get name;
 }
 
-// TODO(johnniwinther): Should [Local] have `enclosingFunction`, `isAssignable`
-// or `type`?
-/// An entity that defines a local variable (memory slot) in generated code.
-///
-/// Several [Element] can define local variable, for instance parameter, local
-/// variables and local functions and thus implement [Local]. For non-element
-/// locals, like `this` and boxes, specialized [Local] class are created.
-abstract class Local extends Entity {
-
-}
-
 /**
  * A declared element of a program.
  *
@@ -289,12 +276,12 @@
   /// parameter.
   ///
   /// This property is `false` if this element is an initializing formal.
-  /// See [isFieldParameter].
+  /// See [isInitializingFormal].
   bool get isParameter => kind == ElementKind.PARAMETER;
 
   /// `true` if this element is an initializing formal of constructor, that
   /// is a formal of the form `this.foo`.
-  bool get isFieldParameter => kind == ElementKind.FIELD_PARAMETER;
+  bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL;
 
   bool get isStatement;
 
@@ -303,7 +290,13 @@
   bool get isWarnOnUse;
 
   bool get isClosure;
-  bool get isMember;
+
+  /// `true` if the element is a (static or instance) member of a class.
+  /// Members are constructors, methods and fields.
+  bool get isClassMember;
+
+  /// `true` if the element is a nonstatic member of a class.
+  /// Instance members are methods and fields but not constructors.
   bool get isInstanceMember;
 
   /// Returns true if this [Element] is a top level element.
@@ -773,6 +766,7 @@
   }
 }
 
+/// An element representing an erroneous resolution.
 abstract class ErroneousElement extends Element implements ConstructorElement {
   MessageKind get messageKind;
   Map get messageArguments;
@@ -790,6 +784,7 @@
   Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
 }
 
+/// An element representing the ambiguous resolution of a name.
 abstract class AmbiguousElement extends Element {
   MessageKind get messageKind;
   Map get messageArguments;
@@ -805,10 +800,6 @@
   void forEachLocalMember(f(Element element));
 }
 
-abstract class ClosureContainer implements Element {
-  List<FunctionElement> get nestedClosures;
-}
-
 abstract class CompilationUnitElement extends Element {
   Script get script;
   PartOf get partTag;
@@ -896,6 +887,7 @@
   int compareTo(LibraryElement other);
 }
 
+/// The implicit scope defined by a import declaration with a prefix clause.
 abstract class PrefixElement extends Element {
   void addImport(Element element, Import import, DiagnosticListener listener);
   Element lookupLocalMember(String memberName);
@@ -905,25 +897,104 @@
   Import get deferredImport;
 }
 
+/// A type alias definition.
 abstract class TypedefElement extends Element
     implements AstElement, TypeDeclarationElement, FunctionTypedElement {
+
+  /// The type defined by this typedef with the type variables as its type
+  /// arguments.
+  ///
+  /// For instance `F<T>` for `typedef void F<T>(T t)`.
   TypedefType get thisType;
+
+  /// The type defined by this typedef with `dynamic` as its type arguments.
+  ///
+  /// For instance `F<dynamic>` for `typedef void F<T>(T t)`.
   TypedefType get rawType;
+
+  /// The type, function type if well-defined, for which this typedef is an
+  /// alias.
+  ///
+  /// For instance `(int)->void` for `typedef void F(int)`.
   DartType get alias;
 
   void checkCyclicReference(Compiler compiler);
 }
 
-abstract class VariableElement extends Element
+/// An executable element is an element that can hold code.
+///
+/// These elements variables (fields, parameters and locals), which can hold
+/// code in their initializer, and functions (including methods and
+/// constructors), which can hold code in their body.
+abstract class ExecutableElement extends Element
     implements TypedElement, AstElement {
+  /// The outermost member that contains this element.
+  ///
+  /// For top level, static or instance members, the member context is the
+  /// element itself. For parameters, local variables and nested closures, the
+  /// member context is the top level, static or instance member in which it is
+  /// defined.
+  MemberElement get memberContext;
+}
+
+/// A top-level or static field or method, or a constructor.
+///
+/// A [MemberElement] is the outermost executable element for any executable
+/// context.
+abstract class MemberElement extends Element implements ExecutableElement {
+  /// The local functions defined within this member.
+  List<FunctionElement> get nestedClosures;
+}
+
+/// A function, variable or parameter defined in an executable context.
+abstract class LocalElement extends Element implements TypedElement, Local {
+}
+
+/// A top level, static or instance field, a formal parameter or local variable.
+abstract class VariableElement extends ExecutableElement {
   Expression get initializer;
 }
 
-abstract class FieldElement extends VariableElement
-    implements ClosureContainer {}
+/// An entity that defines a local entity (memory slot) in generated code.
+///
+/// Parameters, local variables and local functions (can) define local entity
+/// and thus implement [Local] through [LocalElement]. For
+/// non-element locals, like `this` and boxes, specialized [Local] class are
+/// created.
+///
+/// Type variables can introduce locals in factories and constructors
+/// but since one type variable can introduce different locals in different
+/// factories and constructors it is not itself a [Local] but instead
+/// a non-element [Local] is created through a specialized class.
+// TODO(johnniwinther): Should [Local] have `isAssignable` or `type`?
+abstract class Local extends Entity {
+  /// The context in which this local is defined.
+  ExecutableElement get executableContext;
+}
 
-abstract class ParameterElement extends VariableElement
-    implements FunctionTypedElement {
+/// A variable or parameter that is local to an executable context.
+///
+/// The executable context is the [ExecutableElement] in which this variable
+/// is defined.
+abstract class LocalVariableElement extends VariableElement
+    implements LocalElement {
+}
+
+/// A top-level, static or instance field.
+abstract class FieldElement extends VariableElement implements MemberElement {
+}
+
+/// A parameter-like element of a function signature.
+///
+/// If the function signature comes from a typedef or an inline function-typed
+/// parameter (e.g. the parameter 'f' in `method(void f())`), then its
+/// parameters are not real parameters in that they can take no argument and
+/// hold no value. Such parameter-like elements are modeled by [FormalElement].
+///
+/// If the function signature comes from a function or constructor, its
+/// parameters are real parameters and are modeled by [ParameterElement].
+abstract class FormalElement extends Element
+    implements FunctionTypedElement, TypedElement, AstElement {
   /// Use [functionDeclaration] instead.
   @deprecated
   get enclosingElement;
@@ -935,8 +1006,32 @@
   VariableDefinitions get node;
 }
 
-abstract class FieldParameterElement extends ParameterElement {
-  VariableElement get fieldElement;
+/// A formal parameter of a function or constructor.
+///
+/// Normal parameter that introduce a local variable are modeled by
+/// [LocalParameterElement] whereas initializing formals, that is parameter of
+/// the form `this.x`, are modeled by [InitializingFormalParameter].
+abstract class ParameterElement extends Element
+    implements VariableElement, FormalElement, LocalElement {
+  /// The function on which this parameter is declared.
+  FunctionElement get functionDeclaration;
+}
+
+/// A formal parameter on a function or constructor that introduces a local
+/// variable in the scope of the function or constructor.
+abstract class LocalParameterElement extends ParameterElement
+    implements LocalVariableElement {
+}
+
+/// A formal parameter in a constructor that directly initializes a field.
+///
+/// For example: `A(this.field)`.
+abstract class InitializingFormalElement extends ParameterElement {
+  /// The field initialized by this initializing formal.
+  FieldElement get fieldElement;
+
+  /// The function on which this parameter is declared.
+  ConstructorElement get functionDeclaration;
 }
 
 /**
@@ -953,31 +1048,33 @@
 
 abstract class FunctionSignature {
   FunctionType get type;
-  Link<Element> get requiredParameters;
-  Link<Element> get optionalParameters;
+  Link<FormalElement> get requiredParameters;
+  Link<FormalElement> get optionalParameters;
 
   int get requiredParameterCount;
   int get optionalParameterCount;
   bool get optionalParametersAreNamed;
-  Element get firstOptionalParameter;
+  FormalElement get firstOptionalParameter;
 
   int get parameterCount;
-  List<Element> get orderedOptionalParameters;
+  List<FormalElement> get orderedOptionalParameters;
 
-  void forEachParameter(void function(Element parameter));
-  void forEachRequiredParameter(void function(Element parameter));
-  void forEachOptionalParameter(void function(Element parameter));
+  void forEachParameter(void function(FormalElement parameter));
+  void forEachRequiredParameter(void function(FormalElement parameter));
+  void forEachOptionalParameter(void function(FormalElement parameter));
 
-  void orderedForEachParameter(void function(Element parameter));
+  void orderedForEachParameter(void function(FormalElement parameter));
 
   bool isCompatibleWith(FunctionSignature constructorSignature);
 }
 
+/// A top level, static or instance method, constructor, local function, or
+/// closure (anonymous local function).
 abstract class FunctionElement extends Element
     implements AstElement,
                TypedElement,
                FunctionTypedElement,
-               ClosureContainer {
+               ExecutableElement {
   FunctionExpression get node;
 
   FunctionElement get patch;
@@ -995,7 +1092,19 @@
   @deprecated FunctionSignature computeSignature(Compiler compiler);
 }
 
-abstract class ConstructorElement extends FunctionElement {
+/// A top level, static or instance function.
+abstract class MethodElement extends FunctionElement
+    implements MemberElement {
+}
+
+/// A local function or closure (anonymous local function).
+abstract class LocalFunctionElement extends FunctionElement
+    implements LocalElement {
+}
+
+/// A constructor.
+abstract class ConstructorElement extends FunctionElement
+    implements MemberElement {
   /// The effective target of this constructor, that is the non-redirecting
   /// constructor that is called on invocation of this constructor.
   ///
@@ -1049,14 +1158,14 @@
   get enclosingElement;
 }
 
+/// JavaScript backend specific element for the body of constructor.
+// TODO(johnniwinther): Remove this class for the element model.
 abstract class ConstructorBodyElement extends FunctionElement {
   FunctionElement get constructor;
 }
 
-/**
- * [TypeDeclarationElement] defines the common interface for class/interface
- * declarations and typedefs.
- */
+/// [TypeDeclarationElement] defines the common interface for class/interface
+/// declarations and typedefs.
 abstract class TypeDeclarationElement extends Element implements AstElement {
   /**
    * The `this type` for this type declaration.
@@ -1286,7 +1395,7 @@
 }
 
 /// An [Element] that has a type.
-abstract class TypedElement extends Element implements Local {
+abstract class TypedElement extends Element {
   DartType get type;
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index e388d9d..c4e0708 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -75,7 +75,7 @@
   }
 
   bool get isClosure => false;
-  bool get isMember {
+  bool get isClassMember {
     // Check that this element is defined in the scope of a Class.
     return enclosingElement != null && enclosingElement.isClass;
   }
@@ -200,7 +200,7 @@
    */
   Element get enclosingMember {
     for (Element e = this; e != null; e = e.enclosingElement) {
-      if (e.isMember) return e;
+      if (e.isClassMember) return e;
     }
     return null;
   }
@@ -211,7 +211,7 @@
     // the outermost for elements in closure classses, but some call-sites rely
     // on that behavior.
     for (Element e = this; e != null; e = e.enclosingElement) {
-      if (e.isMember || e.isTopLevel) {
+      if (e.isClassMember || e.isTopLevel) {
         return e;
       }
     }
@@ -328,6 +328,8 @@
   get origin => this;
   get immediateRedirectionTarget => unsupported();
   get nestedClosures => unsupported();
+  get memberContext => unsupported();
+  get executableContext => unsupported();
 
   bool get isRedirectingFactory => unsupported();
 
@@ -1142,7 +1144,7 @@
   DartType computeType(Element element, Compiler compiler) => type;
 }
 
-class VariableElementX extends ElementX with AstElementMixin
+abstract class VariableElementX extends ElementX with AstElementMixin
     implements VariableElement {
   final Token token;
   final VariableList variables;
@@ -1243,7 +1245,7 @@
     return variables.type;
   }
 
-  bool get isInstanceMember => isMember && !isStatic;
+  bool get isInstanceMember => isClassMember && !isStatic;
 
   // Note: cachedNode.beginToken will not be correct in all
   // cases, for example, for function typed parameters.
@@ -1252,14 +1254,19 @@
   accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
 }
 
-class LocalVariableElementX extends VariableElementX {
+class LocalVariableElementX extends VariableElementX
+    implements LocalVariableElement {
   LocalVariableElementX(String name,
-                        Element enclosingElement,
+                        ExecutableElement enclosingElement,
                         VariableList variables,
                         Token token)
       : super(name, ElementKind.VARIABLE, enclosingElement, variables, token) {
     createDefinitions(variables.definitions);
   }
+
+  ExecutableElement get executableContext => enclosingElement;
+
+  ExecutableElement get memberContext => executableContext.memberContext;
 }
 
 class FieldElementX extends VariableElementX
@@ -1273,39 +1280,16 @@
             variables, name.token);
 
   accept(ElementVisitor visitor) => visitor.visitFieldElement(this);
+
+  MemberElement get memberContext => this;
 }
 
-/**
- * Parameters in constructors that directly initialize fields. For example:
- * [:A(this.field):].
- */
-class FieldParameterElementX extends ParameterElementX
-    implements FieldParameterElement {
-  VariableElement fieldElement;
-
-  FieldParameterElementX(Element enclosingElement,
-                         VariableDefinitions variables,
-                         Identifier identifier,
-                         Expression initializer,
-                         this.fieldElement)
-      : super(ElementKind.FIELD_PARAMETER, enclosingElement,
-              variables, identifier, initializer);
-
-  accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
-}
-
-/// [Element] for a formal parameter.
-///
-/// A [ParameterElementX] can be patched. A parameter of an external method is
-/// patched with the corresponding parameter of the patch method. This is done
-/// to ensure that default values on parameters are computed once (on the
-/// origin parameter) but can be found through both the origin and the patch.
-class ParameterElementX extends ElementX
-    with PatchMixin<ParameterElement>, AstElementMixin
-    implements ParameterElement {
+/// [Element] for a parameter-like element.
+class FormalElementX extends ElementX
+    with AstElementMixin
+    implements FormalElement {
   final VariableDefinitions definitions;
   final Identifier identifier;
-  final Expression initializer;
   DartType typeCache;
 
   /**
@@ -1315,11 +1299,10 @@
    */
   FunctionSignature functionSignatureCache;
 
-  ParameterElementX(ElementKind elementKind,
-                    FunctionTypedElement enclosingElement,
-                    this.definitions,
-                    Identifier identifier,
-                    this.initializer)
+  FormalElementX(ElementKind elementKind,
+                 FunctionTypedElement enclosingElement,
+                 this.definitions,
+                 Identifier identifier)
       : this.identifier = identifier,
         super(identifier.source, elementKind, enclosingElement);
 
@@ -1355,12 +1338,68 @@
 
   FunctionType get functionType => type;
 
-  accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
+  accept(ElementVisitor visitor) => visitor.visitFormalElement(this);
 
   // A parameter is defined by the declaration element.
   AstElement get definingElement => declaration;
 }
 
+/// [Element] for a formal parameter.
+///
+/// A [ParameterElementX] can be patched. A parameter of an external method is
+/// patched with the corresponding parameter of the patch method. This is done
+/// to ensure that default values on parameters are computed once (on the
+/// origin parameter) but can be found through both the origin and the patch.
+abstract class ParameterElementX extends FormalElementX
+  with PatchMixin<ParameterElement> implements ParameterElement {
+  final Expression initializer;
+
+  ParameterElementX(ElementKind elementKind,
+                    FunctionElement functionDeclaration,
+                    VariableDefinitions definitions,
+                    Identifier identifier,
+                    this.initializer)
+      : super(elementKind, functionDeclaration, definitions, identifier);
+
+  FunctionElement get functionDeclaration => enclosingElement;
+
+  ExecutableElement get executableContext => enclosingElement;
+
+  MemberElement get memberContext => executableContext.memberContext;
+
+  accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
+}
+
+class LocalParameterElementX extends ParameterElementX
+    implements LocalParameterElement {
+  LocalParameterElementX(FunctionElement functionDeclaration,
+                         VariableDefinitions definitions,
+                         Identifier identifier,
+                         Expression initializer)
+      : super(ElementKind.PARAMETER, functionDeclaration,
+              definitions, identifier, initializer);
+}
+
+/// Parameters in constructors that directly initialize fields. For example:
+/// `A(this.field)`.
+class InitializingFormalElementX extends ParameterElementX
+    implements InitializingFormalElement {
+  FieldElement fieldElement;
+
+  InitializingFormalElementX(ConstructorElement constructorDeclaration,
+                             VariableDefinitions variables,
+                             Identifier identifier,
+                             Expression initializer,
+                             this.fieldElement)
+      : super(ElementKind.INITIALIZING_FORMAL, constructorDeclaration,
+              variables, identifier, initializer);
+
+  accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
+
+  MemberElement get memberContext => enclosingElement;
+}
+
+
 class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
   FunctionElementX getter;
   FunctionElementX setter;
@@ -1408,7 +1447,7 @@
   }
 
   bool get isInstanceMember {
-    return isMember && !isStatic;
+    return isClassMember && !isStatic;
   }
 
   accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);
@@ -1530,7 +1569,7 @@
   }
 
   bool get isInstanceMember {
-    return isMember
+    return isClassMember
            && !isConstructor
            && !isStatic;
   }
@@ -1586,25 +1625,32 @@
 }
 
 abstract class FunctionElementX extends BaseFunctionElementX
-    with AnalyzableElementX {
+    with AnalyzableElementX implements MemberElement {
   FunctionElementX(String name,
                    ElementKind kind,
                    Modifiers modifiers,
                    Element enclosing,
                    bool hasNoBody)
       : super(name, kind, modifiers, enclosing, hasNoBody);
+
+  MemberElement get memberContext => this;
 }
 
-class LocalFunctionElementX extends BaseFunctionElementX {
+class LocalFunctionElementX extends BaseFunctionElementX
+    implements LocalFunctionElement {
   final FunctionExpression node;
 
   LocalFunctionElementX(String name,
                         FunctionExpression this.node,
                         ElementKind kind,
                         Modifiers modifiers,
-                        Element enclosing)
+                        ExecutableElement enclosing)
       : super(name, kind, modifiers, enclosing, false);
 
+  ExecutableElement get executableContext => enclosingElement;
+
+  MemberElement get memberContext => executableContext.memberContext;
+
   bool get hasNode => true;
 
   FunctionExpression parseNode(DiagnosticListener listener) => node;
@@ -1682,7 +1728,7 @@
     return functionSignatureCache;
   }
 
-  bool get isMember => false;
+  bool get isClassMember => false;
 
   bool isForeign(Compiler compiler) => true;
 
@@ -1707,7 +1753,7 @@
 
 class ConstructorBodyElementX extends BaseFunctionElementX
     implements ConstructorBodyElement {
-  FunctionElement constructor;
+  ConstructorElement constructor;
 
   ConstructorBodyElementX(FunctionElement constructor)
       : this.constructor = constructor,
@@ -1736,6 +1782,8 @@
   Element get analyzableElement => constructor.analyzableElement;
 
   accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);
+
+  MemberElement get memberContext => constructor;
 }
 
 /**
@@ -2269,7 +2317,10 @@
   }
 
   bool get isNative => nativeTagInfo != null;
+
   void setNative(String name) {
+    assert(invariant(this, nativeTagInfo == null,
+        message: "Native tag info set twice on $this."));
     nativeTagInfo = name;
   }
 
@@ -2514,6 +2565,9 @@
   String toString() => statement.toString();
 
   accept(ElementVisitor visitor) => visitor.visitTargetElement(this);
+
+  // TODO(johnniwinther): Remove this when [TargetElement] is a non-element.
+  get executableContext => enclosingElement;
 }
 
 class TypeVariableElementX extends ElementX with AstElementMixin
diff --git a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
index 8c632f7..961bc22 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
@@ -23,8 +23,11 @@
   R visitPrefixElement(PrefixElement e) => visitElement(e);
   R visitTypedefElement(TypedefElement e) => visitElement(e);
   R visitVariableElement(VariableElement e) => visitElement(e);
+  R visitParameterElement(ParameterElement e) => visitVariableElement(e);
+  R visitFormalElement(FormalElement e) => visitElement(e);
   R visitFieldElement(FieldElement e) => visitVariableElement(e);
-  R visitFieldParameterElement(FieldParameterElement e) => visitElement(e);
+  R visitFieldParameterElement(InitializingFormalElement e) =>
+      visitParameterElement(e);
   R visitAbstractFieldElement(AbstractFieldElement e) => visitElement(e);
   R visitFunctionElement(FunctionElement e) => visitElement(e);
   R visitConstructorBodyElement(ConstructorBodyElement e) => visitElement(e);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
index e467e29..1909dfb 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/concrete_types_inferrer.dart
@@ -1371,7 +1371,7 @@
   /**
    * Add [reader] to the set of [local]'s readers.
    */
-  void addCapturedLocalReader(VariableElement local, FunctionElement reader) {
+  void addCapturedLocalReader(Local local, FunctionElement reader) {
     capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
                          .add(reader);
   }
@@ -2266,7 +2266,7 @@
       final result = currentWorkItem.environment.lookupType(element);
       if (result != null) return result;
     }
-    if (element.isParameter || element.isFieldParameter) {
+    if (element.isParameter || element.isInitializingFormal) {
       return inferredParameterTypes[element];
     } else if (element.isField) {
       return inferredFieldTypes[element];
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index 938ba14..c427573 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -369,7 +369,7 @@
     }
   }
 
-  void update(TypedElement local, T type, Node node) {
+  void update(LocalElement local, T type, Node node) {
     assert(type != null);
     if (compiler.trustTypeAnnotations || compiler.enableTypeAssertions) {
       type = types.narrowType(type, local.type);
@@ -783,7 +783,7 @@
     } else {
       Element element = elements[node];
       if (Elements.isLocal(element)) {
-        TypedElement local = element;
+        LocalElement local = element;
         return locals.use(local);
       }
       return null;
@@ -803,8 +803,8 @@
   }
 
   void updateIsChecks(List<Node> tests, {bool usePositive}) {
-    void narrow(var element, DartType type, Node node) {
-      if (element is Local) {
+    void narrow(Element element, DartType type, Node node) {
+      if (element is LocalElement) {
         T existing = locals.use(element);
         T newType = types.narrowType(existing, type, isNullable: false);
         locals.update(element, newType, node);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 35be403..12aa1df 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -392,7 +392,7 @@
 
   bool isNativeElement(Element element) {
     if (element.isNative) return true;
-    return element.isMember
+    return element.isClassMember
         && element.enclosingClass.isNative
         && element.isField;
   }
@@ -491,20 +491,21 @@
 
     if (analyzedElement.isGenerativeConstructor) {
       isThisExposed = false;
-      signature.forEachParameter((element) {
+      signature.forEachParameter((ParameterElement element) {
         T parameterType = inferrer.typeOfElement(element);
-        if (element.kind == ElementKind.FIELD_PARAMETER) {
-          if (element.fieldElement.modifiers.isFinal) {
+        if (element.isInitializingFormal) {
+          InitializingFormalElement initializingFormal = element;
+          if (initializingFormal.fieldElement.isFinal) {
             inferrer.recordTypeOfFinalField(
                 node,
                 analyzedElement,
-                element.fieldElement,
+                initializingFormal.fieldElement,
                 parameterType);
           } else {
-            locals.updateField(element.fieldElement, parameterType);
+            locals.updateField(initializingFormal.fieldElement, parameterType);
             inferrer.recordTypeOfNonFinalField(
-                element.parseNode(compiler),
-                element.fieldElement,
+                initializingFormal.node,
+                initializingFormal.fieldElement,
                 parameterType);
           }
         }
@@ -538,8 +539,8 @@
       if (!isConstructorRedirect) {
         // Iterate over all instance fields, and give a null type to
         // fields that we haven't initialized for sure.
-        cls.forEachInstanceField((_, field) {
-          if (field.modifiers.isFinal) return;
+        cls.forEachInstanceField((_, FieldElement field) {
+          if (field.isFinal) return;
           T type = locals.fieldScope.readField(field);
           if (type == null && field.initializer == null) {
             inferrer.recordTypeOfNonFinalField(node, field, types.nullType);
@@ -842,7 +843,7 @@
         handleDynamicSend(node, setterSelector, receiverType,
                           new ArgumentsTypes<T>([newType], null));
       } else if (Elements.isLocal(element)) {
-        TypedElement local = element;
+        LocalElement local = element;
         getterType = locals.use(local);
         newType = handleDynamicSend(
             node, operatorSelector, getterType, operatorArguments);
@@ -1079,7 +1080,7 @@
     } else if (Elements.isErroneousElement(element)) {
       return types.dynamicType;
     } else if (Elements.isLocal(element)) {
-      TypedElement local = element;
+      LocalElement local = element;
       assert(locals.use(local) != null);
       return locals.use(local);
     } else {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 40a747f..e17ce9c 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -251,7 +251,7 @@
   factory ElementTypeInformation(Element element) {
     var assignments = null;
     if (element.enclosingElement.isInstanceMember &&
-        (element.isParameter || element.isFieldParameter)) {
+        (element.isParameter || element.isInitializingFormal)) {
       assignments = new ParameterAssignments();
     }
     return new ElementTypeInformation.internal(element, assignments);
@@ -321,7 +321,7 @@
     }
     if (element.isField ||
         element.isParameter ||
-        element.isFieldParameter) {
+        element.isInitializingFormal) {
       if (!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
         // Do not infer types for fields and parameters being assigned
         // by synthesized calls.
@@ -370,7 +370,7 @@
                                  TypeGraphInferrerEngine inferrer) {
     Compiler compiler = inferrer.compiler;
     // Parameters are being explicitly checked in the method.
-    if (element.isParameter || element.isFieldParameter) return mask;
+    if (element.isParameter || element.isInitializingFormal) return mask;
     if (!compiler.trustTypeAnnotations && !compiler.enableTypeAssertions) {
       return mask;
     }
diff --git a/sdk/lib/_internal/compiler/implementation/js/js.dart b/sdk/lib/_internal/compiler/implementation/js/js.dart
index daf216c..03700c7 100644
--- a/sdk/lib/_internal/compiler/implementation/js/js.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/js.dart
@@ -12,6 +12,8 @@
 // CodeBuffer).
 import '../dart2jslib.dart' as leg;
 
+import '../dump_info.dart';
+
 part 'nodes.dart';
 part 'builder.dart';
 part 'printer.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index 5b9fe43..ecc0be5 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -15,11 +15,15 @@
   final LocalNamer localNamer;
   bool pendingSemicolon = false;
   bool pendingSpace = false;
+  DumpInfoTask monitor = null;
+
   static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]');
   static final expressionContinuationRegExp = new RegExp(r'^[-+([]');
 
-  Printer(leg.Compiler compiler, { allowVariableMinification: true })
+  Printer(leg.Compiler compiler, DumpInfoTask monitor,
+          { allowVariableMinification: true })
       : shouldCompressOutput = compiler.enableMinification,
+        monitor = monitor,
         this.compiler = compiler,
         outBuffer = new leg.CodeBuffer(),
         danglingElseVisitor = new DanglingElseVisitor(compiler),
@@ -122,7 +126,11 @@
 
   visit(Node node) {
     beginSourceRange(node);
+    if (monitor != null) monitor.enteringAst(node, outBuffer.length);
+
     node.accept(this);
+
+    if (monitor != null) monitor.exitingAst(node, outBuffer.length);
     endSourceRange(node);
   }
 
@@ -1026,9 +1034,10 @@
 
 
 leg.CodeBuffer prettyPrint(Node node, leg.Compiler compiler,
-                           { allowVariableMinification: true }) {
+                           {DumpInfoTask monitor,
+                            allowVariableMinification: true}) {
   Printer printer =
-      new Printer(compiler,
+      new Printer(compiler, monitor,
                   allowVariableMinification: allowVariableMinification);
   printer.visit(node);
   return printer.outBuffer;
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index c765845..45b3ada 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -417,7 +417,7 @@
 
   bool usedByBackend(Element element) {
     if (element.isParameter
-        || element.isFieldParameter
+        || element.isInitializingFormal
         || element.isField) {
       if (usedByBackend(element.enclosingElement)) return true;
     }
@@ -425,7 +425,7 @@
   }
 
   bool invokedReflectively(Element element) {
-    if (element.isParameter || element.isFieldParameter) {
+    if (element.isParameter || element.isInitializingFormal) {
       ParameterElement parameter = element;
       if (invokedReflectively(parameter.functionDeclaration)) return true;
     }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index b3228f6..0f8ae3d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -26,6 +26,7 @@
 import '../util/util.dart';
 
 import '../compilation_info.dart';
+import '../dump_info.dart';
 
 part 'backend.dart';
 part 'checked_mode_helpers.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index d8b928a..51167f6 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -627,7 +627,7 @@
       String className = element.enclosingClass.name;
       name = '${className}_${Elements.reconstructConstructorName(element)}';
     } else if (Elements.isStaticOrTopLevel(element)) {
-      if (element.isMember) {
+      if (element.isClassMember) {
         ClassElement enclosingClass = element.enclosingClass;
         name = "${enclosingClass.name}_"
                "${element.name}";
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index d875829..061c781 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -287,10 +287,10 @@
     if (compiler.hasIncrementalSupport) {
       builder = cachedBuilders[classElement];
       if (builder != null) return builder;
-      builder = new ClassBuilder(backend.namer);
+      builder = new ClassBuilder(classElement, backend.namer);
       cachedBuilders[classElement] = builder;
     } else {
-      builder = new ClassBuilder(backend.namer);
+      builder = new ClassBuilder(classElement, backend.namer);
     }
 
     // TODO(sra): Issue #13731- this is commented out as part of custom element
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
index f39b26e..7d96726 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_builder.dart
@@ -15,12 +15,13 @@
   String functionType;
   List<jsAst.Node> fieldMetadata;
 
+  final Element element;
   final Namer namer;
 
   /// Set to true by user if class is indistinguishable from its superclass.
   bool isTrivial = false;
 
-  ClassBuilder(this.namer);
+  ClassBuilder(this.element, this.namer);
 
   // Has the same signature as [DefineStubFunction].
   void addProperty(String name, jsAst.Expression value) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
index a9e66df..c936173 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/class_emitter.dart
@@ -34,7 +34,7 @@
       task.needsMixinSupport = true;
     }
 
-    ClassBuilder builder = new ClassBuilder(namer);
+    ClassBuilder builder = new ClassBuilder(classElement, namer);
     emitClassConstructor(classElement, builder, onlyForRti: onlyForRti);
     emitFields(classElement, builder, superName, onlyForRti: onlyForRti);
     emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti);
@@ -325,9 +325,15 @@
     }
 
     List<jsAst.Property> statics = new List<jsAst.Property>();
-    ClassBuilder staticsBuilder = new ClassBuilder(namer);
+    ClassBuilder staticsBuilder = new ClassBuilder(classElement, namer);
     if (emitFields(classElement, staticsBuilder, null, emitStatics: true)) {
-      statics.add(staticsBuilder.toObjectInitializer().properties.single);
+      jsAst.ObjectInitializer initializer =
+        staticsBuilder.toObjectInitializer();
+      compiler.dumpInfoTask.registerElementAst(classElement,
+        initializer);
+      jsAst.Node property = initializer.properties.single;
+      compiler.dumpInfoTask.registerElementAst(classElement, property);
+      statics.add(property);
     }
 
     Map<OutputUnit, ClassBuilder> classPropertyLists =
@@ -346,7 +352,9 @@
     }
 
     // TODO(ahe): This method (generateClass) should return a jsAst.Expression.
-    enclosingBuilder.addProperty(className, classBuilder.toObjectInitializer());
+    jsAst.ObjectInitializer propertyValue = classBuilder.toObjectInitializer();
+    compiler.dumpInfoTask.registerElementAst(classBuilder.element, propertyValue);
+    enclosingBuilder.addProperty(className, propertyValue);
 
     String reflectionName = task.getReflectionName(classElement, className);
     if (reflectionName != null) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 56b6ce4..97e459c 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -778,7 +778,7 @@
       if (compiler.hasIncrementalSupport) {
         ClassBuilder builder =
             cachedClassBuilders.putIfAbsent(classElement, () {
-              ClassBuilder builder = new ClassBuilder(namer);
+              ClassBuilder builder = new ClassBuilder(classElement, namer);
               classEmitter.generateClass(
                   classElement, builder, additionalProperties[classElement]);
               return builder;
@@ -857,7 +857,7 @@
         backend.generatedCode.keys.where(isStaticFunction);
 
     for (Element element in Elements.sortedByPosition(elements)) {
-      ClassBuilder builder = new ClassBuilder(namer);
+      ClassBuilder builder = new ClassBuilder(element, namer);
       containerBuilder.addMember(element, builder);
       getElementDecriptor(element).properties.addAll(builder.properties);
     }
@@ -878,9 +878,9 @@
           js('$isolateProperties.# = #',
               [namer.getNameOfGlobalField(element),
                constantEmitter.referenceInInitializationContext(initialValue)]);
-        buffer.write(jsAst.prettyPrint(init, compiler));
+        buffer.write(jsAst.prettyPrint(init, compiler,
+                                       monitor: compiler.dumpInfoTask));
         buffer.write('$N');
-        compiler.dumpInfoTask.registerGeneratedCode(element, init);
       });
     }
   }
@@ -911,7 +911,8 @@
                 js.string(namer.getLazyInitializerName(element)),
                 code,
                 getter == null ? [] : [getter]]);
-        buffer.write(jsAst.prettyPrint(init, compiler));
+        buffer.write(jsAst.prettyPrint(init, compiler,
+                                       monitor: compiler.dumpInfoTask));
         buffer.write("$N");
       }
     }
@@ -939,7 +940,7 @@
       jsAst.Expression init = js('#.# = #',
           [namer.globalObjectForConstant(constant), name,
            constantInitializerExpression(constant)]);
-      buffer.write(jsAst.prettyPrint(init, compiler));
+      buffer.write(jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
       buffer.write('$N');
     }
     if (compiler.hasIncrementalSupport && isMainBuffer) {
@@ -992,7 +993,7 @@
                                    }''',
                          [namer.isolateName, makeConstListProperty, initName,
                           initName]),
-            compiler));
+            compiler, monitor: compiler.dumpInfoTask));
     buffer.write(N);
   }
 
@@ -1070,14 +1071,14 @@
     if (backend.needToInitializeIsolateAffinityTag) {
       buffer.write(
           jsAst.prettyPrint(generateIsolateAffinityTagInitialization(),
-                            compiler));
+                            compiler, monitor: compiler.dumpInfoTask));
       buffer.write(N);
     }
     if (backend.needToInitializeDispatchProperty) {
       assert(backend.needToInitializeIsolateAffinityTag);
       buffer.write(
           jsAst.prettyPrint(generateDispatchPropertyNameInitialization(),
-              compiler));
+              compiler, monitor: compiler.dumpInfoTask));
       buffer.write(N);
     }
 
@@ -1118,7 +1119,8 @@
 })$N''', [mainCallClosure, mainCallClosure]);
 
     buffer.write(';');
-    buffer.write(jsAst.prettyPrint(invokeMain, compiler));
+    buffer.write(jsAst.prettyPrint(invokeMain,
+                 compiler, monitor: compiler.dumpInfoTask));
     buffer.write(N);
     addComment('END invoke [main].', buffer);
   }
@@ -1263,7 +1265,8 @@
           buildLazyInitializerFunctionIfNecessary(),
           buildFinishIsolateConstructor()]);
 
-    buffer.write(jsAst.prettyPrint(decl, compiler).getText());
+    buffer.write(jsAst.prettyPrint(decl,
+                 compiler, monitor: compiler.dumpInfoTask).getText());
     if (compiler.enableMinification) buffer.write('\n');
   }
 
@@ -1315,7 +1318,8 @@
 
     for (OutputUnit outputUnit in compiler.deferredLoadTask.allOutputUnits) {
       ClassBuilder descriptor =
-          descriptors.putIfAbsent(outputUnit, () => new ClassBuilder(namer));
+          descriptors.putIfAbsent(outputUnit,
+                                  () => new ClassBuilder(library, namer));
       if (descriptor.properties.isEmpty) continue;
       bool isDeferred =
           outputUnit != compiler.deferredLoadTask.mainOutputUnit;
@@ -1326,19 +1330,23 @@
       CodeBuffer outputBuffer =
           outputBuffers.putIfAbsent(outputUnit, () => new CodeBuffer());
       int sizeBefore = outputBuffer.length;
+      compiler.dumpInfoTask.registerElementAst(library, metadata);
+      compiler.dumpInfoTask.registerElementAst(library, initializers);
       outputBuffers[outputUnit]
           ..write('["$libraryName",$_')
           ..write('"${uri}",$_')
-          ..write(metadata == null ? "" : jsAst.prettyPrint(metadata, compiler))
+          ..write(metadata == null ? "" : jsAst.prettyPrint(metadata,
+                                                compiler,
+                                                monitor: compiler.dumpInfoTask))
           ..write(',$_')
           ..write(namer.globalObjectFor(library))
           ..write(',$_')
-          ..write(jsAst.prettyPrint(initializers, compiler))
+          ..write(jsAst.prettyPrint(initializers,
+                                    compiler,
+                                    monitor: compiler.dumpInfoTask))
           ..write(library == compiler.mainApp ? ',${n}1' : "")
           ..write('],$n');
       int sizeAfter = outputBuffer.length;
-      compiler.dumpInfoTask.codeSizeCounter
-          .countCode(library, sizeAfter - sizeBefore);
     }
   }
 
@@ -1434,12 +1442,16 @@
           // not see libraries that only have fields.
           if (element.isLibrary) {
             LibraryElement library = element;
-            ClassBuilder builder = new ClassBuilder(namer);
+            ClassBuilder builder = new ClassBuilder(library, namer);
             if (classEmitter.emitFields(
                     library, builder, null, emitStatics: true)) {
               OutputUnit mainUnit = compiler.deferredLoadTask.mainOutputUnit;
+              jsAst.ObjectInitializer initializer =
+                builder.toObjectInitializer();
+              compiler.dumpInfoTask.registerElementAst(builder.element,
+                                                       initializer);
               getElementDescriptorForOutputUnit(library, mainUnit)
-                  .properties.addAll(builder.toObjectInitializer().properties);
+                  .properties.addAll(initializer.properties);
             }
           }
         }
@@ -1455,7 +1467,9 @@
           var map = new jsAst.ObjectInitializer(properties);
           mainBuffer.write(
               jsAst.prettyPrint(
-                  js.statement('init.mangledNames = #', map), compiler));
+                  js.statement('init.mangledNames = #', map),
+                  compiler,
+                  monitor: compiler.dumpInfoTask));
           if (compiler.enableMinification) {
             mainBuffer.write(';');
           }
@@ -1472,7 +1486,8 @@
           mainBuffer.write(
               jsAst.prettyPrint(
                   js.statement('init.mangledGlobalNames = #', map),
-                  compiler));
+                  compiler,
+                  monitor: compiler.dumpInfoTask));
           if (compiler.enableMinification) {
             mainBuffer.write(';');
           }
@@ -1624,6 +1639,7 @@
         mainBuffer.write(
             jsAst.prettyPrint(
                 precompiledFunctionAst, compiler,
+                monitor: compiler.dumpInfoTask,
                 allowVariableMinification: false).getText());
       }
 
@@ -1693,7 +1709,7 @@
         elementDescriptors.putIfAbsent(
             element, () => new Map<OutputUnit, ClassBuilder>());
     return descriptors.putIfAbsent(outputUnit,
-        () => new ClassBuilder(namer));
+        () => new ClassBuilder(element, namer));
   }
 
   ClassBuilder getElementDecriptor(Element element) {
@@ -1741,7 +1757,7 @@
         ..write(
             jsAst.prettyPrint(
                 getReflectionDataParser(classesCollector, backend),
-                compiler))
+                compiler, monitor: compiler.dumpInfoTask))
         ..write(')')
         ..write('([$n')
         ..addBuffer(outputBuffer)
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
index 1049944..c4142ce 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/container_builder.dart
@@ -305,7 +305,9 @@
             'function(#) { return #.#(#); }',
             [ parameters, buildGetter(), closureCallName, arguments]);
 
+        compiler.dumpInfoTask.registerElementAst(member, function);
         addProperty(invocationName, function);
+
       }
     }
   }
@@ -386,11 +388,13 @@
         canTearOff || canBeReflected || canBeApplied;
     if (!needStructuredInfo) {
       builder.addProperty(name, code);
+      compiler.dumpInfoTask.registerElementAst(member, code);
       if (needsStubs) {
         addParameterStubs(
             member,
             (Selector selector, jsAst.Fun function) {
               builder.addProperty(namer.invocationName(selector), function);
+              compiler.dumpInfoTask.registerElementAst(member, function);
             });
       }
       return;
@@ -539,7 +543,10 @@
     } else if (isClosure && canBeApplied) {
       expressions.add(js.string(member.name));
     }
-    builder.addProperty(name, new jsAst.ArrayInitializer.from(expressions));
+    jsAst.ArrayInitializer arrayInit =
+      new jsAst.ArrayInitializer.from(expressions);
+    builder.addProperty(name, arrayInit);
+    compiler.dumpInfoTask.registerElementAst(member, arrayInit);
   }
 
   void addMemberField(VariableElement member, ClassBuilder builder) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index cd51594..3ec8830 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -60,10 +60,10 @@
       ClosureClassMap closureData =
           compiler.closureToClassMapper.closureMappingCache[node];
       if (closureData != null) {
-        ClosureFieldElement thisElement =
+        ClosureFieldElement thisLocal =
             closureData.getFreeVariableElement(closureData.thisLocal);
-        if (thisElement != null) {
-          String thisName = namer.instanceFieldPropertyName(thisElement);
+        if (thisLocal != null) {
+          String thisName = namer.instanceFieldPropertyName(thisLocal);
           thisAccess = js('this.#', thisName);
         }
       }
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
index 2a3bcc1..7f3899a 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
@@ -166,25 +166,26 @@
   final bool isNamed;
 
   factory Dart2JsParameterMirror(Dart2JsDeclarationMirror owner,
-                                 ParameterElement element,
+                                 FormalElement element,
                                  {bool isOptional: false,
                                   bool isNamed: false}) {
-    if (element is FieldParameterElement) {
+    if (element is InitializingFormalElement) {
       return new Dart2JsFieldParameterMirror(
           owner, element, isOptional, isNamed);
+    } else {
+      return new Dart2JsParameterMirror._normal(
+          owner, element, isOptional, isNamed);
     }
-    return new Dart2JsParameterMirror._normal(
-        owner, element, isOptional, isNamed);
   }
 
   Dart2JsParameterMirror._normal(Dart2JsDeclarationMirror owner,
-                                 ParameterElement element,
+                                 FormalElement element,
                                  this.isOptional,
                                  this.isNamed)
     : this.owner = owner,
       super(owner.mirrorSystem, element);
 
-  ParameterElement get _element => super._element;
+  FormalElement get _element => super._element;
 
   TypeMirror get type => owner._getTypeMirror(_element.type);
 
@@ -196,18 +197,23 @@
     if (hasDefaultValue) {
       // TODO(johnniwinther): Get the constant from the [TreeElements]
       // associated with the enclosing method.
+      ParameterElement parameter = _element;
       Constant constant = mirrorSystem.compiler.constants
-          .getConstantForVariable(_element);
-      assert(invariant(_element, constant != null,
+          .getConstantForVariable(parameter);
+      assert(invariant(parameter, constant != null,
           message: "Missing constant for parameter "
-                   "$_element with default value."));
+                   "$parameter with default value."));
       return _convertConstantToInstanceMirror(mirrorSystem, constant);
     }
     return null;
   }
 
   bool get hasDefaultValue {
-    return _element.initializer != null;
+    if (_element is ParameterElement) {
+      ParameterElement parameter = _element;
+      return parameter.initializer != null;
+    }
+    return false;
   }
 
   bool get isInitializingFormal => false;
@@ -218,12 +224,12 @@
 class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {
 
   Dart2JsFieldParameterMirror(Dart2JsDeclarationMirror method,
-                              FieldParameterElement element,
+                              InitializingFormalElement element,
                               bool isOptional,
                               bool isNamed)
       : super._normal(method, element, isOptional, isNamed);
 
-  FieldParameterElement get _fieldParameterElement => _element;
+  InitializingFormalElement get _fieldParameterElement => _element;
 
   bool get isInitializingFormal => true;
 
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
index c7dab3d..c3851f0 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
@@ -491,8 +491,9 @@
 
   static ResolvedNode defaultValueSyntaxOf(Dart2JsParameterMirror parameter) {
     if (!parameter.hasDefaultValue) return null;
-    var node = parameter._element.initializer;
-    var treeElements = parameter._element.treeElements;
+    ParameterElement parameterElement = parameter._element;
+    var node = parameterElement.initializer;
+    var treeElements = parameterElement.treeElements;
     return new ResolvedNode(node, treeElements, parameter.mirrorSystem);
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 8e84eb7..5fd785e 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -786,6 +786,110 @@
 
   static NativeBehavior NONE = new NativeBehavior();
 
+  /// Processes the type specification string of a call to JS and stores the
+  /// result in the [typesReturned] and [typesInstantiated].
+  ///
+  /// Two forms of the string is supported:
+  /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
+  ///    which defines the types returned and for the later form also created by
+  ///    the call to JS.
+  /// 2) A sequence of the form '<tag>:<type-string>;' where <tag> is either
+  ///    'returns' or 'creates' and where <type-string> is a type string like in
+  ///    1). The type string marked by 'returns' defines the types returned and
+  ///    'creates' defines the types created by the call to JS. Each tag kind
+  ///    can only occur once in the sequence.
+  ///
+  /// [specString] is the specification string, [resolveType] resolves named
+  /// types into type values, [typesReturned] and [typesInstantiated] collects
+  /// the types defined by the specification string, and [objectType] and
+  /// [nullType] define the types for `Object` and `Null`, respectively. The
+  /// latter is used for the type strings of the form '' and 'var'.
+  // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
+  static void processSpecString(
+      DiagnosticListener listener,
+      Spannable spannable,
+      String specString,
+      {dynamic resolveType(String typeString),
+       List typesReturned, List typesInstantiated,
+       objectType, nullType}) {
+
+    /// Resolve a type string of one of the three forms:
+    /// *  'void' - in which case [onVoid] is called,
+    /// *  '' or 'var' - in which case [onVar] is called,
+    /// *  'T1|...|Tn' - in which case [onType] is called for each Ti.
+    void resolveTypesString(String typesString,
+                            {onVoid(), onVar(), onType(type)}) {
+      // Various things that are not in fact types.
+      if (typesString == 'void') {
+        if (onVoid != null) {
+          onVoid();
+        }
+        return;
+      }
+      if (typesString == '' || typesString == 'var') {
+        if (onVar != null) {
+          onVar();
+        }
+        return;
+      }
+      for (final typeString in typesString.split('|')) {
+        onType(resolveType(typeString));
+      }
+    }
+
+    if (specString.contains(':')) {
+      /// Find and remove a substring of the form 'tag:<type-string>;' from
+      /// [specString].
+      String getTypesString(String tag) {
+        String marker = '$tag:';
+        int startPos = specString.indexOf(marker);
+        if (startPos == -1) return null;
+        int endPos = specString.indexOf(';', startPos);
+        if (endPos == -1) return null;
+        String typeString =
+            specString.substring(startPos + marker.length, endPos);
+        specString = '${specString.substring(0, startPos)}'
+                     '${specString.substring(endPos + 1)}'.trim();
+        return typeString;
+      }
+
+      String returns = getTypesString('returns');
+      if (returns != null) {
+        resolveTypesString(returns, onVar: () {
+          typesReturned.add(objectType);
+          typesReturned.add(nullType);
+        }, onType: (type) {
+          typesReturned.add(type);
+        });
+      }
+
+      String creates = getTypesString('creates');
+      if (creates != null) {
+        resolveTypesString(creates, onVoid: () {
+          listener.internalError(spannable,
+              "Invalid type string 'creates:$creates'");
+        }, onVar: () {
+          listener.internalError(spannable,
+              "Invalid type string 'creates:$creates'");
+        }, onType: (type) {
+          typesInstantiated.add(type);
+        });
+      }
+
+      if (!specString.isEmpty) {
+        listener.internalError(spannable, "Invalid JS type string.");
+      }
+    } else {
+      resolveTypesString(specString, onVar: () {
+        typesReturned.add(objectType);
+        typesReturned.add(nullType);
+      }, onType: (type) {
+        typesInstantiated.add(type);
+        typesReturned.add(type);
+      });
+    }
+  }
+
   static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
     // The first argument of a JS-call is a string encoding various attributes
     // of the code.
@@ -810,26 +914,30 @@
       compiler.internalError(argNodes.head, "Unexpected JS first argument.");
     }
 
-    var behavior = new NativeBehavior();
-    behavior.codeTemplate = js.js.parseForeignJS(code.dartString.slowToString());
-    new SideEffectsVisitor(behavior.sideEffects).visit(behavior.codeTemplate.ast);
+    NativeBehavior behavior = new NativeBehavior();
+    behavior.codeTemplate =
+        js.js.parseForeignJS(code.dartString.slowToString());
+    new SideEffectsVisitor(behavior.sideEffects)
+        .visit(behavior.codeTemplate.ast);
 
     String specString = specLiteral.dartString.slowToString();
-    // Various things that are not in fact types.
-    if (specString == 'void') return behavior;
-    if (specString == '' || specString == 'var') {
-      behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
-      behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
-      return behavior;
-    }
-    for (final typeString in specString.split('|')) {
-      var type = _parseType(typeString, compiler,
+
+    resolveType(String typeString) {
+      return _parseType(
+          typeString,
+          compiler,
           (name) => resolver.resolveTypeFromString(specLiteral, name),
           jsCall);
-      behavior.typesInstantiated.add(type);
-      behavior.typesReturned.add(type);
     }
 
+    processSpecString(compiler, jsCall,
+                      specString,
+                      resolveType: resolveType,
+                      typesReturned: behavior.typesReturned,
+                      typesInstantiated: behavior.typesInstantiated,
+                      objectType: compiler.objectClass.computeType(compiler),
+                      nullType: compiler.nullClass.computeType(compiler));
+
     return behavior;
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 541091c..22c2d9d 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -230,11 +230,11 @@
   }
 }
 
-void patchElement(leg.DiagnosticListener listener,
+void patchElement(leg.Compiler compiler,
                   Element origin,
                   Element patch) {
   if (origin == null) {
-    listener.reportError(
+    compiler.reportError(
         patch, leg.MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
     return;
   }
@@ -243,48 +243,168 @@
         origin.isFunction ||
         origin.isAbstractField)) {
     // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
-    listener.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
+    compiler.reportError(origin, leg.MessageKind.PATCH_NONPATCHABLE);
     return;
   }
   if (patch.isClass) {
-    tryPatchClass(listener, origin, patch);
+    tryPatchClass(compiler, origin, patch);
   } else if (patch.isGetter) {
-    tryPatchGetter(listener, origin, patch);
+    tryPatchGetter(compiler, origin, patch);
   } else if (patch.isSetter) {
-    tryPatchSetter(listener, origin, patch);
+    tryPatchSetter(compiler, origin, patch);
   } else if (patch.isConstructor) {
-    tryPatchConstructor(listener, origin, patch);
+    tryPatchConstructor(compiler, origin, patch);
   } else if(patch.isFunction) {
-    tryPatchFunction(listener, origin, patch);
+    tryPatchFunction(compiler, origin, patch);
   } else {
     // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
-    listener.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
+    compiler.reportError(patch, leg.MessageKind.PATCH_NONPATCHABLE);
   }
 }
 
-void tryPatchClass(leg.DiagnosticListener listener,
-                    Element origin,
-                    ClassElement patch) {
+void tryPatchClass(leg.Compiler compiler,
+                   Element origin,
+                   ClassElement patch) {
   if (!origin.isClass) {
-    listener.reportError(
+    compiler.reportError(
         origin, leg.MessageKind.PATCH_NON_CLASS, {'className': patch.name});
-    listener.reportInfo(
+    compiler.reportInfo(
         patch, leg.MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name});
     return;
   }
-  patchClass(listener, origin, patch);
+  patchClass(compiler, origin, patch);
 }
 
-void patchClass(leg.DiagnosticListener listener,
+void patchClass(leg.Compiler compiler,
                 ClassElementX origin,
                 ClassElementX patch) {
   if (origin.isPatched) {
-    listener.internalError(origin,
+    compiler.internalError(origin,
         "Patching the same class more than once.");
   }
   origin.applyPatch(patch);
+  checkNativeAnnotation(compiler, patch);
 }
 
+/// Check whether [cls] has a `@Native(...)` annotation, and if so, set its
+/// native name from the annotation.
+checkNativeAnnotation(leg.Compiler compiler, ClassElement cls) {
+  EagerAnnotationHandler.checkAnnotation(compiler, cls,
+      const NativeAnnotationHandler());
+}
+
+/// Abstract interface for pre-resolution detection of metadata.
+///
+/// The detection is handled in two steps:
+/// - match the annotation syntactically and assume that the annotation is valid
+///   if it looks correct,
+/// - setup a deferred action to check that the annotation has a valid constant
+///   value and report an internal error if not.
+abstract class EagerAnnotationHandler {
+  /// Checks that [annotation] looks like a matching annotation and optionally
+  /// applies actions on [element]. Returns `true` if the annotation matched.
+  bool apply(leg.Compiler compiler,
+             Element element,
+             MetadataAnnotation annotation);
+
+  /// Checks that the annotation value is valid.
+  void validate(leg.Compiler compiler,
+                Element element,
+                MetadataAnnotation annotation,
+                leg.Constant constant);
+
+
+  /// Checks [element] for metadata matching the [handler]. Return `true` if
+  /// matching metadata was found.
+  static bool checkAnnotation(leg.Compiler compiler,
+                              Element element,
+                              EagerAnnotationHandler handler) {
+    for (Link<MetadataAnnotation> link = element.metadata;
+         !link.isEmpty;
+         link = link.tail) {
+      MetadataAnnotation annotation = link.head;
+      if (handler.apply(compiler, element, annotation)) {
+        // TODO(johnniwinther): Perform this check in
+        // [Compiler.onLibrariesLoaded].
+        compiler.enqueuer.resolution.addDeferredAction(element, () {
+          annotation.ensureResolved(compiler);
+          handler.validate(compiler, element, annotation, annotation.value);
+        });
+        return true;
+      }
+    }
+    return false;
+  }
+}
+
+/// Annotation handler for pre-resolution detection of `@Native(...)`
+/// annotations.
+class NativeAnnotationHandler implements EagerAnnotationHandler {
+  const NativeAnnotationHandler();
+
+  String getNativeAnnotation(MetadataAnnotation annotation) {
+    if (annotation.beginToken != null &&
+        annotation.beginToken.next.value == 'Native') {
+      // Skipping '@', 'Native', and '('.
+      Token argument = annotation.beginToken.next.next.next;
+      if (argument is StringToken) {
+        return argument.value;
+      }
+    }
+    return null;
+  }
+
+  bool apply(leg.Compiler compiler,
+             Element element,
+             MetadataAnnotation annotation) {
+    if (element.isClass) {
+      String native = getNativeAnnotation(annotation);
+      if (native != null) {
+        ClassElementX declaration = element.declaration;
+        declaration.setNative(native);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void validate(leg.Compiler compiler,
+                Element element,
+                MetadataAnnotation annotation,
+                leg.Constant constant) {
+    if (constant.computeType(compiler).element !=
+            compiler.nativeAnnotationClass) {
+      compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
+    }
+  }
+}
+
+/// Annotation handler for pre-resolution detection of `@patch` annotations.
+class PatchAnnotationHandler implements EagerAnnotationHandler {
+  const PatchAnnotationHandler();
+
+  bool isPatchAnnotation(MetadataAnnotation annotation) {
+    return annotation.beginToken != null &&
+           annotation.beginToken.next.value == 'patch';
+  }
+
+  bool apply(leg.Compiler compiler,
+             Element element,
+             MetadataAnnotation annotation) {
+    return isPatchAnnotation(annotation);
+  }
+
+  void validate(leg.Compiler compiler,
+                Element element,
+                MetadataAnnotation annotation,
+                leg.Constant constant) {
+    if (constant != compiler.patchConstant) {
+      compiler.internalError(annotation, 'Invalid patch annotation.');
+    }
+  }
+}
+
+
 void tryPatchGetter(leg.DiagnosticListener listener,
                     Element origin,
                     FunctionElement patch) {
@@ -381,24 +501,6 @@
 
 // TODO(johnniwinther): Add unittest when patch is (real) metadata.
 bool isPatchElement(leg.Compiler compiler, Element element) {
-  // TODO(lrn): More checks needed if we introduce metadata for real.
-  // In that case, it must have the identifier "native" as metadata.
-  for (Link<MetadataAnnotation> link = element.metadata;
-       !link.isEmpty;
-       link = link.tail) {
-    MetadataAnnotation annotation = link.head;
-    if (annotation.beginToken != null &&
-        annotation.beginToken.next.value == 'patch') {
-      // TODO(johnniwinther): Perform this check in
-      // [Compiler.onLibrariesLoaded].
-      compiler.enqueuer.resolution.addDeferredAction(element, () {
-        annotation.ensureResolved(compiler);
-        if (annotation.value != compiler.patchConstant) {
-          compiler.internalError(annotation, 'Invalid patch annotation.');
-        }
-      });
-      return true;
-    }
-  }
-  return false;
+  return EagerAnnotationHandler.checkAnnotation(compiler, element,
+      const PatchAnnotationHandler());
 }
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 5a4654b..0061fd7 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1183,7 +1183,8 @@
       return measure(() => SignatureResolver.analyze(
           compiler, node.parameters, node.returnType, element,
           new ResolutionRegistry(compiler, element),
-          defaultValuesError: defaultValuesError));
+          defaultValuesError: defaultValuesError,
+          createRealParameters: true));
     });
   }
 
@@ -1293,13 +1294,13 @@
         MessageKind.ALREADY_INITIALIZED, {'fieldName': field.name});
   }
 
-  void checkForDuplicateInitializers(VariableElementX field, Node init) {
+  void checkForDuplicateInitializers(FieldElementX field, Node init) {
     // [field] can be null if it could not be resolved.
     if (field == null) return;
     String name = field.name;
     if (initialized.containsKey(field)) {
       reportDuplicateInitializerError(field, init, initialized[field]);
-    } else if (field.modifiers.isFinal) {
+    } else if (field.isFinal) {
       field.parseNode(visitor.compiler);
       Expression initializer = field.initializer;
       if (initializer != null) {
@@ -1463,9 +1464,9 @@
     // that we can ensure that fields are initialized only once.
     FunctionSignature functionParameters = constructor.functionSignature;
     functionParameters.forEachParameter((ParameterElement element) {
-      if (identical(element.kind, ElementKind.FIELD_PARAMETER)) {
-        FieldParameterElement fieldParameter = element;
-        checkForDuplicateInitializers(fieldParameter.fieldElement,
+      if (element.isInitializingFormal) {
+        InitializingFormalElement initializingFormal = element;
+        checkForDuplicateInitializers(initializingFormal.fieldElement,
                                       element.initializer);
       }
     });
@@ -1508,7 +1509,7 @@
           Compiler compiler = visitor.compiler;
           FunctionSignature signature = constructor.functionSignature;
           signature.forEachParameter((ParameterElement parameter) {
-            if (parameter.isFieldParameter) {
+            if (parameter.isInitializingFormal) {
               Node node = parameter.node;
               error(node, MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED);
             }
@@ -2032,7 +2033,7 @@
       // fields.
       inInstanceContext = (element.isInstanceMember && !element.isField)
           || element.isGenerativeConstructor,
-      this.currentClass = element.isMember ? element.enclosingClass
+      this.currentClass = element.isClassMember ? element.enclosingClass
                                              : null,
       this.statementScope = new StatementScope(),
       scope = useEnclosingScope
@@ -2222,7 +2223,7 @@
       Node parameterNode = variableDefinitions.definitions.nodes.head;
       // Field parameters (this.x) are not visible inside the constructor. The
       // fields they reference are visible, but must be resolved independently.
-      if (element.kind == ElementKind.FIELD_PARAMETER) {
+      if (element.isInitializingFormal) {
         registry.useElement(parameterNode, element);
       } else {
         defineElement(parameterNode, element);
@@ -2323,7 +2324,7 @@
         enclosingElement);
     function.functionSignatureCache =
         SignatureResolver.analyze(compiler, node.parameters, node.returnType,
-            function, registry);
+            function, registry, createRealParameters: true);
     Scope oldScope = scope; // The scope is modified by [setupFunction].
     setupFunction(node, function);
     defineElement(node, function, doAddToScope: node.name != null);
@@ -3854,7 +3855,7 @@
     element.functionSignature = signature;
 
     scope = new MethodScope(scope, element);
-    signature.forEachParameter((ParameterElement element) {
+    signature.forEachParameter((FormalElement element) {
       defineElement(element.node, element);
     });
 
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 1c06c20..a5f8778 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -14,11 +14,14 @@
     show BaseClassElementX,
          ConstructorElementX,
          ErroneousElementX,
-         FieldParameterElementX,
+         FieldElementX,
+         FormalElementX,
          FunctionElementX,
          FunctionSignatureX,
+         InitializingFormalElementX,
          LabelElementX,
          LocalFunctionElementX,
+         LocalParameterElementX,
          LocalVariableElementX,
          MetadataAnnotationX,
          MixinApplicationElementX,
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
index 97b9ec0..08bb37f 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
@@ -7,11 +7,12 @@
 /**
  * [SignatureResolver] resolves function signatures.
  */
-class SignatureResolver extends MappingVisitor<ParameterElementX> {
+class SignatureResolver extends MappingVisitor<FormalElementX> {
   final ResolverVisitor resolver;
   final FunctionTypedElement enclosingElement;
   final Scope scope;
   final MessageKind defaultValuesError;
+  final bool createRealParameters;
   Link<Element> optionalParameters = const Link<Element>();
   int optionalParameterCount = 0;
   bool isOptionalParameter = false;
@@ -21,7 +22,8 @@
   SignatureResolver(Compiler compiler,
                     FunctionTypedElement enclosingElement,
                     ResolutionRegistry registry,
-                    {this.defaultValuesError})
+                    {this.defaultValuesError,
+                     this.createRealParameters})
       : this.enclosingElement = enclosingElement,
         this.scope = enclosingElement.buildScope(),
         this.resolver =
@@ -43,7 +45,7 @@
     optionalParameters = elements.toLink();
   }
 
-  ParameterElementX visitVariableDefinitions(VariableDefinitions node) {
+  FormalElementX visitVariableDefinitions(VariableDefinitions node) {
     Link<Node> definitions = node.definitions.nodes;
     if (definitions.isEmpty) {
       internalError(node, 'no parameter definition');
@@ -68,7 +70,7 @@
       internalError(node, 'function type parameters not supported');
     }
     currentDefinitions = node;
-    ParameterElementX element = definition.accept(this);
+    FormalElementX element = definition.accept(this);
     if (currentDefinitions.metadata != null) {
       element.metadata = compiler.resolver.resolveMetadata(element, node);
     }
@@ -85,7 +87,7 @@
     }
   }
 
-  void computeParameterType(ParameterElementX element,
+  void computeParameterType(FormalElementX element,
                             [VariableElement fieldElement]) {
     void computeFunctionType(FunctionExpression functionExpression) {
       FunctionSignature functionSignature = SignatureResolver.analyze(
@@ -149,22 +151,27 @@
 
   // The only valid [Send] can be in constructors and must be of the form
   // [:this.x:] (where [:x:] represents an instance field).
-  FieldParameterElementX visitSend(Send node) {
+  InitializingFormalElementX visitSend(Send node) {
     return createFieldParameter(node, null);
   }
 
-  ParameterElementX createParameter(Identifier name, Expression initializer) {
+  FormalElementX createParameter(Identifier name, Expression initializer) {
     validateName(name);
-    ParameterElementX parameter = new ParameterElementX(
-        ElementKind.PARAMETER, enclosingElement,
-        currentDefinitions, name, initializer);
+    FormalElementX parameter;
+    if (createRealParameters) {
+      parameter = new LocalParameterElementX(
+        enclosingElement, currentDefinitions, name, initializer);
+    } else {
+      parameter = new FormalElementX(
+        ElementKind.PARAMETER, enclosingElement, currentDefinitions, name);
+    }
     computeParameterType(parameter);
     return parameter;
   }
 
-  FieldParameterElementX createFieldParameter(Send node,
-                                              Expression initializer) {
-    FieldParameterElementX element;
+  InitializingFormalElementX createFieldParameter(Send node,
+                                                  Expression initializer) {
+    InitializingFormalElementX element;
     if (node.receiver.asIdentifier() == null ||
         !node.receiver.asIdentifier().isThis()) {
       error(node, MessageKind.INVALID_PARAMETER);
@@ -182,7 +189,7 @@
       } else if (!fieldElement.isInstanceMember) {
         error(node, MessageKind.NOT_INSTANCE_FIELD, {'fieldName': name});
       }
-      element = new FieldParameterElementX(enclosingElement,
+      element = new InitializingFormalElementX(enclosingElement,
           currentDefinitions, name, initializer, fieldElement);
       computeParameterType(element, fieldElement);
     }
@@ -191,7 +198,7 @@
 
   /// A [SendSet] node is an optional parameter with a default value.
   Element visitSendSet(SendSet node) {
-    ParameterElementX element;
+    FormalElementX element;
     if (node.receiver != null) {
       element = createFieldParameter(node, node.arguments.first);
     } else if (node.selector.asIdentifier() != null ||
@@ -239,15 +246,21 @@
   /**
    * Resolves formal parameters and return type of a [FunctionExpression]
    * to a [FunctionSignature].
+   *
+   * If [createRealParameters] is `true`, the parameters will be
+   * real parameters implementing the [ParameterElement] interface. Otherwise,
+   * the parameters will only implement [FormalElement].
    */
   static FunctionSignature analyze(Compiler compiler,
                                    NodeList formalParameters,
                                    Node returnNode,
                                    FunctionTypedElement element,
                                    ResolutionRegistry registry,
-                                   {MessageKind defaultValuesError}) {
+                                   {MessageKind defaultValuesError,
+                                    bool createRealParameters: false}) {
     SignatureResolver visitor = new SignatureResolver(compiler, element,
-        registry, defaultValuesError: defaultValuesError);
+        registry, defaultValuesError: defaultValuesError,
+        createRealParameters: createRealParameters);
     Link<Element> parameters = const Link<Element>();
     int requiredParameterCount = 0;
     if (formalParameters == null) {
@@ -297,7 +310,7 @@
       }
     }
     LinkBuilder<DartType> parameterTypes = new LinkBuilder<DartType>();
-    for (ParameterElement parameter in parameters) {
+    for (FormalElement parameter in parameters) {
        parameterTypes.addLast(parameter.type);
     }
     List<DartType> optionalParameterTypes = const <DartType>[];
@@ -313,7 +326,7 @@
       LinkBuilder<String> namedParametersBuilder = new LinkBuilder<String>();
       LinkBuilder<DartType> namedParameterTypesBuilder =
           new LinkBuilder<DartType>();
-      for (ParameterElement parameter in orderedOptionalParameters) {
+      for (FormalElement parameter in orderedOptionalParameters) {
         namedParametersBuilder.addLast(parameter.name);
         namedParameterTypesBuilder.addLast(parameter.type);
       }
@@ -324,7 +337,7 @@
       // TODO(karlklose); replace when [visitor.optinalParameters] is a [List].
       LinkBuilder<DartType> optionalParameterTypesBuilder =
           new LinkBuilder<DartType>();
-      for (ParameterElement parameter in visitor.optionalParameters) {
+      for (FormalElement parameter in visitor.optionalParameters) {
         optionalParameterTypesBuilder.addLast(parameter.type);
       }
       optionalParameterTypes = optionalParameterTypesBuilder.toLink()
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index e76413f..3be7141 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -918,7 +918,7 @@
     int id = idGenerator();
     PartialClassElement element = new PartialClassElement(
         name.source, beginToken, endToken, compilationUnitElement, id);
-    element.nativeTagInfo = nativeTagInfo;
+    element.setNative(nativeTagInfo);
     pushElement(element);
     rejectBuiltInIdentifier(name);
   }
@@ -2220,7 +2220,7 @@
   FunctionExpression parseNode(DiagnosticListener listener) {
     if (cachedNode != null) return cachedNode;
     parseFunction(Parser p) {
-      if (isMember && modifiers.isFactory) {
+      if (isClassMember && modifiers.isFactory) {
         p.parseFactoryMethod(beginToken);
       } else {
         p.parseFunction(beginToken, getOrSet);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 2b13266..460614d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -10,8 +10,9 @@
 /// try-catch statement.
 class SyntheticLocal extends Local {
   final String name;
+  final ExecutableElement executableContext;
 
-  SyntheticLocal(this.name);
+  SyntheticLocal(this.name, this.executableContext);
 }
 
 class SsaBuilderTask extends CompilerTask {
@@ -65,7 +66,7 @@
         }
         if (compiler.tracer.isEnabled) {
           String name;
-          if (element.isMember) {
+          if (element.isClassMember) {
             String className = element.enclosingClass.name;
             String memberName = element.name;
             name = "$className.$memberName";
@@ -110,12 +111,15 @@
       new Map<Local, CapturedVariable>();
   SsaBuilder builder;
   ClosureClassMap closureData;
+  Map<TypeVariableType, TypeVariableLocal> typeVariableLocals =
+      new Map<TypeVariableType, TypeVariableLocal>();
+  final ExecutableElement executableContext;
 
   /// The class that defines the current type environment or null if no type
   /// variables are in scope.
-  final ClassElement contextClass;
+  ClassElement get contextClass => executableContext.contextClass;
 
-  LocalsHandler(this.builder, this.contextClass);
+  LocalsHandler(this.builder, this.executableContext);
 
   /// Substituted type variables occurring in [type] into the context of
   /// [contextClass].
@@ -140,7 +144,7 @@
   LocalsHandler.from(LocalsHandler other)
       : directLocals = new Map<Local, HInstruction>.from(other.directLocals),
         redirectionMapping = other.redirectionMapping,
-        contextClass = other.contextClass,
+        executableContext = other.executableContext,
         builder = other.builder,
         closureData = other.closureData;
 
@@ -189,7 +193,7 @@
     // Make sure that accesses to the boxed locals go into the box. We also
     // need to make sure that parameters are copied into the box if necessary.
     scopeData.forEachCapturedVariable(
-        (VariableElement from, BoxFieldElement to) {
+        (LocalVariableElement from, BoxFieldElement to) {
       // The [from] can only be a parameter for function-scopes and not
       // loop scopes.
       if (from.isParameter && !element.isGenerativeConstructorBody) {
@@ -214,12 +218,12 @@
    * of elements from the old box into the new box.
    */
   void updateCaptureBox(BoxLocal boxElement,
-                        List<VariableElement> toBeCopiedElements) {
+                        List<LocalVariableElement> toBeCopiedElements) {
     // Create a new box and copy over the values from the old box into the
     // new one.
     HInstruction oldBox = readLocal(boxElement);
     HInstruction newBox = createBox();
-    for (VariableElement boxedVariable in toBeCopiedElements) {
+    for (LocalVariableElement boxedVariable in toBeCopiedElements) {
       // [readLocal] uses the [boxElement] to find its box. By replacing it
       // behind its back we can still get to the old values.
       updateLocal(boxElement, oldBox);
@@ -303,7 +307,7 @@
     if (backend.isInterceptedMethod(element)) {
       bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
       String name = isInterceptorClass ? 'receiver' : '_';
-      SyntheticLocal parameter = new SyntheticLocal(name);
+      SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
       HParameterValue value =
           new HParameterValue(parameter, builder.getTypeOfThis());
       builder.graph.explicitReceiverParameter = value;
@@ -314,7 +318,8 @@
         directLocals[closureData.thisLocal] = value;
       }
     } else if (isNativeUpgradeFactory) {
-      SyntheticLocal parameter = new SyntheticLocal('receiver');
+      SyntheticLocal parameter =
+          new SyntheticLocal('receiver', executableContext);
       // Unlike `this`, receiver is nullable since direct calls to generative
       // constructor call the constructor with `null`.
       HParameterValue value =
@@ -424,6 +429,12 @@
     });
   }
 
+  Local getTypeVariableAsLocal(TypeVariableType type) {
+    return typeVariableLocals.putIfAbsent(type, () {
+      return new TypeVariableLocal(type, executableContext);
+    });
+  }
+
   /**
    * Sets the [element] to [value]. If the element is boxed or stored in a
    * closure then the method generates code to set the value.
@@ -588,7 +599,7 @@
     otherLocals.directLocals.forEach((Local local,
                                       HInstruction instruction) {
       // We know 'this' cannot be modified.
-      if (identical(local, closureData.thisLocal)) {
+      if (local == closureData.thisLocal) {
         assert(directLocals[local] == instruction);
         joinedLocals[local] = instruction;
       } else {
@@ -978,7 +989,7 @@
       this.work = work,
       this.rti = backend.rti,
       super(work.resolutionTree, backend.compiler) {
-    localsHandler = new LocalsHandler(this, work.element.contextClass);
+    localsHandler = new LocalsHandler(this, work.element);
     sourceElementStack.add(work.element);
   }
 
@@ -1376,8 +1387,8 @@
   TypeMask getTypeOfThis() {
     TypeMask result = cachedTypeOfThis;
     if (result == null) {
-      ThisLocal element = localsHandler.closureData.thisLocal;
-      ClassElement cls = element.enclosingClass;
+      ThisLocal local = localsHandler.closureData.thisLocal;
+      ClassElement cls = local.enclosingClass;
       if (compiler.world.isUsedAsMixin(cls)) {
         // If the enclosing class is used as a mixin, [:this:] can be
         // of the class that mixins the enclosing class. These two
@@ -1510,7 +1521,7 @@
     return bodyElement;
   }
 
-  HParameterValue addParameter(Local parameter, TypeMask type) {
+  HParameterValue addParameter(Entity parameter, TypeMask type) {
     assert(inliningStack.isEmpty);
     HParameterValue result = new HParameterValue(parameter, type);
     if (lastAddedParameter == null) {
@@ -1533,11 +1544,11 @@
    */
   void setupStateForInlining(FunctionElement function,
                              List<HInstruction> compiledArguments) {
-    localsHandler = new LocalsHandler(this, function.contextClass);
+    localsHandler = new LocalsHandler(this, function);
     localsHandler.closureData =
         compiler.closureToClassMapper.computeClosureToClassMapping(
             function, function.node, elements);
-    returnLocal = new SyntheticLocal("result");
+    returnLocal = new SyntheticLocal("result", function);
     localsHandler.updateLocal(returnLocal,
         graph.addConstantNull(compiler));
 
@@ -1560,7 +1571,8 @@
         && backend.classNeedsRti(enclosing)) {
       enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
         HInstruction argument = compiledArguments[argumentIndex++];
-        localsHandler.updateLocal(typeVariable.element, argument);
+        localsHandler.updateLocal(
+            localsHandler.getTypeVariableAsLocal(typeVariable), argument);
       });
     }
     assert(argumentIndex == compiledArguments.length);
@@ -1666,14 +1678,15 @@
             variables.moveNext();
             TypeVariableType typeVariable = variables.current;
             localsHandler.updateLocal(
-                typeVariable.element,
+                localsHandler.getTypeVariableAsLocal(typeVariable),
                 analyzeTypeArgument(argument));
           });
         } else {
           // If the supertype is a raw type, we need to set to null the
           // type variables.
           for (TypeVariableType variable in typeVariables) {
-            localsHandler.updateLocal(variable.element,
+            localsHandler.updateLocal(
+                localsHandler.getTypeVariableAsLocal(variable),
                 graph.addConstantNull(compiler));
           }
         }
@@ -1699,8 +1712,8 @@
         localsHandler.updateLocal(parameter, argument);
         // Don't forget to update the field, if the parameter is of the
         // form [:this.x:].
-        if (parameter.isFieldParameter) {
-          FieldParameterElement fieldParameterElement = parameter;
+        if (parameter.isInitializingFormal) {
+          InitializingFormalElement fieldParameterElement = parameter;
           fieldValues[fieldParameterElement.fieldElement] = argument;
         }
       });
@@ -1902,10 +1915,10 @@
     // Compile field-parameters such as [:this.x:].
     FunctionSignature params = functionElement.functionSignature;
     params.orderedForEachParameter((ParameterElement parameter) {
-      if (parameter.isFieldParameter) {
+      if (parameter.isInitializingFormal) {
         // If the [element] is a field-parameter then
         // initialize the field element with its value.
-        FieldParameterElement fieldParameter = parameter;
+        InitializingFormalElement fieldParameter = parameter;
         HInstruction parameterValue =
             localsHandler.readLocal(fieldParameter);
         fieldValues[fieldParameter.fieldElement] = parameterValue;
@@ -2021,7 +2034,8 @@
 
       List<HInstruction> typeArguments = <HInstruction>[];
       classElement.typeVariables.forEach((TypeVariableType typeVariable) {
-        HInstruction argument = localsHandler.readLocal(typeVariable.element);
+        HInstruction argument = localsHandler.readLocal(
+            localsHandler.getTypeVariableAsLocal(typeVariable));
         if (allIndexed && !isIndexedTypeArgumentGet(argument)) {
           allIndexed = false;
         }
@@ -2076,7 +2090,8 @@
         currentClass.typeVariables.forEach((TypeVariableType argument) {
           // TODO(johnniwinther): Substitute [argument] with
           // `localsHandler.substInContext(argument)`.
-          bodyCallInputs.add(localsHandler.readLocal(argument.element));
+          bodyCallInputs.add(localsHandler.readLocal(
+              localsHandler.getTypeVariableAsLocal(argument)));
         });
       }
 
@@ -2131,7 +2146,8 @@
       enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
         HParameterValue param = addParameter(
             typeVariable.element, backend.nonNullType);
-        localsHandler.directLocals[typeVariable.element] = param;
+        localsHandler.directLocals[
+            localsHandler.getTypeVariableAsLocal(typeVariable)] = param;
       });
     }
 
@@ -2873,7 +2889,7 @@
   visitFunctionDeclaration(ast.FunctionDeclaration node) {
     assert(isReachable);
     visit(node.function);
-    FunctionElement localFunction = elements[node];
+    LocalFunctionElement localFunction = elements[node];
     localsHandler.updateLocal(localFunction, pop());
   }
 
@@ -3069,7 +3085,7 @@
                                 noSuchMethodTargetSymbolString(element, 'get'),
                                 argumentNodes: const Link<ast.Node>());
     } else {
-      TypedElement local = element;
+      LocalElement local = element;
       stack.add(localsHandler.readLocal(local));
     }
   }
@@ -3123,7 +3139,7 @@
                                 argumentValues: arguments);
     } else {
       stack.add(value);
-      TypedElement local = element;
+      LocalElement local = element;
       // If the value does not already have a name, give it here.
       if (value.sourceElement == null) {
         value.sourceElement = local;
@@ -3378,7 +3394,7 @@
       visit(node.selector);
       closureTarget = pop();
     } else {
-      TypedElement local = element;
+      LocalElement local = element;
       closureTarget = localsHandler.readLocal(local);
     }
     var inputs = <HInstruction>[];
@@ -3880,7 +3896,7 @@
   // fixed.
   bool hasDirectLocal(Local local) {
     return !localsHandler.isAccessedDirectly(local) ||
-        localsHandler.directLocals[local] != null;
+            localsHandler.directLocals[local] != null;
   }
 
   /**
@@ -3897,24 +3913,25 @@
     }
     bool isInConstructorContext = member.isConstructor ||
         member.isGenerativeConstructorBody;
+    Local typeVariableLocal = localsHandler.getTypeVariableAsLocal(type);
     if (isClosure) {
       if (member.isFactoryConstructor ||
-          (isInConstructorContext && hasDirectLocal(type.element))) {
+          (isInConstructorContext && hasDirectLocal(typeVariableLocal))) {
         // The type variable is used from a closure in a factory constructor.
         // The value of the type argument is stored as a local on the closure
         // itself.
-        return localsHandler.readLocal(type.element);
+        return localsHandler.readLocal(typeVariableLocal);
       } else if (member.isFunction ||
-          member.isGetter ||
-          member.isSetter ||
-          isInConstructorContext) {
+                 member.isGetter ||
+                 member.isSetter ||
+                 isInConstructorContext) {
         // The type variable is stored on the "enclosing object" and needs to be
         // accessed using the this-reference in the closure.
         return readTypeVariable(member.enclosingClass, type.element);
       } else {
         assert(member.isField);
         // The type variable is stored in a parameter of the method.
-        return localsHandler.readLocal(type.element);
+        return localsHandler.readLocal(typeVariableLocal);
       }
     } else if (isInConstructorContext ||
                // When [member] is a field, we can be either
@@ -3924,7 +3941,7 @@
                // always return true when seeing one.
                (member.isField && !isBuildingFor(member))) {
       // The type variable is stored in a parameter of the method.
-      return localsHandler.readLocal(type.element);
+      return localsHandler.readLocal(typeVariableLocal);
     } else if (member.isInstanceMember) {
       // The type variable is stored on the object.
       return readTypeVariable(member.enclosingClass,
@@ -4935,7 +4952,7 @@
       ast.Node definition = link.head;
       if (definition is ast.Identifier) {
         HInstruction initialValue = graph.addConstantNull(compiler);
-        VariableElement local = elements[definition];
+        LocalElement local = elements[definition];
         localsHandler.updateLocal(local, initialValue);
       } else {
         assert(definition is ast.SendSet);
@@ -5631,7 +5648,8 @@
       startCatchBlock = graph.addNewBlock();
       open(startCatchBlock);
       // Note that the name of this local is irrelevant.
-      SyntheticLocal local = new SyntheticLocal('exception');
+      SyntheticLocal local =
+          new SyntheticLocal('exception', localsHandler.executableContext);
       exception = new HLocalValue(local, backend.nonNullType);
       add(exception);
       HInstruction oldRethrowableException = rethrowableException;
@@ -5676,7 +5694,8 @@
         ast.CatchBlock catchBlock = link.head;
         link = link.tail;
         if (catchBlock.exception != null) {
-          VariableElement exceptionVariable = elements[catchBlock.exception];
+          LocalVariableElement exceptionVariable =
+              elements[catchBlock.exception];
           localsHandler.updateLocal(exceptionVariable,
                                     unwrappedException);
         }
@@ -5684,7 +5703,7 @@
         if (trace != null) {
           pushInvokeStatic(trace, backend.getTraceFromException(), [exception]);
           HInstruction traceInstruction = pop();
-          VariableElement traceVariable = elements[trace];
+          LocalVariableElement traceVariable = elements[trace];
           localsHandler.updateLocal(traceVariable, traceInstruction);
         }
         visit(catchBlock);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index e8f5746..608b5c2 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -2052,7 +2052,7 @@
   * value from the start, whereas [HLocalValue]s need to be initialized first.
   */
 class HLocalValue extends HInstruction {
-  HLocalValue(Local variable, TypeMask type)
+  HLocalValue(Entity variable, TypeMask type)
       : super(<HInstruction>[], type) {
     sourceElement = variable;
   }
@@ -2062,7 +2062,7 @@
 }
 
 class HParameterValue extends HLocalValue {
-  HParameterValue(Local variable, type) : super(variable, type);
+  HParameterValue(Entity variable, type) : super(variable, type);
 
   toString() => 'parameter ${sourceElement.name}';
   accept(HVisitor visitor) => visitor.visitParameterValue(this);
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 4f56b63..f0391fe 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -589,8 +589,8 @@
       returnType = const VoidType();
 
       element.functionSignature.forEachParameter((ParameterElement parameter) {
-        if (parameter.isFieldParameter) {
-          FieldParameterElement fieldParameter = parameter;
+        if (parameter.isInitializingFormal) {
+          InitializingFormalElement fieldParameter = parameter;
           checkAssignable(parameter, parameter.type,
               fieldParameter.fieldElement.computeType(compiler));
         }
@@ -995,7 +995,7 @@
         return new TypeLiteralAccess(elements.getTypeLiteralType(node));
       }
       return createResolvedAccess(node, name, element);
-    } else if (element.isMember) {
+    } else if (element.isClassMember) {
       // foo() where foo is a member.
       return lookupMember(node, thisType, name, memberKind, null,
           lookupClassMember: element.isStatic);
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 6a933db..ee87577 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -670,7 +670,7 @@
   bool appliesUnnamed(Element element, Compiler compiler) {
     assert(sameNameHack(element, compiler));
     // [TypedSelector] are only used after resolution.
-    if (!element.isMember) return false;
+    if (!element.isClassMember) return false;
 
     // A closure can be called through any typed selector:
     // class A {
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
index 8904464..5591741 100644
--- a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -40,7 +40,7 @@
 
 import 'ssa/ssa.dart' as ssa;
 
-import 'cps_ir/cps_ir_nodes.dart' as cps_ir_nodes;
+import 'cps_ir/cps_ir_nodes_sexpr.dart' as cps_ir_nodes_sexpr;
 
 import 'cps_ir/cps_ir_builder.dart' as ir_builder;
 
@@ -210,9 +210,9 @@
   n.isAccessibleFrom(null);
 }
 
-useIr(cps_ir_nodes.SExpressionStringifier stringifier,
+useIr(cps_ir_nodes_sexpr.SExpressionStringifier stringifier,
       ir_builder.IrBuilderTask task) {
-  new cps_ir_nodes.SExpressionStringifier();
+  new cps_ir_nodes_sexpr.SExpressionStringifier();
   stringifier
     ..newContinuationName()
     ..newValueName()
diff --git a/sdk/lib/_internal/lib/annotations.dart b/sdk/lib/_internal/lib/annotations.dart
index 23f1234..1e63cf9 100644
--- a/sdk/lib/_internal/lib/annotations.dart
+++ b/sdk/lib/_internal/lib/annotations.dart
@@ -28,3 +28,9 @@
   final bool value;
   const IrRepresentation(this.value);
 }
+
+/// Marks a class as native and defines its JavaScript name(s).
+class Native {
+  final String name;
+  const Native(this.name);
+}
diff --git a/sdk/lib/_internal/lib/js_array.dart b/sdk/lib/_internal/lib/js_array.dart
index 42ee248..7345230 100644
--- a/sdk/lib/_internal/lib/js_array.dart
+++ b/sdk/lib/_internal/lib/js_array.dart
@@ -147,7 +147,7 @@
   }
 
   Iterable<E> where(bool f(E element)) {
-    return IterableMixinWorkaround.where(this, f);
+    return new IterableMixinWorkaround<E>().where(this, f);
   }
 
   Iterable expand(Iterable f(E element)) {
@@ -181,19 +181,19 @@
   }
 
   Iterable<E> take(int n) {
-    return IterableMixinWorkaround.takeList(this, n);
+    return new IterableMixinWorkaround<E>().takeList(this, n);
   }
 
   Iterable<E> takeWhile(bool test(E value)) {
-    return IterableMixinWorkaround.takeWhile(this, test);
+    return new IterableMixinWorkaround<E>().takeWhile(this, test);
   }
 
   Iterable<E> skip(int n) {
-    return IterableMixinWorkaround.skipList(this, n);
+    return new IterableMixinWorkaround<E>().skipList(this, n);
   }
 
   Iterable<E> skipWhile(bool test(E value)) {
-    return IterableMixinWorkaround.skipWhile(this, test);
+    return new IterableMixinWorkaround<E>().skipWhile(this, test);
   }
 
   E reduce(E combine(E value, E element)) {
@@ -241,7 +241,7 @@
 
 
   Iterable<E> getRange(int start, int end) {
-    return IterableMixinWorkaround.getRangeList(this, start, end);
+    return new IterableMixinWorkaround<E>().getRangeList(this, start, end);
   }
 
   E get first {
@@ -296,7 +296,8 @@
 
   bool every(bool f(E element)) => IterableMixinWorkaround.every(this, f);
 
-  Iterable<E> get reversed => IterableMixinWorkaround.reversedList(this);
+  Iterable<E> get reversed =>
+      new IterableMixinWorkaround<E>().reversedList(this);
 
   void sort([int compare(E a, E b)]) {
     checkMutable('sort');
@@ -365,7 +366,7 @@
   }
 
   Map<int, E> asMap() {
-    return IterableMixinWorkaround.asMapList(this);
+    return new IterableMixinWorkaround<E>().asMapList(this);
   }
 }
 
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 41fc902..8eb4b65 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -159,6 +159,11 @@
     String unmangledName = mangledNames[name];
     if (unmangledName != null) {
       name = unmangledName.split(':')[0];
+    } else {
+      if (mangledNames[_internalName] == null) {
+        print("Warning: '$name' is used reflectively but not in MirrorsUsed. "
+              "This will break minified code.");
+      }
     }
     _memberName = new _symbol_dev.Symbol.unvalidated(name);
     return _memberName;
diff --git a/sdk/lib/_internal/lib/native_typed_data.dart b/sdk/lib/_internal/lib/native_typed_data.dart
index 575e827..f1ebae5 100644
--- a/sdk/lib/_internal/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/lib/native_typed_data.dart
@@ -12,13 +12,14 @@
 import 'dart:_internal';
 import 'dart:_interceptors' show JSIndexable, JSUInt32, JSUInt31;
 import 'dart:_js_helper'
-    show Creates, JavaScriptIndexingBehavior, JSName, Null, Returns;
+show Creates, JavaScriptIndexingBehavior, JSName, Native, Null, Returns;
 import 'dart:_foreign_helper' show JS;
 import 'dart:math' as Math;
 
 import 'dart:typed_data';
 
-class NativeByteBuffer implements ByteBuffer native "ArrayBuffer" {
+@Native("ArrayBuffer")
+class NativeByteBuffer implements ByteBuffer {
   @JSName('byteLength')
   final int lengthInBytes;
 
@@ -406,7 +407,8 @@
   }
 }
 
-class NativeTypedData implements TypedData native "ArrayBufferView" {
+@Native("ArrayBufferView")
+class NativeTypedData implements TypedData {
   /**
    * Returns the byte buffer associated with this object.
    */
@@ -499,8 +501,8 @@
 }
 
 
-class NativeByteData extends NativeTypedData implements ByteData
-    native "DataView" {
+@Native("DataView")
+class NativeByteData extends NativeTypedData implements ByteData {
   /**
    * Creates a [ByteData] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -914,10 +916,10 @@
 }
 
 
+@Native("Float32Array")
 class NativeFloat32List
     extends NativeTypedArrayOfDouble
-    implements Float32List
-    native "Float32Array" {
+    implements Float32List {
 
   factory NativeFloat32List(int length) => _create1(_checkLength(length));
 
@@ -951,10 +953,10 @@
 }
 
 
+@Native("Float64Array")
 class NativeFloat64List
     extends NativeTypedArrayOfDouble
-    implements Float64List
-    native "Float64Array" {
+    implements Float64List {
 
   factory NativeFloat64List(int length) => _create1(_checkLength(length));
 
@@ -988,10 +990,10 @@
 }
 
 
+@Native("Int16Array")
 class NativeInt16List
     extends NativeTypedArrayOfInt
-    implements Int16List
-    native "Int16Array" {
+    implements Int16List {
 
   factory NativeInt16List(int length) => _create1(_checkLength(length));
 
@@ -1030,10 +1032,8 @@
 }
 
 
-class NativeInt32List
-    extends NativeTypedArrayOfInt
-    implements Int32List
-    native "Int32Array" {
+@Native("Int32Array")
+class NativeInt32List extends NativeTypedArrayOfInt implements Int32List {
 
   factory NativeInt32List(int length) => _create1(_checkLength(length));
 
@@ -1072,10 +1072,8 @@
 }
 
 
-class NativeInt8List
-    extends NativeTypedArrayOfInt
-    implements Int8List
-    native "Int8Array" {
+@Native("Int8Array")
+class NativeInt8List extends NativeTypedArrayOfInt implements Int8List {
 
   factory NativeInt8List(int length) => _create1(_checkLength(length));
 
@@ -1114,10 +1112,8 @@
 }
 
 
-class NativeUint16List
-    extends NativeTypedArrayOfInt
-    implements Uint16List
-    native "Uint16Array" {
+@Native("Uint16Array")
+class NativeUint16List extends NativeTypedArrayOfInt implements Uint16List {
 
   factory NativeUint16List(int length) => _create1(_checkLength(length));
 
@@ -1156,10 +1152,8 @@
 }
 
 
-class NativeUint32List
-    extends NativeTypedArrayOfInt
-    implements Uint32List
-    native "Uint32Array" {
+@Native("Uint32Array")
+class NativeUint32List extends NativeTypedArrayOfInt implements Uint32List {
 
   factory NativeUint32List(int length) => _create1(_checkLength(length));
 
@@ -1198,10 +1192,10 @@
 }
 
 
+@Native("Uint8ClampedArray,CanvasPixelArray")
 class NativeUint8ClampedList
     extends NativeTypedArrayOfInt
-    implements Uint8ClampedList
-    native "Uint8ClampedArray,CanvasPixelArray" {
+    implements Uint8ClampedList {
 
   factory NativeUint8ClampedList(int length) => _create1(_checkLength(length));
 
@@ -1244,14 +1238,12 @@
 }
 
 
-class NativeUint8List
-    extends NativeTypedArrayOfInt
-    implements Uint8List
-    // On some browsers Uint8ClampedArray is a subtype of Uint8Array.  Marking
-    // Uint8List as !nonleaf ensures that the native dispatch correctly handles
-    // the potential for Uint8ClampedArray to 'accidentally' pick up the
-    // dispatch record for Uint8List.
-    native "Uint8Array,!nonleaf" {
+// On some browsers Uint8ClampedArray is a subtype of Uint8Array.  Marking
+// Uint8List as !nonleaf ensures that the native dispatch correctly handles
+// the potential for Uint8ClampedArray to 'accidentally' pick up the
+// dispatch record for Uint8List.
+@Native("Uint8Array,!nonleaf")
+class NativeUint8List extends NativeTypedArrayOfInt implements Uint8List {
 
   factory NativeUint8List(int length) => _create1(_checkLength(length));
 
diff --git a/sdk/lib/_internal/pub/lib/src/lock_file.dart b/sdk/lib/_internal/pub/lib/src/lock_file.dart
index a2dd6e4..128a3a9 100644
--- a/sdk/lib/_internal/pub/lib/src/lock_file.dart
+++ b/sdk/lib/_internal/pub/lib/src/lock_file.dart
@@ -4,6 +4,7 @@
 
 library pub.lock_file;
 
+import 'package:path/path.dart' as p;
 import 'package:source_maps/source_maps.dart';
 import 'package:yaml/yaml.dart';
 
@@ -44,12 +45,18 @@
   }
 
   /// Parses the lockfile whose text is [contents].
+  ///
+  /// [filePath] is the system-native path to the lockfile on disc. It may be
+  /// `null`.
   static LockFile _parse(String filePath, String contents,
       SourceRegistry sources) {
     var packages = <String, PackageId>{};
 
     if (contents.trim() == '') return new LockFile.empty();
-    var parsed = loadYamlNode(contents, sourceName: filePath);
+
+    var sourceName;
+    if (filePath != null) sourceName = p.toUri(filePath).toString();
+    var parsed = loadYamlNode(contents, sourceName: sourceName);
 
     _validate(parsed is Map, 'The lockfile must be a YAML mapping.', parsed);
 
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index fbfb876..f9df64b 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -14,4 +14,3 @@
 
 [ $runtime == vm && $system == windows ]
 test/run/app_can_read_from_stdin_test: Fail # Issue 19448
-test/list_package_dirs/lockfile_error_test: Fail # Issue 20104
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index b6e1a11..6530239 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -49,7 +49,6 @@
  * "package:collection/wrappers.dart" instead.
  */
 abstract class ListMixin<E> implements List<E> {
-
   // Iterable interface.
   Iterator<E> get iterator => new ListIterator<E>(this);
 
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 3aa48c6..3ca1fb3 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -44,60 +44,72 @@
    * A message describing the format error.
    */
   final String message;
+
   /**
-   * The source that caused the error.
+   * The actual source input that caused the error.
    *
-   * This is usually a [String], but can be other types too. If it is a string,
-   * parts of it may be included in the [toString] message.
+   * This is usually a [String], but can be other types too.
+   * If it is a string, parts of it may be included in the [toString] message.
    *
-   * May also be `null` if omitted.
+   * The source is `null` if omitted or unknown.
    */
   final source;
+
   /**
-   * The position in source where the error was detected.
+   * The offset in [source] where the error was detected.
    *
-   * May be omitted. If present, [source] should also be present.
+   * A zero-based offset into the source that marks the format error causing
+   * this exception to be created. If `source` is a string, this should be a
+   * string index in the range `0 <= offset <= source.length`.
+   *
+   * If input is a string, the [toString] method may represent this offset as
+   * a line and character position. The offset should be inside the string,
+   * or at the end of the string.
+   *
+   * May be omitted. If present, [source] should also be present if possible.
    */
-  final int position;
+  final int offset;
 
   /**
    * Creates a new FormatException with an optional error [message].
    *
-   * Optionally also supply the [source] that had the incorrect format, and
-   * even the [position] in the format where this was detected.
+   * Optionally also supply the actual [source] that had the incorrect format,
+   * and an [offset] in the format where a problem was detected.
    */
-  const FormatException([this.message = "", this.source, this.position]);
+  const FormatException([this.message = "", this.source, this.offset]);
 
   /**
    * Returns a description of the format exception.
    *
    * The description always contains the [message].
-   * If [source] was provided, the description will contain (at least a part of)
-   * the source.
-   * If [position] is also provided, the part of the source included will
-   * contain that position, and the position will be marked.
    *
-   * If the source contains a line break before position, only the line
-   * containing position will be included, and its line number will also be
-   * part of the description. Line and character offsets are 1-based.
+   * If [source] is present and is a string, the description will contain
+   * (at least a part of) the source.
+   * If [offset] is also provided, the part of the source included will
+   * contain that offset, and the offset will be marked.
+   *
+   * If the source is a string and it contains a line break before offset,
+   * only the line containing offset will be included, and its line number
+   * will also be part of the description. Line and character offsets are
+   * 1-based.
    */
   String toString() {
     String report = "FormatException";
     if (message != null && "" != message) {
       report = "$report: $message";
     }
-    int position = this.position;
+    int offset = this.offset;
     if (source is! String) {
-      if (position != null) {
-        report += " (at position $position)";
+      if (offset != null) {
+        report += " (at offset $offset)";
       }
       return report;
     }
-    if (position != null && (position < 0 || position > source.length)) {
-      position = null;
+    if (offset != null && (offset < 0 || offset > source.length)) {
+      offset = null;
     }
-    // Source is string and position is null or valid.
-    if (position == null) {
+    // Source is string and offset is null or valid.
+    if (offset == null) {
       String source = this.source;
       if (source.length > 78) {
         source = source.substring(0, 75) + "...";
@@ -107,7 +119,7 @@
     int lineNum = 1;
     int lineStart = 0;
     bool lastWasCR;
-    for (int i = 0; i < position; i++) {
+    for (int i = 0; i < offset; i++) {
       int char = source.codeUnitAt(i);
       if (char == 0x0a) {
         if (lineStart != i || !lastWasCR) {
@@ -122,12 +134,12 @@
       }
     }
     if (lineNum > 1) {
-      report += " (at line $lineNum, character ${position - lineStart + 1})\n";
+      report += " (at line $lineNum, character ${offset - lineStart + 1})\n";
     } else {
-      report += " (at character ${position + 1})\n";
+      report += " (at character ${offset + 1})\n";
     }
     int lineEnd = source.length;
-    for (int i = position; i < source.length; i++) {
+    for (int i = offset; i < source.length; i++) {
       int char = source.codeUnitAt(i);
       if (char == 0x0a || char == 0x0d) {
         lineEnd = i;
@@ -142,22 +154,22 @@
     if (length > 78) {
       // Can't show entire line. Try to anchor at the nearest end, if
       // one is within reach.
-      int index = position - lineStart;
+      int index = offset - lineStart;
       if (index < 75) {
         end = start + 75;
         postfix = "...";
-      } else if (end - position < 75) {
+      } else if (end - offset < 75) {
         start = end - 75;
         prefix = "...";
       } else {
-        // Neither end is near, just pick an area around the position.
-        start = position - 36;
-        end = position + 36;
+        // Neither end is near, just pick an area around the offset.
+        start = offset - 36;
+        end = offset + 36;
         prefix = postfix = "...";
       }
     }
     String slice = source.substring(start, end);
-    int markOffset = position - start + prefix.length;
+    int markOffset = offset - start + prefix.length;
     return "$report$prefix$slice$postfix\n${" " * markOffset}^\n";
   }
 }
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index f9d3a3f..6d10da9 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -54,13 +54,14 @@
   }
 
   /**
-   * Returns an Iterator that iterates over this Iterable object.
+   * Returns a new `Iterator` that allows iterating the elements of this
+   * `Iterable`.
    */
   Iterator<E> get iterator;
 
   /**
-   * Returns a lazy [Iterable] where each element [:e:] of `this` is replaced
-   * by the result of [:f(e):].
+   * Returns a new lazy [Iterable] with elements that are created by
+   * calling `f` on the elements of this `Iterable`.
    *
    * This method returns a view of the mapped elements. As long as the
    * returned [Iterable] is not iterated over, the supplied function [f] will
@@ -71,7 +72,7 @@
   Iterable map(f(E element));
 
   /**
-   * Returns a lazy [Iterable] with all elements that satisfy the
+   * Returns a new lazy [Iterable] with all elements that satisfy the
    * predicate [test].
    *
    * This method returns a view of the mapped elements. As long as the
@@ -96,7 +97,7 @@
   /**
    * Returns true if the collection contains an element equal to [element].
    *
-   * The equality used to determine wheter [element] is equal to an element of
+   * The equality used to determine whether [element] is equal to an element of
    * the iterable, depends on the type of iterable.
    * For example, a [Set] may have a custom equality
    * (see, e.g., [Set.identical]) that its `contains` uses.
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index db6d7bc..81f94f0 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -6,9 +6,10 @@
 
 /**
  * An collection of key-value pairs, from which you retrieve a value
- * by using its associated key.
+ * using its associated key.
  *
- * Each key can occur at most once in a map.
+ * There is a finite number of keys in the map,
+ * and each key has exactly one value associated with it.
  *
  * Maps, and their keys and values, can be iterated.
  * The order of iteration is defined by the individual type of map.
@@ -119,20 +120,30 @@
       = LinkedHashMap<K, V>.fromIterables;
 
   /**
-   * Returns true if this map contains the given value.
+   * Returns true if this map contains the given [value].
+   *
+   * Returns true if any of the values in the map are equal to `value`
+   * according to the `==` operator.
    */
   bool containsValue(Object value);
 
   /**
-   * Returns true if this map contains the given key.
+   * Returns true if this map contains the given [key].
+   *
+   * Returns true if any of the keys in the map ar equal to `key`
+   * according to the equality used by the map.
    */
   bool containsKey(Object key);
 
   /**
-   * Returns the value for the given [key] or null if [key] is not
-   * in the map. Because null values are supported, one should either
-   * use [containsKey] to distinguish between an absent key and a null
-   * value, or use the [putIfAbsent] method.
+   * Returns the value for the given [key] or null if [key] is not in the map.
+   *
+   * Some maps allows keys to have `null` as a value,
+   * For those maps, a lookup using this operator does cannot be used to
+   * distinguish between a key not being in the map, and the key having a null
+   * value.
+   * Methods like [containsKey] or [putIfAbsent] can be use if the distinction
+   * is important.
    */
   V operator [](Object key);
 
@@ -145,9 +156,11 @@
   void operator []=(K key, V value);
 
   /**
-   * If [key] is not associated to a value, calls [ifAbsent] and
-   * updates the map by mapping [key] to the value returned by
-   * [ifAbsent]. Returns the value in the map.
+   * Look up the value of [key], or add a new value if it isn't there.
+   *
+   * Returns the value associated to [key], if there is one.
+   * Otherwise calls [ifAbsent] to get a new value, associates [key] to
+   * that value, and then returns the new value.
    *
    *     Map<String, int> scores = {'Bob': 36};
    *     for (var key in ['Bob', 'Rohan', 'Sophena']) {
@@ -157,7 +170,7 @@
    *     scores['Rohan'];    //  5
    *     scores['Sophena'];  //  7
    *
-   * The code that [ifAbsent] executes must not add or remove keys.
+   * Calling [ifAbsent] must not add or remove keys from the map.
    */
   V putIfAbsent(K key, V ifAbsent());
 
@@ -173,10 +186,13 @@
   void addAll(Map<K, V> other);
 
   /**
-   * Removes the association for the given [key]. Returns the value for
-   * [key] in the map or null if [key] is not in the map. Note that values
-   * can be null and a returned null value does not always imply that the
-   * key is absent.
+   * Removes [key] and its associated value, if present, from the map.
+   *
+   * Returns the value associated with `key` before it was removed.
+   * Returns `null` if `key` was not in the map.
+   *
+   * Note that values can be `null` and a returned `null` value doesn't
+   * always mean that the key was absent.
    */
   V remove(Object key);
 
@@ -188,9 +204,9 @@
   void clear();
 
   /**
-   * Applies [f] to each {key, value} pair of the map.
+   * Applies [f] to each key-value pair of the map.
    *
-   * Adding or removing keys from the map during iteration is not allowed.
+   * Calling `f` must not add or remove keys from the map.
    */
   void forEach(void f(K key, V value));
 
@@ -213,7 +229,8 @@
    * provided matching pairs of keys and values.
    *
    * The returned iterable has an efficient `length` method based on the
-   * [length] of the map.
+   * [length] of the map. Its [Iterable.contains] method is based on
+   * `==` comparison.
    */
   Iterable<V> get values;
 
diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart
index 4cf8418..006b31a 100644
--- a/sdk/lib/internal/iterable.dart
+++ b/sdk/lib/internal/iterable.dart
@@ -195,11 +195,11 @@
     return value;
   }
 
-  Iterable<E> skip(int count) => new SubListIterable(this, count, null);
+  Iterable<E> skip(int count) => new SubListIterable<E>(this, count, null);
 
   Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
 
-  Iterable<E> take(int count) => new SubListIterable(this, 0, count);
+  Iterable<E> take(int count) => new SubListIterable<E>(this, 0, count);
 
   Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
 
@@ -276,17 +276,21 @@
 
   Iterable<E> skip(int count) {
     if (count < 0) throw new RangeError.value(count);
-    return new SubListIterable(_iterable, _start + count, _endOrLength);
+    int newStart = _start + count;
+    if (_endOrLength != null && newStart >= _endOrLength) {
+      return new EmptyIterable<E>();
+    }
+    return new SubListIterable<E>(_iterable, newStart, _endOrLength);
   }
 
   Iterable<E> take(int count) {
     if (count < 0) throw new RangeError.value(count);
     if (_endOrLength == null) {
-      return new SubListIterable(_iterable, _start, _start + count);
+      return new SubListIterable<E>(_iterable, _start, _start + count);
     } else {
       int newEnd = _start + count;
       if (_endOrLength < newEnd) return this;
-      return new SubListIterable(_iterable, _start, newEnd);
+      return new SubListIterable<E>(_iterable, _start, newEnd);
     }
   }
 }
@@ -740,7 +744,7 @@
  *
  * The uses of this class will be replaced by mixins.
  */
-class IterableMixinWorkaround {
+class IterableMixinWorkaround<T> {
   static bool contains(Iterable iterable, var element) {
     for (final e in iterable) {
       if (e == element) return true;
@@ -934,8 +938,8 @@
     return buffer.toString();
   }
 
-  static Iterable where(Iterable iterable, bool f(var element)) {
-    return new WhereIterable(iterable, f);
+  Iterable<T> where(Iterable iterable, bool f(var element)) {
+    return new WhereIterable<T>(iterable, f);
   }
 
   static Iterable map(Iterable iterable, f(var element)) {
@@ -950,28 +954,28 @@
     return new ExpandIterable(iterable, f);
   }
 
-  static Iterable takeList(List list, int n) {
+  Iterable<T> takeList(List list, int n) {
     // The generic type is currently lost. It will be fixed with mixins.
-    return new SubListIterable(list, 0, n);
+    return new SubListIterable<T>(list, 0, n);
   }
 
-  static Iterable takeWhile(Iterable iterable, bool test(var value)) {
+  Iterable<T> takeWhile(Iterable iterable, bool test(var value)) {
     // The generic type is currently lost. It will be fixed with mixins.
-    return new TakeWhileIterable(iterable, test);
+    return new TakeWhileIterable<T>(iterable, test);
   }
 
-  static Iterable skipList(List list, int n) {
+  Iterable<T> skipList(List list, int n) {
     // The generic type is currently lost. It will be fixed with mixins.
-    return new SubListIterable(list, n, null);
+    return new SubListIterable<T>(list, n, null);
   }
 
-  static Iterable skipWhile(Iterable iterable, bool test(var value)) {
+  Iterable<T> skipWhile(Iterable iterable, bool test(var value)) {
     // The generic type is currently lost. It will be fixed with mixins.
-    return new SkipWhileIterable(iterable, test);
+    return new SkipWhileIterable<T>(iterable, test);
   }
 
-  static Iterable reversedList(List list) {
-    return new ReversedListIterable(list);
+  Iterable<T> reversedList(List list) {
+    return new ReversedListIterable<T>(list);
   }
 
   static void sortList(List list, int compare(a, b)) {
@@ -1009,10 +1013,10 @@
     }
   }
 
-  static Iterable getRangeList(List list, int start, int end) {
+  Iterable<T> getRangeList(List list, int start, int end) {
     _rangeCheck(list, start, end);
     // The generic type is currently lost. It will be fixed with mixins.
-    return new SubListIterable(list, start, end);
+    return new SubListIterable<T>(list, start, end);
   }
 
   static void setRangeList(List list, int start, int end,
@@ -1097,8 +1101,8 @@
     }
   }
 
-  static Map<int, dynamic> asMapList(List l) {
-    return new ListMapView(l);
+  Map<int, T> asMapList(List l) {
+    return new ListMapView<T>(l);
   }
 
   static bool setContainsAll(Set set, Iterable other) {
diff --git a/sdk/lib/internal/list.dart b/sdk/lib/internal/list.dart
index 473a87a..43e7e6a 100644
--- a/sdk/lib/internal/list.dart
+++ b/sdk/lib/internal/list.dart
@@ -295,6 +295,8 @@
   void addAll(Map<int, E> other) {
     throw new UnsupportedError("Cannot modify an unmodifiable map");
   }
+
+  String toString() => Maps.mapToString(this);
 }
 
 class ReversedListIterable<E> extends ListIterable<E> {
diff --git a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
index a465276..1af28e2 100644
--- a/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_backend_test.dart
@@ -6,51 +6,13 @@
 import 'dart:async';
 import "package:async_helper/async_helper.dart";
 import '../mock_compiler.dart';
+import '../mock_libraries.dart';
 import 'package:compiler/compiler.dart';
 import 'package:compiler/implementation/dart2jslib.dart' as leg;
 import 'package:compiler/implementation/dart_backend/dart_backend.dart';
 import 'package:compiler/implementation/elements/elements.dart';
 import 'package:compiler/implementation/tree/tree.dart';
 
-const coreLib = r'''
-library corelib;
-class Object {
-  Object();
-}
-class bool {}
-class num {}
-class int extends num {}
-class double extends num {}
-abstract class String {}
-class Function {}
-class List<T> {}
-class Map<K,V> {}
-class BoundClosure {}
-class Closure {}
-class Dynamic_ {}
-class Null {}
-class TypeError {}
-class Type {}
-class StackTrace {}
-class LinkedHashMap {
-  factory LinkedHashMap._empty() => null;
-  factory LinkedHashMap._literal(elements) => null;
-}
-class Math {
-  static double parseDouble(String s) => 1.0;
-}
-print(x) {}
-identical(a, b) => true;
-const proxy = 0;
-''';
-
-const corePatch = r'''
-import 'dart:_js_helper';
-import 'dart:_interceptors';
-import 'dart:_isolate_helper';
-import 'dart:_foreign_helper';
-''';
-
 const ioLib = r'''
 library io;
 class Platform {
@@ -70,24 +32,6 @@
 }
 ''';
 
-const helperLib = r'''
-library js_helper;
-class JSInvocationMirror {}
-assertHelper(a) {}
-class Closure {}
-class BoundClosure {}
-const patch = 0;
-''';
-
-const foreignLib = r'''
-var JS;
-''';
-
-const isolateHelperLib = r'''
-class _WorkerStub {
-}
-''';
-
 testDart2Dart(String src, {void continuation(String s), bool minify: false,
     bool stripTypes: false}) {
   // If continuation is not provided, check that source string remains the same.
@@ -116,20 +60,22 @@
       return new Future.value(srcLibrary);
     }
     if (uri.path.endsWith('/core.dart')) {
-      return new Future.value(coreLib);
+      return new Future.value(buildLibrarySource(DEFAULT_CORE_LIBRARY));
     } else if (uri.path.endsWith('/core_patch.dart')) {
-      return new Future.value(corePatch);
+      return new Future.value(DEFAULT_PATCH_CORE_SOURCE);
     } else if (uri.path.endsWith('/io.dart')) {
       return new Future.value(ioLib);
     } else if (uri.path.endsWith('/js_helper.dart')) {
-      return new Future.value(helperLib);
+      return new Future.value(buildLibrarySource(DEFAULT_JS_HELPER_LIBRARY));
     } else if (uri.path.endsWith('/html_dart2js.dart')) {
       // TODO(smok): The file should change to html_dartium at some point.
       return new Future.value(htmlLib);
     } else if (uri.path.endsWith('/foreign_helper.dart')) {
-      return new Future.value(foreignLib);
+      return new Future.value(
+          buildLibrarySource(DEFAULT_FOREIGN_HELPER_LIBRARY));
     } else if (uri.path.endsWith('/isolate_helper.dart')) {
-      return new Future.value(isolateHelperLib);
+      return new Future.value(
+          buildLibrarySource(DEFAULT_ISOLATE_HELPER_LIBRARY));
     }
     return new Future.value('');
   }
@@ -590,7 +536,7 @@
 testStaticInvocation() {
   testDart2Dart('''
 main() {
-  var x = Math.parseDouble("1");
+  var x = double.parseDouble("1");
 }
 ''');
 }
diff --git a/tests/compiler/dart2js/backend_dart/sexpr_test.dart b/tests/compiler/dart2js/backend_dart/sexpr_test.dart
new file mode 100644
index 0000000..a2bb628
--- /dev/null
+++ b/tests/compiler/dart2js/backend_dart/sexpr_test.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../compiler_helper.dart';
+import 'dart:async';
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import 'package:compiler/implementation/dart2jslib.dart';
+import 'package:compiler/implementation/cps_ir/cps_ir_nodes.dart';
+import 'package:compiler/implementation/cps_ir/cps_ir_nodes_sexpr.dart';
+import 'package:compiler/implementation/dart_backend/dart_backend.dart';
+
+const String CODE = """
+class Foo {
+  static int x = 1;
+  foo() => 42;
+}
+
+class Bar extends Foo {
+  int y = 2;
+  Bar() {
+    Foo.x = 2;
+  }
+  foo() =>  this.y + super.foo();
+} 
+
+class FooBar<T> {
+  bool foobar() => T is int;
+}
+
+main() {
+  Foo foo;
+  if (foo is Foo) {
+    print("Surprise");
+  }
+
+  String inner() => "Inner function";
+  print(inner());
+
+  int j = 42;
+  for (int i = 0; i < 2; i++) {
+    print(i.toString());
+  }
+
+  print(Foo.x);
+
+  String recursive(int h) {
+    if (h < 1) {
+      return j.toString();
+    }
+    j++;
+    return "h\$\{recursive(h - 1)\}";
+  }
+  print(recursive(5));
+
+  Bar bar = new Bar();
+  print(bar.foo().toString());
+
+  bar = foo as Bar;
+  if (bar == null) {
+    var list = [1, 2, 3, 4];
+    var map  = { 1: "one"
+               , 2: "two"
+               , 3: "three"
+               };
+    var double = 3.14;
+    print("\$list \$map \$double");
+  }
+
+  print(new FooBar<int>().foobar());
+}
+
+""";
+
+bool shouldOutput(Element element) {
+  return (!element.library.isPlatformLibrary &&
+          !element.isSynthesized &&
+          element.kind == ElementKind.FUNCTION);
+}
+
+/// Compiles the given dart code (which must include a 'main' function) and
+/// returns a list of all generated CPS IR definitions.
+Future<List<FunctionDefinition>> compile(String code) {
+  MockCompiler compiler = new MockCompiler.internal(
+      emitJavaScript: false,
+      enableMinification: false);
+
+  return compiler.init().then((_) {
+    compiler.parseScript(code);
+
+    Element element = compiler.mainApp.find('main');
+    if (element == null) return null;
+
+    compiler.mainFunction = element;
+    compiler.phase = Compiler.PHASE_RESOLVING;
+    compiler.backend.enqueueHelpers(compiler.enqueuer.resolution,
+                                    compiler.globalDependencies);
+    compiler.processQueue(compiler.enqueuer.resolution, element);
+    compiler.world.populate();
+    compiler.backend.onResolutionComplete();
+
+    compiler.irBuilder.buildNodes(useNewBackend: true);
+
+    return compiler.enqueuer.resolution.resolvedElements
+              .where(shouldOutput)
+              .map(compiler.irBuilder.getIr)
+              .toList();
+  });
+}
+
+Future<String> testStringifier(String code, List<String> expectedTokens) {
+  return compile(code)
+      .then((List<FunctionDefinition> functions) {
+        final stringifier = new SExpressionStringifier();
+        return functions.map((f) {
+          String sexpr = stringifier.visitFunctionDefinition(f);
+          Expect.isNotNull(sexpr, "S-expression generation failed");
+          return sexpr;
+        }).join("\n");
+      })
+      .then((String sexpr) {
+        Expect.isFalse(sexpr.replaceAll("Constant null", "").contains("null"),
+                       "Output contains 'null':\n\n$sexpr");
+
+        expectedTokens.forEach((String token) {
+          Expect.isTrue(sexpr.contains(token),
+                        "Expected token '$token' not present:\n\n$sexpr");
+        });
+
+        return sexpr;
+      });
+}
+
+void main() {
+  final tokens =
+          [ "FunctionDefinition"
+          , "IsTrue"
+
+          // Expressions
+          , "Branch"
+          , "ConcatenateStrings"
+          , "DeclareFunction"
+          , "InvokeConstructor"
+          , "InvokeContinuation"
+          , "InvokeMethod"
+          , "InvokeStatic"
+          , "InvokeSuperMethod"
+          , "LetCont"
+          , "LetPrim"
+          , "SetClosureVariable"
+          , "TypeOperator"
+
+          // Primitives
+          , "Constant"
+          , "CreateFunction"
+          , "GetClosureVariable"
+          , "LiteralList"
+          , "LiteralMap"
+          // Parameters are encoded by name only and hence are not in this list.
+          , "ReifyTypeVar"
+          , "This"
+          ];
+
+  asyncTest(() => testStringifier(CODE, tokens));
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
new file mode 100644
index 0000000..72b26ab
--- /dev/null
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Unit test of the [NativeBehavior.processSpecString] method.
+
+import 'package:expect/expect.dart';
+import 'package:compiler/implementation/native_handler.dart';
+import 'package:compiler/implementation/dart2jslib.dart'
+    show DiagnosticListener;
+
+const OBJECT = 'Object';
+const NULL = 'Null';
+
+class Listener implements DiagnosticListener {
+  String errorMessage;
+  internalError(spannable, message) => errorMessage = message;
+
+  noSuchMethod(_) => null;
+}
+
+void test(String specString,
+          {List returns,
+           List creates,
+           bool expectError: false}) {
+  List actualReturns = [];
+  List actualCreates = [];
+  Listener listener = new Listener();
+  NativeBehavior.processSpecString(
+      listener,
+      null,
+      specString,
+      resolveType: (t) => t,
+      typesReturned: actualReturns, typesInstantiated: actualCreates,
+      objectType: OBJECT, nullType: NULL);
+  if (expectError) {
+    Expect.isNotNull(listener.errorMessage, 'Internal error expected.');
+  } else {
+    Expect.isNull(listener.errorMessage, 'Unexpected internal error.');
+    Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
+    Expect.listEquals(creates, actualCreates, 'Unexpected creates.');
+  }
+}
+
+void main() {
+  test('void', returns: [], creates: []);
+  test('', returns: [OBJECT, NULL], creates: []);
+  test('var', returns: [OBJECT, NULL], creates: []);
+  test('A', returns: ['A'], creates: ['A']);
+  test('A|B', returns: ['A', 'B'], creates: ['A', 'B']);
+  test('A|B|C', returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
+
+  test('returns:void;', returns: [], creates: []);
+  test('returns:;', returns: [OBJECT, NULL], creates: []);
+  test('returns:var;', returns: [OBJECT, NULL], creates: []);
+  test('returns:A;', returns: ['A'], creates: []);
+  test('returns:A|B;', returns: ['A', 'B'], creates: []);
+  test('returns:A|B|C;', returns: ['A', 'B', 'C'], creates: []);
+
+  test('creates:void;', expectError: true);
+  test('creates:;', expectError: true);
+  test('creates:var;', expectError: true);
+  test('creates:A;', returns: [], creates: ['A']);
+  test('creates:A|B;', returns: [], creates: ['A', 'B']);
+  test('creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
+
+  test('returns:void;creates:A;', returns: [], creates: ['A']);
+  test('returns:;creates:A|B;', returns: [OBJECT, NULL], creates: ['A', 'B']);
+  test('returns:var;creates:A|B|C;',
+      returns: [OBJECT, NULL], creates: ['A', 'B', 'C']);
+  test('returns:A; creates:A|B|C; ', returns: ['A'], creates: ['A', 'B', 'C']);
+  test(' returns:A|B;  creates:A|C;',
+      returns: ['A', 'B'], creates: ['A', 'C']);
+  test(' returns:A|B|C;   creates:A;  ',
+      returns: ['A', 'B', 'C'], creates: ['A']);
+}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index c68c58c..d700601 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -198,10 +198,11 @@
 
   CollectingTreeElements resolveStatement(String text) {
     parsedTree = parseStatement(text);
-    return resolveNodeStatement(parsedTree, mainApp);
+    return resolveNodeStatement(parsedTree, new MockElement(mainApp));
   }
 
-  TreeElementMapping resolveNodeStatement(Node tree, Element element) {
+  TreeElementMapping resolveNodeStatement(Node tree,
+                                          ExecutableElement element) {
     ResolverVisitor visitor =
         new ResolverVisitor(this, element,
             new ResolutionRegistry.internal(this,
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 1cb57dd..9174ae5 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -152,6 +152,7 @@
   'listTypeCast': 'listTypeCast(value) {}',
   'listTypeCheck': 'listTypeCheck(value) {}',
   'makeLiteralMap': 'makeLiteralMap(List keyValuePairs) {}',
+  'Native': 'class Native {}',
   'NoInline': 'class NoInline {}',
   'NoSideEffects': 'class NoSideEffects {}',
   'NoThrows': 'class NoThrows {}',
@@ -287,14 +288,14 @@
         operator |(other) => 42;
         operator &(other) => 42;
         operator ^(other) => 42;
-    
+
         operator >(other) => true;
         operator >=(other) => true;
         operator <(other) => true;
         operator <=(other) => true;
         operator ==(other) => true;
         get hashCode => throw "JSNumber.hashCode not implemented.";
-    
+
         // We force side effects on _tdivFast to mimic the shortcomings of
         // the effect analysis: because the `_tdivFast` implementation of
         // the core library has calls that may not already be analyzed,
@@ -305,7 +306,7 @@
         _shrBothPositive(other) => 42;
         _shrReceiverPositive(other) => 42;
         _shrOtherPositive(other) => 42;
-    
+
         abs() => (this is JSInt) ? 42 : 42.2;
         remainder(other) => (this is JSInt) ? 42 : 42.2;
         truncate() => 42;
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 6515eee..7f634e4 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -2140,7 +2140,7 @@
 }
 
 analyzeIn(MockCompiler compiler,
-          Element element,
+          ExecutableElement element,
           String text,
           [expectedWarnings]) {
   if (expectedWarnings == null) expectedWarnings = [];
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index fd54729..e955036 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -40,6 +40,7 @@
 to_string_test: Fail # Issue 7179.
 runtime_type_test: Fail, OK # Tests extected output of Type.toString().
 code_motion_exception_test: Skip  # Requires unminified operator names.
+mirrors_used_warning_test/minif: Fail, OK # Tests warning that minified code will be broken.
 
 [ $compiler == dart2js && ($runtime == drt || $runtime == ff || $runtime == safari || $runtime == jsshell) ]
 code_motion_exception_test: Skip  # Required V8 specific format of JavaScript errors.
diff --git a/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart b/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart
new file mode 100644
index 0000000..1ac19d6
--- /dev/null
+++ b/tests/compiler/dart2js_extra/mirrors_used_warning2_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:mirrors';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(Invocation invocation) {
+    return MirrorSystem.getName(invocation.memberName);
+  }
+}
+
+var lines = [];
+capturePrint(Zone self, ZoneDelegate parent, Zone origin, line) {
+  lines.add(line);
+}
+
+runTests() {
+  // No MirrorsUsed annotation anywhere.
+  // Dart2js should retain all symbols.
+  Expect.equals("foo", new A().foo);
+  Expect.isTrue(lines.isEmpty);
+  var barResult = new A().bar;
+  Expect.equals("bar", barResult);
+  Expect.isTrue(lines.isEmpty);
+}
+
+main() {
+  runZoned(runTests,
+           zoneSpecification: new ZoneSpecification(print: capturePrint));
+}
diff --git a/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart b/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart
new file mode 100644
index 0000000..343e090
--- /dev/null
+++ b/tests/compiler/dart2js_extra/mirrors_used_warning_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@MirrorsUsed(symbols: 'foo')
+import 'dart:mirrors';
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(Invocation invocation) {
+    return MirrorSystem.getName(invocation.memberName);
+  }
+}
+
+var lines = [];
+capturePrint(Zone self, ZoneDelegate parent, Zone origin, line) {
+  lines.add(line);
+}
+
+runTests() {
+  // "foo" is in MirrorsUsed and should therefore always work.
+  Expect.equals("foo", new A().foo);
+  Expect.isTrue(lines.isEmpty);
+  var barResult = new A().bar;
+  Expect.equals("bar", barResult);           /// minif: ok
+  Expect.isTrue(lines.length == 1);
+  var line = lines.first;
+  Expect.isTrue(line.contains("Warning") &&
+                line.contains("bar") &&      /// minif: continued
+                line.contains("minif"));
+}
+
+main() {
+  runZoned(runTests,
+           zoneSpecification: new ZoneSpecification(print: capturePrint));
+}
diff --git a/tests/compiler/dart2js_native/abstract_class_test.dart b/tests/compiler/dart2js_native/abstract_class_test.dart
index 6a5989c..df5738c 100644
--- a/tests/compiler/dart2js_native/abstract_class_test.dart
+++ b/tests/compiler/dart2js_native/abstract_class_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Native classes can have subclasses that are not declared to the program.  The
 // subclasses are indistinguishable from the base class.  This means that
 // abstract native classes can appear to have instances.
 
-abstract class A native "A" {
+@Native("A")
+abstract class A {
 }
 
-abstract class B native "B" {
+@Native("B")
+abstract class B {
   foo() native;
 }
 
diff --git a/tests/compiler/dart2js_native/bound_closure_test.dart b/tests/compiler/dart2js_native/bound_closure_test.dart
index 4be2c80..afbecce 100644
--- a/tests/compiler/dart2js_native/bound_closure_test.dart
+++ b/tests/compiler/dart2js_native/bound_closure_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test calling convention of property extraction closures.
@@ -11,11 +12,13 @@
   foo(a, [b = 'A']) => 'AA.foo($a, $b)';   // foo has interceptor convention.
 }
 
-class BB native "BB" {
+@Native("BB")
+class BB {
   foo(a, [b = 'B']) native;
 }
 
-class CC extends BB native "CC" {
+@Native("CC")
+class CC extends BB {
   foo(a, [b = 'C']) native;
 
   get superfoo => super.foo;
diff --git a/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart b/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
index abeb7d6..36b7f9b 100644
--- a/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_1_prepatched_test.dart
@@ -2,19 +2,23 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 //import 'dart:_foreign_helper' show JS;
 //import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
 
 // Test for dartNativeDispatchHooksTransformer, getTag hook.
 
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
 }
 
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
 }
 
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
 }
 
 makeT1A() native;
diff --git a/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart b/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
index 8db4d43..56c9fb8 100644
--- a/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_1_unpatched_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 //import 'dart:_foreign_helper' show JS;
 //import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
@@ -9,13 +10,16 @@
 // Test for dartNativeDispatchHooksTransformer, getTag hook.
 // Same as browser_compat_1_prepatched_test but with prepatching disabled.
 
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
 }
 
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
 }
 
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
 }
 
 makeT1A() native;
diff --git a/tests/compiler/dart2js_native/browser_compat_2_test.dart b/tests/compiler/dart2js_native/browser_compat_2_test.dart
index 297da7c..858a067 100644
--- a/tests/compiler/dart2js_native/browser_compat_2_test.dart
+++ b/tests/compiler/dart2js_native/browser_compat_2_test.dart
@@ -2,25 +2,30 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for dartNativeDispatchHooksTransformer
 //  - uncached, instance, leaf and interior caching modes.
 //  - composition of getTag.
 
-class T1A native "T1A" {
+@Native("T1A")
+class T1A {
   foo() native;
 }
 
-class T1B native "T1B" {
+@Native("T1B")
+class T1B {
   foo() native;
 }
 
-class T1C native "T1C" {
+@Native("T1C")
+class T1C {
   foo() native;
 }
 
-class T1D native "T1D" {
+@Native("T1D")
+class T1D {
   foo() native;
 }
 
diff --git a/tests/compiler/dart2js_native/call_on_native_class_test.dart b/tests/compiler/dart2js_native/call_on_native_class_test.dart
index 3b07cf6..5142982 100644
--- a/tests/compiler/dart2js_native/call_on_native_class_test.dart
+++ b/tests/compiler/dart2js_native/call_on_native_class_test.dart
@@ -2,10 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-class A native '*A' {
+import 'dart:_js_helper';
+
+@Native('*A')
+class A {
 }
 
-class B extends A{
+class B extends A {
   call() => 42;
 }
 
diff --git a/tests/compiler/dart2js_native/core_type_check_native_test.dart b/tests/compiler/dart2js_native/core_type_check_native_test.dart
index 11890a1..41a4109 100644
--- a/tests/compiler/dart2js_native/core_type_check_native_test.dart
+++ b/tests/compiler/dart2js_native/core_type_check_native_test.dart
@@ -2,20 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 var inscrutable = (int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
 
-class A native "A" {
+@Native("A")
+class A {
 }
 
-class B implements Comparable native "B" {
+@Native("B")
+class B implements Comparable {
 }
 
-class C implements Pattern native "C" {
+@Native("C")
+class C implements Pattern {
 }
 
-class D implements Pattern, Comparable native "D" {
+@Native("D")
+class D implements Pattern, Comparable {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/downcast_test.dart b/tests/compiler/dart2js_native/downcast_test.dart
index 27ec4b2..6810a612 100644
--- a/tests/compiler/dart2js_native/downcast_test.dart
+++ b/tests/compiler/dart2js_native/downcast_test.dart
@@ -4,6 +4,7 @@
 
 // Test for downcasts on native classes.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 abstract class J {
@@ -16,13 +17,15 @@
 
 // Native implementation.
 
-class A implements I native "A" {
+@Native("A")
+class A implements I {
   // The native class accepts only other native instances.
   A read() native;
   write(A x) native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/field_type2_test.dart b/tests/compiler/dart2js_native/field_type2_test.dart
index 15dbf61..6f8c35b 100644
--- a/tests/compiler/dart2js_native/field_type2_test.dart
+++ b/tests/compiler/dart2js_native/field_type2_test.dart
@@ -5,7 +5,10 @@
 // Test that a closure call on a native field is recognized by the
 // type inferrer.
 
-class Node native "Node" {
+import 'dart:_js_helper';
+
+@Native("Node")
+class Node {
   final parentNode;
 }
 
diff --git a/tests/compiler/dart2js_native/field_type_test.dart b/tests/compiler/dart2js_native/field_type_test.dart
index bd2b1c1..75297ad 100644
--- a/tests/compiler/dart2js_native/field_type_test.dart
+++ b/tests/compiler/dart2js_native/field_type_test.dart
@@ -6,9 +6,11 @@
 // This regression test verifies that compiler accounts for hidden constructor
 // when analysing field values.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
-class Node native "Node" {
+@Native("Node")
+class Node {
 
   final Node parentNode;
 
diff --git a/tests/compiler/dart2js_native/fixup_get_tag_test.dart b/tests/compiler/dart2js_native/fixup_get_tag_test.dart
index 957fd25..0f68986 100644
--- a/tests/compiler/dart2js_native/fixup_get_tag_test.dart
+++ b/tests/compiler/dart2js_native/fixup_get_tag_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for dartExperimentalFixupGetTag.
 
-class Foo native "A" { // There is one native class with dispatch tag 'A'.
+@Native("A")
+class Foo { // There is one native class with dispatch tag 'A'.
   token() native;
 }
 
diff --git a/tests/compiler/dart2js_native/hash_code_test.dart b/tests/compiler/dart2js_native/hash_code_test.dart
index c222de6..452c7aa 100644
--- a/tests/compiler/dart2js_native/hash_code_test.dart
+++ b/tests/compiler/dart2js_native/hash_code_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {}
+@Native("A")
+class A {}
 makeA() native;
 
 void setup() native """
diff --git a/tests/compiler/dart2js_native/is_check_test.dart b/tests/compiler/dart2js_native/is_check_test.dart
index db04502..ecc42b2 100644
--- a/tests/compiler/dart2js_native/is_check_test.dart
+++ b/tests/compiler/dart2js_native/is_check_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {}
+@Native("A")
+class A {}
 
 main() {
   var a = [new Object()];
diff --git a/tests/compiler/dart2js_native/issue9182_test.dart b/tests/compiler/dart2js_native/issue9182_test.dart
index 8d2734b..8bbee65 100644
--- a/tests/compiler/dart2js_native/issue9182_test.dart
+++ b/tests/compiler/dart2js_native/issue9182_test.dart
@@ -5,9 +5,11 @@
 // Regression test for Issue 9182.  The generative constructor body function
 // should not have the interceptor calling convention.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
-class Foo native "A" {
+@Native("A")
+class Foo {
   factory Foo() => makeA();
   // Ensure the instance method 'Bar' uses interceptor convention.
   Bar() => 123;
diff --git a/tests/compiler/dart2js_native/jsobject_test.dart b/tests/compiler/dart2js_native/jsobject_test.dart
index a63320e..dd3c991 100644
--- a/tests/compiler/dart2js_native/jsobject_test.dart
+++ b/tests/compiler/dart2js_native/jsobject_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
     JSObject,                 // The interface, which may be re-exported by a
                               // js-interop library.
diff --git a/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart b/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
index a56cbb0..a9cb2e0 100644
--- a/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
+++ b/tests/compiler/dart2js_native/mirror_intercepted_field_test.dart
@@ -3,9 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:mirrors';
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
-class B native "B" {
+@Native("B")
+class B {
   // Having this field in a native class will generate accessors with
   // the interceptor calling convention.
   var f;
diff --git a/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
index 285e349..b4cf449 100644
--- a/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity1_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native methods with unnamed* optional arguments are called with the
@@ -12,11 +13,13 @@
 // * Optional positional arguments are passed in the correct position, so
 // require preceding arguments to be passed.
 
-class A native "A" {
+@Native("A")
+class A {
   int foo(int x) native;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   int foo([x, y, z]) native;
 }
 
diff --git a/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
index 7941775..245c03c 100644
--- a/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity2_frog_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // This is a similar test to NativeCallArity1FrogTest, but makes sure
 // that subclasses also get the right number of arguments.
 
-class A native "A" {
+@Native("A")
+class A {
   int foo([x, y]) native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   int foo([x, y]) native;
 }
 
diff --git a/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart b/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
index 59c35af..0257ed9 100644
--- a/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_call_arity3_frog_test.dart
@@ -2,17 +2,20 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Test similar to NativeCallArity1FrogTest, but with default values to
 // parameters set to null. These parameters should be treated as if they
 // do not have a default value for the native methods.
 
-class A native "A" {
+@Native("A")
+class A {
   int foo(int x) native;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   int foo([x = null, y, z = null]) native;
 }
 
diff --git a/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart b/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
index 3edf17b..d87558d 100644
--- a/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_checked_arguments1_frog_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that type checks occur on native methods.
 
-class A native "A" {
+@Native("A")
+class A {
   int foo(int x) native;
   int cmp(A other) native;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   String foo(String x) native;
   int cmp(B other) native;
 }
diff --git a/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart b/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
index 22b9c7a..7648da4 100644
--- a/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_checked_fields_frog_test.dart
@@ -2,15 +2,18 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that type checks occur on assignment to fields of native methods.
 
-class A native "A" {
+@Native("A")
+class A {
   int foo;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   String foo;
 }
 
diff --git a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
index 1d3b04b..e78544a 100644
--- a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that hidden native class names are not used by generated code.
 
-class AA native "BB" {
+@Native("BB")
+class AA {
   get name => 'AA';
   static AA create() => makeA();
 }
 
-class BB native "CC" {
+@Native("CC")
+class BB {
   get name => 'BB';
   static BB create() => makeB();
 }
diff --git a/tests/compiler/dart2js_native/native_class_fields_2_test.dart b/tests/compiler/dart2js_native/native_class_fields_2_test.dart
index b7ddbf7..4e67b81 100644
--- a/tests/compiler/dart2js_native/native_class_fields_2_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_2_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Verify that methods are not renamed to clash with native field names
 // that are known from the DOM (like x, y, z).
-class A native "A" {
+@Native("A")
+class A {
   int x;
   int y;
   int z;
diff --git a/tests/compiler/dart2js_native/native_class_fields_3_test.dart b/tests/compiler/dart2js_native/native_class_fields_3_test.dart
index cbd97a9..bfee4a7 100644
--- a/tests/compiler/dart2js_native/native_class_fields_3_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_3_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Verify that we can have fields with names that start with g and s even
@@ -12,7 +13,8 @@
 // names for clashes because it's hard - subclasses can force superclasses
 // to rename getters, and that can force unrelated classes to change their
 // getters too if they have a property that has the same name.
-class A native "A" {
+@Native("A")
+class A {
   int bar;
   int g;
   int s;
diff --git a/tests/compiler/dart2js_native/native_class_fields_test.dart b/tests/compiler/dart2js_native/native_class_fields_test.dart
index 309654a..110d6c5 100644
--- a/tests/compiler/dart2js_native/native_class_fields_test.dart
+++ b/tests/compiler/dart2js_native/native_class_fields_test.dart
@@ -2,10 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Verify that native fields on classes are not renamed by the minifier.
-class A native "A" {
+@Native("A")
+class A {
   int myLongPropertyName;
   int getValue;
 
@@ -21,7 +23,7 @@
 function setter(x) {
   this.getValue += 10;
 }
-  
+
 function A(){
   var a = Object.create(
       { constructor: { name: 'A'}},
diff --git a/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
index 75a1032..65085cc 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance1_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test to see if resolving a hidden native class's method interferes with
@@ -10,11 +11,13 @@
 // stored on Object.prototype.
 
 // Version 1: It might be possible to call foo directly.
-class A1 native "A1" {
+@Native("A1")
+class A1 {
   foo() native;
 }
 
-class B1 extends A1 native "B1" {
+@Native("B1")
+class B1 extends A1 {
   foo() native;
 }
 
@@ -23,11 +26,13 @@
 
 
 // Version 2: foo needs some kind of trampoline.
-class A2 native "A2" {
+@Native("A2")
+class A2 {
   foo([a=99]) native;
 }
 
-class B2 extends A2 native "B2" {
+@Native("B2")
+class B2 extends A2 {
   foo([z=1000]) native;
 }
 
diff --git a/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
index 7177573..bb5d7fb 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance2_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test to see if resolving a hidden native class's method interferes with
@@ -9,18 +10,22 @@
 // superclass caches the method in the prototype, so shadowing the dispatcher
 // stored on Object.prototype.
 
-class A native "A" {
+@Native("A")
+class A {
   foo([a=100]) native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
 }
 
-class C extends B native "C" {
+@Native("C")
+class C extends B {
   foo([z=300]) native;
 }
 
-class D extends C native "D" {
+@Native("D")
+class D extends C {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
index aff6345..320da8c 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance3_frog_test.dart
@@ -2,27 +2,32 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Test to see if resolving a hidden native class's method to noSuchMethod
 // interferes with subsequent resolving of the method.  This might happen if the
 // noSuchMethod is cached on Object.prototype.
 
-class A1 native "A1" {
+@Native("A1")
+class A1 {
 }
 
-class B1 extends A1 native "B1" {
+@Native("B1")
+class B1 extends A1 {
 }
 
 makeA1() native;
 makeB1() native;
 
 
-class A2 native "A2" {
+@Native("A2")
+class A2 {
   foo([a=99]) native;
 }
 
-class B2 extends A2 native "B2" {
+@Native("B2")
+class B2 extends A2 {
 }
 
 makeA2() native;
diff --git a/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart b/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
index b243c59..fcd1e3a 100644
--- a/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_inheritance4_frog_test.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Additional Dart code may be 'placed on' hidden native classes.  With
 // inheritance, the superclass method must not be reached by a call on the
 // subclass.
 
-class A native "A" {
+@Native("A")
+class A {
   var _field;
 
   int get X => _field;
@@ -17,7 +19,8 @@
   int method(int z) => _field + z;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   var _field2;
 
   int get X => _field2;
diff --git a/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart b/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
index e01fa1a..32d84bf 100644
--- a/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_is_check1_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for correct simple is-checks on hidden native classes.
@@ -13,7 +14,8 @@
 
 // Native implementation.
 
-class A implements I native "A" {
+@Native("A")
+class A implements I {
   // The native class accepts only other native instances.
   A read() native;
   write(A x) native;
diff --git a/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart b/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
index 490e820..4a9c64d 100644
--- a/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_is_check3_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for correct simple is-checks on hidden native classes.
@@ -16,13 +17,15 @@
 
 // Native implementation.
 
-class A implements I native "A" {
+@Native("A")
+class A implements I {
   // The native class accepts only other native instances.
   A read() native;
   write(A x) native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart b/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
index c5519e9..eb9fd25 100644
--- a/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_with_dart_methods_frog_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Additional Dart code may be 'placed on' hidden native classes.
 
-class A native "A" {
+@Native("A")
+class A {
 
   var _field;
 
diff --git a/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart b/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
index 84b379b..943b063 100644
--- a/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_closure_identity_frog_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 typedef void MyFunctionType();
 
-class A native "A" {
+@Native("A")
+class A {
   setClosure(MyFunctionType f) native;
   check(MyFunctionType f) native;
   invoke() native;
diff --git a/tests/compiler/dart2js_native/native_constructor_name_test.dart b/tests/compiler/dart2js_native/native_constructor_name_test.dart
index 1a88b65..07a7a95 100644
--- a/tests/compiler/dart2js_native/native_constructor_name_test.dart
+++ b/tests/compiler/dart2js_native/native_constructor_name_test.dart
@@ -8,12 +8,14 @@
 // This could be done by renaming the Dart constructor or by being able to check
 // that objects are Dart classes.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 class A {
 }
 
-class Z native "A" {
+@Native("A")
+class Z {
   foo() => 100;
 }
 
diff --git a/tests/compiler/dart2js_native/native_equals_frog_test.dart b/tests/compiler/dart2js_native/native_equals_frog_test.dart
index 9d04fc4..0d1980a 100644
--- a/tests/compiler/dart2js_native/native_equals_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_equals_frog_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {}
+@Native("A")
+class A {}
 makeA() native;
 
 void setup() native """
diff --git a/tests/compiler/dart2js_native/native_exception2_test.dart b/tests/compiler/dart2js_native/native_exception2_test.dart
index 6f26332..113e9ef 100644
--- a/tests/compiler/dart2js_native/native_exception2_test.dart
+++ b/tests/compiler/dart2js_native/native_exception2_test.dart
@@ -8,8 +8,10 @@
 library native_exception2_test;
 
 import 'native_exception_test.dart' as other;
+import 'dart:_js_helper';
 
-class NativeClass native "NativeClass" {
+@Native("NativeClass")
+class NativeClass {
 }
 
 makeNativeClass() native;
diff --git a/tests/compiler/dart2js_native/native_exception_test.dart b/tests/compiler/dart2js_native/native_exception_test.dart
index 9b1d346..e3d2231 100644
--- a/tests/compiler/dart2js_native/native_exception_test.dart
+++ b/tests/compiler/dart2js_native/native_exception_test.dart
@@ -7,8 +7,8 @@
 library native_exception_test;
 
 import 'dart:_foreign_helper' show JS;
-
-import "package:expect/expect.dart";
+import 'dart:_js_helper';
+import 'package:expect/expect.dart';
 
 main() {
   var previous;
diff --git a/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart b/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
index a72911d..aa3c3d6 100644
--- a/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_exceptions1_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that hidden native exception classes can be marked as existing.
@@ -17,14 +18,16 @@
 
 
 // The exception type.
-class E native "E" {
+@Native("E")
+class E {
   E._used() native;  // Bogus native constructor, called only from fake body.
 
   final int code;
 }
 
 // Type with exception-throwing methods.
-class A native "A" {
+@Native("A")
+class A {
   op(int x) native {
     // Fake body calls constructor to mark the exception class (E) as used.
     throw new E._used();
diff --git a/tests/compiler/dart2js_native/native_field_invocation2_test.dart b/tests/compiler/dart2js_native/native_field_invocation2_test.dart
index 29c261c..7b6dc90 100644
--- a/tests/compiler/dart2js_native/native_field_invocation2_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation2_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class NNative native "NNative" {
+@Native("NNative")
+class NNative {
   var status;
 
   var f;
diff --git a/tests/compiler/dart2js_native/native_field_invocation3_test.dart b/tests/compiler/dart2js_native/native_field_invocation3_test.dart
index 5946db7..f0559b6 100644
--- a/tests/compiler/dart2js_native/native_field_invocation3_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation3_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 makeCC() native;
@@ -12,7 +13,8 @@
 """;
 
 
-class ClickCounter native "CC" {
+@Native("CC")
+class ClickCounter {
   var status;
 
   var foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation4_test.dart b/tests/compiler/dart2js_native/native_field_invocation4_test.dart
index 2840926..e0a5c00 100644
--- a/tests/compiler/dart2js_native/native_field_invocation4_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation4_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
   var foo;
 }
 
diff --git a/tests/compiler/dart2js_native/native_field_invocation5_test.dart b/tests/compiler/dart2js_native/native_field_invocation5_test.dart
index 8288344..e5a0440 100644
--- a/tests/compiler/dart2js_native/native_field_invocation5_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation5_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 makeCC() native;
@@ -17,7 +18,8 @@
   foo(x) => x;
 }
 
-class ClickCounter native "CC" {
+@Native("CC")
+class ClickCounter {
   var status;
 
   var foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation6_test.dart b/tests/compiler/dart2js_native/native_field_invocation6_test.dart
index bd8e9c2..cd2d93b 100644
--- a/tests/compiler/dart2js_native/native_field_invocation6_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation6_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 makeA() native;
@@ -15,7 +16,8 @@
 """;
 
 
-class A native "A" {
+@Native("A")
+class A {
   var _foo;
 
   get foo => _foo;
diff --git a/tests/compiler/dart2js_native/native_field_invocation_test.dart b/tests/compiler/dart2js_native/native_field_invocation_test.dart
index 95081bf..54eaf50 100644
--- a/tests/compiler/dart2js_native/native_field_invocation_test.dart
+++ b/tests/compiler/dart2js_native/native_field_invocation_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
   var foo;
 }
 
diff --git a/tests/compiler/dart2js_native/native_field_name_test.dart b/tests/compiler/dart2js_native/native_field_name_test.dart
index 8eab52b..42af8880 100644
--- a/tests/compiler/dart2js_native/native_field_name_test.dart
+++ b/tests/compiler/dart2js_native/native_field_name_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Check that native fields are not incorrectly renamed.
 
-class A native "A" {
+@Native("A")
+class A {
   int myLongPropertyName;
   int getValue;
 
diff --git a/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart b/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
index 8b2a1d6..755da14 100644
--- a/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_field_rename_1_frog_test.dart
@@ -7,9 +7,10 @@
 // for the field must be based on the field's name, not the field's jsname.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
 
-class A native "A" {
+@Native("A")
+class A {
   int key;                    //  jsname is 'key'
   int getKey() => key;
 }
@@ -20,7 +21,8 @@
   int getKey() => key;
 }
 
-class X native "X" {
+@Native("X")
+class X {
   @JSName('key')
   int native_key_method() native;
   // This should cause B.key to be renamed, but not A.key.
diff --git a/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart b/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
index 2bd4481..8a85ab3 100644
--- a/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_field_rename_2_frog_test.dart
@@ -7,13 +7,14 @@
 // for the field must be based on the field's name, not the field's jsname.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
 
 abstract class I {
   int key;
 }
 
-class A implements I native "A" {
+@Native("A")
+class A implements I {
   int key;                    //  jsname is 'key'
   int getKey() => key;
 }
@@ -24,7 +25,8 @@
   int getKey() => key;
 }
 
-class X native "X" {
+@Native("X")
+class X {
   @JSName('key')
   int native_key_method() native;
   // This should cause B.key to be renamed, but not A.key.
diff --git a/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart b/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
index 558e619..9ea0f42 100644
--- a/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
+++ b/tests/compiler/dart2js_native/native_library_same_name_used_lib2.dart
@@ -6,9 +6,11 @@
 
 library lib2;
 import 'native_library_same_name_used_lib1.dart';  // To get abstract class I.
+import 'dart:_js_helper';
 
 // Native impl has same name as abstract class.
-class Impl implements I native "I" {
+@Native("I")
+class Impl implements I {
   Impl read() native;
   write(Impl x) native;
 }
diff --git a/tests/compiler/dart2js_native/native_method_inlining_test.dart b/tests/compiler/dart2js_native/native_method_inlining_test.dart
index 8509685..a3aee2c 100644
--- a/tests/compiler/dart2js_native/native_method_inlining_test.dart
+++ b/tests/compiler/dart2js_native/native_method_inlining_test.dart
@@ -6,11 +6,12 @@
 // number of arguments in the call site AND the call site is inlined.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show NoInline;
+import 'dart:_js_helper' show Native, NoInline;
 
 typedef int Int2Int(int x);
 
-class A native "A" {
+@Native("A")
+class A {
   int foo([x, y, z]) native;
 
   // Calls can be inlined provided they don't pass an argument.
diff --git a/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
index 286e588..22e2eac 100644
--- a/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename1_frog_test.dart
@@ -5,9 +5,10 @@
 // Test the feature where the native string declares the native method's name.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
 
-class A native "A" {
+@Native("A")
+class A {
   @JSName('fooA')
   int foo() native;
 
diff --git a/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
index 31fb465..2fd79c8 100644
--- a/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename2_frog_test.dart
@@ -5,14 +5,16 @@
 // Test the feature where the native string declares the native method's name.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
 
-class A native "A" {
+@Native("A")
+class A {
   @JSName('fooA')
   int foo() native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   @JSName('fooB')
   int foo() native;
 }
diff --git a/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart b/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
index f7455b3..433ff45 100644
--- a/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_method_rename3_frog_test.dart
@@ -6,14 +6,16 @@
 // #3. The name does not get
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show JSName;
+import 'dart:_js_helper' show Native, JSName;
 
-class A native "A" {
+@Native("A")
+class A {
   @JSName('fooA')
   int foo() native;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   @JSName('fooB')
   int foo() native;
   int fooA() => 333;
diff --git a/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart b/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
index 989312d..26ac11b 100644
--- a/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
+++ b/tests/compiler/dart2js_native/native_method_with_keyword_name_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Make sure we can have a native with a name that is a JavaScript keyword.
 
-class A native "A" {
+@Native("A")
+class A {
   int delete() native;
 }
 
@@ -26,5 +28,5 @@
   var a = makeA();
   Expect.equals(87, a.delete());
   A aa = a;
-  Expect.equals(87, aa.delete());  
+  Expect.equals(87, aa.delete());
 }
diff --git a/tests/compiler/dart2js_native/native_mirror_test.dart b/tests/compiler/dart2js_native/native_mirror_test.dart
index 79b842c..58e8ffe 100644
--- a/tests/compiler/dart2js_native/native_mirror_test.dart
+++ b/tests/compiler/dart2js_native/native_mirror_test.dart
@@ -10,9 +10,11 @@
 // convention for others, making this fail.
 
 import "package:expect/expect.dart";
+import "dart:_js_helper";
 import "dart:mirrors";
 
-class A native "A" {
+@Native("A")
+class A {
   final foo;
 }
 
diff --git a/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart b/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
index b630d23..72ffbc6 100644
--- a/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_missing_method1_frog_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart b/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
index 7d473ab..5a083d7 100644
--- a/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_missing_method2_frog_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/native_mixin_field_test.dart b/tests/compiler/dart2js_native/native_mixin_field_test.dart
index 8ccda28..7ef9e2d 100644
--- a/tests/compiler/dart2js_native/native_mixin_field_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_field_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes can use ordinary Dart classes with fields
 // as mixins.
 
-class A native "A" {
+@Native("A")
+class A {
   var foo;
 }
 
-class B extends A with M1, M2 native "B" {
+@Native("B")
+class B extends A with M1, M2 {
   var bar;
 }
 
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
index cf372f6..f59d2e1 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple2_test.dart
@@ -2,15 +2,18 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes can access methods defined only by mixins.
 
-class A native "A" {
+@Native("A")
+class A {
   foo(x, [y]) => '$x;$y';
 }
 
-class B extends A with M1, M2, M3 native "B" {
+@Native("B")
+class B extends A with M1, M2, M3 {
 }
 
 class M1 {}
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
index 50340e4..1bd434b 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple3_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes and plain classes can access methods defined only by
@@ -23,13 +24,16 @@
 
 class M3 { }
 
-class A native "A" {
+@Native("A")
+class A {
   foo() => 'A.foo';
 }
 
-class B extends A with M1, M2, M3 native "B" {}
+@Native("B")
+class B extends A with M1, M2, M3 {}
 
-class C extends B native "C" {
+@Native("C")
+class C extends B {
   foo() => 'C.foo';
 }
 
diff --git a/tests/compiler/dart2js_native/native_mixin_multiple_test.dart b/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
index 4e930c7..031f6c1 100644
--- a/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_multiple_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes can use ordinary Dart classes as mixins.
 
-class A native "A" {
+@Native("A")
+class A {
   foo() => "A-foo";
   baz() => "A-baz";
 }
 
-class B extends A with M1, M2 native "B" {
+@Native("B")
+class B extends A with M1, M2 {
   bar() => baz();
 }
 
diff --git a/tests/compiler/dart2js_native/native_mixin_test.dart b/tests/compiler/dart2js_native/native_mixin_test.dart
index d63f306..7cac689 100644
--- a/tests/compiler/dart2js_native/native_mixin_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes can use ordinary Dart classes as mixins.
 
-class A native "A" {
+@Native("A")
+class A {
   foo() => "A-foo";
   baz() => "A-baz";
 }
 
-class B extends A with M native "B" {
+@Native("B")
+class B extends A with M {
   bar() => baz();
 }
 
diff --git a/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart b/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
index c21e0b3..3708603 100644
--- a/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
+++ b/tests/compiler/dart2js_native/native_mixin_with_plain_test.dart
@@ -2,18 +2,21 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes and ordinary Dart classes can both use the same
 // ordinary Dart classes as a mixin.
 
-class A native "A" {
+@Native("A")
+class A {
   final String aa;
   foo() => "A-foo $aa";
   baz() => "A-baz $aa";
 }
 
-class B extends A with M native "B" {
+@Native("B")
+class B extends A with M {
   bar() => 'B-bar -> ${baz()}';
   get mm => 'B.mm($aa)';
 }
diff --git a/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart b/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
index 2620f96..b0d63e2 100644
--- a/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_named_constructors2_frog_test.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Native class with named constructors and static methods.
 
 
 
-class A native "A" {
+@Native("A")
+class A {
 
   factory A(int len) => _construct(len);
 
diff --git a/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart b/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
index 001c4ae..fa4c14c 100644
--- a/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_named_constructors3_frog_test.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Hidden native class with factory constructors and NO static methods.
 // Regression test.
 
 
-class A native "A" {
+@Native("A")
+class A {
 
   // No static methods in this class.
 
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
index 1c2f5a9..f7581b2 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception2_frog_test.dart
@@ -2,12 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   foo() native;
 }
 
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
index 886e33f..0f1d009 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception3_frog_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:mirrors" show reflect;
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 class GetName {
@@ -11,11 +12,13 @@
 
 String getName(im) => reflect(new GetName()).delegate(im);
 
-class A native "A" {
+@Native("A")
+class A {
   bar() => 42;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   foo() => 42;
 }
 
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
index fed9ce8..ee0af94 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception4_frog_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:mirrors" show reflect;
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 class GetName {
@@ -12,12 +13,14 @@
 
 String getName(im) => reflect(new GetName()).delegate(im);;
 
-class A native "A" {
+@Native("A")
+class A {
   bar() => 42;
   noSuchMethod(x) => "native(${getName(x)}:${x.positionalArguments})";
 }
 
-class B native "B" {
+@Native("B")
+class B {
   baz() => 42;
 }
 
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
index 87b3a37..98041ec 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception5_frog_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:mirrors" show reflect;
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 class GetName {
@@ -12,12 +13,14 @@
 
 String getName(im) => reflect(new GetName()).delegate(im);
 
-class A native "A" {
+@Native("A")
+class A {
   bar() => 42;
   noSuchMethod(x) => "native(${getName(x)}:${x.positionalArguments})";
 }
 
-class B native "B" {
+@Native("B")
+class B {
   baz() => 42;
 }
 
diff --git a/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart b/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
index 007de7f..2319106 100644
--- a/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_no_such_method_exception_frog_test.dart
@@ -2,13 +2,16 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {
+@Native("A")
+class A {
   bar() => 42;
 }
 
-class B native "B" {
+@Native("B")
+class B {
   foo() => 42;
 }
 
diff --git a/tests/compiler/dart2js_native/native_novel_html_test.dart b/tests/compiler/dart2js_native/native_novel_html_test.dart
index 660685a..fba8be7 100644
--- a/tests/compiler/dart2js_native/native_novel_html_test.dart
+++ b/tests/compiler/dart2js_native/native_novel_html_test.dart
@@ -2,11 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test to see if novel HTML tags are interpreted as HTMLElement.
 
-class Element native "HTMLElement" {
+@Native("HTMLElement")
+class Element {
   String dartMethod(int x) => 'dartMethod(${nativeMethod(x+1)})';
   String nativeMethod(int x) native;
 }
diff --git a/tests/compiler/dart2js_native/native_null_closure_frog_test.dart b/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
index 6c08375..69f9e0c 100644
--- a/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_null_closure_frog_test.dart
@@ -4,13 +4,14 @@
 
 // Test that exception unwrapping handle cases like ({foo:null}).foo().
 
-import 'dart:_js_helper';
+import "dart:_js_helper";
 
 import "package:expect/expect.dart";
 
 typedef void MyFunctionType();
 
-class A native "A" {
+@Native("A")
+class A {
   setClosure(MyFunctionType f) native;
   check(MyFunctionType f) native;
   invoke() native;
diff --git a/tests/compiler/dart2js_native/native_null_frog_test.dart b/tests/compiler/dart2js_native/native_null_frog_test.dart
index 846c9b4..7a92684 100644
--- a/tests/compiler/dart2js_native/native_null_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_null_frog_test.dart
@@ -2,12 +2,14 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for values of some basic types.
 
 
-class A native "A" {
+@Native("A")
+class A {
   returnNull() native;
   returnUndefined() native;
   returnEmptyString() native;
diff --git a/tests/compiler/dart2js_native/native_property_frog_test.dart b/tests/compiler/dart2js_native/native_property_frog_test.dart
index 5814994..04cca4d 100644
--- a/tests/compiler/dart2js_native/native_property_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_property_frog_test.dart
@@ -5,9 +5,11 @@
 // Properties on hidden native classes.
 
 import "package:expect/expect.dart";
+import "dart:_js_helper";
 import 'dart:_foreign_helper' show JS;
 
-class A native "A" {
+@Native("A")
+class A {
 
   // Setters and getters should be similar to these methods:
   int getX() => JS('int', '#._x', this);
diff --git a/tests/compiler/dart2js_native/native_to_string_frog_test.dart b/tests/compiler/dart2js_native/native_to_string_frog_test.dart
index c15dc55..3b9a47a 100644
--- a/tests/compiler/dart2js_native/native_to_string_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_to_string_frog_test.dart
@@ -2,9 +2,11 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
-class A native "A" {}
+@Native("A")
+class A {}
 makeA() native;
 
 void setup() native """
diff --git a/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart b/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
index 8c89d38..1f529c9 100644
--- a/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_use_native_name_in_table_frog_test.dart
@@ -2,16 +2,19 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that we put native names and not Dart names into the dynamic
 // dispatch table.
 
-class A native "NativeA" {
+@Native("NativeA")
+class A {
   foo() native;
 }
 
-class B extends A native "NativeB" {
+@Native("NativeB")
+class B extends A {
 }
 
 A makeA() native { return new A(); }
@@ -22,7 +25,7 @@
   if (child.prototype.__proto__) {
     child.prototype.__proto__ = parent.prototype;
   } else {
-    function tmp() {}; 
+    function tmp() {};
     tmp.prototype = parent.prototype;
     child.prototype = new tmp();
     child.prototype.constructor = child;
@@ -44,10 +47,10 @@
   var a = makeA();
   Expect.equals(42, a.foo());
   A aa = a;
-  Expect.equals(42, aa.foo());  
+  Expect.equals(42, aa.foo());
 
   var b = makeB();
   Expect.equals(42, b.foo());
   B bb = b;
-  Expect.equals(42, bb.foo());  
+  Expect.equals(42, bb.foo());
 }
diff --git a/tests/compiler/dart2js_native/native_window1_frog_test.dart b/tests/compiler/dart2js_native/native_window1_frog_test.dart
index f6b727a..b0588ec 100644
--- a/tests/compiler/dart2js_native/native_window1_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_window1_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 abstract class Window {
@@ -10,7 +11,8 @@
 
 // Defining this global object makes Frog eager on optimizing
 // call sites where the receiver is typed 'Window'.
-class _DOMWindowJs implements Window native "@*DOMWindow" {
+@Native("@*DOMWindow")
+class _DOMWindowJs implements Window {
   final int document;
 }
 
diff --git a/tests/compiler/dart2js_native/native_window2_frog_test.dart b/tests/compiler/dart2js_native/native_window2_frog_test.dart
index c1cecef..c252e46 100644
--- a/tests/compiler/dart2js_native/native_window2_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_window2_frog_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 abstract class Window {
@@ -10,7 +11,8 @@
 
 // Defining this global object makes Frog eager on optimizing
 // call sites where the receiver is typed 'Window'.
-class _DOMWindowJs implements Window native "@*DOMWindow" {
+@Native("@*DOMWindow")
+class _DOMWindowJs implements Window {
   final int document;
 }
 
diff --git a/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart b/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
index 22f2f3e..72de377 100644
--- a/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_wrapping_function3_frog_test.dart
@@ -3,12 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
+import "dart:_js_helper";
 
 typedef void Callback0();
 typedef void Callback1(arg1);
 typedef void Callback2(arg1, arg2);
 
-class A native "A" {
+@Native("A")
+class A {
   foo1(Callback1 closure, [arg1 = 0]) native;
   foo2(Callback2 closure, [arg1 = 0, arg2 = 1]) native;
 }
diff --git a/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart b/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
index eca6639..1095c6c 100644
--- a/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_wrapping_function_frog_test.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 typedef void Callback0();
 typedef void Callback1(arg1);
 typedef void Callback2(arg1, arg2);
 
-class A native "A" {
+@Native("A")
+class A {
   foo0(Callback0 closure) native;
   foo1(Callback1 closure, arg1) native;
   foo2(Callback2 closure, arg1, arg2) native;
diff --git a/tests/compiler/dart2js_native/oddly_named_fields_test.dart b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
index b2dae29..984e4d1 100644
--- a/tests/compiler/dart2js_native/oddly_named_fields_test.dart
+++ b/tests/compiler/dart2js_native/oddly_named_fields_test.dart
@@ -61,7 +61,8 @@
 // See section 11.2 "Left-Hand-Side Expressions" which states that a
 // "MemberExpression" includes: "MemberExpression . IdentifierName".
 
-class NativeClassWithOddNames native "NativeClassWithOddNames" {
+@Native("NativeClassWithOddNames")
+class NativeClassWithOddNames {
   @JSName('break') bool breakValue;
   @JSName('case') bool caseValue;
   @JSName('catch') bool catchValue;
diff --git a/tests/compiler/dart2js_native/rti_only_native_test.dart b/tests/compiler/dart2js_native/rti_only_native_test.dart
index 634f752..981f411 100644
--- a/tests/compiler/dart2js_native/rti_only_native_test.dart
+++ b/tests/compiler/dart2js_native/rti_only_native_test.dart
@@ -7,7 +7,10 @@
 // See my explanation in https://codereview.chromium.org/14018036/.
 //   -- ahe
 
-class A native "A" {
+import "dart:_js_helper";
+
+@Native("A")
+class A {
   // Just making sure the field name is unique.
   var rti_only_native_test_field;
 }
diff --git a/tests/compiler/dart2js_native/runtimetype_test.dart b/tests/compiler/dart2js_native/runtimetype_test.dart
index dc8d7a4..460dfd0 100644
--- a/tests/compiler/dart2js_native/runtimetype_test.dart
+++ b/tests/compiler/dart2js_native/runtimetype_test.dart
@@ -3,15 +3,18 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
+import "dart:_js_helper";
 import 'dart:_foreign_helper' show JS;
 
 // Test to see runtimeType works on native classes and does not use the native
 // constructor name.
 
-class A native "TAGX" {
+@Native("TAGX")
+class A {
 }
 
-class B extends A native "TAGY" {
+@Native("TAGY")
+class B extends A {
 }
 
 makeA() native;
diff --git a/tests/compiler/dart2js_native/subclassing_1_test.dart b/tests/compiler/dart2js_native/subclassing_1_test.dart
index b90366a..b86130f 100644
--- a/tests/compiler/dart2js_native/subclassing_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_1_test.dart
@@ -3,13 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show findInterceptorForType;
 
 // Test that subclasses of native classes can be defined by setting the dispatch
 // record.
 
-class A native "A" {
+@Native("A")
+class A {
   foo(x) =>  '$x,${this.oof()}';
   oof() => 'A';
 }
diff --git a/tests/compiler/dart2js_native/subclassing_2_test.dart b/tests/compiler/dart2js_native/subclassing_2_test.dart
index f8b93aa..db588dd 100644
--- a/tests/compiler/dart2js_native/subclassing_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_2_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show findInterceptorForType;
 
 // Test calling convention of methods introduced on subclasses of native
@@ -11,7 +11,8 @@
 
 doFoo(r, x) => '$x,${r.oof()}';
 
-class A native "A" {
+@Native("A")
+class A {
   foo(x) => (doFoo)(this, x);
 }
 
diff --git a/tests/compiler/dart2js_native/subclassing_3_test.dart b/tests/compiler/dart2js_native/subclassing_3_test.dart
index d73f0c8..70595cb 100644
--- a/tests/compiler/dart2js_native/subclassing_3_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_3_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show Interceptor, findInterceptorForType;
 
 // Test calling convention of methods introduced on subclasses of native
@@ -15,7 +15,8 @@
   miz() => 'M';
 }
 
-class N native "N" {
+@Native("N")
+class N {
   foo(x) => (doFoo)(this, x);
 }
 
diff --git a/tests/compiler/dart2js_native/subclassing_4_test.dart b/tests/compiler/dart2js_native/subclassing_4_test.dart
index 9d25e1a..4997bb2 100644
--- a/tests/compiler/dart2js_native/subclassing_4_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_4_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show Interceptor, findInterceptorForType;
 
 // Test calling convention on subclasses of native classes.
@@ -12,7 +12,8 @@
   miz() => 'M';
 }
 
-class N native "N" {}
+@Native("N")
+class N {}
 
 class A extends N {}
 
diff --git a/tests/compiler/dart2js_native/subclassing_5_test.dart b/tests/compiler/dart2js_native/subclassing_5_test.dart
index 39703d1..b1117db 100644
--- a/tests/compiler/dart2js_native/subclassing_5_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_5_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show Interceptor, findInterceptorForType;
 
 // Test type checks.
@@ -14,7 +14,8 @@
   miz() => 'M';
 }
 
-class N native "N" {}
+@Native("N")
+class N {}
 
 class A extends N {}
 
diff --git a/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
index 36fed2e..a1e7105 100644
--- a/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_constructor_1_test.dart
@@ -4,7 +4,7 @@
 
 import "package:expect/expect.dart";
 import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
     findInterceptorForType, findConstructorForNativeSubclassType;
 
@@ -15,7 +15,8 @@
 
 var log;
 
-class A native "A" {
+@Native("A")
+class A {
   final a1 = log(101);  // Only initialized IF named constructor called.
   final a2;             // Initialized by native constructor.
   final a3;             // Initialized only by A.two.
diff --git a/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart b/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
index 75e321c..2b9f6c5 100644
--- a/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_constructor_2_test.dart
@@ -2,12 +2,14 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Test that native classes and subclasses of native classes cannot be directly
 // created via a generative constructor.
 
-class A native "A" {
+@Native("A")
+class A {
   A.one();
 }
 
diff --git a/tests/compiler/dart2js_native/subclassing_super_call_test.dart b/tests/compiler/dart2js_native/subclassing_super_call_test.dart
index f13a42e..a424b95 100644
--- a/tests/compiler/dart2js_native/subclassing_super_call_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_call_test.dart
@@ -4,16 +4,18 @@
 
 import "package:expect/expect.dart";
 import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
     findInterceptorForType, findConstructorForNativeSubclassType;
 
 // Test for super access from classes that extend native classes.
 
-class N1 native "N1" {
+@Native("N1")
+class N1 {
 }
 
-class N2 extends N1 native "N2" {
+@Native("N2")
+class N2 extends N1 {
   N2.init();
   String text;
   foo() native;
diff --git a/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart b/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
index 250c884..97da995 100644
--- a/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_field_1_test.dart
@@ -4,13 +4,14 @@
 
 import "package:expect/expect.dart";
 import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
     findInterceptorForType, findConstructorForNativeSubclassType;
 
 // Test for shadowed fields in classes that extend native classes.
 
-class N native "N" {
+@Native("N")
+class N {
   N.init();
 }
 
diff --git a/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart b/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
index dca071b..f325a727 100644
--- a/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_super_field_2_test.dart
@@ -4,14 +4,15 @@
 
 import "package:expect/expect.dart";
 import 'dart:_foreign_helper' show JS;
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
     findInterceptorForType, findConstructorForNativeSubclassType;
 
 // Test for fields with same name as native fields.  We expect N.foo to have the
 // property name 'foo' and A.foo and B.foo to have non-conflicting names.
 
-class N native "N" {
+@Native("N")
+class N {
   var foo;
   N.init();
 }
diff --git a/tests/compiler/dart2js_native/subclassing_type_test.dart b/tests/compiler/dart2js_native/subclassing_type_test.dart
index 34748bf..abcb629 100644
--- a/tests/compiler/dart2js_native/subclassing_type_test.dart
+++ b/tests/compiler/dart2js_native/subclassing_type_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_js_helper' show Native, Creates, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show Interceptor, findInterceptorForType;
 
 // Test that type checks and casts work for subclasses of native classes and
@@ -11,7 +11,8 @@
 
 class M {}
 
-class N native "N" {}
+@Native("N")
+class N {}
 
 class A extends N {}
 
diff --git a/tests/compiler/dart2js_native/super_call_test.dart b/tests/compiler/dart2js_native/super_call_test.dart
index 68cccb7..ccb6f09 100644
--- a/tests/compiler/dart2js_native/super_call_test.dart
+++ b/tests/compiler/dart2js_native/super_call_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test to see if resolving a hidden native class's method interferes with
@@ -9,21 +10,25 @@
 // superclass caches the method in the prototype, so shadowing the dispatcher
 // stored on Object.prototype.
 
-class A native "A" {
+@Native("A")
+class A {
   foo() => 'A.foo ${bar()}';
   bar() => 'A.bar';
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   bar() => 'B.bar';
 }
 
-class C extends B native "C" {
+@Native("C")
+class C extends B {
   foo() => 'C.foo; super.foo = ${super.foo()}';
   bar() => 'C.bar';
 }
 
-class D extends C native "D" {
+@Native("D")
+class D extends C {
   bar() => 'D.bar';
 }
 
diff --git a/tests/compiler/dart2js_native/super_property_test.dart b/tests/compiler/dart2js_native/super_property_test.dart
index 003a4de..b2c89ea 100644
--- a/tests/compiler/dart2js_native/super_property_test.dart
+++ b/tests/compiler/dart2js_native/super_property_test.dart
@@ -2,18 +2,21 @@
 // for 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:_js_helper";
 import "package:expect/expect.dart";
 
 // Tests super setter where the HInvokeSuper is using interceptor aka
 // explicit-receiver calling convention.
 
-class A native "A" {
+@Native("A")
+class A {
   var foo;
   get_foo() => foo;
   set bar(value) => foo = value;
 }
 
-class B extends A native "B" {
+@Native("B")
+class B extends A {
   set foo(value) {
     super.foo = value;
   }
diff --git a/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
index 61f3b604..43efdb6 100644
--- a/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
+++ b/tests/compiler/dart2js_native/uninstantiated_type_parameter_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "dart:_js_helper";
 import "package:expect/expect.dart";
 
 // Test for uninstantiated native classes as type parameters.
@@ -9,7 +10,8 @@
 class UA {
 }
 
-class UB native "B" {
+@Native("B")
+class UB {
 }
 
 class C<T> {
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index c9d4411..9e3b7aa 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -43,6 +43,9 @@
 symbol_operator_test/03: Fail # bug 11669
 string_case_test/01: Fail # Bug 18061
 
+iterable_return_type_test/01: RuntimeError # Issue 13646
+iterable_return_type_test/02: RuntimeError # Issue 13646
+
 [ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
 main_test: Fail  # Dartium needs to check for both main() and main(args).
 
@@ -67,6 +70,8 @@
 error_stack_trace1_test: RuntimeError # Issue 12399
 hash_set_test/01: RuntimeError # Issue 11551
 integer_to_string_test/01: RuntimeError # Issue 1533
+iterable_return_type_test/01: RuntimeError # Issue 20085
+iterable_return_type_test/02: RuntimeError # Dart2js does not support Uint64*.
 
 big_integer_vm_test: RuntimeError, OK # VM specific test.
 bit_twiddling_bigint_test: RuntimeError # Requires bigint support.
diff --git a/tests/corelib/format_exception_test.dart b/tests/corelib/format_exception_test.dart
index f17bcdc..121494c 100644
--- a/tests/corelib/format_exception_test.dart
+++ b/tests/corelib/format_exception_test.dart
@@ -5,10 +5,10 @@
 library format_exception_test;
 import "package:expect/expect.dart";
 
-test(exn, message, source, position, toString) {
+test(exn, message, source, offset, toString) {
   Expect.equals(message, exn.message);
   Expect.equals(source, exn.source);
-  Expect.equals(position, exn.position);
+  Expect.equals(offset, exn.offset);
   Expect.equals(toString, exn.toString());
 }
 
@@ -39,7 +39,7 @@
 
   var o = new Object();
   e = new FormatException("message", o, 10);
-  test(e, "message", o, 10, "FormatException: message (at position 10)");
+  test(e, "message", o, 10, "FormatException: message (at offset 10)");
 
   e = new FormatException("message", "source", 3);
   test(e, "message", "source", 3,
diff --git a/tests/corelib/iterable_return_type_test.dart b/tests/corelib/iterable_return_type_test.dart
new file mode 100644
index 0000000..a16e1e5
--- /dev/null
+++ b/tests/corelib/iterable_return_type_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js where [List.addAll] was not typed
+// correctly.
+
+import "package:expect/expect.dart";
+
+import 'dart:collection';
+import 'dart:typed_data';
+
+testIntIterable(iterable) {
+  Expect.isTrue(iterable is Iterable<int>);
+  Expect.isFalse(iterable is Iterable<String>);
+}
+
+void testIterable(Iterable<int> iterable, [int depth = 3]) {
+  testIntIterable(iterable);
+  if (depth > 0) {
+    testIterable(iterable, depth - 1);
+    testIterable(iterable.where((x) => true), depth - 1);
+    testIterable(iterable.skip(1), depth - 1);
+    testIterable(iterable.take(1), depth - 1);
+    testIterable(iterable.skipWhile((x) => false), depth - 1);
+    testIterable(iterable.takeWhile((x) => true), depth - 1);
+    testList(iterable.toList(growable: true), depth - 1);
+    testList(iterable.toList(growable: false), depth - 1);
+    testIterable(iterable.toSet(), depth - 1);
+  }
+}
+
+void testList(List<int> list, [int depth = 3]) {
+  testIterable(list, depth);
+  if (depth > 0) {
+    testIterable(list.getRange(0, list.length), depth - 1);
+    testIterable(list.reversed, depth - 1);
+    testMap(list.asMap(), depth - 1);
+  }
+}
+
+void testMap(Map<int, int> map, [int depth = 3]) {
+  Expect.isTrue(map is Map<int,int>);
+  Expect.isFalse(map is Map<int,String>);
+  Expect.isFalse(map is Map<String,int>);
+  if (depth > 0) {
+    testIterable(map.keys, depth - 1);
+    testIterable(map.values, depth - 1);
+  }
+}
+
+main() {
+  // Empty lists.
+  testList(<int>[]);
+  testList(new List<int>(0));
+  testList(new List<int>());
+  testList(const <int>[]);
+  testList(new List<int>.generate(0, (x) => x + 1));
+  // Singleton lists.
+  testList(<int>[1]);
+  testList(new List<int>(1)..[0] = 1);
+  testList(new List<int>()..add(1));
+  testList(const <int>[1]);
+  testList(new List<int>.generate(1, (x) => x + 1));
+
+  // Typed lists.
+  testList(new Uint8List(1)..[0] = 1);   /// 01: ok
+  testList(new Int8List(1)..[0] = 1);    /// 01: continued
+  testList(new Uint16List(1)..[0] = 1);  /// 01: continued
+  testList(new Int16List(1)..[0] = 1);   /// 01: continued
+  testList(new Uint32List(1)..[0] = 1);  /// 01: continued
+  testList(new Int32List(1)..[0] = 1);   /// 01: continued
+  testList(new Uint64List(1)..[0] = 1);  /// 02: ok
+  testList(new Int64List(1)..[0] = 1);   /// 02: continued
+
+  testIterable(new Set<int>()..add(1));
+  testIterable(new HashSet<int>()..add(1));
+  testIterable(new LinkedHashSet<int>()..add(1));
+  testIterable(new SplayTreeSet<int>()..add(1));
+
+  testIterable(new Queue<int>()..add(1));
+  testIterable(new DoubleLinkedQueue<int>()..add(1));
+  testIterable(new ListQueue<int>()..add(1));
+
+  testMap(new Map<int,int>()..[1] = 1);
+  testMap(new HashMap<int,int>()..[1] = 1);
+  testMap(new LinkedHashMap<int,int>()..[1] = 1);
+  testMap(new SplayTreeMap<int,int>()..[1] = 1);
+  testMap(<int,int>{1:1});
+  testMap(const <int,int>{1:1});
+}
diff --git a/tests/language/const_constructor_nonconst_field_test.dart b/tests/language/const_constructor_nonconst_field_test.dart
new file mode 100644
index 0000000..9571a40
--- /dev/null
+++ b/tests/language/const_constructor_nonconst_field_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+  final int i = f(); /// 01: compile-time error
+  final int j = 1;
+  const A();
+}
+int f() {
+  return 3;
+}
+main() {
+  Expect.equals(const A().j, 1);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 2d031678..5e8b8c5 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -137,3 +137,6 @@
 [ $compiler == none && $runtime == vm && $arch == mips && $mode == debug ]
 stack_overflow_test: Skip # Crashes. Issue 17440.
 stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
+
+[ $compiler == none || $compiler == dart2analyzer ]
+const_constructor_nonconst_field_test/01: Fail # Issue 18779, 18780
diff --git a/tests/language/vm/allocation_sinking_vm_test.dart b/tests/language/vm/allocation_sinking_vm_test.dart
index 619235a..55b5f35 100644
--- a/tests/language/vm/allocation_sinking_vm_test.dart
+++ b/tests/language/vm/allocation_sinking_vm_test.dart
@@ -163,6 +163,111 @@
   Expect.equals(84, test_vm_field());
 }
 
+class CompoundA {
+  var b;
+  CompoundA(this.b);
+}
+
+class CompoundB {
+  var c;
+  CompoundB(this.c);
+}
+
+class CompoundC {
+  var d;
+  var root;
+  CompoundC(this.d);
+}
+
+class NoopSink {
+  const NoopSink();
+  call(val) { }
+}
+
+testCompound1() {
+  f(d, [sink = const NoopSink()]) {
+    var c = new CompoundC(d);
+    var a = new CompoundA(new CompoundB(c));
+    sink(a);
+    return c.d;
+  }
+
+  Expect.equals(0.1, f(0.1));
+  for (var i = 0; i < 100; i++) f(0.1);
+  Expect.equals(0.1, f(0.1));
+  Expect.equals(0.1, f(0.1, (val) {
+    Expect.isTrue(val is CompoundA);
+    Expect.isTrue(val.b is CompoundB);
+    Expect.isTrue(val.b.c is CompoundC);
+    Expect.isNull(val.b.c.root);
+    Expect.equals(0.1, val.b.c.d);
+  }));
+}
+
+
+testCompound2() {
+  f(d, [sink = const NoopSink()]) {
+    var c = new CompoundC(d);
+    var a = new CompoundA(new CompoundB(c));
+    c.root = a;
+    sink(a);
+    return c.d;
+  }
+
+  Expect.equals(0.1, f(0.1));
+  for (var i = 0; i < 100; i++) f(0.1);
+  Expect.equals(0.1, f(0.1));
+  Expect.equals(0.1, f(0.1, (val) {
+    Expect.isTrue(val is CompoundA);
+    Expect.isTrue(val.b is CompoundB);
+    Expect.isTrue(val.b.c is CompoundC);
+    Expect.equals(val, val.b.c.root);
+    Expect.equals(0.1, val.b.c.d);
+  }));
+}
+
+
+testCompound3() {
+  f(d, [sink = const NoopSink()]) {
+    var c = new CompoundC(d);
+    c.root = c;
+    sink(c);
+    return c.d;
+  }
+
+  Expect.equals(0.1, f(0.1));
+  for (var i = 0; i < 100; i++) f(0.1);
+  Expect.equals(0.1, f(0.1));
+  Expect.equals(0.1, f(0.1, (val) {
+    Expect.isTrue(val is CompoundC);
+    Expect.equals(val, val.root);
+    Expect.equals(0.1, val.d);
+  }));
+}
+
+
+testCompound4() {
+  f(d, [sink = const NoopSink()]) {
+    var c = new CompoundC(d);
+    c.root = c;
+    for (var i = 0; i < 10; i++) {
+      c.d += 1.0;
+    }
+    sink(c);
+    return c.d - 1.0 * 10;
+  }
+
+  Expect.equals(1.0, f(1.0));
+  for (var i = 0; i < 100; i++) f(1.0);
+  Expect.equals(1.0, f(1.0));
+  Expect.equals(1.0, f(1.0, (val) {
+    Expect.isTrue(val is CompoundC);
+    Expect.equals(val, val.root);
+    Expect.equals(11.0, val.d);
+  }));
+}
+
+
 main() {
   var c = new C(new Point(0.1, 0.2));
 
@@ -220,4 +325,8 @@
 
   testFinalField();
   testVMField();
+  testCompound1();
+  testCompound2();
+  testCompound3();
+  testCompound4();
 }
diff --git a/tests/language/vm/load_to_load_forwarding_vm_test.dart b/tests/language/vm/load_to_load_forwarding_vm_test.dart
index 5926305..86c5de7 100644
--- a/tests/language/vm/load_to_load_forwarding_vm_test.dart
+++ b/tests/language/vm/load_to_load_forwarding_vm_test.dart
@@ -240,49 +240,217 @@
   return a[0] + a[1];
 }
 
-testIndexedAliasedStore(a, b) {
-  a[0] = 1;
-  a[1] = 2;
-  if (a == b) {
-    b[0] = 3;
-  }
-  return a[0] + a[1];
-}
+//
+// Tests for indexed store aliases were autogenerated to have extensive
+// coverage for all interesting aliasing combinations within the alias
+// lattice (*[*], *[C], X[*], X[C])
+//
 
-testIndexedAliasedStore1(a, b) {
-  a[0] = 1;
-  a[1] = 2;
-  if (a == b) {
-    b[0] = 3;
-  }
-  return a[0] + a[1];
-}
-
-testIndexedAliasedStore2(a, b, i) {
-  a[0] = 1;
-  a[1] = 2;
-  if (a == b) {
-    b[i] = 3;
-  }
-  return a[0] + a[1];
-}
-
-
-testIndexedAliasedStore3(i) {
+testIndexedAliasedStore1(i) {
   var a = new List(2);
-  a[0] = 1;
-  a[i] = 3;
+  a[0] = 1;  // X[C]
+  a[i] = 2;  // X[*]
   return a[0];
 }
 
-
-testIndexedAliasedStore4(b) {
+testIndexedAliasedStore2(f, c) {
   var a = new List(2);
-  a[0] = 1;
-  b[0] = 3;
+  var d = f ? a : c;
+  a[0] = 1;  // X[C]
+  d[0] = 2;  // *[C]
   return a[0];
 }
 
+testIndexedAliasedStore3(f, c, i) {
+  var a = new List(2);
+  var d = f ? a : c;
+  a[0] = 1;  // X[C]
+  d[i] = 2;  // *[*]
+  return a[0];
+}
+
+testIndexedAliasedStore4(i) {
+  var a = new List(2);
+  a[i] = 1;  // X[*]
+  a[0] = 2;  // X[C]
+  return a[i];
+}
+
+testIndexedAliasedStore5(i, j) {
+  var a = new List(2);
+  a[i] = 1;  // X[*]
+  a[j] = 2;  // X[*]
+  return a[i];
+}
+
+testIndexedAliasedStore6(i, f, c) {
+  var a = new List(2);
+  var d = f ? a : c;
+  a[i] = 1;  // X[*]
+  d[0] = 2;  // *[C]
+  return a[i];
+}
+
+testIndexedAliasedStore7(i, f, c) {
+  var a = new List(2);
+  var d = f ? a : c;
+  a[i] = 1;  // X[*]
+  d[i] = 2;  // *[*]
+  return a[i];
+}
+
+testIndexedAliasedStore8(c, i) {
+  c[0] = 1;  // *[C]
+  c[i] = 2;  // *[*]
+  return c[0];
+}
+
+testIndexedAliasedStore9(c, f) {
+  var a = new List(2);
+  var d = f ? a : c;
+  c[0] = 1;  // *[C]
+  d[0] = 2;  // *[C]
+  return c[0];
+}
+
+testIndexedAliasedStore10(c, i) {
+  c[i] = 1;  // *[*]
+  c[0] = 2;  // *[C]
+  return c[i];
+}
+
+testIndexedAliasedStore11(c, i, j) {
+  c[i] = 1;  // *[*]
+  c[j] = 2;  // *[*]
+  return c[i];
+}
+
+testIndexedAliasedStore12(f, c) {
+  var a = new List(2);
+  var d = f ? a : c;
+  d[0] = 1;  // *[C]
+  a[0] = 2;  // X[C]
+  return d[0];
+}
+
+testIndexedAliasedStore13(f, c, i) {
+  var a = new List(2);
+  var d = f ? a : c;
+  d[0] = 1;  // *[C]
+  a[i] = 2;  // X[*]
+  return d[0];
+}
+
+testIndexedAliasedStore14(f, c, i) {
+  var a = new List(2);
+  var d = f ? a : c;
+  d[i] = 1;  // *[*]
+  a[0] = 2;  // X[C]
+  return d[i];
+}
+
+testIndexedAliasedStore15(f, c, i) {
+  var a = new List(2);
+  var d = f ? a : c;
+  d[i] = 1;  // *[*]
+  a[i] = 2;  // X[*]
+  return d[i];
+}
+
+testIndexedAliasedStores() {
+  var arr = new List(2);
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore1(0));
+    Expect.equals(1, testIndexedAliasedStore1(1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore2(false, arr));
+    Expect.equals(2, testIndexedAliasedStore2(true, arr));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore3(false, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore3(false, arr, 1));
+    Expect.equals(2, testIndexedAliasedStore3(true, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore3(true, arr, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore4(0));
+    Expect.equals(1, testIndexedAliasedStore4(1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore5(0, 0));
+    Expect.equals(1, testIndexedAliasedStore5(0, 1));
+    Expect.equals(1, testIndexedAliasedStore5(1, 0));
+    Expect.equals(2, testIndexedAliasedStore5(1, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore6(0, false, arr));
+    Expect.equals(2, testIndexedAliasedStore6(0, true, arr));
+    Expect.equals(1, testIndexedAliasedStore6(1, false, arr));
+    Expect.equals(1, testIndexedAliasedStore6(1, true, arr));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore7(0, false, arr));
+    Expect.equals(2, testIndexedAliasedStore7(0, true, arr));
+    Expect.equals(1, testIndexedAliasedStore7(1, false, arr));
+    Expect.equals(2, testIndexedAliasedStore7(1, true, arr));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore8(arr, 0));
+    Expect.equals(1, testIndexedAliasedStore8(arr, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore9(arr, false));
+    Expect.equals(1, testIndexedAliasedStore9(arr, true));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore10(arr, 0));
+    Expect.equals(1, testIndexedAliasedStore10(arr, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(2, testIndexedAliasedStore11(arr, 0, 0));
+    Expect.equals(1, testIndexedAliasedStore11(arr, 0, 1));
+    Expect.equals(1, testIndexedAliasedStore11(arr, 1, 0));
+    Expect.equals(2, testIndexedAliasedStore11(arr, 1, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore12(false, arr));
+    Expect.equals(2, testIndexedAliasedStore12(true, arr));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore13(false, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore13(false, arr, 1));
+    Expect.equals(2, testIndexedAliasedStore13(true, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore13(true, arr, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore14(false, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore14(false, arr, 1));
+    Expect.equals(2, testIndexedAliasedStore14(true, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore14(true, arr, 1));
+  }
+
+  for (var i = 0; i < 50; i++) {
+    Expect.equals(1, testIndexedAliasedStore15(false, arr, 0));
+    Expect.equals(1, testIndexedAliasedStore15(false, arr, 1));
+    Expect.equals(2, testIndexedAliasedStore15(true, arr, 0));
+    Expect.equals(2, testIndexedAliasedStore15(true, arr, 1));
+  }
+}
 
 var indices = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
 
@@ -316,7 +484,7 @@
 
   final obj = new X(new X(new X(null)));
 
-  final cs = new C(0, new C(1, new C(2, null))); 
+  final cs = new C(0, new C(1, new C(2, null)));
 
   for (var i = 0; i < 20; i++) {
     Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
@@ -361,22 +529,8 @@
   for (var i = 0; i < 20; i++) {
     Expect.equals(3, testIndexedNoAlias(array));
   }
-  for (var i = 0; i < 20; i++) {
-    Expect.equals(5, testIndexedAliasedStore1(array, array));
-  }
-  for (var i = 0; i < 20; i++) {
-    Expect.equals(4, testIndexedAliasedStore2(array, array, indices[1]));
-  }
-  for (var i = 0; i < 20; i++) {
-    Expect.equals(3, testIndexedAliasedStore3(indices[0]));
-  }
-  for (var i = 0; i < 20; i++) {
-    Expect.equals(1, testIndexedAliasedStore3(indices[1]));
-  }
 
-  for (var i = 0; i < 20; i++) {
-    Expect.equals(1, testIndexedAliasedStore4(array));
-  }
+  testIndexedAliasedStores();
 
   var test_array = new List(1);
   for (var i = 0; i < 20; i++) {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index ff99e8d..687e9ab 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -319,6 +319,9 @@
 convert/chunked_conversion_utf88_test: Skip  # Pass, Slow Issue 12644.
 convert/utf85_test: Skip  # Pass, Slow Issue 12644.
 
+[ $arch == simarm64 ]
+convert/utf85_test: Skip # Pass, Slow Issue 20111.
+
 # These tests use "const Symbol('void')".
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 mirrors/basic_types_in_dart_core_test: CompileTimeError
diff --git a/tools/VERSION b/tools/VERSION
index e2e56d1..e468720 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 6
 PATCH 0
-PRERELEASE 4
+PRERELEASE 5
 PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 96fdeac..81c9ca4 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -134,8 +134,8 @@
 
   # If no cross compiler is specified, only try to figure one out on Linux.
   if not HOST_OS in ['linux']:
-    print "Unless --toolchain is used cross-building is only supported on Linux"
-    return None
+    raise Exception('Unless --toolchain is used cross-building is only '
+                    'supported on Linux.')
 
   # For ARM Linux, by default use the Linux distribution's cross-compiler.
   if arch == 'arm':
@@ -368,7 +368,7 @@
 
 
 filter_xcodebuild_output = False
-def BuildOneConfig(options, target, target_os, mode, arch, override_tools=True):
+def BuildOneConfig(options, target, target_os, mode, arch, override_tools):
   global filter_xcodebuild_output
   start_time = time.time()
   os.environ['DART_BUILD_MODE'] = mode
@@ -476,7 +476,7 @@
     return 1
 
   # Then, build the runtime for the target arch.
-  if BuildOneConfig(options, 'runtime', target_os, mode, arch) != 0:
+  if BuildOneConfig(options, 'runtime', target_os, mode, arch, True) != 0:
     return 1
 
   # TODO(zra): verify that no platform specific details leak into the snapshots
@@ -529,11 +529,12 @@
     for target_os in options.os:
       for mode in options.mode:
         for arch in options.arch:
-          if target in ['create_sdk'] and utils.IsCrossBuild(target_os, arch):
+          cross_build = utils.IsCrossBuild(target_os, arch)
+          if target in ['create_sdk'] and cross_build:
             if BuildCrossSdk(options, target_os, mode, arch) != 0:
               return 1
           else:
-            if BuildOneConfig(options, target, target_os, mode, arch) != 0:
+            if BuildOneConfig(options, target, target_os, mode, arch, cross_build) != 0:
               return 1
 
   return 0
diff --git a/tools/dartium/update_deps.py b/tools/dartium/update_deps.py
index e2ea7d6..452421f 100755
--- a/tools/dartium/update_deps.py
+++ b/tools/dartium/update_deps.py
@@ -41,7 +41,7 @@
 ########################################################################
 
 BRANCH_CURRENT="dart/1985"
-BRANCH_NEXT="dart/1985"
+BRANCH_NEXT="dart/dartium"
 BRANCH_MULTIVM="dart/multivm"
 
 TARGETS = {