Version 1.20.0-dev.0.0

Merge e95eb9e794ddb607d67e499d41f5f962a811669e into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92e3899..dc58f20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,15 @@
+## 1.20.0
+
+### Core library changes
+* `dart:core`: Remove deprecated `Resource` class.
+  Use the class in `package:resource` instead.
+* `dart:async`
+  * `Future.wait` now catches synchronous errors and returns them in the
+    returned Future.
+* `dart:io`
+  * Added `WebSocket.addUtf8Text` to allow sending a pre-encoded text message
+    without a round-trip UTF-8 conversion.
+
 ## 1.19.0
 
 ### Language changes
diff --git a/DEPS b/DEPS
index d019eee..2d7bfbf 100644
--- a/DEPS
+++ b/DEPS
@@ -71,6 +71,7 @@
   "isolate_tag": "@0.2.2",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@2.0.0",
+  "kernel_rev": "@9509d282a62fe025f8d6242bb233b02e0a7fee04",
   "linter_rev": "@da3ec6ae914b40332fa6b6e100c1d4aabe9e27ca",
   "logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
   "markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
@@ -228,6 +229,8 @@
       (Var("github_dartlang") % "isolate") + Var("isolate_tag"),
   Var("dart_root") + "/third_party/pkg/json_rpc_2":
       (Var("github_mirror") % "json_rpc_2") + Var("json_rpc_2_tag"),
+  Var("dart_root") + "/third_party/pkg/kernel":
+      (Var("github_mirror") % "kernel") + Var("kernel_rev"),
   Var("dart_root") + "/third_party/pkg/linter":
       (Var("github_mirror") % "linter") + Var("linter_rev"),
   Var("dart_root") + "/third_party/pkg/logging":
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index e5a70a8..c1d9e6b 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1227,7 +1227,15 @@
 If an explicit type is attached to the initializing formal, that is its static type. Otherwise, the type of an initializing formal named \code{id} is $T_{id}$, where $T_{id}$ is the type of the field named \code{id} in the immediately enclosing class. It is a static warning if the static type of \code{id} is not assignable to $T_{id}$.
 
 \LMHash{}
-Using an initializing formal \code{\THIS{}.id} in a formal parameter list does not introduce a formal parameter name into the scope of the constructor. However, the initializing formal does effect the type of the constructor function exactly as if a formal parameter  named \code{id}  of the same type were introduced in the same position.
+Initializing formals constitute an exception to the rule that every formal parameter introduces a local variable into the formal parameter scope (\ref{formalParameters}).
+When the formal parameter list of a non-redirecting generative constructor contains any initializing formals, a new scope is introduced, the {\em formal parameter initializer scope}, which is the current scope of the initializer list of the constructor, and which is enclosed in the scope where the constructor is declared.
+Each initializing formal in the formal parameter list introduces a final local variable into the formal parameter initializer scope, but not into the formal parameter scope; every other formal parameter introduces a local variable into both the formal parameter scope and the formal parameter initializer scope.
+
+\commentary{
+This means that formal parameters, including initializing formals, must have distinct names, and that initializing formals are in scope for the initializer list, but they are not in scope for the body of the constructor.
+When a formal parameter introduces a local variable into two scopes, it is still one variable and hence one storage location.
+The type of the constructor is defined in terms of its formal parameters, including the initializing formals.
+}
 
 \LMHash{}
 Initializing formals are executed during the execution of generative constructors detailed below. Executing an initializing formal  \code{\THIS{}.id} causes the field \code{id} of the immediately surrounding class to be assigned the value of the corresponding actual parameter, unless $id$ is a final variable that has already been initialized, in which case a runtime error occurs.
diff --git a/pkg/BUILD.gn b/pkg/BUILD.gn
new file mode 100644
index 0000000..91a2266
--- /dev/null
+++ b/pkg/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+action("pkg") {
+  # TODO(zra): Add third_party/pkg, third_party/pkg_tested, and
+  # third_party/observatory_pub_packages/packages/charted/lib.
+  list_script = "../tools/list_pkg_directories.py"
+  pkg_list = exec_script(list_script, [rebase_path(".")], "list lines")
+  runtime_list = exec_script(
+      list_script, [rebase_path("../runtime")], "list lines")
+
+  inputs = pkg_list +
+           runtime_list +
+           [rebase_path("../sdk/lib/_internal/js_runtime/lib"),
+            rebase_path("../sdk/lib/_internal/sdk_library_metadata/lib"),]
+
+  timestamp_file = "$target_gen_dir/packages.stamp"
+  outputs = [
+    timestamp_file,
+  ]
+
+  script = "../tools/make_links.py"
+  args = [
+    "--quiet",
+    "--timestamp_file",
+    rebase_path(timestamp_file),
+    rebase_path("$root_out_dir/packages"),] +
+    inputs +
+    # Pub imports dart2js as compiler_unsupported so it can work outside
+    # the SDK. Map that to the compiler package.
+    [rebase_path("compiler/lib") + ":compiler_unsupported",]
+}
diff --git a/pkg/analysis_server/README.md b/pkg/analysis_server/README.md
index e5d6caa..15bb487 100644
--- a/pkg/analysis_server/README.md
+++ b/pkg/analysis_server/README.md
@@ -12,10 +12,11 @@
 
 Clients (typically tools, such as an editor) are expected to run the analysis
 server in a separate process and communicate with it using a JSON protocol. The
-protocol is specified in the file `analysis_server/doc/api.html`.
+protocol is specified in the file [`analysis_server/doc/api.html`][api].
 
 ## Features and bugs
 
 Please file feature requests and bugs at the [issue tracker][tracker].
 
-[tracker]: https://code.google.com/p/dart/issues
\ No newline at end of file
+[tracker]: https://code.google.com/p/dart/issues
+[api]: https://htmlpreview.github.io/?https://github.com/dart-lang/sdk/blob/master/pkg/analysis_server/doc/api.html
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 307ed65..866f58a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -1604,7 +1604,6 @@
     context.sourceFactory =
         _createSourceFactory(context, options, disposition, folder);
     context.analysisOptions = options;
-
     if (analysisServer.options.enablePubSummaryManager) {
       List<LinkedPubPackage> linkedBundles =
           analysisServer.pubSummaryManager.getLinkedBundles(context);
@@ -1684,6 +1683,9 @@
         disposition.createPackageUriResolvers(resourceProvider);
 
     // If no embedded URI resolver was provided, defer to a locator-backed one.
+    SdkExtensionFinder extFinder =
+        disposition.getSdkExtensionFinder(resourceProvider);
+    List<String> extFilePaths = extFinder.extensionFilePaths;
     EmbedderYamlLocator locator =
         disposition.getEmbedderLocator(resourceProvider);
     Map<Folder, YamlMap> embedderYamls = locator.embedderYamls;
@@ -1701,8 +1703,12 @@
             .getChildAssumingFile(EmbedderYamlLocator.EMBEDDER_FILE_NAME)
             .path);
       }
+      paths.addAll(extFilePaths);
       DartSdk dartSdk = analysisServer.sdkManager
           .getSdk(new SdkDescription(paths, options), () {
+        if (extFilePaths.isNotEmpty) {
+          embedderSdk.addExtensions(extFinder.urlMappings);
+        }
         embedderSdk.analysisOptions = options;
         // TODO(brianwilkerson) Enable summary use after we have decided where
         // summary files for embedder files will live.
@@ -1713,11 +1719,11 @@
     }
 
     resolvers.addAll(packageUriResolvers);
-    if (context.fileResolverProvider == null) {
-      resolvers.add(new ResourceUriResolver(resourceProvider));
-    } else {
-      resolvers.add(context.fileResolverProvider(folder));
+    UriResolver fileResolver;
+    if (context.fileResolverProvider != null) {
+      fileResolver = context.fileResolverProvider(folder);
     }
+    resolvers.add(fileResolver ?? new ResourceUriResolver(resourceProvider));
     return new SourceFactory(resolvers, disposition.packages);
   }
 }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 86b13a1..fd35213 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -1710,6 +1710,10 @@
   @override
   EmbedderYamlLocator getEmbedderLocator(ResourceProvider resourceProvider) =>
       new EmbedderYamlLocator(null);
+
+  @override
+  SdkExtensionFinder getSdkExtensionFinder(ResourceProvider resourceProvider) =>
+      new SdkExtensionFinder(null);
 }
 
 /**
@@ -1757,6 +1761,13 @@
    * where that is necessary.
    */
   EmbedderYamlLocator getEmbedderLocator(ResourceProvider resourceProvider);
+
+  /**
+   * Return the extension finder used to locate the `_sdkext` file used to add
+   * extensions to the SDK. The [resourceProvider] is used to access the file
+   * system in cases where that is necessary.
+   */
+  SdkExtensionFinder getSdkExtensionFinder(ResourceProvider resourceProvider);
 }
 
 /**
@@ -1780,6 +1791,10 @@
   @override
   EmbedderYamlLocator getEmbedderLocator(ResourceProvider resourceProvider) =>
       new EmbedderYamlLocator(null);
+
+  @override
+  SdkExtensionFinder getSdkExtensionFinder(ResourceProvider resourceProvider) =>
+      new SdkExtensionFinder(null);
 }
 
 /**
@@ -1790,6 +1805,7 @@
   final Map<String, List<Folder>> packageMap;
 
   EmbedderYamlLocator _embedderLocator;
+  SdkExtensionFinder _sdkExtensionFinder;
 
   @override
   final String packageRoot;
@@ -1814,6 +1830,11 @@
     }
     return _embedderLocator;
   }
+
+  @override
+  SdkExtensionFinder getSdkExtensionFinder(ResourceProvider resourceProvider) {
+    return _sdkExtensionFinder ??= new SdkExtensionFinder(packageMap);
+  }
 }
 
 /**
@@ -1827,6 +1848,7 @@
   Map<String, List<Folder>> packageMap;
 
   EmbedderYamlLocator _embedderLocator;
+  SdkExtensionFinder _sdkExtensionFinder;
 
   PackagesFileDisposition(this.packages);
 
@@ -1868,4 +1890,10 @@
     }
     return _embedderLocator;
   }
+
+  @override
+  SdkExtensionFinder getSdkExtensionFinder(ResourceProvider resourceProvider) {
+    return _sdkExtensionFinder ??=
+        new SdkExtensionFinder(buildPackageMap(resourceProvider));
+  }
 }
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 260f67f..83481a9 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -26,8 +26,11 @@
 import 'package:analyzer/src/generated/error.dart' as engine;
 import 'package:analyzer/src/generated/parser.dart' as engine;
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/task/dart.dart';
 import 'package:dart_style/dart_style.dart';
 
+int test_resetCount = 0;
+
 bool test_simulateRefactoringException_change = false;
 bool test_simulateRefactoringException_final = false;
 bool test_simulateRefactoringException_init = false;
@@ -376,7 +379,7 @@
 
   final AnalysisServer server;
   final SearchEngine searchEngine;
-  StreamSubscription onAnalysisStartedSubscription;
+  StreamSubscription subscriptionToReset;
 
   RefactoringKind kind;
   String file;
@@ -392,7 +395,6 @@
   EditGetRefactoringResult result;
 
   _RefactoringManager(this.server, this.searchEngine) {
-    onAnalysisStartedSubscription = server.onAnalysisStarted.listen(_reset);
     _reset();
   }
 
@@ -422,9 +424,9 @@
    * Cancels processing of the current request and cleans up.
    */
   void cancel() {
-    onAnalysisStartedSubscription.cancel();
     server.sendResponse(new Response.refactoringRequestCancelled(request));
     request = null;
+    _reset();
   }
 
   void getRefactoring(Request _request) {
@@ -492,6 +494,29 @@
     });
   }
 
+  /**
+   * Perform enough analysis to be able to perform refactoring of the given
+   * [kind] in the given [file].
+   */
+  Future<Null> _analyzeForRefactoring(String file, RefactoringKind kind) async {
+    // "Extract Local" and "Inline Local" refactorings need only local analysis.
+    if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE ||
+        kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
+      ContextSourcePair pair = server.getContextSourcePair(file);
+      engine.AnalysisContext context = pair.context;
+      Source source = pair.source;
+      if (context != null && source != null) {
+        if (context.computeResult(source, SOURCE_KIND) == SourceKind.LIBRARY) {
+          await context.computeResolvedCompilationUnitAsync(source, source);
+          return;
+        }
+      }
+    }
+    // A refactoring for which we cannot optimize analysis.
+    // So, wait for full analysis.
+    await server.onAnalysisComplete;
+  }
+
   void _checkForReset_afterCreateChange() {
     if (test_simulateRefactoringReset_afterCreateChange) {
       _reset();
@@ -525,7 +550,7 @@
    */
   Future _init(
       RefactoringKind kind, String file, int offset, int length) async {
-    await server.onAnalysisComplete;
+    await _analyzeForRefactoring(file, kind);
     // check if we can continue with the existing Refactoring instance
     if (this.kind == kind &&
         this.file == file &&
@@ -548,6 +573,7 @@
       if (elements.isNotEmpty) {
         Element element = elements[0];
         if (element is ExecutableElement) {
+          _resetOnAnalysisStarted();
           refactoring =
               new ConvertGetterToMethodRefactoring(searchEngine, element);
         }
@@ -558,6 +584,7 @@
       if (elements.isNotEmpty) {
         Element element = elements[0];
         if (element is ExecutableElement) {
+          _resetOnAnalysisStarted();
           refactoring =
               new ConvertMethodToGetterRefactoring(searchEngine, element);
         }
@@ -566,6 +593,7 @@
     if (kind == RefactoringKind.EXTRACT_LOCAL_VARIABLE) {
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
+        _resetOnFileResolutionChanged(file);
         refactoring = new ExtractLocalRefactoring(units[0], offset, length);
         feedback = new ExtractLocalVariableFeedback(
             <String>[], <int>[], <int>[],
@@ -576,6 +604,7 @@
     if (kind == RefactoringKind.EXTRACT_METHOD) {
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
+        _resetOnAnalysisStarted();
         refactoring = new ExtractMethodRefactoring(
             searchEngine, units[0], offset, length);
         feedback = new ExtractMethodFeedback(offset, length, '', <String>[],
@@ -585,6 +614,7 @@
     if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
+        _resetOnFileResolutionChanged(file);
         refactoring =
             new InlineLocalRefactoring(searchEngine, units[0], offset);
       }
@@ -592,11 +622,13 @@
     if (kind == RefactoringKind.INLINE_METHOD) {
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
+        _resetOnAnalysisStarted();
         refactoring =
             new InlineMethodRefactoring(searchEngine, units[0], offset);
       }
     }
     if (kind == RefactoringKind.MOVE_FILE) {
+      _resetOnAnalysisStarted();
       ContextSourcePair contextSource = server.getContextSourcePair(file);
       engine.AnalysisContext context = contextSource.context;
       Source source = contextSource.source;
@@ -619,6 +651,7 @@
           element = constructor.staticElement;
         }
         // do create the refactoring
+        _resetOnAnalysisStarted();
         refactoring = new RenameRefactoring(searchEngine, element);
         feedback =
             new RenameFeedback(node.offset, node.length, 'kind', 'oldName');
@@ -676,7 +709,8 @@
     }
   }
 
-  void _reset([engine.AnalysisContext context]) {
+  void _reset() {
+    test_resetCount++;
     kind = null;
     offset = null;
     length = null;
@@ -685,6 +719,31 @@
     initStatus = new RefactoringStatus();
     optionsStatus = new RefactoringStatus();
     finalStatus = new RefactoringStatus();
+    subscriptionToReset?.cancel();
+    subscriptionToReset = null;
+  }
+
+  void _resetOnAnalysisStarted() {
+    subscriptionToReset?.cancel();
+    subscriptionToReset = server.onAnalysisStarted.listen((_) => _reset());
+  }
+
+  /**
+   * We're performing a refactoring that affects only the given [file].
+   * So, when the [file] resolution is changed, we need to reset refactoring.
+   * But when any other file is changed or analyzed, we can continue.
+   */
+  void _resetOnFileResolutionChanged(String file) {
+    subscriptionToReset?.cancel();
+    subscriptionToReset = server
+        .getAnalysisContext(file)
+        ?.onResultChanged(RESOLVED_UNIT)
+        ?.listen((event) {
+      Source targetSource = event.target.source;
+      if (targetSource?.fullName == file) {
+        _reset();
+      }
+    });
   }
 
   void _sendResultResponse() {
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index b99cec3..3263d2b 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/computer/computer_highlights2.dart';
 import 'package:analysis_server/src/computer/computer_outline.dart';
 import 'package:analysis_server/src/computer/computer_overrides.dart';
+import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/domains/analysis/implemented_dart.dart';
 import 'package:analysis_server/src/domains/analysis/navigation.dart';
 import 'package:analysis_server/src/domains/analysis/occurrences.dart';
@@ -21,6 +22,8 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
 
 /**
  * Runs the given function [f] with the working cache size in [context].
@@ -376,6 +379,7 @@
       setCacheSize(context, IDLE_CACHE_SIZE);
       server.sendContextAnalysisDoneNotifications(
           context, AnalysisDoneReason.COMPLETE);
+      _flushCache(server);
       return;
     }
     // process results
@@ -388,6 +392,28 @@
   }
 
   /**
+   * Flush some of the [context] cache results, which we probably not
+   * going to use anymore.
+   */
+  void _flushCache(AnalysisServer server) {
+    if (context is InternalAnalysisContext) {
+      InternalAnalysisContext context = this.context;
+      // Flush AST results for source outside of the analysis roots.
+      ContextManager contextManager = server.contextManager;
+      context.analysisCache.flush((target) {
+        if (target is Source || target is LibrarySpecificUnit) {
+          Source targetSource = target.source;
+          return !context.prioritySources.contains(targetSource) &&
+              !contextManager.isInAnalysisRoot(targetSource.fullName);
+        }
+        return false;
+      }, (target, result) {
+        return result is ResultDescriptor<CompilationUnit>;
+      });
+    }
+  }
+
+  /**
    * Send the information in the given list of notices back to the client.
    */
   void _sendNotices(AnalysisServer server, List<ChangeNotice> notices) {
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 28deb09..dc971b8 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -386,7 +386,7 @@
     analysisServerOptions.enablePubSummaryManager =
         results[ENABLE_PUB_SUMMARY_MANAGER];
     analysisServerOptions.finerGrainedInvalidation =
-        results[FINER_GRAINED_INVALIDATION];
+        true /*results[FINER_GRAINED_INVALIDATION]*/;
     analysisServerOptions.noErrorNotification = results[NO_ERROR_NOTIFICATION];
     analysisServerOptions.noIndex = results[NO_INDEX];
     analysisServerOptions.useAnalysisHighlight2 =
@@ -425,8 +425,8 @@
     SdkCreator defaultSdkCreator = (AnalysisOptions options) {
       PhysicalResourceProvider resourceProvider =
           PhysicalResourceProvider.INSTANCE;
-      FolderBasedDartSdk sdk = new FolderBasedDartSdk(resourceProvider,
-          FolderBasedDartSdk.defaultSdkDirectory(resourceProvider));
+      FolderBasedDartSdk sdk = new FolderBasedDartSdk(
+          resourceProvider, resourceProvider.getFolder(defaultSdkPath));
       sdk.analysisOptions = options;
       sdk.useSummary = useSummaries;
       return sdk;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index c7c5776..8fa0c44 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -139,6 +139,7 @@
     void addPosition(int offset) {
       positions.add(new Position(file, offset));
     }
+
     // add variable declaration
     {
       String declarationCode;
@@ -180,8 +181,11 @@
           occurrencesShift = target.offset + code.length - expr.offset;
           doSourceChange_addElementEdit(change, unitElement, edit);
         }
-        doSourceChange_addElementEdit(change, unitElement,
-            new SourceEdit(expr.end, 0, ';' + eol + prefix + '}'));
+        doSourceChange_addElementEdit(
+            change,
+            unitElement,
+            new SourceEdit(
+                expr.end, target.end - expr.end, ';' + eol + prefix + '}'));
       }
     }
     // prepare replacement
@@ -298,11 +302,14 @@
       coveringExpressionOffsets.add(node.offset);
       coveringExpressionLengths.add(node.length);
     }
-    // we need enclosing block to add variable declaration statement
+    // We need an enclosing function.
+    // If it has a block body, we can add a new variable declaration statement
+    // into this block.  If it has an expression body, we can convert it into
+    // the block body first.
     if (coveringNode == null ||
-        coveringNode.getAncestor((node) => node is Block) == null) {
+        coveringNode.getAncestor((node) => node is FunctionBody) == null) {
       return new RefactoringStatus.fatal(
-          'Expression inside of function must be selected '
+          'An expression inside a function must be selected '
           'to activate this refactoring.');
     }
     // part of string literal
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 063329d..b76102d 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -67,6 +67,8 @@
   AnalysisDomainHandler get analysisHandler => server.handlers
       .singleWhere((handler) => handler is AnalysisDomainHandler);
 
+  AnalysisContext get testContext => server.getAnalysisContext(testFile);
+
   void addAnalysisSubscription(AnalysisService service, String file) {
     // add file to subscription
     var files = analysisSubscriptions[service];
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 7699859e..1c2e212 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -265,8 +265,8 @@
     server.setAnalysisRoots('0', [dir1Path], [], {});
     // get pair
     ContextSourcePair pair = server.getContextSourcePair(filePath);
-    Source source = pair.source;
     _assertContextOfFolder(pair.context, dir2Path);
+    Source source = pair.source;
     expect(source, isNotNull);
     expect(source.uri.scheme, 'file');
     expect(source.fullName, filePath);
@@ -299,8 +299,8 @@
     server.setAnalysisRoots('0', [rootPath], [], {});
     // get pair
     ContextSourcePair pair = server.getContextSourcePair(filePath);
-    Source source = pair.source;
     _assertContextOfFolder(pair.context, rootPath);
+    Source source = pair.source;
     expect(source, isNotNull);
     expect(source.uri.scheme, 'package');
     expect(source.fullName, filePath);
@@ -314,8 +314,8 @@
     server.setAnalysisRoots('0', [dirPath], [], {});
     // get pair
     ContextSourcePair pair = server.getContextSourcePair(filePath);
-    Source source = pair.source;
     _assertContextOfFolder(pair.context, dirPath);
+    Source source = pair.source;
     expect(source, isNotNull);
     expect(source.uri.scheme, 'file');
     expect(source.fullName, filePath);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 81d8a35..fbd51f6 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -310,7 +310,7 @@
     expect(suggestions, isEmpty);
   }
 
-  test_inDartDoc_reference1() async {
+  fail_inDartDoc_reference1() async {
     addFile(
         '/testA.dart',
         '''
@@ -498,7 +498,7 @@
     });
   }
 
-  test_partFile2() {
+  fail_partFile2() {
     addFile(
         '/testA.dart',
         '''
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index eaaadc8..766e58f 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/services/index/index.dart';
+import 'package:analyzer/task/dart.dart';
 import 'package:plugin/manager.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart' hide ERROR;
@@ -270,12 +271,36 @@
     test_simulateRefactoringException_init = false;
     test_simulateRefactoringException_final = false;
     test_simulateRefactoringException_change = false;
-    test_simulateRefactoringReset_afterInitialConditions = false;
-    test_simulateRefactoringReset_afterFinalConditions = false;
-    test_simulateRefactoringReset_afterCreateChange = false;
     super.tearDown();
   }
 
+  test_analysis_onlyOneFile() async {
+    shouldWaitForFullAnalysis = false;
+    String otherFile = '$testFolder/other.dart';
+    addFile(
+        otherFile,
+        r'''
+foo(int myName) {}
+''');
+    addTestFile('''
+import 'other.dart';
+main() {
+  foo(1 + 2);
+}
+''');
+    // Start refactoring.
+    EditGetRefactoringResult result = await getRefactoringResult(() {
+      return sendStringRequest('1 + 2', 'res', true);
+    });
+    // We get the refactoring feedback....
+    ExtractLocalVariableFeedback feedback = result.feedback;
+    expect(feedback.names, contains('myName'));
+    // ...even though other.dart is not fully analyzed.
+    var otherSource = server.getContextSourcePair(otherFile).source;
+    var otherUnit = new LibrarySpecificUnit(otherSource, otherSource);
+    expect(testContext.getResult(otherUnit, RESOLVED_UNIT), isNull);
+  }
+
   test_coveringExpressions() {
     addTestFile('''
 main() {
@@ -391,46 +416,48 @@
     });
   }
 
-  test_reset_afterCreateChange() {
-    test_simulateRefactoringReset_afterCreateChange = true;
+  test_resetOnFileChange() async {
+    String otherFile = '$testFolder/other.dart';
+    addFile(otherFile, '// other 1');
     addTestFile('''
 main() {
-  print(1 + 2);
+  foo(1 + 2);
 }
+foo(int myName) {}
 ''');
-    return waitForTasksFinished().then((_) {
-      return sendStringRequest('1 + 2', 'res', true).then((response) {
-        _expectRefactoringRequestCancelled(response);
+    // Send the first request.
+    {
+      EditGetRefactoringResult result = await getRefactoringResult(() {
+        return sendStringRequest('1 + 2', 'res', true);
       });
-    });
-  }
-
-  test_reset_afterFinalConditions() {
-    test_simulateRefactoringReset_afterFinalConditions = true;
-    addTestFile('''
+      ExtractLocalVariableFeedback feedback = result.feedback;
+      expect(feedback.names, contains('myName'));
+    }
+    int initialResetCount = test_resetCount;
+    // Update the other.dart file.
+    // The refactoring is not reset, because it's a different file.
+    addFile(otherFile, '// other 2');
+    await pumpEventQueue();
+    expect(test_resetCount, initialResetCount);
+    // Update the test.dart file.
+    modifyTestFile('''
 main() {
-  print(1 + 2);
+  foo(1 + 2);
 }
+foo(int otherName) {}
 ''');
-    return waitForTasksFinished().then((_) {
-      return sendStringRequest('1 + 2', 'res', true).then((response) {
-        _expectRefactoringRequestCancelled(response);
+    // The refactoring was reset.
+    await pumpEventQueue();
+    expect(test_resetCount, initialResetCount + 1);
+    // Send the second request, with the same kind, file and offset.
+    {
+      EditGetRefactoringResult result = await getRefactoringResult(() {
+        return sendStringRequest('1 + 2', 'res', true);
       });
-    });
-  }
-
-  test_reset_afterInitialConditions() {
-    test_simulateRefactoringReset_afterInitialConditions = true;
-    addTestFile('''
-main() {
-  print(1 + 2);
-}
-''');
-    return waitForTasksFinished().then((_) {
-      return sendStringRequest('1 + 2', 'res', true).then((response) {
-        _expectRefactoringRequestCancelled(response);
-      });
-    });
+      ExtractLocalVariableFeedback feedback = result.feedback;
+      // The refactoring was reset, so we don't get stale results.
+      expect(feedback.names, contains('otherName'));
+    }
   }
 
   test_serverError_change() {
@@ -477,12 +504,6 @@
       });
     });
   }
-
-  void _expectRefactoringRequestCancelled(Response response) {
-    expect(response.error, isNotNull);
-    expect(response,
-        isResponseFailure('0', RequestErrorCode.REFACTORING_REQUEST_CANCELLED));
-  }
 }
 
 @reflectiveTest
@@ -930,6 +951,35 @@
 
 @reflectiveTest
 class InlineLocalTest extends _AbstractGetRefactoring_Test {
+  test_analysis_onlyOneFile() async {
+    shouldWaitForFullAnalysis = false;
+    String otherFile = '$testFolder/other.dart';
+    addFile(
+        otherFile,
+        r'''
+foo(int p) {}
+''');
+    addTestFile('''
+import 'other.dart';
+main() {
+  int res = 1 + 2;
+  foo(res);
+  foo(res);
+}
+''');
+    // Start refactoring.
+    EditGetRefactoringResult result = await getRefactoringResult(() {
+      return _sendInlineRequest('res =');
+    });
+    // We get the refactoring feedback....
+    InlineLocalVariableFeedback feedback = result.feedback;
+    expect(feedback.occurrences, 2);
+    // ...even though other.dart is not fully analyzed.
+    var otherSource = server.getContextSourcePair(otherFile).source;
+    var otherUnit = new LibrarySpecificUnit(otherSource, otherSource);
+    expect(testContext.getResult(otherUnit, RESOLVED_UNIT), isNull);
+  }
+
   test_feedback() {
     addTestFile('''
 main() {
@@ -978,6 +1028,36 @@
 ''');
   }
 
+  test_resetOnFileChange() async {
+    String otherFile = '$testFolder/other.dart';
+    addFile(otherFile, '// other 1');
+    addTestFile('''
+main() {
+  int res = 1 + 2;
+  print(res);
+}
+''');
+    // Send the first request.
+    await getRefactoringResult(() {
+      return _sendInlineRequest('res = ');
+    });
+    int initialResetCount = test_resetCount;
+    // Update the other.dart file.
+    // The refactoring is not reset, because it's a different file.
+    addFile(otherFile, '// other 2');
+    await pumpEventQueue();
+    expect(test_resetCount, initialResetCount);
+    // Update the test.dart file.
+    modifyTestFile('''
+main() {
+  print(1 + 2);
+}
+''');
+    // The refactoring was reset.
+    await pumpEventQueue();
+    expect(test_resetCount, initialResetCount + 1);
+  }
+
   Future<Response> _sendInlineRequest(String search) {
     Request request = new EditGetRefactoringParams(
             RefactoringKind.INLINE_LOCAL_VARIABLE,
@@ -1164,6 +1244,13 @@
     return serverChannel.sendRequest(request);
   }
 
+  void tearDown() {
+    test_simulateRefactoringReset_afterInitialConditions = false;
+    test_simulateRefactoringReset_afterFinalConditions = false;
+    test_simulateRefactoringReset_afterCreateChange = false;
+    super.tearDown();
+  }
+
   test_cancelPendingRequest() async {
     addTestFile('''
 main() {
@@ -1733,6 +1820,51 @@
     });
   }
 
+  test_reset_afterCreateChange() {
+    test_simulateRefactoringReset_afterCreateChange = true;
+    addTestFile('''
+test() {}
+main() {
+  test();
+}
+''');
+    return waitForTasksFinished().then((_) {
+      return sendRenameRequest('test() {}', 'newName').then((response) {
+        _expectRefactoringRequestCancelled(response);
+      });
+    });
+  }
+
+  test_reset_afterFinalConditions() {
+    test_simulateRefactoringReset_afterFinalConditions = true;
+    addTestFile('''
+test() {}
+main() {
+  test();
+}
+''');
+    return waitForTasksFinished().then((_) {
+      return sendRenameRequest('test() {}', 'newName').then((response) {
+        _expectRefactoringRequestCancelled(response);
+      });
+    });
+  }
+
+  test_reset_afterInitialConditions() {
+    test_simulateRefactoringReset_afterInitialConditions = true;
+    addTestFile('''
+test() {}
+main() {
+  test();
+}
+''');
+    return waitForTasksFinished().then((_) {
+      return sendRenameRequest('test() {}', 'newName').then((response) {
+        _expectRefactoringRequestCancelled(response);
+      });
+    });
+  }
+
   test_resetOnAnalysis() {
     addTestFile('''
 main() {
@@ -1767,6 +1899,12 @@
     });
   }
 
+  void _expectRefactoringRequestCancelled(Response response) {
+    expect(response.error, isNotNull);
+    expect(response,
+        isResponseFailure('0', RequestErrorCode.REFACTORING_REQUEST_CANCELLED));
+  }
+
   SourceEdit _findEditWithId(SourceChange change, String id) {
     SourceEdit potentialEdit;
     change.edits.forEach((fileEdit) {
@@ -1782,6 +1920,8 @@
 
 @reflectiveTest
 class _AbstractGetRefactoring_Test extends AbstractAnalysisTest {
+  bool shouldWaitForFullAnalysis = true;
+
   /**
    * Asserts that [problems] has a single ERROR problem.
    */
@@ -1865,7 +2005,9 @@
 
   Future<EditGetRefactoringResult> getRefactoringResult(
       Future<Response> requestSender()) async {
-    await waitForTasksFinished();
+    if (shouldWaitForFullAnalysis) {
+      await waitForTasksFinished();
+    }
     Response response = await requestSender();
     return new EditGetRefactoringResult.fromResponse(response);
   }
diff --git a/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk.dart b/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk.dart
new file mode 100644
index 0000000..2fee03a
--- /dev/null
+++ b/pkg/analysis_server/test/integration/analysis/get_errors_nonStandard_sdk.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.integration.analysis.get.errors;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:path/path.dart' as path;
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../mock_sdk.dart';
+import '../../utils.dart';
+import '../integration_tests.dart';
+
+main() {
+  initializeTestEnvironment();
+  defineReflectiveTests(AnalysisDomainGetErrorsTest);
+}
+
+/**
+ * Tests that when an SDK path is specified on the command-line (via the `--sdk`
+ * argument) that the specified SDK is used.
+ */
+@reflectiveTest
+class AnalysisDomainGetErrorsTest
+    extends AbstractAnalysisServerIntegrationTest {
+  AnalysisDomainGetErrorsTest();
+
+  String createNonStandardSdk() {
+    MockSdkLibrary fakeLibrary =
+        new MockSdkLibrary('dart:fake', '/lib/fake/fake.dart', '');
+    String sdkPath = path.join(sourceDirectory.path, 'sdk');
+    StringBuffer librariesContent = new StringBuffer();
+    librariesContent.writeln(
+        'final Map<String, LibraryInfo> LIBRARIES = const <String, LibraryInfo> {');
+    MockSdk.LIBRARIES.toList()
+      ..add(fakeLibrary)
+      ..forEach((SdkLibrary library) {
+        List<String> components = path.posix.split(library.path);
+        components[0] = sdkPath;
+        String libraryPath = path.joinAll(components);
+        new Directory(path.dirname(libraryPath)).createSync(recursive: true);
+        new File(libraryPath)
+            .writeAsStringSync((library as MockSdkLibrary).content);
+
+        String relativePath = path.joinAll(components.sublist(2));
+        librariesContent.write('"');
+        librariesContent
+            .write(library.shortName.substring(5)); // Remove the 'dart:' prefix
+        librariesContent.write('": const LibraryInfo("');
+        librariesContent.write(relativePath);
+        librariesContent.writeln('"),');
+      });
+    librariesContent.writeln('};');
+
+    String librariesPath = path.joinAll([
+      sdkPath,
+      'lib',
+      '_internal',
+      'sdk_library_metadata',
+      'lib',
+      'libraries.dart'
+    ]);
+    new Directory(path.dirname(librariesPath)).createSync(recursive: true);
+    new File(librariesPath).writeAsStringSync(librariesContent.toString());
+
+    return sdkPath;
+  }
+
+  @override
+  Future startServer({int servicesPort, bool checked: true}) {
+    String sdkPath = createNonStandardSdk();
+    return server.start(
+        servicesPort: servicesPort, checked: checked, sdkPath: sdkPath);
+  }
+
+  Future test_getErrors() async {
+    String pathname = sourcePath('test.dart');
+    String text = r'''
+import 'dart:core';
+import 'dart:fake';
+''';
+    writeFile(pathname, text);
+    standardAnalysisSetup();
+    await analysisFinished;
+    List<AnalysisError> errors = currentAnalysisErrors[pathname];
+    expect(errors, hasLength(1));
+    expect(errors[0].code, 'unused_import');
+  }
+}
diff --git a/pkg/analysis_server/test/integration/analysis/test_all.dart b/pkg/analysis_server/test/integration/analysis/test_all.dart
index 1952f20..eb8a06e 100644
--- a/pkg/analysis_server/test/integration/analysis/test_all.dart
+++ b/pkg/analysis_server/test/integration/analysis/test_all.dart
@@ -12,6 +12,7 @@
 import 'get_errors_after_analysis_test.dart' as get_errors_after_analysis_test;
 import 'get_errors_before_analysis_test.dart'
     as get_errors_before_analysis_test;
+import 'get_errors_nonStandard_sdk.dart' as get_errors_nonStandard_sdk;
 import 'get_hover_test.dart' as get_hover_test;
 import 'highlights_test.dart' as highlights_test;
 import 'highlights_test2.dart' as highlights_test2;
@@ -36,6 +37,7 @@
     error_test.main();
     get_errors_after_analysis_test.main();
     get_errors_before_analysis_test.main();
+    get_errors_nonStandard_sdk.main();
     get_hover_test.main();
     highlights_test.main();
     highlights_test2.main();
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index 9835a1e..5ae41f9 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -597,11 +597,12 @@
    * "--pause-isolates-on-exit", allowing the observatory to be used.
    */
   Future start(
-      {bool debugServer: false,
+      {bool checked: true,
+      bool debugServer: false,
       int diagnosticPort,
       bool profileServer: false,
+      String sdkPath,
       int servicesPort,
-      bool checked: true,
       bool useAnalysisHighlight2: false}) {
     if (_process != null) {
       throw new Exception('Process already started');
@@ -612,6 +613,9 @@
         findRoot(Platform.script.toFilePath(windows: Platform.isWindows));
     String serverPath = normalize(join(rootDir, 'bin', 'server.dart'));
     List<String> arguments = [];
+    //
+    // Add VM arguments.
+    //
     if (debugServer) {
       arguments.add('--debug');
     }
@@ -631,11 +635,20 @@
     if (checked) {
       arguments.add('--checked');
     }
+    //
+    // Add the server executable.
+    //
     arguments.add(serverPath);
+    //
+    // Add server arguments.
+    //
     if (diagnosticPort != null) {
       arguments.add('--port');
       arguments.add(diagnosticPort.toString());
     }
+    if (sdkPath != null) {
+      arguments.add('--sdk=$sdkPath');
+    }
     if (useAnalysisHighlight2) {
       arguments.add('--useAnalysisHighlight2');
     }
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 18d5316..5681817 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -13,7 +13,7 @@
 import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
 
 class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_CORE = const MockSdkLibrary(
       'dart:core',
       '/lib/core/core.dart',
       '''
@@ -155,7 +155,7 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_ASYNC = const MockSdkLibrary(
       'dart:async',
       '/lib/async/async.dart',
       '''
@@ -174,7 +174,7 @@
 abstract class StreamTransformer<S, T> {}
 ''');
 
-  static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_COLLECTION = const MockSdkLibrary(
       'dart:collection',
       '/lib/collection/collection.dart',
       '''
@@ -183,7 +183,7 @@
 abstract class HashMap<K, V> implements Map<K, V> {}
 ''');
 
-  static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_CONVERT = const MockSdkLibrary(
       'dart:convert',
       '/lib/convert/convert.dart',
       '''
@@ -195,7 +195,7 @@
 class JsonDecoder extends Converter<String, Object> {}
 ''');
 
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_MATH = const MockSdkLibrary(
       'dart:math',
       '/lib/math/math.dart',
       '''
@@ -216,7 +216,7 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_HTML = const MockSdkLibrary(
       'dart:html',
       '/lib/html/dartium/html_dartium.dart',
       '''
@@ -224,7 +224,7 @@
 class HtmlElement {}
 ''');
 
-  static const _MockSdkLibrary LIB_INTERNAL = const _MockSdkLibrary(
+  static const MockSdkLibrary LIB_INTERNAL = const MockSdkLibrary(
       'dart:_internal',
       '/lib/internal/internal.dart',
       '''
@@ -252,7 +252,7 @@
 
   MockSdk() {
     LIBRARIES.forEach((SdkLibrary library) {
-      provider.newFile(library.path, (library as _MockSdkLibrary).content);
+      provider.newFile(library.path, (library as MockSdkLibrary).content);
     });
   }
 
@@ -352,12 +352,12 @@
   }
 }
 
-class _MockSdkLibrary implements SdkLibrary {
+class MockSdkLibrary implements SdkLibrary {
   final String shortName;
   final String path;
   final String content;
 
-  const _MockSdkLibrary(this.shortName, this.path, this.content);
+  const MockSdkLibrary(this.shortName, this.path, this.content);
 
   @override
   String get category => throw unimplemented;
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index 0ced288..c35969f 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -112,8 +112,8 @@
     // check conditions
     RefactoringStatus status = await refactoring.checkAllConditions();
     assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
-        expectedMessage:
-            'Expression inside of function must be selected to activate this refactoring.');
+        expectedMessage: 'An expression inside a function must be selected '
+            'to activate this refactoring.');
   }
 
   test_checkInitialConditions_stringSelection_leadingQuote() async {
@@ -953,7 +953,7 @@
 ''');
   }
 
-  test_singleExpression_inExpressionBody() async {
+  test_singleExpression_inExpressionBody_ofClosure() async {
     indexTestUnit('''
 main() {
   print((x) => x.y * x.y + 1);
@@ -973,6 +973,46 @@
         length: 3, offsets: [31, 53, 59], names: ['y']);
   }
 
+  test_singleExpression_inExpressionBody_ofFunction() async {
+    indexTestUnit('''
+foo(Point p) => p.x * p.x + p.y * p.y;
+class Point {int x; int y;}
+''');
+    _createRefactoringForString('p.x');
+    // apply refactoring
+    await _assertSuccessfulRefactoring('''
+foo(Point p) {
+  var res = p.x;
+  return res * res + p.y * p.y;
+}
+class Point {int x; int y;}
+''');
+    _assertSingleLinkedEditGroup(
+        length: 3, offsets: [21, 41, 47], names: ['x', 'i']);
+  }
+
+  test_singleExpression_inExpressionBody_ofMethod() async {
+    indexTestUnit('''
+class A {
+  foo(Point p) => p.x * p.x + p.y * p.y;
+}
+class Point {int x; int y;}
+''');
+    _createRefactoringForString('p.x');
+    // apply refactoring
+    await _assertSuccessfulRefactoring('''
+class A {
+  foo(Point p) {
+    var res = p.x;
+    return res * res + p.y * p.y;
+  }
+}
+class Point {int x; int y;}
+''');
+    _assertSingleLinkedEditGroup(
+        length: 3, offsets: [35, 57, 63], names: ['x', 'i']);
+  }
+
   test_singleExpression_inIfElseIf() {
     indexTestUnit('''
 main(int p) {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 4be083e..c033606 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.29.0-alpha.0
+* Removed `Element.docRange`.
+
+## 0.28.0-alpha.2
+* Fixed PubSummaryManager linking when a listed package does not have the unlinked bundle.
+
 ## 0.27.4-alpha.19
 * Added support for running the dev compiler in the browser.
 
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index b829bee..b5b80b7 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -590,15 +590,6 @@
   String get displayName;
 
   /**
-   * Return the source range of the documentation comment for this element,
-   * or `null` if this element does not or cannot have a documentation.
-   *
-   * Deprecated.  Use [documentationComment] instead.
-   */
-  @deprecated
-  SourceRange get docRange;
-
-  /**
    * Return the content of the documentation comment (including delimiters) for
    * this element, or `null` if this element does not or cannot have
    * documentation.
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 41d6f84..8fb6025 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -54,11 +54,26 @@
   File renameSync(String newPath);
 
   /**
-   * Synchronously write a list of bytes to the file.
+   * Return a file that refers to the same file as this file, but whose path
+   * does not contain any symbolic links.
+   */
+  File resolveSymbolicLinksSync();
+
+  /**
+   * Synchronously write the given [bytes] to the file. The new content will
+   * replace any existing content.
    *
    * Throws a [FileSystemException] if the operation fails.
    */
   void writeAsBytesSync(List<int> bytes);
+
+  /**
+   * Synchronously write the given [content] to the file. The new content will
+   * replace any existing content.
+   *
+   * Throws a [FileSystemException] if the operation fails.
+   */
+  void writeAsStringSync(String content);
 }
 
 /**
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index dbc41d1..d179d7f 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -6,6 +6,7 @@
 
 import 'dart:async';
 import 'dart:collection';
+import 'dart:convert';
 import 'dart:core' hide Resource;
 
 import 'package:analyzer/file_system/file_system.dart';
@@ -22,7 +23,6 @@
 class MemoryResourceProvider implements ResourceProvider {
   final Map<String, _MemoryResource> _pathToResource =
       new HashMap<String, _MemoryResource>();
-  final Map<String, String> _pathToContent = new HashMap<String, String>();
   final Map<String, List<int>> _pathToBytes = new HashMap<String, List<int>>();
   final Map<String, int> _pathToTimestamp = new HashMap<String, int>();
   final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers =
@@ -30,6 +30,7 @@
   int nextStamp = 0;
 
   final Context _pathContext;
+
   @override
   final AbsolutePathContext absolutePathContext;
 
@@ -46,7 +47,7 @@
   void deleteFile(String path) {
     _checkFileAtPath(path);
     _pathToResource.remove(path);
-    _pathToContent.remove(path);
+    _pathToBytes.remove(path);
     _pathToTimestamp.remove(path);
     _notifyWatchers(path, ChangeType.REMOVE);
   }
@@ -68,7 +69,7 @@
       }
     }
     _pathToResource.remove(path);
-    _pathToContent.remove(path);
+    _pathToBytes.remove(path);
     _pathToTimestamp.remove(path);
     _notifyWatchers(path, ChangeType.REMOVE);
   }
@@ -104,7 +105,7 @@
 
   void modifyFile(String path, String content) {
     _checkFileAtPath(path);
-    _pathToContent[path] = content;
+    _pathToBytes[path] = UTF8.encode(content);
     _pathToTimestamp[path] = nextStamp++;
     _notifyWatchers(path, ChangeType.MODIFY);
   }
@@ -126,7 +127,7 @@
   File newFile(String path, String content, [int stamp]) {
     path = pathContext.normalize(path);
     _MemoryFile file = _newFile(path);
-    _pathToContent[path] = content;
+    _pathToBytes[path] = UTF8.encode(content);
     _pathToTimestamp[path] = stamp ?? nextStamp++;
     _notifyWatchers(path, ChangeType.ADD);
     return file;
@@ -179,7 +180,6 @@
     }
     _MemoryFile newFile = _newFile(newPath);
     _pathToResource.remove(path);
-    _pathToContent[newPath] = _pathToContent.remove(path);
     _pathToBytes[newPath] = _pathToBytes.remove(path);
     _pathToTimestamp[newPath] = _pathToTimestamp.remove(path);
     if (existingNewResource != null) {
@@ -195,7 +195,7 @@
     newFolder(pathContext.dirname(path));
     _MemoryFile file = new _MemoryFile(this, path);
     _pathToResource[path] = file;
-    _pathToContent[path] = content;
+    _pathToBytes[path] = UTF8.encode(content);
     _pathToTimestamp[path] = stamp ?? nextStamp++;
     _notifyWatchers(path, ChangeType.MODIFY);
     return file;
@@ -245,7 +245,7 @@
     });
   }
 
-  void _setFileBytes(_MemoryFile file, List<int> bytes) {
+  void _setFileContent(_MemoryFile file, List<int> bytes) {
     String path = file.path;
     _pathToResource[path] = file;
     _pathToBytes[path] = bytes;
@@ -310,12 +310,22 @@
   }
 
   @override
+  File resolveSymbolicLinksSync() {
+    return throw new FileSystemException(path, "File does not exist");
+  }
+
+  @override
   Uri toUri() => new Uri.file(path, windows: _provider.pathContext == windows);
 
   @override
   void writeAsBytesSync(List<int> bytes) {
     throw new FileSystemException(path, 'File could not be written');
   }
+
+  @override
+  void writeAsStringSync(String content) {
+    throw new FileSystemException(path, 'File could not be written');
+  }
 }
 
 /**
@@ -355,16 +365,7 @@
 
   @override
   List<int> readAsBytesSync() {
-    List<int> bytes = _provider._pathToBytes[path];
-    if (bytes == null) {
-      throw new FileSystemException(path, 'File "$path" is not binary.');
-    }
-    return bytes;
-  }
-
-  @override
-  String readAsStringSync() {
-    String content = _provider._pathToContent[path];
+    List<int> content = _provider._pathToBytes[path];
     if (content == null) {
       throw new FileSystemException(path, 'File "$path" does not exist.');
     }
@@ -372,16 +373,33 @@
   }
 
   @override
+  String readAsStringSync() {
+    List<int> content = _provider._pathToBytes[path];
+    if (content == null) {
+      throw new FileSystemException(path, 'File "$path" does not exist.');
+    }
+    return UTF8.decode(content);
+  }
+
+  @override
   File renameSync(String newPath) {
     return _provider.renameFileSync(this, newPath);
   }
 
   @override
+  File resolveSymbolicLinksSync() => this;
+
+  @override
   Uri toUri() => new Uri.file(path, windows: _provider.pathContext == windows);
 
   @override
   void writeAsBytesSync(List<int> bytes) {
-    _provider._setFileBytes(this, bytes);
+    _provider._setFileContent(this, bytes);
+  }
+
+  @override
+  void writeAsStringSync(String content) {
+    _provider._setFileContent(this, UTF8.encode(content));
   }
 }
 
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 3b02335..b771149 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -129,13 +129,17 @@
   @override
   int get modificationStamp {
     try {
-      io.File file = _entry as io.File;
-      return file.lastModifiedSync().millisecondsSinceEpoch;
+      return _file.lastModifiedSync().millisecondsSinceEpoch;
     } on io.FileSystemException catch (exception) {
       throw new FileSystemException(exception.path, exception.message);
     }
   }
 
+  /**
+   * Return the underlying file being represented by this wrapper.
+   */
+  io.File get _file => _entry as io.File;
+
   @override
   Source createSource([Uri uri]) {
     return new FileSource(this, uri ?? pathContext.toUri(path));
@@ -149,8 +153,7 @@
   @override
   List<int> readAsBytesSync() {
     try {
-      io.File file = _entry as io.File;
-      return file.readAsBytesSync();
+      return _file.readAsBytesSync();
     } on io.FileSystemException catch (exception) {
       throw new FileSystemException(exception.path, exception.message);
     }
@@ -159,8 +162,7 @@
   @override
   String readAsStringSync() {
     try {
-      io.File file = _entry as io.File;
-      return FileBasedSource.fileReadMode(file.readAsStringSync());
+      return FileBasedSource.fileReadMode(_file.readAsStringSync());
     } on io.FileSystemException catch (exception) {
       throw new FileSystemException(exception.path, exception.message);
     }
@@ -169,9 +171,16 @@
   @override
   File renameSync(String newPath) {
     try {
-      io.File file = _entry as io.File;
-      io.File newFile = file.renameSync(newPath);
-      return new _PhysicalFile(newFile);
+      return new _PhysicalFile(_file.renameSync(newPath));
+    } on io.FileSystemException catch (exception) {
+      throw new FileSystemException(exception.path, exception.message);
+    }
+  }
+
+  @override
+  File resolveSymbolicLinksSync() {
+    try {
+      return new _PhysicalFile(new io.File(_file.resolveSymbolicLinksSync()));
     } on io.FileSystemException catch (exception) {
       throw new FileSystemException(exception.path, exception.message);
     }
@@ -183,8 +192,16 @@
   @override
   void writeAsBytesSync(List<int> bytes) {
     try {
-      io.File file = _entry as io.File;
-      file.writeAsBytesSync(bytes);
+      _file.writeAsBytesSync(bytes);
+    } on io.FileSystemException catch (exception) {
+      throw new FileSystemException(exception.path, exception.message);
+    }
+  }
+
+  @override
+  void writeAsStringSync(String content) {
+    try {
+      _file.writeAsStringSync(content);
     } on io.FileSystemException catch (exception) {
       throw new FileSystemException(exception.path, exception.message);
     }
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 1ba7dd2..51c0a21 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -6,7 +6,6 @@
 
 import 'dart:collection';
 import 'dart:core' hide Resource;
-import 'dart:io' as io;
 
 import 'package:analyzer/context/declared_variables.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -18,7 +17,6 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/options.dart';
-import 'package:package_config/discovery.dart';
 import 'package:package_config/packages.dart';
 import 'package:package_config/packages_file.dart';
 import 'package:package_config/src/packages_impl.dart';
@@ -60,7 +58,7 @@
   final DartSdkManager sdkManager;
 
   /**
-   * The cache containing the contents of overlayed files.
+   * The cache containing the contents of overlaid files.
    */
   final ContentCache contentCache;
 
@@ -183,30 +181,29 @@
 
   Packages createPackageMap(String rootDirectoryPath) {
     if (defaultPackageFilePath != null) {
-      // TODO(brianwilkerson) Figure out why we're going through Uri rather than
-      // just creating the file from the path.
-      Uri fileUri = new Uri.file(defaultPackageFilePath);
-      io.File configFile = new io.File.fromUri(fileUri).absolute;
+      File configFile = resourceProvider.getFile(defaultPackageFilePath);
       List<int> bytes = configFile.readAsBytesSync();
-      Map<String, Uri> map = parse(bytes, configFile.uri);
+      Map<String, Uri> map = parse(bytes, configFile.toUri());
       return new MapPackages(map);
     } else if (defaultPackagesDirectoryPath != null) {
-      return getPackagesDirectory(
-          new Uri.directory(defaultPackagesDirectoryPath));
+      Folder folder = resourceProvider.getFolder(defaultPackagesDirectoryPath);
+      return getPackagesFromFolder(folder);
     }
-    return findPackagesFromFile(new Uri.directory(rootDirectoryPath));
+    return findPackagesFromFile(rootDirectoryPath);
   }
 
   SourceFactory createSourceFactory(
       String rootDirectoryPath, AnalysisOptions options) {
     Folder _folder = null;
     Folder folder() {
-      return _folder ??= resourceProvider.getResource('.');
+      return _folder ??= resourceProvider.getFolder(rootDirectoryPath);
     }
 
-    UriResolver fileResolver = fileResolverProvider == null
-        ? new ResourceUriResolver(resourceProvider)
-        : fileResolverProvider(folder());
+    UriResolver fileResolver;
+    if (fileResolverProvider != null) {
+      fileResolver = fileResolverProvider(folder());
+    }
+    fileResolver ??= new ResourceUriResolver(resourceProvider);
     if (packageResolverProvider != null) {
       UriResolver packageResolver = packageResolverProvider(folder());
       if (packageResolver != null) {
@@ -221,11 +218,13 @@
         return new SourceFactory(resolvers);
       }
     }
-    Map<String, List<Folder>> packageMap =
-        convertPackagesToMap(createPackageMap(rootDirectoryPath));
+    Packages packages = createPackageMap(rootDirectoryPath);
+    Map<String, List<Folder>> packageMap = convertPackagesToMap(packages);
     List<UriResolver> resolvers = <UriResolver>[];
     resolvers.add(new DartUriResolver(findSdk(packageMap, options)));
     if (packageMap != null) {
+      // TODO(brianwilkerson) I think that we don't need a PackageUriResolver
+      // when we can pass the packages object to the source factory directly.
       resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap));
     }
     resolvers.add(fileResolver);
@@ -246,6 +245,29 @@
   }
 
   /**
+   * Finds a package resolution strategy for the directory at the given absolute
+   * [path].
+   *
+   * This function first tries to locate a `.packages` file in the directory. If
+   * that is not found, it instead checks for the presence of a `packages/`
+   * directory in the same place. If that also fails, it starts checking parent
+   * directories for a `.packages` file, and stops if it finds it. Otherwise it
+   * gives up and returns [Packages.noPackages].
+   */
+  Packages findPackagesFromFile(String path) {
+    Resource location = _findPackagesLocation(path);
+    if (location is File) {
+      List<int> fileBytes = location.readAsBytesSync();
+      Map<String, Uri> map =
+          parse(fileBytes, resourceProvider.pathContext.toUri(location.path));
+      return new MapPackages(map);
+    } else if (location is Folder) {
+      return getPackagesFromFolder(location);
+    }
+    return Packages.noPackages;
+  }
+
+  /**
    * Return the SDK that should be used to analyze code. Use the given
    * [packageMap] and [options] to locate the SDK.
    */
@@ -349,6 +371,77 @@
     }
     return null;
   }
+
+  /**
+   * Create a [Packages] object for a 'package' directory ([folder]).
+   *
+   * Package names are resolved as relative to sub-directories of the package
+   * directory.
+   */
+  Packages getPackagesFromFolder(Folder folder) {
+    Map<String, Uri> map = new HashMap<String, Uri>();
+    for (Resource child in folder.getChildren()) {
+      if (child is Folder) {
+        String packageName = resourceProvider.pathContext.basename(child.path);
+        // Create a file URI (rather than a directory URI) and add a '.' so that
+        // the URI is suitable for resolving relative URI's against it.
+        //
+        // TODO(brianwilkerson) Decide whether we need to pass in a 'windows:'
+        // argument for testing purposes.
+        map[packageName] = resourceProvider.pathContext.toUri(
+            resourceProvider.pathContext.join(folder.path, packageName, '.'));
+      }
+    }
+    return new MapPackages(map);
+  }
+
+  /**
+   * Find the location of the package resolution file/directory for the
+   * directory at the given absolute [path].
+   *
+   * Checks for a `.packages` file in the [path]. If not found,
+   * checks for a `packages` directory in the same directory. If still not
+   * found, starts checking parent directories for `.packages` until reaching
+   * the root directory.
+   *
+   * Return a [File] object representing a `.packages` file if one is found, a
+   * [Folder] object for the `packages/` directory if that is found, or `null`
+   * if neither is found.
+   */
+  Resource _findPackagesLocation(String path) {
+    Folder folder = resourceProvider.getFolder(path);
+    if (!folder.exists) {
+      throw new ArgumentError.value(path, "path", "Directory does not exist.");
+    }
+    File checkForConfigFile(Folder folder) {
+      File file = folder.getChildAssumingFile('.packages');
+      if (file.exists) {
+        return file;
+      }
+      return null;
+    }
+
+    // Check for $cwd/.packages
+    File packagesCfgFile = checkForConfigFile(folder);
+    if (packagesCfgFile != null) {
+      return packagesCfgFile;
+    }
+    // Check for $cwd/packages/
+    Folder packagesDir = folder.getChildAssumingFolder("packages");
+    if (packagesDir.exists) {
+      return packagesDir;
+    }
+    // Check for cwd(/..)+/.packages
+    Folder parentDir = folder.parent;
+    while (parentDir != null) {
+      packagesCfgFile = checkForConfigFile(parentDir);
+      if (packagesCfgFile != null) {
+        return packagesCfgFile;
+      }
+      parentDir = parentDir.parent;
+    }
+    return null;
+  }
 }
 
 /**
@@ -378,7 +471,7 @@
   }
 
   /**
-   * Programatically add an `_embedder.yaml` mapping.
+   * Programmatically add an `_embedder.yaml` mapping.
    */
   void addEmbedderYaml(Folder libDir, String embedderYaml) {
     _processEmbedderYaml(libDir, embedderYaml);
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index 7b956a9..58dda21 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -27,6 +27,11 @@
     AnalysisTarget target, ResultDescriptor<V> result);
 
 /**
+ * Return `true` if some results of the [target] should be flushed.
+ */
+typedef bool FlushTargetFilter<V>(AnalysisTarget target);
+
+/**
  * Return `true` if the given [target] is a priority one.
  */
 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target);
@@ -113,11 +118,11 @@
   }
 
   /**
-   * Flush results that satisfy the given [filter].
+   * Flush results that satisfy the given [targetFilter] and [resultFilter].
    */
-  void flush(FlushResultFilter filter) {
+  void flush(FlushTargetFilter targetFilter, FlushResultFilter resultFilter) {
     for (CachePartition partition in _partitions) {
-      partition.flush(filter);
+      partition.flush(targetFilter, resultFilter);
     }
   }
 
@@ -405,14 +410,18 @@
   }
 
   /**
-   * Flush results that satisfy the given [filter].
+   * Flush results that satisfy the given [targetFilter] and [resultFilter].
    */
-  void flush(FlushResultFilter filter) {
-    _resultMap.forEach((ResultDescriptor result, ResultData data) {
-      if (filter(target, result)) {
-        data.flush();
-      }
-    });
+  void flush(FlushTargetFilter targetFilter, FlushResultFilter resultFilter) {
+    if (targetFilter(target)) {
+      _resultMap.forEach((ResultDescriptor result, ResultData data) {
+        if (data.state == CacheState.VALID) {
+          if (resultFilter(target, result)) {
+            data.flush();
+          }
+        }
+      });
+    }
   }
 
   /**
@@ -608,6 +617,9 @@
     if (delta == null) {
       return false;
     }
+    if (!delta.shouldGatherChanges) {
+      return true;
+    }
     for (int i = 0; i < 64; i++) {
       bool hasVisitChanges = false;
       _visitResults(nextVisitId++, result,
@@ -1090,11 +1102,11 @@
   }
 
   /**
-   * Flush results that satisfy the given [filter].
+   * Flush results that satisfy the given [targetFilter] and [resultFilter].
    */
-  void flush(FlushResultFilter filter) {
+  void flush(FlushTargetFilter targetFilter, FlushResultFilter resultFilter) {
     for (CacheEntry entry in entryMap.values) {
-      entry.flush(filter);
+      entry.flush(targetFilter, resultFilter);
     }
   }
 
@@ -1246,6 +1258,21 @@
 
   Delta(this.source);
 
+  /**
+   * Return `true` if this delta needs cache walking to gather additional
+   * changes before it can be used to [validate].  In this case [gatherChanges]
+   * is invoked for every targeted result in transitive dependencies, and
+   * [gatherEnd] is invoked after cache walking is done.
+   */
+  bool get shouldGatherChanges => false;
+
+  /**
+   * This method is called during a cache walk, so that the delta can gather
+   * additional changes to which are caused by the changes it already knows
+   * about.  Return `true` if a new change was added, so that one more cache
+   * walk will be performed (to include changes that depend on results which we
+   * decided to be changed later in the previous cache walk).
+   */
   bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
       ResultDescriptor descriptor, Object value) {
     return false;
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 6d861b5..55cd2c8 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -1856,6 +1856,9 @@
       return;
     }
 
+    // We're going to update the cache, so reset the driver.
+    driver.reset();
+
     // We need to invalidate the cache.
     {
       if (analysisOptions.finerGrainedInvalidation &&
@@ -1871,6 +1874,7 @@
           CacheEntry unitEntry =
               getCacheEntry(new LibrarySpecificUnit(librarySource, source));
           CompilationUnit oldUnit = RESOLVED_UNIT_RESULTS
+              .skipWhile((result) => result != RESOLVED_UNIT2)
               .map(unitEntry.getValue)
               .firstWhere((unit) => unit != null, orElse: () => null);
           // If we have the old unit, we can try to update it.
@@ -1897,7 +1901,6 @@
       entry.setState(MODIFICATION_TIME, CacheState.INVALID);
       entry.setState(SOURCE_KIND, CacheState.INVALID);
     }
-    driver.reset();
     for (WorkManager workManager in workManagers) {
       workManager.applyChange(
           Source.EMPTY_LIST, <Source>[source], Source.EMPTY_LIST);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 491025e..d2fbf23 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -584,18 +584,6 @@
   }
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedClass != null) {
-      UnlinkedDocumentationComment comment =
-          _unlinkedClass.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedClass != null) {
       return _unlinkedClass?.documentationComment?.text;
@@ -1814,18 +1802,6 @@
       : super(enumElement);
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedEnumValue != null) {
-      UnlinkedDocumentationComment comment =
-          _unlinkedEnumValue.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedEnumValue != null) {
       return _unlinkedEnumValue?.documentationComment?.text;
@@ -2693,17 +2669,6 @@
   String _docComment;
 
   /**
-   * The offset to the beginning of the documentation comment,
-   * or `null` if this element does not have a documentation comment.
-   */
-  int _docRangeOffset;
-
-  /**
-   * The length of the documentation comment range for this element.
-   */
-  int _docRangeLength;
-
-  /**
    * The offset of the beginning of the element's code in the file that contains
    * the element, or `null` if the element is synthetic.
    */
@@ -2756,14 +2721,6 @@
   String get displayName => _name;
 
   @override
-  SourceRange get docRange {
-    if (_docRangeOffset != null && _docRangeLength != null) {
-      return new SourceRange(_docRangeOffset, _docRangeLength);
-    }
-    return null;
-  }
-
-  @override
   String get documentationComment => _docComment;
 
   /**
@@ -3108,15 +3065,6 @@
   }
 
   /**
-   * Set the documentation comment source range for this element.
-   */
-  void setDocRange(int offset, int length) {
-    assert(!isResynthesized);
-    _docRangeOffset = offset;
-    _docRangeLength = length;
-  }
-
-  /**
    * Set whether the given [modifier] is associated with this element to
    * correspond to the given [value].
    */
@@ -3402,17 +3350,6 @@
   }
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedEnum != null) {
-      UnlinkedDocumentationComment comment = _unlinkedEnum.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedEnum != null) {
       return _unlinkedEnum?.documentationComment?.text;
@@ -3666,18 +3603,6 @@
   }
 
   @override
-  SourceRange get docRange {
-    if (serializedExecutable != null) {
-      UnlinkedDocumentationComment comment =
-          serializedExecutable.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (serializedExecutable != null) {
       return serializedExecutable?.documentationComment?.text;
@@ -4644,18 +4569,6 @@
   String get displayName => name;
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedTypedef != null) {
-      UnlinkedDocumentationComment comment =
-          _unlinkedTypedef.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedTypedef != null) {
       return _unlinkedTypedef?.documentationComment?.text;
@@ -5413,18 +5326,6 @@
   }
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedDefiningUnit != null) {
-      UnlinkedDocumentationComment comment =
-          _unlinkedDefiningUnit.libraryDocumentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedDefiningUnit != null) {
       return _unlinkedDefiningUnit?.libraryDocumentationComment?.text;
@@ -6458,9 +6359,6 @@
   String get displayName => _name;
 
   @override
-  SourceRange get docRange => null;
-
-  @override
   String get documentationComment => null;
 
   @override
@@ -6744,18 +6642,6 @@
   }
 
   @override
-  SourceRange get docRange {
-    if (_unlinkedVariable != null) {
-      UnlinkedDocumentationComment comment =
-          _unlinkedVariable.documentationComment;
-      return comment != null
-          ? new SourceRange(comment.offset, comment.length)
-          : null;
-    }
-    return super.docRange;
-  }
-
-  @override
   String get documentationComment {
     if (_unlinkedVariable != null) {
       return _unlinkedVariable?.documentationComment?.text;
diff --git a/pkg/analyzer/lib/src/dart/element/handle.dart b/pkg/analyzer/lib/src/dart/element/handle.dart
index 6823b99..9bd58af 100644
--- a/pkg/analyzer/lib/src/dart/element/handle.dart
+++ b/pkg/analyzer/lib/src/dart/element/handle.dart
@@ -340,10 +340,6 @@
   @override
   String get displayName => actualElement.displayName;
 
-  @deprecated
-  @override
-  SourceRange get docRange => actualElement.docRange;
-
   @override
   String get documentationComment => actualElement.documentationComment;
 
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 76ec36c..bd3dc3f 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -447,10 +447,6 @@
   @override
   String get displayName => _baseElement.displayName;
 
-  @deprecated
-  @override
-  SourceRange get docRange => _baseElement.docRange;
-
   @override
   String get documentationComment => _baseElement.documentationComment;
 
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
index d692a28..ec64039 100644
--- a/pkg/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -265,10 +265,16 @@
   static const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs';
   final Map<String, String> _urlMappings = new HashMap<String, String>();
 
+  PackageBundle _embedderBundle;
+
   EmbedderSdk(
       ResourceProvider resourceProvider, Map<Folder, YamlMap> embedderYamls) {
     this.resourceProvider = resourceProvider;
     embedderYamls?.forEach(_processEmbedderYaml);
+    if (embedderYamls?.length == 1) {
+      Folder libFolder = embedderYamls.keys.first;
+      _loadEmbedderBundle(libFolder);
+    }
   }
 
   @override
@@ -281,13 +287,15 @@
   Map<String, String> get urlMappings => _urlMappings;
 
   @override
-  PackageBundle getLinkedBundle() => null;
-
-  @override
   String getRelativePathFromFile(File file) => file.path;
 
   @override
-  PackageBundle getSummarySdkBundle(bool strongMode) => null;
+  PackageBundle getSummarySdkBundle(bool strongMode) {
+    if (strongMode) {
+      return _embedderBundle;
+    }
+    return null;
+  }
 
   @override
   Source internalMapDartUri(String dartUri) {
@@ -329,6 +337,16 @@
     }
   }
 
+  void _loadEmbedderBundle(Folder libFolder) {
+    File bundleFile = libFolder.parent.getChildAssumingFile('sdk.ds');
+    if (bundleFile.exists) {
+      try {
+        List<int> bytes = bundleFile.readAsBytesSync();
+        _embedderBundle = new PackageBundle.fromBuffer(bytes);
+      } on FileSystemException {}
+    }
+  }
+
   /**
    * Install the mapping from [name] to [libDir]/[file].
    */
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index a9f2f6c..4e2de26 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1439,6 +1439,10 @@
       List<ParameterElement> parameters,
       List<AstNode> parameterLocations,
       SimpleIdentifier errorNameTarget) {
+    if (_options.strongMode) {
+      return false; // strong mode already checked for this
+    }
+
     bool isGetter = false;
     bool isSetter = false;
     if (derivedElement is PropertyAccessorElement) {
@@ -1778,6 +1782,7 @@
       List<ParameterElement> parameters,
       List<AstNode> parameterLocations,
       SimpleIdentifier errorNameTarget) {
+    assert(!_options.strongMode); // strong mode already checked for these
     //
     // Compute the overridden executable from the InheritanceManager
     //
@@ -1802,6 +1807,10 @@
    */
   void _checkForAllInvalidOverrideErrorCodesForField(
       FieldDeclaration declaration) {
+    if (_options.strongMode) {
+      return; // strong mode already checked for this
+    }
+
     if (_enclosingClass == null || declaration.isStatic) {
       return;
     }
@@ -1833,6 +1842,9 @@
    */
   void _checkForAllInvalidOverrideErrorCodesForMethod(
       MethodDeclaration method) {
+    if (_options.strongMode) {
+      return; // strong mode already checked for this
+    }
     if (_enclosingClass == null ||
         method.isStatic ||
         method.body is NativeFunctionBody) {
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 9e2a1d4..c1bc461 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -77,6 +77,7 @@
     bool isByTask(TaskDescriptor taskDescriptor) {
       return taskDescriptor.results.contains(descriptor);
     }
+
     if (descriptor == CONTENT) {
       return DeltaResult.KEEP_CONTINUE;
     }
@@ -809,6 +810,7 @@
             }
           }
         }
+
         Element parentElement = ElementLocator.locate(newComment.parent);
         if (parentElement is ElementImpl) {
           setElementDocumentationComment(parentElement, parent);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index db027ac..9d04dff 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -56,7 +56,7 @@
    * A flag indicating whether a surrounding member (compilation unit or class)
    * is deprecated.
    */
-  bool inDeprecatedMember = false;
+  bool inDeprecatedMember;
 
   /**
    * The error reporter by which errors will be reported.
@@ -88,7 +88,9 @@
       this._errorReporter, TypeProvider typeProvider, this._currentLibrary,
       {TypeSystem typeSystem})
       : _futureNullType = typeProvider.futureNullType,
-        _typeSystem = typeSystem ?? new TypeSystemImpl();
+        _typeSystem = typeSystem ?? new TypeSystemImpl() {
+    inDeprecatedMember = _currentLibrary.isDeprecated;
+  }
 
   @override
   Object visitAnnotation(Annotation node) {
@@ -7258,7 +7260,7 @@
     DartType contextType = node.staticInvokeType;
     if (contextType is FunctionType) {
       DartType originalType = node.function.staticType;
-      DartType returnContextType = InferenceContext.getType(node);
+      DartType returnContextType = InferenceContext.getContext(node);
       TypeSystem ts = typeSystem;
       if (returnContextType != null &&
           node.typeArguments == null &&
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 82e4e86..f889078 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -85,6 +85,7 @@
  * Instances of the class [ExplicitSourceResolver] map URIs to files on disk
  * using a fixed mapping provided at construction time.
  */
+@deprecated
 class ExplicitSourceResolver extends UriResolver {
   final Map<Uri, JavaFile> uriToFileMap;
   final Map<String, Uri> pathToUriMap;
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 628c340..d678751 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -1944,16 +1944,6 @@
         }
       }
 
-      DartType returnContext = InferenceContext.getContext(node);
-      DartType returnType;
-      if (returnContext is FutureUnionType) {
-        returnType = _resolver.isSubtypeOfFuture(fnType.returnType)
-            ? returnContext.futureOfType
-            : returnContext.type;
-      } else {
-        returnType = returnContext;
-      }
-
       // Special case Future<T>.then upwards inference. It has signature:
       //
       //     <S>(T -> (S | Future<S>)) -> Future<S>
@@ -1991,8 +1981,8 @@
           }
         }
       }
-      return ts.inferGenericFunctionCall(
-          _typeProvider, fnType, paramTypes, argTypes, returnType);
+      return ts.inferGenericFunctionCall(_typeProvider, fnType, paramTypes,
+          argTypes, InferenceContext.getContext(node));
     }
     return null;
   }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 9a4a5cf..1abf232 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -277,6 +277,16 @@
       return fnType;
     }
 
+    // If we're in a future union context, choose either the Future<T> or the T
+    // based on the function's return type.
+    if (returnContextType is FutureUnionType) {
+      var futureUnion = returnContextType as FutureUnionType;
+      returnContextType =
+          isSubtypeOf(fnType.returnType, typeProvider.futureDynamicType)
+              ? futureUnion.futureOfType
+              : futureUnion.type;
+    }
+
     // Create a TypeSystem that will allow certain type parameters to be
     // inferred. It will optimistically assume these type parameters can be
     // subtypes (or supertypes) as necessary, and track the constraints that
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index d244dce..0f18777 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -51,7 +51,6 @@
   if (comment != null && comment.isDocumentation) {
     element.documentationComment =
         comment.tokens.map((Token t) => t.lexeme).join('\n');
-    element.setDocRange(comment.offset, comment.length);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 626f443..641287e 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -4795,32 +4795,13 @@
 }
 
 class UnlinkedDocumentationCommentBuilder extends Object with _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
-  int _length;
-  int _offset;
   String _text;
 
   @override
-  int get length => _length ??= 0;
-
-  /**
-   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
-   */
-  void set length(int _value) {
-    assert(_value == null || _value >= 0);
-    _length = _value;
-  }
+  int get length => throw new UnimplementedError('attempt to access deprecated field');
 
   @override
-  int get offset => _offset ??= 0;
-
-  /**
-   * Offset of the beginning of the documentation comment relative to the
-   * beginning of the file.
-   */
-  void set offset(int _value) {
-    assert(_value == null || _value >= 0);
-    _offset = _value;
-  }
+  int get offset => throw new UnimplementedError('attempt to access deprecated field');
 
   @override
   String get text => _text ??= '';
@@ -4835,10 +4816,8 @@
     _text = _value;
   }
 
-  UnlinkedDocumentationCommentBuilder({int length, int offset, String text})
-    : _length = length,
-      _offset = offset,
-      _text = text;
+  UnlinkedDocumentationCommentBuilder({String text})
+    : _text = text;
 
   /**
    * Flush [informative] data recursively.
@@ -4850,9 +4829,7 @@
    * Accumulate non-[informative] data into [signature].
    */
   void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._length ?? 0);
     signature.addString(this._text ?? '');
-    signature.addInt(this._offset ?? 0);
   }
 
   fb.Offset finish(fb.Builder fbBuilder) {
@@ -4861,12 +4838,6 @@
       offset_text = fbBuilder.writeString(_text);
     }
     fbBuilder.startTable();
-    if (_length != null && _length != 0) {
-      fbBuilder.addUint32(0, _length);
-    }
-    if (_offset != null && _offset != 0) {
-      fbBuilder.addUint32(2, _offset);
-    }
     if (offset_text != null) {
       fbBuilder.addOffset(1, offset_text);
     }
@@ -4887,21 +4858,13 @@
 
   _UnlinkedDocumentationCommentImpl(this._bc, this._bcOffset);
 
-  int _length;
-  int _offset;
   String _text;
 
   @override
-  int get length {
-    _length ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
-    return _length;
-  }
+  int get length => throw new UnimplementedError('attempt to access deprecated field');
 
   @override
-  int get offset {
-    _offset ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 2, 0);
-    return _offset;
-  }
+  int get offset => throw new UnimplementedError('attempt to access deprecated field');
 
   @override
   String get text {
@@ -4914,16 +4877,12 @@
   @override
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
-    if (length != 0) _result["length"] = length;
-    if (offset != 0) _result["offset"] = offset;
     if (text != '') _result["text"] = text;
     return _result;
   }
 
   @override
   Map<String, Object> toMap() => {
-    "length": length,
-    "offset": offset,
     "text": text,
   };
 
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index ba46f01..de2afb2 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -1631,13 +1631,13 @@
   /**
    * Length of the documentation comment (prior to replacing '\r\n' with '\n').
    */
-  length:uint (id: 0);
+  length:uint (id: 0, deprecated);
 
   /**
    * Offset of the beginning of the documentation comment relative to the
    * beginning of the file.
    */
-  offset:uint (id: 2);
+  offset:uint (id: 2, deprecated);
 
   /**
    * Text of the documentation comment, with '\r\n' replaced by '\n'.
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index 70b329b..3cd6562 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -1674,6 +1674,7 @@
    * Length of the documentation comment (prior to replacing '\r\n' with '\n').
    */
   @Id(0)
+  @deprecated
   int get length;
 
   /**
@@ -1681,6 +1682,7 @@
    * beginning of the file.
    */
   @Id(2)
+  @deprecated
   int get offset;
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
index 719dbab..dc9685f 100644
--- a/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary/package_bundle_reader.dart
@@ -207,6 +207,9 @@
           result == READY_LIBRARY_ELEMENT7) {
         entry.setValue(result, true, TargetedResult.EMPTY_LIST);
         return true;
+      } else if (result == MODIFICATION_TIME) {
+        entry.setValue(result, 0, TargetedResult.EMPTY_LIST);
+        return true;
       } else if (result == SOURCE_KIND) {
         if (_dataStore.linkedMap.containsKey(uriString)) {
           entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart
index dc2d110..ed7221a 100644
--- a/pkg/analyzer/lib/src/summary/pub_summary.dart
+++ b/pkg/analyzer/lib/src/summary/pub_summary.dart
@@ -11,12 +11,10 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/scanner/reader.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -139,86 +137,6 @@
   pathos.Context get pathContext => resourceProvider.pathContext;
 
   /**
-   * Compute and return the linked bundle for the SDK extension for the given
-   * [context], or `null` if none of the packages has an SDK extension.  At most
-   * one extension library is supported, if more than one is found, then an
-   * error will be logged, and `null` returned.
-   */
-  PackageBundle computeSdkExtension(
-      AnalysisContext context, PackageBundle sdkBundle) {
-    // Prepare SDK extension library files.
-    String libUriStr;
-    String libPath;
-    {
-      Map<String, List<Folder>> packageMap = context.sourceFactory.packageMap;
-      SdkExtensionFinder extFinder = new SdkExtensionFinder(packageMap);
-      Map<String, String> sdkExtMappings = extFinder.urlMappings;
-      if (sdkExtMappings.length == 1) {
-        libUriStr = sdkExtMappings.keys.first;
-        libPath = sdkExtMappings.values.first;
-      } else if (sdkExtMappings.length > 1) {
-        AnalysisEngine.instance.logger
-            .logError('At most one _sdkext file is supported, '
-                'with at most one extension library. $sdkExtMappings found.');
-        return null;
-      } else {
-        return null;
-      }
-    }
-    // Compute the extension unlinked bundle.
-    bool strong = context.analysisOptions.strongMode;
-    PackageBundleAssembler assembler = new PackageBundleAssembler();
-    try {
-      File libFile = resourceProvider.getFile(libPath);
-      Uri libUri = FastUri.parse(libUriStr);
-      Source libSource = libFile.createSource(libUri);
-      CompilationUnit libraryUnit = _parse(libSource, strong);
-      // Add the library unit.
-      assembler.addUnlinkedUnit(libSource, serializeAstUnlinked(libraryUnit));
-      // Add part units.
-      for (Directive directive in libraryUnit.directives) {
-        if (directive is PartDirective) {
-          Source partSource;
-          {
-            String partUriStr = directive.uri.stringValue;
-            Uri partUri = resolveRelativeUri(libUri, FastUri.parse(partUriStr));
-            pathos.Context pathContext = resourceProvider.pathContext;
-            String partPath =
-                pathContext.join(pathContext.dirname(libPath), partUriStr);
-            File partFile = resourceProvider.getFile(partPath);
-            partSource = partFile.createSource(partUri);
-          }
-          CompilationUnit partUnit = _parse(partSource, strong);
-          assembler.addUnlinkedUnit(partSource, serializeAstUnlinked(partUnit));
-        }
-      }
-      // Add the SDK and the unlinked extension bundle.
-      PackageBundleBuilder unlinkedBuilder = assembler.assemble();
-      SummaryDataStore store = new SummaryDataStore(const <String>[]);
-      store.addBundle(null, sdkBundle);
-      store.addBundle(null, unlinkedBuilder);
-      // Link the extension bundle.
-      Map<String, LinkedLibraryBuilder> linkedLibraries =
-          link([libUriStr].toSet(), (String absoluteUri) {
-        return store.linkedMap[absoluteUri];
-      }, (String absoluteUri) {
-        return store.unlinkedMap[absoluteUri];
-      }, strong);
-      if (linkedLibraries.length != 1) {
-        return null;
-      }
-      // Append linked libraries into the assembler.
-      linkedLibraries.forEach((uri, library) {
-        assembler.addLinkedLibrary(uri, library);
-      });
-      List<int> bytes = assembler.assemble().toBuffer();
-      return new PackageBundle.fromBuffer(bytes);
-    } on FileSystemException {
-      return null;
-    }
-  }
-
-  /**
    * Complete when the unlinked bundles for the package with the given [name]
    * and the [libFolder] are computed and written to the files.
    *
@@ -241,20 +159,14 @@
   List<LinkedPubPackage> getLinkedBundles(AnalysisContext context) {
 //    Stopwatch timer = new Stopwatch()..start();
 
-    PackageBundle sdkBundle = context.sourceFactory.dartSdk.getLinkedBundle();
+    SourceFactory sourceFactory = context.sourceFactory;
+    _ListedPackages listedPackages = new _ListedPackages(sourceFactory);
+
+    PackageBundle sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
     if (sdkBundle == null) {
       return const <LinkedPubPackage>[];
     }
 
-    // Prepare all SDK bundles.
-    List<PackageBundle> sdkBundles = <PackageBundle>[sdkBundle];
-    {
-      PackageBundle extension = computeSdkExtension(context, sdkBundle);
-      if (extension != null) {
-        sdkBundles.add(extension);
-      }
-    }
-
     bool strong = context.analysisOptions.strongMode;
     Map<PubPackage, PackageBundle> unlinkedBundles =
         getUnlinkedBundles(context);
@@ -273,22 +185,27 @@
     List<_LinkedNode> nodes = <_LinkedNode>[];
     Map<String, _LinkedNode> packageToNode = <String, _LinkedNode>{};
     unlinkedBundles.forEach((package, unlinked) {
-      _LinkedNode node =
-          new _LinkedNode(sdkBundles, package, unlinked, packageToNode);
+      _LinkedNode node = new _LinkedNode(
+          sdkBundle, listedPackages, package, unlinked, packageToNode);
       nodes.add(node);
       packageToNode[package.name] = node;
     });
 
+    // Compute transitive dependencies, mark some nodes as failed.
+    for (_LinkedNode node in nodes) {
+      node.computeTransitiveDependencies();
+    }
+
     // Attempt to read existing linked bundles.
     for (_LinkedNode node in nodes) {
       _readLinked(node, strong);
     }
 
     // Fill the store with bundles.
-    // Append linked SDK bundles.
+    // Append the linked SDK bundle.
     // Append unlinked and (if read from a cache) linked package bundles.
     SummaryDataStore store = new SummaryDataStore(const <String>[]);
-    sdkBundles.forEach((bundle) => store.addBundle(null, bundle));
+    store.addBundle(null, sdkBundle);
     for (_LinkedNode node in nodes) {
       store.addBundle(null, node.unlinked);
       if (node.linked != null) {
@@ -299,7 +216,7 @@
     // Link each package node.
     for (_LinkedNode node in nodes) {
       if (!node.isEvaluated) {
-        new _LinkedWalker(store, strong).walk(node);
+        new _LinkedWalker(listedPackages, store, strong).walk(node);
       }
     }
 
@@ -618,20 +535,24 @@
  * Specialization of [Node] for linking packages in proper dependency order.
  */
 class _LinkedNode extends Node<_LinkedNode> {
-  final List<PackageBundle> sdkBundles;
+  final PackageBundle sdkBundle;
+  final _ListedPackages listedPackages;
   final PubPackage package;
   final PackageBundle unlinked;
   final Map<String, _LinkedNode> packageToNode;
 
+  bool failed = false;
+  Set<_LinkedNode> transitiveDependencies;
   String _linkedHash;
 
   List<int> linkedNewBytes;
   PackageBundle linked;
 
-  _LinkedNode(this.sdkBundles, this.package, this.unlinked, this.packageToNode);
+  _LinkedNode(this.sdkBundle, this.listedPackages, this.package, this.unlinked,
+      this.packageToNode);
 
   @override
-  bool get isEvaluated => linked != null;
+  bool get isEvaluated => linked != null || failed;
 
   /**
    * Return the hash string that corresponds to this linked bundle in the
@@ -640,12 +561,10 @@
    * dependencies cannot computed.
    */
   String get linkedHash {
-    if (_linkedHash == null) {
+    if (_linkedHash == null && transitiveDependencies != null) {
+      // Collect all unlinked API signatures.
       List<String> signatures = <String>[];
-      Set<_LinkedNode> transitiveDependencies = computeTransitiveDependencies();
-      sdkBundles
-          .map((sdkBundle) => sdkBundle.apiSignature)
-          .forEach(signatures.add);
+      signatures.add(sdkBundle.apiSignature);
       transitiveDependencies
           .map((node) => node.unlinked.apiSignature)
           .forEach(signatures.add);
@@ -672,9 +591,14 @@
       } else if (uriStr.startsWith('package:')) {
         String package = PubSummaryManager.getPackageName(uriStr);
         _LinkedNode packageNode = packageToNode[package];
+        if (packageNode == null && listedPackages.isListed(uriStr)) {
+          failed = true;
+        }
         if (packageNode != null) {
           dependencies.add(packageNode);
         }
+      } else {
+        failed = true;
       }
     }
 
@@ -693,39 +617,41 @@
   }
 
   /**
-   * Return the set of existing transitive dependencies for this node, skipping
-   * any missing dependencies.  Only [unlinked] is used, so this method can be
-   * called before linking.
+   * Compute the set of existing transitive dependencies for this node.
+   * If any `package` dependency cannot be resolved, but it is one of the
+   * [listedPackages] then set [failed] to `true`.
+   * Only [unlinked] is used, so this method can be called before linking.
    */
-  Set<_LinkedNode> computeTransitiveDependencies() {
-    Set<_LinkedNode> allDependencies = new Set<_LinkedNode>();
-    _appendDependencies(allDependencies);
-    return allDependencies;
+  void computeTransitiveDependencies() {
+    if (transitiveDependencies == null) {
+      transitiveDependencies = new Set<_LinkedNode>();
+
+      void appendDependencies(_LinkedNode node) {
+        if (transitiveDependencies.add(node)) {
+          node.dependencies.forEach(appendDependencies);
+        }
+      }
+
+      appendDependencies(this);
+      if (transitiveDependencies.any((node) => node.failed)) {
+        failed = true;
+      }
+    }
   }
 
   @override
   String toString() => package.toString();
-
-  /**
-   * Append this node and its dependencies to [allDependencies] recursively.
-   */
-  void _appendDependencies(Set<_LinkedNode> allDependencies) {
-    if (allDependencies.add(this)) {
-      for (_LinkedNode dependency in dependencies) {
-        dependency._appendDependencies(allDependencies);
-      }
-    }
-  }
 }
 
 /**
  * Specialization of [DependencyWalker] for linking packages.
  */
 class _LinkedWalker extends DependencyWalker<_LinkedNode> {
+  final _ListedPackages listedPackages;
   final SummaryDataStore store;
   final bool strong;
 
-  _LinkedWalker(this.store, this.strong);
+  _LinkedWalker(this.listedPackages, this.store, this.strong);
 
   @override
   void evaluate(_LinkedNode node) {
@@ -743,10 +669,10 @@
     Set<String> libraryUris = uriToNode.keys.toSet();
     // Perform linking.
     Map<String, LinkedLibraryBuilder> linkedLibraries =
-        link(libraryUris, (String absoluteUri) {
-      return store.linkedMap[absoluteUri];
-    }, (String absoluteUri) {
-      return store.unlinkedMap[absoluteUri];
+        link(libraryUris, (String uri) {
+      return store.linkedMap[uri];
+    }, (String uri) {
+      return store.unlinkedMap[uri];
     }, strong);
     // Assemble linked bundles and put them into the store.
     for (_LinkedNode node in scc) {
@@ -763,3 +689,28 @@
     }
   }
 }
+
+/**
+ * The set of package names that are listed in the `.packages` file of a
+ * context.  These are the only packages, references to which can
+ * be possibly resolved in the context.  Nodes that reference a `package:` URI
+ * without the unlinked bundle, so without the node, cannot be linked.
+ */
+class _ListedPackages {
+  final Set<String> names = new Set<String>();
+
+  _ListedPackages(SourceFactory sourceFactory) {
+    Map<String, List<Folder>> map = sourceFactory.packageMap;
+    if (map != null) {
+      names.addAll(map.keys);
+    }
+  }
+
+  /**
+   * Check whether the given `package:` [uri] is listed in the package map.
+   */
+  bool isListed(String uri) {
+    String package = PubSummaryManager.getPackageName(uri);
+    return names.contains(package);
+  }
+}
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
index ec4f609..9672241 100644
--- a/pkg/analyzer/lib/src/summary/summarize_ast.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -585,10 +585,7 @@
         .map((Token t) => t.toString())
         .join()
         .replaceAll('\r\n', '\n');
-    return new UnlinkedDocumentationCommentBuilder(
-        text: text,
-        offset: documentationComment.offset,
-        length: documentationComment.length);
+    return new UnlinkedDocumentationCommentBuilder(text: text);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index e62f408..1a0e22d 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -721,9 +721,7 @@
       return null;
     }
     return new UnlinkedDocumentationCommentBuilder(
-        text: element.documentationComment,
-        offset: element.docRange.offset,
-        length: element.docRange.length);
+        text: element.documentationComment);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index da8fcec..04c4ec4 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -975,7 +975,7 @@
 final ListResultDescriptor<AnalysisError>
     STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT =
     new ListResultDescriptor<AnalysisError>(
-        'STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT', null);
+        'STATIC_VARIABLE_RESOLUTION_ERRORS_IN_UNIT', AnalysisError.NO_ERRORS);
 
 /**
  * The additional strong mode errors produced while verifying a
@@ -2563,6 +2563,9 @@
 
   DartDelta(Source source) : super(source);
 
+  @override
+  bool get shouldGatherChanges => true;
+
   /**
    * Add names that are changed in the given [references].
    * Return `true` if any change was added.
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index d0b55fe..a623b1c 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -186,9 +186,7 @@
         // so no need to insert an error for this here.
         continue;
       }
-      DartType expectedType = _elementType(element);
-      if (expectedType == null) expectedType = DynamicTypeImpl.instance;
-      checkArgument(arg, expectedType);
+      checkArgument(arg, _elementType(element));
     }
   }
 
@@ -701,34 +699,28 @@
       assert(functionType.namedParameterTypes.isEmpty);
       assert(functionType.optionalParameterTypes.isEmpty);
 
-      // Check the LHS type.
+      // Refine the return type.
       var rhsType = _getDefiniteType(expr.rightHandSide);
       var lhsType = _getDefiniteType(expr.leftHandSide);
       var returnType = rules.refineBinaryExpressionType(
           typeProvider, lhsType, op, rhsType, functionType.returnType);
 
-      if (!rules.isSubtypeOf(returnType, lhsType)) {
-        final numType = typeProvider.numType;
-        // TODO(jmesserly): this seems to duplicate logic in StaticTypeAnalyzer.
-        // Try to fix up the numerical case if possible.
-        if (rules.isSubtypeOf(lhsType, numType) &&
-            rules.isSubtypeOf(lhsType, rhsType)) {
-          // This is also slightly different from spec, but allows us to keep
-          // compound operators in the int += num and num += dynamic cases.
-          _recordImplicitCast(expr.rightHandSide, rhsType, lhsType);
-        } else {
-          // TODO(jmesserly): this results in a duplicate error, because
-          // ErrorVerifier also reports it.
-          _recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR,
-              [expr, returnType, lhsType]);
-        }
-      } else {
-        // Check the RHS type.
-        //
-        // This is only needed if we didn't already need a cast, and avoids
-        // emitting two messages for the same expression.
-        _checkDowncast(expr.rightHandSide, paramTypes.first);
-      }
+      // Check the argument for an implicit cast.
+      _checkDowncast(expr.rightHandSide, paramTypes[0], from: rhsType);
+
+      // Check the return type for an implicit cast.
+      //
+      // If needed, mark the left side to indicate a down cast when we assign
+      // back to it. So these two implicit casts are equivalent:
+      //
+      //     y = /*implicit cast*/(y + 42);
+      //     y/*implicit cast*/ += 42;
+      //
+      // TODO(jmesserly): this is an unambiguous way to represent it, but it's
+      // a bit sneaky. We can't use the rightHandSide because that could be a
+      // downcast on its own, and we can't use the entire expression because its
+      // result value could used and then implicitly downcast.
+      _checkDowncast(expr.leftHandSide, lhsType, from: returnType);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/util/fast_uri.dart b/pkg/analyzer/lib/src/util/fast_uri.dart
index 0df5ce05..40681bd 100644
--- a/pkg/analyzer/lib/src/util/fast_uri.dart
+++ b/pkg/analyzer/lib/src/util/fast_uri.dart
@@ -19,6 +19,8 @@
   static int _currentCacheLength = 0;
   static int _currentCacheGeneration = 0;
 
+  static bool _hashUsingText = _shouldComputeHashCodeUsingText();
+
   final int _cacheGeneration;
   final String _text;
   final String _scheme;
@@ -31,7 +33,7 @@
   final int _lastSlashIndex;
 
   /**
-   * The cached hashcode.
+   * The cached hash code.
    */
   int _hashCode;
 
@@ -62,7 +64,11 @@
   bool get hasFragment => false;
 
   @override
-  int get hashCode => _text.hashCode;
+  int get hashCode {
+    return _hashCode ??= _hashUsingText
+        ? _computeHashUsingText(this)
+        : _computeHashUsingCombine(this);
+  }
 
   @override
   bool get hasPort => false;
@@ -222,6 +228,38 @@
     return uri;
   }
 
+  /**
+   * This implementation was used before 'fast-URI' in Dart VM.
+   */
+  static int _computeHashUsingCombine(FastUri uri) {
+    // This code is copied from the standard Uri implementation.
+    // It is important that Uri and FastUri generate compatible hashCodes
+    // because Uri and FastUri may be used as keys in the same map.
+    int combine(part, current) {
+      // The sum is truncated to 30 bits to make sure it fits into a Smi.
+      return (current * 31 + part.hashCode) & 0x3FFFFFFF;
+    }
+
+    return combine(
+        uri.scheme,
+        combine(
+            uri.userInfo,
+            combine(
+                uri.host,
+                combine(
+                    uri.port,
+                    combine(uri.path,
+                        combine(uri.query, combine(uri.fragment, 1)))))));
+  }
+
+  /**
+   * This implementation should be used with 'fast-URI' in Dart VM.
+   * https://github.com/dart-lang/sdk/commit/afbbbb97cfcd86a64d0ba5dcfe1ab758954adaf4
+   */
+  static int _computeHashUsingText(FastUri uri) {
+    return uri._text.hashCode;
+  }
+
   static bool _isAlphabetic(int char) {
     return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) ||
         char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0);
@@ -272,4 +310,15 @@
     return new FastUri._(_currentCacheGeneration, text, scheme,
         hasEmptyAuthority, path, lastSlashIndex);
   }
+
+  /**
+   * Determine whether VM has the text based hash code computation in [Uri],
+   * or the old combine style.
+   *
+   * See https://github.com/dart-lang/sdk/issues/27159 for details.
+   */
+  static bool _shouldComputeHashCodeUsingText() {
+    String text = 'package:foo/foo.dart';
+    return Uri.parse(text).hashCode == text.hashCode;
+  }
 }
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 1ad2b79..c768235 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.28.0-alpha.1
+version: 0.29.0-alpha.0
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
diff --git a/pkg/analyzer/test/embedder_tests.dart b/pkg/analyzer/test/embedder_tests.dart
new file mode 100644
index 0000000..ba79d0c
--- /dev/null
+++ b/pkg/analyzer/test/embedder_tests.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.embedder_tests;
+
+import 'dart:core' hide Resource;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:path/path.dart' as path;
+
+import 'resource_utils.dart';
+import 'utils.dart';
+
+abstract class EmbedderRelatedTest {
+  final String emptyPath = '/home/.pub-cache/empty';
+  final String foxPath = '/home/.pub-cache/fox';
+  final String foxLib = '/home/.pub-cache/fox/lib';
+
+  TestPathTranslator pathTranslator;
+  ResourceProvider resourceProvider;
+
+  buildResourceProvider() {
+    MemoryResourceProvider rawProvider =
+        new MemoryResourceProvider(isWindows: isWindows);
+    resourceProvider = new TestResourceProvider(rawProvider);
+    pathTranslator = new TestPathTranslator(rawProvider)
+      ..newFolder('/home/.pub-cache/empty')
+      ..newFolder('/home/.pub-cache/fox/lib')
+      ..newFile(
+          '/home/.pub-cache/fox/lib/_embedder.yaml',
+          r'''
+embedded_libs:
+  "dart:core" : "core.dart"
+  "dart:fox": "slippy.dart"
+  "dart:bear": "grizzly.dart"
+  "dart:relative": "../relative.dart"
+  "dart:deep": "deep/directory/file.dart"
+  "fart:loudly": "nomatter.dart"
+''');
+  }
+
+  clearResourceProvider() {
+    resourceProvider = null;
+    pathTranslator = null;
+  }
+
+  void setUp() {
+    initializeTestEnvironment(path.context);
+    buildResourceProvider();
+  }
+
+  void tearDown() {
+    initializeTestEnvironment();
+    clearResourceProvider();
+  }
+}
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index 5c931b1..58e06bf 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -194,6 +194,11 @@
     expect(file.exists, isTrue);
   }
 
+  void test_resolveSymbolicLinksSync() {
+    File file = provider.newFile('/test.txt', 'text');
+    expect(file.resolveSymbolicLinksSync(), file);
+  }
+
   void test_shortName() {
     File file = provider.getResource('/foo/bar/file.txt');
     expect(file.shortName, 'file.txt');
@@ -211,20 +216,43 @@
   }
 
   void test_writeAsBytesSync_existing() {
-    File file = provider.newFileWithBytes('/foo/file.bin', <int>[1, 2]);
-    expect(file.readAsBytesSync(), <int>[1, 2]);
+    List<int> content = <int>[1, 2];
+    File file = provider.newFileWithBytes('/foo/file.bin', content);
+    expect(file.readAsBytesSync(), content);
     // write new bytes
-    file.writeAsBytesSync(<int>[10, 20]);
-    expect(file.readAsBytesSync(), <int>[10, 20]);
+    content = <int>[10, 20];
+    file.writeAsBytesSync(content);
+    expect(file.readAsBytesSync(), content);
   }
 
   void test_writeAsBytesSync_new() {
     File file = provider.getFile('/foo/file.bin');
     expect(file.exists, false);
     // write new bytes
-    file.writeAsBytesSync(<int>[10, 20]);
+    List<int> content = <int>[10, 20];
+    file.writeAsBytesSync(content);
     expect(file.exists, true);
-    expect(file.readAsBytesSync(), <int>[10, 20]);
+    expect(file.readAsBytesSync(), content);
+  }
+
+  void test_writeAsStringSync_existing() {
+    String content = 'ab';
+    File file = provider.newFile('/foo/file.txt', content);
+    expect(file.readAsStringSync(), content);
+    // write new bytes
+    content = 'CD';
+    file.writeAsStringSync(content);
+    expect(file.readAsStringSync(), content);
+  }
+
+  void test_writeAsStringSync_new() {
+    File file = provider.getFile('/foo/file.txt');
+    expect(file.exists, false);
+    // write new bytes
+    String content = 'ef';
+    file.writeAsStringSync(content);
+    expect(file.exists, true);
+    expect(file.readAsStringSync(), content);
   }
 }
 
diff --git a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
index a7c7c1f..0308293 100644
--- a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
+++ b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
@@ -180,6 +180,43 @@
     expect(file.exists, isTrue);
   }
 
+  void test_resolveSymbolicLinksSync_links() {
+    Context pathContext = PhysicalResourceProvider.INSTANCE.pathContext;
+    String pathA = pathContext.join(tempPath, 'a');
+    String pathB = pathContext.join(pathA, 'b');
+    new io.Directory(pathB).createSync(recursive: true);
+    String filePath = pathContext.join(pathB, 'test.txt');
+    io.File testFile = new io.File(filePath);
+    testFile.writeAsStringSync('test');
+
+    String pathC = pathContext.join(tempPath, 'c');
+    String pathD = pathContext.join(pathC, 'd');
+    new io.Link(pathD).createSync(pathA, recursive: true);
+
+    String pathE = pathContext.join(tempPath, 'e');
+    String pathF = pathContext.join(pathE, 'f');
+    new io.Link(pathF).createSync(pathC, recursive: true);
+
+    String linkPath =
+        pathContext.join(tempPath, 'e', 'f', 'd', 'b', 'test.txt');
+    File file = PhysicalResourceProvider.INSTANCE.getFile(linkPath);
+    expect(file.resolveSymbolicLinksSync().path,
+        testFile.resolveSymbolicLinksSync());
+  }
+
+  void test_resolveSymbolicLinksSync_noLinks() {
+    //
+    // On some platforms the path to the temp directory includes a symbolic
+    // link. We remove that from the equation before creating the File in order
+    // to show that the operation works as expected without symbolic links.
+    //
+    io.File ioFile = new io.File(path);
+    ioFile.writeAsStringSync('test');
+    file = PhysicalResourceProvider.INSTANCE
+        .getFile(ioFile.resolveSymbolicLinksSync());
+    expect(file.resolveSymbolicLinksSync(), file);
+  }
+
   void test_shortName() {
     expect(file.shortName, 'file.txt');
   }
@@ -195,11 +232,23 @@
   }
 
   void test_writeAsBytesSync() {
-    new io.File(path).writeAsBytesSync(<int>[1, 2]);
-    expect(file.readAsBytesSync(), <int>[1, 2]);
+    List<int> content = <int>[1, 2];
+    new io.File(path).writeAsBytesSync(content);
+    expect(file.readAsBytesSync(), content);
     // write new bytes
-    file.writeAsBytesSync(<int>[10, 20]);
-    expect(file.readAsBytesSync(), <int>[10, 20]);
+    content = <int>[10, 20];
+    file.writeAsBytesSync(content);
+    expect(file.readAsBytesSync(), content);
+  }
+
+  void test_writeAsStringSync() {
+    String content = 'ab';
+    new io.File(path).writeAsStringSync(content);
+    expect(file.readAsStringSync(), content);
+    // write new bytes
+    content = 'CD';
+    file.writeAsStringSync(content);
+    expect(file.readAsStringSync(), content);
   }
 }
 
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 0f06f13..71fbe5b 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart' hide ConstantEvaluator;
@@ -30,6 +31,7 @@
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:path/path.dart';
 import 'package:source_span/source_span.dart';
 import 'package:unittest/unittest.dart';
@@ -62,6 +64,32 @@
   runReflectiveTests(UriKindTest);
 }
 
+/**
+ * Create a tiny mock SDK for use in URI resolution tests.
+ */
+DartSdk _createSdk() {
+  MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+  String sdkFolderName =
+      resourceProvider.pathContext.separator == '/' ? '/sdk' : r'C:\sdk';
+  Folder sdkFolder = resourceProvider.newFolder(sdkFolderName);
+  expect(sdkFolder, isNotNull);
+  resourceProvider.newFile(
+      resourceProvider.pathContext.join(sdkFolderName, 'lib', '_internal',
+          'sdk_library_metadata', 'lib', 'libraries.dart'),
+      '''
+const Map<String, LibraryInfo> libraries = const {
+  "core": const LibraryInfo("core/core.dart")
+};
+''');
+  resourceProvider.newFile(
+      resourceProvider.pathContext
+          .join(sdkFolderName, 'lib', 'core', 'core.dart'),
+      '''
+library dart.core;
+''');
+  return new FolderBasedDartSdk(resourceProvider, sdkFolder);
+}
+
 @reflectiveTest
 class ContentCacheTest {
   void test_setContents() {
@@ -88,9 +116,8 @@
   }
 
   void test_resolve_unknown_uri() {
-    UriResolver resolver = new CustomUriResolver({
-      'custom:library': '/path/to/library.dart',
-    });
+    UriResolver resolver =
+        new CustomUriResolver({'custom:library': '/path/to/library.dart',});
     Source result =
         resolver.resolveAbsolute(parseUriWithException("custom:non_library"));
     expect(result, isNull);
@@ -99,9 +126,7 @@
   void test_resolve_uri() {
     String path =
         FileUtilities2.createFile("/path/to/library.dart").getAbsolutePath();
-    UriResolver resolver = new CustomUriResolver({
-      'custom:library': path,
-    });
+    UriResolver resolver = new CustomUriResolver({'custom:library': path,});
     Source result =
         resolver.resolveAbsolute(parseUriWithException("custom:library"));
     expect(result, isNotNull);
@@ -144,13 +169,6 @@
         .resolveAbsolute(parseUriWithException("package:some/file.dart"));
     expect(result, isNull);
   }
-
-  DartSdk _createSdk() {
-    ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
-    Folder sdkFolder = FolderBasedDartSdk.defaultSdkDirectory(resourceProvider);
-    expect(sdkFolder, isNotNull);
-    return new FolderBasedDartSdk(resourceProvider, sdkFolder);
-  }
 }
 
 @deprecated
@@ -313,16 +331,15 @@
 @reflectiveTest
 class DirectoryBasedSourceContainerTest {
   void test_contains() {
-    JavaFile dir = FileUtilities2.createFile("/does/not/exist");
-    JavaFile file1 = FileUtilities2.createFile("/does/not/exist/some.dart");
-    JavaFile file2 =
-        FileUtilities2.createFile("/does/not/exist/folder/some2.dart");
-    JavaFile file3 = FileUtilities2.createFile("/does/not/exist3/some3.dart");
-    FileBasedSource source1 = new FileBasedSource(file1);
-    FileBasedSource source2 = new FileBasedSource(file2);
-    FileBasedSource source3 = new FileBasedSource(file3);
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    File file1 = resourceProvider.getFile('/does/not/exist/some.dart');
+    File file2 = resourceProvider.getFile('/does/not/exist/folder/some2.dart');
+    File file3 = resourceProvider.getFile('/does/not/exist3/some3.dart');
+    Source source1 = new FileSource(file1);
+    Source source2 = new FileSource(file2);
+    Source source3 = new FileSource(file3);
     DirectoryBasedSourceContainer container =
-        new DirectoryBasedSourceContainer.con1(dir);
+        new DirectoryBasedSourceContainer.con2('/does/not/exist');
     expect(container.contains(source1), isTrue);
     expect(container.contains(source2), isTrue);
     expect(container.contains(source3), isFalse);
@@ -717,7 +734,6 @@
     expect(type.isMixinApplication, isFalse);
     expect(type.isSynthetic, isFalse);
     expect(type.documentationComment, '/// aaa');
-    _assertHasDocRange(type, 50, 7);
     _assertHasCodeRange(type, 50, 31);
   }
 
@@ -984,7 +1000,6 @@
     expect(constructor, isNotNull);
     _assertHasCodeRange(constructor, 50, 31);
     expect(constructor.documentationComment, '/// aaa');
-    _assertHasDocRange(constructor, 50, 7);
     expect(constructor.isExternal, isFalse);
     expect(constructor.isFactory, isFalse);
     expect(constructor.name, "");
@@ -1187,7 +1202,6 @@
     expect(enumElement, isNotNull);
     _assertHasCodeRange(enumElement, 50, 31);
     expect(enumElement.documentationComment, '/// aaa');
-    _assertHasDocRange(enumElement, 50, 7);
     expect(enumElement.name, enumName);
   }
 
@@ -1213,7 +1227,6 @@
     expect(firstField, isNotNull);
     _assertHasCodeRange(firstField, 50, 61);
     expect(firstField.documentationComment, '/// aaa');
-    _assertHasDocRange(firstField, 50, 7);
     expect(firstField.name, firstFieldName);
     expect(firstField.initializer, isNull);
     expect(firstField.isConst, isFalse);
@@ -1224,7 +1237,6 @@
     expect(secondField, isNotNull);
     _assertHasCodeRange(secondField, 50, 61);
     expect(secondField.documentationComment, '/// aaa');
-    _assertHasDocRange(secondField, 50, 7);
     expect(secondField.name, secondFieldName);
     expect(secondField.initializer, isNull);
     expect(secondField.isConst, isFalse);
@@ -1345,7 +1357,6 @@
     expect(accessor, isNotNull);
     _assertHasCodeRange(accessor, 50, 31);
     expect(accessor.documentationComment, '/// aaa');
-    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.name, functionName);
     expect(declaration.element, same(accessor));
     expect(declaration.functionExpression.element, same(accessor));
@@ -1383,7 +1394,6 @@
     expect(function, isNotNull);
     _assertHasCodeRange(function, 50, 31);
     expect(function.documentationComment, '/// aaa');
-    _assertHasDocRange(function, 50, 7);
     expect(function.hasImplicitReturnType, isFalse);
     expect(function.name, functionName);
     expect(declaration.element, same(function));
@@ -1415,7 +1425,6 @@
     expect(accessor, isNotNull);
     _assertHasCodeRange(accessor, 50, 31);
     expect(accessor.documentationComment, '/// aaa');
-    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.hasImplicitReturnType, isTrue);
     expect(accessor.name, "$functionName=");
     expect(declaration.element, same(accessor));
@@ -1496,7 +1505,6 @@
     expect(alias, isNotNull);
     _assertHasCodeRange(alias, 50, 31);
     expect(alias.documentationComment, '/// aaa');
-    _assertHasDocRange(alias, 50, 7);
     expect(alias.name, aliasName);
     expect(alias.parameters, hasLength(0));
     List<TypeParameterElement> typeParameters = alias.typeParameters;
@@ -1697,7 +1705,6 @@
     expect(getter, isNotNull);
     _assertHasCodeRange(getter, 50, 31);
     expect(getter.documentationComment, '/// aaa');
-    _assertHasDocRange(getter, 50, 7);
     expect(getter.hasImplicitReturnType, isTrue);
     expect(getter.isAbstract, isFalse);
     expect(getter.isExternal, isFalse);
@@ -1810,7 +1817,6 @@
     expect(method, isNotNull);
     _assertHasCodeRange(method, 50, 31);
     expect(method.documentationComment, '/// aaa');
-    _assertHasDocRange(method, 50, 7);
     expect(method.hasImplicitReturnType, isFalse);
     expect(method.name, methodName);
     expect(method.functions, hasLength(0));
@@ -1887,7 +1893,6 @@
     expect(setter, isNotNull);
     _assertHasCodeRange(setter, 50, 31);
     expect(setter.documentationComment, '/// aaa');
-    _assertHasDocRange(setter, 50, 7);
     expect(setter.hasImplicitReturnType, isTrue);
     expect(setter.isAbstract, isFalse);
     expect(setter.isExternal, isFalse);
@@ -2476,6 +2481,34 @@
     expect(variable.setter, isNotNull);
   }
 
+  void test_visitVariableDeclaration_top() {
+    // final a, b;
+    ElementHolder holder = new ElementHolder();
+    ElementBuilder builder = _makeBuilder(holder);
+    VariableDeclaration variableDeclaration1 =
+        AstFactory.variableDeclaration('a');
+    VariableDeclaration variableDeclaration2 =
+        AstFactory.variableDeclaration('b');
+    TopLevelVariableDeclaration topLevelVariableDeclaration = AstFactory
+        .topLevelVariableDeclaration(
+            Keyword.FINAL, null, [variableDeclaration1, variableDeclaration2]);
+    topLevelVariableDeclaration.documentationComment = AstFactory
+        .documentationComment(
+            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+
+    topLevelVariableDeclaration.accept(builder);
+    List<TopLevelVariableElement> variables = holder.topLevelVariables;
+    expect(variables, hasLength(2));
+
+    TopLevelVariableElement variable1 = variables[0];
+    expect(variable1, isNotNull);
+    expect(variable1.documentationComment, '/// aaa');
+
+    TopLevelVariableElement variable2 = variables[1];
+    expect(variable2, isNotNull);
+    expect(variable2.documentationComment, '/// aaa');
+  }
+
   void test_visitVariableDeclaration_top_const_hasInitializer() {
     // const v = 42;
     ElementHolder holder = new ElementHolder();
@@ -2502,36 +2535,6 @@
     expect(variable.setter, isNull);
   }
 
-  void test_visitVariableDeclaration_top_docRange() {
-    // final a, b;
-    ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = _makeBuilder(holder);
-    VariableDeclaration variableDeclaration1 =
-        AstFactory.variableDeclaration('a');
-    VariableDeclaration variableDeclaration2 =
-        AstFactory.variableDeclaration('b');
-    TopLevelVariableDeclaration topLevelVariableDeclaration = AstFactory
-        .topLevelVariableDeclaration(
-            Keyword.FINAL, null, [variableDeclaration1, variableDeclaration2]);
-    topLevelVariableDeclaration.documentationComment = AstFactory
-        .documentationComment(
-            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
-
-    topLevelVariableDeclaration.accept(builder);
-    List<TopLevelVariableElement> variables = holder.topLevelVariables;
-    expect(variables, hasLength(2));
-
-    TopLevelVariableElement variable1 = variables[0];
-    expect(variable1, isNotNull);
-    expect(variable1.documentationComment, '/// aaa');
-    _assertHasDocRange(variable1, 50, 7);
-
-    TopLevelVariableElement variable2 = variables[1];
-    expect(variable2, isNotNull);
-    expect(variable2.documentationComment, '/// aaa');
-    _assertHasDocRange(variable2, 50, 7);
-  }
-
   void test_visitVariableDeclaration_top_final() {
     // final v;
     ElementHolder holder = new ElementHolder();
@@ -2561,15 +2564,6 @@
     expect(elementImpl.codeLength, length);
   }
 
-  void _assertHasDocRange(
-      Element element, int expectedOffset, int expectedLength) {
-    // Cast to dynamic here to avoid a hint about @deprecated docRange.
-    SourceRange docRange = (element as dynamic).docRange;
-    expect(docRange, isNotNull);
-    expect(docRange.offset, expectedOffset);
-    expect(docRange.length, expectedLength);
-  }
-
   void _assertVisibleRange(LocalElement element, int offset, int end) {
     SourceRange visibleRange = element.visibleRange;
     expect(visibleRange.offset, offset);
@@ -3123,8 +3117,6 @@
     expect(constant.isStatic, isTrue);
     expect((constant as FieldElementImpl).evaluationResult, isNotNull);
     expect(constant.documentationComment, '/// aaa');
-    expect(constant.docRange.offset, 50);
-    expect(constant.docRange.length, 7);
     _assertGetter(constant);
   }
 
@@ -4133,7 +4125,7 @@
     _assertNthStatementDoesNotExit(source, 0);
   }
 
-  void test_whileStatement_breakWithLabel_afterExting() {
+  void test_whileStatement_breakWithLabel_afterExiting() {
     Source source = addSource(r'''
 void f() {
   x: while (true) {
@@ -4401,13 +4393,6 @@
     expect(source.fullName, file.getAbsolutePath());
     expect(source.isInSystemLibrary, isTrue);
   }
-
-  DartSdk _createSdk() {
-    ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
-    Folder sdkFolder = FolderBasedDartSdk.defaultSdkDirectory(resourceProvider);
-    expect(sdkFolder, isNotNull);
-    return new FolderBasedDartSdk(resourceProvider, sdkFolder);
-  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/generated/analysis_context_factory.dart b/pkg/analyzer/test/generated/analysis_context_factory.dart
index dc8920b..1e48058 100644
--- a/pkg/analyzer/test/generated/analysis_context_factory.dart
+++ b/pkg/analyzer/test/generated/analysis_context_factory.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -25,6 +26,7 @@
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:analyzer/src/string_source.dart';
 import 'package:unittest/unittest.dart';
 
@@ -499,21 +501,25 @@
  * Helper for creating and managing single [AnalysisContext].
  */
 class AnalysisContextHelper {
+  ResourceProvider resourceProvider;
   AnalysisContext context;
 
   /**
    * Creates new [AnalysisContext] using [AnalysisContextFactory].
    */
-  AnalysisContextHelper([AnalysisOptionsImpl options]) {
+  AnalysisContextHelper(
+      [AnalysisOptionsImpl options, ResourceProvider provider]) {
+    resourceProvider = provider ?? new MemoryResourceProvider();
     if (options == null) {
       options = new AnalysisOptionsImpl();
     }
     options.cacheSize = 256;
-    context = AnalysisContextFactory.contextWithCoreAndOptions(options);
+    context = AnalysisContextFactory.contextWithCoreAndOptions(options,
+        resourceProvider: resourceProvider);
   }
 
   Source addSource(String path, String code) {
-    Source source = new FileBasedSource(FileUtilities2.createFile(path));
+    Source source = new FileSource(resourceProvider.getFile(path));
     if (path.endsWith(".dart") || path.endsWith(".html")) {
       ChangeSet changeSet = new ChangeSet();
       changeSet.addedSource(source);
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index ac35f08..9893933 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_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.
 
+@deprecated
 library analyzer.test.constant_test;
 
 import 'package:analyzer/dart/ast/ast.dart';
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index aaefc2a..976ee73 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -8,17 +8,18 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -868,20 +869,18 @@
   }
 
   /**
-   * Create the resolver used by the tests.
-   *
-   * @return the resolver that was created
+   * Create and return the resolver used by the tests.
    */
   ElementResolver _createResolver() {
-    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
-    FileBasedSource source =
-        new FileBasedSource(FileUtilities2.createFile("/test.dart"));
-    CompilationUnitElementImpl definingCompilationUnit =
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
+        resourceProvider: resourceProvider);
+    Source source = new FileSource(resourceProvider.getFile("/test.dart"));
+    CompilationUnitElementImpl unit =
         new CompilationUnitElementImpl("test.dart");
-    definingCompilationUnit.librarySource =
-        definingCompilationUnit.source = source;
+    unit.librarySource = unit.source = source;
     _definingLibrary = ElementFactory.library(context, "test");
-    _definingLibrary.definingCompilationUnit = definingCompilationUnit;
+    _definingLibrary.definingCompilationUnit = unit;
     _visitor = new ResolverVisitor(
         _definingLibrary, source, _typeProvider, _listener,
         nameScope: new LibraryScope(_definingLibrary, _listener));
diff --git a/pkg/analyzer/test/generated/incremental_scanner_test.dart b/pkg/analyzer/test/generated/incremental_scanner_test.dart
index 2c21e61..b762338 100644
--- a/pkg/analyzer/test/generated/incremental_scanner_test.dart
+++ b/pkg/analyzer/test/generated/incremental_scanner_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.
 
+@deprecated
 library analyzer.test.generated.incremental_scanner_test;
 
 import 'package:analyzer/dart/ast/token.dart';
diff --git a/pkg/analyzer/test/generated/inheritance_manager_test.dart b/pkg/analyzer/test/generated/inheritance_manager_test.dart
index 06d6c98..1ac3a31 100644
--- a/pkg/analyzer/test/generated/inheritance_manager_test.dart
+++ b/pkg/analyzer/test/generated/inheritance_manager_test.dart
@@ -8,6 +8,7 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -19,6 +20,7 @@
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -1306,9 +1308,10 @@
    * @return the inheritance manager that was created
    */
   InheritanceManager _createInheritanceManager() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore();
-    FileBasedSource source =
-        new FileBasedSource(FileUtilities2.createFile("/test.dart"));
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    AnalysisContext context = AnalysisContextFactory.contextWithCore(
+        resourceProvider: resourceProvider);
+    Source source = new FileSource(resourceProvider.getFile("/test.dart"));
     CompilationUnitElementImpl definingCompilationUnit =
         new CompilationUnitElementImpl("test.dart");
     definingCompilationUnit.librarySource =
diff --git a/pkg/analyzer/test/generated/non_hint_code_test.dart b/pkg/analyzer/test/generated/non_hint_code_test.dart
index 16ba3a9..a590420 100644
--- a/pkg/analyzer/test/generated/non_hint_code_test.dart
+++ b/pkg/analyzer/test/generated/non_hint_code_test.dart
@@ -242,6 +242,25 @@
     verify([source]);
   }
 
+  void test_deprecatedMemberUse_inDeprecatedLibrary() {
+    Source source = addSource(r'''
+@deprecated
+library lib;
+
+@deprecated
+f() {}
+
+class C {
+  m() {
+    f();
+  }
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_deprecatedMemberUse_inDeprecatedMethod() {
     Source source = addSource(r'''
 @deprecated
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 1d3577e..e48c4dc 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -29,6 +29,7 @@
   initializeTestEnvironment();
   runReflectiveTests(ComplexParserTest);
   runReflectiveTests(ErrorParserTest);
+  // ignore: deprecated_member_use
   runReflectiveTests(IncrementalParserTest);
   runReflectiveTests(NonErrorParserTest);
   runReflectiveTests(RecoveryParserTest);
@@ -2366,6 +2367,7 @@
   }
 }
 
+@deprecated
 @reflectiveTest
 class IncrementalParserTest extends EngineTestCase {
   void fail_replace_identifier_with_functionLiteral_in_initializer_interp() {
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index e3756ac..1135a52 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -25,6 +26,7 @@
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -1035,9 +1037,10 @@
   CompilationUnitElementImpl _definingCompilationUnit;
 
   void setUp() {
-    AnalysisContext context = AnalysisContextFactory.contextWithCore();
-    FileBasedSource source =
-        new FileBasedSource(FileUtilities2.createFile("/test.dart"));
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    AnalysisContext context = AnalysisContextFactory.contextWithCore(
+        resourceProvider: resourceProvider);
+    Source source = new FileSource(resourceProvider.getFile("/test.dart"));
     _definingCompilationUnit = new CompilationUnitElementImpl("test.dart");
     _definingCompilationUnit.librarySource =
         _definingCompilationUnit.source = source;
@@ -3022,9 +3025,11 @@
 
   void setUp() {
     _listener = new GatheringErrorListener();
-    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore();
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
+        resourceProvider: resourceProvider);
     Source librarySource =
-        new FileBasedSource(FileUtilities2.createFile("/lib.dart"));
+        new FileSource(resourceProvider.getFile("/lib.dart"));
     LibraryElementImpl element = new LibraryElementImpl.forNode(
         context, AstFactory.libraryIdentifier2(["lib"]));
     element.definingCompilationUnit =
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 9aa7fc1..0133de5 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -7,16 +7,15 @@
 import 'dart:convert';
 
 import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine, Logger;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine_io.dart';
-import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:package_config/packages.dart';
 import 'package:package_config/packages_file.dart' as pkgfile show parse;
 import 'package:package_config/src/packages_impl.dart';
@@ -40,9 +39,10 @@
         .createSource(uri != null ? Uri.parse(uri) : null);
 
 void runPackageMapTests() {
+  MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
   final Uri baseUri = new Uri.file('test/base');
   final List<UriResolver> testResolvers = [
-    new ResourceUriResolver(PhysicalResourceProvider.INSTANCE)
+    new ResourceUriResolver(resourceProvider)
   ];
 
   Packages createPackageMap(Uri base, String configFileContents) {
@@ -146,7 +146,7 @@
           expect(
               () => resolvePackageUri(
                   config: 'foo:<:&%>', uri: 'package:foo/bar.dart'),
-              throwsA(new isInstanceOf('FormatException')));
+              throwsA(new isInstanceOf<FormatException>()));
         });
         test('Valid URI that cannot be further resolved', () {
           String uri = resolvePackageUri(
@@ -172,7 +172,7 @@
 async:/home/somebody/.pub/cache/async-1.1.0/lib/
 quiver:/home/somebody/.pub/cache/quiver-1.2.1/lib
 ''',
-              source: new FileBasedSource(FileUtilities2.createFile(
+              source: new FileSource(resourceProvider.getFile(
                   '/home/somebody/.pub/cache/unittest-0.9.9/lib/unittest.dart')));
           expect(uri, isNotNull);
           expect(uri.toString(), equals('package:unittest/unittest.dart'));
@@ -207,6 +207,19 @@
   });
 }
 
+class AbsoluteUriResolver extends UriResolver {
+  final MemoryResourceProvider resourceProvider;
+
+  AbsoluteUriResolver(this.resourceProvider);
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    return new FileSource(
+        resourceProvider.getFile(resourceProvider.pathContext.fromUri(uri)),
+        actualUri);
+  }
+}
+
 class CustomUriResolver extends UriResolver {
   String uriPath;
   CustomUriResolver({this.uriPath});
@@ -218,6 +231,8 @@
 
 @reflectiveTest
 class SourceFactoryTest {
+  MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+
   void test_creation() {
     expect(new SourceFactory([]), isNotNull);
   }
@@ -250,10 +265,10 @@
 
   void test_resolveUri_nonAbsolute_absolute() {
     SourceFactory factory =
-        new SourceFactory([new UriResolver_nonAbsolute_absolute()]);
+        new SourceFactory([new AbsoluteUriResolver(resourceProvider)]);
     String absolutePath = "/does/not/matter.dart";
     Source containingSource =
-        new FileBasedSource(FileUtilities2.createFile("/does/not/exist.dart"));
+        new FileSource(resourceProvider.getFile("/does/not/exist.dart"));
     Source result = factory.resolveUri(containingSource, absolutePath);
     expect(result.fullName,
         FileUtilities2.createFile(absolutePath).getAbsolutePath());
@@ -261,9 +276,9 @@
 
   void test_resolveUri_nonAbsolute_relative() {
     SourceFactory factory =
-        new SourceFactory([new UriResolver_nonAbsolute_relative()]);
+        new SourceFactory([new AbsoluteUriResolver(resourceProvider)]);
     Source containingSource =
-        new FileBasedSource(FileUtilities2.createFile("/does/not/have.dart"));
+        new FileSource(resourceProvider.getFile("/does/not/have.dart"));
     Source result = factory.resolveUri(containingSource, "exist.dart");
     expect(result.fullName,
         FileUtilities2.createFile("/does/not/exist.dart").getAbsolutePath());
@@ -299,10 +314,10 @@
   }
 
   void test_restoreUri() {
-    JavaFile file1 = FileUtilities2.createFile("/some/file1.dart");
-    JavaFile file2 = FileUtilities2.createFile("/some/file2.dart");
-    Source source1 = new FileBasedSource(file1);
-    Source source2 = new FileBasedSource(file2);
+    File file1 = resourceProvider.getFile("/some/file1.dart");
+    File file2 = resourceProvider.getFile("/some/file2.dart");
+    Source source1 = new FileSource(file1);
+    Source source2 = new FileSource(file2);
     Uri expected1 = parseUriWithException("file:///my_file.dart");
     SourceFactory factory =
         new SourceFactory([new UriResolver_restoreUri(source1, expected1)]);
@@ -323,20 +338,6 @@
   }
 }
 
-class UriResolver_nonAbsolute_absolute extends UriResolver {
-  @override
-  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
-    return new FileBasedSource(new JavaFile.fromUri(uri), actualUri);
-  }
-}
-
-class UriResolver_nonAbsolute_relative extends UriResolver {
-  @override
-  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
-    return new FileBasedSource(new JavaFile.fromUri(uri), actualUri);
-  }
-}
-
 class UriResolver_restoreUri extends UriResolver {
   Source source1;
   Uri expected1;
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 2795236..44297ea 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -10,19 +10,20 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/static_type_analyzer.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -387,6 +388,7 @@
       expect(_analyze(node), same(intType));
       _listener.assertNoErrors();
     }
+
     validate(TokenType.MINUS_EQ);
     validate(TokenType.PERCENT_EQ);
     validate(TokenType.PLUS_EQ);
@@ -403,6 +405,7 @@
       expect(_analyze(node), same(boolType));
       _listener.assertNoErrors();
     }
+
     validate(TokenType.AMPERSAND_AMPERSAND_EQ);
     validate(TokenType.BAR_BAR_EQ);
   }
@@ -420,6 +423,7 @@
       expect(_analyze(node), same(doubleType));
       _listener.assertNoErrors();
     }
+
     validate(TokenType.MINUS_EQ);
     validate(TokenType.PERCENT_EQ);
     validate(TokenType.PLUS_EQ);
@@ -1526,16 +1530,18 @@
    * Create the analyzer used by the tests.
    */
   StaticTypeAnalyzer _createAnalyzer({bool strongMode: false}) {
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
     InternalAnalysisContext context;
     if (strongMode) {
       AnalysisOptionsImpl options = new AnalysisOptionsImpl();
       options.strongMode = true;
-      context = AnalysisContextFactory.contextWithCoreAndOptions(options);
+      context = AnalysisContextFactory.contextWithCoreAndOptions(options,
+          resourceProvider: resourceProvider);
     } else {
-      context = AnalysisContextFactory.contextWithCore();
+      context = AnalysisContextFactory.contextWithCore(
+          resourceProvider: resourceProvider);
     }
-    FileBasedSource source =
-        new FileBasedSource(FileUtilities2.createFile("/lib.dart"));
+    Source source = new FileSource(resourceProvider.getFile("/lib.dart"));
     CompilationUnitElementImpl definingCompilationUnit =
         new CompilationUnitElementImpl("lib.dart");
     definingCompilationUnit.librarySource =
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index ddf6dc0..90c4e27 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -1801,23 +1801,7 @@
 class D extends C {
   String f/*<S>*/(/*=S*/ x) => null;
 }''');
-    // TODO(jmesserly): we can't use assertErrors because STRONG_MODE_* errors
-    // from CodeChecker don't have working equality.
-    List<AnalysisError> errors = analysisContext2.computeErrors(source);
-
-    // Sort errors by name.
-    errors.sort((AnalysisError e1, AnalysisError e2) =>
-        e1.errorCode.name.compareTo(e2.errorCode.name));
-
-    expect(
-        errors.map((e) => e.errorCode.name),
-        unorderedEquals([
-          'INVALID_METHOD_OVERRIDE_RETURN_TYPE',
-          'STRONG_MODE_INVALID_METHOD_OVERRIDE'
-        ]));
-    expect(errors[0].message, contains('Iterable<S>'),
-        reason: 'errors should be in terms of the type parameters '
-            'at the error location');
+    assertErrors(source, [StrongModeCode.INVALID_METHOD_OVERRIDE]);
     verify([source]);
   }
 
@@ -1831,15 +1815,7 @@
 class D extends C {
   /*=T*/ f/*<T extends B>*/(/*=T*/ x) => null;
 }''');
-    // TODO(jmesserly): this is modified code from assertErrors, which we can't
-    // use directly because STRONG_MODE_* errors don't have working equality.
-    List<AnalysisError> errors = analysisContext2.computeErrors(source);
-    expect(
-        errors.map((e) => e.errorCode.name),
-        unorderedEquals([
-          'INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND',
-          'STRONG_MODE_INVALID_METHOD_OVERRIDE'
-        ]));
+    assertErrors(source, [StrongModeCode.INVALID_METHOD_OVERRIDE]);
     verify([source]);
   }
 
@@ -1851,15 +1827,7 @@
 class D extends C {
   /*=S*/ f/*<T, S>*/(/*=T*/ x) => null;
 }''');
-    // TODO(jmesserly): we can't use assertErrors because STRONG_MODE_* errors
-    // from CodeChecker don't have working equality.
-    List<AnalysisError> errors = analysisContext2.computeErrors(source);
-    expect(
-        errors.map((e) => e.errorCode.name),
-        unorderedEquals([
-          'STRONG_MODE_INVALID_METHOD_OVERRIDE',
-          'INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS'
-        ]));
+    assertErrors(source, [StrongModeCode.INVALID_METHOD_OVERRIDE]);
     verify([source]);
   }
 
diff --git a/pkg/analyzer/test/resource_utils.dart b/pkg/analyzer/test/resource_utils.dart
index 65f7069..688eae0 100644
--- a/pkg/analyzer/test/resource_utils.dart
+++ b/pkg/analyzer/test/resource_utils.dart
@@ -78,6 +78,9 @@
   File newFile(String posixPath, String content) =>
       _provider.newFile(posixToOSPath(posixPath), content);
 
+  File newFileWithBytes(String posixPath, List<int> bytes) =>
+      _provider.newFileWithBytes(posixToOSPath(posixPath), bytes);
+
   Folder newFolder(String posixPath) =>
       _provider.newFolder(posixToOSPath(posixPath));
 }
diff --git a/pkg/analyzer/test/source/embedder_test.dart b/pkg/analyzer/test/source/embedder_test.dart
index ea20cd7..fbbaf51 100644
--- a/pkg/analyzer/test/source/embedder_test.dart
+++ b/pkg/analyzer/test/source/embedder_test.dart
@@ -2,21 +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.
 
+@deprecated
 library analyzer.test.source.embedder_test;
 
 import 'dart:core' hide Resource;
 
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
+import '../embedder_tests.dart';
 import '../reflective_tests.dart';
 import '../resource_utils.dart';
-import '../utils.dart';
 
 main() {
   runReflectiveTests(DartUriResolverTest);
@@ -28,7 +26,7 @@
 class DartUriResolverTest extends EmbedderRelatedTest {
   void test_embedderYaml() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(locator.embedderYamls);
     DartUriResolver resolver = new DartUriResolver(sdk);
@@ -40,51 +38,11 @@
     }
 
     // Check that they map to the correct paths.
-    expectResolved('dart:core', '/tmp/core.dart');
-    expectResolved('dart:fox', '/tmp/slippy.dart');
-    expectResolved('dart:bear', '/tmp/grizzly.dart');
-    expectResolved('dart:relative', '/relative.dart');
-    expectResolved('dart:deep', '/tmp/deep/directory/file.dart');
-  }
-}
-
-abstract class EmbedderRelatedTest {
-  TestPathTranslator pathTranslator;
-  ResourceProvider resourceProvider;
-
-  buildResourceProvider() {
-    MemoryResourceProvider rawProvider =
-        new MemoryResourceProvider(isWindows: isWindows);
-    resourceProvider = new TestResourceProvider(rawProvider);
-    pathTranslator = new TestPathTranslator(rawProvider)
-      ..newFolder('/empty')
-      ..newFolder('/tmp')
-      ..newFile(
-          '/tmp/_embedder.yaml',
-          r'''
-embedded_libs:
-  "dart:core" : "core.dart"
-  "dart:fox": "slippy.dart"
-  "dart:bear": "grizzly.dart"
-  "dart:relative": "../relative.dart"
-  "dart:deep": "deep/directory/file.dart"
-  "fart:loudly": "nomatter.dart"
-''');
-  }
-
-  clearResourceProvider() {
-    resourceProvider = null;
-    pathTranslator = null;
-  }
-
-  void setUp() {
-    initializeTestEnvironment(path.context);
-    buildResourceProvider();
-  }
-
-  void tearDown() {
-    initializeTestEnvironment();
-    clearResourceProvider();
+    expectResolved('dart:core', '$foxLib/core.dart');
+    expectResolved('dart:fox', '$foxLib/slippy.dart');
+    expectResolved('dart:bear', '$foxLib/grizzly.dart');
+    expectResolved('dart:relative', '$foxPath/relative.dart');
+    expectResolved('dart:deep', '$foxLib/deep/directory/file.dart');
   }
 }
 
@@ -92,7 +50,7 @@
 class EmbedderSdkTest extends EmbedderRelatedTest {
   void test_creation() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(locator.embedderYamls);
 
@@ -101,7 +59,7 @@
 
   void test_fromFileUri() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(locator.embedderYamls);
 
@@ -113,26 +71,26 @@
       expect(source.fullName, posixToOSPath(posixPath));
     }
 
-    expectSource('/tmp/slippy.dart', 'dart:fox');
-    expectSource('/tmp/deep/directory/file.dart', 'dart:deep');
-    expectSource('/tmp/deep/directory/part.dart', 'dart:deep/part.dart');
+    expectSource('$foxLib/slippy.dart', 'dart:fox');
+    expectSource('$foxLib/deep/directory/file.dart', 'dart:deep');
+    expectSource('$foxLib/deep/directory/part.dart', 'dart:deep/part.dart');
   }
 
   void test_getSdkLibrary() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(locator.embedderYamls);
 
     SdkLibrary lib = sdk.getSdkLibrary('dart:fox');
     expect(lib, isNotNull);
-    expect(lib.path, posixToOSPath('/tmp/slippy.dart'));
+    expect(lib.path, posixToOSPath('$foxLib/slippy.dart'));
     expect(lib.shortName, 'dart:fox');
   }
 
   void test_mapDartUri() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(locator.embedderYamls);
 
@@ -143,10 +101,10 @@
       expect(source.fullName, posixToOSPath(posixPath));
     }
 
-    expectSource('dart:core', '/tmp/core.dart');
-    expectSource('dart:fox', '/tmp/slippy.dart');
-    expectSource('dart:deep', '/tmp/deep/directory/file.dart');
-    expectSource('dart:deep/part.dart', '/tmp/deep/directory/part.dart');
+    expectSource('dart:core', '$foxLib/core.dart');
+    expectSource('dart:fox', '$foxLib/slippy.dart');
+    expectSource('dart:deep', '$foxLib/deep/directory/file.dart');
+    expectSource('dart:deep/part.dart', '$foxLib/deep/directory/part.dart');
   }
 }
 
@@ -154,7 +112,7 @@
 class EmbedderUriResolverTest extends EmbedderRelatedTest {
   void test_embedderYaml() {
     var locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     var resolver = new EmbedderUriResolver(locator.embedderYamls);
 
@@ -167,11 +125,11 @@
     // We have five mappings.
     expect(resolver, hasLength(5));
     // Check that they map to the correct paths.
-    expectResolved('dart:core', '/tmp/core.dart');
-    expectResolved('dart:fox', '/tmp/slippy.dart');
-    expectResolved('dart:bear', '/tmp/grizzly.dart');
-    expectResolved('dart:relative', '/relative.dart');
-    expectResolved('dart:deep', '/tmp/deep/directory/file.dart');
+    expectResolved('dart:core', '$foxLib/core.dart');
+    expectResolved('dart:fox', '$foxLib/slippy.dart');
+    expectResolved('dart:bear', '$foxLib/grizzly.dart');
+    expectResolved('dart:relative', '$foxPath/relative.dart');
+    expectResolved('dart:deep', '$foxLib/deep/directory/file.dart');
   }
 
   void test_nullEmbedderYamls() {
@@ -181,7 +139,7 @@
 
   void test_restoreAbsolute() {
     var locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     var resolver = new EmbedderUriResolver(locator.embedderYamls);
 
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index cba70fa..e43d56f 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -4,11 +4,8 @@
 
 library analyzer.test.src.context.context_builder_test;
 
-import 'dart:io' as io;
-
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/context/builder.dart';
 import 'package:analyzer/src/context/source.dart';
@@ -20,25 +17,24 @@
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
+import '../../embedder_tests.dart';
 import '../../generated/test_support.dart';
 import '../../reflective_tests.dart';
-import '../../source/embedder_test.dart';
 import '../../utils.dart';
 import 'mock_sdk.dart';
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(ContextBuilderTest_WithDisk);
-  runReflectiveTests(ContextBuilderTest_WithoutDisk);
+  runReflectiveTests(ContextBuilderTest);
   runReflectiveTests(EmbedderYamlLocatorTest);
 }
 
 @reflectiveTest
-class ContextBuilderTest_WithDisk extends EngineTestCase {
+class ContextBuilderTest extends EngineTestCase {
   /**
    * The resource provider to be used by tests.
    */
-  PhysicalResourceProvider resourceProvider;
+  MemoryResourceProvider resourceProvider;
 
   /**
    * The path context used to manipulate file paths.
@@ -66,11 +62,11 @@
    */
   String defaultSdkPath = null;
 
-  void createDefaultSdk(io.Directory tempDir) {
-    defaultSdkPath = pathContext.join(tempDir.path, 'default', 'sdk');
+  void createDefaultSdk(Folder sdkDir) {
+    defaultSdkPath = pathContext.join(sdkDir.path, 'default', 'sdk');
     String librariesFilePath = pathContext.join(defaultSdkPath, 'lib',
         '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart');
-    createFile(
+    resourceProvider.newFile(
         librariesFilePath,
         r'''
 const Map<String, LibraryInfo> libraries = const {
@@ -83,21 +79,18 @@
     builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
   }
 
-  void createDirectory(String path) {
-    new io.Directory(path).createSync(recursive: true);
-  }
-
   void createFile(String path, String content) {
-    new io.File(path)
-      ..createSync(recursive: true)
-      ..writeAsStringSync(content);
+    resourceProvider.newFile(path, content);
   }
 
   @override
   void setUp() {
-    resourceProvider = PhysicalResourceProvider.INSTANCE;
+    resourceProvider = new MemoryResourceProvider();
     pathContext = resourceProvider.pathContext;
-    sdkManager = new DartSdkManager('', false, (_) => new MockSdk());
+    new MockSdk(resourceProvider: resourceProvider);
+    sdkManager = new DartSdkManager('/', false, (_) {
+      fail('Should not be used to create an SDK');
+    });
     contentCache = new ContentCache();
     builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
   }
@@ -107,364 +100,6 @@
     fail('Incomplete test');
   }
 
-  void test_createPackageMap_fromPackageDirectory_explicit() {
-    withTempDir((io.Directory tempDir) {
-      // Use a package directory that is outside the project directory.
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageDirPath = pathContext.join(rootPath, 'packages');
-      String fooName = 'foo';
-      String fooPath = pathContext.join(packageDirPath, fooName);
-      String barName = 'bar';
-      String barPath = pathContext.join(packageDirPath, barName);
-      createDirectory(projectPath);
-      createDirectory(fooPath);
-      createDirectory(barPath);
-
-      builder.defaultPackagesDirectoryPath = packageDirPath;
-
-      Packages packages = builder.createPackageMap(projectPath);
-      expect(packages, isNotNull);
-      Map<String, Uri> map = packages.asMap();
-      expect(map, hasLength(2));
-      expect(map[fooName], new Uri.directory(fooPath));
-      expect(map[barName], new Uri.directory(barPath));
-    });
-  }
-
-  void test_createPackageMap_fromPackageDirectory_inRoot() {
-    withTempDir((io.Directory tempDir) {
-      // Use a package directory that is inside the project directory.
-      String projectPath = tempDir.path;
-      String packageDirPath = pathContext.join(projectPath, 'packages');
-      String fooName = 'foo';
-      String fooPath = pathContext.join(packageDirPath, fooName);
-      String barName = 'bar';
-      String barPath = pathContext.join(packageDirPath, barName);
-      createDirectory(fooPath);
-      createDirectory(barPath);
-
-      Packages packages = builder.createPackageMap(projectPath);
-      expect(packages, isNotNull);
-      Map<String, Uri> map = packages.asMap();
-      expect(map, hasLength(2));
-      expect(map[fooName], new Uri.directory(fooPath));
-      expect(map[barName], new Uri.directory(barPath));
-    });
-  }
-
-  void test_createPackageMap_fromPackageFile_explicit() {
-    withTempDir((io.Directory tempDir) {
-      // Use a package file that is outside the project directory's hierarchy.
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(rootPath, 'child', '.packages');
-      createDirectory(projectPath);
-      createFile(
-          packageFilePath,
-          r'''
-foo:/pkg/foo
-bar:/pkg/bar
-''');
-
-      builder.defaultPackageFilePath = packageFilePath;
-      Packages packages = builder.createPackageMap(projectPath);
-      expect(packages, isNotNull);
-      Map<String, Uri> map = packages.asMap();
-      expect(map, hasLength(2));
-      expect(map['foo'], new Uri.directory('/pkg/foo'));
-      expect(map['bar'], new Uri.directory('/pkg/bar'));
-    });
-  }
-
-  void test_createPackageMap_fromPackageFile_inParentOfRoot() {
-    withTempDir((io.Directory tempDir) {
-      // Use a package file that is inside the parent of the project directory.
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(rootPath, '.packages');
-      createDirectory(projectPath);
-      createFile(
-          packageFilePath,
-          r'''
-foo:/pkg/foo
-bar:/pkg/bar
-''');
-
-      Packages packages = builder.createPackageMap(projectPath);
-      expect(packages, isNotNull);
-      Map<String, Uri> map = packages.asMap();
-      expect(map, hasLength(2));
-      expect(map['foo'], new Uri.directory('/pkg/foo'));
-      expect(map['bar'], new Uri.directory('/pkg/bar'));
-    });
-  }
-
-  void test_createPackageMap_fromPackageFile_inRoot() {
-    withTempDir((io.Directory tempDir) {
-      // Use a package file that is inside the project directory.
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(projectPath, '.packages');
-      createDirectory(projectPath);
-      createFile(
-          packageFilePath,
-          r'''
-foo:/pkg/foo
-bar:/pkg/bar
-''');
-
-      Packages packages = builder.createPackageMap(projectPath);
-      expect(packages, isNotNull);
-      Map<String, Uri> map = packages.asMap();
-      expect(map, hasLength(2));
-      expect(map['foo'], new Uri.directory('/pkg/foo'));
-      expect(map['bar'], new Uri.directory('/pkg/bar'));
-    });
-  }
-
-  void test_createPackageMap_none() {
-    withTempDir((io.Directory tempDir) {
-      Packages packages = builder.createPackageMap(tempDir.path);
-      expect(packages, same(Packages.noPackages));
-    });
-  }
-
-  void test_createSourceFactory_fileProvider() {
-    withTempDir((io.Directory tempDir) {
-      createDefaultSdk(tempDir);
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(projectPath, '.packages');
-      String packageA = pathContext.join(rootPath, 'pkgs', 'a');
-      String packageB = pathContext.join(rootPath, 'pkgs', 'b');
-      createFile(
-          packageFilePath,
-          '''
-a:${pathContext.toUri(packageA)}
-b:${pathContext.toUri(packageB)}
-''');
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-      UriResolver resolver = new ResourceUriResolver(resourceProvider);
-      builder.fileResolverProvider = (folder) => resolver;
-      SourceFactoryImpl factory =
-          builder.createSourceFactory(projectPath, options);
-      expect(factory.resolvers, contains(same(resolver)));
-    });
-  }
-
-  void test_createSourceFactory_noProvider_packages_embedder_extensions() {
-    withTempDir((io.Directory tempDir) {
-      createDefaultSdk(tempDir);
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(projectPath, '.packages');
-      String packageA = pathContext.join(rootPath, 'pkgs', 'a');
-      String embedderPath = pathContext.join(packageA, '_embedder.yaml');
-      String packageB = pathContext.join(rootPath, 'pkgs', 'b');
-      String extensionPath = pathContext.join(packageB, '_sdkext');
-      createFile(
-          packageFilePath,
-          '''
-a:${pathContext.toUri(packageA)}
-b:${pathContext.toUri(packageB)}
-''');
-      String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
-      String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
-      createFile(
-          embedderPath,
-          '''
-embedded_libs:
-  "dart:async": ${_relativeUri(asyncPath, from: packageA)}
-  "dart:core": ${_relativeUri(corePath, from: packageA)}
-''');
-      String fooPath = pathContext.join(packageB, 'ext', 'foo.dart');
-      createFile(
-          extensionPath,
-          '''{
-"dart:foo": "${_relativeUri(fooPath, from: packageB)}"
-}''');
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-
-      SourceFactory factory = builder.createSourceFactory(projectPath, options);
-
-      Source asyncSource = factory.forUri('dart:async');
-      expect(asyncSource, isNotNull);
-      expect(asyncSource.fullName, asyncPath);
-
-      Source fooSource = factory.forUri('dart:foo');
-      expect(fooSource, isNotNull);
-      expect(fooSource.fullName, fooPath);
-
-      Source packageSource = factory.forUri('package:b/b.dart');
-      expect(packageSource, isNotNull);
-      expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
-    });
-  }
-
-  void test_createSourceFactory_noProvider_packages_embedder_noExtensions() {
-    withTempDir((io.Directory tempDir) {
-      createDefaultSdk(tempDir);
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(projectPath, '.packages');
-      String packageA = pathContext.join(rootPath, 'pkgs', 'a');
-      String embedderPath = pathContext.join(packageA, '_embedder.yaml');
-      String packageB = pathContext.join(rootPath, 'pkgs', 'b');
-      createFile(
-          packageFilePath,
-          '''
-a:${pathContext.toUri(packageA)}
-b:${pathContext.toUri(packageB)}
-''');
-      String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
-      String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
-      createFile(
-          embedderPath,
-          '''
-embedded_libs:
-  "dart:async": ${_relativeUri(asyncPath, from: packageA)}
-  "dart:core": ${_relativeUri(corePath, from: packageA)}
-''');
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-
-      SourceFactory factory = builder.createSourceFactory(projectPath, options);
-
-      Source dartSource = factory.forUri('dart:async');
-      expect(dartSource, isNotNull);
-      expect(dartSource.fullName, asyncPath);
-
-      Source packageSource = factory.forUri('package:b/b.dart');
-      expect(packageSource, isNotNull);
-      expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
-    });
-  }
-
-  @failingTest
-  void test_createSourceFactory_noProvider_packages_noEmbedder_extensions() {
-    fail('Incomplete test');
-  }
-
-  void test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions() {
-    withTempDir((io.Directory tempDir) {
-      createDefaultSdk(tempDir);
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      String packageFilePath = pathContext.join(projectPath, '.packages');
-      String packageA = pathContext.join(rootPath, 'pkgs', 'a');
-      String packageB = pathContext.join(rootPath, 'pkgs', 'b');
-      createFile(
-          packageFilePath,
-          '''
-a:${pathContext.toUri(packageA)}
-b:${pathContext.toUri(packageB)}
-''');
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-
-      SourceFactory factory = builder.createSourceFactory(projectPath, options);
-
-      Source dartSource = factory.forUri('dart:core');
-      expect(dartSource, isNotNull);
-      expect(dartSource.fullName, '$defaultSdkPath/lib/core/core.dart');
-
-      Source packageSource = factory.forUri('package:a/a.dart');
-      expect(packageSource, isNotNull);
-      expect(packageSource.fullName, pathContext.join(packageA, 'a.dart'));
-    });
-  }
-
-  void test_createSourceFactory_packageProvider() {
-    withTempDir((io.Directory tempDir) {
-      createDefaultSdk(tempDir);
-      String rootPath = tempDir.path;
-      String projectPath = pathContext.join(rootPath, 'project');
-      AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-      UriResolver resolver = new PackageMapUriResolver(resourceProvider, {});
-      builder.packageResolverProvider = (folder) => resolver;
-      SourceFactoryImpl factory =
-          builder.createSourceFactory(projectPath, options);
-      expect(factory.resolvers, contains(same(resolver)));
-    });
-  }
-
-  @failingTest
-  void test_findSdk_embedder_extensions() {
-    // See test_createSourceFactory_noProvider_packages_embedder_extensions
-    fail('Incomplete test');
-  }
-
-  @failingTest
-  void test_findSdk_embedder_noExtensions() {
-    // See test_createSourceFactory_noProvider_packages_embedder_noExtensions
-    fail('Incomplete test');
-  }
-
-  @failingTest
-  void test_findSdk_noEmbedder_extensions() {
-    // See test_createSourceFactory_noProvider_packages_noEmbedder_extensions
-    fail('Incomplete test');
-  }
-
-  @failingTest
-  void test_findSdk_noEmbedder_noExtensions() {
-    // See test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions
-    fail('Incomplete test');
-  }
-
-  /**
-   * Execute the [test] function with a temporary [directory]. The test function
-   * can perform any disk operations within the directory and the directory (and
-   * its content) will be removed after the function returns.
-   */
-  void withTempDir(test(io.Directory directory)) {
-    io.Directory directory =
-        io.Directory.systemTemp.createTempSync('analyzer_');
-    try {
-      test(directory);
-    } finally {
-      directory.deleteSync(recursive: true);
-    }
-  }
-
-  Uri _relativeUri(String path, {String from}) {
-    String relativePath = pathContext.relative(path, from: from);
-    return pathContext.toUri(relativePath);
-  }
-}
-
-@reflectiveTest
-class ContextBuilderTest_WithoutDisk extends EngineTestCase {
-  /**
-   * The resource provider to be used by tests.
-   */
-  MemoryResourceProvider resourceProvider;
-
-  /**
-   * The SDK manager used by the tests;
-   */
-  DartSdkManager sdkManager;
-
-  /**
-   * The content cache used by the tests.
-   */
-  ContentCache contentCache;
-
-  /**
-   * The context builder to be used in the test.
-   */
-  ContextBuilder builder;
-
-  @override
-  void setUp() {
-    resourceProvider = new MemoryResourceProvider();
-    new MockSdk(resourceProvider: resourceProvider);
-    sdkManager = new DartSdkManager('/', false, (_) {
-      fail('Should not be used to create an SDK');
-    });
-    contentCache = new ContentCache();
-    builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
-  }
-
   void test_convertPackagesToMap_noPackages() {
     expect(builder.convertPackagesToMap(Packages.noPackages), isNull);
   }
@@ -512,6 +147,270 @@
     _expectEqualOptions(options, new AnalysisOptionsImpl());
   }
 
+  void test_createPackageMap_fromPackageDirectory_explicit() {
+    // Use a package directory that is outside the project directory.
+    String rootPath = '/root';
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageDirPath = pathContext.join(rootPath, 'packages');
+    String fooName = 'foo';
+    String fooPath = pathContext.join(packageDirPath, fooName);
+    String barName = 'bar';
+    String barPath = pathContext.join(packageDirPath, barName);
+    resourceProvider.newFolder(projectPath);
+    resourceProvider.newFolder(fooPath);
+    resourceProvider.newFolder(barPath);
+
+    builder.defaultPackagesDirectoryPath = packageDirPath;
+
+    Packages packages = builder.createPackageMap(projectPath);
+    expect(packages, isNotNull);
+    Map<String, Uri> map = packages.asMap();
+    expect(map, hasLength(2));
+    expect(map[fooName], new Uri.directory(fooPath));
+    expect(map[barName], new Uri.directory(barPath));
+  }
+
+  void test_createPackageMap_fromPackageDirectory_inRoot() {
+    // Use a package directory that is inside the project directory.
+    String projectPath = '/root/project';
+    String packageDirPath = pathContext.join(projectPath, 'packages');
+    String fooName = 'foo';
+    String fooPath = pathContext.join(packageDirPath, fooName);
+    String barName = 'bar';
+    String barPath = pathContext.join(packageDirPath, barName);
+    resourceProvider.newFolder(fooPath);
+    resourceProvider.newFolder(barPath);
+
+    Packages packages = builder.createPackageMap(projectPath);
+    expect(packages, isNotNull);
+    Map<String, Uri> map = packages.asMap();
+    expect(map, hasLength(2));
+    expect(map[fooName], new Uri.directory(fooPath));
+    expect(map[barName], new Uri.directory(barPath));
+  }
+
+  void test_createPackageMap_fromPackageFile_explicit() {
+    // Use a package file that is outside the project directory's hierarchy.
+    String rootPath = '/root';
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(rootPath, 'child', '.packages');
+    resourceProvider.newFolder(projectPath);
+    createFile(
+        packageFilePath,
+        r'''
+foo:/pkg/foo
+bar:/pkg/bar
+''');
+
+    builder.defaultPackageFilePath = packageFilePath;
+    Packages packages = builder.createPackageMap(projectPath);
+    expect(packages, isNotNull);
+    Map<String, Uri> map = packages.asMap();
+    expect(map, hasLength(2));
+    expect(map['foo'], new Uri.directory('/pkg/foo'));
+    expect(map['bar'], new Uri.directory('/pkg/bar'));
+  }
+
+  void test_createPackageMap_fromPackageFile_inParentOfRoot() {
+    // Use a package file that is inside the parent of the project directory.
+    String rootPath = '/root';
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(rootPath, '.packages');
+    resourceProvider.newFolder(projectPath);
+    createFile(
+        packageFilePath,
+        r'''
+foo:/pkg/foo
+bar:/pkg/bar
+''');
+
+    Packages packages = builder.createPackageMap(projectPath);
+    expect(packages, isNotNull);
+    Map<String, Uri> map = packages.asMap();
+    expect(map, hasLength(2));
+    expect(map['foo'], new Uri.directory('/pkg/foo'));
+    expect(map['bar'], new Uri.directory('/pkg/bar'));
+  }
+
+  void test_createPackageMap_fromPackageFile_inRoot() {
+    // Use a package file that is inside the project directory.
+    String rootPath = '/root';
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(projectPath, '.packages');
+    resourceProvider.newFolder(projectPath);
+    createFile(
+        packageFilePath,
+        r'''
+foo:/pkg/foo
+bar:/pkg/bar
+''');
+
+    Packages packages = builder.createPackageMap(projectPath);
+    expect(packages, isNotNull);
+    Map<String, Uri> map = packages.asMap();
+    expect(map, hasLength(2));
+    expect(map['foo'], new Uri.directory('/pkg/foo'));
+    expect(map['bar'], new Uri.directory('/pkg/bar'));
+  }
+
+  void test_createPackageMap_none() {
+    String rootPath = '/root';
+    Packages packages = builder.createPackageMap(rootPath);
+    expect(packages, same(Packages.noPackages));
+  }
+
+  void test_createSourceFactory_fileProvider() {
+    String rootPath = '/root';
+    Folder rootFolder = resourceProvider.getFolder(rootPath);
+    createDefaultSdk(rootFolder);
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(projectPath, '.packages');
+    String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+    String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+    createFile(
+        packageFilePath,
+        '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    UriResolver resolver = new ResourceUriResolver(resourceProvider);
+    builder.fileResolverProvider = (folder) => resolver;
+    SourceFactoryImpl factory =
+        builder.createSourceFactory(projectPath, options);
+    expect(factory.resolvers, contains(same(resolver)));
+  }
+
+  void test_createSourceFactory_noProvider_packages_embedder_extensions() {
+    String rootPath = '/root';
+    Folder rootFolder = resourceProvider.getFolder(rootPath);
+    createDefaultSdk(rootFolder);
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(projectPath, '.packages');
+    String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+    String embedderPath = pathContext.join(packageA, '_embedder.yaml');
+    String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+    String extensionPath = pathContext.join(packageB, '_sdkext');
+    createFile(
+        packageFilePath,
+        '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+    String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
+    String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
+    createFile(
+        embedderPath,
+        '''
+embedded_libs:
+  "dart:async": ${_relativeUri(asyncPath, from: packageA)}
+  "dart:core": ${_relativeUri(corePath, from: packageA)}
+''');
+    String fooPath = pathContext.join(packageB, 'ext', 'foo.dart');
+    createFile(
+        extensionPath,
+        '''{
+"dart:foo": "${_relativeUri(fooPath, from: packageB)}"
+}''');
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+    SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+    Source asyncSource = factory.forUri('dart:async');
+    expect(asyncSource, isNotNull);
+    expect(asyncSource.fullName, asyncPath);
+
+    Source fooSource = factory.forUri('dart:foo');
+    expect(fooSource, isNotNull);
+    expect(fooSource.fullName, fooPath);
+
+    Source packageSource = factory.forUri('package:b/b.dart');
+    expect(packageSource, isNotNull);
+    expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
+  }
+
+  void test_createSourceFactory_noProvider_packages_embedder_noExtensions() {
+    String rootPath = '/root';
+    Folder rootFolder = resourceProvider.getFolder(rootPath);
+    createDefaultSdk(rootFolder);
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(projectPath, '.packages');
+    String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+    String embedderPath = pathContext.join(packageA, '_embedder.yaml');
+    String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+    createFile(
+        packageFilePath,
+        '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+    String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
+    String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
+    createFile(
+        embedderPath,
+        '''
+embedded_libs:
+  "dart:async": ${_relativeUri(asyncPath, from: packageA)}
+  "dart:core": ${_relativeUri(corePath, from: packageA)}
+''');
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+    SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+    Source dartSource = factory.forUri('dart:async');
+    expect(dartSource, isNotNull);
+    expect(dartSource.fullName, asyncPath);
+
+    Source packageSource = factory.forUri('package:b/b.dart');
+    expect(packageSource, isNotNull);
+    expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
+  }
+
+  @failingTest
+  void test_createSourceFactory_noProvider_packages_noEmbedder_extensions() {
+    fail('Incomplete test');
+  }
+
+  void test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions() {
+    String rootPath = '/root';
+    Folder rootFolder = resourceProvider.getFolder(rootPath);
+    createDefaultSdk(rootFolder);
+    String projectPath = pathContext.join(rootPath, 'project');
+    String packageFilePath = pathContext.join(projectPath, '.packages');
+    String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+    String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+    createFile(
+        packageFilePath,
+        '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+    SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+    Source dartSource = factory.forUri('dart:core');
+    expect(dartSource, isNotNull);
+    expect(dartSource.fullName, '$defaultSdkPath/lib/core/core.dart');
+
+    Source packageSource = factory.forUri('package:a/a.dart');
+    expect(packageSource, isNotNull);
+    expect(packageSource.fullName, pathContext.join(packageA, 'a.dart'));
+  }
+
+  void test_createSourceFactory_packageProvider() {
+    String rootPath = '/root';
+    Folder rootFolder = resourceProvider.getFolder(rootPath);
+    createDefaultSdk(rootFolder);
+    String projectPath = pathContext.join(rootPath, 'project');
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    UriResolver resolver = new PackageMapUriResolver(resourceProvider, {});
+    builder.packageResolverProvider = (folder) => resolver;
+    SourceFactoryImpl factory =
+        builder.createSourceFactory(projectPath, options);
+    expect(factory.resolvers, contains(same(resolver)));
+  }
+
   void test_declareVariables_emptyMap() {
     AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
     Iterable<String> expected = context.declaredVariables.variableNames;
@@ -541,6 +440,30 @@
     expect(context.declaredVariables.variableNames, unorderedEquals(expected));
   }
 
+  @failingTest
+  void test_findSdk_embedder_extensions() {
+    // See test_createSourceFactory_noProvider_packages_embedder_extensions
+    fail('Incomplete test');
+  }
+
+  @failingTest
+  void test_findSdk_embedder_noExtensions() {
+    // See test_createSourceFactory_noProvider_packages_embedder_noExtensions
+    fail('Incomplete test');
+  }
+
+  @failingTest
+  void test_findSdk_noEmbedder_extensions() {
+    // See test_createSourceFactory_noProvider_packages_noEmbedder_extensions
+    fail('Incomplete test');
+  }
+
+  @failingTest
+  void test_findSdk_noEmbedder_noExtensions() {
+    // See test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions
+    fail('Incomplete test');
+  }
+
   void test_findSdk_noPackageMap() {
     DartSdk sdk = builder.findSdk(null, new AnalysisOptionsImpl());
     expect(sdk, isNotNull);
@@ -699,13 +622,18 @@
     expect(actual.trackCacheDependencies, expected.trackCacheDependencies);
     expect(actual.finerGrainedInvalidation, expected.finerGrainedInvalidation);
   }
+
+  Uri _relativeUri(String path, {String from}) {
+    String relativePath = pathContext.relative(path, from: from);
+    return pathContext.toUri(relativePath);
+  }
 }
 
 @reflectiveTest
 class EmbedderYamlLocatorTest extends EmbedderRelatedTest {
   void test_empty() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/empty')]
+      'fox': [pathTranslator.getResource(emptyPath)]
     });
     expect(locator.embedderYamls, hasLength(0));
   }
@@ -718,7 +646,7 @@
 
   void test_valid() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     expect(locator.embedderYamls, hasLength(1));
   }
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index bc8342a..387eae9 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -70,7 +70,7 @@
     expect(cache.getValue(target, resultA), 'a');
     expect(cache.getValue(target, resultB), 'b');
     // flush A
-    cache.flush((target, result) => result == resultA);
+    cache.flush((target) => true, (target, result) => result == resultA);
     expect(cache.getState(target, resultA), CacheState.FLUSHED);
     expect(cache.getState(target, resultB), CacheState.VALID);
     expect(cache.getValue(target, resultA), isNull);
@@ -336,7 +336,7 @@
     expect(entry.getValue(resultA), 'a');
     expect(entry.getValue(resultB), 'b');
     // flush A
-    entry.flush((target, result) => result == resultA);
+    entry.flush((target) => true, (target, result) => result == resultA);
     expect(entry.getState(resultA), CacheState.FLUSHED);
     expect(entry.getState(resultB), CacheState.VALID);
     expect(entry.getValue(resultA), isNull);
@@ -1244,6 +1244,9 @@
   _KeepContinueDelta(this.source, this.keepDescriptor);
 
   @override
+  bool get shouldGatherChanges => false;
+
+  @override
   bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
       ResultDescriptor descriptor, Object value) {
     return false;
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index adc7778..42b91f8 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -1122,7 +1122,7 @@
     context.applyChanges(new ChangeSet()..addedSource(source));
     context.resolveCompilationUnit2(source, source);
     // Flush all results units.
-    context.analysisCache.flush((target, result) {
+    context.analysisCache.flush((target) => true, (target, result) {
       if (target.source == source) {
         return RESOLVED_UNIT_RESULTS.contains(result);
       }
@@ -1148,7 +1148,7 @@
     context.applyChanges(new ChangeSet()..addedSource(source));
     context.resolveCompilationUnit2(source, source);
     // Flush all results units.
-    context.analysisCache.flush((target, result) {
+    context.analysisCache.flush((target) => true, (target, result) {
       if (target.source == source) {
         if (target.source == source) {
           return RESOLVED_UNIT_RESULTS.contains(result);
@@ -4624,6 +4624,31 @@
     _assertValid(b, LIBRARY_ERRORS_READY);
   }
 
+  void test_sequence_useAnyResolvedUnit_needsLibraryElement() {
+    Source a = addSource(
+        '/a.dart',
+        r'''
+class A {}
+class B {}
+''');
+    // Perform analysis until we get RESOLVED_UNIT1.
+    // But it does not have 'library' set, so `unitElement.context` is `null`.
+    LibrarySpecificUnit aUnitTarget = new LibrarySpecificUnit(a, a);
+    while (context.getResult(aUnitTarget, RESOLVED_UNIT1) == null) {
+      context.performAnalysisTask();
+    }
+    // There was a bug with exception in incremental element builder.
+    // We should not attempt to use `unitElement.context`.
+    // It calls `unitElement.library`, which might be not set yet.
+    context.setContents(
+        a,
+        r'''
+class A {}
+class B2 {}
+''');
+    // OK, no exceptions.
+  }
+
   void test_unusedName_class_add() {
     Source a = addSource(
         '/a.dart',
diff --git a/pkg/analyzer/test/src/dart/sdk/sdk_test.dart b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart
index 49738ff..9e5b18f 100644
--- a/pkg/analyzer/test/src/dart/sdk/sdk_test.dart
+++ b/pkg/analyzer/test/src/dart/sdk/sdk_test.dart
@@ -12,12 +12,13 @@
 import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/summarize_elements.dart';
 import 'package:unittest/unittest.dart';
 
+import '../../../embedder_tests.dart';
 import '../../../generated/test_support.dart';
 import '../../../reflective_tests.dart';
 import '../../../resource_utils.dart';
-import '../../../source/embedder_test.dart';
 import '../../../utils.dart';
 
 main() {
@@ -32,7 +33,7 @@
 class EmbedderSdkTest extends EmbedderRelatedTest {
   void test_creation() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
 
@@ -41,7 +42,7 @@
 
   void test_fromFileUri() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
 
@@ -53,26 +54,56 @@
       expect(source.fullName, posixToOSPath(posixPath));
     }
 
-    expectSource('/tmp/slippy.dart', 'dart:fox');
-    expectSource('/tmp/deep/directory/file.dart', 'dart:deep');
-    expectSource('/tmp/deep/directory/part.dart', 'dart:deep/part.dart');
+    expectSource('$foxLib/slippy.dart', 'dart:fox');
+    expectSource('$foxLib/deep/directory/file.dart', 'dart:deep');
+    expectSource('$foxLib/deep/directory/part.dart', 'dart:deep/part.dart');
+  }
+
+  void test_getLinkedBundle_hasBundle() {
+    pathTranslator.newFileWithBytes(
+        '$foxPath/sdk.ds', new PackageBundleAssembler().assemble().toBuffer());
+    EmbedderYamlLocator locator = new EmbedderYamlLocator({
+      'fox': [pathTranslator.getResource(foxLib)]
+    });
+    // No bundle for spec mode.
+    {
+      EmbedderSdk sdk =
+          new EmbedderSdk(resourceProvider, locator.embedderYamls);
+      sdk.analysisOptions = new AnalysisOptionsImpl()..strongMode = false;
+      expect(sdk.getLinkedBundle(), isNull);
+    }
+    // Has bundle for strong mode.
+    {
+      EmbedderSdk sdk =
+          new EmbedderSdk(resourceProvider, locator.embedderYamls);
+      sdk.analysisOptions = new AnalysisOptionsImpl()..strongMode = true;
+      expect(sdk.getLinkedBundle(), isNotNull);
+    }
+  }
+
+  void test_getLinkedBundle_noBundle() {
+    EmbedderYamlLocator locator = new EmbedderYamlLocator({
+      'fox': [pathTranslator.getResource(foxLib)]
+    });
+    EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
+    expect(sdk.getLinkedBundle(), isNull);
   }
 
   void test_getSdkLibrary() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
 
     SdkLibrary lib = sdk.getSdkLibrary('dart:fox');
     expect(lib, isNotNull);
-    expect(lib.path, posixToOSPath('/tmp/slippy.dart'));
+    expect(lib.path, posixToOSPath('$foxLib/slippy.dart'));
     expect(lib.shortName, 'dart:fox');
   }
 
   void test_mapDartUri() {
     EmbedderYamlLocator locator = new EmbedderYamlLocator({
-      'fox': [pathTranslator.getResource('/tmp')]
+      'fox': [pathTranslator.getResource(foxLib)]
     });
     EmbedderSdk sdk = new EmbedderSdk(resourceProvider, locator.embedderYamls);
 
@@ -83,10 +114,10 @@
       expect(source.fullName, posixToOSPath(posixPath));
     }
 
-    expectSource('dart:core', '/tmp/core.dart');
-    expectSource('dart:fox', '/tmp/slippy.dart');
-    expectSource('dart:deep', '/tmp/deep/directory/file.dart');
-    expectSource('dart:deep/part.dart', '/tmp/deep/directory/part.dart');
+    expectSource('dart:core', '$foxLib/core.dart');
+    expectSource('dart:fox', '$foxLib/slippy.dart');
+    expectSource('dart:deep', '$foxLib/deep/directory/file.dart');
+    expectSource('dart:deep/part.dart', '$foxLib/deep/directory/part.dart');
   }
 }
 
diff --git a/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart b/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
index 07ce00f..31f5bde 100644
--- a/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
+++ b/pkg/analyzer/test/src/summary/package_bundle_reader_test.dart
@@ -93,6 +93,12 @@
     expect(entry2.getValue(CONTAINING_LIBRARIES), unorderedEquals([source1]));
   }
 
+  test_compute_LINE_INFO_emptyLineStarts() {
+    when(unlinkedUnit1.lineStarts).thenReturn(<int>[]);
+    bool success = provider.compute(entry1, LINE_INFO);
+    expect(success, isFalse);
+  }
+
   test_compute_LINE_INFO_hasLineStarts() {
     when(unlinkedUnit1.lineStarts).thenReturn(<int>[10, 20, 30]);
     bool success = provider.compute(entry1, LINE_INFO);
@@ -100,10 +106,16 @@
     expect(entry1.getValue(LINE_INFO).lineStarts, <int>[10, 20, 30]);
   }
 
-  test_compute_LINE_INFO_emptyLineStarts() {
-    when(unlinkedUnit1.lineStarts).thenReturn(<int>[]);
-    bool success = provider.compute(entry1, LINE_INFO);
+  test_compute_MODIFICATION_TIME_hasResult() {
+    bool success = provider.compute(entry1, MODIFICATION_TIME);
+    expect(success, isTrue);
+    expect(entry1.getValue(MODIFICATION_TIME), 0);
+  }
+
+  test_compute_MODIFICATION_TIME_noResult() {
+    bool success = provider.compute(entry3, MODIFICATION_TIME);
     expect(success, isFalse);
+    expect(entry3.getState(MODIFICATION_TIME), CacheState.INVALID);
   }
 
   test_compute_SOURCE_KIND_librarySource() {
diff --git a/pkg/analyzer/test/src/summary/pub_summary_test.dart b/pkg/analyzer/test/src/summary/pub_summary_test.dart
index 8475203..f17df0e 100644
--- a/pkg/analyzer/test/src/summary/pub_summary_test.dart
+++ b/pkg/analyzer/test/src/summary/pub_summary_test.dart
@@ -34,119 +34,6 @@
     _createManager();
   }
 
-  test_computeSdkExtension() async {
-    // Create package files.
-    resourceProvider.newFile(
-        '$CACHE/aaa/lib/a.dart',
-        '''
-class A {}
-''');
-    resourceProvider.newFile(
-        '$CACHE/aaa/sdk_ext/extA.dart',
-        '''
-library test.a;
-import 'dart:async';
-part 'src/p1.dart';
-part 'src/p2.dart';
-class ExtA {}
-int V0;
-''');
-    resourceProvider.newFile(
-        '$CACHE/aaa/sdk_ext/src/p1.dart',
-        '''
-part of test.a;
-class ExtAA {}
-double V1;
-''');
-    resourceProvider.newFile(
-        '$CACHE/aaa/sdk_ext/src/p2.dart',
-        '''
-part of test.a;
-class ExtAB {}
-Future V2;
-''');
-    resourceProvider.newFile(
-        '$CACHE/aaa/lib/_sdkext',
-        '''
-{
-  "dart:aaa.internal": "../sdk_ext/extA.dart"
-}
-''');
-    resourceProvider.newFile(
-        '$CACHE/bbb/lib/b.dart',
-        '''
-class B {}
-''');
-
-    // Configure packages resolution.
-    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
-    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
-    context.sourceFactory = new SourceFactory(<UriResolver>[
-      sdkResolver,
-      resourceResolver,
-      new PackageMapUriResolver(resourceProvider, {
-        'aaa': [libFolderA],
-        'bbb': [libFolderB],
-      })
-    ]);
-
-    PackageBundle sdkBundle = sdk.getLinkedBundle();
-    PackageBundle bundle = manager.computeSdkExtension(context, sdkBundle);
-    expect(bundle, isNotNull);
-    expect(bundle.linkedLibraryUris, ['dart:aaa.internal']);
-    expect(bundle.unlinkedUnitUris, [
-      'dart:aaa.internal',
-      'dart:aaa.internal/src/p1.dart',
-      'dart:aaa.internal/src/p2.dart'
-    ]);
-    expect(bundle.unlinkedUnits, hasLength(3));
-    expect(bundle.unlinkedUnits[0].classes.map((c) => c.name), ['ExtA']);
-    expect(bundle.unlinkedUnits[1].classes.map((c) => c.name), ['ExtAA']);
-    expect(bundle.unlinkedUnits[2].classes.map((c) => c.name), ['ExtAB']);
-    // The library is linked.
-    expect(bundle.linkedLibraries, hasLength(1));
-    LinkedLibrary linkedLibrary = bundle.linkedLibraries[0];
-    // V0 is linked
-    {
-      UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[0];
-      LinkedUnit linkedUnit = linkedLibrary.units[0];
-      expect(unlinkedUnit.variables, hasLength(1));
-      UnlinkedVariable variable = unlinkedUnit.variables[0];
-      expect(variable.name, 'V0');
-      int typeRef = variable.type.reference;
-      expect(unlinkedUnit.references[typeRef].name, 'int');
-      LinkedReference linkedReference = linkedUnit.references[typeRef];
-      expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
-          'dart:core');
-    }
-    // V1 is linked
-    {
-      UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[1];
-      LinkedUnit linkedUnit = linkedLibrary.units[1];
-      expect(unlinkedUnit.variables, hasLength(1));
-      UnlinkedVariable variable = unlinkedUnit.variables[0];
-      expect(variable.name, 'V1');
-      int typeRef = variable.type.reference;
-      expect(unlinkedUnit.references[typeRef].name, 'double');
-      LinkedReference linkedReference = linkedUnit.references[typeRef];
-      expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
-          'dart:core');
-    }
-    // V2 is linked
-    {
-      UnlinkedUnit unlinkedUnit = bundle.unlinkedUnits[2];
-      LinkedUnit linkedUnit = linkedLibrary.units[2];
-      expect(unlinkedUnit.variables, hasLength(1));
-      UnlinkedVariable variable = unlinkedUnit.variables[0];
-      expect(variable.name, 'V2');
-      int typeRef = variable.type.reference;
-      expect(unlinkedUnit.references[typeRef].name, 'Future');
-      LinkedReference linkedReference = linkedUnit.references[typeRef];
-      expect(linkedLibrary.dependencies[linkedReference.dependency].uri,
-          'dart:async');
-    }
-  }
-
   test_computeUnlinkedForFolder() async {
     // Create package files.
     resourceProvider.newFile(
@@ -373,123 +260,6 @@
     }
   }
 
-  test_getLinkedBundles_cached_useSdkExtension() async {
-    String pathA1 = '$CACHE/aaa-1.0.0';
-    String pathA2 = '$CACHE/aaa-2.0.0';
-    // aaa-1.0.0
-    resourceProvider.newFile(
-        '$pathA1/lib/a.dart',
-        '''
-class A {}
-int a;
-''');
-    resourceProvider.newFile(
-        '$pathA1/sdk_ext/extA.dart',
-        '''
-class ExtA1 {}
-''');
-    resourceProvider.newFile(
-        '$pathA1/lib/_sdkext',
-        '''
-{
-  "dart:aaa": "../sdk_ext/extA.dart"
-}
-''');
-    // aaa-2.0.0
-    resourceProvider.newFile(
-        '$pathA2/lib/a.dart',
-        '''
-class A {}
-int a;
-''');
-    resourceProvider.newFile(
-        '$pathA2/sdk_ext/extA.dart',
-        '''
-class ExtA2 {}
-''');
-    resourceProvider.newFile(
-        '$pathA2/lib/_sdkext',
-        '''
-{
-  "dart:aaa": "../sdk_ext/extA.dart"
-}
-''');
-    // bbb
-    resourceProvider.newFile(
-        '$CACHE/bbb/lib/b.dart',
-        '''
-import 'package:aaa/a.dart';
-A b;
-''');
-    Folder folderA1 = resourceProvider.getFolder(pathA1);
-    Folder folderA2 = resourceProvider.getFolder(pathA2);
-    Folder folderB = resourceProvider.getFolder('$CACHE/bbb');
-
-    // Configure packages resolution.
-    Folder libFolderA1 = resourceProvider.newFolder('$pathA1/lib');
-    Folder libFolderA2 = resourceProvider.newFolder('$pathA2/lib');
-    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
-    context.sourceFactory = new SourceFactory(<UriResolver>[
-      sdkResolver,
-      resourceResolver,
-      new PackageMapUriResolver(resourceProvider, {
-        'aaa': [libFolderA1],
-        'bbb': [libFolderB],
-      })
-    ]);
-
-    // Session 1.
-    // Create linked bundles and store them in files.
-    String linkedHashA;
-    String linkedHashB;
-    {
-      // Ensure unlinked bundles.
-      manager.getUnlinkedBundles(context);
-      await manager.onUnlinkedComplete;
-
-      // Now we should be able to get linked bundles.
-      List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
-      expect(linkedPackages, hasLength(2));
-
-      // Verify that files with linked bundles were created.
-      LinkedPubPackage packageA = _getLinkedPackage(linkedPackages, 'aaa');
-      LinkedPubPackage packageB = _getLinkedPackage(linkedPackages, 'bbb');
-      linkedHashA = packageA.linkedHash;
-      linkedHashB = packageB.linkedHash;
-      _assertFileExists(folderA1, 'linked_spec_$linkedHashA.ds');
-      _assertFileExists(folderB, 'linked_spec_$linkedHashB.ds');
-    }
-
-    // Session 2.
-    // Use 'aaa-2.0.0', with a different SDK extension.
-    {
-      context.sourceFactory = new SourceFactory(<UriResolver>[
-        sdkResolver,
-        resourceResolver,
-        new PackageMapUriResolver(resourceProvider, {
-          'aaa': [libFolderA2],
-          'bbb': [libFolderB],
-        })
-      ]);
-
-      // Ensure unlinked bundles.
-      manager.getUnlinkedBundles(context);
-      await manager.onUnlinkedComplete;
-
-      // Now we should be able to get linked bundles.
-      List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
-      expect(linkedPackages, hasLength(2));
-
-      // Verify that new files with linked bundles were created.
-      LinkedPubPackage packageA = _getLinkedPackage(linkedPackages, 'aaa');
-      LinkedPubPackage packageB = _getLinkedPackage(linkedPackages, 'bbb');
-      expect(packageA.linkedHash, isNot(linkedHashA));
-      expect(packageB.linkedHash, isNot(linkedHashB));
-      _assertFileExists(folderA2, 'linked_spec_${packageA.linkedHash}.ds');
-      _assertFileExists(folderB, 'linked_spec_${packageB.linkedHash}.ds');
-    }
-  }
-
   test_getLinkedBundles_hasCycle() async {
     resourceProvider.newFile(
         '$CACHE/aaa/lib/a.dart',
@@ -587,7 +357,136 @@
     }
   }
 
-  test_getLinkedBundles_missingBundle() async {
+  test_getLinkedBundles_missingBundle_listed() async {
+    resourceProvider.newFile(
+        '$CACHE/aaa/lib/a.dart',
+        '''
+import 'package:bbb/b.dart';
+B a;
+''');
+    resourceProvider.newFile(
+        '$CACHE/bbb/lib/b.dart',
+        '''
+class B {}
+''');
+
+    // Configure packages resolution.
+    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolderA],
+        'bbb': [libFolderB],
+      })
+    ]);
+
+    // Ensure unlinked bundles for 'aaa'.
+    await manager.computeUnlinkedForFolder('aaa', libFolderA);
+
+    // Try to link.
+    // Neither 'aaa' nor 'bbb' are linked.
+    // 'bbb' does not have the unlinked bundle.
+    // 'aaa' is not linked because it references 'bbb', which is listed.
+    List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+    expect(linkedPackages, hasLength(0));
+  }
+
+  test_getLinkedBundles_missingBundle_listed_chained() async {
+    resourceProvider.newFile(
+        '$CACHE/aaa/lib/a.dart',
+        '''
+import 'package:bbb/b.dart';
+''');
+    resourceProvider.newFile(
+        '$CACHE/bbb/lib/b.dart',
+        '''
+import 'package:ccc/c.dart';
+''');
+    resourceProvider.newFile(
+        '$CACHE/ccc/lib/c.dart',
+        '''
+class C {}
+''');
+
+    // Configure packages resolution.
+    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+    Folder libFolderC = resourceProvider.newFolder('$CACHE/ccc/lib');
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolderA],
+        'bbb': [libFolderB],
+        'ccc': [libFolderC],
+      })
+    ]);
+
+    // Ensure unlinked bundles.
+    await manager.computeUnlinkedForFolder('aaa', libFolderA);
+    await manager.computeUnlinkedForFolder('bbb', libFolderB);
+
+    // Try to link.
+    // Neither 'aaa' nor 'bbb' are linked.
+    // 'ccc' is listed in the package map, but its unlinked bundle is not ready.
+    List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+    expect(linkedPackages, hasLength(0));
+  }
+
+  test_getLinkedBundles_missingBundle_listed_partial() async {
+    resourceProvider.newFile(
+        '$CACHE/aaa/lib/a.dart',
+        '''
+int a;
+''');
+    resourceProvider.newFile(
+        '$CACHE/bbb/lib/b.dart',
+        '''
+import 'package:ccc/c.dart';
+C b;
+''');
+    resourceProvider.newFile(
+        '$CACHE/ccc/lib/c.dart',
+        '''
+class C {}
+''');
+
+    // Configure packages resolution.
+    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
+    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
+    Folder libFolderC = resourceProvider.newFolder('$CACHE/ccc/lib');
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      sdkResolver,
+      resourceResolver,
+      new PackageMapUriResolver(resourceProvider, {
+        'aaa': [libFolderA],
+        'bbb': [libFolderB],
+        'ccc': [libFolderC],
+      })
+    ]);
+
+    // Ensure unlinked bundles for 'aaa'.
+    await manager.computeUnlinkedForFolder('aaa', libFolderA);
+    await manager.computeUnlinkedForFolder('bbb', libFolderB);
+
+    // Try to link.
+    // Only 'aaa' is linked.
+    // The package 'bbb' references the listed 'ccc' without unlinked bundle.
+    List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
+    expect(linkedPackages, hasLength(1));
+
+    // package:aaa
+    {
+      LinkedPubPackage linkedPackage = linkedPackages
+          .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
+      _assertHasLinkedVariable(linkedPackage, 'a', 'int',
+          expectedTypeNameUri: 'dart:core');
+    }
+  }
+
+  test_getLinkedBundles_missingBundle_notListed() async {
     resourceProvider.newFile(
         '$CACHE/aaa/lib/a.dart',
         '''
@@ -619,7 +518,8 @@
 
     // Try to link.
     // Both 'aaa' and 'bbb' are linked.
-    // The name 'C' in 'b.dart' is not resolved.
+    // The package 'ccc' is not listed, so it cannot be resolved anyway,
+    // with summaries or without them.
     List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
     expect(linkedPackages, hasLength(2));
 
@@ -642,66 +542,6 @@
     }
   }
 
-  test_getLinkedBundles_missingBundle_chained() async {
-    resourceProvider.newFile(
-        '$CACHE/aaa/lib/a.dart',
-        '''
-import 'package:bbb/b.dart';
-int a1;
-B a2;
-''');
-    resourceProvider.newFile(
-        '$CACHE/bbb/lib/b.dart',
-        '''
-import 'package:ccc/c.dart';
-class B {}
-int b1;
-C b2;
-''');
-
-    // Configure packages resolution.
-    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
-    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
-    context.sourceFactory = new SourceFactory(<UriResolver>[
-      sdkResolver,
-      resourceResolver,
-      new PackageMapUriResolver(resourceProvider, {
-        'aaa': [libFolderA],
-        'bbb': [libFolderB],
-      })
-    ]);
-
-    // Ensure unlinked bundles.
-    manager.getUnlinkedBundles(context);
-    await manager.onUnlinkedComplete;
-
-    // Try to link.
-    // Both 'aaa' and 'bbb' are linked.
-    // The name 'C' in 'b.dart' is not resolved.
-    List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
-    expect(linkedPackages, hasLength(2));
-
-    // package:aaa
-    {
-      LinkedPubPackage linkedPackage = linkedPackages
-          .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
-      _assertHasLinkedVariable(linkedPackage, 'a1', 'int',
-          expectedTypeNameUri: 'dart:core');
-      _assertHasLinkedVariable(linkedPackage, 'a2', 'B',
-          expectedTypeNameUri: 'package:bbb/b.dart');
-    }
-
-    // package:bbb
-    {
-      LinkedPubPackage linkedPackage = linkedPackages
-          .singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
-      _assertHasLinkedVariable(linkedPackage, 'b1', 'int',
-          expectedTypeNameUri: 'dart:core');
-      _assertHasLinkedVariable(linkedPackage, 'b2', 'C',
-          expectedToBeResolved: false);
-    }
-  }
-
   test_getLinkedBundles_missingLibrary() async {
     resourceProvider.newFile(
         '$CACHE/aaa/lib/a.dart',
@@ -802,6 +642,9 @@
     // Try to link.
     // All bundles 'aaa' and 'bbb' and 'ccc' are linked.
     // The name 'C2' in 'b.dart' is not resolved.
+    // We have the corresponding unlinked bundle, and it is full, so if it does
+    // not have the library 'package:ccc/c2.dart', this means that this library
+    // does not exist in 'ccc' at all.
     List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
     expect(linkedPackages, hasLength(3));
 
@@ -972,69 +815,6 @@
     }
   }
 
-  test_getLinkedBundles_useSdkExtension() async {
-    resourceProvider.newFile(
-        '$CACHE/aaa/lib/a.dart',
-        '''
-import 'dart:bbb';
-ExtB a;
-''');
-    resourceProvider.newFile(
-        '$CACHE/bbb/lib/b.dart',
-        '''
-import 'dart:bbb';
-ExtB b;
-''');
-    resourceProvider.newFile(
-        '$CACHE/bbb/sdk_ext/extB.dart',
-        '''
-class ExtB {}
-''');
-    resourceProvider.newFile(
-        '$CACHE/bbb/lib/_sdkext',
-        '''
-{
-  "dart:bbb": "../sdk_ext/extB.dart"
-}
-''');
-
-    // Configure packages resolution.
-    Folder libFolderA = resourceProvider.newFolder('$CACHE/aaa/lib');
-    Folder libFolderB = resourceProvider.newFolder('$CACHE/bbb/lib');
-    context.sourceFactory = new SourceFactory(<UriResolver>[
-      sdkResolver,
-      resourceResolver,
-      new PackageMapUriResolver(resourceProvider, {
-        'aaa': [libFolderA],
-        'bbb': [libFolderB],
-      })
-    ]);
-
-    // Ensure unlinked bundles.
-    manager.getUnlinkedBundles(context);
-    await manager.onUnlinkedComplete;
-
-    // Now we should be able to get linked bundles.
-    List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
-    expect(linkedPackages, hasLength(2));
-
-    // package:aaa
-    {
-      LinkedPubPackage linkedPackage = linkedPackages
-          .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
-      _assertHasLinkedVariable(linkedPackage, 'a', 'ExtB',
-          expectedTypeNameUri: 'dart:bbb');
-    }
-
-    // package:bbb
-    {
-      LinkedPubPackage linkedPackage = linkedPackages
-          .singleWhere((linkedPackage) => linkedPackage.package.name == 'bbb');
-      _assertHasLinkedVariable(linkedPackage, 'b', 'ExtB',
-          expectedTypeNameUri: 'dart:bbb');
-    }
-  }
-
   test_getLinkedBundles_wrongScheme() async {
     resourceProvider.newFile(
         '$CACHE/aaa/lib/a.dart',
@@ -1059,26 +839,17 @@
     await manager.onUnlinkedComplete;
 
     // Try to link.
-    // The package 'aaa' is linked.
-    // The name 'Z' in 'a.dart' is not resolved.
+    // The package 'aaa' is not linked.
+    // We don't know how to handle the URI scheme 'xxx'.
     List<LinkedPubPackage> linkedPackages = manager.getLinkedBundles(context);
-    expect(linkedPackages, hasLength(1));
-
-    // package:aaa
-    {
-      LinkedPubPackage linkedPackage = linkedPackages
-          .singleWhere((linkedPackage) => linkedPackage.package.name == 'aaa');
-      _assertHasLinkedVariable(linkedPackage, 'a1', 'int',
-          expectedTypeNameUri: 'dart:core');
-      _assertHasLinkedVariable(linkedPackage, 'a2', 'Z',
-          expectedToBeResolved: false);
-    }
+    expect(linkedPackages, hasLength(0));
   }
 
   test_getPackageName() {
     String getPackageName(String uriStr) {
       return PubSummaryManager.getPackageName(uriStr);
     }
+
     expect(getPackageName('package:foo/bar.dart'), 'foo');
     expect(getPackageName('package:foo/bar/baz.dart'), 'foo');
     expect(getPackageName('wrong:foo/bar.dart'), isNull);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index bd2c1fb..ee6985c 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -60,6 +60,7 @@
     for (Source otherSource in otherLibrarySources) {
       _checkSource(resynthesizer, otherSource);
     }
+    _reset();
     return resynthesized.definingCompilationUnit;
   }
 
@@ -209,36 +210,6 @@
 
   @override
   @failingTest
-  void test_futureThen() {
-    super.test_futureThen();
-  }
-
-  @override
-  @failingTest
-  void test_futureThen_conditional() {
-    super.test_futureThen_conditional();
-  }
-
-  @override
-  @failingTest
-  void test_futureThen_upwards() {
-    super.test_futureThen_upwards();
-  }
-
-  @override
-  @failingTest
-  void test_futureUnion_asyncConditional() {
-    super.test_futureUnion_asyncConditional();
-  }
-
-  @override
-  @failingTest
-  void test_futureUnion_downwards() {
-    super.test_futureUnion_downwards();
-  }
-
-  @override
-  @failingTest
   void test_genericMethods_inferJSBuiltin() {
     super.test_genericMethods_inferJSBuiltin();
   }
@@ -748,7 +719,7 @@
 abstract class _AstResynthesizeTestMixin
     implements _AstResynthesizeTestMixinInterface {
   final Set<Source> serializedSources = new Set<Source>();
-  final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
+  PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
   final Map<String, UnlinkedUnitBuilder> uriToUnit =
       <String, UnlinkedUnitBuilder>{};
 
@@ -838,6 +809,12 @@
     });
   }
 
+  void _reset() {
+    serializedSources.clear();
+    bundleAssembler = new PackageBundleAssembler();
+    uriToUnit.clear();
+  }
+
   void _serializeLibrary(Source librarySource) {
     if (librarySource.isInSystemLibrary) {
       return;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index f08366b8..ac0dc3a 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -696,7 +696,6 @@
     expect(rImpl.codeLength, oImpl.codeLength, reason: desc);
     expect(resynthesized.documentationComment, original.documentationComment,
         reason: desc);
-    expect(resynthesized.docRange, original.docRange, reason: desc);
     compareMetadata(resynthesized.metadata, original.metadata, desc);
 
     // Validate modifiers.
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index 09af948..287b482 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -286,8 +286,6 @@
     String expectedCommentText =
         text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
     expect(documentationComment.text, expectedCommentText);
-    expect(documentationComment.offset, commentStart);
-    expect(documentationComment.length, commentEnd - commentStart);
   }
 
   /**
diff --git a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
index 56f174e..f5668ff 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -2001,7 +2001,7 @@
       unitDelta = builder.unitDelta;
       expect(newUnit.element, unitElement);
       // Flush all tokens, ASTs and elements.
-      context.analysisCache.flush((target, result) {
+      context.analysisCache.flush((target) => true, (target, result) {
         return result == TOKEN_STREAM ||
             result == PARSED_UNIT ||
             RESOLVED_UNIT_RESULTS.contains(result) ||
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index d2a0bd5..a00747e 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -164,8 +164,7 @@
 abstract class Base implements I1 {}
 
 class T1 extends Base {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -186,7 +185,7 @@
     // not reported technically because if the class is concrete,
     // it should implement all its interfaces and hence it is
     // sufficient to check overrides against it.
-    m(/*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+    m(B a) {}
 }
 ''');
   }
@@ -202,8 +201,7 @@
 abstract class I2 implements I1 {}
 
 class T1 implements I2 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -219,8 +217,7 @@
 abstract class I2 extends Object with M1 {}
 
 class T1 implements I2 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -236,8 +233,7 @@
 abstract class I2 extends I1 {}
 
 class T1 implements I2 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -273,7 +269,7 @@
 test() {
   int x = 0;
   x += 5;
-  /*error:STATIC_TYPE_ERROR*/x += /*error:INVALID_ASSIGNMENT*/3.14;
+  x += /*error:INVALID_ASSIGNMENT*/3.14;
 
   double y = 0.0;
   y += 5;
@@ -284,12 +280,12 @@
   z += 3.14;
 
   x = /*info:DOWN_CAST_IMPLICIT*/x + z;
-  x += /*info:DOWN_CAST_IMPLICIT*/z;
+  /*info:DOWN_CAST_IMPLICIT*/x += z;
   y = y + z;
   y += z;
 
   dynamic w = 42;
-  x += /*info:DYNAMIC_CAST*/w;
+  /*info:DOWN_CAST_IMPLICIT*/x += /*info:DYNAMIC_CAST*/w;
   y += /*info:DYNAMIC_CAST*/w;
   z += /*info:DYNAMIC_CAST*/w;
 
@@ -305,7 +301,7 @@
   a += b;
   a += /*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/a;
   a -= b;
-  /*error:STATIC_TYPE_ERROR*/b -= /*error:INVALID_ASSIGNMENT*/b;
+  b -= /*error:INVALID_ASSIGNMENT*/b;
   a <<= b;
   a >>= b;
   a &= b;
@@ -324,6 +320,20 @@
 ''');
   }
 
+  void test_compoundAssignment_returnsDynamic() {
+    checkFile(r'''
+class Foo {
+  operator +(other) => null;
+}
+
+main() {
+  var foo = new Foo();
+  foo = /*info:DYNAMIC_CAST*/foo + 1;
+  /*info:DYNAMIC_CAST*/foo += 1;
+}
+    ''');
+  }
+
   void test_constructorInvalid() {
     // Regression test for https://github.com/dart-lang/sdk/issues/26695
     checkFile('''
@@ -1787,8 +1797,7 @@
 }
 
 class Derived<S extends A> extends Base<B> {
-  /*error:INVALID_METHOD_OVERRIDE*/S
-      /*error:INVALID_METHOD_OVERRIDE_RETURN_TYPE*/foo() => null;
+  /*error:INVALID_METHOD_OVERRIDE*/S foo() => null;
 }
 
 class Derived2<S extends B> extends Base<B> {
@@ -2253,43 +2262,37 @@
 }
 
 class T1 extends Base {
-  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B get
-      /*error:INVALID_GETTER_OVERRIDE_RETURN_TYPE*/f => null;
+  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B get f => null;
 }
 
 class T2 extends Base {
   /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/set f(
-      /*error:INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE*/B b) => null;
+      B b) => null;
 }
 
 class T3 extends Base {
   /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/final B
-      /*warning:FINAL_NOT_INITIALIZED, error:INVALID_GETTER_OVERRIDE_RETURN_TYPE*/f;
+      /*warning:FINAL_NOT_INITIALIZED*/f;
 }
 class T4 extends Base {
   // two: one for the getter one for the setter.
-  /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B
-      /*error:INVALID_GETTER_OVERRIDE_RETURN_TYPE, error:INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE*/f;
+  /*error:INVALID_FIELD_OVERRIDE, error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B f;
 }
 
 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T5 implements Base {
-  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/B get
-      /*error:INVALID_GETTER_OVERRIDE_RETURN_TYPE*/f => null;
+  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/B get f => null;
 }
 
 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T6 implements Base {
-  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/set f(
-      /*error:INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE*/B b) => null;
+  /*warning:MISMATCHED_GETTER_AND_SETTER_TYPES_FROM_SUPERTYPE, error:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
 }
 
 class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T7 implements Base {
-  /*error:INVALID_METHOD_OVERRIDE*/final B
-      /*error:INVALID_GETTER_OVERRIDE_RETURN_TYPE*/f = null;
+  /*error:INVALID_METHOD_OVERRIDE*/final B f = null;
 }
 class T8 implements Base {
   // two: one for the getter one for the setter.
-  /*error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B
-      /*error:INVALID_GETTER_OVERRIDE_RETURN_TYPE, error:INVALID_SETTER_OVERRIDE_NORMAL_PARAM_TYPE*/f;
+  /*error:INVALID_METHOD_OVERRIDE, error:INVALID_METHOD_OVERRIDE*/B f;
 }
 ''');
   }
@@ -2304,8 +2307,7 @@
 }
 
 class Test extends Base {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-        /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -2320,8 +2322,7 @@
 }
 
 class T1 implements I {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -2340,8 +2341,7 @@
 
 class Test extends Parent {
     // Reported only once
-    /*error:INVALID_METHOD_OVERRIDE*/m(
-        /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+    /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -2355,8 +2355,7 @@
     m(A a) {}
 }
 class Parent extends Grandparent {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 
 class Test extends Parent {
@@ -2378,8 +2377,7 @@
 }
 
 class Test extends Parent {
-    /*error:INVALID_METHOD_OVERRIDE*/m(
-          /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+    /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
     /*error:INVALID_FIELD_OVERRIDE*/int x;
 }
 ''');
@@ -2910,8 +2908,7 @@
 // Note: no error reported in `extends Base` to avoid duplicating
 // the error in T1.
 class T1 extends Base implements I1 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 
 // If there is no error in the class, we do report the error at
@@ -2937,8 +2934,7 @@
 }
 
 class T1 extends Object with M implements I1 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 
 class /*error:INCONSISTENT_METHOD_INHERITANCE*/T2
@@ -2963,8 +2959,7 @@
 class Base {}
 
 class T1 implements I2 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 ''');
   }
@@ -3019,7 +3014,7 @@
   n(B b);
 }
 abstract class D extends C {
-  /*error:INVALID_METHOD_OVERRIDE*/m(/*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B b);
+  /*error:INVALID_METHOD_OVERRIDE*/m(B b);
   n(A a);
 }
     ''');
@@ -3045,8 +3040,7 @@
   /*error:INVALID_FIELD_OVERRIDE*/var _f3;
   var _f4;
 
-  /*error:INVALID_METHOD_OVERRIDE*/String
-      /*error:INVALID_METHOD_OVERRIDE_RETURN_TYPE*/_m1() => null;
+  /*error:INVALID_METHOD_OVERRIDE*/String _m1() => null;
 }
 ''',
         name: '/helper.dart');
@@ -3304,8 +3298,7 @@
 }
 
 abstract class Base implements I1 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 
 class T1 extends Base {
@@ -3329,8 +3322,7 @@
 }
 
 class Base implements I1 {
-  /*error:INVALID_METHOD_OVERRIDE*/m(
-      /*error:INVALID_METHOD_OVERRIDE_NORMAL_PARAM_TYPE*/B a) {}
+  /*error:INVALID_METHOD_OVERRIDE*/m(B a) {}
 }
 
 class T1 extends Base {
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 5405293..8b00a44 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -1676,6 +1676,24 @@
     checkFile(build(downwards: "Future", upwards: "MyFuture"));
   }
 
+  void test_futureUnion_downwardsGenericMethods() {
+    // Regression test for https://github.com/dart-lang/sdk/issues/27134
+    //
+    // We need to take a future union into account for both directions of
+    // generic method inference.
+    checkFile(r'''
+import 'dart:async';
+
+foo() async {
+  Future<List<A>> f1 = null;
+  Future<List<A>> f2 = null;
+  List<List<A>> merged = await Future.wait(/*info:INFERRED_TYPE_LITERAL*/[f1, f2]);
+}
+
+class A {}
+    ''');
+  }
+
   void test_futureUnion_downwards() {
     String build({String declared, String downwards, String upwards}) {
       // TODO(leafp): The use of matchTypes in visitInstanceCreationExpression
diff --git a/pkg/analyzer/tool/summary/generate.dart b/pkg/analyzer/tool/summary/generate.dart
index 124a6b8..b9616867 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -119,7 +119,7 @@
         }
       }
       Map<int, String> idsUsed = <int, String>{};
-      for (idlModel.FieldDeclaration field in cls.fields) {
+      for (idlModel.FieldDeclaration field in cls.allFields) {
         String fieldName = field.name;
         idlModel.FieldType type = field.type;
         if (type.isList) {
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index b69669d..025e620 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -13,10 +13,10 @@
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/link.dart';
@@ -131,7 +131,7 @@
 
   SummaryDataStore summaryDataStore;
   InternalAnalysisContext context;
-  Map<Uri, JavaFile> uriToFileMap;
+  Map<Uri, File> uriToFileMap;
   final List<Source> explicitSources = <Source>[];
 
   PackageBundleAssembler assembler;
@@ -167,13 +167,13 @@
     // Add sources.
     ChangeSet changeSet = new ChangeSet();
     for (Uri uri in uriToFileMap.keys) {
-      JavaFile file = uriToFileMap[uri];
-      if (!file.exists()) {
-        errorSink.writeln('File not found: ${file.getPath()}');
+      File file = uriToFileMap[uri];
+      if (!file.exists) {
+        errorSink.writeln('File not found: ${file.path}');
         io.exitCode = ErrorSeverity.ERROR.ordinal;
         return ErrorSeverity.ERROR;
       }
-      Source source = new FileBasedSource(file, uri);
+      Source source = new FileSource(file, uri);
       explicitSources.add(source);
       changeSet.addedSource(source);
     }
@@ -291,7 +291,7 @@
     context = AnalysisEngine.instance.createAnalysisContext();
     context.sourceFactory = new SourceFactory(<UriResolver>[
       new DartUriResolver(sdk),
-      new InSummaryPackageUriResolver(summaryDataStore),
+      new InSummaryUriResolver(resourceProvider, summaryDataStore),
       new ExplicitSourceResolver(uriToFileMap)
     ]);
 
@@ -312,6 +312,28 @@
   }
 
   /**
+   * Convert [sourceEntities] (a list of file specifications of the form
+   * "$uri|$path") to a map from URI to path.  If an error occurs, report the
+   * error and return null.
+   */
+  Map<Uri, File> _createUriToFileMap(List<String> sourceEntities) {
+    Map<Uri, File> uriToFileMap = <Uri, File>{};
+    for (String sourceFile in sourceEntities) {
+      int pipeIndex = sourceFile.indexOf('|');
+      if (pipeIndex == -1) {
+        // TODO(paulberry): add the ability to guess the URI from the path.
+        errorSink.writeln(
+            'Illegal input file (must be "\$uri|\$path"): $sourceFile');
+        return null;
+      }
+      Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex));
+      String path = sourceFile.substring(pipeIndex + 1);
+      uriToFileMap[uri] = resourceProvider.getFile(path);
+    }
+    return uriToFileMap;
+  }
+
+  /**
    * Print errors for all explicit sources.  If [outputPath] is supplied, output
    * is sent to a new file at that path.
    */
@@ -377,26 +399,48 @@
         link(sourceUris, _getDependency, _getUnit, options.strongMode);
     linkResult.forEach(assembler.addLinkedLibrary);
   }
+}
+
+/**
+ * Instances of the class [ExplicitSourceResolver] map URIs to files on disk
+ * using a fixed mapping provided at construction time.
+ */
+class ExplicitSourceResolver extends UriResolver {
+  final Map<Uri, File> uriToFileMap;
+  final Map<String, Uri> pathToUriMap;
 
   /**
-   * Convert [sourceEntities] (a list of file specifications of the form
-   * "$uri|$path") to a map from URI to path.  If an error occurs, report the
-   * error and return null.
+   * Construct an [ExplicitSourceResolver] based on the given [uriToFileMap].
    */
-  static Map<Uri, JavaFile> _createUriToFileMap(List<String> sourceEntities) {
-    Map<Uri, JavaFile> uriToFileMap = <Uri, JavaFile>{};
-    for (String sourceFile in sourceEntities) {
-      int pipeIndex = sourceFile.indexOf('|');
-      if (pipeIndex == -1) {
-        // TODO(paulberry): add the ability to guess the URI from the path.
-        errorSink.writeln(
-            'Illegal input file (must be "\$uri|\$path"): $sourceFile');
-        return null;
-      }
-      Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex));
-      String path = sourceFile.substring(pipeIndex + 1);
-      uriToFileMap[uri] = new JavaFile(path);
+  ExplicitSourceResolver(Map<Uri, File> uriToFileMap)
+      : uriToFileMap = uriToFileMap,
+        pathToUriMap = _computePathToUriMap(uriToFileMap);
+
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    File file = uriToFileMap[uri];
+    actualUri ??= uri;
+    if (file == null) {
+      return new NonExistingSource(
+          uri.toString(), actualUri, UriKind.fromScheme(actualUri.scheme));
+    } else {
+      return new FileSource(file, actualUri);
     }
-    return uriToFileMap;
+  }
+
+  @override
+  Uri restoreAbsolute(Source source) {
+    return pathToUriMap[source.fullName];
+  }
+
+  /**
+   * Build the inverse mapping of [uriToSourceMap].
+   */
+  static Map<String, Uri> _computePathToUriMap(Map<Uri, File> uriToSourceMap) {
+    Map<String, Uri> pathToUriMap = <String, Uri>{};
+    uriToSourceMap.forEach((Uri uri, File file) {
+      pathToUriMap[file.path] = uri;
+    });
+    return pathToUriMap;
   }
 }
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 68c9b25..e0c1eea 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -6,9 +6,10 @@
 
 import 'dart:async';
 import 'dart:convert';
-import 'dart:io';
+import 'dart:io' as io;
 
 import 'package:analyzer/file_system/file_system.dart' as file_system;
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/plugin/options.dart';
 import 'package:analyzer/plugin/resolver_provider.dart';
@@ -31,6 +32,7 @@
 import 'package:analyzer/src/generated/utilities_general.dart'
     show PerformanceTag;
 import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/source/source_resource.dart';
 import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer_cli/src/analyzer_impl.dart';
@@ -53,12 +55,12 @@
 /// Shared IO sink for standard error reporting.
 ///
 /// *Visible for testing.*
-StringSink errorSink = stderr;
+StringSink errorSink = io.stderr;
 
 /// Shared IO sink for standard out reporting.
 ///
 /// *Visible for testing.*
-StringSink outSink = stdout;
+StringSink outSink = io.stdout;
 
 /// Test this option map to see if it specifies lint rules.
 bool containsLintRuleEntry(Map<String, YamlNode> options) {
@@ -132,7 +134,7 @@
       ErrorSeverity severity = _buildModeAnalyze(options);
       // In case of error propagate exit code.
       if (severity == ErrorSeverity.ERROR) {
-        exitCode = severity.ordinal;
+        io.exitCode = severity.ordinal;
       }
     } else if (options.shouldBatch) {
       _BatchRunner.runAsBatch(args, (List<String> args) {
@@ -143,7 +145,7 @@
       ErrorSeverity severity = _analyzeAll(options);
       // In case of error propagate exit code.
       if (severity == ErrorSeverity.ERROR) {
-        exitCode = severity.ordinal;
+        io.exitCode = severity.ordinal;
       }
     }
 
@@ -154,7 +156,7 @@
     if (options.perfReport != null) {
       String json = makePerfReport(
           startTime, currentTimeMillis(), options, _analyzedFileCount, stats);
-      new File(options.perfReport).writeAsStringSync(json);
+      new io.File(options.perfReport).writeAsStringSync(json);
     }
   }
 
@@ -191,14 +193,14 @@
       // Note that these files will all be analyzed in the same context.
       // This should be updated when the ContextManager re-work is complete
       // (See: https://github.com/dart-lang/sdk/issues/24133)
-      Iterable<File> files = _collectFiles(sourcePath);
+      Iterable<io.File> files = _collectFiles(sourcePath);
       if (files.isEmpty) {
         errorSink.writeln('No dart files found at: $sourcePath');
-        exitCode = ErrorSeverity.ERROR.ordinal;
+        io.exitCode = ErrorSeverity.ERROR.ordinal;
         return ErrorSeverity.ERROR;
       }
 
-      for (File file in files) {
+      for (io.File file in files) {
         Source source = _computeLibrarySource(file.absolute.path);
         if (!knownSources.contains(source)) {
           changeSet.addedSource(source);
@@ -235,7 +237,7 @@
       if (!found) {
         errorSink.writeln("${part.fullName} is a part and cannot be analyzed.");
         errorSink.writeln("Please pass in a library that contains this part.");
-        exitCode = ErrorSeverity.ERROR.ordinal;
+        io.exitCode = ErrorSeverity.ERROR.ordinal;
         allResult = allResult.max(ErrorSeverity.ERROR);
       }
     }
@@ -423,15 +425,15 @@
 
   /// Collect all analyzable files at [filePath], recursively if it's a
   /// directory, ignoring links.
-  Iterable<File> _collectFiles(String filePath) {
-    List<File> files = <File>[];
-    File file = new File(filePath);
+  Iterable<io.File> _collectFiles(String filePath) {
+    List<io.File> files = <io.File>[];
+    io.File file = new io.File(filePath);
     if (file.existsSync()) {
       files.add(file);
     } else {
-      Directory directory = new Directory(filePath);
+      io.Directory directory = new io.Directory(filePath);
       if (directory.existsSync()) {
-        for (FileSystemEntity entry
+        for (io.FileSystemEntity entry
             in directory.listSync(recursive: true, followLinks: false)) {
           String relative = path.relative(entry.path, from: directory.path);
           if (AnalysisEngine.isDartFileName(entry.path) &&
@@ -449,17 +451,17 @@
   /// context.
   Source _computeLibrarySource(String sourcePath) {
     sourcePath = _normalizeSourcePath(sourcePath);
-    JavaFile sourceFile = new JavaFile(sourcePath);
-    Source source = sdk.fromFileUri(sourceFile.toURI());
+    File sourceFile = resourceProvider.getFile(sourcePath);
+    Source source = sdk.fromFileUri(sourceFile.toUri());
     if (source != null) {
       return source;
     }
-    source = new FileBasedSource(sourceFile, sourceFile.toURI());
+    source = new FileSource(sourceFile, sourceFile.toUri());
     Uri uri = _context.sourceFactory.restoreUri(source);
     if (uri == null) {
       return source;
     }
-    return new FileBasedSource(sourceFile, uri);
+    return new FileSource(sourceFile, uri);
   }
 
   /// Create an analysis context that is prepared to analyze sources according
@@ -538,7 +540,7 @@
       String packageConfigPath = options.packageConfigPath;
       Uri fileUri = new Uri.file(packageConfigPath);
       try {
-        File configFile = new File.fromUri(fileUri).absolute;
+        io.File configFile = new io.File.fromUri(fileUri).absolute;
         List<int> bytes = configFile.readAsBytesSync();
         Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
         packages = new MapPackages(map);
@@ -609,10 +611,10 @@
         _context, incrementalSession, source, options, stats, startTime);
     var errorSeverity = analyzer.analyzeSync();
     if (errorSeverity == ErrorSeverity.ERROR) {
-      exitCode = errorSeverity.ordinal;
+      io.exitCode = errorSeverity.ordinal;
     }
     if (options.warningsAreFatal && errorSeverity == ErrorSeverity.WARNING) {
-      exitCode = errorSeverity.ordinal;
+      io.exitCode = errorSeverity.ordinal;
     }
     return errorSeverity;
   }
@@ -721,7 +723,7 @@
 
   /// Convert [sourcePath] into an absolute path.
   static String _normalizeSourcePath(String sourcePath) =>
-      path.normalize(new File(sourcePath).absolute.path);
+      path.normalize(new io.File(sourcePath).absolute.path);
 
   static void _processAnalysisOptions(
       file_system.ResourceProvider resourceProvider,
@@ -769,14 +771,14 @@
     ErrorSeverity batchResult = ErrorSeverity.NONE;
     // Read line from stdin.
     Stream cmdLine =
-        stdin.transform(UTF8.decoder).transform(new LineSplitter());
+        io.stdin.transform(UTF8.decoder).transform(new LineSplitter());
     cmdLine.listen((String line) {
       // Maybe finish.
       if (line.isEmpty) {
         var time = stopwatch.elapsedMilliseconds;
         outSink.writeln(
             '>>> BATCH END (${totalTests - testsFailed}/$totalTests) ${time}ms');
-        exitCode = batchResult.ordinal;
+        io.exitCode = batchResult.ordinal;
       }
       // Prepare arguments.
       var lineArgs = line.split(new RegExp('\\s+'));
@@ -828,7 +830,7 @@
 class _PackageRootPackageMapBuilder {
   static Map<String, List<file_system.Folder>> buildPackageMap(
       String packageRootPath) {
-    var packageRoot = new Directory(packageRootPath);
+    var packageRoot = new io.Directory(packageRootPath);
     if (!packageRoot.existsSync()) {
       throw new _DriverError(
           'Package root directory ($packageRootPath) does not exist.');
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 52c7cf3..94a751c 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -44,6 +44,7 @@
   static const String trustJSInteropTypeAnnotations =
       '--experimental-trust-js-interop-type-annotations';
   static const String useContentSecurityPolicy = '--csp';
+  static const String useKernel = '--use-kernel';
   static const String useNewSourceInfo = '--use-new-source-info';
   static const String verbose = '--verbose';
   static const String version = '--version';
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 42f7b32..b58b82e 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -9,7 +9,7 @@
 import '../compiler.dart' show Compiler;
 import '../constants/expressions.dart' show ConstantExpression;
 import '../constants/values.dart' show ConstantValue;
-import '../core_types.dart' show CoreClasses, CoreTypes;
+import '../core_types.dart' show CoreClasses, CoreTypes, CommonElements;
 import '../dart_types.dart' show DartType, Types;
 import '../elements/elements.dart'
     show
@@ -70,7 +70,6 @@
   Iterable<dynamic> get nativeData => const <dynamic>[];
 }
 
-
 /// Interface for the accessing the front-end analysis.
 // TODO(johnniwinther): Find a better name for this.
 abstract class Frontend {
@@ -122,6 +121,7 @@
   DiagnosticReporter get reporter;
   CoreClasses get coreClasses;
   CoreTypes get coreTypes;
+  CommonElements get commonElements;
   Types get types;
   Target get target;
   ResolverTask get resolver;
@@ -131,17 +131,10 @@
   ConstantEnvironment get constants;
   MirrorUsageAnalyzerTask get mirrorUsageAnalyzerTask;
 
-  // TODO(het): Move all elements into common/elements.dart
-  LibraryElement get coreLibrary;
-  FunctionElement get identicalFunction;
-  ClassElement get mirrorSystemClass;
-  FunctionElement get mirrorSystemGetNameFunction;
-  ConstructorElement get mirrorsUsedConstructor;
-  ConstructorElement get symbolConstructor;
-
-  // TODO(het): This is only referenced in a test...
-  /// The constant for the [proxy] variable defined in dart:core.
-  ConstantValue get proxyConstant;
+  /// Whether internally we computed the constant for the [proxy] variable
+  /// defined in dart:core (used only for testing).
+  // TODO(sigmund): delete, we need a better way to test this.
+  bool get wasProxyConstantComputedTestingOnly;
 
   /// If set to `true` resolution caches will not be cleared. Use this only for
   /// testing.
@@ -163,9 +156,6 @@
   /// Resolve [element] if it has not already been resolved.
   void ensureResolved(Element element);
 
-  /// Called whenever a class has been resolved.
-  void onClassResolved(ClassElement element);
-
   /// Registers that [element] has a compile time error.
   ///
   /// The error itself is given in [message].
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index bda354e2..a8f3a89 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -600,7 +600,7 @@
       new AstConstant(context, node, new StringConstantExpression(text),
           constantSystem.createString(new LiteralDartString(text)))
     ];
-    ConstructorElement constructor = compiler.symbolConstructor;
+    ConstructorElement constructor = compiler.commonElements.symbolConstructor;
     AstConstant constant = createConstructorInvocation(
         node, type, constructor, CallStructure.ONE_ARG,
         normalizedArguments: arguments);
@@ -711,7 +711,8 @@
       }
       return result;
     } else if (send.isCall) {
-      if (element == compiler.identicalFunction && send.argumentCount() == 2) {
+      if (element == compiler.commonElements.identicalFunction &&
+          send.argumentCount() == 2) {
         AstConstant left = evaluate(send.argumentsNode.nodes.head);
         AstConstant right = evaluate(send.argumentsNode.nodes.tail.head);
         if (left == null || right == null) {
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index cf4e215..2fc4ceb 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -26,7 +26,7 @@
 import 'common.dart';
 import 'compile_time_constants.dart';
 import 'constants/values.dart';
-import 'core_types.dart' show CoreClasses, CoreTypes;
+import 'core_types.dart' show CoreClasses, CommonElements, CoreTypes;
 import 'dart_types.dart' show DartType, DynamicType, InterfaceType, Types;
 import 'deferred_load.dart' show DeferredLoadTask;
 import 'diagnostics/code_location.dart';
@@ -75,7 +75,8 @@
 import 'tracer.dart' show Tracer;
 import 'tree/tree.dart' show Node, TypeAnnotation;
 import 'typechecker.dart' show TypeCheckerTask;
-import 'types/types.dart' as ti;
+import 'types/types.dart' show GlobalTypeInferenceTask;
+import 'types/masks.dart' show CommonMasks;
 import 'universe/selector.dart' show Selector;
 import 'universe/universe.dart' show Universe;
 import 'universe/use.dart' show StaticUse;
@@ -145,64 +146,17 @@
 
   Tracer tracer;
 
-  LibraryElement coreLibrary;
-  LibraryElement asyncLibrary;
-
   LibraryElement mainApp;
   FunctionElement mainFunction;
 
-  /// Initialized when dart:mirrors is loaded.
-  LibraryElement mirrorsLibrary;
-
-  /// Initialized when dart:typed_data is loaded.
-  LibraryElement typedDataLibrary;
-
   DiagnosticReporter get reporter => _reporter;
+  CommonElements get commonElements => _coreTypes;
   CoreClasses get coreClasses => _coreTypes;
   CoreTypes get coreTypes => _coreTypes;
+  CommonMasks get commonMasks => globalInference.masks;
   Resolution get resolution => _resolution;
   ParsingContext get parsingContext => _parsingContext;
 
-  ClassElement typedDataClass;
-
-  // TODO(johnniwinther): Move this to the JavaScriptBackend.
-  /// The class for patch annotation defined in dart:_js_helper.
-  ClassElement patchAnnotationClass;
-
-  // TODO(johnniwinther): Move this to the JavaScriptBackend.
-  ClassElement nativeAnnotationClass;
-
-  ConstructorElement _symbolConstructor;
-  ConstructorElement get symbolConstructor {
-    if (_symbolConstructor == null) {
-      ClassElement symbolClass = coreClasses.symbolClass;
-      symbolClass.ensureResolved(resolution);
-      _symbolConstructor = symbolClass.lookupConstructor('');
-      assert(invariant(symbolClass, _symbolConstructor != null,
-          message: "Default constructor not found ${symbolClass}."));
-    }
-    return _symbolConstructor;
-  }
-
-  // Initialized when dart:mirrors is loaded.
-  ClassElement mirrorSystemClass;
-
-  // Initialized when dart:mirrors is loaded.
-  ClassElement mirrorsUsedClass;
-
-  // Initialized after mirrorSystemClass has been resolved.
-  FunctionElement mirrorSystemGetNameFunction;
-
-  // Initialized when mirrorsUsedClass has been resolved.
-  FunctionElement mirrorsUsedConstructor;
-
-  // Initialized when dart:mirrors is loaded.
-  ClassElement deferredLibraryClass;
-
-  Element identicalFunction;
-  Element loadLibraryFunction;
-  Element functionApplyMethod;
-
   // TODO(zarah): Remove this map and incorporate compile-time errors
   // in the model.
   /// Tracks elements with compile-time errors.
@@ -227,7 +181,7 @@
   ResolverTask resolver;
   closureMapping.ClosureTask closureToClassMapper;
   TypeCheckerTask checker;
-  ti.TypesTask typesTask;
+  GlobalTypeInferenceTask globalInference;
   Backend backend;
 
   GenericTask selfTask;
@@ -285,7 +239,7 @@
     _resolution = new _CompilerResolution(this);
     // TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
     // make its field final.
-    _coreTypes = new _CompilerCoreTypes(_resolution);
+    _coreTypes = new _CompilerCoreTypes(_resolution, reporter);
     types = new Types(_resolution);
     tracer = new Tracer(this, this.outputProvider);
 
@@ -304,7 +258,8 @@
           this,
           generateSourceMap: options.generateSourceMap,
           useStartupEmitter: options.useStartupEmitter,
-          useNewSourceInfo: options.useNewSourceInfo);
+          useNewSourceInfo: options.useNewSourceInfo,
+          useKernel: options.useKernel);
       backend = jsBackend;
     }
 
@@ -321,7 +276,8 @@
       libraryLoader = new LibraryLoaderTask(
           resolvedUriTranslator,
           options.compileOnly
-              ? new _NoScriptLoader(this) : new _ScriptLoader(this),
+              ? new _NoScriptLoader(this)
+              : new _ScriptLoader(this),
           new _ElementScanner(scanner),
           serialization,
           this,
@@ -333,7 +289,7 @@
       resolver = createResolverTask(),
       closureToClassMapper = new closureMapping.ClosureTask(this),
       checker = new TypeCheckerTask(this),
-      typesTask = new ti.TypesTask(this),
+      globalInference = new GlobalTypeInferenceTask(this),
       constants = backend.constantCompilerTask,
       deferredLoadTask = new DeferredLoadTask(this),
       mirrorUsageAnalyzerTask = new MirrorUsageAnalyzerTask(this),
@@ -406,14 +362,7 @@
   /// Note that [library] has not been scanned yet, nor has its imports/exports
   /// been resolved.
   void onLibraryCreated(LibraryElement library) {
-    Uri uri = library.canonicalUri;
-    if (uri == Uris.dart_core) {
-      coreLibrary = library;
-    } else if (uri == Uris.dart__native_typed_data) {
-      typedDataLibrary = library;
-    } else if (uri == Uris.dart_mirrors) {
-      mirrorsLibrary = library;
-    }
+    _coreTypes.onLibraryCreated(library);
     backend.onLibraryCreated(library);
   }
 
@@ -427,31 +376,6 @@
   /// Use [loader] to register the creation and scanning of a patch library
   /// for [library].
   Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
-    Uri uri = library.canonicalUri;
-    // If the script of the library is synthesized, the library does not exist
-    // and we do not try to load the helpers.
-    //
-    // This could for example happen if dart:async is disabled, then loading it
-    // should not try to find the given element.
-    if (!library.isSynthesized) {
-      if (uri == Uris.dart_core) {
-        initializeCoreClasses();
-        identicalFunction = coreLibrary.find('identical');
-      } else if (uri == Uris.dart_mirrors) {
-        mirrorSystemClass = findRequiredElement(library, 'MirrorSystem');
-        mirrorsUsedClass = findRequiredElement(library, 'MirrorsUsed');
-      } else if (uri == Uris.dart_async) {
-        asyncLibrary = library;
-        deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
-        _coreTypes.futureClass = findRequiredElement(library, 'Future');
-        _coreTypes.streamClass = findRequiredElement(library, 'Stream');
-      } else if (uri == Uris.dart__native_typed_data) {
-        typedDataClass = findRequiredElement(library, 'NativeTypedData');
-      } else if (uri == js_backend.BackendHelpers.DART_JS_HELPER) {
-        patchAnnotationClass = findRequiredElement(library, '_Patch');
-        nativeAnnotationClass = findRequiredElement(library, 'Native');
-      }
-    }
     return backend.onLibraryScanned(library, loader);
   }
 
@@ -558,71 +482,13 @@
               .join(MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)
         });
       }
-
-      coreClasses.functionClass.ensureResolved(resolution);
-      functionApplyMethod =
-          coreClasses.functionClass.lookupLocalMember('apply');
     }).then((_) => backend.onLibrariesLoaded(loadedLibraries));
   }
 
-  Element findRequiredElement(LibraryElement library, String name) {
-    var element = library.find(name);
-    if (element == null) {
-      reporter.internalError(
-          library,
-          "The library '${library.canonicalUri}' does not contain required "
-          "element: '$name'.");
-    }
-    return element;
-  }
-
   // TODO(johnniwinther): Move this to [PatchParser] when it is moved to the
   // [JavaScriptBackend]. Currently needed for testing.
   String get patchVersion => backend.patchVersion;
 
-  // TODO(johnniwinther): Remove this. All elements should be looked up on
-  // demand.
-  void onClassResolved(ClassElement cls) {
-    if (mirrorSystemClass == cls) {
-      mirrorSystemGetNameFunction = cls.lookupLocalMember('getName');
-    } else if (mirrorsUsedClass == cls) {
-      mirrorsUsedConstructor = cls.constructors.head;
-    }
-  }
-
-  void initializeCoreClasses() {
-    final List missingCoreClasses = [];
-    ClassElement lookupCoreClass(String name) {
-      ClassElement result = coreLibrary.find(name);
-      if (result == null) {
-        missingCoreClasses.add(name);
-      }
-      return result;
-    }
-
-    _coreTypes.objectClass = lookupCoreClass('Object');
-    _coreTypes.boolClass = lookupCoreClass('bool');
-    _coreTypes.numClass = lookupCoreClass('num');
-    _coreTypes.intClass = lookupCoreClass('int');
-    _coreTypes.doubleClass = lookupCoreClass('double');
-    _coreTypes.resourceClass = lookupCoreClass('Resource');
-    _coreTypes.stringClass = lookupCoreClass('String');
-    _coreTypes.functionClass = lookupCoreClass('Function');
-    _coreTypes.listClass = lookupCoreClass('List');
-    _coreTypes.typeClass = lookupCoreClass('Type');
-    _coreTypes.mapClass = lookupCoreClass('Map');
-    _coreTypes.nullClass = lookupCoreClass('Null');
-    _coreTypes.stackTraceClass = lookupCoreClass('StackTrace');
-    _coreTypes.iterableClass = lookupCoreClass('Iterable');
-    _coreTypes.symbolClass = lookupCoreClass('Symbol');
-    if (!missingCoreClasses.isEmpty) {
-      reporter.internalError(
-          coreLibrary,
-          'dart:core library does not contain required classes: '
-          '$missingCoreClasses');
-    }
-  }
-
   Element _unnamedListConstructor;
   Element get unnamedListConstructor {
     if (_unnamedListConstructor != null) return _unnamedListConstructor;
@@ -856,7 +722,7 @@
         deferredLoadTask.onResolutionComplete(mainFunction);
 
         reporter.log('Inferring types...');
-        typesTask.onResolutionComplete(mainFunction);
+        globalInference.runGlobalTypeInference(mainFunction);
 
         if (stopAfterTypeInference) return;
 
@@ -904,7 +770,24 @@
           world.addToWorkList(loadLibrary);
         }
       }
+      if (serialization.supportSerialization) {
+        for (MetadataAnnotation metadata in import.metadata) {
+          metadata.ensureResolved(resolution);
+        }
+      }
     });
+    if (serialization.supportSerialization) {
+      library.exports.forEach((ExportElement export) {
+        for (MetadataAnnotation metadata in export.metadata) {
+          metadata.ensureResolved(resolution);
+        }
+      });
+      library.compilationUnits.forEach((CompilationUnitElement unit) {
+        for (MetadataAnnotation metadata in unit.metadata) {
+          metadata.ensureResolved(resolution);
+        }
+      });
+    }
   }
 
   void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
@@ -1282,28 +1165,188 @@
   int hints = 0;
 }
 
-class _CompilerCoreTypes implements CoreTypes, CoreClasses {
+class _CompilerCoreTypes implements CoreTypes, CoreClasses, CommonElements {
   final Resolution resolution;
+  final DiagnosticReporter reporter;
 
-  ClassElement objectClass;
-  ClassElement boolClass;
-  ClassElement numClass;
-  ClassElement intClass;
-  ClassElement doubleClass;
-  ClassElement stringClass;
-  ClassElement functionClass;
-  ClassElement nullClass;
-  ClassElement listClass;
-  ClassElement typeClass;
-  ClassElement mapClass;
-  ClassElement symbolClass;
-  ClassElement stackTraceClass;
-  ClassElement futureClass;
-  ClassElement iterableClass;
-  ClassElement streamClass;
-  ClassElement resourceClass;
+  LibraryElement coreLibrary;
+  LibraryElement asyncLibrary;
+  LibraryElement mirrorsLibrary;
+  LibraryElement typedDataLibrary;
 
-  _CompilerCoreTypes(this.resolution);
+  // TODO(sigmund): possibly move this to target-specific collection of
+  // elements, or refactor the library so that the helpers we need are in a
+  // target-agnostic place.  Currently we are using @patch and @Native from
+  // here. We hope we can make those independent of the backend and generic
+  // enough so the patching algorithm can work without being configured for a
+  // specific backend.
+  LibraryElement jsHelperLibrary;
+
+  _CompilerCoreTypes(this.resolution, this.reporter);
+
+  // From dart:core
+
+  ClassElement _objectClass;
+  ClassElement get objectClass =>
+      _objectClass ??= _findRequired(coreLibrary, 'Object');
+
+  ClassElement _boolClass;
+  ClassElement get boolClass =>
+      _boolClass ??= _findRequired(coreLibrary, 'bool');
+
+  ClassElement _numClass;
+  ClassElement get numClass => _numClass ??= _findRequired(coreLibrary, 'num');
+
+  ClassElement _intClass;
+  ClassElement get intClass => _intClass ??= _findRequired(coreLibrary, 'int');
+
+  ClassElement _doubleClass;
+  ClassElement get doubleClass =>
+      _doubleClass ??= _findRequired(coreLibrary, 'double');
+
+  ClassElement _stringClass;
+  ClassElement get stringClass =>
+      _stringClass ??= _findRequired(coreLibrary, 'String');
+
+  ClassElement _functionClass;
+  ClassElement get functionClass =>
+      _functionClass ??= _findRequired(coreLibrary, 'Function');
+
+  Element _functionApplyMethod;
+  Element get functionApplyMethod {
+    if (_functionApplyMethod == null) {
+      functionClass.ensureResolved(resolution);
+      _functionApplyMethod = functionClass.lookupLocalMember('apply');
+      assert(invariant(functionClass, _functionApplyMethod != null,
+          message: "Member `apply` not found in ${functionClass}."));
+    }
+    return _functionApplyMethod;
+  }
+
+  bool isFunctionApplyMethod(Element element) =>
+      element.name == 'apply' && element.enclosingClass == functionClass;
+
+  ClassElement _nullClass;
+  ClassElement get nullClass =>
+      _nullClass ??= _findRequired(coreLibrary, 'Null');
+
+  ClassElement _listClass;
+  ClassElement get listClass =>
+      _listClass ??= _findRequired(coreLibrary, 'List');
+
+  ClassElement _typeClass;
+  ClassElement get typeClass =>
+      _typeClass ??= _findRequired(coreLibrary, 'Type');
+
+  ClassElement _mapClass;
+  ClassElement get mapClass => _mapClass ??= _findRequired(coreLibrary, 'Map');
+
+  ClassElement _symbolClass;
+  ClassElement get symbolClass =>
+      _symbolClass ??= _findRequired(coreLibrary, 'Symbol');
+
+  ConstructorElement _symbolConstructor;
+  ConstructorElement get symbolConstructor {
+    if (_symbolConstructor == null) {
+      symbolClass.ensureResolved(resolution);
+      _symbolConstructor = symbolClass.lookupConstructor('');
+      assert(invariant(symbolClass, _symbolConstructor != null,
+          message: "Default constructor not found ${symbolClass}."));
+    }
+    return _symbolConstructor;
+  }
+
+  bool isSymbolConstructor(Element e) =>
+      e.enclosingClass == symbolClass && e == symbolConstructor;
+
+  ClassElement _stackTraceClass;
+  ClassElement get stackTraceClass =>
+      _stackTraceClass ??= _findRequired(coreLibrary, 'StackTrace');
+
+  ClassElement _iterableClass;
+  ClassElement get iterableClass =>
+      _iterableClass ??= _findRequired(coreLibrary, 'Iterable');
+
+  ClassElement _resourceClass;
+  ClassElement get resourceClass =>
+      _resourceClass ??= _findRequired(coreLibrary, 'Resource');
+
+  Element _identicalFunction;
+  Element get identicalFunction =>
+      _identicalFunction ??= coreLibrary.find('identical');
+
+  // From dart:async
+
+  ClassElement _futureClass;
+  ClassElement get futureClass =>
+      _futureClass ??= _findRequired(asyncLibrary, 'Future');
+
+  ClassElement _streamClass;
+  ClassElement get streamClass =>
+      _streamClass ??= _findRequired(asyncLibrary, 'Stream');
+
+  ClassElement _deferredLibraryClass;
+  ClassElement get deferredLibraryClass =>
+      _deferredLibraryClass ??= _findRequired(asyncLibrary, "DeferredLibrary");
+
+  // From dart:mirrors
+
+  ClassElement _mirrorSystemClass;
+  ClassElement get mirrorSystemClass =>
+      _mirrorSystemClass ??= _findRequired(mirrorsLibrary, 'MirrorSystem');
+
+  FunctionElement _mirrorSystemGetNameFunction;
+  bool isMirrorSystemGetNameFunction(Element element) {
+    if (_mirrorSystemGetNameFunction == null) {
+      if (!element.isFunction || mirrorsLibrary == null) return false;
+      ClassElement cls = mirrorSystemClass;
+      if (element.enclosingClass != cls) return false;
+      if (cls != null) {
+        cls.ensureResolved(resolution);
+        _mirrorSystemGetNameFunction = cls.lookupLocalMember('getName');
+      }
+    }
+    return element == _mirrorSystemGetNameFunction;
+  }
+
+  ClassElement _mirrorsUsedClass;
+  ClassElement get mirrorsUsedClass =>
+      _mirrorsUsedClass ??= _findRequired(mirrorsLibrary, 'MirrorsUsed');
+
+  bool isMirrorsUsedConstructor(ConstructorElement element) =>
+      mirrorsLibrary != null && mirrorsUsedClass == element.enclosingClass;
+
+  ConstructorElement _mirrorsUsedConstructor;
+  @override
+  ConstructorElement get mirrorsUsedConstructor {
+    if (_mirrorsUsedConstructor == null) {
+      ClassElement cls = mirrorsUsedClass;
+      if (cls != null) {
+        cls.ensureResolved(resolution);
+        _mirrorsUsedConstructor = cls.constructors.head;
+      }
+    }
+    return _mirrorsUsedConstructor;
+  }
+
+  // From dart:typed_data
+
+  ClassElement _typedDataClass;
+  ClassElement get typedDataClass =>
+      _typedDataClass ??= _findRequired(typedDataLibrary, 'NativeTypedData');
+
+  // From dart:_js_helper
+  // TODO(sigmund,johnniwinther): refactor needed: either these move to a
+  // backend-specific collection of helpers, or the helper code moves to a
+  // backend agnostic library (see commend above on [jsHelperLibrary].
+
+  ClassElement _patchAnnotationClass;
+  ClassElement get patchAnnotationClass =>
+      _patchAnnotationClass ??= _findRequired(jsHelperLibrary, '_Patch');
+
+  ClassElement _nativeAnnotationClass;
+  ClassElement get nativeAnnotationClass =>
+      _nativeAnnotationClass ??= _findRequired(jsHelperLibrary, 'Native');
 
   @override
   InterfaceType get objectType {
@@ -1430,6 +1473,39 @@
     }
     return type.createInstantiation([elementType]);
   }
+
+  void onLibraryCreated(LibraryElement library) {
+    Uri uri = library.canonicalUri;
+    if (uri == Uris.dart_core) {
+      coreLibrary = library;
+    } else if (uri == Uris.dart_async) {
+      asyncLibrary = library;
+    } else if (uri == Uris.dart__native_typed_data) {
+      typedDataLibrary = library;
+    } else if (uri == Uris.dart_mirrors) {
+      mirrorsLibrary = library;
+    } else if (uri == js_backend.BackendHelpers.DART_JS_HELPER) {
+      jsHelperLibrary = library;
+    }
+  }
+
+  Element _findRequired(LibraryElement library, String name) {
+    // If the script of the library is synthesized, the library does not exist
+    // and we do not try to load the helpers.
+    //
+    // This could for example happen if dart:async is disabled, then loading it
+    // should not try to find the given element.
+    if (library == null || library.isSynthesized) return null;
+
+    var element = library.find(name);
+    if (element == null) {
+      reporter.internalError(
+          library,
+          "The library '${library.canonicalUri}' does not contain required "
+          "element: '$name'.");
+    }
+    return element;
+  }
 }
 
 class CompilerDiagnosticReporter extends DiagnosticReporter {
@@ -1876,6 +1952,9 @@
   CoreTypes get coreTypes => compiler.coreTypes;
 
   @override
+  CommonElements get commonElements => compiler.commonElements;
+
+  @override
   Types get types => compiler.types;
 
   @override
@@ -1901,27 +1980,10 @@
       compiler.mirrorUsageAnalyzerTask;
 
   @override
-  LibraryElement get coreLibrary => compiler.coreLibrary;
+  LibraryElement get coreLibrary => compiler._coreTypes.coreLibrary;
 
   @override
-  FunctionElement get identicalFunction => compiler.identicalFunction;
-
-  @override
-  ClassElement get mirrorSystemClass => compiler.mirrorSystemClass;
-
-  @override
-  FunctionElement get mirrorSystemGetNameFunction =>
-      compiler.mirrorSystemGetNameFunction;
-
-  @override
-  ConstructorElement get mirrorsUsedConstructor =>
-      compiler.mirrorsUsedConstructor;
-
-  @override
-  ConstructorElement get symbolConstructor => compiler.symbolConstructor;
-
-  @override
-  ConstantValue proxyConstant;
+  bool get wasProxyConstantComputedTestingOnly => _proxyConstant != null;
 
   @override
   void registerClass(ClassElement cls) {
@@ -1962,10 +2024,6 @@
   }
 
   @override
-  void onClassResolved(ClassElement element) =>
-      compiler.onClassResolved(element);
-
-  @override
   void registerCompileTimeError(Element element, DiagnosticMessage message) =>
       compiler.registerCompileTimeError(element, message);
 
@@ -2114,16 +2172,18 @@
     _resolutionImpactCache.remove(element);
   }
 
+  ConstantValue _proxyConstant;
+
   @override
   bool isProxyConstant(ConstantValue value) {
     FieldElement field = coreLibrary.find('proxy');
     if (field == null) return false;
     if (!hasBeenResolved(field)) return false;
-    if (proxyConstant == null) {
-      proxyConstant = constants
+    if (_proxyConstant == null) {
+      _proxyConstant = constants
           .getConstantValue(resolver.constantCompiler.compileConstant(field));
     }
-    return proxyConstant == value;
+    return _proxyConstant == value;
   }
 }
 
@@ -2166,8 +2226,8 @@
   _NoScriptLoader(this.compiler);
 
   Future<Script> readScript(Uri uri, [Spannable spannable]) {
-    compiler.reporter.internalError(spannable,
-        "Script loading of '$uri' is not enabled.");
+    compiler.reporter
+        .internalError(spannable, "Script loading of '$uri' is not enabled.");
   }
 }
 
diff --git a/pkg/compiler/lib/src/core_types.dart b/pkg/compiler/lib/src/core_types.dart
index ff30de2..ea201f9 100644
--- a/pkg/compiler/lib/src/core_types.dart
+++ b/pkg/compiler/lib/src/core_types.dart
@@ -2,10 +2,17 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// TODO(sigmund): rename and move to common/elements.dart
 library dart2js.type_system;
 
 import 'dart_types.dart';
-import 'elements/elements.dart' show ClassElement;
+import 'elements/elements.dart'
+    show
+        ClassElement,
+        ConstructorElement,
+        FunctionElement,
+        LibraryElement,
+        Element;
 
 /// The core classes in Dart.
 abstract class CoreClasses {
@@ -61,6 +68,70 @@
   ClassElement get streamClass;
 }
 
+/// TODO(sigmund): delete CoreClasses and merge it here.
+abstract class CommonElements extends CoreClasses {
+  /// The dart:core library.
+  LibraryElement get coreLibrary;
+
+  /// The dart:async library.
+  LibraryElement get asyncLibrary;
+
+  /// The dart:mirrors library. Null if the program doesn't access dart:mirrors.
+  LibraryElement get mirrorsLibrary;
+
+  /// The dart:typed_data library.
+  LibraryElement get typedDataLibrary;
+
+  /// The `NativeTypedData` class from dart:typed_data.
+  ClassElement get typedDataClass;
+
+  // TODO(johnniwinther): Move this to the JavaScriptBackend.
+  /// The class for patch annotation defined in dart:_js_helper.
+  ClassElement get patchAnnotationClass;
+
+  // TODO(johnniwinther): Move this to the JavaScriptBackend.
+  ClassElement get nativeAnnotationClass;
+
+  /// Constructor of the `Symbol` class. This getter will ensure that `Symbol`
+  /// is resolved and lookup the constructor on demand.
+  ConstructorElement get symbolConstructor;
+
+  /// Whether [element] is the same as [symbolConstructor]. Used to check
+  /// for the constructor without computing it until it is likely to be seen.
+  bool isSymbolConstructor(Element e);
+
+  /// The `MirrorSystem` class in dart:mirrors.
+  ClassElement get mirrorSystemClass;
+
+  /// Whether [element] is `MirrorClass.getName`. Used to check for the use of
+  /// that static method without forcing the resolution of the `MirrorSystem`
+  /// class until it is necessary.
+  bool isMirrorSystemGetNameFunction(Element element);
+
+  /// The `MirrorsUsed` annotation in dart:mirrors.
+  ClassElement get mirrorsUsedClass;
+
+  /// Whether [element] is the constructor of the `MirrorsUsed` class. Used to
+  /// check for the constructor without forcing the resolution of the
+  /// `MirrorsUsed` class until it is necessary.
+  bool isMirrorsUsedConstructor(ConstructorElement element);
+
+  /// The `DeferredLibrary` annotation in dart:async that was used before the
+  /// deferred import syntax was introduced.
+  // TODO(sigmund): drop support for this old syntax?
+  ClassElement get deferredLibraryClass;
+
+  /// The function `identical` in dart:core.
+  FunctionElement get identicalFunction;
+
+  /// The method `Function.apply`.
+  FunctionElement get functionApplyMethod;
+
+  /// Whether [element] is the same as [functionApplyMethod]. This will not
+  /// resolve the apply method if it hasn't been seen yet during compilation.
+  bool isFunctionApplyMethod(Element element);
+}
+
 /// The core types in Dart.
 abstract class CoreTypes {
   /// The `Object` type defined in 'dart:core'.
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index f839dd9..0c3a507 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -324,6 +324,7 @@
     new OptionHandler(
         '--output-type=dart|--output-type=dart-multi|--output-type=js',
         setOutputType),
+    new OptionHandler(Flags.useKernel, passThrough),
     new OptionHandler(Flags.noFrequencyBasedMinification, passThrough),
     new OptionHandler(Flags.verbose, setVerbose),
     new OptionHandler(Flags.version, (_) => wantVersion = true),
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 723bd9f..114bdca 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -89,7 +89,8 @@
   String get name => 'Deferred Loading';
 
   /// DeferredLibrary from dart:async
-  ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;
+  ClassElement get deferredLibraryClass =>
+      compiler.commonElements.deferredLibraryClass;
 
   /// A synthetic import representing the loading of the main program.
   final _DeferredImport _fakeMainImport = const _DeferredImport();
@@ -463,7 +464,7 @@
     }
 
     traverseLibrary(root);
-    result.add(compiler.coreLibrary);
+    result.add(compiler.commonElements.coreLibrary);
     return result;
   }
 
@@ -668,7 +669,7 @@
 
               // Now check to see if we have to add more elements due to
               // mirrors.
-              if (compiler.mirrorsLibrary != null) {
+              if (compiler.commonElements.mirrorsLibrary != null) {
                 _addMirrorElements();
               }
 
@@ -1021,7 +1022,7 @@
         ConstantValue value =
             compiler.constants.getConstantValue(metadata.constant);
         Element element = value.getType(compiler.coreTypes).element;
-        if (element == compiler.deferredLibraryClass) {
+        if (element == compiler.commonElements.deferredLibraryClass) {
           ConstructedConstantValue constant = value;
           StringConstantValue s = constant.fields.values.single;
           result = s.primitiveValue.slowToString();
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 93f1312..d5314b0 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -116,7 +116,7 @@
 
   FieldInfo visitFieldElement(FieldElement element, _) {
     TypeMask inferredType =
-        compiler.typesTask.getGuaranteedTypeOfElement(element);
+        compiler.globalInference.getGuaranteedTypeOfElement(element);
     // If a field has an empty inferred type it is never used.
     if (inferredType == null || inferredType.isEmpty) return null;
 
@@ -257,7 +257,7 @@
       signature.forEachParameter((parameter) {
         parameters.add(new ParameterInfo(
             parameter.name,
-            '${compiler.typesTask.getGuaranteedTypeOfElement(parameter)}',
+            '${compiler.globalInference.getGuaranteedTypeOfElement(parameter)}',
             '${parameter.node.type}'));
       });
     }
@@ -270,7 +270,7 @@
       returnType = '${element.type.returnType}';
     }
     String inferredReturnType =
-        '${compiler.typesTask.getGuaranteedReturnTypeOfElement(element)}';
+        '${compiler.globalInference.getGuaranteedReturnTypeOfElement(element)}';
     String sideEffects = '${compiler.world.getSideEffectsOfElement(element)}';
 
     int inlinedCount = compiler.dumpInfoTask.inlineCount[element];
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index e80ea6b..1df89f8 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -675,17 +675,17 @@
   }
 
   static bool isNumberOrStringSupertype(Element element, Compiler compiler) {
-    LibraryElement coreLibrary = compiler.coreLibrary;
+    LibraryElement coreLibrary = compiler.commonElements.coreLibrary;
     return (element == coreLibrary.find('Comparable'));
   }
 
   static bool isStringOnlySupertype(Element element, Compiler compiler) {
-    LibraryElement coreLibrary = compiler.coreLibrary;
+    LibraryElement coreLibrary = compiler.commonElements.coreLibrary;
     return element == coreLibrary.find('Pattern');
   }
 
   static bool isListSupertype(Element element, Compiler compiler) {
-    LibraryElement coreLibrary = compiler.coreLibrary;
+    LibraryElement coreLibrary = compiler.commonElements.coreLibrary;
     return element == coreLibrary.find('Iterable');
   }
 
@@ -794,14 +794,15 @@
 
   static bool isConstructorOfTypedArraySubclass(
       Element element, Compiler compiler) {
-    if (compiler.typedDataLibrary == null) return false;
+    if (compiler.commonElements.typedDataLibrary == null) return false;
     if (!element.isConstructor) return false;
     ConstructorElement constructor = element.implementation;
     constructor = constructor.effectiveTarget;
     ClassElement cls = constructor.enclosingClass;
-    return cls.library == compiler.typedDataLibrary &&
+    return cls.library == compiler.commonElements.typedDataLibrary &&
         compiler.backend.isNative(cls) &&
-        compiler.world.isSubtypeOf(cls, compiler.typedDataClass) &&
+        compiler.world
+            .isSubtypeOf(cls, compiler.commonElements.typedDataClass) &&
         compiler.world.isSubtypeOf(cls, compiler.coreClasses.listClass) &&
         constructor.name == '';
   }
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 01b258e..7361576 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -776,7 +776,7 @@
       compiler.enabledRuntimeType = true;
       // TODO(ahe): Record precise dependency here.
       compiler.backend.registerRuntimeType(this, compiler.globalDependencies);
-    } else if (element == compiler.functionApplyMethod) {
+    } else if (compiler.commonElements.isFunctionApplyMethod(element)) {
       compiler.enabledFunctionApply = true;
     }
 
diff --git a/pkg/compiler/lib/src/inferrer/closure_tracer.dart b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
index 80b7e3d..bb406ca 100644
--- a/pkg/compiler/lib/src/inferrer/closure_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
@@ -94,7 +94,7 @@
       inferrer.types.getInferredTypeOf(element) == currentUser;
 
   bool _checkIfFunctionApply(element) =>
-      compiler.functionApplyMethod == element;
+      compiler.commonElements.isFunctionApplyMethod(element);
 
   @override
   visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index d610c54..2308e41 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -18,8 +18,9 @@
 import '../tree/dartstring.dart' show DartString;
 import '../tree/tree.dart' as ast show Node, LiteralBool, TryStatement;
 import '../types/constants.dart' show computeTypeMask;
-import '../types/types.dart'
-    show ContainerTypeMask, MapTypeMask, TypeMask, TypesInferrer;
+import '../types/masks.dart'
+    show CommonMasks, ContainerTypeMask, MapTypeMask, TypeMask;
+import '../types/types.dart' show TypesInferrer;
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart' show Selector;
 import '../universe/side_effects.dart' show SideEffects;
@@ -37,6 +38,7 @@
 class TypeInformationSystem extends TypeSystem<TypeInformation> {
   final Compiler compiler;
   final ClassWorld classWorld;
+  final CommonMasks commonMasks;
 
   /// [ElementTypeInformation]s for elements.
   final Map<Element, TypeInformation> typeInformations =
@@ -70,7 +72,7 @@
         allocatedTypes
       ].expand((x) => x);
 
-  TypeInformationSystem(Compiler compiler)
+  TypeInformationSystem(Compiler compiler, this.commonMasks)
       : this.compiler = compiler,
         this.classWorld = compiler.world {
     nonNullEmptyType = getConcreteTypeFor(const TypeMask.nonNullEmpty());
@@ -92,148 +94,142 @@
   TypeInformation nullTypeCache;
   TypeInformation get nullType {
     if (nullTypeCache != null) return nullTypeCache;
-    return nullTypeCache = getConcreteTypeFor(compiler.typesTask.nullType);
+    return nullTypeCache = getConcreteTypeFor(commonMasks.nullType);
   }
 
   TypeInformation intTypeCache;
   TypeInformation get intType {
     if (intTypeCache != null) return intTypeCache;
-    return intTypeCache = getConcreteTypeFor(compiler.typesTask.intType);
+    return intTypeCache = getConcreteTypeFor(commonMasks.intType);
   }
 
   TypeInformation uint32TypeCache;
   TypeInformation get uint32Type {
     if (uint32TypeCache != null) return uint32TypeCache;
-    return uint32TypeCache = getConcreteTypeFor(compiler.typesTask.uint32Type);
+    return uint32TypeCache = getConcreteTypeFor(commonMasks.uint32Type);
   }
 
   TypeInformation uint31TypeCache;
   TypeInformation get uint31Type {
     if (uint31TypeCache != null) return uint31TypeCache;
-    return uint31TypeCache = getConcreteTypeFor(compiler.typesTask.uint31Type);
+    return uint31TypeCache = getConcreteTypeFor(commonMasks.uint31Type);
   }
 
   TypeInformation positiveIntTypeCache;
   TypeInformation get positiveIntType {
     if (positiveIntTypeCache != null) return positiveIntTypeCache;
     return positiveIntTypeCache =
-        getConcreteTypeFor(compiler.typesTask.positiveIntType);
+        getConcreteTypeFor(commonMasks.positiveIntType);
   }
 
   TypeInformation doubleTypeCache;
   TypeInformation get doubleType {
     if (doubleTypeCache != null) return doubleTypeCache;
-    return doubleTypeCache = getConcreteTypeFor(compiler.typesTask.doubleType);
+    return doubleTypeCache = getConcreteTypeFor(commonMasks.doubleType);
   }
 
   TypeInformation numTypeCache;
   TypeInformation get numType {
     if (numTypeCache != null) return numTypeCache;
-    return numTypeCache = getConcreteTypeFor(compiler.typesTask.numType);
+    return numTypeCache = getConcreteTypeFor(commonMasks.numType);
   }
 
   TypeInformation boolTypeCache;
   TypeInformation get boolType {
     if (boolTypeCache != null) return boolTypeCache;
-    return boolTypeCache = getConcreteTypeFor(compiler.typesTask.boolType);
+    return boolTypeCache = getConcreteTypeFor(commonMasks.boolType);
   }
 
   TypeInformation functionTypeCache;
   TypeInformation get functionType {
     if (functionTypeCache != null) return functionTypeCache;
-    return functionTypeCache =
-        getConcreteTypeFor(compiler.typesTask.functionType);
+    return functionTypeCache = getConcreteTypeFor(commonMasks.functionType);
   }
 
   TypeInformation listTypeCache;
   TypeInformation get listType {
     if (listTypeCache != null) return listTypeCache;
-    return listTypeCache = getConcreteTypeFor(compiler.typesTask.listType);
+    return listTypeCache = getConcreteTypeFor(commonMasks.listType);
   }
 
   TypeInformation constListTypeCache;
   TypeInformation get constListType {
     if (constListTypeCache != null) return constListTypeCache;
-    return constListTypeCache =
-        getConcreteTypeFor(compiler.typesTask.constListType);
+    return constListTypeCache = getConcreteTypeFor(commonMasks.constListType);
   }
 
   TypeInformation fixedListTypeCache;
   TypeInformation get fixedListType {
     if (fixedListTypeCache != null) return fixedListTypeCache;
-    return fixedListTypeCache =
-        getConcreteTypeFor(compiler.typesTask.fixedListType);
+    return fixedListTypeCache = getConcreteTypeFor(commonMasks.fixedListType);
   }
 
   TypeInformation growableListTypeCache;
   TypeInformation get growableListType {
     if (growableListTypeCache != null) return growableListTypeCache;
     return growableListTypeCache =
-        getConcreteTypeFor(compiler.typesTask.growableListType);
+        getConcreteTypeFor(commonMasks.growableListType);
   }
 
   TypeInformation mapTypeCache;
   TypeInformation get mapType {
     if (mapTypeCache != null) return mapTypeCache;
-    return mapTypeCache = getConcreteTypeFor(compiler.typesTask.mapType);
+    return mapTypeCache = getConcreteTypeFor(commonMasks.mapType);
   }
 
   TypeInformation constMapTypeCache;
   TypeInformation get constMapType {
     if (constMapTypeCache != null) return constMapTypeCache;
-    return constMapTypeCache =
-        getConcreteTypeFor(compiler.typesTask.constMapType);
+    return constMapTypeCache = getConcreteTypeFor(commonMasks.constMapType);
   }
 
   TypeInformation stringTypeCache;
   TypeInformation get stringType {
     if (stringTypeCache != null) return stringTypeCache;
-    return stringTypeCache = getConcreteTypeFor(compiler.typesTask.stringType);
+    return stringTypeCache = getConcreteTypeFor(commonMasks.stringType);
   }
 
   TypeInformation typeTypeCache;
   TypeInformation get typeType {
     if (typeTypeCache != null) return typeTypeCache;
-    return typeTypeCache = getConcreteTypeFor(compiler.typesTask.typeType);
+    return typeTypeCache = getConcreteTypeFor(commonMasks.typeType);
   }
 
   TypeInformation dynamicTypeCache;
   TypeInformation get dynamicType {
     if (dynamicTypeCache != null) return dynamicTypeCache;
-    return dynamicTypeCache =
-        getConcreteTypeFor(compiler.typesTask.dynamicType);
+    return dynamicTypeCache = getConcreteTypeFor(commonMasks.dynamicType);
   }
 
   TypeInformation asyncFutureTypeCache;
   TypeInformation get asyncFutureType {
     if (asyncFutureTypeCache != null) return asyncFutureTypeCache;
     return asyncFutureTypeCache =
-        getConcreteTypeFor(compiler.typesTask.asyncFutureType);
+        getConcreteTypeFor(commonMasks.asyncFutureType);
   }
 
   TypeInformation syncStarIterableTypeCache;
   TypeInformation get syncStarIterableType {
     if (syncStarIterableTypeCache != null) return syncStarIterableTypeCache;
     return syncStarIterableTypeCache =
-        getConcreteTypeFor(compiler.typesTask.syncStarIterableType);
+        getConcreteTypeFor(commonMasks.syncStarIterableType);
   }
 
   TypeInformation asyncStarStreamTypeCache;
   TypeInformation get asyncStarStreamType {
     if (asyncStarStreamTypeCache != null) return asyncStarStreamTypeCache;
     return asyncStarStreamTypeCache =
-        getConcreteTypeFor(compiler.typesTask.asyncStarStreamType);
+        getConcreteTypeFor(commonMasks.asyncStarStreamType);
   }
 
   TypeInformation nonNullEmptyType;
 
   TypeInformation stringLiteralType(DartString value) {
-    return new StringLiteralTypeInformation(
-        value, compiler.typesTask.stringType);
+    return new StringLiteralTypeInformation(value, commonMasks.stringType);
   }
 
   TypeInformation boolLiteralType(ast.LiteralBool value) {
-    return new BoolLiteralTypeInformation(value, compiler.typesTask.boolType);
+    return new BoolLiteralTypeInformation(value, commonMasks.boolType);
   }
 
   TypeInformation computeLUB(
@@ -367,13 +363,13 @@
   TypeInformation allocateList(
       TypeInformation type, ast.Node node, Element enclosing,
       [TypeInformation elementType, int length]) {
-    bool isTypedArray = compiler.typedDataClass != null &&
-        classWorld.isInstantiated(compiler.typedDataClass) &&
-        type.type.satisfies(compiler.typedDataClass, classWorld);
-    bool isConst = (type.type == compiler.typesTask.constListType);
-    bool isFixed = (type.type == compiler.typesTask.fixedListType) ||
-        isConst ||
-        isTypedArray;
+    ClassElement typedDataClass = compiler.commonElements.typedDataClass;
+    bool isTypedArray = typedDataClass != null &&
+        classWorld.isInstantiated(typedDataClass) &&
+        type.type.satisfies(typedDataClass, classWorld);
+    bool isConst = (type.type == commonMasks.constListType);
+    bool isFixed =
+        (type.type == commonMasks.fixedListType) || isConst || isTypedArray;
     bool isElementInferred = isConst || isTypedArray;
 
     int inferredLength = isFixed ? length : null;
@@ -401,7 +397,7 @@
       ConcreteTypeInformation type, ast.Node node, Element element,
       [List<TypeInformation> keyTypes, List<TypeInformation> valueTypes]) {
     assert(keyTypes.length == valueTypes.length);
-    bool isFixed = (type.type == compiler.typesTask.constMapType);
+    bool isFixed = (type.type == commonMasks.constMapType);
 
     TypeMask keyType, valueType;
     if (isFixed) {
@@ -501,7 +497,7 @@
   }
 
   TypeMask joinTypeMasks(Iterable<TypeMask> masks) {
-    var dynamicType = compiler.typesTask.dynamicType;
+    var dynamicType = commonMasks.dynamicType;
     // Optimization: we are iterating over masks twice, but because `masks` is a
     // mapped iterable, we save the intermediate results to avoid computing them
     // again.
@@ -571,6 +567,7 @@
       <CallSiteTypeInformation>[];
   final WorkQueue workQueue = new WorkQueue();
   final Element mainElement;
+  final CommonMasks commonMasks;
   final Set<Element> analyzedElements = new Set<Element>();
 
   /// The maximum number of times we allow a node in the graph to
@@ -581,8 +578,10 @@
   int overallRefineCount = 0;
   int addedInGraph = 0;
 
-  TypeGraphInferrerEngine(Compiler compiler, this.mainElement)
-      : super(compiler, new TypeInformationSystem(compiler));
+  TypeGraphInferrerEngine(
+      Compiler compiler, CommonMasks commonMasks, this.mainElement)
+      : commonMasks = commonMasks,
+        super(compiler, new TypeInformationSystem(compiler, commonMasks));
 
   JavaScriptBackend get backend => compiler.backend;
   Annotations get annotations => backend.annotations;
@@ -624,7 +623,7 @@
 
     info.bailedOut = false;
     info.elementType.inferred = true;
-    TypeMask fixedListType = compiler.typesTask.fixedListType;
+    TypeMask fixedListType = commonMasks.fixedListType;
     if (info.originalType.forwardTo == fixedListType) {
       info.checksGrowable = tracer.callsGrowableMethod;
     }
@@ -1356,32 +1355,34 @@
 class TypeGraphInferrer implements TypesInferrer {
   TypeGraphInferrerEngine inferrer;
   final Compiler compiler;
-  TypeGraphInferrer(Compiler this.compiler);
+  final CommonMasks commonMasks;
+  TypeGraphInferrer(this.compiler, this.commonMasks);
 
   String get name => 'Graph inferrer';
+  TypeMask get _dynamicType => commonMasks.dynamicType;
 
   void analyzeMain(Element main) {
-    inferrer = new TypeGraphInferrerEngine(compiler, main);
+    inferrer = new TypeGraphInferrerEngine(compiler, commonMasks, main);
     inferrer.runOverAllElements();
   }
 
   TypeMask getReturnTypeOfElement(Element element) {
-    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    if (compiler.disableTypeInference) return _dynamicType;
     // Currently, closure calls return dynamic.
-    if (element is! FunctionElement) return compiler.typesTask.dynamicType;
+    if (element is! FunctionElement) return _dynamicType;
     return inferrer.types.getInferredTypeOf(element).type;
   }
 
   TypeMask getTypeOfElement(Element element) {
-    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    if (compiler.disableTypeInference) return _dynamicType;
     // The inferrer stores the return type for a function, so we have to
     // be careful to not return it here.
-    if (element is FunctionElement) return compiler.typesTask.functionType;
+    if (element is FunctionElement) return commonMasks.functionType;
     return inferrer.types.getInferredTypeOf(element).type;
   }
 
   TypeMask getTypeOfNode(Element owner, ast.Node node) {
-    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    if (compiler.disableTypeInference) return _dynamicType;
     return inferrer.types.allocatedLists[node].type;
   }
 
@@ -1392,22 +1393,22 @@
   }
 
   TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
-    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    if (compiler.disableTypeInference) return _dynamicType;
     // Bailout for closure calls. We're not tracking types of
     // closures.
-    if (selector.isClosureCall) return compiler.typesTask.dynamicType;
+    if (selector.isClosureCall) return _dynamicType;
     if (selector.isSetter || selector.isIndexSet) {
-      return compiler.typesTask.dynamicType;
+      return _dynamicType;
     }
     if (inferrer.returnsListElementType(selector, mask)) {
       ContainerTypeMask containerTypeMask = mask;
       TypeMask elementType = containerTypeMask.elementType;
-      return elementType == null ? compiler.typesTask.dynamicType : elementType;
+      return elementType == null ? _dynamicType : elementType;
     }
     if (inferrer.returnsMapValueType(selector, mask)) {
       MapTypeMask mapTypeMask = mask;
       TypeMask valueType = mapTypeMask.valueType;
-      return valueType == null ? compiler.typesTask.dynamicType : valueType;
+      return valueType == null ? _dynamicType : valueType;
     }
 
     TypeMask result = const TypeMask.nonNullEmpty();
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 0c3fb31..feaed3e 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -14,8 +14,9 @@
 import '../elements/elements.dart';
 import '../tree/dartstring.dart' show DartString;
 import '../tree/tree.dart' as ast show Node, LiteralBool, Send;
-import '../types/types.dart'
+import '../types/masks.dart'
     show
+        CommonMasks,
         ContainerTypeMask,
         DictionaryTypeMask,
         MapTypeMask,
@@ -491,18 +492,18 @@
       }
     }
 
-    Compiler compiler = inferrer.compiler;
+    CommonMasks commonMasks = inferrer.commonMasks;
     if (element.isConstructor) {
       ConstructorElement constructor = element;
       if (constructor.isIntFromEnvironmentConstructor) {
         giveUp(inferrer);
-        return compiler.typesTask.intType.nullable();
+        return commonMasks.intType.nullable();
       } else if (constructor.isBoolFromEnvironmentConstructor) {
         giveUp(inferrer);
-        return compiler.typesTask.boolType.nullable();
+        return commonMasks.boolType.nullable();
       } else if (constructor.isStringFromEnvironmentConstructor) {
         giveUp(inferrer);
-        return compiler.typesTask.stringType.nullable();
+        return commonMasks.stringType.nullable();
       }
     }
     return null;
@@ -836,7 +837,7 @@
     TypeMask receiverType = receiver.type;
 
     if (mask != receiverType) {
-      return receiverType == inferrer.compiler.typesTask.dynamicType
+      return receiverType == inferrer.commonMasks.dynamicType
           ? null
           : receiverType;
     } else {
@@ -1725,12 +1726,12 @@
   if (annotation.isObject) return type;
   TypeMask otherType;
   if (annotation.isTypedef || annotation.isFunctionType) {
-    otherType = compiler.typesTask.functionType;
+    otherType = compiler.commonMasks.functionType;
   } else if (annotation.isTypeVariable) {
     // TODO(ngeoffray): Narrow to bound.
     return type;
   } else if (annotation.isVoid) {
-    otherType = compiler.typesTask.nullType;
+    otherType = compiler.commonMasks.nullType;
   } else {
     assert(annotation.isInterfaceType);
     otherType = new TypeMask.nonNullSubtype(annotation.element, compiler.world);
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 8433ec4..f11ed3780 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -15,11 +15,7 @@
 import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem;
 import '../common/names.dart' show Identifiers, Selectors, Uris;
 import '../common/registry.dart' show EagerRegistry, Registry;
-import '../common/resolution.dart'
-    show
-        Frontend,
-        Resolution,
-        ResolutionImpact;
+import '../common/resolution.dart' show Frontend, Resolution, ResolutionImpact;
 import '../common/tasks.dart' show CompilerTask;
 import '../common/work.dart' show ItemCompilationContext;
 import '../compiler.dart' show Compiler;
@@ -43,7 +39,7 @@
 import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
 import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
 import '../native/native.dart' as native;
-import '../ssa/builder.dart' show SsaFunctionCompiler;
+import '../ssa/ssa.dart' show SsaFunctionCompiler;
 import '../ssa/nodes.dart' show HInstruction;
 import '../tree/tree.dart';
 import '../types/types.dart';
@@ -337,17 +333,18 @@
       TRACE_METHOD == 'post' || TRACE_METHOD == 'console';
   Element traceHelper;
 
-  TypeMask get stringType => compiler.typesTask.stringType;
-  TypeMask get doubleType => compiler.typesTask.doubleType;
-  TypeMask get intType => compiler.typesTask.intType;
-  TypeMask get uint32Type => compiler.typesTask.uint32Type;
-  TypeMask get uint31Type => compiler.typesTask.uint31Type;
-  TypeMask get positiveIntType => compiler.typesTask.positiveIntType;
-  TypeMask get numType => compiler.typesTask.numType;
-  TypeMask get boolType => compiler.typesTask.boolType;
-  TypeMask get dynamicType => compiler.typesTask.dynamicType;
-  TypeMask get nullType => compiler.typesTask.nullType;
+  TypeMask get stringType => compiler.commonMasks.stringType;
+  TypeMask get doubleType => compiler.commonMasks.doubleType;
+  TypeMask get intType => compiler.commonMasks.intType;
+  TypeMask get uint32Type => compiler.commonMasks.uint32Type;
+  TypeMask get uint31Type => compiler.commonMasks.uint31Type;
+  TypeMask get positiveIntType => compiler.commonMasks.positiveIntType;
+  TypeMask get numType => compiler.commonMasks.numType;
+  TypeMask get boolType => compiler.commonMasks.boolType;
+  TypeMask get dynamicType => compiler.commonMasks.dynamicType;
+  TypeMask get nullType => compiler.commonMasks.nullType;
   TypeMask get emptyType => const TypeMask.nonNullEmpty();
+  TypeMask get nonNullType => compiler.commonMasks.nonNullType;
 
   TypeMask _indexablePrimitiveTypeCache;
   TypeMask get indexablePrimitiveType {
@@ -403,13 +400,6 @@
     return _fixedArrayTypeCache;
   }
 
-  TypeMask _nonNullTypeCache;
-  TypeMask get nonNullType {
-    if (_nonNullTypeCache == null) {
-      _nonNullTypeCache = compiler.typesTask.dynamicType.nonNullable();
-    }
-    return _nonNullTypeCache;
-  }
 
   /// Maps special classes to their implementation (JSXxx) class.
   Map<ClassElement, ClassElement> implementationClasses;
@@ -522,6 +512,9 @@
   /// True if the html library has been loaded.
   bool htmlLibraryIsLoaded = false;
 
+  /// True when we enqueue the loadLibrary code.
+  bool isLoadLibraryFunctionResolved = false;
+
   /// List of constants from metadata.  If metadata must be preserved,
   /// these constants must be registered.
   final List<Dependency> metadataConstants = <Dependency>[];
@@ -598,7 +591,8 @@
   JavaScriptBackend(Compiler compiler,
       {bool generateSourceMap: true,
       bool useStartupEmitter: false,
-      bool useNewSourceInfo: false})
+      bool useNewSourceInfo: false,
+      bool useKernel: false})
       : namer = determineNamer(compiler),
         oneShotInterceptors = new Map<jsAst.Name, Selector>(),
         interceptedElements = new Map<String, Set<Element>>(),
@@ -626,7 +620,8 @@
     constantCompilerTask = new JavaScriptConstantTask(compiler);
     impactTransformer = new JavaScriptImpactTransformer(this);
     patchResolverTask = new PatchResolverTask(compiler);
-    functionCompiler = new SsaFunctionCompiler(this, sourceInformationStrategy);
+    functionCompiler =
+        new SsaFunctionCompiler(this, sourceInformationStrategy, useKernel);
     serialization = new JavaScriptBackendSerialization(this);
   }
 
@@ -701,7 +696,7 @@
   bool _isValidBackendUse(Element element) {
     assert(invariant(element, element.isDeclaration, message: ""));
     if (element == helpers.streamIteratorConstructor ||
-        element == helpers.compiler.symbolConstructor ||
+        compiler.commonElements.isSymbolConstructor(element) ||
         helpers.isSymbolValidatedConstructor(element) ||
         element == helpers.syncCompleterConstructor ||
         element == coreClasses.symbolClass ||
@@ -1685,7 +1680,8 @@
         if (library.isInternalLibrary) continue;
         for (ImportElement import in library.imports) {
           LibraryElement importedLibrary = import.importedLibrary;
-          if (importedLibrary != compiler.mirrorsLibrary) continue;
+          if (importedLibrary != compiler.commonElements.mirrorsLibrary)
+            continue;
           MessageKind kind =
               compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
                   ? MessageKind.MIRROR_IMPORT
@@ -1917,10 +1913,10 @@
       needToInitializeIsolateAffinityTag = true;
     } else if (element.isDeferredLoaderGetter) {
       // TODO(sigurdm): Create a function registerLoadLibraryAccess.
-      if (compiler.loadLibraryFunction == null) {
-        compiler.loadLibraryFunction = helpers.loadLibraryWrapper;
+      if (!isLoadLibraryFunctionResolved) {
+        isLoadLibraryFunctionResolved = true;
         enqueueInResolution(
-            compiler.loadLibraryFunction, compiler.globalDependencies);
+            helpers.loadLibraryWrapper, compiler.globalDependencies);
       }
     } else if (element == helpers.requiresPreambleMarker) {
       requiresPreamble = true;
@@ -2132,7 +2128,7 @@
    */
   computeMembersNeededForReflection() {
     if (_membersNeededForReflection != null) return;
-    if (compiler.mirrorsLibrary == null) {
+    if (compiler.commonElements.mirrorsLibrary == null) {
       _membersNeededForReflection = const ImmutableEmptySet<Element>();
       return;
     }
@@ -2290,9 +2286,10 @@
     // Just checking for [:TypedData:] is not sufficient, as it is an
     // abstract class any user-defined class can implement. So we also
     // check for the interface [JavaScriptIndexingBehavior].
-    return compiler.typedDataClass != null &&
-        compiler.world.isInstantiated(compiler.typedDataClass) &&
-        mask.satisfies(compiler.typedDataClass, compiler.world) &&
+    ClassElement typedDataClass = compiler.commonElements.typedDataClass;
+    return typedDataClass != null &&
+        compiler.world.isInstantiated(typedDataClass) &&
+        mask.satisfies(typedDataClass, compiler.world) &&
         mask.satisfies(helpers.jsIndexingBehaviorInterface, compiler.world);
   }
 
@@ -2301,10 +2298,11 @@
         !type1.intersection(type2, compiler.world).isEmpty;
     // TODO(herhut): Maybe cache the TypeMask for typedDataClass and
     //               jsIndexingBehaviourInterface.
-    return compiler.typedDataClass != null &&
-        compiler.world.isInstantiated(compiler.typedDataClass) &&
-        intersects(mask,
-            new TypeMask.subtype(compiler.typedDataClass, compiler.world)) &&
+    ClassElement typedDataClass = compiler.commonElements.typedDataClass;
+    return typedDataClass != null &&
+        compiler.world.isInstantiated(typedDataClass) &&
+        intersects(
+            mask, new TypeMask.subtype(typedDataClass, compiler.world)) &&
         intersects(
             mask,
             new TypeMask.subtype(
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index 3852e2f..dc5bb12 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -347,8 +347,9 @@
 
     // [LinkedHashMap] is reexported from dart:collection and can therefore not
     // be loaded from dart:core in [onLibraryScanned].
-    mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap');
-    assert(invariant(compiler.coreLibrary, mapLiteralClass != null,
+    mapLiteralClass = compiler.commonElements.coreLibrary.find('LinkedHashMap');
+    assert(invariant(
+        compiler.commonElements.coreLibrary, mapLiteralClass != null,
         message: "Element 'LinkedHashMap' not found in 'dart:core'."));
 
     // TODO(kasperl): Some tests do not define the special JSArray
@@ -488,10 +489,6 @@
     return findHelper('getTypeArgumentByIndex');
   }
 
-  Element get copyTypeArguments {
-    return findHelper('copyTypeArguments');
-  }
-
   Element get computeSignature {
     return findHelper('computeSignature');
   }
@@ -625,7 +622,7 @@
   }
 
   Element get syncCompleterConstructor {
-    ClassElement classElement = find(compiler.asyncLibrary, "Completer");
+    ClassElement classElement = find(asyncLibrary, "Completer");
     classElement.ensureResolved(resolution);
     return classElement.lookupConstructor("sync");
   }
@@ -642,7 +639,7 @@
   }
 
   Element get streamIteratorConstructor {
-    ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator");
+    ClassElement classElement = find(asyncLibrary, "StreamIterator");
     classElement.ensureResolved(resolution);
     return classElement.lookupConstructor("");
   }
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 7606e4d..9a9a0d1 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -5,7 +5,7 @@
 library dart2js.js_helpers.impact;
 
 import '../compiler.dart' show Compiler;
-import '../core_types.dart' show CoreClasses;
+import '../core_types.dart' show CommonElements;
 import '../dart_types.dart' show InterfaceType;
 import '../elements/elements.dart' show ClassElement, Element;
 import 'backend_helpers.dart';
@@ -36,7 +36,7 @@
 
   BackendHelpers get helpers => backend.helpers;
 
-  CoreClasses get coreClasses => compiler.coreClasses;
+  CommonElements get commonElements => compiler.commonElements;
 
   BackendImpact _getRuntimeTypeArgument;
 
@@ -45,7 +45,6 @@
       _getRuntimeTypeArgument = new BackendImpact(staticUses: [
         helpers.getRuntimeTypeArgument,
         helpers.getTypeArgumentByIndex,
-        helpers.copyTypeArguments
       ]);
     }
     return _getRuntimeTypeArgument;
@@ -301,8 +300,8 @@
   BackendImpact get constSymbol {
     if (_constSymbol == null) {
       _constSymbol = new BackendImpact(
-          instantiatedClasses: [coreClasses.symbolClass],
-          staticUses: [compiler.symbolConstructor.declaration]);
+          instantiatedClasses: [commonElements.symbolClass],
+          staticUses: [commonElements.symbolConstructor.declaration]);
     }
     return _constSymbol;
   }
@@ -599,8 +598,8 @@
 
   BackendImpact get closure {
     if (_closure == null) {
-      _closure =
-          new BackendImpact(instantiatedClasses: [coreClasses.functionClass]);
+      _closure = new BackendImpact(
+          instantiatedClasses: [commonElements.functionClass]);
     }
     return _closure;
   }
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 391a35c..beae71b 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -320,20 +320,29 @@
     if (type is InterfaceType &&
         !type.treatAsRaw &&
         backend.classNeedsRti(type.element)) {
-      InterfaceType interface = type;
-      RuntimeTypesEncoder rtiEncoder = backend.rtiEncoder;
-      Iterable<jsAst.Expression> arguments = interface.typeArguments.map(
-          (DartType type) =>
-              rtiEncoder.getTypeRepresentationWithPlaceholders(type, (_) {}));
-      jsAst.Expression argumentList =
-          new jsAst.ArrayInitializer(arguments.toList());
       return new jsAst.Call(
           getHelperProperty(backend.helpers.setRuntimeTypeInfo),
-          [value, argumentList]);
+          [value, _reifiedTypeArguments(type)]);
     }
     return value;
   }
 
+  jsAst.Expression _reifiedTypeArguments(InterfaceType type) {
+    jsAst.Expression unexpected(TypeVariableType variable) {
+      reporter.internalError(
+          NO_LOCATION_SPANNABLE,
+          "Unexpected type variable '${variable.getStringAsDeclared(null)}'"
+          " in constant type '${type.getStringAsDeclared(null)}'");
+      return null;
+    }
+    List<jsAst.Expression> arguments = <jsAst.Expression>[];
+    RuntimeTypesEncoder rtiEncoder = backend.rtiEncoder;
+    for (DartType argument in type.typeArguments) {
+      arguments.add(rtiEncoder.getTypeRepresentation(argument, unexpected));
+    }
+    return new jsAst.ArrayInitializer(arguments);
+  }
+
   @override
   jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) {
     return constantReferenceGenerator(constant.referenced);
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 4464214..bef06b2 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -125,9 +125,7 @@
   }
 
   _subcategorizeOther(FunctionElement element) {
-    TypeMask returnType =
-        _compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
-    if (returnType == const TypeMask.nonNullEmpty()) {
+    if (_compiler.globalInference.throwsAlways(element)) {
       complexNoReturnImpls.add(element);
     } else {
       complexReturningImpls.add(element);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index a28f232..1d7470f 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -88,20 +88,11 @@
   jsAst.Template get templateForCreateFunctionType;
   jsAst.Name get getFunctionThatReturnsNullName;
 
+  /// Returns a [jsAst.Expression] representing the given [type]. Type variables
+  /// are replaced by the [jsAst.Expression] returned by [onVariable].
   jsAst.Expression getTypeRepresentation(
       DartType type, OnVariableCallback onVariable,
       [ShouldEncodeTypedefCallback shouldEncodeTypedef]);
-  /**
-   * Returns a [jsAst.Expression] representing the given [type]. Type
-   * variables are replaced by placeholders in the ast.
-   *
-   * [firstPlaceholderIndex] is the index to use for the first placeholder.
-   * This is useful if the returned [jsAst.Expression] is only part of a
-   * larger template. By default, indexing starts with 0.
-   */
-  jsAst.Expression getTypeRepresentationWithPlaceholders(
-      DartType type, OnVariableCallback onVariable,
-      {int firstPlaceholderIndex: 0});
 
   String getTypeRepresentationForTypeConstant(DartType type);
 }
@@ -619,20 +610,6 @@
   }
 
   @override
-  jsAst.Expression getTypeRepresentationWithPlaceholders(
-      DartType type, OnVariableCallback onVariable,
-      {int firstPlaceholderIndex: 0}) {
-    // Create a type representation.  For type variables call the original
-    // callback for side effects and return a template placeholder.
-    int positions = firstPlaceholderIndex;
-    jsAst.Expression representation = getTypeRepresentation(type, (variable) {
-      onVariable(variable);
-      return new jsAst.InterpolatedExpression(positions++);
-    });
-    return representation;
-  }
-
-  @override
   jsAst.Expression getSubstitutionRepresentation(
       List<DartType> types, OnVariableCallback onVariable) {
     List<jsAst.Expression> elements = types
@@ -648,7 +625,6 @@
       return new jsAst.VariableUse(v.name);
     }
 
-    ;
     jsAst.Expression encoding = getTypeRepresentation(type, onVariable);
     if (contextClass == null && !alwaysGenerateFunction) {
       return encoding;
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index 6301e77..d903f99 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -2112,7 +2112,7 @@
 
   jsAst.Comment buildGeneratedBy() {
     List<String> options = [];
-    if (compiler.mirrorsLibrary != null) options.add('mirrors');
+    if (compiler.commonElements.mirrorsLibrary != null) options.add('mirrors');
     if (compiler.options.useContentSecurityPolicy) options.add("CSP");
     return new jsAst.Comment(generatedBy(compiler, flavor: options.join(", ")));
   }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
index 7df112d..56b1e29 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
@@ -137,8 +137,8 @@
     'objectClassName':
         js.quoteName(namer.runtimeTypeName(compiler.coreClasses.objectClass)),
     'needsStructuredMemberInfo': emitter.needsStructuredMemberInfo,
-    'usesMangledNames':
-        compiler.mirrorsLibrary != null || compiler.enabledFunctionApply,
+    'usesMangledNames': compiler.commonElements.mirrorsLibrary != null ||
+        compiler.enabledFunctionApply,
     'tearOffCode': buildTearOffCode(backend),
     'nativeInfoHandler': nativeInfoHandler,
     'operatorIsPrefix': js.string(namer.operatorIsPrefix),
diff --git a/pkg/compiler/lib/src/kernel/accessors.dart b/pkg/compiler/lib/src/kernel/accessors.dart
new file mode 100644
index 0000000..026ba63
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/accessors.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/frontend/accessors.dart' as ir_accessors;
+
+import 'kernel.dart' show Kernel;
+import 'unresolved.dart' show UnresolvedVisitor;
+
+export 'package:kernel/frontend/accessors.dart' show Accessor;
+
+class TopLevelStaticAccessor extends ir_accessors.StaticAccessor {
+  final UnresolvedVisitor builder;
+
+  /// Name of the property attempted to be accessed, used to generate an
+  /// error if unresolved.
+  final String name;
+
+  Kernel get kernel => builder.kernel;
+
+  TopLevelStaticAccessor(
+      this.builder,
+      this.name,
+      ir.Member readTarget,
+      ir.Member writeTarget)
+      : super(readTarget, writeTarget);
+
+  @override
+  makeInvalidRead() {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedTopLevelGetterBuilder(),
+        new ir.NullLiteral(),
+        name,
+        new ir.Arguments.empty());
+  }
+
+  @override
+  makeInvalidWrite(ir.Expression value) {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedTopLevelSetterBuilder(),
+        new ir.NullLiteral(),
+        name,
+        new ir.Arguments(<ir.Expression>[value]));
+  }
+}
+
+class ClassStaticAccessor extends ir_accessors.StaticAccessor {
+  final UnresolvedVisitor builder;
+
+  /// Name of the property attempted to be accessed, used to generate an
+  /// error if unresolved.
+  final String name;
+
+  Kernel get kernel => builder.kernel;
+
+  ClassStaticAccessor(this.builder, this.name,
+      ir.Member readTarget, ir.Member writeTarget)
+      : super(readTarget, writeTarget);
+
+  @override
+  makeInvalidRead() {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedStaticGetterBuilder(),
+        new ir.NullLiteral(),
+        name,
+        new ir.Arguments.empty());
+  }
+
+  @override
+  makeInvalidWrite(ir.Expression value) {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedStaticSetterBuilder(),
+        new ir.NullLiteral(),
+        name,
+        new ir.Arguments(<ir.Expression>[value]));
+  }
+}
+
+class SuperPropertyAccessor extends ir_accessors.SuperPropertyAccessor {
+  final UnresolvedVisitor builder;
+
+  /// Name of the property attempted to be accessed, used to generate an
+  /// error if unresolved.
+  final String name;
+
+  SuperPropertyAccessor(
+      this.builder,
+      this.name,
+      ir.Member readTarget,
+      ir.Member writeTarget)
+      : super(readTarget, writeTarget);
+
+  @override
+  makeInvalidRead() {
+    // TODO(asgerf): Technically, we should invoke 'super.noSuchMethod' for
+    //   this and the other invalid super cases.
+    return builder.buildThrowUnresolvedSuperGetter(name);
+  }
+
+  @override
+  makeInvalidWrite(ir.Expression value) {
+    return builder.buildThrowUnresolvedSuperSetter(name, value);
+  }
+}
+
+class SuperIndexAccessor extends ir_accessors.SuperIndexAccessor {
+  final UnresolvedVisitor builder;
+
+  Kernel get kernel => builder.kernel;
+
+  SuperIndexAccessor(
+      this.builder,
+      ir.Expression index,
+      ir.Member readTarget,
+      ir.Member writeTarget)
+      : super(index, readTarget, writeTarget);
+
+  @override
+  makeInvalidRead() {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedSuperMethodBuilder(),
+        new ir.ThisExpression(),
+        '[]',
+        new ir.Arguments(<ir.Expression>[indexAccess()]));
+  }
+
+  @override
+  makeInvalidWrite(ir.Expression value) {
+    return builder.buildThrowNoSuchMethodError(
+        kernel.getUnresolvedSuperMethodBuilder(),
+        new ir.ThisExpression(),
+        '[]=',
+        new ir.Arguments(<ir.Expression>[indexAccess(), value]));
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/error.dart b/pkg/compiler/lib/src/kernel/error.dart
new file mode 100644
index 0000000..464112f
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/error.dart
@@ -0,0 +1,139 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' as ir;
+
+import "../dart_types.dart" show DartType;
+import "../elements/elements.dart" show Element, ErroneousElement;
+import "../resolution/operators.dart"
+    show AssignmentOperator, BinaryOperator, IncDecOperator, UnaryOperator;
+import "../tree/tree.dart"
+    show Expression, NewExpression, Node, NodeList, Operator, Send, SendSet;
+import "../universe/call_structure.dart" show CallStructure;
+import "../universe/selector.dart" show Selector;
+
+abstract class KernelError {
+  // TODO(ahe): Get rid of this method, each error should be handled according
+  // to the semantics required by the Dart Language Specification.
+  ir.Expression handleError(Expression node);
+
+  ir.Expression errorInvalidBinary(Send node, ErroneousElement error,
+      BinaryOperator operator, Node right, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidCompound(Send node, ErroneousElement error,
+      AssignmentOperator operator, Node rhs, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidCompoundIndexSet(Send node, ErroneousElement error,
+      Node index, AssignmentOperator operator, Node rhs, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidEquals(
+      Send node, ErroneousElement error, Node right, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidGet(Send node, ErroneousElement error, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidIndex(
+      Send node, ErroneousElement error, Node index, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidIndexPostfix(Send node, ErroneousElement error,
+      Node index, IncDecOperator operator, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidIndexPrefix(Send node, ErroneousElement error,
+      Node index, IncDecOperator operator, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidIndexSet(
+      Send node, ErroneousElement error, Node index, Node rhs, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidInvoke(Send node, ErroneousElement error,
+      NodeList arguments, Selector selector, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidNotEquals(
+      Send node, ErroneousElement error, Node right, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidPostfix(
+      Send node, ErroneousElement error, IncDecOperator operator, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidPrefix(
+      Send node, ErroneousElement error, IncDecOperator operator, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidSet(
+      Send node, ErroneousElement error, Node rhs, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidSetIfNull(
+      Send node, ErroneousElement error, Node rhs, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidUnary(
+      Send node, UnaryOperator operator, ErroneousElement error, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorNonConstantConstructorInvoke(
+      NewExpression node,
+      Element element,
+      DartType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorUndefinedBinaryExpression(
+      Send node, Node left, Operator operator, Node right, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorUndefinedUnaryExpression(
+      Send node, Operator operator, Node expression, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorUnresolvedFieldInitializer(
+      SendSet node, Element element, Node initializer, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorUnresolvedSuperConstructorInvoke(
+      Send node, Element element, NodeList arguments, Selector selector, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorUnresolvedThisConstructorInvoke(
+      Send node, Element element, NodeList arguments, Selector selector, _) {
+    return handleError(node);
+  }
+
+  ir.Expression errorInvalidIndexSetIfNull(
+      SendSet node, ErroneousElement error, Node index, Node rhs, _) {
+    return handleError(node);
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/fall_through_visitor.dart b/pkg/compiler/lib/src/kernel/fall_through_visitor.dart
new file mode 100644
index 0000000..cd74708
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/fall_through_visitor.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart'
+    show
+        AssertStatement,
+        Block,
+        BreakStatement,
+        Catch,
+        ContinueSwitchStatement,
+        DoStatement,
+        EmptyStatement,
+        ExpressionStatement,
+        ForInStatement,
+        ForStatement,
+        FunctionDeclaration,
+        IfStatement,
+        InvalidStatement,
+        LabeledStatement,
+        ReturnStatement,
+        Statement,
+        StatementVisitor,
+        SwitchStatement,
+        Throw,
+        TryCatch,
+        TryFinally,
+        VariableDeclaration,
+        WhileStatement,
+        YieldStatement;
+
+/// Returns true if [node] would let execution reach the next node (aka
+/// fall-through in switch cases).
+bool fallsThrough(Statement node) => node.accept(const FallThroughVisitor());
+
+/// Visitor implementing [computeFallThrough].
+class FallThroughVisitor implements StatementVisitor<bool> {
+  const FallThroughVisitor();
+
+  bool defaultStatement(Statement node) => throw "Not implemented.";
+
+  bool visitInvalidStatement(InvalidStatement node) => false;
+
+  bool visitExpressionStatement(ExpressionStatement node) {
+    return node.expression is! Throw;
+  }
+
+  bool visitBlock(Block node) {
+    for (Statement statement in node.statements) {
+      if (!statement.accept(this)) return false;
+    }
+    return true;
+  }
+
+  bool visitEmptyStatement(EmptyStatement node) => true;
+
+  bool visitAssertStatement(AssertStatement node) => true;
+
+  bool visitLabeledStatement(LabeledStatement node) => true;
+
+  bool visitBreakStatement(BreakStatement node) => false;
+
+  bool visitWhileStatement(WhileStatement node) => true;
+
+  bool visitDoStatement(DoStatement node) => node.body.accept(this);
+
+  bool visitForStatement(ForStatement node) => true;
+
+  bool visitForInStatement(ForInStatement node) => true;
+
+  bool visitSwitchStatement(SwitchStatement node) => true;
+
+  bool visitContinueSwitchStatement(ContinueSwitchStatement node) => false;
+
+  bool visitIfStatement(IfStatement node) {
+    if (node.then == null || node.otherwise == null) return true;
+    return node.then.accept(this) || node.otherwise.accept(this);
+  }
+
+  bool visitReturnStatement(ReturnStatement node) => false;
+
+  bool visitTryCatch(TryCatch node) {
+    if (node.body.accept(this)) return true;
+    for (Catch catchNode in node.catches) {
+      if (catchNode.body.accept(this)) return true;
+    }
+    return false;
+  }
+
+  bool visitTryFinally(TryFinally node) {
+    return node.body.accept(this) && node.finalizer.accept(this);
+  }
+
+  bool visitYieldStatement(YieldStatement node) => true;
+
+  bool visitVariableDeclaration(VariableDeclaration node) => true;
+
+  bool visitFunctionDeclaration(FunctionDeclaration node) => true;
+}
diff --git a/pkg/compiler/lib/src/kernel/kernel.dart b/pkg/compiler/lib/src/kernel/kernel.dart
new file mode 100644
index 0000000..34ac4f8
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/kernel.dart
@@ -0,0 +1,584 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'dart:collection' show Queue;
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/checks.dart' show CheckParentPointers;
+import 'package:kernel/frontend/super_calls.dart' show moveSuperCallLast;
+
+import '../compiler.dart' show Compiler;
+import '../constants/expressions.dart' show TypeConstantExpression;
+import '../dart_types.dart'
+    show DartType, FunctionType, InterfaceType, TypeKind, TypeVariableType;
+import '../diagnostics/messages.dart' show MessageKind;
+import '../diagnostics/spannable.dart' show Spannable;
+import '../elements/elements.dart'
+    show
+        ClassElement,
+        ConstructorElement,
+        Element,
+        FieldElement,
+        FunctionElement,
+        LibraryElement,
+        MixinApplicationElement,
+        TypeVariableElement;
+import '../elements/modelx.dart' show ErroneousFieldElementX;
+import '../tree/tree.dart' show FunctionExpression, Node;
+import 'kernel_visitor.dart' show IrFunction, KernelVisitor;
+
+typedef void WorkAction();
+
+class WorkItem {
+  final Element element;
+  final WorkAction action;
+
+  WorkItem(this.element, this.action);
+}
+
+class Kernel {
+  final Compiler compiler;
+
+  final Map<LibraryElement, ir.Library> libraries =
+      <LibraryElement, ir.Library>{};
+
+  final Map<ClassElement, ir.Class> classes = <ClassElement, ir.Class>{};
+
+  final Map<FunctionElement, ir.Member> functions =
+      <FunctionElement, ir.Member>{};
+
+  final Map<FieldElement, ir.Field> fields = <FieldElement, ir.Field>{};
+
+  final Map<TypeVariableElement, ir.TypeParameter> typeParameters =
+      <TypeVariableElement, ir.TypeParameter>{};
+
+  final Map<TypeVariableElement, ir.TypeParameter> factoryTypeParameters =
+      <TypeVariableElement, ir.TypeParameter>{};
+
+  final Set<ir.TreeNode> checkedNodes = new Set<ir.TreeNode>();
+
+  final Map<LibraryElement, Map<String, int>> mixinApplicationNamesByLibrary =
+      <LibraryElement, Map<String, int>>{};
+
+  /// FIFO queue of work that needs to be completed before the returned AST
+  /// nodes are correct.
+  final Queue<WorkItem> workQueue = new Queue<WorkItem>();
+
+  Kernel(this.compiler);
+
+  void addWork(Element element, WorkAction action) {
+    workQueue.addLast(new WorkItem(element, action));
+  }
+
+  void checkMember(Element key, ir.TreeNode value) {
+    if (!checkedNodes.add(value)) return;
+    if (value.parent == null) {
+      internalError(key, "Missing parent on IR node.");
+    }
+    try {
+      CheckParentPointers.check(value);
+    } catch (e, s) {
+      internalError(key, "$e\n$s");
+    }
+  }
+
+  void checkLibrary(Element key, ir.Library library) {
+    if (!checkedNodes.add(library)) return;
+    CheckParentPointers.check(library);
+  }
+
+  void processWorkQueue() {
+    while (workQueue.isNotEmpty) {
+      WorkItem work = workQueue.removeFirst();
+      work.action();
+    }
+    assert(() {
+      libraries.forEach(checkLibrary);
+      classes.forEach(checkMember);
+      functions.forEach(checkMember);
+      fields.forEach(checkMember);
+      return true;
+    });
+  }
+
+  ir.Name irName(String name, Element element) {
+    ir.Library irLibrary = null;
+    if (name.startsWith("_")) {
+      ClassElement cls = element.enclosingClass;
+      if (cls != null && cls.isMixinApplication) {
+        MixinApplicationElement mixinApplication = cls;
+        element = mixinApplication.mixin;
+      }
+      irLibrary = libraryToIr(element.library);
+    }
+    return new ir.Name(name, irLibrary);
+  }
+
+  ir.Library libraryToIr(LibraryElement library) {
+    library = library.declaration;
+    return libraries.putIfAbsent(library, () {
+      String name = library.hasLibraryName ? library.libraryName : null;
+      ir.Library libraryNode = new ir.Library(library.canonicalUri,
+          name: name, classes: null, procedures: null, fields: null);
+      addWork(library, () {
+        Queue<ir.Class> classes = new Queue<ir.Class>();
+        Queue<ir.Member> members = new Queue<ir.Member>();
+        library.implementation.forEachLocalMember((Element e) {
+          if (e.isClass) {
+            classes.addFirst(classToIr(e));
+          } else if (e.isFunction || e.isAccessor) {
+            members.addFirst(functionToIr(e));
+          } else if (e.isField) {
+            members.addFirst(fieldToIr(e));
+          } else if (e.isTypedef) {
+            // Ignored, typedefs are unaliased on use.
+          } else {
+            internalError(e, "Unhandled library member: $e");
+          }
+        });
+        // The elements were inserted in reverse order as forEachLocalMember
+        // above gives them in reversed order.
+        classes.forEach(libraryNode.addClass);
+        members.forEach(libraryNode.addMember);
+      });
+      return libraryNode;
+    });
+  }
+
+  /// Compute a name for [cls]. We want to have unique names in a library, but
+  /// mixin applications can lead to multiple classes with the same name. So
+  /// for those we append `#` and a number.
+  String computeName(ClassElement cls) {
+    String name = cls.name;
+    if (!cls.isUnnamedMixinApplication) return name;
+    Map<String, int> mixinApplicationNames = mixinApplicationNamesByLibrary
+        .putIfAbsent(cls.library.implementation, () => <String, int>{});
+    int count = mixinApplicationNames.putIfAbsent(name, () => 0);
+    mixinApplicationNames[name] = count + 1;
+    return "$name#$count";
+  }
+
+  ir.Class classToIr(ClassElement cls) {
+    cls = cls.declaration;
+    return classes.putIfAbsent(cls, () {
+      String name = computeName(cls);
+      ir.Class classNode = new ir.Class(
+          name: name,
+          isAbstract: cls.isAbstract,
+          typeParameters: null,
+          implementedTypes: null,
+          constructors: null,
+          procedures: null,
+          fields: null);
+      addWork(cls, () {
+        if (cls.supertype != null) {
+          classNode.supertype = interfaceTypeToIr(cls.supertype);
+        }
+        classNode.parent = libraryToIr(cls.library);
+        if (cls.isUnnamedMixinApplication) {
+          classNode.enclosingLibrary.addClass(classNode);
+        }
+        cls.implementation
+            .forEachMember((ClassElement enclosingClass, Element member) {
+          if (member.enclosingClass.declaration != cls) {
+            internalError(cls, "`$member` isn't mine.");
+          } else if (member.isFunction ||
+              member.isAccessor ||
+              member.isConstructor) {
+            classNode.addMember(functionToIr(member));
+          } else if (member.isField) {
+            classNode.addMember(fieldToIr(member));
+          } else {
+            internalError(member, "Unhandled class member: $member");
+          }
+        });
+        classNode.typeParameters.addAll(typeVariablesToIr(cls.typeVariables));
+        for (ir.InterfaceType interface in typesToIr(cls.interfaces.toList())) {
+          classNode.implementedTypes.add(interface);
+        }
+      });
+      return classNode;
+    });
+  }
+
+  bool hasHierarchyProblem(ClassElement cls) => cls.hasIncompleteHierarchy;
+
+  ir.InterfaceType interfaceTypeToIr(InterfaceType type) {
+    ir.Class cls = classToIr(type.element);
+    if (type.typeArguments.isEmpty) {
+      return cls.rawType;
+    } else {
+      return new ir.InterfaceType(cls, typesToIr(type.typeArguments));
+    }
+  }
+
+  // TODO(ahe): Remove this method when dart2js support generic type arguments.
+  List<ir.TypeParameter> typeParametersNotImplemented() {
+    return const <ir.TypeParameter>[];
+  }
+
+  ir.FunctionType functionTypeToIr(FunctionType type) {
+    List<ir.TypeParameter> typeParameters = typeParametersNotImplemented();
+    int requiredParameterCount = type.parameterTypes.length;
+    List<ir.DartType> positionalParameters =
+        new List<ir.DartType>.from(typesToIr(type.parameterTypes))
+          ..addAll(typesToIr(type.optionalParameterTypes));
+    Map<String, ir.DartType> namedParameters = <String, ir.DartType>{};
+    for (int i = 0; i < type.namedParameters.length; i++) {
+      namedParameters[type.namedParameters[i]] =
+          typeToIr(type.namedParameterTypes[i]);
+    }
+    ir.DartType returnType = typeToIr(type.returnType);
+
+    return new ir.FunctionType(positionalParameters, returnType,
+        namedParameters: namedParameters,
+        typeParameters: typeParameters,
+        requiredParameterCount: requiredParameterCount);
+  }
+
+  ir.TypeParameterType typeVariableTypeToIr(TypeVariableType type) {
+    return new ir.TypeParameterType(typeVariableToIr(type.element));
+  }
+
+  List<ir.DartType> typesToIr(List<DartType> types) {
+    List<ir.DartType> result = new List<ir.DartType>(types.length);
+    for (int i = 0; i < types.length; i++) {
+      result[i] = typeToIr(types[i]);
+    }
+    return result;
+  }
+
+  ir.DartType typeToIr(DartType type) {
+    switch (type.kind) {
+      case TypeKind.FUNCTION:
+        return functionTypeToIr(type);
+
+      case TypeKind.INTERFACE:
+        return interfaceTypeToIr(type);
+
+      case TypeKind.STATEMENT:
+        throw "Internal error: statement type: $type.";
+
+      case TypeKind.TYPEDEF:
+        type.computeUnaliased(compiler.resolution);
+        return typeToIr(type.unaliased);
+
+      case TypeKind.TYPE_VARIABLE:
+        return typeVariableTypeToIr(type);
+
+      case TypeKind.MALFORMED_TYPE:
+        return const ir.InvalidType();
+
+      case TypeKind.DYNAMIC:
+        return const ir.DynamicType();
+
+      case TypeKind.VOID:
+        return const ir.VoidType();
+    }
+  }
+
+  ir.DartType typeLiteralToIr(TypeConstantExpression constant) {
+    return typeToIr(constant.type);
+  }
+
+  void setParent(ir.Member member, Element element) {
+    if (element.isLocal) {
+      member.parent = elementToIr(element.enclosingElement);
+    } else if (element.isTopLevel) {
+      member.parent = elementToIr(element.library);
+    } else if (element.isClassMember) {
+      member.parent = elementToIr(element.enclosingClass);
+    } else {
+      member.parent = elementToIr(element.enclosingElement);
+    }
+  }
+
+  bool isNativeMethod(FunctionElement element) {
+    // This method is a (modified) copy of the same method in
+    // `pkg/compiler/lib/src/native/enqueue.dart`.
+    if (!compiler.backend.canLibraryUseNative(element.library)) return false;
+    return compiler.reporter.withCurrentElement(element, () {
+      FunctionExpression functionExpression =
+          element.node?.asFunctionExpression();
+      if (functionExpression == null) return false;
+      Node body = functionExpression.body;
+      if (body == null) return false;
+      if (identical(body.getBeginToken().stringValue, 'native')) return true;
+      return false;
+    });
+  }
+
+  ir.Member functionToIr(FunctionElement function) {
+    if (function.isDeferredLoaderGetter) {
+      internalError(function, "Deferred loader.");
+    }
+    if (function.isLocal) {
+      internalError(function, "Local function.");
+    }
+    if (isSyntheticError(function)) {
+      internalError(function, "Synthetic error function: $function.");
+    }
+    function = function.declaration;
+    return functions.putIfAbsent(function, () {
+      function = function.implementation;
+      ir.Member member;
+      ir.Constructor constructor;
+      ir.Procedure procedure;
+      ir.Name name = irName(function.name, function);
+      bool isNative = isNativeMethod(function);
+      if (function.isGenerativeConstructor) {
+        member = constructor = new ir.Constructor(null,
+            name: name,
+            isConst: function.isConst,
+            isExternal: isNative || function.isExternal,
+            initializers: null);
+      } else {
+        member = procedure = new ir.Procedure(name, null, null,
+            isAbstract: function.isAbstract,
+            isStatic: function.isStatic ||
+                function.isTopLevel ||
+                function.isFactoryConstructor,
+            isExternal: isNative || function.isExternal,
+            isConst: false); // TODO(ahe): When is this true?
+      }
+      addWork(function, () {
+        setParent(member, function);
+        KernelVisitor visitor =
+            new KernelVisitor(function, function.treeElements, this);
+        beginFactoryScope(function);
+        IrFunction irFunction = visitor.buildFunction();
+        // TODO(ahe): Add addFunction/set function to [ir.Procedure].
+        irFunction.node.parent = member;
+        if (irFunction.isConstructor) {
+          assert(irFunction.kind == null);
+          constructor.function = irFunction.node;
+          constructor.initializers = irFunction.initializers;
+          // TODO(ahe): Add setInitializers to [ir.Constructor].
+          for (ir.Initializer initializer in irFunction.initializers) {
+            initializer.parent = constructor;
+          }
+          moveSuperCallLast(constructor);
+        } else {
+          assert(irFunction.kind != null);
+          procedure.function = irFunction.node;
+          procedure.kind = irFunction.kind;
+        }
+        endFactoryScope(function);
+        assert(() {
+          visitor.locals.forEach(checkMember);
+          return true;
+        });
+      });
+      return member;
+    });
+  }
+
+  /// Adds the type parameters of the enclosing class of [function] to
+  /// [factoryTypeParameters]. This serves as a local scope for type variables
+  /// resolved inside the factory.
+  ///
+  /// This method solves the problem that a factory method really is a generic
+  /// method that has its own type parameters, one for each type parameter in
+  /// the enclosing class.
+  void beginFactoryScope(FunctionElement function) {
+    assert(factoryTypeParameters.isEmpty);
+    if (!function.isFactoryConstructor) return;
+    ClassElement cls = function.enclosingClass;
+    for (DartType type in cls.typeVariables) {
+      if (type.isTypeVariable) {
+        TypeVariableElement variable = type.element;
+        factoryTypeParameters[variable] =
+            new ir.TypeParameter(variable.name, null);
+      }
+    }
+    for (DartType type in cls.typeVariables) {
+      if (type.isTypeVariable) {
+        TypeVariableElement variable = type.element;
+        factoryTypeParameters[variable].bound = typeToIr(variable.bound);
+      }
+    }
+  }
+
+  /// Ends the local scope started by [beginFactoryScope].
+  void endFactoryScope(FunctionElement function) {
+    factoryTypeParameters.clear();
+  }
+
+  ir.Field fieldToIr(FieldElement field) {
+    if (isSyntheticError(field)) {
+      internalError(field, "Synthetic error field: $field.");
+    }
+    field = field.declaration;
+    return fields.putIfAbsent(field, () {
+      field = field.implementation;
+      ir.DartType type =
+          field.isMalformed ? const ir.InvalidType() : typeToIr(field.type);
+      ir.Field fieldNode = new ir.Field(irName(field.memberName.text, field),
+          type: type,
+          initializer: null,
+          isFinal: field.isFinal,
+          isStatic: field.isStatic || field.isTopLevel,
+          isConst: field.isConst);
+      addWork(field, () {
+        setParent(fieldNode, field);
+        if (!field.isMalformed &&
+            !field.isInstanceMember &&
+            field.initializer != null) {
+          KernelVisitor visitor =
+              new KernelVisitor(field, field.treeElements, this);
+          fieldNode.initializer = visitor.buildInitializer()
+            ..parent = fieldNode;
+        }
+      });
+      return fieldNode;
+    });
+  }
+
+  ir.TypeParameter typeVariableToIr(TypeVariableElement variable) {
+    variable = variable.declaration;
+    ir.TypeParameter parameter = factoryTypeParameters[variable];
+    if (parameter != null) return parameter;
+    return typeParameters.putIfAbsent(variable, () {
+      ir.TypeParameter parameter = new ir.TypeParameter(variable.name, null);
+      addWork(variable, () {
+        // TODO(ahe): This assignment will probably not be correct when dart2js
+        // supports generic methods.
+        ClassElement cls = variable.typeDeclaration;
+        parameter.parent = classToIr(cls);
+        parameter.bound = typeToIr(variable.bound);
+      });
+      return parameter;
+    });
+  }
+
+  List<ir.TypeParameter> typeVariablesToIr(List<DartType> variables) {
+    List<ir.TypeParameter> result =
+        new List<ir.TypeParameter>(variables.length);
+    for (int i = 0; i < variables.length; i++) {
+      TypeVariableType type = variables[i];
+      result[i] = typeVariableToIr(type.element);
+    }
+    return result;
+  }
+
+  ir.TreeNode elementToIr(Element element) {
+    if (element.isLibrary) return libraryToIr(element);
+    if (element.isClass) return classToIr(element);
+    if (element.isFunction || element.isAccessor) return functionToIr(element);
+    if (element.isField) return fieldToIr(element);
+    throw "unhandled element: $element";
+  }
+
+  void debugMessage(Spannable spannable, String message) {
+    compiler.reporter
+        .reportHintMessage(spannable, MessageKind.GENERIC, {'text': message});
+  }
+
+  void internalError(Spannable spannable, String message) {
+    compiler.reporter.internalError(spannable, message);
+    throw message;
+  }
+
+  ConstructorTarget computeEffectiveTarget(
+      ConstructorElement constructor, DartType type) {
+    constructor = constructor.implementation;
+    Set<ConstructorElement> seen = new Set<ConstructorElement>();
+    functionToIr(constructor);
+    while (constructor != constructor.effectiveTarget) {
+      type = constructor.computeEffectiveTargetType(type);
+      if (constructor.isGenerativeConstructor) break;
+      if (!seen.add(constructor)) break;
+      constructor = constructor.effectiveTarget.implementation;
+      if (isSyntheticError(constructor)) break;
+      functionToIr(constructor);
+    }
+    return new ConstructorTarget(constructor, type);
+  }
+
+  /// Returns true if [element] is synthesized to recover or represent a
+  /// semantic error, for example, missing, duplicated, or ambiguous elements.
+  /// However, returns false for elements that have an unrecoverable syntax
+  /// error. Both kinds of element will return true from [Element.isMalformed],
+  /// but they must be handled differently. For example, a static call to
+  /// synthetic error element should be compiled to [ir.InvalidExpression],
+  /// whereas a static call to a method which has a syntax error should be
+  /// compiled to a static call to the method. The method itself will have a
+  /// method body that is [ir.InvalidStatement].
+  bool isSyntheticError(Element element) {
+    if (element.isAmbiguous) return true;
+    if (element.isError) return true;
+    if (element.isField && element is ErroneousFieldElementX) {
+      return true;
+    }
+    return false;
+  }
+
+  ir.Procedure getDartCoreMethod(String name) {
+    LibraryElement library =
+        compiler.libraryLoader.lookupLibrary(Uri.parse("dart:core"));
+    Element function = library.implementation.localLookup(name);
+    return functionToIr(function);
+  }
+
+  ir.Procedure getMalformedTypeErrorBuilder() {
+    return getDartCoreMethod('_malformedTypeError');
+  }
+
+  ir.Procedure getUnresolvedConstructorBuilder() {
+    return getDartCoreMethod('_unresolvedConstructorError');
+  }
+
+  ir.Procedure getUnresolvedStaticGetterBuilder() {
+    return getDartCoreMethod('_unresolvedStaticGetterError');
+  }
+
+  ir.Procedure getUnresolvedStaticSetterBuilder() {
+    return getDartCoreMethod('_unresolvedStaticSetterError');
+  }
+
+  ir.Procedure getUnresolvedStaticMethodBuilder() {
+    return getDartCoreMethod('_unresolvedStaticMethodError');
+  }
+
+  ir.Procedure getUnresolvedTopLevelGetterBuilder() {
+    return getDartCoreMethod('_unresolvedTopLevelGetterError');
+  }
+
+  ir.Procedure getUnresolvedTopLevelSetterBuilder() {
+    return getDartCoreMethod('_unresolvedTopLevelSetterError');
+  }
+
+  ir.Procedure getUnresolvedTopLevelMethodBuilder() {
+    return getDartCoreMethod('_unresolvedTopLevelMethodError');
+  }
+
+  ir.Procedure getUnresolvedSuperGetterBuilder() {
+    return getDartCoreMethod('_unresolvedSuperGetterError');
+  }
+
+  ir.Procedure getUnresolvedSuperSetterBuilder() {
+    return getDartCoreMethod('_unresolvedSuperSetterError');
+  }
+
+  ir.Procedure getUnresolvedSuperMethodBuilder() {
+    return getDartCoreMethod('_unresolvedSuperMethodError');
+  }
+
+  ir.Procedure getGenericNoSuchMethodBuilder() {
+    return getDartCoreMethod('_genericNoSuchMethod');
+  }
+
+  ir.Procedure getFallThroughErrorBuilder() {
+    return getDartCoreMethod('_fallThroughError');
+  }
+}
+
+class ConstructorTarget {
+  final ConstructorElement element;
+  final DartType type;
+
+  ConstructorTarget(this.element, this.type);
+
+  String toString() => "ConstructorTarget($element, $type)";
+}
diff --git a/pkg/compiler/lib/src/kernel/kernel_visitor.dart b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
new file mode 100644
index 0000000..68945d0
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
@@ -0,0 +1,2714 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/frontend/accessors.dart'
+    show
+        Accessor,
+        IndexAccessor,
+        NullAwarePropertyAccessor,
+        PropertyAccessor,
+        ReadOnlyAccessor,
+        StaticAccessor,
+        SuperIndexAccessor,
+        SuperPropertyAccessor,
+        ThisPropertyAccessor,
+        VariableAccessor,
+        buildIsNull,
+        makeBinary,
+        makeLet,
+        makeOrReuseVariable;
+
+import '../constants/expressions.dart'
+    show
+        BoolFromEnvironmentConstantExpression,
+        ConstantExpression,
+        ConstructedConstantExpression,
+        IntFromEnvironmentConstantExpression,
+        StringFromEnvironmentConstantExpression,
+        TypeConstantExpression;
+import '../dart_types.dart' show DartType, InterfaceType;
+import '../diagnostics/spannable.dart' show Spannable;
+import '../elements/elements.dart'
+    show
+        AstElement,
+        AsyncMarker,
+        ClassElement,
+        ConstructorElement,
+        Element,
+        FieldElement,
+        FunctionElement,
+        FunctionSignature,
+        GetterElement,
+        InitializingFormalElement,
+        JumpTarget,
+        LocalElement,
+        LocalFunctionElement,
+        LocalVariableElement,
+        MethodElement,
+        Name,
+        ParameterElement,
+        PrefixElement,
+        TypeVariableElement;
+import '../resolution/operators.dart'
+    show AssignmentOperator, BinaryOperator, IncDecOperator, UnaryOperator;
+import '../resolution/semantic_visitor.dart'
+    show
+        BaseImplementationOfCompoundsMixin,
+        BaseImplementationOfLocalsMixin,
+        BaseImplementationOfSetIfNullsMixin,
+        BaseImplementationOfStaticsMixin,
+        CompoundGetter,
+        CompoundKind,
+        CompoundRhs,
+        CompoundSetter,
+        SemanticDeclarationResolvedMixin,
+        SemanticDeclarationVisitor,
+        SemanticSendResolvedMixin,
+        SemanticSendVisitor,
+        SemanticVisitor;
+import '../resolution/send_resolver.dart' show DeclarationResolverMixin;
+import '../resolution/send_structure.dart'
+    show
+        InitializerStructure,
+        InitializersStructure,
+        ParameterStructure,
+        VariableStructure;
+import '../resolution/tree_elements.dart' show TreeElements;
+import '../tree/tree.dart'
+    show
+        Assert,
+        AsyncForIn,
+        Await,
+        Block,
+        BreakStatement,
+        Cascade,
+        CascadeReceiver,
+        CaseMatch,
+        CatchBlock,
+        Conditional,
+        ConditionalUri,
+        ContinueStatement,
+        DoWhile,
+        DottedName,
+        EmptyStatement,
+        Enum,
+        Expression,
+        ExpressionStatement,
+        For,
+        ForIn,
+        FunctionDeclaration,
+        FunctionExpression,
+        Identifier,
+        If,
+        Label,
+        LabeledStatement,
+        LiteralBool,
+        LiteralDouble,
+        LiteralInt,
+        LiteralList,
+        LiteralMap,
+        LiteralMapEntry,
+        LiteralNull,
+        LiteralString,
+        LiteralSymbol,
+        Metadata,
+        NamedArgument,
+        NewExpression,
+        Node,
+        NodeList,
+        Operator,
+        ParenthesizedExpression,
+        RedirectingFactoryBody,
+        Rethrow,
+        Return,
+        Send,
+        SendSet,
+        Statement,
+        StringInterpolation,
+        StringInterpolationPart,
+        StringJuxtaposition,
+        SwitchCase,
+        SwitchStatement,
+        SyncForIn,
+        Throw,
+        TryStatement,
+        TypeAnnotation,
+        TypeVariable,
+        VariableDefinitions,
+        While,
+        Yield;
+import '../universe/call_structure.dart' show CallStructure;
+import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show Link;
+import 'error.dart' show KernelError;
+import 'fall_through_visitor.dart' show fallsThrough;
+import 'kernel.dart' show ConstructorTarget, Kernel;
+import 'unavailable.dart' show UnavailableVisitor;
+import 'unresolved.dart' show UnresolvedVisitor;
+
+/// Translates dart2js AST nodes [Node] into Kernel IR [ir.TreeNode].
+///
+/// Most methods in this class have a prefix that follows these conventions:
+///
+///   * `visit` for overridden visitor methods.
+///   * `handle` for methods that implement common behavior for several `visit`
+///     methods. These methods are called by `visit` methods implemented by
+///     various mixins below.
+///   * `build` helper method that builds a new Kernel IR tree.
+///   * `get` helper method that use a cache to build exactly one Kernel IR
+///     tree for a given element.
+///
+/// We reserve the prefixes `visit` and `handle` for superclasses of this
+/// class. So those methods should always have an @override annotation. Use
+/// `build` instead of `handle` when adding a new helper method to this class.
+class KernelVisitor extends Object
+    with
+        SemanticSendResolvedMixin,
+        BaseImplementationOfStaticsMixin,
+        BaseImplementationOfLocalsMixin,
+        BaseImplementationOfCompoundsMixin,
+        BaseImplementationOfSetIfNullsMixin,
+        SemanticDeclarationResolvedMixin,
+        DeclarationResolverMixin,
+        UnavailableVisitor,
+        UnresolvedVisitor,
+        KernelError
+    implements
+        SemanticVisitor,
+        SemanticSendVisitor,
+        SemanticDeclarationVisitor {
+  TreeElements elements;
+  AstElement currentElement;
+  final Kernel kernel;
+
+  final Map<JumpTarget, ir.LabeledStatement> continueTargets =
+      <JumpTarget, ir.LabeledStatement>{};
+
+  final Map<JumpTarget, ir.SwitchCase> continueSwitchTargets =
+      <JumpTarget, ir.SwitchCase>{};
+
+  final Map<JumpTarget, ir.LabeledStatement> breakTargets =
+      <JumpTarget, ir.LabeledStatement>{};
+
+  final Map<LocalElement, ir.VariableDeclaration> locals =
+      <LocalElement, ir.VariableDeclaration>{};
+
+  final Map<CascadeReceiver, ir.VariableGet> cascadeReceivers =
+      <CascadeReceiver, ir.VariableGet>{};
+
+  final Map<ir.Node, Element> nodeToElement = <ir.Node, Element>{};
+
+  ir.Node associate(ir.Node node, Element element) {
+    nodeToElement[node] = element;
+    return node;
+  }
+
+  bool isVoidContext = false;
+
+  KernelVisitor(this.currentElement, this.elements, this.kernel);
+
+  KernelVisitor get sendVisitor => this;
+
+  KernelVisitor get declVisitor => this;
+
+  ir.TreeNode visitForValue(Expression node) {
+    bool wasVoidContext = isVoidContext;
+    isVoidContext = false;
+    try {
+      return node?.accept(this);
+    } finally {
+      isVoidContext = wasVoidContext;
+    }
+  }
+
+  ir.TreeNode visitForEffect(Expression node) {
+    bool wasVoidContext = isVoidContext;
+    isVoidContext = true;
+    try {
+      return node?.accept(this);
+    } finally {
+      isVoidContext = wasVoidContext;
+    }
+  }
+
+  ir.TreeNode visitWithCurrentContext(Expression node) => node?.accept(this);
+
+  withCurrentElement(AstElement element, f()) {
+    assert(element.library == kernel.compiler.currentElement.library);
+    Element previousElement = currentElement;
+    currentElement = element;
+    try {
+      return f();
+    } finally {
+      currentElement = previousElement;
+    }
+  }
+
+  ir.DartType computeType(TypeAnnotation node) {
+    if (node == null) return const ir.DynamicType();
+    return kernel.typeToIr(elements.getType(node));
+  }
+
+  // This works around a bug in dart2js.
+  // TODO(ahe): Fix the bug in dart2js and remove this function.
+  ir.DartType typeToIrHack(DartType type) {
+    if (currentElement.isSynthesized &&
+        currentElement.enclosingClass.isMixinApplication &&
+        !kernel.hasHierarchyProblem(currentElement.enclosingClass)) {
+      // Dart2js doesn't compute the correct functionSignature for synthetic
+      // constructors in mixin applications. So we compute the correct type:
+      // First, find the first superclass that isn't a mixin.
+      ClassElement superclass = currentElement.enclosingClass.superclass;
+      while (superclass.isMixinApplication) {
+        superclass = superclass.superclass;
+      }
+      // Then translate the "this type" of the mixin application to its
+      // supertype with the correct type arguments.
+      //
+      // Consider this example:
+      //
+      //     class Super<S> {}
+      //     class Sub<T> extends Object with Super<T> {}
+      //
+      // Here the problem is that dart2js has created a constructor that refers
+      // to S (not T) in Sub (for example, the return type of the constructor
+      // is Super<S> and it should be Sub<T>, but we settle for Super<T> for
+      // now). So we need to translate Sub<T> to an instance of Super, which is
+      // Super<T> (not Super<S>).
+      InterfaceType supertype =
+          currentElement.enclosingClass.asInstanceOf(superclass);
+      // Once we have [supertype], we know how to substitute S with T: the type
+      // arguments of [supertype] corresponds to T, and the type variables of
+      // its element correspond to S.
+      type =
+          type.subst(supertype.typeArguments, supertype.element.typeVariables);
+    }
+    return kernel.typeToIr(type);
+  }
+
+  // TODO(ahe): Hack. Fix dart2js instead.
+  ir.Name nameToIrName(Name name) {
+    assert(!name.isPrivate ||
+        name.library.implementation == currentElement.library.implementation);
+    return kernel.irName(name.text, currentElement);
+  }
+
+  List<ir.DartType> computeTypesFromTypes(NodeList nodes, {int expected}) {
+    if (expected == null) {
+      throw "[expected] is null";
+    }
+    List<ir.DartType> types = new List<ir.DartType>(expected);
+    Iterator<Node> iterator = nodes?.iterator;
+    for (int i = 0; i < expected; i++) {
+      TypeAnnotation type = null;
+      if (iterator != null && iterator.moveNext()) {
+        type = iterator.current;
+      }
+      types[i] = computeType(type);
+    }
+    if (iterator != null && iterator.moveNext()) {
+      // Should already have been reported by resolution.
+      // TODO(ahe): Delete this debug message.
+      kernel.debugMessage(iterator.current, "Extra type arguments.");
+    }
+    return types;
+  }
+
+  ir.DartType computeTypeFromTypes(NodeList node) {
+    return computeTypesFromTypes(node, expected: 1).single;
+  }
+
+  ir.MethodInvocation buildInvokeSelector(
+      ir.Expression receiver, Selector selector, ir.Arguments arguments) {
+    return new ir.MethodInvocation(
+        receiver, nameToIrName(selector.memberName), arguments);
+  }
+
+  ir.MethodInvocation buildCall(
+      ir.Expression receiver, CallStructure callStructure, NodeList arguments) {
+    return buildInvokeSelector(
+        receiver, callStructure.callSelector, buildArguments(arguments));
+  }
+
+  @override
+  ir.Expression visitIdentifier(Identifier node) {
+    // TODO(ahe): Shouldn't have to override this method, but
+    // [SemanticSendResolvedMixin.visitIdentifier] may return `null` on errors.
+    if (node.isThis()) {
+      return sendVisitor.visitThisGet(node, null);
+    } else {
+      return new ir.InvalidExpression();
+    }
+  }
+
+  @override
+  ir.InvalidExpression handleUnresolved(Node node) {
+    return new ir.InvalidExpression();
+  }
+
+  @override
+  ir.Expression handleError(Node node) => new ir.InvalidExpression();
+
+  @override
+  void apply(Node node, _) {
+    throw new UnsupportedError("apply");
+  }
+
+  @override
+  void previsitDeferredAccess(Send node, PrefixElement prefix, _) {}
+
+  @override
+  internalError(Spannable spannable, String message) {
+    kernel.internalError(spannable, message);
+  }
+
+  @override
+  applyParameters(NodeList parameters, _) {
+    throw new UnsupportedError("applyParameters");
+  }
+
+  @override
+  applyInitializers(FunctionExpression constructor, _) {
+    throw new UnsupportedError("applyInitializers");
+  }
+
+  @override
+  ir.AssertStatement visitAssert(Assert node) {
+    return new ir.AssertStatement(
+        visitForValue(node.condition), visitForValue(node.message));
+  }
+
+  ir.LabeledStatement getBreakTarget(JumpTarget target) {
+    return breakTargets.putIfAbsent(
+        target, () => new ir.LabeledStatement(null));
+  }
+
+  ir.LabeledStatement getContinueTarget(JumpTarget target) {
+    return continueTargets.putIfAbsent(
+        target, () => new ir.LabeledStatement(null));
+  }
+
+  ir.SwitchCase getContinueSwitchTarget(JumpTarget target) {
+    return continueSwitchTargets[target];
+  }
+
+  ir.Statement buildBreakTarget(
+      ir.Statement statement, Node node, JumpTarget jumpTarget) {
+    assert(node.isValidBreakTarget());
+    assert(jumpTarget == elements.getTargetDefinition(node));
+    if (jumpTarget != null && jumpTarget.isBreakTarget) {
+      ir.LabeledStatement breakTarget = getBreakTarget(jumpTarget);
+      breakTarget.body = statement;
+      statement.parent = breakTarget;
+      return breakTarget;
+    } else {
+      return statement;
+    }
+  }
+
+  ir.Statement buildContinueTarget(
+      ir.Statement statement, Node node, JumpTarget jumpTarget) {
+    assert(node.isValidContinueTarget());
+    assert(jumpTarget == elements.getTargetDefinition(node));
+    if (jumpTarget != null && jumpTarget.isContinueTarget) {
+      ir.LabeledStatement continueTarget = getContinueTarget(jumpTarget);
+      continueTarget.body = statement;
+      statement.parent = continueTarget;
+      return continueTarget;
+    } else {
+      return statement;
+    }
+  }
+
+  ir.Statement buildForInCommon(
+      ForIn node, ir.VariableDeclaration variable, ir.Statement body,
+      {bool isAsync}) {
+    ir.Expression iterable = visitForValue(node.expression);
+    JumpTarget jumpTarget = elements.getTargetDefinition(node);
+    body = buildContinueTarget(body, node, jumpTarget);
+    return buildBreakTarget(
+        new ir.ForInStatement(variable, iterable, body, isAsync: isAsync),
+        node,
+        jumpTarget);
+  }
+
+  /// Builds a for-in statement for this case:
+  ///
+  ///     for (constOrVarOrType loopVariable in expression) body
+  ir.Statement buildForInWithDeclaration(
+      ForIn node, VariableDefinitions declaration,
+      {bool isAsync}) {
+    if (declaration.definitions.slowLength() != 1) {
+      // It's not legal to declare more than one variable in a for-in loop.
+      return new ir.InvalidStatement();
+    }
+    ir.VariableDeclaration variable = declaration.accept(this);
+    return buildForInCommon(node, variable, buildStatementInBlock(node.body),
+        isAsync: isAsync);
+  }
+
+  Accessor buildStaticAccessor(Element getter, [Element setter]) {
+    if (setter == null &&
+        getter != null &&
+        getter.isField &&
+        !getter.isFinal &&
+        !getter.isConst) {
+      setter = getter;
+    }
+    return new StaticAccessor(
+        (getter == null) ? null : kernel.elementToIr(getter),
+        (setter == null) ? null : kernel.elementToIr(setter));
+  }
+
+  Accessor computeAccessor(ForIn node, Element element) {
+    if (element == null) {
+      Send send = node.declaredIdentifier.asSend();
+      if (send == null) {
+        return buildStaticAccessor(null);
+      }
+      // This should be the situation where `node.declaredIdentifier` is
+      // unresolved, but in an instance method context. If it is some different
+      // situation, the assignment to [ir.PropertyGet] should act as an
+      // assertion.
+      ir.PropertyGet expression = visitForValue(send);
+      return PropertyAccessor.make(expression.receiver, expression.name);
+    } else if (kernel.isSyntheticError(element)) {
+      return buildStaticAccessor(null);
+    } else if (element.isGetter) {
+      if (element.isInstanceMember) {
+        return new ThisPropertyAccessor(kernel.irName(element.name, element));
+      } else {
+        GetterElement getter = element;
+        Element setter = getter.setter;
+        return buildStaticAccessor(getter, setter);
+      }
+    } else if (element.isLocal) {
+      return new VariableAccessor(getLocal(element));
+    } else if (element.isField) {
+      return buildStaticAccessor(element);
+    } else {
+      return buildStaticAccessor(null);
+    }
+  }
+
+  /// Builds a for-in statement for this case:
+  ///
+  ///     for (element in expression) body
+  ///
+  /// This is normalized to:
+  ///
+  ///     for (final #t in expression) {
+  ///       element = #t;
+  ///       body;
+  ///     }
+  ir.Statement buildForInWithoutDeclaration(ForIn node, Element element,
+      {bool isAsync}) {
+    Accessor accessor = computeAccessor(node, elements.getForInVariable(node));
+    // Since we've created [variable], we know it's only assigned to in the
+    // loop header and can be final.
+    ir.VariableDeclaration variable =
+        new ir.VariableDeclaration.forValue(null, isFinal: true);
+    ir.Statement assigment = new ir.ExpressionStatement(accessor
+        .buildAssignment(new ir.VariableGet(variable), voidContext: true));
+    ir.Block body = buildStatementInBlock(node.body, forceBlock: true);
+    List<ir.Statement> statements = <ir.Statement>[assigment]
+      ..addAll(body.statements);
+    return buildForInCommon(node, variable, new ir.Block(statements),
+        isAsync: isAsync);
+  }
+
+  ir.Statement buildForIn(ForIn node, {bool isAsync}) {
+    VariableDefinitions declaration =
+        node.declaredIdentifier.asVariableDefinitions();
+    if (declaration != null) {
+      return buildForInWithDeclaration(node, declaration, isAsync: isAsync);
+    } else {
+      Element element = elements.getForInVariable(node);
+      return buildForInWithoutDeclaration(node, element, isAsync: isAsync);
+    }
+  }
+
+  @override
+  ir.Statement visitAsyncForIn(AsyncForIn node) {
+    return buildForIn(node, isAsync: true);
+  }
+
+  @override
+  ir.AwaitExpression visitAwait(Await node) {
+    return new ir.AwaitExpression(visitForValue(node.expression));
+  }
+
+  @override
+  ir.Statement visitBlock(Block node) {
+    return buildBreakTarget(
+        buildStatementInBlock(node), node, elements.getTargetDefinition(node));
+  }
+
+  bool buildStatement(Statement statement, List<ir.Statement> statements) {
+    ir.Node irNode = statement.accept(this);
+    bool hasVariableDeclaration = false;
+    if (irNode is VariableDeclarations) {
+      statements.addAll(irNode.variables);
+      hasVariableDeclaration = true;
+    } else {
+      statements.add(irNode);
+      if (irNode is ir.VariableDeclaration) {
+        hasVariableDeclaration = true;
+      }
+    }
+    return hasVariableDeclaration;
+  }
+
+  ir.Statement buildStatementInBlock(Statement node, {bool forceBlock: false}) {
+    if (node == null) return null;
+    List<ir.Statement> statements = <ir.Statement>[];
+    if (node is Block) {
+      for (Node statement in node.statements.nodes) {
+        buildStatement(statement, statements);
+      }
+    } else {
+      if (buildStatement(node, statements)) forceBlock = true;
+      if (!forceBlock && statements.length == 1) {
+        return statements.single;
+      }
+      // One VariableDefinitions statement node (dart2js AST) may generate
+      // multiple statements in Kernel IR so we sometimes fall through here.
+    }
+    return new ir.Block(statements);
+  }
+
+  @override
+  ir.Statement visitBreakStatement(BreakStatement node) {
+    JumpTarget target = elements.getTargetOf(node);
+    if (target == null || !target.statement.isValidBreakTarget()) {
+      // This is a break in an invalid position.
+      return new ir.InvalidStatement();
+    }
+    // A break can break to itself in the degenerate case `label: break
+    // label'`.
+    return buildBreakTarget(new ir.BreakStatement(getBreakTarget(target)), node,
+        elements.getTargetDefinition(node));
+  }
+
+  CascadeReceiver computeCascadeReceiver(Cascade cascade) {
+    CascadeReceiver receiver;
+    Expression send = cascade.expression.asSend();
+    while (send != null && (receiver = send.asCascadeReceiver()) == null) {
+      Expression possibleReceiver = send.asSend()?.receiver;
+      if (possibleReceiver != null) {
+        send = possibleReceiver;
+      } else {
+        // Can happen in this case: `a..add(foo)('WHAT')`.
+        send = send.asSend()?.selector;
+      }
+    }
+    if (receiver == null) {
+      internalError(cascade, "Can't find cascade receiver");
+    }
+    return receiver;
+  }
+
+  @override
+  ir.Let visitCascade(Cascade node) {
+    // Given this cascade expression `receiver..cascade1()..cascade2()`, the
+    // parser has produced a tree like this:
+    //     Cascade(Send(
+    //         CascadeReceiver(Cascade(Send(
+    //             CascadeRecevier(receiver), 'cascade1', []))),
+    //         'cascade2', []))
+    // If viewed as a tree, `CascadeReceiver(receiver)` is the left-most leaf
+    // node.  Below, we create this:
+    //     cascades = [
+    //         Cascade(Send(CascadeReceiver(...), 'cascade2', [])),
+    //         Cascade(Send(CascadeReceiver(...), 'cascade1', []))]
+    // Notice that the cascades are in reverse order, which we use to build a
+    // `let` expression bottom up.
+    // First iteration of the loop produces:
+    //     let dummy = rcv.cascade2() in
+    //         rcv
+    // Second iteration:
+    //     let dummy = rcv.cascade1() in
+    //         let dummy = rcv.cascade2() in
+    //             rcv
+    // Finally we return:
+    //     let rcv = receiver in
+    //         let dummy = rcv.cascade1() in
+    //             let dummy = rcv.cascade2() in
+    //                 rcv
+    int startLength;
+    assert((startLength = cascadeReceivers.length) >= 0);
+
+    Cascade cascade = node;
+    List<Cascade> cascades = <Cascade>[];
+    CascadeReceiver receiver;
+    ir.VariableDeclaration receiverVariable = makeOrReuseVariable(null);
+
+    do {
+      cascades.add(cascade);
+      receiver = computeCascadeReceiver(cascade);
+      cascadeReceivers[receiver] = new ir.VariableGet(receiverVariable);
+      cascade = receiver.expression.asCascade();
+    } while (cascade != null);
+    // At this point, all nested [Cascades] targeting the same receiver have
+    // been collected in [cascades] in reverse order. [receiver] is the
+    // left-most receiver. [receiverVariable] will hold the value of evaluating
+    // [receiver]. Each [CascadeReceiver] has a getter for [receiverVariable]
+    // in [cascadeReceivers].
+
+    receiverVariable.initializer = visitForValue(receiver.expression);
+    receiverVariable.initializer.parent = receiverVariable;
+
+    ir.Expression result = new ir.VariableGet(receiverVariable); // rcv.
+    for (Cascade cascade in cascades) {
+      // When evaluating `cascade.expression`, we stop the recursion at
+      // [visitCascadeReceiver] and instead returns an [ir.VariableGet].
+      // TODO(ahe): Use visitForEffect here?
+      ir.Expression value = visitForValue(cascade.expression);
+      result = new ir.Let(makeOrReuseVariable(value), result);
+    }
+
+    assert(startLength == cascadeReceivers.length);
+    return new ir.Let(receiverVariable, result);
+  }
+
+  @override
+  ir.VariableGet visitCascadeReceiver(CascadeReceiver node) {
+    return cascadeReceivers.remove(node);
+  }
+
+  @override
+  visitCaseMatch(CaseMatch node) {
+    // Shouldn't be called. Handled by [visitSwitchCase].
+    return internalError(node, "CaseMatch");
+  }
+
+  @override
+  ir.Catch visitCatchBlock(CatchBlock node) {
+    ir.VariableDeclaration exception =
+        (node.exception == null) ? null : getLocal(elements[node.exception]);
+    ir.VariableDeclaration trace =
+        (node.trace == null) ? null : getLocal(elements[node.trace]);
+    ir.DartType guard = computeType(node.type);
+    return new ir.Catch(exception, buildStatementInBlock(node.block),
+        guard: guard, stackTrace: trace);
+  }
+
+  @override
+  ir.ConditionalExpression visitConditional(Conditional node) {
+    return new ir.ConditionalExpression(
+        visitForValue(node.condition),
+        visitWithCurrentContext(node.thenExpression),
+        visitWithCurrentContext(node.elseExpression));
+  }
+
+  @override
+  ir.Statement visitContinueStatement(ContinueStatement node) {
+    JumpTarget target = elements.getTargetOf(node);
+    if (target == null || !target.statement.isValidContinueTarget()) {
+      // This is a continue in an invalid position.
+      return new ir.InvalidStatement();
+    }
+    ir.SwitchCase switchCase = getContinueSwitchTarget(target);
+    return (switchCase == null)
+        ? new ir.BreakStatement(getContinueTarget(target))
+        : new ir.ContinueSwitchStatement(switchCase);
+  }
+
+  @override
+  ir.Statement visitDoWhile(DoWhile node) {
+    JumpTarget jumpTarget = elements.getTargetDefinition(node);
+    ir.Statement body =
+        buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget);
+    ir.Expression condition = visitForValue(node.condition);
+    return buildBreakTarget(
+        new ir.DoStatement(body, condition), node, jumpTarget);
+  }
+
+  @override
+  ir.EmptyStatement visitEmptyStatement(EmptyStatement node) {
+    return new ir.EmptyStatement();
+  }
+
+  @override
+  visitEnum(Enum node) {
+    // Not called normally. In dart2js, enums are represented as class
+    // elements, so `classToIr` handles enums.  All the synthetic members of an
+    // enum class have already been installed by dart2js and we don't have to
+    // do anything special.
+    return internalError(node, "Enum");
+  }
+
+  @override
+  ir.ExpressionStatement visitExpressionStatement(ExpressionStatement node) {
+    return new ir.ExpressionStatement(visitForEffect(node.expression));
+  }
+
+  @override
+  ir.Statement visitFor(For node) {
+    VariableDefinitions initializers =
+        node.initializer?.asVariableDefinitions();
+    ir.Expression initializer;
+    List<ir.VariableDeclaration> variables;
+    if (initializers != null) {
+      ir.Block block = buildStatementInBlock(initializers, forceBlock: true);
+      variables = new List<ir.VariableDeclaration>.from(block.statements);
+    } else {
+      if (node.initializer != null) {
+        initializer = visitForValue(node.initializer);
+      }
+      variables = const <ir.VariableDeclaration>[];
+    }
+    ir.Expression condition = visitForValue(node.condition);
+    List<ir.Expression> updates = <ir.Expression>[];
+    for (Expression update in node.update) {
+      updates.add(visitForEffect(update));
+    }
+
+    JumpTarget jumpTarget = elements.getTargetDefinition(node);
+    ir.Statement body =
+        buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget);
+    ir.ForStatement forStatement =
+        new ir.ForStatement(variables, condition, updates, body);
+    ir.Statement result = buildBreakTarget(forStatement, node, jumpTarget);
+    if (initializer != null) {
+      result = new ir.Block(
+          <ir.Statement>[new ir.ExpressionStatement(initializer), result]);
+    }
+    return result;
+  }
+
+  @override
+  ir.FunctionDeclaration visitFunctionDeclaration(FunctionDeclaration node) {
+    return node.function.accept(this);
+  }
+
+  @override
+  ir.Statement visitIf(If node) {
+    return buildBreakTarget(
+        new ir.IfStatement(
+            visitForValue(node.condition),
+            buildStatementInBlock(node.thenPart),
+            buildStatementInBlock(node.elsePart)),
+        node,
+        elements.getTargetDefinition(node));
+  }
+
+  @override
+  visitLabel(Label node) {
+    // Shouldn't be called. Handled by visitLabeledStatement and
+    // visitSwitchCase.
+    return internalError(node, "Label");
+  }
+
+  @override
+  ir.Statement visitLabeledStatement(LabeledStatement node) {
+    Statement statement = node.statement;
+    ir.Statement result = (statement is Block)
+        // If [statement] is a Block, we need to ensure that we don't bypass
+        // its visit method (so it can build break targets correctly).
+        ? statement.accept(this)
+        : buildStatementInBlock(statement);
+
+    // A [LabeledStatement] isn't the actual jump target, instead, [statement]
+    // is the target. This allows uniform handling of break and continue in
+    // loops. The following code simply assert that [result] has been generated
+    // correctly with respect to jump targets.
+    JumpTarget jumpTarget = elements.getTargetDefinition(node.statement);
+    if (jumpTarget != null) {
+      if (jumpTarget.isBreakTarget) {
+        ir.LabeledStatement target = breakTargets[jumpTarget];
+        if (target != null && target != result && target.parent == null) {
+          internalError(node, "no parent");
+        }
+      }
+      if (jumpTarget.isContinueTarget) {
+        ir.LabeledStatement target = continueTargets[jumpTarget];
+        if (target != null && target != result && target.parent == null) {
+          internalError(node, "no parent");
+        }
+      }
+    }
+
+    return result;
+  }
+
+  @override
+  ir.BoolLiteral visitLiteralBool(LiteralBool node) {
+    return new ir.BoolLiteral(node.value);
+  }
+
+  @override
+  ir.DoubleLiteral visitLiteralDouble(LiteralDouble node) {
+    return new ir.DoubleLiteral(node.value);
+  }
+
+  @override
+  ir.IntLiteral visitLiteralInt(LiteralInt node) {
+    return new ir.IntLiteral(node.value);
+  }
+
+  @override
+  ir.ListLiteral visitLiteralList(LiteralList node) {
+    // TODO(ahe): Type arguments.
+    List<ir.Expression> elements = <ir.Expression>[];
+    for (Expression element in node.elements.nodes) {
+      elements.add(visitForValue(element));
+    }
+    return new ir.ListLiteral(elements,
+        typeArgument: computeTypeFromTypes(node.typeArguments),
+        // TODO(ahe): Should constness be validated?
+        isConst: node.isConst);
+  }
+
+  @override
+  ir.MapLiteral visitLiteralMap(LiteralMap node) {
+    // TODO(ahe): Type arguments.
+    List<ir.MapEntry> entries = <ir.MapEntry>[];
+    for (LiteralMapEntry entry in node.entries.nodes) {
+      entries.add(new ir.MapEntry(
+          visitForValue(entry.key), visitForValue(entry.value)));
+    }
+    List<ir.DartType> typeArguments =
+        computeTypesFromTypes(node.typeArguments, expected: 2);
+    return new ir.MapLiteral(entries,
+        keyType: typeArguments.first,
+        valueType: typeArguments.last,
+        // TODO(ahe): Should Constness be validated?
+        isConst: node.isConst);
+  }
+
+  @override
+  visitLiteralMapEntry(LiteralMapEntry node) {
+    // Shouldn't be called. Handled by [visitLiteralMap].
+    return internalError(node, "LiteralMapEntry");
+  }
+
+  @override
+  ir.NullLiteral visitLiteralNull(LiteralNull node) {
+    return new ir.NullLiteral();
+  }
+
+  @override
+  ir.Expression visitLiteralString(LiteralString node) {
+    if (node.dartString == null) return new ir.InvalidExpression();
+    return new ir.StringLiteral(node.dartString.slowToString());
+  }
+
+  @override
+  ir.SymbolLiteral visitLiteralSymbol(LiteralSymbol node) {
+    return new ir.SymbolLiteral(node.slowNameString);
+  }
+
+  @override
+  visitMetadata(Metadata node) {
+    // Shouldn't be called. Metadata should already have been analyzed and
+    // converted to a constant expression in the resolver.
+    return internalError(node, "Metadata not handled as constant.");
+  }
+
+  @override
+  ir.NamedExpression visitNamedArgument(NamedArgument node) {
+    return new ir.NamedExpression(
+        node.name.source, visitForValue(node.expression));
+  }
+
+  @override
+  visitOperator(Operator node) {
+    // This is a special subclass of [Identifier], and we should never see that
+    // in the semantic visitor.
+    return internalError(node, "Operator");
+  }
+
+  @override
+  ir.Expression visitParenthesizedExpression(ParenthesizedExpression node) {
+    return visitWithCurrentContext(node.expression);
+  }
+
+  @override
+  ir.InvalidStatement visitRedirectingFactoryBody(RedirectingFactoryBody node) {
+    // Not implemented yet, only serves to recover from parser errors as
+    // dart2js is lenient in parsing something that looks like a redirecting
+    // factory method.
+    return new ir.InvalidStatement();
+  }
+
+  @override
+  ir.ExpressionStatement visitRethrow(Rethrow node) {
+    return new ir.ExpressionStatement(new ir.Rethrow());
+  }
+
+  @override
+  ir.ReturnStatement visitReturn(Return node) {
+    return new ir.ReturnStatement(visitForValue(node.expression));
+  }
+
+  @override
+  ir.StringConcatenation visitStringInterpolation(StringInterpolation node) {
+    List<ir.Expression> expressions = <ir.Expression>[];
+    expressions.add(visitForValue(node.string));
+    for (StringInterpolationPart part in node.parts) {
+      expressions.add(visitForValue(part.expression));
+      expressions.add(visitForValue(part.string));
+    }
+    return new ir.StringConcatenation(expressions);
+  }
+
+  @override
+  ir.StringConcatenation visitStringJuxtaposition(StringJuxtaposition node) {
+    return new ir.StringConcatenation(
+        <ir.Expression>[visitForValue(node.first), visitForValue(node.second)]);
+  }
+
+  @override
+  ir.SwitchCase visitSwitchCase(SwitchCase node) {
+    List<ir.Expression> expressions = <ir.Expression>[];
+    for (var labelOrCase in node.labelsAndCases.nodes) {
+      CaseMatch match = labelOrCase.asCaseMatch();
+      if (match != null) {
+        expressions.add(visitForValue(match.expression));
+      } else {
+        // Assert that labelOrCase is one of two known types: [CaseMatch] or
+        // [Label]. We ignore cases, as any users have been resolved to use the
+        // case directly.
+        assert(labelOrCase.asLabel() != null);
+      }
+    }
+    // We ignore the node's statements here, they're generated below in
+    // [visitSwitchStatement] once we've set up all the jump targets.
+    return new ir.SwitchCase(expressions, null, isDefault: node.isDefaultCase);
+  }
+
+  @override
+  ir.Statement visitSwitchStatement(SwitchStatement node) {
+    ir.Expression expression = visitForValue(node.expression);
+    List<ir.SwitchCase> cases = <ir.SwitchCase>[];
+    for (SwitchCase caseNode in node.cases.nodes) {
+      cases.add(caseNode.accept(this));
+      JumpTarget jumpTarget = elements.getTargetDefinition(caseNode);
+      if (jumpTarget != null) {
+        assert(jumpTarget.isContinueTarget);
+        assert(!continueSwitchTargets.containsKey(jumpTarget));
+        continueSwitchTargets[jumpTarget] = cases.last;
+      }
+    }
+
+    Iterator<ir.SwitchCase> casesIterator = cases.iterator;
+    for (Link<Node> link = node.cases.nodes;
+        link.isNotEmpty;
+        link = link.tail) {
+      SwitchCase caseNode = link.head;
+      bool isLastCase = link.tail.isEmpty;
+      if (!casesIterator.moveNext()) {
+        internalError(caseNode, "case node mismatch");
+      }
+      ir.SwitchCase irCase = casesIterator.current;
+      List<ir.Statement> statements = <ir.Statement>[];
+      bool hasVariableDeclaration = false;
+      for (Statement statement in caseNode.statements.nodes) {
+        if (buildStatement(statement, statements)) {
+          hasVariableDeclaration = true;
+        }
+      }
+      if (!isLastCase &&
+          (statements.isEmpty || fallsThrough(statements.last))) {
+        statements.add(new ir.ExpressionStatement(new ir.Throw(
+            new ir.StaticInvocation(kernel.getFallThroughErrorBuilder(),
+                new ir.Arguments.empty()))));
+      }
+      ir.Statement body;
+      if (!hasVariableDeclaration && statements.length == 1) {
+        body = statements.single;
+      } else {
+        body = new ir.Block(statements);
+      }
+      irCase.body = body;
+      body.parent = irCase;
+    }
+    assert(!casesIterator.moveNext());
+
+    return buildBreakTarget(new ir.SwitchStatement(expression, cases), node,
+        elements.getTargetDefinition(node));
+  }
+
+  @override
+  ir.Statement visitSyncForIn(SyncForIn node) {
+    return buildForIn(node, isAsync: false);
+  }
+
+  @override
+  ir.Throw visitThrow(Throw node) {
+    return new ir.Throw(visitForValue(node?.expression));
+  }
+
+  @override
+  ir.Statement visitTryStatement(TryStatement node) {
+    ir.Statement result = buildStatementInBlock(node.tryBlock);
+    if (node.catchBlocks != null && !node.catchBlocks.isEmpty) {
+      List<ir.Catch> catchBlocks = <ir.Catch>[];
+      for (CatchBlock block in node.catchBlocks.nodes) {
+        catchBlocks.add(block.accept(this));
+      }
+      result = new ir.TryCatch(result, catchBlocks);
+    }
+    if (node.finallyBlock != null) {
+      result =
+          new ir.TryFinally(result, buildStatementInBlock(node.finallyBlock));
+    }
+    return buildBreakTarget(result, node, elements.getTargetDefinition(node));
+  }
+
+  @override
+  visitTypeAnnotation(TypeAnnotation node) {
+    // Shouldn't be called, as the resolver have already resolved types and
+    // created [DartType] objects.
+    return internalError(node, "TypeAnnotation");
+  }
+
+  @override
+  visitTypeVariable(TypeVariable node) {
+    // Shouldn't be called, as the resolver have already resolved types and
+    // created [DartType] objects.
+    return internalError(node, "TypeVariable");
+  }
+
+  @override
+  ir.Statement visitWhile(While node) {
+    ir.Expression condition = visitForValue(node.condition);
+    JumpTarget jumpTarget = elements.getTargetDefinition(node);
+    ir.Statement body =
+        buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget);
+    return buildBreakTarget(
+        new ir.WhileStatement(condition, body), node, jumpTarget);
+  }
+
+  @override
+  ir.YieldStatement visitYield(Yield node) {
+    return new ir.YieldStatement(visitForValue(node.expression),
+        isYieldStar: node.hasStar);
+  }
+
+  @override
+  ir.InvalidExpression visitAbstractClassConstructorInvoke(
+      NewExpression node,
+      ConstructorElement element,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return new ir.InvalidExpression();
+  }
+
+  IrFunction buildIrFunction(
+      ir.ProcedureKind kind, FunctionElement function, Node body) {
+    return new IrFunction.procedure(kind, buildFunctionNode(function, body));
+  }
+
+  @override
+  IrFunction visitAbstractGetterDeclaration(
+      FunctionExpression node, MethodElement getter, _) {
+    return buildIrFunction(ir.ProcedureKind.Getter, getter, null);
+  }
+
+  @override
+  IrFunction visitAbstractSetterDeclaration(
+      FunctionExpression node, MethodElement setter, NodeList parameters, _) {
+    return buildIrFunction(ir.ProcedureKind.Setter, setter, null);
+  }
+
+  @override
+  ir.AsExpression visitAs(Send node, Node expression, DartType type, _) {
+    return new ir.AsExpression(
+        visitForValue(expression), kernel.typeToIr(type));
+  }
+
+  @override
+  ir.MethodInvocation visitBinary(
+      Send node, Node left, BinaryOperator operator, Node right, _) {
+    return buildBinaryOperator(left, operator.selectorName, right);
+  }
+
+  ir.Expression buildConstructorInvoke(NewExpression node, {bool isConst}) {
+    ConstructorElement constructor = elements[node.send];
+    ConstructorTarget target =
+        kernel.computeEffectiveTarget(constructor, elements.getType(node));
+    NodeList arguments = node.send.argumentsNode;
+    if (kernel.isSyntheticError(target.element)) {
+      return new ir.MethodInvocation(new ir.InvalidExpression(),
+          kernel.irName("call", currentElement), buildArguments(arguments));
+    }
+    ir.InvocationExpression invoke = target.element.isGenerativeConstructor
+        ? buildGenerativeConstructorInvoke(target.element, arguments,
+            isConst: isConst)
+        : buildStaticInvoke(target.element, arguments, isConst: isConst);
+    if (target.type.isInterfaceType) {
+      InterfaceType type = target.type;
+      if (type.isGeneric) {
+        invoke.arguments.types.addAll(kernel.typesToIr(type.typeArguments));
+      }
+    }
+    return invoke;
+  }
+
+  @override
+  ir.InvocationExpression visitBoolFromEnvironmentConstructorInvoke(
+      NewExpression node, BoolFromEnvironmentConstantExpression constant, _) {
+    return buildConstructorInvoke(node, isConst: true);
+  }
+
+  ir.TypeLiteral buildTypeLiteral(TypeConstantExpression constant) {
+    return new ir.TypeLiteral(kernel.typeLiteralToIr(constant));
+  }
+
+  @override
+  ir.TypeLiteral visitClassTypeLiteralGet(
+      Send node, ConstantExpression constant, _) {
+    return buildTypeLiteral(constant);
+  }
+
+  @override
+  ir.MethodInvocation visitClassTypeLiteralInvoke(
+      Send node,
+      ConstantExpression constant,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildCall(buildTypeLiteral(constant), callStructure, arguments);
+  }
+
+  ir.Expression buildTypeLiteralSet(TypeConstantExpression constant, Node rhs) {
+    return new ReadOnlyAccessor(buildTypeLiteral(constant))
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitClassTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, _) {
+    return buildTypeLiteralSet(constant, rhs);
+  }
+
+  @override
+  ir.FunctionExpression visitClosureDeclaration(FunctionExpression node,
+      LocalFunctionElement closure, NodeList parameters, Node body, _) {
+    return withCurrentElement(closure, () {
+      return new ir.FunctionExpression(buildFunctionNode(closure, body));
+    });
+  }
+
+  @override
+  ir.Expression visitCompoundIndexSet(SendSet node, Node receiver, Node index,
+      AssignmentOperator operator, Node rhs, _) {
+    return buildIndexAccessor(receiver, index).buildCompoundAssignment(
+        kernel.irName(operator.selectorName, currentElement),
+        visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  @override
+  ir.InvocationExpression visitConstConstructorInvoke(
+      NewExpression node, ConstructedConstantExpression constant, _) {
+    return buildConstructorInvoke(node, isConst: true);
+  }
+
+  @override
+  visitConstantGet(Send node, ConstantExpression constant, _) {
+    // TODO(ahe): This method is never called. Is it a bug in semantic visitor?
+    return internalError(node, "ConstantGet");
+  }
+
+  @override
+  visitConstantInvoke(Send node, ConstantExpression constant,
+      NodeList arguments, CallStructure callStructure, _) {
+    // TODO(ahe): This method is never called. Is it a bug in semantic visitor?
+    return internalError(node, "ConstantInvoke");
+  }
+
+  @override
+  ir.InvalidExpression visitConstructorIncompatibleInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return new ir.InvalidExpression();
+  }
+
+  @override
+  ir.PropertyGet visitDynamicPropertyGet(
+      Send node, Node receiver, Name name, _) {
+    return new ir.PropertyGet(visitForValue(receiver), nameToIrName(name));
+  }
+
+  @override
+  ir.MethodInvocation visitDynamicPropertyInvoke(
+      Send node, Node receiver, NodeList arguments, Selector selector, _) {
+    return buildInvokeSelector(
+        visitForValue(receiver), selector, buildArguments(arguments));
+  }
+
+  @override
+  ir.Expression handleDynamicCompounds(
+      Send node, Node receiver, Name name, CompoundRhs rhs, _) {
+    ir.Expression receiverNode =
+        receiver == null ? new ir.ThisExpression() : visitForValue(receiver);
+    return buildCompound(
+        PropertyAccessor.make(receiverNode, nameToIrName(name)), rhs);
+  }
+
+  @override
+  ir.PropertySet visitDynamicPropertySet(
+      SendSet node, Node receiver, Name name, Node rhs, _) {
+    ir.Expression value = visitForValue(rhs);
+    return new ir.PropertySet(
+        visitForValue(receiver), nameToIrName(name), value);
+  }
+
+  @override
+  ir.Expression handleDynamicSetIfNulls(
+      Send node, Node receiver, Name name, Node rhs, _) {
+    ir.Name irName = nameToIrName(name);
+    Accessor accessor = (receiver == null)
+        ? new ThisPropertyAccessor(irName)
+        : PropertyAccessor.make(visitForValue(receiver), irName);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  @override
+  ir.TypeLiteral visitDynamicTypeLiteralGet(
+      Send node, ConstantExpression constant, _) {
+    return buildTypeLiteral(constant);
+  }
+
+  @override
+  ir.MethodInvocation visitDynamicTypeLiteralInvoke(
+      Send node,
+      ConstantExpression constant,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildCall(buildTypeLiteral(constant), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitDynamicTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, _) {
+    return buildTypeLiteralSet(constant, rhs);
+  }
+
+  ir.MethodInvocation buildBinaryOperator(
+      Node left, String operator, Node right) {
+    ir.Name name = kernel.irName(operator, currentElement);
+    return makeBinary(visitForValue(left), name, visitForValue(right));
+  }
+
+  @override
+  ir.MethodInvocation visitEquals(Send node, Node left, Node right, _) {
+    return buildBinaryOperator(left, '==', right);
+  }
+
+  @override
+  ir.MethodInvocation visitExpressionInvoke(Send node, Node expression,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(visitForValue(expression), callStructure, arguments);
+  }
+
+  @override
+  IrFunction visitFactoryConstructorDeclaration(FunctionExpression node,
+      ConstructorElement constructor, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Factory, constructor, body);
+  }
+
+  @override
+  ir.InvocationExpression visitFactoryConstructorInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildConstructorInvoke(node, isConst: false);
+  }
+
+  @override
+  ir.Initializer visitFieldInitializer(
+      SendSet node, FieldElement field, Node expression, _) {
+    if (kernel.isSyntheticError(field)) {
+      return new ir.InvalidInitializer();
+    } else {
+      return new ir.FieldInitializer(
+          kernel.fieldToIr(field), visitForValue(expression));
+    }
+  }
+
+  ir.Expression buildStaticFieldSet(FieldElement field, Node rhs) {
+    return buildStaticAccessor(field)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression handleFinalStaticFieldSet(
+      SendSet node, FieldElement field, Node rhs, _) {
+    return buildStaticFieldSet(field, rhs);
+  }
+
+  @override
+  ir.Expression visitFinalSuperFieldSet(
+      SendSet node, FieldElement field, Node rhs, _) {
+    return buildSuperPropertyAccessor(field)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  void addFieldsWithInitializers(
+      ConstructorElement constructor, List<ir.Initializer> initializers) {
+    constructor.enclosingClass.forEachInstanceField((_, FieldElement element) {
+      // Convert the element into the corresponding IR field before asking
+      // if the initializer exists. This is necessary to ensure that the
+      // element has been analyzed before looking at its initializer.
+      ir.Field field = kernel.fieldToIr(element);
+      if (element.initializer != null) {
+        KernelVisitor visitor =
+            new KernelVisitor(element, element.treeElements, kernel);
+        ir.Expression value = visitor.buildInitializer();
+        initializers.add(new ir.FieldInitializer(field, value));
+      }
+    });
+  }
+
+  IrFunction buildGenerativeConstructor(
+      ConstructorElement constructor, NodeList parameters, Node body) {
+    List<ir.Initializer> constructorInitializers = <ir.Initializer>[];
+    if (kernel.hasHierarchyProblem(constructor.enclosingClass)) {
+      constructorInitializers.add(new ir.InvalidInitializer());
+    } else if (constructor.isSynthesized) {
+      List<ir.Expression> arguments = const <ir.Expression>[];
+      List<ir.NamedExpression> named = const <ir.NamedExpression>[];
+      FunctionSignature signature = constructor.functionSignature;
+      if (signature.parameterCount != 0) {
+        // Mixin application implicit super call.
+        arguments = <ir.Expression>[];
+        named = <ir.NamedExpression>[];
+        signature.orderedForEachParameter((ParameterElement parameter) {
+          ir.VariableGet argument = buildLocalGet(parameter);
+          if (parameter.isNamed) {
+            named.add(new ir.NamedExpression(parameter.name, argument));
+          } else {
+            arguments.add(argument);
+          }
+        });
+      }
+      if (kernel.isSyntheticError(constructor.definingConstructor)) {
+        constructorInitializers.add(new ir.InvalidInitializer());
+      } else {
+        addFieldsWithInitializers(constructor, constructorInitializers);
+        constructorInitializers.add(new ir.SuperInitializer(
+            kernel.functionToIr(constructor.definingConstructor),
+            new ir.Arguments(arguments, named: named, types: null)));
+      }
+    } else {
+      addFieldsWithInitializers(constructor, constructorInitializers);
+      if (parameters != null) {
+        // TODO(ahe): the following is a (modified) copy of
+        // [SemanticDeclarationResolvedMixin.visitParameters].
+        List<ParameterStructure> structures =
+            computeParameterStructures(parameters);
+        for (ParameterStructure structure in structures) {
+          if (structure.parameter.isInitializingFormal) {
+            constructorInitializers.add(structure.dispatch(declVisitor, null));
+          }
+        }
+      }
+      // TODO(ahe): the following is a (modified) copy of
+      // [SemanticDeclarationResolvedMixin.visitInitializers].
+      InitializersStructure initializers =
+          computeInitializersStructure(constructor.node);
+      for (InitializerStructure structure in initializers.initializers) {
+        constructorInitializers.add(structure.dispatch(declVisitor, null));
+      }
+    }
+    return new IrFunction.constructor(
+        buildFunctionNode(constructor, body), constructorInitializers);
+  }
+
+  @override
+  IrFunction visitGenerativeConstructorDeclaration(
+      FunctionExpression node,
+      ConstructorElement constructor,
+      NodeList parameters,
+      NodeList initializers,
+      Node body,
+      _) {
+    return buildGenerativeConstructor(constructor, parameters, body);
+  }
+
+  ir.ConstructorInvocation buildGenerativeConstructorInvoke(
+      ConstructorElement constructor, NodeList arguments,
+      {bool isConst}) {
+    if (const bool.fromEnvironment("require_kernel_arguments")) {
+      // Check that all constructors from kernel/ast.dart (that are invoked
+      // from this package) provide all arguments (including optional
+      // arguments).
+      // TODO(ahe): Remove this when the implementation has matured.
+      if (("package:kernel/ast.dart" ==
+              "${constructor.library.canonicalUri}") &&
+          "${currentElement.library.canonicalUri}"
+              .startsWith("package:rasta/")) {
+        if (constructor.functionSignature.parameterCount !=
+            arguments.slowLength()) {
+          kernel.debugMessage(arguments, "Missing arguments");
+          kernel.debugMessage(constructor, "When calling the constructor");
+        }
+      }
+    }
+    ir.Arguments argumentsNode = buildArguments(arguments);
+    ir.Constructor target = kernel.functionToIr(constructor);
+    return new ir.ConstructorInvocation(target, argumentsNode,
+        isConst: isConst);
+  }
+
+  @override
+  ir.InvocationExpression visitGenerativeConstructorInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildConstructorInvoke(node, isConst: false);
+  }
+
+  Accessor buildNullAwarePropertyAccessor(Node receiver, Name name) {
+    return new NullAwarePropertyAccessor(
+        visitForValue(receiver), nameToIrName(name));
+  }
+
+  @override
+  ir.Expression visitIfNotNullDynamicPropertyGet(
+      Send node, Node receiver, Name name, _) {
+    return buildNullAwarePropertyAccessor(receiver, name).buildSimpleRead();
+  }
+
+  @override
+  ir.Let visitIfNotNullDynamicPropertyInvoke(
+      Send node, Node receiverNode, NodeList arguments, Selector selector, _) {
+    ir.VariableDeclaration receiver =
+        makeOrReuseVariable(visitForValue(receiverNode));
+    return makeLet(
+        receiver,
+        new ir.ConditionalExpression(
+            buildIsNull(new ir.VariableGet(receiver)),
+            new ir.NullLiteral(),
+            buildInvokeSelector(new ir.VariableGet(receiver), selector,
+                buildArguments(arguments))));
+  }
+
+  @override
+  ir.Expression visitIfNotNullDynamicPropertySet(
+      SendSet node, Node receiver, Name name, Node rhs, _) {
+    return buildNullAwarePropertyAccessor(receiver, name)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitIfNotNullDynamicPropertySetIfNull(
+      Send node, Node receiver, Name name, Node rhs, _) {
+    return buildNullAwarePropertyAccessor(receiver, name)
+        .buildNullAwareAssignment(visitForValue(rhs),
+            voidContext: isVoidContext);
+  }
+
+  ir.LogicalExpression buildLogicalExpression(
+      Node left, Operator operator, Node right) {
+    return new ir.LogicalExpression(
+        visitForValue(left), operator.source, visitForValue(right));
+  }
+
+  @override
+  ir.LogicalExpression visitIfNull(Send node, Node left, Node right, _) {
+    return buildLogicalExpression(left, node.selector, right);
+  }
+
+  @override
+  ir.Initializer visitImplicitSuperConstructorInvoke(FunctionExpression node,
+      ConstructorElement superConstructor, InterfaceType type, _) {
+    if (superConstructor == null) {
+      // TODO(ahe): Semantic visitor shouldn't call this.
+      return new ir.InvalidInitializer();
+    }
+    return new ir.SuperInitializer(
+        kernel.functionToIr(superConstructor), new ir.Arguments.empty());
+  }
+
+  Accessor buildIndexAccessor(Node receiver, Node index) {
+    return IndexAccessor.make(visitForValue(receiver), visitForValue(index));
+  }
+
+  @override
+  ir.Expression visitIndex(Send node, Node receiver, Node index, _) {
+    return buildIndexAccessor(receiver, index).buildSimpleRead();
+  }
+
+  ir.Expression buildIndexPostfix(Accessor accessor, IncDecOperator operator) {
+    ir.Name name = kernel.irName(operator.selectorName, currentElement);
+    return accessor.buildPostfixIncrement(name, voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitIndexPostfix(
+      Send node, Node receiver, Node index, IncDecOperator operator, _) {
+    return buildIndexPostfix(buildIndexAccessor(receiver, index), operator);
+  }
+
+  ir.Expression buildIndexPrefix(Accessor accessor, IncDecOperator operator) {
+    ir.Name name = kernel.irName(operator.selectorName, currentElement);
+    return accessor.buildPrefixIncrement(name, voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitIndexPrefix(
+      Send node, Node receiver, Node index, IncDecOperator operator, _) {
+    return buildIndexPrefix(buildIndexAccessor(receiver, index), operator);
+  }
+
+  @override
+  ir.Expression visitIndexSet(
+      SendSet node, Node receiver, Node index, Node rhs, _) {
+    return buildIndexAccessor(receiver, index)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  ir.Initializer buildInitializingFormal(InitializingFormalElement parameter) {
+    FieldElement field = parameter.fieldElement;
+    if (kernel.isSyntheticError(field)) {
+      return new ir.InvalidInitializer();
+    } else {
+      return new ir.FieldInitializer(
+          kernel.fieldToIr(field), buildLocalGet(parameter));
+    }
+  }
+
+  @override
+  ir.Initializer visitInitializingFormalDeclaration(VariableDefinitions node,
+      Node definition, InitializingFormalElement parameter, int index, _) {
+    return buildInitializingFormal(parameter);
+  }
+
+  @override
+  visitInstanceFieldDeclaration(VariableDefinitions node, Node definition,
+      FieldElement field, Node initializer, _) {
+    // Shouldn't be called, handled by fieldToIr.
+    return internalError(node, "InstanceFieldDeclaration");
+  }
+
+  @override
+  IrFunction visitInstanceGetterDeclaration(
+      FunctionExpression node, MethodElement getter, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Getter, getter, body);
+  }
+
+  @override
+  IrFunction visitInstanceSetterDeclaration(FunctionExpression node,
+      MethodElement setter, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Setter, setter, body);
+  }
+
+  @override
+  ir.InvocationExpression visitIntFromEnvironmentConstructorInvoke(
+      NewExpression node, IntFromEnvironmentConstantExpression constant, _) {
+    return buildConstructorInvoke(node, isConst: true);
+  }
+
+  ir.IsExpression buildIs(Node expression, DartType type) {
+    return new ir.IsExpression(
+        visitForValue(expression), kernel.typeToIr(type));
+  }
+
+  @override
+  ir.IsExpression visitIs(Send node, Node expression, DartType type, _) {
+    return buildIs(expression, type);
+  }
+
+  @override
+  ir.Not visitIsNot(Send node, Node expression, DartType type, _) {
+    return new ir.Not(buildIs(expression, type));
+  }
+
+  ir.VariableDeclaration buildLocalVariableDeclaration(
+      LocalVariableElement variable, Node initializer) {
+    ir.Expression initializerNode = visitForValue(initializer);
+    ir.VariableDeclaration local = getLocal(variable);
+    if (initializer != null) {
+      local.initializer = initializerNode;
+      initializerNode.parent = local;
+    }
+    return local;
+  }
+
+  @override
+  ir.VariableDeclaration visitLocalConstantDeclaration(
+      VariableDefinitions node,
+      Node definition,
+      LocalVariableElement variable,
+      ConstantExpression constant,
+      _) {
+    // TODO(ahe): Use [constant]?
+    return buildLocalVariableDeclaration(variable, variable.initializer)
+      ..isConst = true;
+  }
+
+  @override
+  ir.FunctionDeclaration visitLocalFunctionDeclaration(FunctionExpression node,
+      LocalFunctionElement localFunction, NodeList parameters, Node body, _) {
+    return withCurrentElement(localFunction, () {
+      ir.VariableDeclaration local = getLocal(localFunction)..isFinal = true;
+      return new ir.FunctionDeclaration(
+          local, buildFunctionNode(localFunction, body));
+    });
+  }
+
+  @override
+  ir.VariableDeclaration visitLocalVariableDeclaration(VariableDefinitions node,
+      Node definition, LocalVariableElement variable, Node initializer, _) {
+    return buildLocalVariableDeclaration(variable, initializer);
+  }
+
+  ir.VariableGet buildLocalGet(LocalElement local) {
+    return new ir.VariableGet(getLocal(local));
+  }
+
+  @override
+  ir.VariableGet handleLocalGet(Send node, LocalElement element, _) {
+    return buildLocalGet(element);
+  }
+
+  ir.Expression buildCompound(Accessor accessor, CompoundRhs rhs) {
+    ir.Name name = kernel.irName(rhs.operator.selectorName, currentElement);
+    switch (rhs.kind) {
+      case CompoundKind.POSTFIX:
+        return accessor.buildPostfixIncrement(name, voidContext: isVoidContext);
+
+      case CompoundKind.PREFIX:
+        return accessor.buildPrefixIncrement(name, voidContext: isVoidContext);
+
+      case CompoundKind.ASSIGNMENT:
+        return accessor.buildCompoundAssignment(name, visitForValue(rhs.rhs),
+            voidContext: isVoidContext);
+    }
+  }
+
+  @override
+  ir.Expression handleLocalCompounds(
+      SendSet node, LocalElement local, CompoundRhs rhs, _,
+      {bool isSetterValid}) {
+    return buildCompound(new VariableAccessor(getLocal(local)), rhs);
+  }
+
+  @override
+  ir.VariableSet handleLocalSet(
+      SendSet node, LocalElement element, Node rhs, _) {
+    return new ir.VariableSet(getLocal(element), visitForValue(rhs));
+  }
+
+  @override
+  ir.VariableSet handleImmutableLocalSet(
+      SendSet node, LocalElement element, Node rhs, _) {
+    // TODO(ahe): Build invalid?
+    return handleLocalSet(node, element, rhs, _);
+  }
+
+  @override
+  ir.LogicalExpression visitLogicalAnd(Send node, Node left, Node right, _) {
+    return buildLogicalExpression(left, node.selector, right);
+  }
+
+  @override
+  ir.LogicalExpression visitLogicalOr(Send node, Node left, Node right, _) {
+    return buildLogicalExpression(left, node.selector, right);
+  }
+
+  @override
+  ir.Initializer visitNamedInitializingFormalDeclaration(
+      VariableDefinitions node,
+      Node definition,
+      InitializingFormalElement parameter,
+      ConstantExpression defaultValue,
+      _) {
+    return buildInitializingFormal(parameter);
+  }
+
+  @override
+  visitNamedParameterDeclaration(VariableDefinitions node, Node definition,
+      ParameterElement parameter, ConstantExpression defaultValue, _) {
+    // Shouldn't be called, we handle parameters via [FunctionSignture].
+    return internalError(node, "NamedParameterDeclaration");
+  }
+
+  @override
+  ir.Not visitNot(Send node, Node expression, _) {
+    return new ir.Not(visitForValue(expression));
+  }
+
+  @override
+  ir.Not visitNotEquals(Send node, Node left, Node right, _) {
+    return new ir.Not(buildBinaryOperator(left, '==', right));
+  }
+
+  @override
+  ir.Initializer visitOptionalInitializingFormalDeclaration(
+      VariableDefinitions node,
+      Node definition,
+      InitializingFormalElement parameter,
+      ConstantExpression defaultValue,
+      int index,
+      _) {
+    return buildInitializingFormal(parameter);
+  }
+
+  @override
+  visitOptionalParameterDeclaration(
+      VariableDefinitions node,
+      Node definition,
+      ParameterElement parameter,
+      ConstantExpression defaultValue,
+      int index,
+      _) {
+    // Shouldn't be called, we handle parameters via [FunctionSignture].
+    return internalError(node, "OptionalParameterDeclaration");
+  }
+
+  @override
+  visitParameterDeclaration(VariableDefinitions node, Node definition,
+      ParameterElement parameter, int index, _) {
+    // Shouldn't be called, we handle parameters via [FunctionSignture].
+    return internalError(node, "ParameterDeclaration");
+  }
+
+  @override
+  ir.MethodInvocation handleLocalInvoke(Send node, LocalElement element,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(buildLocalGet(element), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression handleLocalSetIfNulls(
+      SendSet node, LocalElement local, Node rhs, _,
+      {bool isSetterValid}) {
+    return new VariableAccessor(getLocal(local)).buildNullAwareAssignment(
+        visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  @override
+  IrFunction visitRedirectingFactoryConstructorDeclaration(
+      FunctionExpression node,
+      ConstructorElement constructor,
+      NodeList parameters,
+      DartType redirectionType, // TODO(ahe): Should be InterfaceType.
+      ConstructorElement redirectionTarget,
+      _) {
+    if (!constructor.isFactoryConstructor) {
+      // TODO(ahe): This seems like a bug in semantic visitor and how it
+      // recovers from a bad constructor.
+      return new IrFunction.constructor(buildFunctionNode(constructor, null),
+          <ir.Initializer>[new ir.InvalidInitializer()]);
+    }
+    ir.Statement body = null;
+    if (kernel.isSyntheticError(redirectionTarget)) {
+      body = new ir.InvalidStatement();
+    } else {
+      // TODO(ahe): This should be implemented, but doesn't matter much unless
+      // we support reflection. At the call-site, we bypass this factory and
+      // call its effective target directly. So this factory is only necessary
+      // for reflection.
+      body = new ir.InvalidStatement();
+    }
+    IrFunction function =
+        buildIrFunction(ir.ProcedureKind.Factory, constructor, null);
+    function.node.body = body..parent = function.node;
+    return function;
+  }
+
+  @override
+  ir.InvocationExpression visitRedirectingFactoryConstructorInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      ConstructorElement effectiveTarget,
+      InterfaceType effectiveTargetType,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildConstructorInvoke(node, isConst: false);
+  }
+
+  @override
+  IrFunction visitRedirectingGenerativeConstructorDeclaration(
+      FunctionExpression node,
+      ConstructorElement constructor,
+      NodeList parameters,
+      NodeList initializers,
+      _) {
+    return buildGenerativeConstructor(constructor, parameters, null);
+  }
+
+  @override
+  ir.InvocationExpression visitRedirectingGenerativeConstructorInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildConstructorInvoke(node, isConst: false);
+  }
+
+  @override
+  visitStaticConstantDeclaration(VariableDefinitions node, Node definition,
+      FieldElement field, ConstantExpression constant, _) {
+    // Shouldn't be called, handled by fieldToIr.
+    return internalError(node, "StaticConstantDeclaration");
+  }
+
+  @override
+  visitStaticFieldDeclaration(VariableDefinitions node, Node definition,
+      FieldElement field, Node initializer, _) {
+    // Shouldn't be called, handled by fieldToIr.
+    return internalError(node, "StaticFieldDeclaration");
+  }
+
+  ir.Expression buildStaticGet(Element element) {
+    return buildStaticAccessor(element).buildSimpleRead();
+  }
+
+  @override
+  ir.Expression handleStaticFieldGet(Send node, FieldElement field, _) {
+    return buildStaticGet(field);
+  }
+
+  @override
+  ir.MethodInvocation handleStaticFieldInvoke(Send node, FieldElement field,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(buildStaticGet(field), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression handleStaticFieldSet(
+      SendSet node, FieldElement field, Node rhs, _) {
+    return buildStaticFieldSet(field, rhs);
+  }
+
+  @override
+  ir.Expression handleStaticSetIfNulls(
+      SendSet node,
+      Element getter,
+      CompoundGetter getterKind,
+      Element setter,
+      CompoundSetter setterKind,
+      Node rhs,
+      _) {
+    if (setterKind == CompoundSetter.INVALID) {
+      setter = null;
+    }
+    return buildStaticAccessor(getter, setter).buildNullAwareAssignment(
+        visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  ir.VariableDeclaration getLocal(LocalElement local) {
+    return locals.putIfAbsent(local, () {
+      return associate(
+          new ir.VariableDeclaration(local.name,
+              initializer: null,
+              type: typeToIrHack(local.type),
+              isFinal: local.isFinal,
+              isConst: local.isConst),
+          local);
+    });
+  }
+
+  ir.FunctionNode buildFunctionNode(FunctionElement function, Node bodyNode) {
+    List<ir.TypeParameter> typeParameters =
+        kernel.typeParametersNotImplemented();
+    List<ir.VariableDeclaration> positionalParameters =
+        <ir.VariableDeclaration>[];
+    List<ir.VariableDeclaration> namedParameters = <ir.VariableDeclaration>[];
+    int requiredParameterCount = 0;
+    ir.DartType returnType = const ir.DynamicType();
+    if (function.hasFunctionSignature) {
+      FunctionSignature signature = function.functionSignature;
+      requiredParameterCount = signature.requiredParameterCount;
+      signature.forEachParameter((ParameterElement parameter) {
+        ir.VariableDeclaration variable = getLocal(parameter);
+        if (parameter.isNamed) {
+          namedParameters.add(variable);
+        } else {
+          positionalParameters.add(variable);
+        }
+      });
+      signature.forEachParameter((ParameterElement parameter) {
+        if (!parameter.isOptional) return;
+        ir.Expression initializer = visitForValue(parameter.initializer);
+        ir.VariableDeclaration variable = getLocal(parameter);
+        if (initializer != null) {
+          variable.initializer = initializer;
+          initializer.parent = variable;
+        }
+      });
+      returnType = typeToIrHack(signature.type.returnType);
+      if (function.isFactoryConstructor) {
+        InterfaceType type = function.enclosingClass.thisType;
+        if (type.isGeneric) {
+          typeParameters = new List<ir.TypeParameter>();
+          for (DartType parameter in type.typeArguments) {
+            typeParameters.add(kernel.typeVariableToIr(parameter.element));
+          }
+        }
+      }
+    }
+    ir.AsyncMarker asyncMarker = ir.AsyncMarker.Sync;
+    if (!kernel.isSyntheticError(function)) {
+      switch (function.asyncMarker) {
+        case AsyncMarker.SYNC:
+          asyncMarker = ir.AsyncMarker.Sync;
+          break;
+
+        case AsyncMarker.SYNC_STAR:
+          asyncMarker = ir.AsyncMarker.SyncStar;
+          break;
+
+        case AsyncMarker.ASYNC:
+          asyncMarker = ir.AsyncMarker.Async;
+          break;
+
+        case AsyncMarker.ASYNC_STAR:
+          asyncMarker = ir.AsyncMarker.AsyncStar;
+          break;
+
+        default:
+          internalError(
+              function, "Unknown async maker: ${function.asyncMarker}");
+          break;
+      }
+    }
+    ir.Statement body =
+        (bodyNode == null) ? null : buildStatementInBlock(bodyNode);
+    return associate(
+        new ir.FunctionNode(body,
+            asyncMarker: asyncMarker,
+            returnType: returnType,
+            typeParameters: typeParameters,
+            positionalParameters: positionalParameters,
+            namedParameters: namedParameters,
+            requiredParameterCount: requiredParameterCount),
+        function);
+  }
+
+  @override
+  IrFunction visitStaticFunctionDeclaration(FunctionExpression node,
+      MethodElement function, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Method, function, body);
+  }
+
+  ir.ProcedureKind computeInstanceMethodKind(MethodElement method) {
+    assert(method.isFunction);
+    return method.isOperator
+        ? ir.ProcedureKind.Operator
+        : ir.ProcedureKind.Method;
+  }
+
+  @override
+  IrFunction visitInstanceMethodDeclaration(FunctionExpression node,
+      MethodElement method, NodeList parameters, Node body, _) {
+    return buildIrFunction(
+        computeInstanceMethodKind(currentElement), currentElement, body);
+  }
+
+  @override
+  IrFunction visitAbstractMethodDeclaration(
+      FunctionExpression node, MethodElement method, NodeList parameters, _) {
+    return buildIrFunction(
+        computeInstanceMethodKind(currentElement), currentElement, null);
+  }
+
+  @override
+  ir.Expression handleStaticFunctionGet(Send node, MethodElement function, _) {
+    return buildStaticGet(function);
+  }
+
+  @override
+  ir.StaticInvocation handleStaticFunctionIncompatibleInvoke(
+      Send node,
+      MethodElement function,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildStaticInvoke(function, arguments, isConst: false);
+  }
+
+  ir.StaticInvocation buildStaticInvoke(
+      FunctionElement function, NodeList arguments,
+      {bool isConst}) {
+    ir.Arguments argumentsNode = buildArguments(arguments);
+    return new ir.StaticInvocation(kernel.functionToIr(function), argumentsNode,
+        isConst: isConst);
+  }
+
+  @override
+  ir.StaticInvocation handleStaticFunctionInvoke(
+      Send node,
+      MethodElement function,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildStaticInvoke(function, arguments, isConst: false);
+  }
+
+  @override
+  ir.Expression handleStaticFunctionSet(
+      Send node, MethodElement function, Node rhs, _) {
+    return buildStaticAccessor(function)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  IrFunction visitStaticGetterDeclaration(
+      FunctionExpression node, MethodElement getter, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Getter, getter, body);
+  }
+
+  @override
+  ir.Expression handleStaticGetterGet(Send node, FunctionElement getter, _) {
+    if (getter.isDeferredLoaderGetter) {
+      // TODO(ahe): Support deferred load.
+      return new ir.InvalidExpression();
+    }
+    return buildStaticGet(getter);
+  }
+
+  @override
+  ir.Expression handleStaticGetterInvoke(Send node, FunctionElement getter,
+      NodeList arguments, CallStructure callStructure, _) {
+    if (getter.isDeferredLoaderGetter) {
+      // TODO(ahe): Support deferred load.
+      return new ir.InvalidExpression();
+    }
+    return buildCall(buildStaticGet(getter), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression handleStaticGetterSet(
+      SendSet node, FunctionElement getter, Node rhs, _) {
+    return buildStaticAccessor(getter)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  IrFunction visitStaticSetterDeclaration(FunctionExpression node,
+      MethodElement setter, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Setter, setter, body);
+  }
+
+  @override
+  ir.Expression handleStaticSetterGet(Send node, FunctionElement setter, _) {
+    return buildStaticAccessor(null, setter).buildSimpleRead();
+  }
+
+  @override
+  ir.MethodInvocation handleStaticSetterInvoke(
+      Send node,
+      FunctionElement setter,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildCall(buildStaticAccessor(null, setter).buildSimpleRead(),
+        callStructure, arguments);
+  }
+
+  @override
+  ir.Expression handleStaticSetterSet(
+      SendSet node, FunctionElement setter, Node rhs, _) {
+    return buildStaticAccessor(null, setter)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.InvocationExpression visitStringFromEnvironmentConstructorInvoke(
+      NewExpression node, StringFromEnvironmentConstantExpression constant, _) {
+    return buildConstructorInvoke(node, isConst: true);
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperBinary(Send node, FunctionElement function,
+      BinaryOperator operator, Node argument, _) {
+    return new ir.SuperMethodInvocation(kernel.functionToIr(function),
+        new ir.Arguments(<ir.Expression>[visitForValue(argument)]));
+  }
+
+  @override
+  ir.Expression visitSuperCompoundIndexSet(
+      SendSet node,
+      MethodElement getter,
+      MethodElement setter,
+      Node index,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    return buildSuperIndexAccessor(index, getter, setter)
+        .buildCompoundAssignment(
+            kernel.irName(operator.selectorName, currentElement),
+            visitForValue(rhs),
+            voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Initializer visitSuperConstructorInvoke(
+      Send node,
+      ConstructorElement superConstructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    if (kernel.isSyntheticError(superConstructor)) {
+      // TODO(ahe): Semantic visitor shouldn't call in this case.
+      return new ir.InvalidInitializer();
+    }
+    return new ir.SuperInitializer(
+        kernel.functionToIr(superConstructor), buildArguments(arguments));
+  }
+
+  ir.SuperMethodInvocation buildSuperEquals(
+      FunctionElement function, Node argument) {
+    return new ir.SuperMethodInvocation(
+        kernel.functionToIr(function),
+        new ir.Arguments(<ir.Expression>[visitForValue(argument)],
+            types: null, named: null));
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperEquals(
+      Send node, FunctionElement function, Node argument, _) {
+    return buildSuperEquals(function, argument);
+  }
+
+  @override
+  ir.Expression handleSuperCompounds(
+      SendSet node,
+      Element getter,
+      CompoundGetter getterKind,
+      Element setter,
+      CompoundSetter setterKind,
+      CompoundRhs rhs,
+      _) {
+    if (setterKind == CompoundSetter.INVALID) {
+      setter = null;
+    }
+    return buildCompound(buildSuperPropertyAccessor(getter, setter), rhs);
+  }
+
+  @override
+  ir.Expression handleStaticCompounds(
+      SendSet node,
+      Element getter,
+      CompoundGetter getterKind,
+      Element setter,
+      CompoundSetter setterKind,
+      CompoundRhs rhs,
+      _) {
+    if (setterKind == CompoundSetter.INVALID) {
+      setter = null;
+    }
+    return buildCompound(buildStaticAccessor(getter, setter), rhs);
+  }
+
+  @override
+  ir.Expression handleTypeLiteralConstantCompounds(
+      SendSet node, ConstantExpression constant, CompoundRhs rhs, _) {
+    return buildCompound(new ReadOnlyAccessor(buildTypeLiteral(constant)), rhs);
+  }
+
+  ir.TypeLiteral buildTypeVariable(TypeVariableElement element) {
+    return new ir.TypeLiteral(kernel.typeToIr(element.type));
+  }
+
+  @override
+  ir.Expression handleTypeVariableTypeLiteralCompounds(
+      SendSet node, TypeVariableElement element, CompoundRhs rhs, _) {
+    return buildCompound(new ReadOnlyAccessor(buildTypeVariable(element)), rhs);
+  }
+
+  @override
+  ir.SuperPropertyGet visitSuperFieldGet(Send node, FieldElement field, _) {
+    return buildSuperPropertyAccessor(field).buildSimpleRead();
+  }
+
+  @override
+  ir.MethodInvocation visitSuperFieldInvoke(Send node, FieldElement field,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(buildSuperPropertyAccessor(field).buildSimpleRead(),
+        callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitSuperFieldSet(
+      SendSet node, FieldElement field, Node rhs, _) {
+    return buildSuperPropertyAccessor(field)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  Accessor buildSuperPropertyAccessor(Element getter, [Element setter]) {
+    if (setter == null &&
+        getter.isField &&
+        !getter.isFinal &&
+        !getter.isConst) {
+      setter = getter;
+    }
+    return new SuperPropertyAccessor(
+        (getter == null) ? null : kernel.elementToIr(getter),
+        (setter == null) ? null : kernel.elementToIr(setter));
+  }
+
+  Accessor buildSuperIndexAccessor(Expression index, Element getter,
+      [Element setter]) {
+    if (setter == null &&
+        getter.isField &&
+        !getter.isFinal &&
+        !getter.isConst) {
+      setter = getter;
+    }
+    return new SuperIndexAccessor(
+        visitForValue(index),
+        (getter == null) ? null : kernel.elementToIr(getter),
+        (setter == null) ? null : kernel.elementToIr(setter));
+  }
+
+  @override
+  ir.SuperPropertyGet visitSuperGetterGet(
+      Send node, FunctionElement getter, _) {
+    return buildSuperPropertyAccessor(getter).buildSimpleRead();
+  }
+
+  @override
+  ir.MethodInvocation visitSuperGetterInvoke(Send node, FunctionElement getter,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(buildSuperPropertyAccessor(getter).buildSimpleRead(),
+        callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitSuperGetterSet(
+      SendSet node, FunctionElement getter, Node rhs, _) {
+    return buildSuperPropertyAccessor(getter)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression handleSuperSetIfNulls(
+      SendSet node,
+      Element getter,
+      CompoundGetter getterKind,
+      Element setter,
+      CompoundSetter setterKind,
+      Node rhs,
+      _) {
+    if (setterKind == CompoundSetter.INVALID) {
+      setter = null;
+    }
+    return buildSuperPropertyAccessor(getter, setter).buildNullAwareAssignment(
+        visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperIndex(
+      Send node, FunctionElement function, Node index, _) {
+    return buildSuperIndexAccessor(index, function).buildSimpleRead();
+  }
+
+  @override
+  ir.Expression visitSuperIndexPostfix(Send node, MethodElement indexFunction,
+      MethodElement indexSetFunction, Node index, IncDecOperator operator, _) {
+    Accessor accessor =
+        buildSuperIndexAccessor(index, indexFunction, indexSetFunction);
+    return buildIndexPostfix(accessor, operator);
+  }
+
+  @override
+  ir.Expression visitSuperIndexPrefix(Send node, MethodElement indexFunction,
+      MethodElement indexSetFunction, Node index, IncDecOperator operator, _) {
+    Accessor accessor =
+        buildSuperIndexAccessor(index, indexFunction, indexSetFunction);
+    return buildIndexPrefix(accessor, operator);
+  }
+
+  @override
+  ir.Expression visitSuperIndexSet(
+      SendSet node, FunctionElement function, Node index, Node rhs, _) {
+    return buildSuperIndexAccessor(index, null, function)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitSuperMethodGet(Send node, MethodElement method, _) {
+    return buildSuperPropertyAccessor(method).buildSimpleRead();
+  }
+
+  ir.SuperMethodInvocation buildSuperMethodInvoke(
+      MethodElement method, NodeList arguments) {
+    return new ir.SuperMethodInvocation(
+        kernel.functionToIr(method), buildArguments(arguments));
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperMethodIncompatibleInvoke(
+      Send node,
+      MethodElement method,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildSuperMethodInvoke(method, arguments);
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperMethodInvoke(
+      Send node,
+      MethodElement method,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildSuperMethodInvoke(method, arguments);
+  }
+
+  @override
+  ir.Expression visitSuperMethodSet(
+      Send node, MethodElement method, Node rhs, _) {
+    return buildSuperPropertyAccessor(method)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Not visitSuperNotEquals(
+      Send node, FunctionElement function, Node argument, _) {
+    return new ir.Not(buildSuperEquals(function, argument));
+  }
+
+  @override
+  ir.Expression visitSuperSetterGet(Send node, FunctionElement setter, _) {
+    return buildSuperPropertyAccessor(null, setter).buildSimpleRead();
+  }
+
+  @override
+  ir.MethodInvocation visitSuperSetterInvoke(Send node, FunctionElement setter,
+      NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(buildSuperPropertyAccessor(null, setter).buildSimpleRead(),
+        callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitSuperSetterSet(
+      SendSet node, FunctionElement setter, Node rhs, _) {
+    return buildSuperPropertyAccessor(null, setter)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.SuperMethodInvocation visitSuperUnary(
+      Send node, UnaryOperator operator, FunctionElement function, _) {
+    return new ir.SuperMethodInvocation(
+        kernel.functionToIr(function), new ir.Arguments.empty());
+  }
+
+  @override
+  ir.Initializer visitThisConstructorInvoke(
+      Send node,
+      ConstructorElement thisConstructor,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    if (kernel.isSyntheticError(thisConstructor)) {
+      return new ir.InvalidInitializer();
+    } else {
+      return new ir.RedirectingInitializer(
+          kernel.functionToIr(thisConstructor), buildArguments(arguments));
+    }
+  }
+
+  @override
+  ir.ThisExpression visitThisGet(Identifier node, _) {
+    return new ir.ThisExpression();
+  }
+
+  @override
+  ir.MethodInvocation visitThisInvoke(
+      Send node, NodeList arguments, CallStructure callStructure, _) {
+    return buildCall(new ir.ThisExpression(), callStructure, arguments);
+  }
+
+  Accessor buildThisPropertyAccessor(Name name) {
+    return new ThisPropertyAccessor(nameToIrName(name));
+  }
+
+  @override
+  ir.Expression visitThisPropertyGet(Send node, Name name, _) {
+    return buildThisPropertyAccessor(name).buildSimpleRead();
+  }
+
+  @override
+  ir.MethodInvocation visitThisPropertyInvoke(
+      Send node, NodeList arguments, Selector selector, _) {
+    return buildInvokeSelector(
+        new ir.ThisExpression(), selector, buildArguments(arguments));
+  }
+
+  @override
+  ir.Expression visitThisPropertySet(SendSet node, Name name, Node rhs, _) {
+    return buildThisPropertyAccessor(name)
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitTopLevelConstantDeclaration(VariableDefinitions node,
+      Node definition, FieldElement field, ConstantExpression constant, _) {
+    // Shouldn't be called, handled by fieldToIr.
+    return internalError(node, "TopLevelFieldDeclaration");
+  }
+
+  @override
+  ir.Expression visitTopLevelFieldDeclaration(VariableDefinitions node,
+      Node definition, FieldElement field, Node initializer, _) {
+    // Shouldn't be called, handled by fieldToIr.
+    return internalError(node, "TopLevelFieldDeclaration");
+  }
+
+  @override
+  IrFunction visitTopLevelFunctionDeclaration(FunctionExpression node,
+      MethodElement function, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Method, function, body);
+  }
+
+  ir.Arguments buildArguments(NodeList arguments) {
+    List<ir.Expression> positional = <ir.Expression>[];
+    List<ir.NamedExpression> named = <ir.NamedExpression>[];
+    for (Expression expression in arguments.nodes) {
+      ir.TreeNode argument = visitForValue(expression);
+      if (argument is ir.NamedExpression) {
+        named.add(argument);
+      } else {
+        positional.add(argument);
+      }
+    }
+    return new ir.Arguments(positional, named: named, types: null);
+  }
+
+  @override
+  IrFunction visitTopLevelGetterDeclaration(
+      FunctionExpression node, MethodElement getter, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Getter, getter, body);
+  }
+
+  @override
+  IrFunction visitTopLevelSetterDeclaration(FunctionExpression node,
+      MethodElement setter, NodeList parameters, Node body, _) {
+    return buildIrFunction(ir.ProcedureKind.Setter, setter, body);
+  }
+
+  @override
+  ir.TypeLiteral visitTypeVariableTypeLiteralGet(
+      Send node, TypeVariableElement element, _) {
+    return buildTypeVariable(element);
+  }
+
+  @override
+  ir.MethodInvocation visitTypeVariableTypeLiteralInvoke(
+      Send node,
+      TypeVariableElement element,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildCall(buildTypeVariable(element), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitTypeVariableTypeLiteralSet(
+      SendSet node, TypeVariableElement element, Node rhs, _) {
+    return new ReadOnlyAccessor(buildTypeVariable(element))
+        .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitTypeVariableTypeLiteralSetIfNull(
+      Send node, TypeVariableElement element, Node rhs, _) {
+    return new ReadOnlyAccessor(buildTypeVariable(element))
+        .buildNullAwareAssignment(visitForValue(rhs),
+            voidContext: isVoidContext);
+  }
+
+  @override
+  ir.TypeLiteral visitTypedefTypeLiteralGet(
+      Send node, ConstantExpression constant, _) {
+    return buildTypeLiteral(constant);
+  }
+
+  @override
+  ir.MethodInvocation visitTypedefTypeLiteralInvoke(
+      Send node,
+      ConstantExpression constant,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    return buildCall(buildTypeLiteral(constant), callStructure, arguments);
+  }
+
+  @override
+  ir.Expression visitTypedefTypeLiteralSet(
+      SendSet node, ConstantExpression constant, Node rhs, _) {
+    return buildTypeLiteralSet(constant, rhs);
+  }
+
+  @override
+  ir.Expression handleTypeLiteralConstantSetIfNulls(
+      SendSet node, ConstantExpression constant, Node rhs, _) {
+    // Degenerate case: ignores [rhs] as a type literal is never null.
+    return buildTypeLiteral(constant);
+  }
+
+  @override
+  ir.MethodInvocation visitUnary(
+      Send node, UnaryOperator operator, Node expression, _) {
+    return new ir.MethodInvocation(
+        visitForValue(expression),
+        kernel.irName(operator.selectorName, currentElement),
+        new ir.Arguments.empty());
+  }
+
+  @override
+  visitConditionalUri(ConditionalUri node) {
+    // Shouldn't be called, handled by library loader.
+    return internalError(node, "ConditionalUri");
+  }
+
+  @override
+  visitDottedName(DottedName node) {
+    // Shouldn't be called, handled by library loader.
+    return internalError(node, "DottedName");
+  }
+
+  @override
+  visitForIn(ForIn node) {
+    // Shouldn't be called, handled by [visitAsyncForIn] or [visitSyncForIn].
+    return internalError(node, "ForIn");
+  }
+
+  @override
+  ir.Expression visitIndexSetIfNull(
+      SendSet node, Node receiver, Node index, Node rhs, _) {
+    return buildIndexAccessor(receiver, index).buildNullAwareAssignment(
+        visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter,
+      MethodElement setter, Node index, Node rhs, _) {
+    return buildSuperIndexAccessor(index, getter, setter)
+        .buildNullAwareAssignment(visitForValue(rhs),
+            voidContext: isVoidContext);
+  }
+
+  @override
+  ir.Node visitVariableDefinitions(VariableDefinitions definitions) {
+    // TODO(ahe): This method is copied from [SemanticDeclarationResolvedMixin]
+    // and modified. Perhaps we can find a way to avoid code duplication.
+    List<ir.VariableDeclaration> variables = <ir.VariableDeclaration>[];
+    computeVariableStructures(definitions,
+        (Node node, VariableStructure structure) {
+      if (structure == null) {
+        return internalError(node, 'No structure for $node');
+      } else {
+        ir.VariableDeclaration variable =
+            structure.dispatch(declVisitor, node, null);
+        variables.add(variable);
+        return variable;
+      }
+    });
+    if (variables.length == 1) return variables.single;
+    return new VariableDeclarations(variables);
+  }
+
+  IrFunction buildFunction() {
+    return kernel.compiler.reporter.withCurrentElement(currentElement, () {
+      if (kernel.isSyntheticError(currentElement)) {
+        kernel.internalError(currentElement,
+            "Can't build synthetic function element: $currentElement");
+      } else if (currentElement.isMalformed) {
+        ir.FunctionNode node = buildFunctionNode(currentElement, null);
+        if (currentElement.isGenerativeConstructor) {
+          return new IrFunction.constructor(
+              node, <ir.Initializer>[new ir.InvalidInitializer()]);
+        } else {
+          node.body = new ir.InvalidStatement()..parent = node;
+          return new IrFunction.procedure(ir.ProcedureKind.Method, node);
+        }
+      } else if (currentElement.isSynthesized) {
+        if (currentElement.isGenerativeConstructor) {
+          return buildGenerativeConstructor(currentElement, null, null);
+        } else {
+          return internalError(currentElement, "Unhandled synthetic function.");
+        }
+      } else {
+        Node node = currentElement.node;
+        if (node.isErroneous) {
+          return internalError(currentElement, "Unexpected syntax error.");
+        } else {
+          return node.accept(this);
+        }
+      }
+    });
+  }
+
+  ir.Expression buildInitializer() {
+    return kernel.compiler.reporter.withCurrentElement(currentElement, () {
+      FieldElement field = currentElement;
+      return field.isMalformed
+          ? new ir.InvalidExpression()
+          : visitForValue(field.initializer);
+    });
+  }
+}
+
+class VariableDeclarations implements ir.Node {
+  final List<ir.VariableDeclaration> variables;
+
+  VariableDeclarations(this.variables);
+
+  accept(ir.Visitor v) => throw "unsupported";
+
+  visitChildren(ir.Visitor v) => throw "unsupported";
+
+  String toString() => "VariableDeclarations($variables)";
+}
+
+class IrFunction implements ir.Node {
+  final ir.ProcedureKind kind;
+  final bool isConstructor;
+  final ir.FunctionNode node;
+  final List<ir.Initializer> initializers;
+
+  IrFunction(this.kind, this.isConstructor, this.node, this.initializers);
+
+  IrFunction.procedure(ir.ProcedureKind kind, ir.FunctionNode node)
+      : this(kind, false, node, null);
+
+  IrFunction.constructor(
+      ir.FunctionNode node, List<ir.Initializer> initializers)
+      : this(null, true, node, initializers);
+
+  accept(ir.Visitor v) => throw "unsupported";
+
+  visitChildren(ir.Visitor v) => throw "unsupported";
+
+  String toString() {
+    return "IrFunction($kind, $isConstructor, $node, $initializers)";
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/unavailable.dart b/pkg/compiler/lib/src/kernel/unavailable.dart
new file mode 100644
index 0000000..d97f76c
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/unavailable.dart
@@ -0,0 +1,133 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import "../tree/tree.dart"
+    show
+        AsyncModifier,
+        ClassNode,
+        Combinator,
+        Export,
+        Expression,
+        GotoStatement,
+        Import,
+        LibraryDependency,
+        LibraryName,
+        LibraryTag,
+        Literal,
+        Loop,
+        MixinApplication,
+        Modifiers,
+        NamedMixinApplication,
+        Node,
+        NodeList,
+        Part,
+        PartOf,
+        Postfix,
+        Prefix,
+        Statement,
+        StringInterpolationPart,
+        StringNode,
+        Typedef;
+
+abstract class UnavailableVisitor {
+  void visitNode(Node node) {
+    throw "No RAST available for Node";
+  }
+
+  void visitAsyncModifier(AsyncModifier node) {
+    throw "No RAST available for AsyncModifier";
+  }
+
+  void visitClassNode(ClassNode node) {
+    throw "No RAST available for ClassNode";
+  }
+
+  void visitCombinator(Combinator node) {
+    throw "No RAST available for Combinator";
+  }
+
+  void visitExport(Export node) {
+    throw "No RAST available for Export";
+  }
+
+  void visitExpression(Expression node) {
+    throw "No RAST available for Expression";
+  }
+
+  void visitGotoStatement(GotoStatement node) {
+    throw "No RAST available for GotoStatement";
+  }
+
+  void visitImport(Import node) {
+    throw "No RAST available for Import";
+  }
+
+  void visitLibraryDependency(LibraryDependency node) {
+    throw "No RAST available for LibraryDependency";
+  }
+
+  void visitLibraryName(LibraryName node) {
+    throw "No RAST available for LibraryName";
+  }
+
+  void visitLibraryTag(LibraryTag node) {
+    throw "No RAST available for LibraryTag";
+  }
+
+  void visitLiteral(Literal node) {
+    throw "No RAST available for Literal";
+  }
+
+  void visitLoop(Loop node) {
+    throw "No RAST available for Loop";
+  }
+
+  void visitMixinApplication(MixinApplication node) {
+    throw "No RAST available for MixinApplication";
+  }
+
+  void visitModifiers(Modifiers node) {
+    throw "No RAST available for Modifiers";
+  }
+
+  void visitNamedMixinApplication(NamedMixinApplication node) {
+    throw "No RAST available for NamedMixinApplication";
+  }
+
+  void visitNodeList(NodeList node) {
+    throw "No RAST available for NodeList";
+  }
+
+  void visitPart(Part node) {
+    throw "No RAST available for Part";
+  }
+
+  void visitPartOf(PartOf node) {
+    throw "No RAST available for PartOf";
+  }
+
+  void visitPostfix(Postfix node) {
+    throw "No RAST available for Postfix";
+  }
+
+  void visitPrefix(Prefix node) {
+    throw "No RAST available for Prefix";
+  }
+
+  void visitStatement(Statement node) {
+    throw "No RAST available for Statement";
+  }
+
+  void visitStringNode(StringNode node) {
+    throw "No RAST available for StringNode";
+  }
+
+  void visitStringInterpolationPart(StringInterpolationPart node) {
+    throw "No RAST available for StringInterpolationPart";
+  }
+
+  void visitTypedef(Typedef node) {
+    throw "No RAST available for Typedef";
+  }
+}
diff --git a/pkg/compiler/lib/src/kernel/unresolved.dart b/pkg/compiler/lib/src/kernel/unresolved.dart
new file mode 100644
index 0000000..167d211
--- /dev/null
+++ b/pkg/compiler/lib/src/kernel/unresolved.dart
@@ -0,0 +1,565 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' as ir;
+
+import "../dart_types.dart" show DartType, InterfaceType;
+import "../elements/elements.dart"
+    show
+        AstElement,
+        ConstructorElement,
+        Element,
+        ErroneousElement,
+        FunctionElement,
+        MethodElement;
+import "../resolution/operators.dart"
+    show AssignmentOperator, BinaryOperator, IncDecOperator, UnaryOperator;
+import "../tree/tree.dart" show Expression, NewExpression, Node, NodeList, Send;
+import "../universe/call_structure.dart" show CallStructure;
+import "../universe/selector.dart" show Selector;
+import 'accessors.dart';
+import "kernel.dart" show Kernel;
+
+abstract class UnresolvedVisitor {
+  Kernel get kernel;
+
+  // Implemented in KernelVisitor
+  AstElement get currentElement;
+  bool get isVoidContext;
+  ir.Arguments buildArguments(NodeList arguments);
+  ir.TreeNode visitForValue(Expression node);
+
+  // TODO(ahe): Delete this method.
+  ir.InvalidExpression handleUnresolved(Node node);
+
+  /// Similar to [Kernel.functionToIr] but returns null if [function] is a
+  /// synthetic function created for error recovery.
+  ir.Member possiblyErroneousFunctionToIr(FunctionElement function) {
+    return kernel.isSyntheticError(function)
+        ? null
+        : kernel.functionToIr(function);
+  }
+
+  /// Throws a [NoSuchMethodError] corresponding to a call to
+  /// [receiver].[memberName] with the arguments [callArguments].
+  ///
+  /// The exception object is built by calling [exceptionBuilder]. This should
+  /// take the same arguments as the default constructor to [NoSuchMethodError],
+  /// but the method itself may encode additional details about the call than
+  /// is possible through the public interface of NoSuchMethodError.
+  ///
+  /// Note that [callArguments] are the arguments as they occur in the attempted
+  /// call in user code -- they are not the arguments to [exceptionBuilder].
+  ///
+  /// If [candidateTarget] is given, it will provide the expected parameter
+  /// names.
+  ir.Expression buildThrowNoSuchMethodError(ir.Procedure exceptionBuilder,
+      ir.Expression receiver, String memberName, ir.Arguments callArguments,
+      [Element candidateTarget]) {
+    ir.Expression memberNameArg = new ir.SymbolLiteral(memberName);
+    ir.Expression positional = new ir.ListLiteral(callArguments.positional);
+    ir.Expression named = new ir.MapLiteral(callArguments.named.map((e) {
+      return new ir.MapEntry(new ir.SymbolLiteral(e.name), e.value);
+    }).toList());
+    if (candidateTarget is FunctionElement) {
+      // Ensure [candidateTarget] has been resolved.
+      possiblyErroneousFunctionToIr(candidateTarget);
+    }
+    ir.Expression existingArguments;
+    if (candidateTarget is FunctionElement &&
+        !kernel.isSyntheticError(candidateTarget) &&
+        candidateTarget.hasFunctionSignature) {
+      List<ir.Expression> existingArgumentsList = <ir.Expression>[];
+      candidateTarget.functionSignature.forEachParameter((param) {
+        existingArgumentsList.add(new ir.StringLiteral(param.name));
+      });
+      existingArguments = new ir.ListLiteral(existingArgumentsList);
+    } else {
+      existingArguments = new ir.NullLiteral();
+    }
+    return new ir.Throw(new ir.StaticInvocation(
+        exceptionBuilder,
+        new ir.Arguments(<ir.Expression>[
+          receiver,
+          memberNameArg,
+          positional,
+          named,
+          existingArguments
+        ])));
+  }
+
+  /// Throws a NoSuchMethodError for an unresolved getter named [name].
+  ir.Expression buildThrowUnresolvedGetter(String name,
+      [ir.Procedure exceptionBuilder]) {
+    // TODO(asgerf): We should remove this fallback, but in some cases we do
+    //   not get sufficient information to determine exactly what kind of
+    //   getter it is.
+    exceptionBuilder ??= kernel.getGenericNoSuchMethodBuilder();
+    return buildThrowNoSuchMethodError(
+        exceptionBuilder, new ir.NullLiteral(), name, new ir.Arguments.empty());
+  }
+
+  ir.Expression buildThrowUnresolvedSetter(String name, ir.Expression argument,
+      [ir.Procedure exceptionBuilder]) {
+    // TODO(asgerf): We should remove this fallback, but in some cases we do
+    //   not get sufficient information to determine exactly what kind of
+    //   setter it is.
+    exceptionBuilder ??= kernel.getGenericNoSuchMethodBuilder();
+    return buildThrowNoSuchMethodError(exceptionBuilder, new ir.NullLiteral(),
+        name, new ir.Arguments(<ir.Expression>[argument]));
+  }
+
+  ir.Expression buildThrowUnresolvedSuperGetter(String name) {
+    return buildThrowNoSuchMethodError(kernel.getUnresolvedSuperGetterBuilder(),
+        new ir.ThisExpression(), name, new ir.Arguments.empty());
+  }
+
+  ir.Expression buildThrowUnresolvedSuperSetter(
+      String name, ir.Expression argument) {
+    return buildThrowNoSuchMethodError(
+        kernel.getUnresolvedSuperSetterBuilder(),
+        new ir.ThisExpression(),
+        name,
+        new ir.Arguments(<ir.Expression>[argument]));
+  }
+
+  ir.Expression buildThrowSingleArgumentError(
+      ir.Procedure exceptionBuilder, String errorMessage) {
+    return new ir.Throw(new ir.StaticInvocation(exceptionBuilder,
+        new ir.Arguments(<ir.Expression>[new ir.StringLiteral(errorMessage)])));
+  }
+
+  ir.Expression visitUnresolvedClassConstructorInvoke(
+      NewExpression node,
+      ErroneousElement element,
+      DartType type,
+      NodeList arguments,
+      Selector selector,
+      _) {
+    // TODO(asgerf): The VM includes source information as part of the error
+    //   message.  We could do the same when we add source maps.
+    return buildThrowSingleArgumentError(
+        kernel.getMalformedTypeErrorBuilder(), element.message);
+  }
+
+  ir.Expression visitUnresolvedConstructorInvoke(
+      NewExpression node,
+      Element constructor,
+      DartType type,
+      NodeList arguments,
+      Selector selector,
+      _) {
+    ir.Expression receiver = new ir.TypeLiteral(kernel.interfaceTypeToIr(type));
+    String methodName =
+        node.send.selector != null ? '${node.send.selector}' : type.name;
+    return buildThrowNoSuchMethodError(kernel.getUnresolvedConstructorBuilder(),
+        receiver, methodName, buildArguments(arguments), constructor);
+  }
+
+  ir.Expression visitUnresolvedCompound(
+      Send node, Element element, AssignmentOperator operator, Node rhs, _) {
+    return buildThrowUnresolvedGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedGet(Send node, Element element, _) {
+    return buildThrowUnresolvedGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedInvoke(
+      Send node, Element element, NodeList arguments, Selector selector, _) {
+    // TODO(asgerf): Should we use a type literal as receiver for unresolved
+    //   static invocations?
+    return buildThrowNoSuchMethodError(kernel.getGenericNoSuchMethodBuilder(),
+        new ir.NullLiteral(), element.name, buildArguments(arguments), element);
+  }
+
+  ir.Expression visitUnresolvedPostfix(
+      Send node, Element element, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedPrefix(
+      Send node, Element element, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedRedirectingFactoryConstructorInvoke(
+      NewExpression node,
+      ConstructorElement constructor,
+      InterfaceType type,
+      NodeList arguments,
+      CallStructure callStructure,
+      _) {
+    // The body of the factory will throw an error.
+    return new ir.StaticInvocation(
+        possiblyErroneousFunctionToIr(constructor), buildArguments(arguments));
+  }
+
+  ir.Expression visitUnresolvedSet(Send node, Element element, Node rhs, _) {
+    return buildThrowUnresolvedSetter('${node.selector}', visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSetIfNull(
+      Send node, Element element, Node rhs, _) {
+    return buildThrowUnresolvedGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedStaticGetterCompound(Send node, Element element,
+      MethodElement setter, AssignmentOperator operator, Node rhs, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedStaticGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedStaticGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedStaticGetterSetIfNull(
+      Send node, Element element, MethodElement setter, Node rhs, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedStaticSetterCompound(
+      Send node,
+      MethodElement getter,
+      Element element,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    return buildThrowUnresolvedSetter('${node.selector}', visitForValue(rhs),
+        kernel.getUnresolvedStaticSetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedStaticSetterPostfix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new ClassStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPostfixIncrement(new ir.Name(operator.selectorName),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedStaticSetterPrefix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new ClassStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPrefixIncrement(new ir.Name(operator.selectorName),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedStaticSetterSetIfNull(
+      Send node, MethodElement getter, Element element, Node rhs, _) {
+    var accessor = new ClassStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedSuperBinary(
+      Send node, Element element, BinaryOperator operator, Node argument, _) {
+    return buildThrowNoSuchMethodError(
+        kernel.getUnresolvedSuperMethodBuilder(),
+        new ir.ThisExpression(),
+        operator.selectorName,
+        new ir.Arguments(<ir.Expression>[visitForValue(argument)]));
+  }
+
+  ir.Expression visitUnresolvedSuperCompound(
+      Send node, Element element, AssignmentOperator operator, Node rhs, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperCompoundIndexSet(Send node, Element element,
+      Node index, AssignmentOperator operator, Node rhs, _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index),
+        possiblyErroneousFunctionToIr(element), null);
+    return accessor.buildCompoundAssignment(
+        new ir.Name(operator.selectorName), visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperGet(Send node, Element element, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterCompound(Send node, Element element,
+      MethodElement setter, AssignmentOperator operator, Node rhs, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterCompoundIndexSet(
+      Send node,
+      Element element,
+      MethodElement setter,
+      Node index,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterIndexPostfix(
+      Send node,
+      Element element,
+      MethodElement setter,
+      Node index,
+      IncDecOperator operator,
+      _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterIndexPrefix(
+      Send node,
+      Element element,
+      MethodElement setter,
+      Node index,
+      IncDecOperator operator,
+      _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperGetterSetIfNull(
+      Send node, Element element, MethodElement setter, Node rhs, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperIndex(
+      Send node, Element element, Node index, _) {
+    return new SuperIndexAccessor(this, visitForValue(index), null, null)
+        .buildSimpleRead();
+  }
+
+  ir.Expression visitUnresolvedSuperIndexPostfix(
+      Send node, Element element, Node index, IncDecOperator operator, _) {
+    return new SuperIndexAccessor(this, visitForValue(index), null, null)
+        .buildSimpleRead();
+  }
+
+  ir.Expression visitUnresolvedSuperIndexPrefix(
+      Send node, Element element, Node index, IncDecOperator operator, _) {
+    return new SuperIndexAccessor(this, visitForValue(index), null, null)
+        .buildSimpleRead();
+  }
+
+  ir.Expression visitUnresolvedSuperIndexSet(
+      Send node, Element element, Node index, Node rhs, _) {
+    return new SuperIndexAccessor(this, visitForValue(index), null, null)
+        .buildAssignment(visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperInvoke(
+      Send node, Element element, NodeList arguments, Selector selector, _) {
+    // TODO(asgerf): Should really invoke 'super.noSuchMethod'.
+    return buildThrowNoSuchMethodError(kernel.getUnresolvedSuperMethodBuilder(),
+        new ir.ThisExpression(), '${node.selector}', buildArguments(arguments));
+  }
+
+  ir.Expression visitUnresolvedSuperPostfix(
+      Send node, Element element, IncDecOperator operator, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperPrefix(
+      Send node, Element element, IncDecOperator operator, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperSetIfNull(
+      Send node, Element element, Node rhs, _) {
+    return buildThrowUnresolvedSuperGetter('${node.selector}');
+  }
+
+  ir.Expression visitUnresolvedSuperSetterCompound(
+      Send node,
+      MethodElement getter,
+      Element element,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    var accessor = new SuperPropertyAccessor(
+        this, '${node.selector}', possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildCompoundAssignment(
+        new ir.Name(operator.selectorName), visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterCompoundIndexSet(
+      Send node,
+      MethodElement getter,
+      Element element,
+      Node index,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index),
+        possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildCompoundAssignment(
+        new ir.Name(operator.selectorName), visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterIndexPostfix(
+      Send node,
+      MethodElement indexFunction,
+      Element element,
+      Node index,
+      IncDecOperator operator,
+      _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index),
+        possiblyErroneousFunctionToIr(indexFunction), null);
+    return accessor.buildPostfixIncrement(new ir.Name(operator.selectorName));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterIndexPrefix(
+      Send node,
+      MethodElement indexFunction,
+      Element element,
+      Node index,
+      IncDecOperator operator,
+      _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index),
+        possiblyErroneousFunctionToIr(indexFunction), null);
+    return accessor.buildPrefixIncrement(new ir.Name(operator.selectorName));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterPostfix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new SuperPropertyAccessor(
+        this, '${node.selector}', possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPostfixIncrement(new ir.Name(operator.selectorName));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterPrefix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new SuperPropertyAccessor(
+        this, '${node.selector}', possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPrefixIncrement(new ir.Name(operator.selectorName));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterSetIfNull(
+      Send node, MethodElement getter, Element element, Node rhs, _) {
+    var accessor = new SuperPropertyAccessor(
+        this, '${node.selector}', possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperUnary(
+      Send node, UnaryOperator operator, Element element, _) {
+    // TODO(asgerf): Should really call 'super.noSuchMethod'.
+    return buildThrowNoSuchMethodError(
+        kernel.getUnresolvedSuperMethodBuilder(),
+        new ir.ThisExpression(),
+        operator.selectorName,
+        new ir.Arguments.empty());
+  }
+
+  ir.Expression visitUnresolvedTopLevelGetterCompound(
+      Send node,
+      Element element,
+      MethodElement setter,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedTopLevelGetterPostfix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedTopLevelGetterPrefix(Send node, Element element,
+      MethodElement setter, IncDecOperator operator, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedTopLevelGetterSetIfNull(
+      Send node, Element element, MethodElement setter, Node rhs, _) {
+    return buildThrowUnresolvedGetter(
+        '${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
+  }
+
+  ir.Expression visitUnresolvedTopLevelSetterCompound(
+      Send node,
+      MethodElement getter,
+      Element element,
+      AssignmentOperator operator,
+      Node rhs,
+      _) {
+    var accessor = new TopLevelStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildCompoundAssignment(
+        new ir.Name(operator.selectorName), visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedTopLevelSetterPostfix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new TopLevelStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPostfixIncrement(new ir.Name(operator.selectorName),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedTopLevelSetterPrefix(Send node,
+      MethodElement getter, Element element, IncDecOperator operator, _) {
+    var accessor = new TopLevelStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildPrefixIncrement(new ir.Name(operator.selectorName),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedTopLevelSetterSetIfNull(
+      Send node, MethodElement getter, Element element, Node rhs, _) {
+    var accessor = new TopLevelStaticAccessor(
+        this, getter.name, possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs),
+        voidContext: isVoidContext);
+  }
+
+  ir.Expression visitUnresolvedSuperGetterIndexSetIfNull(Send node,
+      Element element, MethodElement setter, Node index, Node rhs, _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index), null,
+        possiblyErroneousFunctionToIr(setter));
+    return accessor.buildNullAwareAssignment(visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperSetterIndexSetIfNull(Send node,
+      MethodElement getter, Element element, Node index, Node rhs, _) {
+    var accessor = new SuperIndexAccessor(this, visitForValue(index),
+        possiblyErroneousFunctionToIr(getter), null);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperIndexSetIfNull(
+      Send node, Element element, Node index, Node rhs, _) {
+    var accessor =
+        new SuperIndexAccessor(this, visitForValue(index), null, null);
+    return accessor.buildNullAwareAssignment(visitForValue(rhs));
+  }
+
+  ir.Expression visitUnresolvedSuperSet(
+      Send node, Element element, Node rhs, _) {
+    return buildThrowUnresolvedSuperSetter(
+        '${node.selector}', visitForValue(rhs));
+  }
+}
diff --git a/pkg/compiler/lib/src/mirrors_used.dart b/pkg/compiler/lib/src/mirrors_used.dart
index c909c8a..79dac05 100644
--- a/pkg/compiler/lib/src/mirrors_used.dart
+++ b/pkg/compiler/lib/src/mirrors_used.dart
@@ -91,7 +91,9 @@
   /// Collect @MirrorsUsed annotations in all libraries.  Called by the
   /// compiler after all libraries are loaded, but before resolution.
   void analyzeUsage(LibraryElement mainApp) {
-    if (mainApp == null || compiler.mirrorsLibrary == null) return;
+    if (mainApp == null || compiler.commonElements.mirrorsLibrary == null) {
+      return;
+    }
     measure(analyzer.run);
     List<String> symbols = analyzer.mergedMirrorUsage.symbols;
     List<Element> targets = analyzer.mergedMirrorUsage.targets;
@@ -241,7 +243,7 @@
   List<MirrorUsage> mirrorsUsedOnLibraryTag(
       LibraryElement library, ImportElement import) {
     LibraryElement importedLibrary = import.importedLibrary;
-    if (importedLibrary != compiler.mirrorsLibrary) {
+    if (importedLibrary != compiler.commonElements.mirrorsLibrary) {
       return null;
     }
     List<MirrorUsage> result = <MirrorUsage>[];
@@ -250,7 +252,7 @@
       ConstantValue value =
           compiler.constants.getConstantValue(metadata.constant);
       Element element = value.getType(compiler.coreTypes).element;
-      if (element == compiler.mirrorsUsedClass) {
+      if (element == compiler.commonElements.mirrorsUsedClass) {
         result.add(buildUsage(value));
       }
     }
@@ -313,14 +315,11 @@
   /// that was resolved during [MirrorUsageAnalyzerTask.validate].
   MirrorUsage buildUsage(ConstructedConstantValue constant) {
     Map<Element, ConstantValue> fields = constant.fields;
-    VariableElement symbolsField =
-        compiler.mirrorsUsedClass.lookupLocalMember('symbols');
-    VariableElement targetsField =
-        compiler.mirrorsUsedClass.lookupLocalMember('targets');
-    VariableElement metaTargetsField =
-        compiler.mirrorsUsedClass.lookupLocalMember('metaTargets');
-    VariableElement overrideField =
-        compiler.mirrorsUsedClass.lookupLocalMember('override');
+    ClassElement cls = compiler.commonElements.mirrorsUsedClass;
+    VariableElement symbolsField = cls.lookupLocalMember('symbols');
+    VariableElement targetsField = cls.lookupLocalMember('targets');
+    VariableElement metaTargetsField = cls.lookupLocalMember('metaTargets');
+    VariableElement overrideField = cls.lookupLocalMember('override');
 
     return new MirrorUsage(
         cachedStrings[fields[symbolsField]],
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 1c597ef..0b54370 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -221,6 +221,9 @@
   /// Whether to generate code compliant with content security policy (CSP).
   final bool useContentSecurityPolicy;
 
+  /// Whether to use kernel internally as part of compilation.
+  final bool useKernel;
+
   /// When obfuscating for minification, whether to use the frequency of a name
   /// as an heuristic to pick shorter names.
   final bool useFrequencyNamer;
@@ -318,6 +321,7 @@
         trustTypeAnnotations: _hasOption(options, Flags.trustTypeAnnotations),
         useContentSecurityPolicy:
             _hasOption(options, Flags.useContentSecurityPolicy),
+        useKernel: _hasOption(options, Flags.useKernel),
         useFrequencyNamer:
             !_hasOption(options, Flags.noFrequencyBasedMinification),
         useNewSourceInfo: _hasOption(options, Flags.useNewSourceInfo),
@@ -378,6 +382,7 @@
       bool trustPrimitives: false,
       bool trustTypeAnnotations: false,
       bool useContentSecurityPolicy: false,
+      bool useKernel: false,
       bool useFrequencyNamer: true,
       bool useNewSourceInfo: false,
       bool useStartupEmitter: false,
@@ -450,6 +455,7 @@
         trustPrimitives: trustPrimitives,
         trustTypeAnnotations: trustTypeAnnotations,
         useContentSecurityPolicy: useContentSecurityPolicy,
+        useKernel: useKernel,
         useFrequencyNamer: useFrequencyNamer,
         useNewSourceInfo: useNewSourceInfo,
         useStartupEmitter: useStartupEmitter,
@@ -500,6 +506,7 @@
       this.trustPrimitives: false,
       this.trustTypeAnnotations: false,
       this.useContentSecurityPolicy: false,
+      this.useKernel: false,
       this.useFrequencyNamer: false,
       this.useNewSourceInfo: false,
       this.useStartupEmitter: false,
@@ -557,6 +564,7 @@
       trustPrimitives,
       trustTypeAnnotations,
       useContentSecurityPolicy,
+      useKernel,
       useFrequencyNamer,
       useNewSourceInfo,
       useStartupEmitter,
@@ -626,6 +634,7 @@
             trustTypeAnnotations ?? options.trustTypeAnnotations,
         useContentSecurityPolicy:
             useContentSecurityPolicy ?? options.useContentSecurityPolicy,
+        useKernel: useKernel ?? options.useKernel,
         useFrequencyNamer: useFrequencyNamer ?? options.useFrequencyNamer,
         useNewSourceInfo: useNewSourceInfo ?? options.useNewSourceInfo,
         useStartupEmitter: useStartupEmitter ?? options.useStartupEmitter,
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 9f51036..4e6ea8c 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -432,7 +432,8 @@
   void validate(Compiler compiler, Element element,
       MetadataAnnotation annotation, ConstantValue constant) {
     DartType annotationType = constant.getType(compiler.coreTypes);
-    if (annotationType.element != compiler.nativeAnnotationClass) {
+    if (annotationType.element !=
+        compiler.commonElements.nativeAnnotationClass) {
       DiagnosticReporter reporter = compiler.reporter;
       reporter.internalError(annotation, 'Invalid @Native(...) annotation.');
     }
@@ -500,7 +501,8 @@
   void validate(Compiler compiler, Element element,
       MetadataAnnotation annotation, ConstantValue constant) {
     DartType annotationType = constant.getType(compiler.coreTypes);
-    if (annotationType.element != compiler.patchAnnotationClass) {
+    if (annotationType.element !=
+        compiler.commonElements.patchAnnotationClass) {
       DiagnosticReporter reporter = compiler.reporter;
       reporter.internalError(annotation, 'Invalid patch annotation.');
     }
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index edf87b7..ef03ab5 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -553,7 +553,7 @@
 
   isBlackListed(DartType type) {
     LibraryElement lib = element.library;
-    return !identical(lib, resolution.coreLibrary) &&
+    return !identical(lib, resolution.commonElements.coreLibrary) &&
         !resolution.target.isTargetSpecificLibrary(lib) &&
         (type.isDynamic ||
             type == coreTypes.boolType ||
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index aca4df5..8e6f85e 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -310,6 +310,7 @@
     assert(!cls.isAbstract);
 
     ClassElement functionClass = resolution.coreClasses.functionClass;
+    functionClass.ensureResolved(resolution);
     if (cls.asInstanceOf(functionClass) == null) return;
     if (cls.lookupMember(Identifiers.call) != null) return;
     // TODO(johnniwinther): Make separate methods for backend exceptions.
@@ -688,8 +689,7 @@
         bool allAreGetters = true;
         Map<DartType, Setlet<Member>> subtypesOfAllInherited =
             new Map<DartType, Setlet<Member>>();
-        outer:
-        for (Member inherited in inheritedMembers) {
+        outer: for (Member inherited in inheritedMembers) {
           if (inherited.isGetter) {
             someAreGetters = true;
             if (!allAreGetters) break outer;
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index b337d35..9f32c0b 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -481,6 +481,8 @@
 
   ResolutionRegistry get registry => resolver.registry;
 
+  Element get context => resolver.enclosingElement;
+
   visitNode(Node node) {
     throw 'not supported';
   }
@@ -489,7 +491,6 @@
       Spannable diagnosticNode,
       ConstructorResultKind resultKind,
       DartType type,
-      Element enclosing,
       String name,
       MessageKind kind,
       Map arguments,
@@ -509,7 +510,7 @@
       reporter.reportWarning(message, infos);
     }
     ErroneousElement error =
-        new ErroneousConstructorElementX(kind, arguments, name, enclosing);
+        new ErroneousConstructorElementX(kind, arguments, name, context);
     if (type == null) {
       type = new MalformedType(error, null);
     }
@@ -521,7 +522,7 @@
     ClassElement cls = type.element;
     cls.ensureResolved(resolution);
     ConstructorElement constructor = findConstructor(
-        resolver.enclosingElement.library, cls, constructorName);
+        context.library, cls, constructorName);
     if (constructor == null) {
       MessageKind kind = constructorName.isEmpty
           ? MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR
@@ -530,7 +531,6 @@
           diagnosticNode,
           ConstructorResultKind.UNRESOLVED_CONSTRUCTOR,
           type,
-          cls,
           constructorName,
           kind,
           {'className': cls.name, 'constructorName': constructorName},
@@ -546,7 +546,6 @@
             diagnosticNode,
             ConstructorResultKind.INVALID_TYPE,
             type,
-            cls,
             constructorName,
             MessageKind.CANNOT_INSTANTIATE_ENUM,
             {'enumName': cls.name},
@@ -607,7 +606,6 @@
             diagnosticNode,
             ConstructorResultKind.INVALID_TYPE,
             null,
-            element,
             element.name,
             MessageKind.NOT_A_TYPE,
             {'node': diagnosticNode});
@@ -661,7 +659,6 @@
             name,
             ConstructorResultKind.INVALID_TYPE,
             null,
-            resolver.enclosingElement,
             name.source,
             MessageKind.NOT_A_TYPE,
             {'node': name});
@@ -700,7 +697,6 @@
           node,
           ConstructorResultKind.INVALID_TYPE,
           null,
-          resolver.enclosingElement,
           name,
           MessageKind.CANNOT_RESOLVE,
           {'name': name});
@@ -710,11 +706,10 @@
           node,
           ConstructorResultKind.INVALID_TYPE,
           null,
-          resolver.enclosingElement,
           name,
           ambiguous.messageKind,
           ambiguous.messageArguments,
-          infos: ambiguous.computeInfos(resolver.enclosingElement, reporter));
+          infos: ambiguous.computeInfos(context, reporter));
     } else if (element.isMalformed) {
       return constructorResultForErroneous(node, element);
     } else if (element.isClass) {
@@ -735,7 +730,6 @@
           node,
           ConstructorResultKind.INVALID_TYPE,
           null,
-          resolver.enclosingElement,
           name,
           MessageKind.NOT_A_TYPE,
           {'node': name});
@@ -761,7 +755,6 @@
           node,
           ConstructorResultKind.INVALID_TYPE,
           type,
-          resolver.enclosingElement,
           name,
           MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
           {'typeVariableName': name});
@@ -776,7 +769,6 @@
           node,
           ConstructorResultKind.INVALID_TYPE,
           type,
-          resolver.enclosingElement,
           name,
           MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
           {'typedefName': name});
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index d2ca86e..efc6e0d 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -2623,12 +2623,12 @@
     // of parse errors to make [element] erroneous. Fix this!
     member.computeType(resolution);
 
-    if (member == resolution.mirrorSystemGetNameFunction &&
+    if (resolution.commonElements.isMirrorSystemGetNameFunction(member) &&
         !resolution.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
-      reporter
-          .reportHintMessage(node.selector, MessageKind.STATIC_FUNCTION_BLOAT, {
-        'class': resolution.mirrorSystemClass.name,
-        'name': resolution.mirrorSystemGetNameFunction.name
+      reporter.reportHintMessage(
+          node.selector, MessageKind.STATIC_FUNCTION_BLOAT, {
+        'class': resolution.commonElements.mirrorSystemClass.name,
+        'name': member.name
       });
     }
 
@@ -2654,7 +2654,7 @@
             registry.registerStaticUse(
                 new StaticUse.staticInvoke(semantics.element, callStructure));
             handleForeignCall(node, semantics.element, callStructure);
-            if (method == resolution.identicalFunction &&
+            if (method == resolution.commonElements.identicalFunction &&
                 argumentsResult.isValidAsConstant) {
               result = new ConstantResult(
                   node,
@@ -3677,7 +3677,7 @@
     registry.registerTypeUse(new TypeUse.instantiation(redirectionTarget
         .enclosingClass.thisType
         .subst(type.typeArguments, targetClass.typeVariables)));
-    if (enclosingElement == resolution.symbolConstructor) {
+    if (resolution.commonElements.isSymbolConstructor(enclosingElement)) {
       registry.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
     }
     if (isValidAsConstant) {
@@ -3887,7 +3887,8 @@
     if (node.isConst) {
       bool isValidAsConstant = !isInvalid && constructor.isConst;
 
-      if (constructor == resolution.symbolConstructor) {
+      CommonElements commonElements = resolution.commonElements;
+      if (commonElements.isSymbolConstructor(constructor)) {
         Node argumentNode = node.send.arguments.head;
         ConstantExpression constant = resolver.constantCompiler
             .compileNode(argumentNode, registry.mapping);
@@ -3903,7 +3904,7 @@
             registry.registerConstSymbol(nameString);
           }
         }
-      } else if (constructor == resolution.mirrorsUsedConstructor) {
+      } else if (commonElements.isMirrorsUsedConstructor(constructor)) {
         resolution.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
       }
 
@@ -3963,7 +3964,7 @@
       analyzeConstantDeferred(node, onAnalyzed: onAnalyzed);
     } else {
       // Not constant.
-      if (constructor == resolution.symbolConstructor &&
+      if (resolution.commonElements.isSymbolConstructor(constructor) &&
           !resolution.mirrorUsageAnalyzerTask
               .hasMirrorUsage(enclosingElement)) {
         reporter.reportHintMessage(node.newToken, MessageKind.NON_CONST_BLOAT,
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index 73dd7fe..4d747cd 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -19,7 +19,7 @@
         ConstructedConstantExpression,
         ErroneousConstantExpression;
 import '../constants/values.dart' show ConstantValue;
-import '../core_types.dart' show CoreClasses, CoreTypes;
+import '../core_types.dart' show CoreClasses, CoreTypes, CommonElements;
 import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart'
@@ -76,6 +76,7 @@
   Target get target => resolution.target;
   CoreTypes get coreTypes => resolution.coreTypes;
   CoreClasses get coreClasses => resolution.coreClasses;
+  CommonElements get commonElements => resolution.commonElements;
   ParsingContext get parsingContext => resolution.parsingContext;
   CompilerOptions get options => resolution.options;
   ResolutionEnqueuer get enqueuer => resolution.enqueuer;
@@ -634,7 +635,6 @@
                     new ClassResolverVisitor(resolution, element, registry);
                 visitor.visit(tree);
                 element.resolutionState = STATE_DONE;
-                resolution.onClassResolved(element);
                 pendingClassesToBePostProcessed.add(element);
               }));
       if (element.isPatched) {
@@ -1066,7 +1066,8 @@
               switch (constant.kind) {
                 case ConstantExpressionKind.CONSTRUCTED:
                   ConstructedConstantExpression constructedConstant = constant;
-                  if (constructedConstant.type.isGeneric) {
+                  if (constructedConstant.type.isGeneric &&
+                      !constructedConstant.type.isRaw) {
                     // Const constructor calls cannot have type arguments.
                     // TODO(24312): Remove this.
                     reporter.reportErrorMessage(
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index 3b14778..d24a5ea 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -12,6 +12,7 @@
 import '../elements/elements.dart';
 import '../elements/modelx.dart'
     show
+        AmbiguousImportX,
         DeferredLoaderGetterElementX,
         ErroneousElementX,
         WarnOnUseElementX,
@@ -59,6 +60,7 @@
   DEFERRED_LOAD_LIBRARY,
   LOCAL_VARIABLE,
   WARN_ON_USE,
+  AMBIGUOUS,
   EXTERNAL_LIBRARY,
   EXTERNAL_LIBRARY_MEMBER,
   EXTERNAL_CLASS_MEMBER,
@@ -89,6 +91,7 @@
   const ExportSerializer(),
   const LocalVariableSerializer(),
   const WarnOnUseSerializer(),
+  const AmbiguousSerializer(),
 ];
 
 /// Interface for a function that can serialize a set of element kinds.
@@ -815,6 +818,28 @@
   }
 }
 
+class AmbiguousSerializer implements ElementSerializer {
+  const AmbiguousSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isAmbiguous) {
+      return SerializedElementKind.AMBIGUOUS;
+    }
+    return null;
+  }
+
+  void serialize(AmbiguousImportX element, ObjectEncoder encoder,
+      SerializedElementKind kind) {
+    // TODO(johnniwinther): Also support [DuplicateElementX] if serialization
+    // of code with compile-time errors is supported.
+    encoder.setElement(Key.ENCLOSING, element.enclosingElement);
+    encoder.setElement(Key.EXISTING, element.existingElement);
+    encoder.setElement(Key.NEW, element.newElement);
+    encoder.setEnum(Key.MESSAGE_KIND, element.messageKind);
+    serializeMessageArguments(encoder, Key.ARGUMENTS, element.messageArguments);
+  }
+}
+
 /// Utility class for deserializing [Element]s.
 ///
 /// This is used by the [Deserializer].
@@ -912,7 +937,18 @@
             deserializeWrappedMessage(decoder, Key.WARNING);
         WrappedMessage info = deserializeWrappedMessage(decoder, Key.INFO);
         return new WarnOnUseElementX(warning, info, enclosing, element);
-      case SerializedElementKind.EXTERNAL_LIBRARY:
+      case SerializedElementKind.AMBIGUOUS:
+        Element enclosingElement = decoder.getElement(Key.ENCLOSING);
+        Element existingElement = decoder.getElement(Key.EXISTING);
+        Element newElement = decoder.getElement(Key.NEW);
+        MessageKind messageKind =
+            decoder.getEnum(Key.MESSAGE_KIND, MessageKind.values);
+        Map messageArguments =
+            deserializeMessageArguments(decoder, Key.ARGUMENTS);
+        return new AmbiguousImportX(
+            messageKind, messageArguments,
+            enclosingElement, existingElement, newElement);
+  case SerializedElementKind.EXTERNAL_LIBRARY:
       case SerializedElementKind.EXTERNAL_LIBRARY_MEMBER:
       case SerializedElementKind.EXTERNAL_CLASS_MEMBER:
       case SerializedElementKind.EXTERNAL_CONSTRUCTOR:
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index 0fa501a..928bbc7 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -35,6 +35,7 @@
   static const Key ELEMENTS = const Key('elements');
   static const Key ENCLOSING = const Key('enclosing');
   static const Key EXECUTABLE_CONTEXT = const Key('executable-context');
+  static const Key EXISTING = const Key('existing');
   static const Key EXPORTS = const Key('exports');
   static const Key EXPORT_SCOPE = const Key('export-scope');
   static const Key EXPRESSION = const Key('expression');
@@ -102,6 +103,7 @@
   static const Key NAMED_PARAMETER_TYPES = const Key('named-parameter-types');
   static const Key NATIVE = const Key('native');
   static const Key NESTING_LEVEL = const Key('nestingLevel');
+  static const Key NEW = const Key('new');
   static const Key NEW_STRUCTURE = const Key('newStructure');
   static const Key NODE = const Key('node');
   static const Key OFFSET = const Key('offset');
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 77025b0..e44ebf3 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -38,42 +38,12 @@
 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
 import '../util/util.dart';
 import '../world.dart' show ClassWorld;
-import 'codegen.dart';
+import 'graph_builder.dart';
+import 'locals_handler.dart';
 import 'nodes.dart';
 import 'optimize.dart';
 import 'types.dart';
 
-class SsaFunctionCompiler implements FunctionCompiler {
-  final SsaCodeGeneratorTask generator;
-  final SsaBuilderTask builder;
-  final SsaOptimizerTask optimizer;
-  final JavaScriptBackend backend;
-
-  SsaFunctionCompiler(JavaScriptBackend backend,
-      SourceInformationStrategy sourceInformationFactory)
-      : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory),
-        builder = new SsaBuilderTask(backend, sourceInformationFactory),
-        optimizer = new SsaOptimizerTask(backend),
-        backend = backend;
-
-  /// Generates JavaScript code for `work.element`.
-  /// Using the ssa builder, optimizer and codegenerator.
-  js.Fun compile(CodegenWorkItem work) {
-    HGraph graph = builder.build(work);
-    optimizer.optimize(work, graph);
-    Element element = work.element;
-    js.Expression result = generator.generateCode(work, graph);
-    if (element is FunctionElement) {
-      result = backend.rewriteAsync(element, result);
-    }
-    return result;
-  }
-
-  Iterable<CompilerTask> get tasks {
-    return <CompilerTask>[builder, optimizer, generator];
-  }
-}
-
 /// A synthetic local variable only used with the SSA graph.
 ///
 /// For instance used for holding return value of function or the exception of a
@@ -154,634 +124,6 @@
   }
 }
 
-/**
- * Keeps track of locals (including parameters and phis) when building. The
- * 'this' reference is treated as parameter and hence handled by this class,
- * too.
- */
-class LocalsHandler {
-  /**
-   * The values of locals that can be directly accessed (without redirections
-   * to boxes or closure-fields).
-   *
-   * [directLocals] is iterated, so it is "insertion ordered" to make the
-   * iteration order a function only of insertions and not a function of
-   * e.g. Element hash codes.  I'd prefer to use a SortedMap but some elements
-   * don't have source locations for [Elements.compareByPosition].
-   */
-  Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>();
-  Map<Local, CapturedVariable> redirectionMapping =
-      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.
-  ClassElement get contextClass => executableContext.contextClass;
-
-  /// The type of the current instance, if concrete.
-  ///
-  /// This allows for handling fixed type argument in case of inlining. For
-  /// instance, checking `'foo'` against `String` instead of `T` in `main`:
-  ///
-  ///     class Foo<T> {
-  ///       T field;
-  ///       Foo(this.field);
-  ///     }
-  ///     main() {
-  ///       new Foo<String>('foo');
-  ///     }
-  ///
-  /// [instanceType] is not used if it contains type variables, since these
-  /// might not be in scope or from the current instance.
-  ///
-  final InterfaceType instanceType;
-
-  SourceInformationBuilder get sourceInformationBuilder {
-    return builder.sourceInformationBuilder;
-  }
-
-  LocalsHandler(
-      this.builder, this.executableContext, InterfaceType instanceType)
-      : this.instanceType =
-            instanceType == null || instanceType.containsTypeVariables
-                ? null
-                : instanceType;
-
-  /// Substituted type variables occurring in [type] into the context of
-  /// [contextClass].
-  DartType substInContext(DartType type) {
-    if (contextClass != null) {
-      ClassElement typeContext = Types.getClassContext(type);
-      if (typeContext != null) {
-        type = type.substByContext(contextClass.asInstanceOf(typeContext));
-      }
-    }
-    if (instanceType != null) {
-      type = type.substByContext(instanceType);
-    }
-    return type;
-  }
-
-  get typesTask => builder.compiler.typesTask;
-
-  /**
-   * Creates a new [LocalsHandler] based on [other]. We only need to
-   * copy the [directLocals], since the other fields can be shared
-   * throughout the AST visit.
-   */
-  LocalsHandler.from(LocalsHandler other)
-      : directLocals = new Map<Local, HInstruction>.from(other.directLocals),
-        redirectionMapping = other.redirectionMapping,
-        executableContext = other.executableContext,
-        instanceType = other.instanceType,
-        builder = other.builder,
-        closureData = other.closureData;
-
-  /**
-   * Redirects accesses from element [from] to element [to]. The [to] element
-   * must be a boxed variable or a variable that is stored in a closure-field.
-   */
-  void redirectElement(Local from, CapturedVariable to) {
-    assert(redirectionMapping[from] == null);
-    redirectionMapping[from] = to;
-    assert(isStoredInClosureField(from) || isBoxed(from));
-  }
-
-  HInstruction createBox() {
-    // TODO(floitsch): Clean up this hack. Should we create a box-object by
-    // just creating an empty object literal?
-    JavaScriptBackend backend = builder.backend;
-    HInstruction box = new HForeignCode(
-        js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[],
-        nativeBehavior: native.NativeBehavior.PURE_ALLOCATION);
-    builder.add(box);
-    return box;
-  }
-
-  /**
-   * If the scope (function or loop) [node] has captured variables then this
-   * method creates a box and sets up the redirections.
-   */
-  void enterScope(ast.Node node, Element element) {
-    // See if any variable in the top-scope of the function is captured. If yes
-    // we need to create a box-object.
-    ClosureScope scopeData = closureData.capturingScopes[node];
-    if (scopeData == null) return;
-    HInstruction box;
-    // The scope has captured variables.
-    if (element != null && element.isGenerativeConstructorBody) {
-      // The box is passed as a parameter to a generative
-      // constructor body.
-      JavaScriptBackend backend = builder.backend;
-      box = builder.addParameter(scopeData.boxElement, backend.nonNullType);
-    } else {
-      box = createBox();
-    }
-    // Add the box to the known locals.
-    directLocals[scopeData.boxElement] = box;
-    // 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(
-        (LocalVariableElement from, BoxFieldElement to) {
-      // The [from] can only be a parameter for function-scopes and not
-      // loop scopes.
-      if (from.isRegularParameter && !element.isGenerativeConstructorBody) {
-        // Now that the redirection is set up, the update to the local will
-        // write the parameter value into the box.
-        // Store the captured parameter in the box. Get the current value
-        // before we put the redirection in place.
-        // We don't need to update the local for a generative
-        // constructor body, because it receives a box that already
-        // contains the updates as the last parameter.
-        HInstruction instruction = readLocal(from);
-        redirectElement(from, to);
-        updateLocal(from, instruction);
-      } else {
-        redirectElement(from, to);
-      }
-    });
-  }
-
-  /**
-   * Replaces the current box with a new box and copies over the given list
-   * of elements from the old box into the new box.
-   */
-  void updateCaptureBox(
-      BoxLocal boxElement, 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 (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);
-      HInstruction oldValue = readLocal(boxedVariable);
-      updateLocal(boxElement, newBox);
-      updateLocal(boxedVariable, oldValue);
-    }
-    updateLocal(boxElement, newBox);
-  }
-
-  /**
-   * Documentation wanted -- johnniwinther
-   *
-   * Invariant: [function] must be an implementation element.
-   */
-  void startFunction(AstElement element, ast.Node node) {
-    assert(invariant(element, element.isImplementation));
-    Compiler compiler = builder.compiler;
-    closureData = compiler.closureToClassMapper
-        .computeClosureToClassMapping(element.resolvedAst);
-
-    if (element is FunctionElement) {
-      FunctionElement functionElement = element;
-      FunctionSignature params = functionElement.functionSignature;
-      ClosureScope scopeData = closureData.capturingScopes[node];
-      params.orderedForEachParameter((ParameterElement parameterElement) {
-        if (element.isGenerativeConstructorBody) {
-          if (scopeData != null &&
-              scopeData.isCapturedVariable(parameterElement)) {
-            // The parameter will be a field in the box passed as the
-            // last parameter. So no need to have it.
-            return;
-          }
-        }
-        HInstruction parameter = builder.addParameter(parameterElement,
-            TypeMaskFactory.inferredTypeForElement(parameterElement, compiler));
-        builder.parameters[parameterElement] = parameter;
-        directLocals[parameterElement] = parameter;
-      });
-    }
-
-    enterScope(node, element);
-
-    // If the freeVariableMapping is not empty, then this function was a
-    // nested closure that captures variables. Redirect the captured
-    // variables to fields in the closure.
-    closureData.forEachFreeVariable((Local from, CapturedVariable to) {
-      redirectElement(from, to);
-    });
-    JavaScriptBackend backend = compiler.backend;
-    if (closureData.isClosure) {
-      // Inside closure redirect references to itself to [:this:].
-      HThis thisInstruction =
-          new HThis(closureData.thisLocal, backend.nonNullType);
-      builder.graph.thisInstruction = thisInstruction;
-      builder.graph.entry.addAtEntry(thisInstruction);
-      updateLocal(closureData.closureElement, thisInstruction);
-    } else if (element.isInstanceMember) {
-      // Once closures have been mapped to classes their instance members might
-      // not have any thisElement if the closure was created inside a static
-      // context.
-      HThis thisInstruction =
-          new HThis(closureData.thisLocal, builder.getTypeOfThis());
-      builder.graph.thisInstruction = thisInstruction;
-      builder.graph.entry.addAtEntry(thisInstruction);
-      directLocals[closureData.thisLocal] = thisInstruction;
-    }
-
-    // If this method is an intercepted method, add the extra
-    // parameter to it, that is the actual receiver for intercepted
-    // classes, or the same as [:this:] for non-intercepted classes.
-    ClassElement cls = element.enclosingClass;
-
-    // When the class extends a native class, the instance is pre-constructed
-    // and passed to the generative constructor factory function as a parameter.
-    // Instead of allocating and initializing the object, the constructor
-    // 'upgrades' the native subclass object by initializing the Dart fields.
-    bool isNativeUpgradeFactory =
-        element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls);
-    if (backend.isInterceptedMethod(element)) {
-      bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
-      String name = isInterceptorClass ? 'receiver' : '_';
-      SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
-      HParameterValue value =
-          new HParameterValue(parameter, builder.getTypeOfThis());
-      builder.graph.explicitReceiverParameter = value;
-      builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value);
-      if (builder.lastAddedParameter == null) {
-        // If this is the first parameter inserted, make sure it stays first.
-        builder.lastAddedParameter = value;
-      }
-      if (isInterceptorClass) {
-        // Only use the extra parameter in intercepted classes.
-        directLocals[closureData.thisLocal] = value;
-      }
-    } else if (isNativeUpgradeFactory) {
-      SyntheticLocal parameter =
-          new SyntheticLocal('receiver', executableContext);
-      // Unlike `this`, receiver is nullable since direct calls to generative
-      // constructor call the constructor with `null`.
-      ClassWorld classWorld = compiler.world;
-      HParameterValue value =
-          new HParameterValue(parameter, new TypeMask.exact(cls, classWorld));
-      builder.graph.explicitReceiverParameter = value;
-      builder.graph.entry.addAtEntry(value);
-    }
-  }
-
-  /**
-   * Returns true if the local can be accessed directly. Boxed variables or
-   * captured variables that are stored in the closure-field return [:false:].
-   */
-  bool isAccessedDirectly(Local local) {
-    assert(local != null);
-    return !redirectionMapping.containsKey(local) &&
-        !closureData.variablesUsedInTryOrGenerator.contains(local);
-  }
-
-  bool isStoredInClosureField(Local local) {
-    assert(local != null);
-    if (isAccessedDirectly(local)) return false;
-    CapturedVariable redirectTarget = redirectionMapping[local];
-    if (redirectTarget == null) return false;
-    return redirectTarget is ClosureFieldElement;
-  }
-
-  bool isBoxed(Local local) {
-    if (isAccessedDirectly(local)) return false;
-    if (isStoredInClosureField(local)) return false;
-    return redirectionMapping.containsKey(local);
-  }
-
-  bool isUsedInTryOrGenerator(Local local) {
-    return closureData.variablesUsedInTryOrGenerator.contains(local);
-  }
-
-  /**
-   * Returns an [HInstruction] for the given element. If the element is
-   * boxed or stored in a closure then the method generates code to retrieve
-   * the value.
-   */
-  HInstruction readLocal(Local local, {SourceInformation sourceInformation}) {
-    if (isAccessedDirectly(local)) {
-      if (directLocals[local] == null) {
-        if (local is TypeVariableElement) {
-          builder.reporter.internalError(builder.compiler.currentElement,
-              "Runtime type information not available for $local.");
-        } else {
-          builder.reporter.internalError(
-              local, "Cannot find value $local in ${directLocals.keys}.");
-        }
-      }
-      HInstruction value = directLocals[local];
-      if (sourceInformation != null) {
-        value = new HRef(value, sourceInformation);
-        builder.add(value);
-      }
-      return value;
-    } else if (isStoredInClosureField(local)) {
-      ClosureFieldElement redirect = redirectionMapping[local];
-      HInstruction receiver = readLocal(closureData.closureElement);
-      TypeMask type = local is BoxLocal
-          ? builder.backend.nonNullType
-          : builder.getTypeOfCapturedVariable(redirect);
-      HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
-      builder.add(fieldGet);
-      return fieldGet..sourceInformation = sourceInformation;
-    } else if (isBoxed(local)) {
-      BoxFieldElement redirect = redirectionMapping[local];
-      // In the function that declares the captured variable the box is
-      // accessed as direct local. Inside the nested closure the box is
-      // accessed through a closure-field.
-      // Calling [readLocal] makes sure we generate the correct code to get
-      // the box.
-      HInstruction box = readLocal(redirect.box);
-      HInstruction lookup = new HFieldGet(
-          redirect, box, builder.getTypeOfCapturedVariable(redirect));
-      builder.add(lookup);
-      return lookup..sourceInformation = sourceInformation;
-    } else {
-      assert(isUsedInTryOrGenerator(local));
-      HLocalValue localValue = getLocal(local);
-      HInstruction instruction = new HLocalGet(
-          local, localValue, builder.backend.dynamicType, sourceInformation);
-      builder.add(instruction);
-      return instruction;
-    }
-  }
-
-  HInstruction readThis() {
-    HInstruction res = readLocal(closureData.thisLocal);
-    if (res.instructionType == null) {
-      res.instructionType = builder.getTypeOfThis();
-    }
-    return res;
-  }
-
-  HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) {
-    // If the element is a parameter, we already have a
-    // HParameterValue for it. We cannot create another one because
-    // it could then have another name than the real parameter. And
-    // the other one would not know it is just a copy of the real
-    // parameter.
-    if (local is ParameterElement) {
-      assert(invariant(local, builder.parameters.containsKey(local),
-          message: "No local value for parameter $local in "
-              "${builder.parameters}."));
-      return builder.parameters[local];
-    }
-
-    return builder.activationVariables.putIfAbsent(local, () {
-      JavaScriptBackend backend = builder.backend;
-      HLocalValue localValue = new HLocalValue(local, backend.nonNullType)
-        ..sourceInformation = sourceInformation;
-      builder.graph.entry.addAtExit(localValue);
-      return localValue;
-    });
-  }
-
-  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.
-   */
-  void updateLocal(Local local, HInstruction value,
-      {SourceInformation sourceInformation}) {
-    if (value is HRef) {
-      HRef ref = value;
-      value = ref.value;
-    }
-    assert(!isStoredInClosureField(local));
-    if (isAccessedDirectly(local)) {
-      directLocals[local] = value;
-    } else if (isBoxed(local)) {
-      BoxFieldElement redirect = redirectionMapping[local];
-      // The box itself could be captured, or be local. A local variable that
-      // is captured will be boxed, but the box itself will be a local.
-      // Inside the closure the box is stored in a closure-field and cannot
-      // be accessed directly.
-      HInstruction box = readLocal(redirect.box);
-      builder.add(new HFieldSet(redirect, box, value)
-        ..sourceInformation = sourceInformation);
-    } else {
-      assert(isUsedInTryOrGenerator(local));
-      HLocalValue localValue = getLocal(local);
-      builder.add(new HLocalSet(local, localValue, value)
-        ..sourceInformation = sourceInformation);
-    }
-  }
-
-  /**
-   * This function, startLoop, must be called before visiting any children of
-   * the loop. In particular it needs to be called before executing the
-   * initializers.
-   *
-   * The [LocalsHandler] will make the boxes and updates at the right moment.
-   * The builder just needs to call [enterLoopBody] and [enterLoopUpdates]
-   * (for [ast.For] loops) at the correct places. For phi-handling
-   * [beginLoopHeader] and [endLoop] must also be called.
-   *
-   * The correct place for the box depends on the given loop. In most cases
-   * the box will be created when entering the loop-body: while, do-while, and
-   * for-in (assuming the call to [:next:] is inside the body) can always be
-   * constructed this way.
-   *
-   * Things are slightly more complicated for [ast.For] loops. If no declared
-   * loop variable is boxed then the loop-body approach works here too. If a
-   * loop-variable is boxed we need to introduce a new box for the
-   * loop-variable before we enter the initializer so that the initializer
-   * writes the values into the box. In any case we need to create the box
-   * before the condition since the condition could box the variable.
-   * Since the first box is created outside the actual loop we have a second
-   * location where a box is created: just before the updates. This is
-   * necessary since updates are considered to be part of the next iteration
-   * (and can again capture variables).
-   *
-   * For example the following Dart code prints 1 3 -- 3 4.
-   *
-   *     var fs = [];
-   *     for (var i = 0; i < 3; (f() { fs.add(f); print(i); i++; })()) {
-   *       i++;
-   *     }
-   *     print("--");
-   *     for (var i = 0; i < 2; i++) fs[i]();
-   *
-   * We solve this by emitting the following code (only for [ast.For] loops):
-   *  <Create box>    <== move the first box creation outside the loop.
-   *  <initializer>;
-   *  loop-entry:
-   *    if (!<condition>) goto loop-exit;
-   *    <body>
-   *    <update box>  // create a new box and copy the captured loop-variables.
-   *    <updates>
-   *    goto loop-entry;
-   *  loop-exit:
-   */
-  void startLoop(ast.Node node) {
-    ClosureScope scopeData = closureData.capturingScopes[node];
-    if (scopeData == null) return;
-    if (scopeData.hasBoxedLoopVariables()) {
-      // If there are boxed loop variables then we set up the box and
-      // redirections already now. This way the initializer can write its
-      // values into the box.
-      // For other loops the box will be created when entering the body.
-      enterScope(node, null);
-    }
-  }
-
-  /**
-   * Create phis at the loop entry for local variables (ready for the values
-   * from the back edge).  Populate the phis with the current values.
-   */
-  void beginLoopHeader(HBasicBlock loopEntry) {
-    // Create a copy because we modify the map while iterating over it.
-    Map<Local, HInstruction> savedDirectLocals =
-        new Map<Local, HInstruction>.from(directLocals);
-
-    JavaScriptBackend backend = builder.backend;
-    // Create phis for all elements in the definitions environment.
-    savedDirectLocals.forEach((Local local, HInstruction instruction) {
-      if (isAccessedDirectly(local)) {
-        // We know 'this' cannot be modified.
-        if (local != closureData.thisLocal) {
-          HPhi phi =
-              new HPhi.singleInput(local, instruction, backend.dynamicType);
-          loopEntry.addPhi(phi);
-          directLocals[local] = phi;
-        } else {
-          directLocals[local] = instruction;
-        }
-      }
-    });
-  }
-
-  void enterLoopBody(ast.Node node) {
-    ClosureScope scopeData = closureData.capturingScopes[node];
-    if (scopeData == null) return;
-    // If there are no declared boxed loop variables then we did not create the
-    // box before the initializer and we have to create the box now.
-    if (!scopeData.hasBoxedLoopVariables()) {
-      enterScope(node, null);
-    }
-  }
-
-  void enterLoopUpdates(ast.Node node) {
-    // If there are declared boxed loop variables then the updates might have
-    // access to the box and we must switch to a new box before executing the
-    // updates.
-    // In all other cases a new box will be created when entering the body of
-    // the next iteration.
-    ClosureScope scopeData = closureData.capturingScopes[node];
-    if (scopeData == null) return;
-    if (scopeData.hasBoxedLoopVariables()) {
-      updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables);
-    }
-  }
-
-  /**
-   * Goes through the phis created in beginLoopHeader entry and adds the
-   * input from the back edge (from the current value of directLocals) to them.
-   */
-  void endLoop(HBasicBlock loopEntry) {
-    // If the loop has an aborting body, we don't update the loop
-    // phis.
-    if (loopEntry.predecessors.length == 1) return;
-    loopEntry.forEachPhi((HPhi phi) {
-      Local element = phi.sourceElement;
-      HInstruction postLoopDefinition = directLocals[element];
-      phi.addInput(postLoopDefinition);
-    });
-  }
-
-  /**
-   * Merge [otherLocals] into this locals handler, creating phi-nodes when
-   * there is a conflict.
-   * If a phi node is necessary, it will use this handler's instruction as the
-   * first input, and the otherLocals instruction as the second.
-   */
-  void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) {
-    // If an element is in one map but not the other we can safely
-    // ignore it. It means that a variable was declared in the
-    // block. Since variable declarations are scoped the declared
-    // variable cannot be alive outside the block. Note: this is only
-    // true for nodes where we do joins.
-    Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
-    JavaScriptBackend backend = builder.backend;
-    otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
-      // We know 'this' cannot be modified.
-      if (local == closureData.thisLocal) {
-        assert(directLocals[local] == instruction);
-        joinedLocals[local] = instruction;
-      } else {
-        HInstruction mine = directLocals[local];
-        if (mine == null) return;
-        if (identical(instruction, mine)) {
-          joinedLocals[local] = instruction;
-        } else {
-          HInstruction phi = new HPhi.manyInputs(
-              local, <HInstruction>[mine, instruction], backend.dynamicType);
-          joinBlock.addPhi(phi);
-          joinedLocals[local] = phi;
-        }
-      }
-    });
-    directLocals = joinedLocals;
-  }
-
-  /**
-   * When control flow merges, this method can be used to merge several
-   * localsHandlers into a new one using phis.  The new localsHandler is
-   * returned.  Unless it is also in the list, the current localsHandler is not
-   * used for its values, only for its declared variables. This is a way to
-   * exclude local values from the result when they are no longer in scope.
-   */
-  LocalsHandler mergeMultiple(
-      List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) {
-    assert(localsHandlers.length > 0);
-    if (localsHandlers.length == 1) return localsHandlers[0];
-    Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
-    HInstruction thisValue = null;
-    JavaScriptBackend backend = builder.backend;
-    directLocals.forEach((Local local, HInstruction instruction) {
-      if (local != closureData.thisLocal) {
-        HPhi phi = new HPhi.noInputs(local, backend.dynamicType);
-        joinedLocals[local] = phi;
-        joinBlock.addPhi(phi);
-      } else {
-        // We know that "this" never changes, if it's there.
-        // Save it for later. While merging, there is no phi for "this",
-        // so we don't have to special case it in the merge loop.
-        thisValue = instruction;
-      }
-    });
-    for (LocalsHandler handler in localsHandlers) {
-      handler.directLocals.forEach((Local local, HInstruction instruction) {
-        HPhi phi = joinedLocals[local];
-        if (phi != null) {
-          phi.addInput(instruction);
-        }
-      });
-    }
-    if (thisValue != null) {
-      // If there was a "this" for the scope, add it to the new locals.
-      joinedLocals[closureData.thisLocal] = thisValue;
-    }
-
-    // Remove locals that are not in all handlers.
-    directLocals = new Map<Local, HInstruction>();
-    joinedLocals.forEach((Local local, HInstruction instruction) {
-      if (local != closureData.thisLocal &&
-          instruction.inputs.length != localsHandlers.length) {
-        joinBlock.removePhi(instruction);
-      } else {
-        directLocals[local] = instruction;
-      }
-    });
-    return this;
-  }
-}
-
 // Represents a single break/continue instruction.
 class JumpHandlerEntry {
   final HJump jumpInstruction;
@@ -1012,7 +354,8 @@
         BaseImplementationOfSuperIndexSetIfNullMixin,
         SemanticSendResolvedMixin,
         NewBulkMixin,
-        ErrorBulkMixin
+        ErrorBulkMixin,
+        GraphBuilder
     implements SemanticSendVisitor {
   /// The element for which this SSA builder is being used.
   final Element target;
@@ -1049,38 +392,6 @@
   /* This field is used by the native handler. */
   final NativeEmitter nativeEmitter;
 
-  /// Holds the resulting SSA graph.
-  final HGraph graph = new HGraph();
-
-  /**
-   * The current block to add instructions to. Might be null, if we are
-   * visiting dead code, but see [isReachable].
-   */
-  HBasicBlock _current;
-
-  HBasicBlock get current => _current;
-
-  void set current(c) {
-    isReachable = c != null;
-    _current = c;
-  }
-
-  /**
-   * The most recently opened block. Has the same value as [current] while
-   * the block is open, but unlike [current], it isn't cleared when the
-   * current block is closed.
-   */
-  HBasicBlock lastOpenedBlock;
-
-  /**
-   * Indicates whether the current block is dead (because it has a throw or a
-   * return further up). If this is false, then [current] may be null. If the
-   * block is dead then it may also be aborted, but for simplicity we only
-   * abort on statement boundaries, not in the middle of expressions. See
-   * isAborted.
-   */
-  bool isReachable = true;
-
   /**
    * True if we are visiting the expression of a throw statement; we assume this
    * is a slow path.
@@ -1104,20 +415,8 @@
 
   HInstruction rethrowableException;
 
-  HParameterValue lastAddedParameter;
-
-  Map<ParameterElement, HInstruction> parameters =
-      <ParameterElement, HInstruction>{};
-
   Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{};
 
-  /**
-   * Variables stored in the current activation. These variables are
-   * being updated in try/catch blocks, and should be
-   * accessed indirectly through [HLocalGet] and [HLocalSet].
-   */
-  Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{};
-
   // We build the Ssa graph by simulating a stack machine.
   List<HInstruction> stack = <HInstruction>[];
 
@@ -1144,12 +443,12 @@
         this.rti = backend.rti {
     assert(target.isImplementation);
     graph.element = target;
-    localsHandler = new LocalsHandler(this, target, null);
     sourceElementStack.add(target);
     sourceInformationBuilder =
         sourceInformationFactory.createBuilderForContext(resolvedAst);
     graph.sourceInformation =
         sourceInformationBuilder.buildVariableDeclaration();
+    localsHandler = new LocalsHandler(this, target, null, compiler);
   }
 
   BackendHelpers get helpers => backend.helpers;
@@ -1216,58 +515,6 @@
     return result;
   }
 
-  HBasicBlock addNewBlock() {
-    HBasicBlock block = graph.addNewBlock();
-    // If adding a new block during building of an expression, it is due to
-    // conditional expressions or short-circuit logical operators.
-    return block;
-  }
-
-  void open(HBasicBlock block) {
-    block.open();
-    current = block;
-    lastOpenedBlock = block;
-  }
-
-  HBasicBlock close(HControlFlow end) {
-    HBasicBlock result = current;
-    current.close(end);
-    current = null;
-    return result;
-  }
-
-  HBasicBlock closeAndGotoExit(HControlFlow end) {
-    HBasicBlock result = current;
-    current.close(end);
-    current = null;
-    result.addSuccessor(graph.exit);
-    return result;
-  }
-
-  void goto(HBasicBlock from, HBasicBlock to) {
-    from.close(new HGoto());
-    from.addSuccessor(to);
-  }
-
-  bool isAborted() {
-    return current == null;
-  }
-
-  /**
-   * Creates a new block, transitions to it from any current block, and
-   * opens the new block.
-   */
-  HBasicBlock openNewBlock() {
-    HBasicBlock newBlock = addNewBlock();
-    if (!isAborted()) goto(current, newBlock);
-    open(newBlock);
-    return newBlock;
-  }
-
-  void add(HInstruction instruction) {
-    current.add(instruction);
-  }
-
   void addWithPosition(HInstruction instruction, ast.Node node) {
     add(attachPosition(instruction, node));
   }
@@ -1436,11 +683,7 @@
       // A generative constructor body is not seen by global analysis,
       // so we should not query for its type.
       if (!element.isGenerativeConstructorBody) {
-        // Don't inline if the return type was inferred to be non-null empty.
-        // This means that the function always throws an exception.
-        TypeMask returnType =
-            compiler.typesTask.getGuaranteedReturnTypeOfElement(element);
-        if (returnType != null && returnType.isEmpty) {
+        if (compiler.globalInference.throwsAlways(element)) {
           isReachable = false;
           return false;
         }
@@ -1577,8 +820,7 @@
       // ConstructorBodyElements are not in the type inference graph.
       return false;
     }
-    TypesInferrer inferrer = compiler.typesTask.typesInferrer;
-    return inferrer.isCalledOnce(element);
+    return compiler.globalInference.isCalledOnce(element);
   }
 
   bool isCalledOnce(Element element) {
@@ -1604,7 +846,7 @@
 
   /**
    * Return null so it is simple to remove the optional parameters completely
-   * from interop methods to match JavaScript semantics for ommitted arguments.
+   * from interop methods to match JavaScript semantics for omitted arguments.
    */
   HInstruction handleConstantForOptionalParameterJsInterop(Element parameter) =>
       null;
@@ -1654,38 +896,6 @@
     return graph.addConstant(getConstantForNode(node), compiler);
   }
 
-  TypeMask cachedTypeOfThis;
-
-  TypeMask getTypeOfThis() {
-    TypeMask result = cachedTypeOfThis;
-    if (result == null) {
-      ThisLocal local = localsHandler.closureData.thisLocal;
-      ClassElement cls = local.enclosingClass;
-      ClassWorld classWorld = compiler.world;
-      if (classWorld.isUsedAsMixin(cls)) {
-        // If the enclosing class is used as a mixin, [:this:] can be
-        // of the class that mixins the enclosing class. These two
-        // classes do not have a subclass relationship, so, for
-        // simplicity, we mark the type as an interface type.
-        result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world);
-      } else {
-        result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world);
-      }
-      cachedTypeOfThis = result;
-    }
-    return result;
-  }
-
-  Map<Element, TypeMask> cachedTypesOfCapturedVariables =
-      new Map<Element, TypeMask>();
-
-  TypeMask getTypeOfCapturedVariable(Element element) {
-    assert(element.isField);
-    return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
-      return TypeMaskFactory.inferredTypeForElement(element, compiler);
-    });
-  }
-
   /**
    * Documentation wanted -- johnniwinther
    *
@@ -1709,7 +919,7 @@
     }
     assert(invariant(functionElement, !function.modifiers.isExternal));
 
-    // If [functionElement] is `operator==` we explicitely add a null check at
+    // If [functionElement] is `operator==` we explicitly add a null check at
     // the beginning of the method. This is to avoid having call sites do the
     // null check.
     if (name == '==') {
@@ -1726,7 +936,7 @@
             sourceInformation: sourceInformationBuilder.buildIf(function.body));
       }
     }
-    if (const bool.fromEnvironment('unreachable-throw') == true) {
+    if (const bool.fromEnvironment('unreachable-throw')) {
       var emptyParameters =
           parameters.values.where((p) => p.instructionType.isEmpty);
       if (emptyParameters.length > 0) {
@@ -1832,18 +1042,6 @@
     return bodyElement;
   }
 
-  HParameterValue addParameter(Entity parameter, TypeMask type) {
-    assert(inliningStack.isEmpty);
-    HParameterValue result = new HParameterValue(parameter, type);
-    if (lastAddedParameter == null) {
-      graph.entry.addBefore(graph.entry.first, result);
-    } else {
-      graph.entry.addAfter(lastAddedParameter, result);
-    }
-    lastAddedParameter = result;
-    return result;
-  }
-
   /**
    * This method sets up the local state of the builder for inlining [function].
    * The arguments of the function are inserted into the [localsHandler].
@@ -1858,7 +1056,7 @@
       {InterfaceType instanceType}) {
     ResolvedAst resolvedAst = function.resolvedAst;
     assert(resolvedAst != null);
-    localsHandler = new LocalsHandler(this, function, instanceType);
+    localsHandler = new LocalsHandler(this, function, instanceType, compiler);
     localsHandler.closureData =
         compiler.closureToClassMapper.computeClosureToClassMapping(resolvedAst);
     returnLocal = new SyntheticLocal("result", function);
@@ -2326,11 +1524,14 @@
     }
     removeInlinedInstantiation(type);
     // Create the runtime type information, if needed.
-    if (backend.classNeedsRti(classElement)) {
-      // Read the values of the type arguments and create a list to set on the
-      // newly create object.  We can identify the case where the new list
-      // would be of the form:
+    if (classElement.typeVariables.isNotEmpty &&
+        backend.classNeedsRti(classElement)) {
+      // Read the values of the type arguments and create a HTypeInfoExpression
+      // to set on the newly create object.  We can identify the case where the
+      // expression would be of the form:
+      //
       //  [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)]
+      //
       // and k is the number of type arguments of this.  If this is the case,
       // we can simply copy the list from this.
 
@@ -2343,41 +1544,42 @@
       // of `this`.
 
       /// Helper to identify instructions that read a type variable without
-      /// substitution (that is, directly use the index). These instructions
-      /// are of the form:
-      ///   HInvokeStatic(getTypeArgumentByIndex, this, index)
+      /// substitution (that is, directly use the index). These are
+      /// HTypeInfoReadVariable instructions that require no substitution.
       ///
       /// Return `true` if [instruction] is of that form and the index is the
       /// next index in the sequence (held in [expectedIndex]).
+
+      /// TODO: Move this to a simplifier optimization of HTypeInfoExpression.
       bool isIndexedTypeArgumentGet(HInstruction instruction) {
-        if (instruction is! HInvokeStatic) return false;
-        HInvokeStatic invoke = instruction;
-        if (invoke.element != helpers.getTypeArgumentByIndex) {
-          return false;
+        if (instruction is HTypeInfoReadVariable) {
+          HInstruction newSource = instruction.inputs[0];
+          if (newSource is! HThis) {
+            return false;
+          }
+          if (source == null) {
+            // This is the first match. Extract the context class for the type
+            // variables and get the list of type variables to keep track of how
+            // many arguments we need to process.
+            source = newSource;
+            contextClass = source.sourceElement.enclosingClass;
+            if (needsSubstitutionForTypeVariableAccess(contextClass)) {
+              return false;
+            }
+            remainingTypeVariables = contextClass.typeVariables.length;
+          } else {
+            assert(source == newSource);
+          }
+          // If there are no more type variables, then there are more type
+          // arguments for the new object than the source has, and it can't be
+          // a copy.  Otherwise remove one argument.
+          if (remainingTypeVariables == 0) return false;
+          remainingTypeVariables--;
+          // Check that the index is the one we expect.
+          int index = instruction.variable.element.index;
+          return index == expectedIndex++;
         }
-        HConstant index = invoke.inputs[1];
-        HInstruction newSource = invoke.inputs[0];
-        if (newSource is! HThis) {
-          return false;
-        }
-        if (source == null) {
-          // This is the first match. Extract the context class for the type
-          // variables and get the list of type variables to keep track of how
-          // many arguments we need to process.
-          source = newSource;
-          contextClass = source.sourceElement.enclosingClass;
-          remainingTypeVariables = contextClass.typeVariables.length;
-        } else {
-          assert(source == newSource);
-        }
-        // If there are no more type variables, then there are more type
-        // arguments for the new object than the source has, and it can't be
-        // a copy.  Otherwise remove one argument.
-        if (remainingTypeVariables == 0) return false;
-        remainingTypeVariables--;
-        // Check that the index is the one we expect.
-        IntConstantValue constant = index.constant;
-        return constant.primitiveValue == expectedIndex++;
+        return false;
       }
 
       List<HInstruction> typeArguments = <HInstruction>[];
@@ -2391,10 +1593,18 @@
       });
 
       if (source != null && allIndexed && remainingTypeVariables == 0) {
-        copyRuntimeTypeInfo(source, newObject);
+        HInstruction typeInfo =
+            new HTypeInfoReadRaw(source, backend.dynamicType);
+        add(typeInfo);
+        newObject = callSetRuntimeTypeInfo(typeInfo, newObject);
       } else {
-        newObject =
-            callSetRuntimeTypeInfo(classElement, typeArguments, newObject);
+        HInstruction typeInfo = new HTypeInfoExpression(
+            TypeInfoExpressionKind.INSTANCE,
+            classElement.thisType,
+            typeArguments,
+            backend.dynamicType);
+        add(typeInfo);
+        newObject = callSetRuntimeTypeInfo(typeInfo, newObject);
       }
     }
 
@@ -3787,38 +2997,22 @@
     return new HLiteralList(inputs, backend.extendableArrayType);
   }
 
-  // TODO(karlklose): change construction of the representations to be GVN'able
-  // (dartbug.com/7182).
   HInstruction buildTypeArgumentRepresentations(DartType type) {
+    assert(!type.isTypeVariable);
     // Compute the representation of the type arguments, including access
     // to the runtime type information for type variables as instructions.
-    if (type.isTypeVariable) {
-      return buildLiteralList(<HInstruction>[addTypeVariableReference(type)]);
-    } else {
-      assert(type.element.isClass);
-      InterfaceType interface = type;
-      List<HInstruction> inputs = <HInstruction>[];
-      List<js.Expression> templates = <js.Expression>[];
-      for (DartType argument in interface.typeArguments) {
-        // As we construct the template in stages, we have to make sure that for
-        // each part the generated sub-template's holes match the index of the
-        // inputs that are later used to instantiate it. We do this by starting
-        // the indexing with the number of inputs from previous sub-templates.
-        templates.add(rtiEncoder.getTypeRepresentationWithPlaceholders(argument,
-            (variable) {
-          HInstruction runtimeType = addTypeVariableReference(variable);
-          inputs.add(runtimeType);
-        }, firstPlaceholderIndex: inputs.length));
-      }
-      // TODO(sra): This is a fresh template each time.  We can't let the
-      // template manager build them.
-      js.Template code =
-          new js.Template(null, new js.ArrayInitializer(templates));
-      HInstruction representation = new HForeignCode(
-          code, backend.readableArrayType, inputs,
-          nativeBehavior: native.NativeBehavior.PURE_ALLOCATION);
-      return representation;
+    assert(type.element.isClass);
+    InterfaceType interface = type;
+    List<HInstruction> inputs = <HInstruction>[];
+    for (DartType argument in interface.typeArguments) {
+      inputs.add(analyzeTypeArgument(argument));
     }
+    HInstruction representation = new HTypeInfoExpression(
+        TypeInfoExpressionKind.INSTANCE,
+        interface.element.thisType,
+        inputs,
+        backend.dynamicType);
+    return representation;
   }
 
   @override
@@ -4461,7 +3655,7 @@
       SourceInformation sourceInformation) {
     // Until now we only handle these as getters.
     invariant(node, deferredLoader.isDeferredLoaderGetter);
-    Element loadFunction = compiler.loadLibraryFunction;
+    Element loadFunction = helpers.loadLibraryWrapper;
     PrefixElement prefixElement = deferredLoader.enclosingElement;
     String loadId =
         compiler.deferredLoadTask.getImportDeferName(node, prefixElement);
@@ -4710,32 +3904,15 @@
   }
 
   /**
-   * Generate code to extract the type arguments from the object, substitute
-   * them as an instance of the type we are testing against (if necessary), and
-   * extract the type argument by the index of the variable in the list of type
-   * variables for that class.
+   * Generate code to extract the type argument from the object.
    */
-  HInstruction readTypeVariable(ClassElement cls, TypeVariableElement variable,
+  HInstruction readTypeVariable(TypeVariableType variable,
       {SourceInformation sourceInformation}) {
     assert(sourceElement.isInstanceMember);
-
+    assert(variable is! MethodTypeVariableType);
     HInstruction target = localsHandler.readThis();
-    HConstant index = graph.addConstantInt(variable.index, compiler);
-
-    if (needsSubstitutionForTypeVariableAccess(cls)) {
-      // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
-      // string concatenation in the implementation), and may prevent
-      // segmentation of '$'.
-      js.Name substitutionName = backend.namer.runtimeTypeName(cls);
-      HInstruction substitutionNameInstr =
-          graph.addConstantStringFromName(substitutionName, compiler);
-      pushInvokeStatic(null, helpers.getRuntimeTypeArgument,
-          [target, substitutionNameInstr, index],
-          typeMask: backend.dynamicType, sourceInformation: sourceInformation);
-    } else {
-      pushInvokeStatic(null, helpers.getTypeArgumentByIndex, [target, index],
-          typeMask: backend.dynamicType, sourceInformation: sourceInformation);
-    }
+    push(new HTypeInfoReadVariable(variable, target, backend.dynamicType)
+      ..sourceInformation = sourceInformation);
     return pop();
   }
 
@@ -4753,6 +3930,9 @@
   HInstruction addTypeVariableReference(TypeVariableType type,
       {SourceInformation sourceInformation}) {
     assert(assertTypeInContext(type));
+    if (type is MethodTypeVariableType) {
+      return graph.addConstantNull(compiler);
+    }
     Element member = sourceElement;
     bool isClosure = member.enclosingElement.isClosure;
     if (isClosure) {
@@ -4777,8 +3957,7 @@
           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,
-            sourceInformation: sourceInformation);
+        return readTypeVariable(type, sourceInformation: sourceInformation);
       } else {
         assert(member.isField);
         // The type variable is stored in a parameter of the method.
@@ -4796,8 +3975,7 @@
           sourceInformation: sourceInformation);
     } else if (member.isInstanceMember) {
       // The type variable is stored on the object.
-      return readTypeVariable(member.enclosingClass, type.element,
-          sourceInformation: sourceInformation);
+      return readTypeVariable(type, sourceInformation: sourceInformation);
     } else {
       reporter.internalError(
           type.element, 'Unexpected type variable in static context.');
@@ -4819,15 +3997,14 @@
     }
 
     List<HInstruction> inputs = <HInstruction>[];
-
-    js.Expression template =
-        rtiEncoder.getTypeRepresentationWithPlaceholders(argument, (variable) {
-      inputs.add(addTypeVariableReference(variable));
+    argument.forEachTypeVariable((variable) {
+      if (variable is! MethodTypeVariableType) {
+        inputs.add(analyzeTypeArgument(variable));
+      }
     });
-
-    js.Template code = new js.Template(null, template);
-    HInstruction result = new HForeignCode(code, backend.stringType, inputs,
-        nativeBehavior: native.NativeBehavior.PURE);
+    HInstruction result = new HTypeInfoExpression(
+        TypeInfoExpressionKind.COMPLETE, argument, inputs, backend.dynamicType)
+      ..sourceInformation = sourceInformation;
     add(result);
     return result;
   }
@@ -4844,25 +4021,27 @@
     });
     // TODO(15489): Register at codegen.
     registry?.registerInstantiation(type);
-    return callSetRuntimeTypeInfo(type.element, inputs, newObject);
+    return callSetRuntimeTypeInfoWithTypeArguments(
+        type.element, inputs, newObject);
   }
 
-  void copyRuntimeTypeInfo(HInstruction source, HInstruction target) {
-    Element copyHelper = helpers.copyTypeArguments;
-    pushInvokeStatic(null, copyHelper, [source, target],
-        sourceInformation: target.sourceInformation);
-    pop();
-  }
-
-  HInstruction callSetRuntimeTypeInfo(ClassElement element,
+  HInstruction callSetRuntimeTypeInfoWithTypeArguments(ClassElement element,
       List<HInstruction> rtiInputs, HInstruction newObject) {
-    if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) {
+    if (!backend.classNeedsRti(element)) {
       return newObject;
     }
 
-    HInstruction typeInfo = buildLiteralList(rtiInputs);
+    HInstruction typeInfo = new HTypeInfoExpression(
+        TypeInfoExpressionKind.INSTANCE,
+        element.thisType,
+        rtiInputs,
+        backend.dynamicType);
     add(typeInfo);
+    return callSetRuntimeTypeInfo(typeInfo, newObject);
+  }
 
+  HInstruction callSetRuntimeTypeInfo(
+      HInstruction typeInfo, HInstruction newObject) {
     // Set the runtime type information on the object.
     Element typeInfoSetterElement = helpers.setRuntimeTypeInfo;
     pushInvokeStatic(
@@ -4877,7 +4056,7 @@
         stack.last is HInvokeStatic || stack.last == newObject,
         message: "Unexpected `stack.last`: Found ${stack.last}, "
             "expected ${newObject} or an HInvokeStatic. "
-            "State: element=$element, rtiInputs=$rtiInputs, stack=$stack."));
+            "State: typeInfo=$typeInfo, stack=$stack."));
     stack.last.instructionType = newObject.instructionType;
     return pop();
   }
@@ -4941,7 +4120,7 @@
     constructor = constructorImplementation.effectiveTarget;
 
     final bool isSymbolConstructor =
-        constructorDeclaration == compiler.symbolConstructor;
+        compiler.commonElements.isSymbolConstructor(constructorDeclaration);
     final bool isJSArrayTypedConstructor =
         constructorDeclaration == helpers.jsArrayTypedConstructor;
 
@@ -5045,8 +4224,7 @@
               ? native.NativeThrowBehavior.MAY
               : native.NativeThrowBehavior.NEVER);
       push(foreign);
-      TypesInferrer inferrer = compiler.typesTask.typesInferrer;
-      if (inferrer.isFixedArrayCheckedForGrowable(send)) {
+      if (compiler.globalInference.isFixedArrayCheckedForGrowable(send)) {
         js.Template code = js.js.parseForeignJS(r'#.fixed$length = Array');
         // We set the instruction as [canThrow] to avoid it being dead code.
         // We need a finer grained side effect.
@@ -5103,8 +4281,7 @@
       List<HInstruction> inputs, ClassElement cls, InterfaceType expectedType,
       {SourceInformation sourceInformation}) {
     if (!backend.classNeedsRti(cls)) return;
-    assert(expectedType.typeArguments.isEmpty ||
-        cls.typeVariables.length == expectedType.typeArguments.length);
+    assert(cls.typeVariables.length == expectedType.typeArguments.length);
     expectedType.typeArguments.forEach((DartType argument) {
       inputs.add(
           analyzeTypeArgument(argument, sourceInformation: sourceInformation));
@@ -5175,7 +4352,7 @@
     List<HInstruction> inputs = makeStaticArgumentList(
         callStructure, node.arguments, function.implementation);
 
-    if (function == compiler.identicalFunction) {
+    if (function == compiler.commonElements.identicalFunction) {
       pushWithPosition(
           new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
       return;
@@ -5499,7 +4676,8 @@
   @override
   void bulkHandleNew(ast.NewExpression node, [_]) {
     Element element = elements[node.send];
-    final bool isSymbolConstructor = element == compiler.symbolConstructor;
+    final bool isSymbolConstructor =
+        element == compiler.commonElements.symbolConstructor;
     if (!Elements.isMalformed(element)) {
       ConstructorElement function = element;
       element = function.effectiveTarget;
@@ -6814,7 +5992,8 @@
     }
     // TODO(15489): Register at codegen.
     registry?.registerInstantiation(type);
-    return callSetRuntimeTypeInfo(type.element, arguments, object);
+    return callSetRuntimeTypeInfoWithTypeArguments(
+        type.element, arguments, object);
   }
 
   visitLiteralList(ast.LiteralList node) {
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
new file mode 100644
index 0000000..a44ea37
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart' as ir;
+
+import '../common/codegen.dart' show CodegenWorkItem;
+import '../common/tasks.dart' show CompilerTask;
+import '../compiler.dart';
+import '../elements/elements.dart';
+import '../io/source_information.dart';
+import '../js_backend/backend.dart' show JavaScriptBackend;
+import '../kernel/kernel.dart';
+import '../kernel/kernel_visitor.dart';
+import '../resolution/tree_elements.dart';
+import 'graph_builder.dart';
+import 'locals_handler.dart';
+import 'nodes.dart';
+
+class SsaKernelBuilderTask extends CompilerTask {
+  final JavaScriptBackend backend;
+  final SourceInformationStrategy sourceInformationFactory;
+
+  String get name => 'SSA kernel builder';
+
+  SsaKernelBuilderTask(JavaScriptBackend backend, this.sourceInformationFactory)
+      : backend = backend,
+        super(backend.compiler.measurer);
+
+  HGraph build(CodegenWorkItem work) {
+    return measure(() {
+      AstElement element = work.element.implementation;
+      TreeElements treeElements = work.resolvedAst.elements;
+      Kernel kernel = new Kernel(backend.compiler);
+      KernelVisitor visitor = new KernelVisitor(element, treeElements, kernel);
+      IrFunction function;
+      try {
+        function = visitor.buildFunction();
+      } catch (e) {
+        throw "Failed to convert to Kernel IR: $e";
+      }
+      KernelSsaBuilder builder = new KernelSsaBuilder(
+          function,
+          element,
+          work.resolvedAst,
+          backend.compiler,
+          sourceInformationFactory,
+          visitor.nodeToElement);
+      return builder.build();
+    });
+  }
+}
+
+class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
+  final IrFunction function;
+  final FunctionElement functionElement;
+  final ResolvedAst resolvedAst;
+  final Compiler compiler;
+  final Map<ir.Node, Element> nodeToElement;
+
+  JavaScriptBackend get backend => compiler.backend;
+
+  LocalsHandler localsHandler;
+  SourceInformationBuilder sourceInformationBuilder;
+
+  KernelSsaBuilder(
+      this.function,
+      this.functionElement,
+      this.resolvedAst,
+      this.compiler,
+      SourceInformationStrategy sourceInformationFactory,
+      this.nodeToElement) {
+    graph.element = functionElement;
+    // TODO(het): Should sourceInformationBuilder be in GraphBuilder?
+    this.sourceInformationBuilder =
+        sourceInformationFactory.createBuilderForContext(resolvedAst);
+    graph.sourceInformation =
+        sourceInformationBuilder.buildVariableDeclaration();
+    this.localsHandler =
+        new LocalsHandler(this, functionElement, null, compiler);
+  }
+
+  HGraph build() {
+    // TODO(het): no reason to do this here...
+    HInstruction.idCounter = 0;
+    if (function.kind == ir.ProcedureKind.Method) {
+      buildMethod(function, functionElement);
+    } else {
+      compiler.reporter.internalError(
+          functionElement,
+          "Unable to convert this kind of Kernel "
+          "procedure to SSA: ${function.kind}");
+    }
+    assert(graph.isValid());
+    return graph;
+  }
+
+  /// Builds a SSA graph for [method].
+  void buildMethod(IrFunction method, FunctionElement functionElement) {
+    openFunction(method, functionElement);
+    method.node.body.accept(this);
+    closeFunction();
+  }
+
+  void openFunction(IrFunction method, FunctionElement functionElement) {
+    HBasicBlock block = graph.addNewBlock();
+    open(graph.entry);
+    // TODO(het): Register parameters with a locals handler
+    localsHandler.startFunction(functionElement, resolvedAst.node);
+    close(new HGoto()).addSuccessor(block);
+
+    open(block);
+  }
+
+  void closeFunction() {
+    if (!isAborted()) closeAndGotoExit(new HGoto());
+    graph.finalize();
+  }
+}
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index e961485..c235348 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2855,6 +2855,75 @@
     }
   }
 
+  void visitTypeInfoReadRaw(HTypeInfoReadRaw node) {
+    use(node.inputs[0]);
+    js.Expression receiver = pop();
+    push(js.js(r'#.$builtinTypeInfo', receiver));
+  }
+
+  void visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
+    TypeVariableElement element = node.variable.element;
+    ClassElement context = element.enclosingClass;
+
+    int index = element.index;
+    use(node.inputs[0]);
+    js.Expression receiver = pop();
+
+    if (needsSubstitutionForTypeVariableAccess(context)) {
+      js.Expression typeName =
+          js.quoteName(backend.namer.runtimeTypeName(context));
+      Element helperElement = helpers.getRuntimeTypeArgument;
+      registry.registerStaticUse(
+          new StaticUse.staticInvoke(helperElement, CallStructure.THREE_ARGS));
+      js.Expression helper =
+          backend.emitter.staticFunctionAccess(helperElement);
+      push(js.js(
+          r'#(#, #, #)', [helper, receiver, typeName, js.js.number(index)]));
+    } else {
+      Element helperElement = helpers.getTypeArgumentByIndex;
+      registry.registerStaticUse(
+          new StaticUse.staticInvoke(helperElement, CallStructure.TWO_ARGS));
+      js.Expression helper =
+          backend.emitter.staticFunctionAccess(helperElement);
+      push(js.js(r'#(#, #)', [helper, receiver, js.js.number(index)]));
+    }
+  }
+
+  void visitTypeInfoExpression(HTypeInfoExpression node) {
+    List<js.Expression> arguments = <js.Expression>[];
+    for (HInstruction input in node.inputs) {
+      use(input);
+      arguments.add(pop());
+    }
+
+    switch (node.kind) {
+      case TypeInfoExpressionKind.COMPLETE:
+        int index = 0;
+        js.Expression result = backend.rtiEncoder.getTypeRepresentation(
+            node.dartType, (TypeVariableType variable) => arguments[index++]);
+        assert(index == node.inputs.length);
+        push(result);
+        return;
+
+      case TypeInfoExpressionKind.INSTANCE:
+        // We expect only flat types for the INSTANCE representation.
+        assert(
+            node.dartType == (node.dartType.element as ClassElement).thisType);
+        registry.registerInstantiatedClass(coreClasses.listClass);
+        push(new js.ArrayInitializer(arguments)
+            .withSourceInformation(node.sourceInformation));
+    }
+  }
+
+  bool needsSubstitutionForTypeVariableAccess(ClassElement cls) {
+    ClassWorld classWorld = compiler.world;
+    if (classWorld.isUsedAsMixin(cls)) return true;
+
+    return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
+      return !backend.rti.isTrivialSubstitution(subclass, cls);
+    });
+  }
+
   void visitReadTypeVariable(HReadTypeVariable node) {
     TypeVariableElement element = node.dartType.element;
     Element helperElement = helpers.convertRtiToRuntimeType;
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 5a0f558..dca34c5 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -96,49 +96,61 @@
 
   HInstruction visitInvokeDynamic(HInvokeDynamic node) {
     if (node.isInterceptedCall) {
-      // Calls of the form
-      //
-      //     a.foo$1(a, x)
-      //
-      // where the interceptor calling convention is used come from recognizing
-      // that 'a' is a 'self-interceptor'.  If the selector matches only methods
-      // that ignore the explicit receiver parameter, replace occurences of the
-      // receiver argument with a dummy receiver '0':
-      //
-      //     a.foo$1(a, x)   --->   a.foo$1(0, x)
-      //
-      // This often reduces the number of references to 'a' to one, allowing 'a'
-      // to be generated at use to avoid a temporary, e.g.
-      //
-      //     t1 = b.get$thing();
-      //     t1.foo$1(t1, x)
-      // --->
-      //     b.get$thing().foo$1(0, x)
-      //
-      Selector selector = node.selector;
-      TypeMask mask = node.mask;
+      tryReplaceInterceptorWithDummy(node, node.selector, node.mask);
+    }
+    return node;
+  }
+
+  HInstruction visitInvokeSuper(HInvokeSuper node) {
+    if (node.isInterceptedCall) {
+      TypeMask mask = node.getDartReceiver(compiler).instructionType;
+      tryReplaceInterceptorWithDummy(node, node.selector, mask);
+    }
+    return node;
+  }
+
+  void tryReplaceInterceptorWithDummy(
+      HInvoke node, Selector selector, TypeMask mask) {
+    // Calls of the form
+    //
+    //     a.foo$1(a, x)
+    //
+    // where the interceptor calling convention is used come from recognizing
+    // that 'a' is a 'self-interceptor'.  If the selector matches only methods
+    // that ignore the explicit receiver parameter, replace occurences of the
+    // receiver argument with a dummy receiver '0':
+    //
+    //     a.foo$1(a, x)   --->   a.foo$1(0, x)
+    //
+    // This often reduces the number of references to 'a' to one, allowing 'a'
+    // to be generated at use to avoid a temporary, e.g.
+    //
+    //     t1 = b.get$thing();
+    //     t1.foo$1(t1, x)
+    // --->
+    //     b.get$thing().foo$1(0, x)
+    //
+
+    // TODO(15933): Make automatically generated property extraction closures
+    // work with the dummy receiver optimization.
+    if (selector.isGetter) return;
+
+    // This assignment of inputs is uniform for HInvokeDynamic and HInvokeSuper.
+    HInstruction interceptor = node.inputs[0];
+    HInstruction receiverArgument = node.inputs[1];
+
+    if (interceptor.nonCheck() == receiverArgument.nonCheck()) {
       if (backend.isInterceptedSelector(selector) &&
           !backend.isInterceptedMixinSelector(selector, mask)) {
-        HInstruction interceptor = node.inputs[0];
-        HInstruction receiverArgument = node.inputs[1];
-
-        if (interceptor.nonCheck() == receiverArgument.nonCheck()) {
-          // TODO(15933): Make automatically generated property extraction
-          // closures work with the dummy receiver optimization.
-          if (!selector.isGetter) {
-            ConstantValue constant = new SyntheticConstantValue(
-                SyntheticConstantKind.DUMMY_INTERCEPTOR,
-                receiverArgument.instructionType);
-            HConstant dummy = graph.addConstant(constant, compiler);
-            receiverArgument.usedBy.remove(node);
-            node.inputs[1] = dummy;
-            dummy.usedBy.add(node);
-          }
-        }
+        ConstantValue constant = new SyntheticConstantValue(
+            SyntheticConstantKind.DUMMY_INTERCEPTOR,
+            receiverArgument.instructionType);
+        HConstant dummy = graph.addConstant(constant, compiler);
+        receiverArgument.usedBy.remove(node);
+        node.inputs[1] = dummy;
+        dummy.usedBy.add(node);
       }
     }
-
-    return node;
   }
 
   HInstruction visitFieldSet(HFieldSet setter) {
diff --git a/pkg/compiler/lib/src/ssa/graph_builder.dart b/pkg/compiler/lib/src/ssa/graph_builder.dart
new file mode 100644
index 0000000..969899f
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/graph_builder.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../elements/elements.dart';
+import '../types/types.dart';
+import 'nodes.dart';
+
+/// Base class for objects that build up an SSA graph.
+///
+/// This contains helpers for building the graph and tracking information about
+/// the current state of the graph being built.
+abstract class GraphBuilder {
+  /// Holds the resulting SSA graph.
+  final HGraph graph = new HGraph();
+
+  HBasicBlock _current;
+
+  /// The current block to add instructions to. Might be null, if we are
+  /// visiting dead code, but see [isReachable].
+  HBasicBlock get current => _current;
+
+  void set current(c) {
+    isReachable = c != null;
+    _current = c;
+  }
+
+  /// The most recently opened block. Has the same value as [current] while
+  /// the block is open, but unlike [current], it isn't cleared when the
+  /// current block is closed.
+  HBasicBlock lastOpenedBlock;
+
+  /// Indicates whether the current block is dead (because it has a throw or a
+  /// return further up). If this is false, then [current] may be null. If the
+  /// block is dead then it may also be aborted, but for simplicity we only
+  /// abort on statement boundaries, not in the middle of expressions. See
+  /// [isAborted].
+  bool isReachable = true;
+
+  HParameterValue lastAddedParameter;
+
+  Map<ParameterElement, HInstruction> parameters =
+      <ParameterElement, HInstruction>{};
+
+  HBasicBlock addNewBlock() {
+    HBasicBlock block = graph.addNewBlock();
+    // If adding a new block during building of an expression, it is due to
+    // conditional expressions or short-circuit logical operators.
+    return block;
+  }
+
+  void open(HBasicBlock block) {
+    block.open();
+    current = block;
+    lastOpenedBlock = block;
+  }
+
+  HBasicBlock close(HControlFlow end) {
+    HBasicBlock result = current;
+    current.close(end);
+    current = null;
+    return result;
+  }
+
+  HBasicBlock closeAndGotoExit(HControlFlow end) {
+    HBasicBlock result = current;
+    current.close(end);
+    current = null;
+    result.addSuccessor(graph.exit);
+    return result;
+  }
+
+  void goto(HBasicBlock from, HBasicBlock to) {
+    from.close(new HGoto());
+    from.addSuccessor(to);
+  }
+
+  bool isAborted() {
+    return current == null;
+  }
+
+  /// Creates a new block, transitions to it from any current block, and
+  /// opens the new block.
+  HBasicBlock openNewBlock() {
+    HBasicBlock newBlock = addNewBlock();
+    if (!isAborted()) goto(current, newBlock);
+    open(newBlock);
+    return newBlock;
+  }
+
+  void add(HInstruction instruction) {
+    current.add(instruction);
+  }
+
+  HParameterValue addParameter(Entity parameter, TypeMask type) {
+    HParameterValue result = new HParameterValue(parameter, type);
+    if (lastAddedParameter == null) {
+      graph.entry.addBefore(graph.entry.first, result);
+    } else {
+      graph.entry.addAfter(lastAddedParameter, result);
+    }
+    lastAddedParameter = result;
+    return result;
+  }
+}
diff --git a/pkg/compiler/lib/src/ssa/locals_handler.dart b/pkg/compiler/lib/src/ssa/locals_handler.dart
new file mode 100644
index 0000000..dd36480
--- /dev/null
+++ b/pkg/compiler/lib/src/ssa/locals_handler.dart
@@ -0,0 +1,655 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../closure.dart';
+import '../common.dart';
+import '../compiler.dart' show Compiler;
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import '../io/source_information.dart';
+import '../js/js.dart' as js;
+import '../js_backend/js_backend.dart';
+import '../native/native.dart' as native;
+import '../tree/tree.dart' as ast;
+import '../types/types.dart';
+import '../world.dart' show ClassWorld;
+import 'builder.dart' show SyntheticLocal;
+import 'graph_builder.dart';
+import 'nodes.dart';
+import 'types.dart';
+
+/// Keeps track of locals (including parameters and phis) when building. The
+/// 'this' reference is treated as parameter and hence handled by this class,
+/// too.
+class LocalsHandler {
+  /// The values of locals that can be directly accessed (without redirections
+  /// to boxes or closure-fields).
+  ///
+  /// [directLocals] is iterated, so it is "insertion ordered" to make the
+  /// iteration order a function only of insertions and not a function of
+  /// e.g. Element hash codes.  I'd prefer to use a SortedMap but some elements
+  /// don't have source locations for [Elements.compareByPosition].
+  Map<Local, HInstruction> directLocals = new Map<Local, HInstruction>();
+  Map<Local, CapturedVariable> redirectionMapping =
+      new Map<Local, CapturedVariable>();
+  final GraphBuilder 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.
+  ClassElement get contextClass => executableContext.contextClass;
+
+  /// The type of the current instance, if concrete.
+  ///
+  /// This allows for handling fixed type argument in case of inlining. For
+  /// instance, checking `'foo'` against `String` instead of `T` in `main`:
+  ///
+  ///     class Foo<T> {
+  ///       T field;
+  ///       Foo(this.field);
+  ///     }
+  ///     main() {
+  ///       new Foo<String>('foo');
+  ///     }
+  ///
+  /// [instanceType] is not used if it contains type variables, since these
+  /// might not be in scope or from the current instance.
+  ///
+  final InterfaceType instanceType;
+
+  final Compiler compiler;
+
+  LocalsHandler(this.builder, this.executableContext,
+      InterfaceType instanceType, this.compiler)
+      : this.instanceType =
+            instanceType == null || instanceType.containsTypeVariables
+                ? null
+                : instanceType;
+
+  /// Substituted type variables occurring in [type] into the context of
+  /// [contextClass].
+  DartType substInContext(DartType type) {
+    if (contextClass != null) {
+      ClassElement typeContext = Types.getClassContext(type);
+      if (typeContext != null) {
+        type = type.substByContext(contextClass.asInstanceOf(typeContext));
+      }
+    }
+    if (instanceType != null) {
+      type = type.substByContext(instanceType);
+    }
+    return type;
+  }
+
+  /// Creates a new [LocalsHandler] based on [other]. We only need to
+  /// copy the [directLocals], since the other fields can be shared
+  /// throughout the AST visit.
+  LocalsHandler.from(LocalsHandler other)
+      : directLocals = new Map<Local, HInstruction>.from(other.directLocals),
+        redirectionMapping = other.redirectionMapping,
+        executableContext = other.executableContext,
+        instanceType = other.instanceType,
+        builder = other.builder,
+        closureData = other.closureData,
+        compiler = other.compiler,
+        activationVariables = other.activationVariables,
+        cachedTypeOfThis = other.cachedTypeOfThis,
+        cachedTypesOfCapturedVariables = other.cachedTypesOfCapturedVariables;
+
+  /// Redirects accesses from element [from] to element [to]. The [to] element
+  /// must be a boxed variable or a variable that is stored in a closure-field.
+  void redirectElement(Local from, CapturedVariable to) {
+    assert(redirectionMapping[from] == null);
+    redirectionMapping[from] = to;
+    assert(isStoredInClosureField(from) || isBoxed(from));
+  }
+
+  HInstruction createBox() {
+    // TODO(floitsch): Clean up this hack. Should we create a box-object by
+    // just creating an empty object literal?
+    JavaScriptBackend backend = compiler.backend;
+    HInstruction box = new HForeignCode(
+        js.js.parseForeignJS('{}'), backend.nonNullType, <HInstruction>[],
+        nativeBehavior: native.NativeBehavior.PURE_ALLOCATION);
+    builder.add(box);
+    return box;
+  }
+
+  /// If the scope (function or loop) [node] has captured variables then this
+  /// method creates a box and sets up the redirections.
+  void enterScope(ast.Node node, Element element) {
+    // See if any variable in the top-scope of the function is captured. If yes
+    // we need to create a box-object.
+    ClosureScope scopeData = closureData.capturingScopes[node];
+    if (scopeData == null) return;
+    HInstruction box;
+    // The scope has captured variables.
+    if (element != null && element.isGenerativeConstructorBody) {
+      // The box is passed as a parameter to a generative
+      // constructor body.
+      JavaScriptBackend backend = compiler.backend;
+      box = builder.addParameter(scopeData.boxElement, backend.nonNullType);
+    } else {
+      box = createBox();
+    }
+    // Add the box to the known locals.
+    directLocals[scopeData.boxElement] = box;
+    // 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(
+        (LocalVariableElement from, BoxFieldElement to) {
+      // The [from] can only be a parameter for function-scopes and not
+      // loop scopes.
+      if (from.isRegularParameter && !element.isGenerativeConstructorBody) {
+        // Now that the redirection is set up, the update to the local will
+        // write the parameter value into the box.
+        // Store the captured parameter in the box. Get the current value
+        // before we put the redirection in place.
+        // We don't need to update the local for a generative
+        // constructor body, because it receives a box that already
+        // contains the updates as the last parameter.
+        HInstruction instruction = readLocal(from);
+        redirectElement(from, to);
+        updateLocal(from, instruction);
+      } else {
+        redirectElement(from, to);
+      }
+    });
+  }
+
+  /// Replaces the current box with a new box and copies over the given list
+  /// of elements from the old box into the new box.
+  void updateCaptureBox(
+      BoxLocal boxElement, 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 (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);
+      HInstruction oldValue = readLocal(boxedVariable);
+      updateLocal(boxElement, newBox);
+      updateLocal(boxedVariable, oldValue);
+    }
+    updateLocal(boxElement, newBox);
+  }
+
+  /// Documentation wanted -- johnniwinther
+  ///
+  /// Invariant: [function] must be an implementation element.
+  void startFunction(AstElement element, ast.Node node) {
+    assert(invariant(element, element.isImplementation));
+    closureData = compiler.closureToClassMapper
+        .computeClosureToClassMapping(element.resolvedAst);
+
+    if (element is FunctionElement) {
+      FunctionElement functionElement = element;
+      FunctionSignature params = functionElement.functionSignature;
+      ClosureScope scopeData = closureData.capturingScopes[node];
+      params.orderedForEachParameter((ParameterElement parameterElement) {
+        if (element.isGenerativeConstructorBody) {
+          if (scopeData != null &&
+              scopeData.isCapturedVariable(parameterElement)) {
+            // The parameter will be a field in the box passed as the
+            // last parameter. So no need to have it.
+            return;
+          }
+        }
+        HInstruction parameter = builder.addParameter(parameterElement,
+            TypeMaskFactory.inferredTypeForElement(parameterElement, compiler));
+        builder.parameters[parameterElement] = parameter;
+        directLocals[parameterElement] = parameter;
+      });
+    }
+
+    enterScope(node, element);
+
+    // If the freeVariableMapping is not empty, then this function was a
+    // nested closure that captures variables. Redirect the captured
+    // variables to fields in the closure.
+    closureData.forEachFreeVariable((Local from, CapturedVariable to) {
+      redirectElement(from, to);
+    });
+    JavaScriptBackend backend = compiler.backend;
+    if (closureData.isClosure) {
+      // Inside closure redirect references to itself to [:this:].
+      HThis thisInstruction =
+          new HThis(closureData.thisLocal, backend.nonNullType);
+      builder.graph.thisInstruction = thisInstruction;
+      builder.graph.entry.addAtEntry(thisInstruction);
+      updateLocal(closureData.closureElement, thisInstruction);
+    } else if (element.isInstanceMember) {
+      // Once closures have been mapped to classes their instance members might
+      // not have any thisElement if the closure was created inside a static
+      // context.
+      HThis thisInstruction = new HThis(closureData.thisLocal, getTypeOfThis());
+      builder.graph.thisInstruction = thisInstruction;
+      builder.graph.entry.addAtEntry(thisInstruction);
+      directLocals[closureData.thisLocal] = thisInstruction;
+    }
+
+    // If this method is an intercepted method, add the extra
+    // parameter to it, that is the actual receiver for intercepted
+    // classes, or the same as [:this:] for non-intercepted classes.
+    ClassElement cls = element.enclosingClass;
+
+    // When the class extends a native class, the instance is pre-constructed
+    // and passed to the generative constructor factory function as a parameter.
+    // Instead of allocating and initializing the object, the constructor
+    // 'upgrades' the native subclass object by initializing the Dart fields.
+    bool isNativeUpgradeFactory =
+        element.isGenerativeConstructor && backend.isNativeOrExtendsNative(cls);
+    if (backend.isInterceptedMethod(element)) {
+      bool isInterceptorClass = backend.isInterceptorClass(cls.declaration);
+      String name = isInterceptorClass ? 'receiver' : '_';
+      SyntheticLocal parameter = new SyntheticLocal(name, executableContext);
+      HParameterValue value = new HParameterValue(parameter, getTypeOfThis());
+      builder.graph.explicitReceiverParameter = value;
+      builder.graph.entry.addAfter(directLocals[closureData.thisLocal], value);
+      if (builder.lastAddedParameter == null) {
+        // If this is the first parameter inserted, make sure it stays first.
+        builder.lastAddedParameter = value;
+      }
+      if (isInterceptorClass) {
+        // Only use the extra parameter in intercepted classes.
+        directLocals[closureData.thisLocal] = value;
+      }
+    } else if (isNativeUpgradeFactory) {
+      SyntheticLocal parameter =
+          new SyntheticLocal('receiver', executableContext);
+      // Unlike `this`, receiver is nullable since direct calls to generative
+      // constructor call the constructor with `null`.
+      ClassWorld classWorld = compiler.world;
+      HParameterValue value =
+          new HParameterValue(parameter, new TypeMask.exact(cls, classWorld));
+      builder.graph.explicitReceiverParameter = value;
+      builder.graph.entry.addAtEntry(value);
+    }
+  }
+
+  /// Returns true if the local can be accessed directly. Boxed variables or
+  /// captured variables that are stored in the closure-field return [:false:].
+  bool isAccessedDirectly(Local local) {
+    assert(local != null);
+    return !redirectionMapping.containsKey(local) &&
+        !closureData.variablesUsedInTryOrGenerator.contains(local);
+  }
+
+  bool isStoredInClosureField(Local local) {
+    assert(local != null);
+    if (isAccessedDirectly(local)) return false;
+    CapturedVariable redirectTarget = redirectionMapping[local];
+    if (redirectTarget == null) return false;
+    return redirectTarget is ClosureFieldElement;
+  }
+
+  bool isBoxed(Local local) {
+    if (isAccessedDirectly(local)) return false;
+    if (isStoredInClosureField(local)) return false;
+    return redirectionMapping.containsKey(local);
+  }
+
+  bool isUsedInTryOrGenerator(Local local) {
+    return closureData.variablesUsedInTryOrGenerator.contains(local);
+  }
+
+  /// Returns an [HInstruction] for the given element. If the element is
+  /// boxed or stored in a closure then the method generates code to retrieve
+  /// the value.
+  HInstruction readLocal(Local local, {SourceInformation sourceInformation}) {
+    if (isAccessedDirectly(local)) {
+      if (directLocals[local] == null) {
+        if (local is TypeVariableElement) {
+          compiler.reporter.internalError(compiler.currentElement,
+              "Runtime type information not available for $local.");
+        } else {
+          compiler.reporter.internalError(
+              local, "Cannot find value $local in ${directLocals.keys}.");
+        }
+      }
+      HInstruction value = directLocals[local];
+      if (sourceInformation != null) {
+        value = new HRef(value, sourceInformation);
+        builder.add(value);
+      }
+      return value;
+    } else if (isStoredInClosureField(local)) {
+      ClosureFieldElement redirect = redirectionMapping[local];
+      HInstruction receiver = readLocal(closureData.closureElement);
+      TypeMask type = local is BoxLocal
+          ? (compiler.backend as JavaScriptBackend).nonNullType
+          : getTypeOfCapturedVariable(redirect);
+      HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
+      builder.add(fieldGet);
+      return fieldGet..sourceInformation = sourceInformation;
+    } else if (isBoxed(local)) {
+      BoxFieldElement redirect = redirectionMapping[local];
+      // In the function that declares the captured variable the box is
+      // accessed as direct local. Inside the nested closure the box is
+      // accessed through a closure-field.
+      // Calling [readLocal] makes sure we generate the correct code to get
+      // the box.
+      HInstruction box = readLocal(redirect.box);
+      HInstruction lookup =
+          new HFieldGet(redirect, box, getTypeOfCapturedVariable(redirect));
+      builder.add(lookup);
+      return lookup..sourceInformation = sourceInformation;
+    } else {
+      assert(isUsedInTryOrGenerator(local));
+      HLocalValue localValue = getLocal(local);
+      HInstruction instruction = new HLocalGet(
+          local,
+          localValue,
+          (compiler.backend as JavaScriptBackend).dynamicType,
+          sourceInformation);
+      builder.add(instruction);
+      return instruction;
+    }
+  }
+
+  HInstruction readThis() {
+    HInstruction res = readLocal(closureData.thisLocal);
+    if (res.instructionType == null) {
+      res.instructionType = getTypeOfThis();
+    }
+    return res;
+  }
+
+  HLocalValue getLocal(Local local, {SourceInformation sourceInformation}) {
+    // If the element is a parameter, we already have a
+    // HParameterValue for it. We cannot create another one because
+    // it could then have another name than the real parameter. And
+    // the other one would not know it is just a copy of the real
+    // parameter.
+    if (local is ParameterElement) {
+      assert(invariant(local, builder.parameters.containsKey(local),
+          message: "No local value for parameter $local in "
+              "${builder.parameters}."));
+      return builder.parameters[local];
+    }
+
+    return activationVariables.putIfAbsent(local, () {
+      JavaScriptBackend backend = compiler.backend;
+      HLocalValue localValue = new HLocalValue(local, backend.nonNullType)
+        ..sourceInformation = sourceInformation;
+      builder.graph.entry.addAtExit(localValue);
+      return localValue;
+    });
+  }
+
+  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.
+  void updateLocal(Local local, HInstruction value,
+      {SourceInformation sourceInformation}) {
+    if (value is HRef) {
+      HRef ref = value;
+      value = ref.value;
+    }
+    assert(!isStoredInClosureField(local));
+    if (isAccessedDirectly(local)) {
+      directLocals[local] = value;
+    } else if (isBoxed(local)) {
+      BoxFieldElement redirect = redirectionMapping[local];
+      // The box itself could be captured, or be local. A local variable that
+      // is captured will be boxed, but the box itself will be a local.
+      // Inside the closure the box is stored in a closure-field and cannot
+      // be accessed directly.
+      HInstruction box = readLocal(redirect.box);
+      builder.add(new HFieldSet(redirect, box, value)
+        ..sourceInformation = sourceInformation);
+    } else {
+      assert(isUsedInTryOrGenerator(local));
+      HLocalValue localValue = getLocal(local);
+      builder.add(new HLocalSet(local, localValue, value)
+        ..sourceInformation = sourceInformation);
+    }
+  }
+
+  /// This function, startLoop, must be called before visiting any children of
+  /// the loop. In particular it needs to be called before executing the
+  /// initializers.
+  ///
+  /// The [LocalsHandler] will make the boxes and updates at the right moment.
+  /// The builder just needs to call [enterLoopBody] and [enterLoopUpdates]
+  /// (for [ast.For] loops) at the correct places. For phi-handling
+  /// [beginLoopHeader] and [endLoop] must also be called.
+  ///
+  /// The correct place for the box depends on the given loop. In most cases
+  /// the box will be created when entering the loop-body: while, do-while, and
+  /// for-in (assuming the call to [:next:] is inside the body) can always be
+  /// constructed this way.
+  ///
+  /// Things are slightly more complicated for [ast.For] loops. If no declared
+  /// loop variable is boxed then the loop-body approach works here too. If a
+  /// loop-variable is boxed we need to introduce a new box for the
+  /// loop-variable before we enter the initializer so that the initializer
+  /// writes the values into the box. In any case we need to create the box
+  /// before the condition since the condition could box the variable.
+  /// Since the first box is created outside the actual loop we have a second
+  /// location where a box is created: just before the updates. This is
+  /// necessary since updates are considered to be part of the next iteration
+  /// (and can again capture variables).
+  ///
+  /// For example the following Dart code prints 1 3 -- 3 4.
+  ///
+  ///     var fs = [];
+  ///     for (var i = 0; i < 3; (f() { fs.add(f); print(i); i++; })()) {
+  ///       i++;
+  ///     }
+  ///     print("--");
+  ///     for (var i = 0; i < 2; i++) fs[i]();
+  ///
+  /// We solve this by emitting the following code (only for [ast.For] loops):
+  ///  <Create box>    <== move the first box creation outside the loop.
+  ///  <initializer>;
+  ///  loop-entry:
+  ///    if (!<condition>) goto loop-exit;
+  ///    <body>
+  ///    <update box>  // create a new box and copy the captured loop-variables.
+  ///    <updates>
+  ///    goto loop-entry;
+  ///  loop-exit:
+  void startLoop(ast.Node node) {
+    ClosureScope scopeData = closureData.capturingScopes[node];
+    if (scopeData == null) return;
+    if (scopeData.hasBoxedLoopVariables()) {
+      // If there are boxed loop variables then we set up the box and
+      // redirections already now. This way the initializer can write its
+      // values into the box.
+      // For other loops the box will be created when entering the body.
+      enterScope(node, null);
+    }
+  }
+
+  /// Create phis at the loop entry for local variables (ready for the values
+  /// from the back edge).  Populate the phis with the current values.
+  void beginLoopHeader(HBasicBlock loopEntry) {
+    // Create a copy because we modify the map while iterating over it.
+    Map<Local, HInstruction> savedDirectLocals =
+        new Map<Local, HInstruction>.from(directLocals);
+
+    JavaScriptBackend backend = compiler.backend;
+    // Create phis for all elements in the definitions environment.
+    savedDirectLocals.forEach((Local local, HInstruction instruction) {
+      if (isAccessedDirectly(local)) {
+        // We know 'this' cannot be modified.
+        if (local != closureData.thisLocal) {
+          HPhi phi =
+              new HPhi.singleInput(local, instruction, backend.dynamicType);
+          loopEntry.addPhi(phi);
+          directLocals[local] = phi;
+        } else {
+          directLocals[local] = instruction;
+        }
+      }
+    });
+  }
+
+  void enterLoopBody(ast.Node node) {
+    ClosureScope scopeData = closureData.capturingScopes[node];
+    if (scopeData == null) return;
+    // If there are no declared boxed loop variables then we did not create the
+    // box before the initializer and we have to create the box now.
+    if (!scopeData.hasBoxedLoopVariables()) {
+      enterScope(node, null);
+    }
+  }
+
+  void enterLoopUpdates(ast.Node node) {
+    // If there are declared boxed loop variables then the updates might have
+    // access to the box and we must switch to a new box before executing the
+    // updates.
+    // In all other cases a new box will be created when entering the body of
+    // the next iteration.
+    ClosureScope scopeData = closureData.capturingScopes[node];
+    if (scopeData == null) return;
+    if (scopeData.hasBoxedLoopVariables()) {
+      updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables);
+    }
+  }
+
+  /// Goes through the phis created in beginLoopHeader entry and adds the
+  /// input from the back edge (from the current value of directLocals) to them.
+  void endLoop(HBasicBlock loopEntry) {
+    // If the loop has an aborting body, we don't update the loop
+    // phis.
+    if (loopEntry.predecessors.length == 1) return;
+    loopEntry.forEachPhi((HPhi phi) {
+      Local element = phi.sourceElement;
+      HInstruction postLoopDefinition = directLocals[element];
+      phi.addInput(postLoopDefinition);
+    });
+  }
+
+  /// Merge [otherLocals] into this locals handler, creating phi-nodes when
+  /// there is a conflict.
+  /// If a phi node is necessary, it will use this handler's instruction as the
+  /// first input, and the otherLocals instruction as the second.
+  void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) {
+    // If an element is in one map but not the other we can safely
+    // ignore it. It means that a variable was declared in the
+    // block. Since variable declarations are scoped the declared
+    // variable cannot be alive outside the block. Note: this is only
+    // true for nodes where we do joins.
+    Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
+    JavaScriptBackend backend = compiler.backend;
+    otherLocals.directLocals.forEach((Local local, HInstruction instruction) {
+      // We know 'this' cannot be modified.
+      if (local == closureData.thisLocal) {
+        assert(directLocals[local] == instruction);
+        joinedLocals[local] = instruction;
+      } else {
+        HInstruction mine = directLocals[local];
+        if (mine == null) return;
+        if (identical(instruction, mine)) {
+          joinedLocals[local] = instruction;
+        } else {
+          HInstruction phi = new HPhi.manyInputs(
+              local, <HInstruction>[mine, instruction], backend.dynamicType);
+          joinBlock.addPhi(phi);
+          joinedLocals[local] = phi;
+        }
+      }
+    });
+    directLocals = joinedLocals;
+  }
+
+  /// When control flow merges, this method can be used to merge several
+  /// localsHandlers into a new one using phis.  The new localsHandler is
+  /// returned.  Unless it is also in the list, the current localsHandler is not
+  /// used for its values, only for its declared variables. This is a way to
+  /// exclude local values from the result when they are no longer in scope.
+  LocalsHandler mergeMultiple(
+      List<LocalsHandler> localsHandlers, HBasicBlock joinBlock) {
+    assert(localsHandlers.length > 0);
+    if (localsHandlers.length == 1) return localsHandlers[0];
+    Map<Local, HInstruction> joinedLocals = new Map<Local, HInstruction>();
+    HInstruction thisValue = null;
+    JavaScriptBackend backend = compiler.backend;
+    directLocals.forEach((Local local, HInstruction instruction) {
+      if (local != closureData.thisLocal) {
+        HPhi phi = new HPhi.noInputs(local, backend.dynamicType);
+        joinedLocals[local] = phi;
+        joinBlock.addPhi(phi);
+      } else {
+        // We know that "this" never changes, if it's there.
+        // Save it for later. While merging, there is no phi for "this",
+        // so we don't have to special case it in the merge loop.
+        thisValue = instruction;
+      }
+    });
+    for (LocalsHandler handler in localsHandlers) {
+      handler.directLocals.forEach((Local local, HInstruction instruction) {
+        HPhi phi = joinedLocals[local];
+        if (phi != null) {
+          phi.addInput(instruction);
+        }
+      });
+    }
+    if (thisValue != null) {
+      // If there was a "this" for the scope, add it to the new locals.
+      joinedLocals[closureData.thisLocal] = thisValue;
+    }
+
+    // Remove locals that are not in all handlers.
+    directLocals = new Map<Local, HInstruction>();
+    joinedLocals.forEach((Local local, HInstruction instruction) {
+      if (local != closureData.thisLocal &&
+          instruction.inputs.length != localsHandlers.length) {
+        joinBlock.removePhi(instruction);
+      } else {
+        directLocals[local] = instruction;
+      }
+    });
+    return this;
+  }
+
+  TypeMask cachedTypeOfThis;
+
+  TypeMask getTypeOfThis() {
+    TypeMask result = cachedTypeOfThis;
+    if (result == null) {
+      ThisLocal local = closureData.thisLocal;
+      ClassElement cls = local.enclosingClass;
+      ClassWorld classWorld = compiler.world;
+      if (classWorld.isUsedAsMixin(cls)) {
+        // If the enclosing class is used as a mixin, [:this:] can be
+        // of the class that mixins the enclosing class. These two
+        // classes do not have a subclass relationship, so, for
+        // simplicity, we mark the type as an interface type.
+        result = new TypeMask.nonNullSubtype(cls.declaration, compiler.world);
+      } else {
+        result = new TypeMask.nonNullSubclass(cls.declaration, compiler.world);
+      }
+      cachedTypeOfThis = result;
+    }
+    return result;
+  }
+
+  Map<Element, TypeMask> cachedTypesOfCapturedVariables =
+      new Map<Element, TypeMask>();
+
+  TypeMask getTypeOfCapturedVariable(Element element) {
+    assert(element.isField);
+    return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
+      return TypeMaskFactory.inferredTypeForElement(element, compiler);
+    });
+  }
+
+  /// Variables stored in the current activation. These variables are
+  /// being updated in try/catch blocks, and should be
+  /// accessed indirectly through [HLocalGet] and [HLocalSet].
+  Map<Local, HLocalValue> activationVariables = <Local, HLocalValue>{};
+}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 01be037..6ed6aef 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -99,6 +99,10 @@
   R visitVoidType(HVoidType node);
   R visitInterfaceType(HInterfaceType node);
   R visitDynamicType(HDynamicType node);
+
+  R visitTypeInfoReadRaw(HTypeInfoReadRaw node);
+  R visitTypeInfoReadVariable(HTypeInfoReadVariable node);
+  R visitTypeInfoExpression(HTypeInfoExpression node);
 }
 
 abstract class HGraphVisitor {
@@ -394,6 +398,11 @@
   visitDynamicType(HDynamicType node) => visitInstruction(node);
   visitAwait(HAwait node) => visitInstruction(node);
   visitYield(HYield node) => visitInstruction(node);
+
+  visitTypeInfoReadRaw(HTypeInfoReadRaw node) => visitInstruction(node);
+  visitTypeInfoReadVariable(HTypeInfoReadVariable node) =>
+      visitInstruction(node);
+  visitTypeInfoExpression(HTypeInfoExpression node) => visitInstruction(node);
 }
 
 class SubGraph {
@@ -854,6 +863,10 @@
   static const int TRUNCATING_DIVIDE_TYPECODE = 36;
   static const int IS_VIA_INTERCEPTOR_TYPECODE = 37;
 
+  static const int TYPE_INFO_READ_RAW_TYPECODE = 38;
+  static const int TYPE_INFO_READ_VARIABLE_TYPECODE = 39;
+  static const int TYPE_INFO_EXPRESSION_TYPECODE = 40;
+
   HInstruction(this.inputs, this.instructionType)
       : id = idCounter++,
         usedBy = <HInstruction>[] {
@@ -3182,6 +3195,136 @@
       visitor.visitSwitchInfo(this);
 }
 
+/// Reads raw reified type info from an object.
+class HTypeInfoReadRaw extends HInstruction {
+  HTypeInfoReadRaw(HInstruction receiver, TypeMask instructionType)
+      : super(<HInstruction>[receiver], instructionType) {
+    setUseGvn();
+  }
+
+  accept(HVisitor visitor) => visitor.visitTypeInfoReadRaw(this);
+
+  bool canThrow() => false;
+
+  int typeCode() => HInstruction.TYPE_INFO_READ_RAW_TYPECODE;
+  bool typeEquals(HInstruction other) => other is HTypeInfoReadRaw;
+
+  bool dataEquals(HTypeInfoReadRaw other) {
+    return true;
+  }
+}
+
+/// Reads a type variable from an object. The read may be a simple indexing of
+/// the type parameters or it may require 'substitution'.
+class HTypeInfoReadVariable extends HInstruction {
+  /// The type variable being read.
+  final TypeVariableType variable;
+
+  HTypeInfoReadVariable(
+      this.variable, HInstruction receiver, TypeMask instructionType)
+      : super(<HInstruction>[receiver], instructionType) {
+    setUseGvn();
+  }
+
+  HInstruction get object => inputs.single;
+
+  accept(HVisitor visitor) => visitor.visitTypeInfoReadVariable(this);
+
+  bool canThrow() => false;
+
+  int typeCode() => HInstruction.TYPE_INFO_READ_VARIABLE_TYPECODE;
+  bool typeEquals(HInstruction other) => other is HTypeInfoReadVariable;
+
+  bool dataEquals(HTypeInfoReadVariable other) {
+    return variable.element == other.variable.element;
+  }
+}
+
+enum TypeInfoExpressionKind { COMPLETE, INSTANCE }
+
+/// Constructs a representation of a closed or ground-term type (that is, a type
+/// without type variables).
+///
+/// There are two forms:
+///
+/// - COMPLETE: A complete form that is self contained, used for the values of
+///   type parameters and non-raw is-checks.
+///
+/// - INSTANCE: A headless flat form for representing the sequence of values of
+///   the type parameters of an instance of a generic type.
+///
+/// The COMPLETE form value is constructed from [dartType] by replacing the type
+/// variables with consecutive values from [inputs], in the order generated by
+/// [DartType.forEachTypeVariable].  The type variables in [dartType] are
+/// treated as 'holes' in the term, which means that it must be ensured at
+/// construction, that duplicate occurences of a type variable in [dartType] are
+/// assigned the same value.
+///
+/// The INSTANCE form is constructed as a list of [inputs]. This is the same as
+/// the COMPLETE form for the 'thisType', except the root term's type is
+/// missing; this is implicit as the raw type of instance.  The [dartType] of
+/// the INSTANCE form must be the thisType of some class.
+///
+/// We want to remove the constrains on the INSTANCE form. In the meantime we
+/// get by with a tree of TypeExpressions.  Consider:
+///
+///     class Foo<T> {
+///       ... new Set<List<T>>()
+///     }
+///     class Set<E1> {
+///       factory Set() => new _LinkedHashSet<E1>();
+///     }
+///     class List<E2> { ... }
+///     class _LinkedHashSet<E3> { ... }
+///
+/// After inlining the factory constructor for `Set<E1>`, the HForeignNew
+/// should have type `_LinkedHashSet<List<T>>` and the TypeExpression should be
+/// a tree:
+///
+///    HForeignNew(dartType: _LinkedHashSet<List<T>>,
+///        [], // No arguments
+///        HTypeInfoExpression(INSTANCE,
+///            dartType: _LinkedHashSet<E3>, // _LinkedHashSet's thisType
+///            HTypeInfoExpression(COMPLETE,  // E3 = List<T>
+///                dartType: List<E2>,
+///                HTypeInfoReadVariable(this, T)))) // E2 = T
+
+// TODO(sra): The INSTANCE form requires the actual instance for full
+// interpretation. If the COMPLETE form was used on instances, then we could
+// simplify HTypeInfoReadVariable without an object.
+
+class HTypeInfoExpression extends HInstruction {
+  final TypeInfoExpressionKind kind;
+  final DartType dartType;
+  HTypeInfoExpression(this.kind, this.dartType, List<HInstruction> inputs,
+      TypeMask instructionType)
+      : super(inputs, instructionType) {
+    setUseGvn();
+  }
+
+  accept(HVisitor visitor) => visitor.visitTypeInfoExpression(this);
+
+  bool canThrow() => false;
+
+  int typeCode() => HInstruction.TYPE_INFO_EXPRESSION_TYPECODE;
+  bool typeEquals(HInstruction other) => other is HTypeInfoExpression;
+
+  bool dataEquals(HTypeInfoExpression other) {
+    return kind == other.kind && dartType == other.dartType;
+  }
+
+  String toString() => 'HTypeInfoExpression $kindAsString $dartType';
+
+  String get kindAsString {
+    switch (kind) {
+      case TypeInfoExpressionKind.COMPLETE:
+        return 'COMPLETE';
+      case TypeInfoExpressionKind.INSTANCE:
+        return 'INSTANCE';
+    }
+  }
+}
+
 class HReadTypeVariable extends HInstruction {
   /// The type variable being read.
   final TypeVariableType dartType;
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 9dd26ff..0319222 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -247,9 +247,26 @@
   }
 
   HInstruction visitParameterValue(HParameterValue node) {
+    // [HParameterValue]s are either the value of the parameter (in fully SSA
+    // converted code), or the mutable variable containing the value (in
+    // incompletely SSA converted code, e.g. methods containing exceptions).
+    //
     // If the parameter is used as a mutable variable we cannot replace the
     // variable with a value.
-    if (node.usedAsVariable()) return node;
+    //
+    // If the parameter is used as a mutable variable but never written, first
+    // convert to a value parameter.
+
+    if (node.usedAsVariable()) {
+      if (!node.usedBy.every((user) => user is HLocalGet)) return node;
+      // Trivial SSA-conversion. Replace all HLocalGet instructions with the
+      // parameter.
+      for (HLocalGet user in node.usedBy.toList()) {
+        user.block.rewrite(user, node);
+        user.block.remove(user);
+      }
+    }
+
     propagateConstantValueToUses(node);
     return node;
   }
@@ -1019,6 +1036,44 @@
   HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
     return handleInterceptedCall(node);
   }
+
+  HInstruction visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
+    TypeVariableType variable = node.variable;
+    HInstruction object = node.object;
+
+    HInstruction finishGroundType(InterfaceType groundType) {
+      InterfaceType typeAtVariable =
+          groundType.asInstanceOf(variable.element.enclosingClass);
+      if (typeAtVariable != null) {
+        int index = variable.element.index;
+        DartType typeArgument = typeAtVariable.typeArguments[index];
+        HInstruction replacement = new HTypeInfoExpression(
+            TypeInfoExpressionKind.COMPLETE,
+            typeArgument,
+            const <HInstruction>[],
+            backend.dynamicType);
+        return replacement;
+      }
+      return node;
+    }
+
+    // Type variable evaluated in the context of a constant can be replaced with
+    // a ground term type.
+    if (object is HConstant) {
+      ConstantValue value = object.constant;
+      if (value is ConstructedConstantValue) {
+        return finishGroundType(value.type);
+      }
+      return node;
+    }
+
+    // TODO(sra): HTypeInfoReadVariable on an instance creation can be replaced
+    // with an input of the instance creation's HTypeInfoExpression (or a
+    // HTypeInfoExpression of an input).  This would in effect store-forward the
+    // type parameters.
+
+    return node;
+  }
 }
 
 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 555b82c..55b13b0 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -4,4 +4,55 @@
 
 library ssa;
 
-export 'builder.dart' show SsaFunctionCompiler;
+import '../common/codegen.dart' show CodegenWorkItem;
+import '../common/tasks.dart' show CompilerTask;
+import '../elements/elements.dart' show Element, FunctionElement;
+import '../io/source_information.dart';
+import '../js/js.dart' as js;
+import '../js_backend/backend.dart' show JavaScriptBackend, FunctionCompiler;
+
+import 'builder.dart';
+import 'builder_kernel.dart';
+import 'codegen.dart';
+import 'nodes.dart';
+import 'optimize.dart';
+
+class SsaFunctionCompiler implements FunctionCompiler {
+  final SsaCodeGeneratorTask generator;
+  final SsaBuilderTask builder;
+  final SsaKernelBuilderTask builderKernel;
+  final SsaOptimizerTask optimizer;
+  final JavaScriptBackend backend;
+  final bool useKernel;
+
+  SsaFunctionCompiler(JavaScriptBackend backend,
+      SourceInformationStrategy sourceInformationFactory, this.useKernel)
+      : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory),
+        builder = new SsaBuilderTask(backend, sourceInformationFactory),
+        builderKernel =
+            new SsaKernelBuilderTask(backend, sourceInformationFactory),
+        optimizer = new SsaOptimizerTask(backend),
+        backend = backend;
+
+  /// Generates JavaScript code for `work.element`.
+  /// Using the ssa builder, optimizer and codegenerator.
+  js.Fun compile(CodegenWorkItem work) {
+    HGraph graph = useKernel ? builderKernel.build(work) : builder.build(work);
+    optimizer.optimize(work, graph);
+    Element element = work.element;
+    js.Expression result = generator.generateCode(work, graph);
+    if (element is FunctionElement) {
+      // TODO(sigmund): replace by kernel transformer when `useKernel` is true.
+      result = backend.rewriteAsync(element, result);
+    }
+    return result;
+  }
+
+  Iterable<CompilerTask> get tasks {
+    return <CompilerTask>[
+      useKernel ? builderKernel : builder,
+      optimizer,
+      generator
+    ];
+  }
+}
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 5591851..131f4dc 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -506,6 +506,18 @@
     return "RangeConversion: ${node.checkedInput}";
   }
 
+  String visitTypeInfoReadRaw(HTypeInfoReadRaw node) {
+    return "TypeInfoReadRaw";
+  }
+
+  String visitTypeInfoReadVariable(HTypeInfoReadVariable node) {
+    return "TypeInfoReadVariable ${node.variable}";
+  }
+
+  String visitTypeInfoExpression(HTypeInfoExpression node) {
+    return "TypeInfoExpression ${node.kindAsString} ${node.dartType}";
+  }
+
   String visitReadTypeVariable(HReadTypeVariable node) {
     return "ReadTypeVariable: ${node.dartType} ${node.hasReceiver}";
   }
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 7efebe7..3722bf5 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -5,7 +5,6 @@
 import '../compiler.dart' show Compiler;
 import '../core_types.dart' show CoreClasses;
 import '../elements/elements.dart';
-import '../js_backend/js_backend.dart';
 import '../native/native.dart' as native;
 import '../tree/tree.dart' as ast;
 import '../types/types.dart';
@@ -13,65 +12,56 @@
 import '../world.dart' show ClassWorld;
 
 class TypeMaskFactory {
-  static TypeMask fromInferredType(TypeMask mask, Compiler compiler) {
-    JavaScriptBackend backend = compiler.backend;
-    if (mask == null) return backend.dynamicType;
-    return mask;
-  }
-
   static TypeMask inferredReturnTypeForElement(
       Element element, Compiler compiler) {
-    return fromInferredType(
-        compiler.typesTask.getGuaranteedReturnTypeOfElement(element), compiler);
+    return compiler.globalInference.getGuaranteedReturnTypeOfElement(element) ??
+        compiler.commonMasks.dynamicType;
   }
 
   static TypeMask inferredTypeForElement(Element element, Compiler compiler) {
-    return fromInferredType(
-        compiler.typesTask.getGuaranteedTypeOfElement(element), compiler);
+    return compiler.globalInference.getGuaranteedTypeOfElement(element) ??
+        compiler.commonMasks.dynamicType;
   }
 
   static TypeMask inferredTypeForSelector(
       Selector selector, TypeMask mask, Compiler compiler) {
-    return fromInferredType(
-        compiler.typesTask.getGuaranteedTypeOfSelector(selector, mask),
-        compiler);
+    return compiler.globalInference
+            .getGuaranteedTypeOfSelector(selector, mask) ??
+        compiler.commonMasks.dynamicType;
   }
 
   static TypeMask inferredForNode(
       Element owner, ast.Node node, Compiler compiler) {
-    return fromInferredType(
-        compiler.typesTask.getGuaranteedTypeOfNode(owner, node), compiler);
+    return compiler.globalInference.getGuaranteedTypeOfNode(owner, node) ??
+        compiler.commonMasks.dynamicType;
   }
 
   static TypeMask fromNativeBehavior(
       native.NativeBehavior nativeBehavior, Compiler compiler) {
-    ClassWorld classWorld = compiler.world;
-    JavaScriptBackend backend = compiler.backend;
-    if (nativeBehavior.typesReturned.isEmpty) return backend.dynamicType;
+    var typesReturned = nativeBehavior.typesReturned;
+    if (typesReturned.isEmpty) return compiler.commonMasks.dynamicType;
 
-    TypeMask result = nativeBehavior.typesReturned
-        .map((type) => fromNativeType(type, compiler))
-        .reduce((t1, t2) => t1.union(t2, classWorld));
+    ClassWorld world = compiler.world;
+    CommonMasks commonMasks = compiler.commonMasks;
+    CoreClasses coreClasses = compiler.coreClasses;
+
+    // [type] is either an instance of [DartType] or special objects
+    // like [native.SpecialType.JsObject].
+    TypeMask fromNativeType(dynamic type) {
+      if (type == native.SpecialType.JsObject) {
+        return new TypeMask.nonNullExact(coreClasses.objectClass, world);
+      }
+
+      if (type.isVoid) return commonMasks.nullType;
+      if (type.element == coreClasses.nullClass) return commonMasks.nullType;
+      if (type.treatAsDynamic) return commonMasks.dynamicType;
+      return new TypeMask.nonNullSubtype(type.element, world);
+    }
+
+    TypeMask result = typesReturned
+        .map(fromNativeType)
+        .reduce((t1, t2) => t1.union(t2, compiler.world));
     assert(!result.isEmpty);
     return result;
   }
-
-  // [type] is either an instance of [DartType] or special objects
-  // like [native.SpecialType.JsObject].
-  static TypeMask fromNativeType(type, Compiler compiler) {
-    ClassWorld classWorld = compiler.world;
-    JavaScriptBackend backend = compiler.backend;
-    CoreClasses coreClasses = compiler.coreClasses;
-    if (type == native.SpecialType.JsObject) {
-      return new TypeMask.nonNullExact(coreClasses.objectClass, classWorld);
-    } else if (type.isVoid) {
-      return backend.nullType;
-    } else if (type.element == coreClasses.nullClass) {
-      return backend.nullType;
-    } else if (type.treatAsDynamic) {
-      return backend.dynamicType;
-    } else {
-      return new TypeMask.nonNullSubtype(type.element, classWorld);
-    }
-  }
 }
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index 219e6b1..b4689ce 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -8,7 +8,7 @@
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
 import '../js_backend/js_backend.dart' show SyntheticConstantKind;
-import 'types.dart';
+import 'masks.dart';
 
 /// Computes the [TypeMask] for the constant [value].
 TypeMask computeTypeMask(Compiler compiler, ConstantValue value) {
@@ -22,7 +22,7 @@
   TypeMask visitConstructed(
       ConstructedConstantValue constant, Compiler compiler) {
     if (compiler.backend.isInterceptorClass(constant.type.element)) {
-      return compiler.typesTask.nonNullType;
+      return compiler.commonMasks.nonNullType;
     }
     return new TypeMask.nonNullExact(constant.type.element, compiler.world);
   }
@@ -37,13 +37,13 @@
     // We have to recognize double constants that are 'is int'.
     if (compiler.backend.constantSystem.isInt(constant)) {
       if (constant.isMinusZero) {
-        return compiler.typesTask.uint31Type;
+        return compiler.commonMasks.uint31Type;
       } else {
         assert(constant.isPositiveInfinity || constant.isNegativeInfinity);
-        return compiler.typesTask.intType;
+        return compiler.commonMasks.intType;
       }
     }
-    return compiler.typesTask.doubleType;
+    return compiler.commonMasks.doubleType;
   }
 
   @override
@@ -54,9 +54,9 @@
       case SyntheticConstantKind.EMPTY_VALUE:
         return constant.payload;
       case SyntheticConstantKind.TYPEVARIABLE_REFERENCE:
-        return compiler.typesTask.intType;
+        return compiler.commonMasks.intType;
       case SyntheticConstantKind.NAME:
-        return compiler.typesTask.stringType;
+        return compiler.commonMasks.stringType;
       default:
         DiagnosticReporter reporter = compiler.reporter;
         reporter.internalError(
@@ -67,55 +67,55 @@
 
   @override
   TypeMask visitBool(BoolConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.boolType;
+    return compiler.commonMasks.boolType;
   }
 
   @override
   TypeMask visitFunction(FunctionConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.functionType;
+    return compiler.commonMasks.functionType;
   }
 
   @override
   TypeMask visitInt(IntConstantValue constant, Compiler compiler) {
-    if (constant.isUInt31()) return compiler.typesTask.uint31Type;
-    if (constant.isUInt32()) return compiler.typesTask.uint32Type;
-    if (constant.isPositive()) return compiler.typesTask.positiveIntType;
-    return compiler.typesTask.intType;
+    if (constant.isUInt31()) return compiler.commonMasks.uint31Type;
+    if (constant.isUInt32()) return compiler.commonMasks.uint32Type;
+    if (constant.isPositive()) return compiler.commonMasks.positiveIntType;
+    return compiler.commonMasks.intType;
   }
 
   @override
   TypeMask visitInterceptor(
       InterceptorConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.nonNullType;
+    return compiler.commonMasks.nonNullType;
   }
 
   @override
   TypeMask visitList(ListConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.constListType;
+    return compiler.commonMasks.constListType;
   }
 
   @override
   TypeMask visitMap(MapConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.constMapType;
+    return compiler.commonMasks.constMapType;
   }
 
   @override
   TypeMask visitNull(NullConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.nullType;
+    return compiler.commonMasks.nullType;
   }
 
   @override
   TypeMask visitNonConstant(NonConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.nullType;
+    return compiler.commonMasks.nullType;
   }
 
   @override
   TypeMask visitString(StringConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.stringType;
+    return compiler.commonMasks.stringType;
   }
 
   @override
   TypeMask visitType(TypeConstantValue constant, Compiler compiler) {
-    return compiler.typesTask.typeType;
+    return compiler.commonMasks.typeType;
   }
 }
diff --git a/pkg/compiler/lib/src/types/container_type_mask.dart b/pkg/compiler/lib/src/types/container_type_mask.dart
index 6a6ad80..acde3b2 100644
--- a/pkg/compiler/lib/src/types/container_type_mask.dart
+++ b/pkg/compiler/lib/src/types/container_type_mask.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.
 
-part of types;
+part of masks;
 
 /// A [ContainerTypeMask] is a [TypeMask] for a specific allocation
 /// site of a container (currently only List) that will get specialized
diff --git a/pkg/compiler/lib/src/types/dictionary_type_mask.dart b/pkg/compiler/lib/src/types/dictionary_type_mask.dart
index 74f9fdd..c308041 100644
--- a/pkg/compiler/lib/src/types/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/types/dictionary_type_mask.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.
 
-part of types;
+part of masks;
 
 /**
  * A [DictionaryTypeMask] is a [TypeMask] for a specific allocation
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 0ad5cd7..f38c6f6 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.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.
 
-part of types;
+part of masks;
 
 /**
  * A flat type mask is a type mask that has been flattened to contain a
diff --git a/pkg/compiler/lib/src/types/forwarding_type_mask.dart b/pkg/compiler/lib/src/types/forwarding_type_mask.dart
index 0e30bac..bc9ce15 100644
--- a/pkg/compiler/lib/src/types/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/types/forwarding_type_mask.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.
 
-part of types;
+part of masks;
 
 /**
  * A type mask that wraps an other one, and delegate all its
diff --git a/pkg/compiler/lib/src/types/map_type_mask.dart b/pkg/compiler/lib/src/types/map_type_mask.dart
index b3fbc96..4645cd7 100644
--- a/pkg/compiler/lib/src/types/map_type_mask.dart
+++ b/pkg/compiler/lib/src/types/map_type_mask.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.
 
-part of types;
+part of masks;
 
 /**
  * A [MapTypeMask] is a [TypeMask] for a specific allocation
@@ -77,7 +77,7 @@
       return new MapTypeMask(
           newForwardTo, null, null, newKeyType, newValueType);
     } else if (other.isDictionary) {
-      assert(other.keyType == classWorld.compiler.typesTask.stringType);
+      assert(other.keyType == classWorld.compiler.commonMasks.stringType);
       TypeMask newKeyType = keyType.union(other.keyType, classWorld);
       TypeMask newValueType =
           other.typeMap.values.fold(keyType, (p, n) => p.union(n, classWorld));
diff --git a/pkg/compiler/lib/src/types/masks.dart b/pkg/compiler/lib/src/types/masks.dart
new file mode 100644
index 0000000..ee12b65
--- /dev/null
+++ b/pkg/compiler/lib/src/types/masks.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library masks;
+
+import '../common.dart';
+import '../common/backend_api.dart' show Backend;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart' show PrimitiveConstantValue;
+import '../elements/elements.dart';
+import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
+import '../tree/tree.dart';
+import '../universe/selector.dart' show Selector;
+import '../universe/universe.dart'
+    show
+        ReceiverConstraint,
+        UniverseSelectorConstraints,
+        SelectorConstraintsStrategy;
+import '../util/util.dart';
+import '../world.dart' show ClassWorld, World;
+import 'abstract_value_domain.dart' show AbstractValue;
+
+part 'container_type_mask.dart';
+part 'dictionary_type_mask.dart';
+part 'flat_type_mask.dart';
+part 'forwarding_type_mask.dart';
+part 'map_type_mask.dart';
+part 'type_mask.dart';
+part 'union_type_mask.dart';
+part 'value_type_mask.dart';
+
+class CommonMasks {
+  final ClassWorld classWorld;
+  // TODO(sigmund): once we split out the backend common elements, depend
+  // directly on those instead.
+  final Compiler compiler;
+
+  CommonMasks(Compiler compiler)
+      : this.classWorld = compiler.world,
+        compiler = compiler;
+
+  TypeMask _dynamicType;
+  TypeMask _nonNullType;
+  TypeMask _nullType;
+  TypeMask _intType;
+  TypeMask _uint32Type;
+  TypeMask _uint31Type;
+  TypeMask _positiveIntType;
+  TypeMask _doubleType;
+  TypeMask _numType;
+  TypeMask _boolType;
+  TypeMask _functionType;
+  TypeMask _listType;
+  TypeMask _constListType;
+  TypeMask _fixedListType;
+  TypeMask _growableListType;
+  TypeMask _mapType;
+  TypeMask _constMapType;
+  TypeMask _stringType;
+  TypeMask _typeType;
+  TypeMask _syncStarIterableType;
+  TypeMask _asyncFutureType;
+  TypeMask _asyncStarStreamType;
+
+  TypeMask get dynamicType => _dynamicType ??=
+      new TypeMask.subclass(classWorld.objectClass, classWorld);
+
+  TypeMask get nonNullType => _nonNullType ??=
+      new TypeMask.nonNullSubclass(classWorld.objectClass, classWorld);
+
+  TypeMask get intType => _intType ??= new TypeMask.nonNullSubclass(
+      compiler.backend.intImplementation, classWorld);
+
+  TypeMask get uint32Type => _uint32Type ??= new TypeMask.nonNullSubclass(
+      compiler.backend.uint32Implementation, classWorld);
+
+  TypeMask get uint31Type => _uint31Type ??= new TypeMask.nonNullExact(
+      compiler.backend.uint31Implementation, classWorld);
+
+  TypeMask get positiveIntType =>
+      _positiveIntType ??= new TypeMask.nonNullSubclass(
+          compiler.backend.positiveIntImplementation, classWorld);
+
+  TypeMask get doubleType => _doubleType ??= new TypeMask.nonNullExact(
+      compiler.backend.doubleImplementation, classWorld);
+
+  TypeMask get numType => _numType ??= new TypeMask.nonNullSubclass(
+      compiler.backend.numImplementation, classWorld);
+
+  TypeMask get boolType => _boolType ??= new TypeMask.nonNullExact(
+      compiler.backend.boolImplementation, classWorld);
+
+  TypeMask get functionType => _functionType ??= new TypeMask.nonNullSubtype(
+      compiler.backend.functionImplementation, classWorld);
+
+  TypeMask get listType => _listType ??= new TypeMask.nonNullExact(
+      compiler.backend.listImplementation, classWorld);
+
+  TypeMask get constListType => _constListType ??= new TypeMask.nonNullExact(
+      compiler.backend.constListImplementation, classWorld);
+
+  TypeMask get fixedListType => _fixedListType ??= new TypeMask.nonNullExact(
+      compiler.backend.fixedListImplementation, classWorld);
+
+  TypeMask get growableListType =>
+      _growableListType ??= new TypeMask.nonNullExact(
+          compiler.backend.growableListImplementation, classWorld);
+
+  TypeMask get mapType => _mapType ??= new TypeMask.nonNullSubtype(
+      compiler.backend.mapImplementation, classWorld);
+
+  TypeMask get constMapType => _constMapType ??= new TypeMask.nonNullSubtype(
+      compiler.backend.constMapImplementation, classWorld);
+
+  TypeMask get stringType => _stringType ??= new TypeMask.nonNullExact(
+      compiler.backend.stringImplementation, classWorld);
+
+  TypeMask get typeType => _typeType ??= new TypeMask.nonNullExact(
+      compiler.backend.typeImplementation, classWorld);
+
+  TypeMask get syncStarIterableType =>
+      _syncStarIterableType ??= new TypeMask.nonNullExact(
+          compiler.backend.syncStarIterableImplementation, classWorld);
+
+  TypeMask get asyncFutureType =>
+      _asyncFutureType ??= new TypeMask.nonNullExact(
+          compiler.backend.asyncFutureImplementation, classWorld);
+
+  TypeMask get asyncStarStreamType =>
+      _asyncStarStreamType ??= new TypeMask.nonNullExact(
+          compiler.backend.asyncStarStreamImplementation, classWorld);
+
+  // TODO(johnniwinther): Assert that the null type has been resolved.
+  TypeMask get nullType => _nullType ??= const TypeMask.empty();
+}
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index d444afe..698d87e 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.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.
 
-part of types;
+part of masks;
 
 /// An implementation of a [UniverseSelectorConstraints] that is consists if an only
 /// increasing set of [TypeMask]s, that is, once a mask is added it cannot be
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index d12b2bd..28dc608 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -4,36 +4,17 @@
 
 library types;
 
-import '../common.dart';
-import '../common/backend_api.dart' show Backend;
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
-import '../constants/values.dart' show PrimitiveConstantValue;
 import '../elements/elements.dart';
 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
 import '../tree/tree.dart';
 import '../universe/selector.dart' show Selector;
-import '../universe/universe.dart'
-    show
-        ReceiverConstraint,
-        UniverseSelectorConstraints,
-        SelectorConstraintsStrategy;
-import '../util/util.dart';
-import '../world.dart' show ClassWorld, World;
-import 'abstract_value_domain.dart' show AbstractValue;
 
-part 'container_type_mask.dart';
-part 'dictionary_type_mask.dart';
-part 'flat_type_mask.dart';
-part 'forwarding_type_mask.dart';
-part 'map_type_mask.dart';
-part 'type_mask.dart';
-part 'union_type_mask.dart';
-part 'value_type_mask.dart';
+import 'masks.dart';
+export 'masks.dart';
 
-/**
- * Common super class for our type inferrers.
- */
+/// API to interact with the global type-inference engine.
 abstract class TypesInferrer {
   void analyzeMain(Element element);
   TypeMask getReturnTypeOfElement(Element element);
@@ -45,249 +26,24 @@
   bool isFixedArrayCheckedForGrowable(Node node);
 }
 
-/**
- * The types task infers guaranteed types globally.
- */
-class TypesTask extends CompilerTask {
+/// Global analysis that infers concrete types.
+class GlobalTypeInferenceTask extends CompilerTask {
+  // TODO(sigmund): rename at the same time as our benchmarking tools.
   final String name = 'Type inference';
-  final ClassWorld classWorld;
+
   final Compiler compiler;
   TypesInferrer typesInferrer;
+  CommonMasks masks;
 
-  TypesTask(Compiler compiler)
-      : this.classWorld = compiler.world,
+  GlobalTypeInferenceTask(Compiler compiler)
+      : masks = new CommonMasks(compiler),
         compiler = compiler,
         super(compiler.measurer) {
-    typesInferrer = new TypeGraphInferrer(compiler);
+    typesInferrer = new TypeGraphInferrer(compiler, masks);
   }
 
-  TypeMask dynamicTypeCache;
-  TypeMask nonNullTypeCache;
-  TypeMask nullTypeCache;
-  TypeMask intTypeCache;
-  TypeMask uint32TypeCache;
-  TypeMask uint31TypeCache;
-  TypeMask positiveIntTypeCache;
-  TypeMask doubleTypeCache;
-  TypeMask numTypeCache;
-  TypeMask boolTypeCache;
-  TypeMask functionTypeCache;
-  TypeMask listTypeCache;
-  TypeMask constListTypeCache;
-  TypeMask fixedListTypeCache;
-  TypeMask growableListTypeCache;
-  TypeMask mapTypeCache;
-  TypeMask constMapTypeCache;
-  TypeMask stringTypeCache;
-  TypeMask typeTypeCache;
-  TypeMask syncStarIterableTypeCache;
-  TypeMask asyncFutureTypeCache;
-  TypeMask asyncStarStreamTypeCache;
-
-  TypeMask get dynamicType {
-    if (dynamicTypeCache == null) {
-      dynamicTypeCache =
-          new TypeMask.subclass(classWorld.objectClass, classWorld);
-    }
-    return dynamicTypeCache;
-  }
-
-  TypeMask get nonNullType {
-    if (nonNullTypeCache == null) {
-      nonNullTypeCache =
-          new TypeMask.nonNullSubclass(classWorld.objectClass, classWorld);
-    }
-    return nonNullTypeCache;
-  }
-
-  TypeMask get intType {
-    if (intTypeCache == null) {
-      intTypeCache = new TypeMask.nonNullSubclass(
-          compiler.backend.intImplementation, classWorld);
-    }
-    return intTypeCache;
-  }
-
-  TypeMask get uint32Type {
-    if (uint32TypeCache == null) {
-      uint32TypeCache = new TypeMask.nonNullSubclass(
-          compiler.backend.uint32Implementation, classWorld);
-    }
-    return uint32TypeCache;
-  }
-
-  TypeMask get uint31Type {
-    if (uint31TypeCache == null) {
-      uint31TypeCache = new TypeMask.nonNullExact(
-          compiler.backend.uint31Implementation, classWorld);
-    }
-    return uint31TypeCache;
-  }
-
-  TypeMask get positiveIntType {
-    if (positiveIntTypeCache == null) {
-      positiveIntTypeCache = new TypeMask.nonNullSubclass(
-          compiler.backend.positiveIntImplementation, classWorld);
-    }
-    return positiveIntTypeCache;
-  }
-
-  TypeMask get doubleType {
-    if (doubleTypeCache == null) {
-      doubleTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.doubleImplementation, classWorld);
-    }
-    return doubleTypeCache;
-  }
-
-  TypeMask get numType {
-    if (numTypeCache == null) {
-      numTypeCache = new TypeMask.nonNullSubclass(
-          compiler.backend.numImplementation, classWorld);
-    }
-    return numTypeCache;
-  }
-
-  TypeMask get boolType {
-    if (boolTypeCache == null) {
-      boolTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.boolImplementation, classWorld);
-    }
-    return boolTypeCache;
-  }
-
-  TypeMask get functionType {
-    if (functionTypeCache == null) {
-      functionTypeCache = new TypeMask.nonNullSubtype(
-          compiler.backend.functionImplementation, classWorld);
-    }
-    return functionTypeCache;
-  }
-
-  TypeMask get listType {
-    if (listTypeCache == null) {
-      listTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.listImplementation, classWorld);
-    }
-    return listTypeCache;
-  }
-
-  TypeMask get constListType {
-    if (constListTypeCache == null) {
-      constListTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.constListImplementation, classWorld);
-    }
-    return constListTypeCache;
-  }
-
-  TypeMask get fixedListType {
-    if (fixedListTypeCache == null) {
-      fixedListTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.fixedListImplementation, classWorld);
-    }
-    return fixedListTypeCache;
-  }
-
-  TypeMask get growableListType {
-    if (growableListTypeCache == null) {
-      growableListTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.growableListImplementation, classWorld);
-    }
-    return growableListTypeCache;
-  }
-
-  TypeMask get mapType {
-    if (mapTypeCache == null) {
-      mapTypeCache = new TypeMask.nonNullSubtype(
-          compiler.backend.mapImplementation, classWorld);
-    }
-    return mapTypeCache;
-  }
-
-  TypeMask get constMapType {
-    if (constMapTypeCache == null) {
-      constMapTypeCache = new TypeMask.nonNullSubtype(
-          compiler.backend.constMapImplementation, classWorld);
-    }
-    return constMapTypeCache;
-  }
-
-  TypeMask get stringType {
-    if (stringTypeCache == null) {
-      stringTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.stringImplementation, classWorld);
-    }
-    return stringTypeCache;
-  }
-
-  TypeMask get typeType {
-    if (typeTypeCache == null) {
-      typeTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.typeImplementation, classWorld);
-    }
-    return typeTypeCache;
-  }
-
-  TypeMask get syncStarIterableType {
-    if (syncStarIterableTypeCache == null) {
-      syncStarIterableTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.syncStarIterableImplementation, classWorld);
-    }
-    return syncStarIterableTypeCache;
-  }
-
-  TypeMask get asyncFutureType {
-    if (asyncFutureTypeCache == null) {
-      asyncFutureTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.asyncFutureImplementation, classWorld);
-    }
-    return asyncFutureTypeCache;
-  }
-
-  TypeMask get asyncStarStreamType {
-    if (asyncStarStreamTypeCache == null) {
-      asyncStarStreamTypeCache = new TypeMask.nonNullExact(
-          compiler.backend.asyncStarStreamImplementation, classWorld);
-    }
-    return asyncStarStreamTypeCache;
-  }
-
-  TypeMask get nullType {
-    if (nullTypeCache == null) {
-      // TODO(johnniwinther): Assert that the null type has been resolved.
-      nullTypeCache = const TypeMask.empty();
-    }
-    return nullTypeCache;
-  }
-
-  /** Helper method for [intersection]. */
-  TypeMask _intersection(TypeMask type1, TypeMask type2) {
-    if (type1 == null) return type2;
-    if (type2 == null) return type1;
-    return type1.intersection(type2, classWorld);
-  }
-
-  /** Computes the intersection of [type1] and [type2] */
-  TypeMask intersection(TypeMask type1, TypeMask type2, element) {
-    TypeMask result = _intersection(type1, type2);
-    return result;
-  }
-
-  /** Returns true if [type1] is strictly better than [type2]. */
-  bool better(TypeMask type1, TypeMask type2) {
-    if (type1 == null) return false;
-    if (type2 == null) {
-      return (type1 != null) && (type1 != dynamicType);
-    }
-    return (type1 != type2) &&
-        type2.containsMask(type1, classWorld) &&
-        !type1.containsMask(type2, classWorld);
-  }
-
-  /**
-   * Called when resolution is complete.
-   */
-  void onResolutionComplete(Element mainElement) {
+  /// Runs the global type-inference algorithm once.
+  void runGlobalTypeInference(Element mainElement) {
     measure(() {
       typesInferrer.analyzeMain(mainElement);
       typesInferrer.clear();
@@ -300,7 +56,7 @@
   TypeMask getGuaranteedTypeOfElement(Element element) {
     // TODO(24489): trust some JsInterop types.
     if (compiler.backend.isJsInterop(element)) {
-      return dynamicType;
+      return masks.dynamicType;
     }
     TypeMask guaranteedType = typesInferrer.getTypeOfElement(element);
     return guaranteedType;
@@ -309,13 +65,27 @@
   TypeMask getGuaranteedReturnTypeOfElement(Element element) {
     // TODO(24489): trust some JsInterop types.
     if (compiler.backend.isJsInterop(element)) {
-      return dynamicType;
+      return masks.dynamicType;
     }
 
     TypeMask guaranteedType = typesInferrer.getReturnTypeOfElement(element);
     return guaranteedType;
   }
 
+  /// Return whether the global inference algorithm determined that [element]
+  /// always throws.
+  bool throwsAlways(Element element) {
+    // We know the element always throws if the return type was inferred to be
+    // non-null empty.
+    TypeMask returnType = getGuaranteedReturnTypeOfElement(element);
+    return returnType != null && returnType.isEmpty;
+  }
+
+  bool isFixedArrayCheckedForGrowable(Node send) =>
+      typesInferrer.isFixedArrayCheckedForGrowable(send);
+
+  bool isCalledOnce(Element element) => typesInferrer.isCalledOnce(element);
+
   /**
    * Return the (inferred) guaranteed type of [node] or null.
    * [node] must be an AST node of [owner].
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index 5a191db..0f96e10 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.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.
 
-part of types;
+part of masks;
 
 class UnionTypeMask implements TypeMask {
   final Iterable<FlatTypeMask> disjointMasks;
diff --git a/pkg/compiler/lib/src/types/value_type_mask.dart b/pkg/compiler/lib/src/types/value_type_mask.dart
index 1be16ba..1ca437b 100644
--- a/pkg/compiler/lib/src/types/value_type_mask.dart
+++ b/pkg/compiler/lib/src/types/value_type_mask.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.
 
-part of types;
+part of masks;
 
 class ValueTypeMask extends ForwardingTypeMask {
   final TypeMask forwardTo;
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index a96622e..b60d435 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -19,6 +19,7 @@
   static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
   static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
   static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
+  static const CallStructure THREE_ARGS = const CallStructure.unnamed(3);
 
   /// The numbers of arguments of the call. Includes named arguments.
   final int argumentCount;
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 99aca9f..19fb9a2 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -19,7 +19,7 @@
         TypedefElement,
         VariableElement;
 import 'ordered_typeset.dart';
-import 'types/types.dart' as ti;
+import 'types/masks.dart' show TypeMask, FlatTypeMask;
 import 'universe/class_set.dart';
 import 'universe/function_set.dart' show FunctionSet;
 import 'universe/selector.dart' show Selector;
@@ -190,10 +190,10 @@
   ClassElement get stringClass => coreClasses.stringClass;
   ClassElement get nullClass => coreClasses.nullClass;
 
-  /// Cache of [ti.FlatTypeMask]s grouped by the 8 possible values of the
-  /// [ti.FlatTypeMask.flags] property.
-  List<Map<ClassElement, ti.TypeMask>> canonicalizedTypeMasks =
-      new List<Map<ClassElement, ti.TypeMask>>.filled(8, null);
+  /// Cache of [FlatTypeMask]s grouped by the 8 possible values of the
+  /// `FlatTypeMask.flags` property.
+  List<Map<ClassElement, TypeMask>> canonicalizedTypeMasks =
+      new List<Map<ClassElement, TypeMask>>.filled(8, null);
 
   bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) {
     return invariant(cls, cls.isDeclaration,
@@ -710,7 +710,7 @@
     users.add(mixinApplication);
   }
 
-  bool hasAnyUserDefinedGetter(Selector selector, ti.TypeMask mask) {
+  bool hasAnyUserDefinedGetter(Selector selector, TypeMask mask) {
     return allFunctions.filter(selector, mask).any((each) => each.isGetter);
   }
 
@@ -720,23 +720,23 @@
     }
   }
 
-  VariableElement locateSingleField(Selector selector, ti.TypeMask mask) {
+  VariableElement locateSingleField(Selector selector, TypeMask mask) {
     Element result = locateSingleElement(selector, mask);
     return (result != null && result.isField) ? result : null;
   }
 
-  Element locateSingleElement(Selector selector, ti.TypeMask mask) {
-    mask = mask == null ? compiler.typesTask.dynamicType : mask;
+  Element locateSingleElement(Selector selector, TypeMask mask) {
+    mask ??= compiler.commonMasks.dynamicType;
     return mask.locateSingleElement(selector, mask, compiler);
   }
 
-  ti.TypeMask extendMaskIfReachesAll(Selector selector, ti.TypeMask mask) {
+  TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) {
     bool canReachAll = true;
     if (mask != null) {
       canReachAll = compiler.enabledInvokeOn &&
           mask.needsNoSuchMethodHandling(selector, this);
     }
-    return canReachAll ? compiler.typesTask.dynamicType : mask;
+    return canReachAll ? compiler.commonMasks.dynamicType : mask;
   }
 
   void addFunctionCalledInLoop(Element element) {
@@ -791,7 +791,7 @@
     sideEffectsFreeElements.add(element);
   }
 
-  SideEffects getSideEffectsOfSelector(Selector selector, ti.TypeMask mask) {
+  SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask) {
     // We're not tracking side effects of closures.
     if (selector.isClosureCall) return new SideEffects();
     SideEffects sideEffects = new SideEffects.empty();
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index d8998ef..a3e6070 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -11,6 +11,8 @@
     path: ../js_ast
   js_runtime:
     path: ../../sdk/lib/_internal/js_runtime
+  kernel:
+    path: ../../third_party/pkg/kernel
   sdk_library_metadata:
     path: ../../sdk/lib/_internal/sdk_library_metadata
   dart2js_info: ^0.2.4
diff --git a/pkg/js/README.md b/pkg/js/README.md
index e1da41e..393a489 100644
--- a/pkg/js/README.md
+++ b/pkg/js/README.md
@@ -34,6 +34,8 @@
 @JS('google.maps')
 library maps;
 
+import "package:js/js.dart";
+
 // Invokes the JavaScript getter `google.maps.map`.
 external Map get map;
 
diff --git a/pkg/package_test_data/lib/resources/sample.txt b/pkg/package_test_data/lib/resources/sample.txt
deleted file mode 100644
index 94ad275..0000000
--- a/pkg/package_test_data/lib/resources/sample.txt
+++ /dev/null
@@ -1 +0,0 @@
-Sample text file.
diff --git a/pkg/package_test_data/pubspec.yaml b/pkg/package_test_data/pubspec.yaml
deleted file mode 100644
index 8585f51..0000000
--- a/pkg/package_test_data/pubspec.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: package_test_data
-version: 0.0.1
-author: "Dart Team <misc@dartlang.org>"
-publish_to: "none"
-description: >
- Contains data used by platform tests using package: URIs.
- Should *not* be published.
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 099686e..49825b6 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -450,26 +450,6 @@
 }
 
 if (defined(is_fuchsia) && is_fuchsia) {
-  executable("fuchsia_test") {
-    configs += ["..:dart_config",
-                "..:dart_product_config",
-                "..:dart_precompiled_runtime_config"]
-    sources = [
-      "fuchsia_test.cc",
-      "log_fuchsia.cc",
-    ]
-
-    include_dirs = [
-      "..",
-      "../include"
-    ]
-
-    deps = [
-      ":dart_snapshot_cc",
-      ":libdart_embedder_noio",
-    ]
-  }
-
   copy("hello_fuchsia") {
     sources = [ "../tests/vm/dart/hello_fuchsia_test.dart" ]
     outputs = [ "$root_out_dir/hello_fuchsia.dart" ]
@@ -487,6 +467,7 @@
       "../vm:libdart_platform",
       "..:libdart",
       ":dart_snapshot_cc",
+      "../../pkg:pkg",  # Pull this out to top-level for a real SDK build.
       "//third_party/zlib",
     ]
 
@@ -579,17 +560,15 @@
     ] + builtin_impl_tests_list.sources + vm_tests
   }
 
-  copy("fuchsia_vm_tests") {
-    sources = [ "fuchsia_vm_tests.txt" ]
-    outputs = [ "$root_out_dir/fuchsia_vm_tests.txt" ]
-  }
-
   executable("run_vm_tests_fuchsia") {
     testonly = true
     configs += ["..:dart_config"]
     sources = [
       "run_vm_tests_fuchsia.cc"
     ]
-    libs = [ "launchpad" ]
+    libs = [
+      "launchpad",
+      "runtime",
+    ]
   }
 }  # defined(is_fuchsia) && is_fuchsia
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index ac6ee92..846244a 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -24,6 +24,7 @@
     'directory_fuchsia.cc',
     'directory_linux.cc',
     'directory_macos.cc',
+    'directory_test.cc',
     'directory_unsupported.cc',
     'directory_win.cc',
     'eventhandler_test.cc',
diff --git a/runtime/bin/directory_fuchsia.cc b/runtime/bin/directory_fuchsia.cc
index a1387b0..1e374d1 100644
--- a/runtime/bin/directory_fuchsia.cc
+++ b/runtime/bin/directory_fuchsia.cc
@@ -10,8 +10,14 @@
 #include <errno.h>  // NOLINT
 #include <stdlib.h>  // NOLINT
 #include <string.h>  // NOLINT
+#include <sys/stat.h>  // NOLINT
 #include <unistd.h>  // NOLINT
 
+#include "bin/dartutils.h"
+#include "bin/file.h"
+#include "bin/platform.h"
+#include "platform/signal_blocker.h"
+
 namespace dart {
 namespace bin {
 
@@ -94,8 +100,31 @@
 
 
 Directory::ExistsResult Directory::Exists(const char* dir_name) {
-  UNIMPLEMENTED();
-  return UNKNOWN;
+  struct stat entry_info;
+  int success = NO_RETRY_EXPECTED(stat(dir_name, &entry_info));
+  if (success == 0) {
+    if (S_ISDIR(entry_info.st_mode)) {
+      return EXISTS;
+    } else {
+      return DOES_NOT_EXIST;
+    }
+  } else {
+    if ((errno == EACCES) ||
+        (errno == EBADF) ||
+        (errno == EFAULT) ||
+        (errno == ENOMEM) ||
+        (errno == EOVERFLOW)) {
+      // Search permissions denied for one of the directories in the
+      // path or a low level error occured. We do not know if the
+      // directory exists.
+      return UNKNOWN;
+    }
+    ASSERT((errno == ELOOP) ||
+           (errno == ENAMETOOLONG) ||
+           (errno == ENOENT) ||
+           (errno == ENOTDIR));
+    return DOES_NOT_EXIST;
+  }
 }
 
 
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index d099b0e..2f2e6b0 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -117,20 +117,17 @@
 
   // Iterate the directory and post the directories and files to the
   // ports.
-  int status = 0;
-  dirent entry;
-  dirent* result;
-  status = NO_RETRY_EXPECTED(readdir_r(
-      reinterpret_cast<DIR*>(lister_), &entry, &result));
-  if ((status == 0) && (result != NULL)) {
-    if (!listing->path_buffer().Add(entry.d_name)) {
+  errno = 0;
+  dirent* entry = readdir(reinterpret_cast<DIR*>(lister_));
+  if (entry != NULL) {
+    if (!listing->path_buffer().Add(entry->d_name)) {
       done_ = true;
       return kListError;
     }
-    switch (entry.d_type) {
+    switch (entry->d_type) {
       case DT_DIR:
-        if ((strcmp(entry.d_name, ".") == 0) ||
-            (strcmp(entry.d_name, "..") == 0)) {
+        if ((strcmp(entry->d_name, ".") == 0) ||
+            (strcmp(entry->d_name, "..") == 0)) {
           return Next(listing);
         }
         return kListDirectory;
@@ -144,7 +141,7 @@
         // Fall through.
       case DT_UNKNOWN: {
         // On some file systems the entry type is not determined by
-        // readdir_r. For those and for links we use stat to determine
+        // readdir. For those and for links we use stat to determine
         // the actual entry type. Notice that stat returns the type of
         // the file pointed to.
         struct stat64 entry_info;
@@ -178,16 +175,16 @@
             // Recurse into the subdirectory with current_link added to the
             // linked list of seen file system links.
             link_ = new LinkList(current_link);
-            if ((strcmp(entry.d_name, ".") == 0) ||
-                (strcmp(entry.d_name, "..") == 0)) {
+            if ((strcmp(entry->d_name, ".") == 0) ||
+                (strcmp(entry->d_name, "..") == 0)) {
               return Next(listing);
             }
             return kListDirectory;
           }
         }
         if (S_ISDIR(entry_info.st_mode)) {
-          if ((strcmp(entry.d_name, ".") == 0) ||
-              (strcmp(entry.d_name, "..") == 0)) {
+          if ((strcmp(entry->d_name, ".") == 0) ||
+              (strcmp(entry->d_name, "..") == 0)) {
             return Next(listing);
           }
           return kListDirectory;
@@ -204,8 +201,7 @@
   }
   done_ = true;
 
-  if (status != 0) {
-    errno = status;
+  if (errno != 0) {
     return kListError;
   }
 
@@ -277,32 +273,47 @@
 
   // Iterate the directory and delete all files and directories.
   int path_length = path->length();
-  dirent entry;
-  dirent* result;
-  while (NO_RETRY_EXPECTED(readdir_r(dir_pointer, &entry, &result)) == 0) {
-    if (result == NULL) {
+  while (true){
+    // In case `readdir()` returns `NULL` we distinguish between end-of-stream and error
+    // by looking if `errno` was updated.
+    errno = 0;
+    // In glibc 2.24+, readdir_r is deprecated.
+    // According to the man page for readdir:
+    // "readdir(3) is not required to be thread-safe. However, in modern
+    // implementations (including the glibc implementation), concurrent calls to
+    // readdir(3) that specify different directory streams are thread-safe.
+    // Therefore, the use of readdir_r() is generally unnecessary in multithreaded
+    // programs. In cases where multiple threads must read from the same directory
+    // stream, using readdir(3) with external synchronization is still preferable
+    // to the use of readdir_r(), for the reasons given in the points above."
+    dirent* entry = readdir(dir_pointer);
+    if (entry == NULL) {
+      // Failed to read next directory entry.
+      if (errno != 0) {
+          break;
+      }
       // End of directory.
       return (NO_RETRY_EXPECTED(closedir(dir_pointer)) == 0) &&
              (NO_RETRY_EXPECTED(remove(path->AsString())) == 0);
     }
     bool ok = false;
-    switch (entry.d_type) {
+    switch (entry->d_type) {
       case DT_DIR:
-        ok = DeleteDir(entry.d_name, path);
+        ok = DeleteDir(entry->d_name, path);
         break;
       case DT_REG:
       case DT_LNK:
         // Treat all links as files. This will delete the link which
         // is what we want no matter if the link target is a file or a
         // directory.
-        ok = DeleteFile(entry.d_name, path);
+        ok = DeleteFile(entry->d_name, path);
         break;
       case DT_UNKNOWN: {
-        if (!path->Add(entry.d_name)) {
+        if (!path->Add(entry->d_name)) {
           break;
         }
         // On some file systems the entry type is not determined by
-        // readdir_r. For those we use lstat to determine the entry
+        // readdir. For those we use lstat to determine the entry
         // type.
         struct stat64 entry_info;
         if (TEMP_FAILURE_RETRY(lstat64(path->AsString(), &entry_info)) == -1) {
@@ -310,12 +321,12 @@
         }
         path->Reset(path_length);
         if (S_ISDIR(entry_info.st_mode)) {
-          ok = DeleteDir(entry.d_name, path);
+          ok = DeleteDir(entry->d_name, path);
         } else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
           // Treat links as files. This will delete the link which is
           // what we want no matter if the link target is a file or a
           // directory.
-          ok = DeleteFile(entry.d_name, path);
+          ok = DeleteFile(entry->d_name, path);
         }
         break;
       }
diff --git a/runtime/bin/directory_test.cc b/runtime/bin/directory_test.cc
new file mode 100644
index 0000000..d5b8175
--- /dev/null
+++ b/runtime/bin/directory_test.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "bin/directory.h"
+#include "include/dart_api.h"
+#include "platform/assert.h"
+#include "vm/isolate.h"
+#include "vm/thread.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+UNIT_TEST_CASE(DirectoryCurrentNoScope) {
+  char* current_dir = dart::bin::Directory::CurrentNoScope();
+  EXPECT_NOTNULL(current_dir);
+  free(current_dir);
+}
+
+
+TEST_CASE(DirectoryCurrent) {
+  const char* current = dart::bin::Directory::Current();
+  EXPECT_NOTNULL(current);
+}
+
+
+TEST_CASE(DirectoryExists) {
+  const char* current = dart::bin::Directory::Current();
+  EXPECT_NOTNULL(current);
+
+  dart::bin::Directory::ExistsResult r =
+      dart::bin::Directory::Exists(current);
+  EXPECT_EQ(dart::bin::Directory::EXISTS, r);
+}
+
+
+TEST_CASE(DirectorySystemTemp) {
+  const char* system_temp = dart::bin::Directory::SystemTemp();
+  EXPECT_NOTNULL(system_temp);
+}
+
+
+TEST_CASE(DirectoryCreateTemp) {
+  const char* kTempPrefix = "test_prefix";
+  const char* system_temp = dart::bin::Directory::SystemTemp();
+  EXPECT_NOTNULL(system_temp);
+
+  const char* temp_dir = dart::bin::Directory::CreateTemp(kTempPrefix);
+  EXPECT_NOTNULL(temp_dir);
+
+  // Make sure temp_dir contains test_prefix.
+  EXPECT_NOTNULL(strstr(temp_dir, kTempPrefix));
+
+  // Cleanup.
+  EXPECT(dart::bin::Directory::Delete(temp_dir, false));
+}
+
+
+TEST_CASE(DirectorySetCurrent) {
+  const char* current = dart::bin::Directory::Current();
+  EXPECT_NOTNULL(current);
+
+  const char* system_temp = dart::bin::Directory::SystemTemp();
+  EXPECT_NOTNULL(system_temp);
+
+  EXPECT(dart::bin::Directory::SetCurrent(system_temp));
+
+  const char* new_current = dart::bin::Directory::Current();
+  EXPECT_NOTNULL(new_current);
+
+  EXPECT_NOTNULL(strstr(new_current, system_temp));
+
+  EXPECT(dart::bin::Directory::SetCurrent(current));
+}
+
+
+TEST_CASE(DirectoryCreateDelete) {
+  const char* kTempDirName = "test_name";
+
+  const char* system_temp = dart::bin::Directory::SystemTemp();
+  EXPECT_NOTNULL(system_temp);
+
+  const intptr_t name_len =
+      snprintf(NULL, 0, "%s/%s", system_temp, kTempDirName);
+  ASSERT(name_len > 0);
+  char* name = new char[name_len + 1];
+  snprintf(name, name_len + 1, "%s/%s", system_temp, kTempDirName);
+
+  // Make a directory.
+  EXPECT(dart::bin::Directory::Create(name));
+
+  // Make sure it exists.
+  dart::bin::Directory::ExistsResult r = dart::bin::Directory::Exists(name);
+  EXPECT_EQ(dart::bin::Directory::EXISTS, r);
+
+  // Cleanup.
+  EXPECT(dart::bin::Directory::Delete(name, false));
+  delete[] name;
+}
+
+
+TEST_CASE(DirectoryRename) {
+  const char* kTempDirName = "test_name";
+
+  const char* system_temp = dart::bin::Directory::SystemTemp();
+  EXPECT_NOTNULL(system_temp);
+
+  const intptr_t name_len =
+      snprintf(NULL, 0, "%s/%s", system_temp, kTempDirName);
+  ASSERT(name_len > 0);
+  char* name = new char[name_len + 1];
+  snprintf(name, name_len + 1, "%s/%s", system_temp, kTempDirName);
+
+  // Make a directory.
+  EXPECT(dart::bin::Directory::Create(name));
+
+  // Make sure it exists.
+  dart::bin::Directory::ExistsResult r = dart::bin::Directory::Exists(name);
+  EXPECT_EQ(dart::bin::Directory::EXISTS, r);
+
+  const intptr_t new_name_len =
+      snprintf(NULL, 0, "%s/%snewname", system_temp, kTempDirName);
+  ASSERT(new_name_len > 0);
+  char* new_name = new char[new_name_len + 1];
+  snprintf(new_name, new_name_len + 1, "%s/%snewname",
+      system_temp, kTempDirName);
+
+  EXPECT(dart::bin::Directory::Rename(name, new_name));
+
+  r = dart::bin::Directory::Exists(new_name);
+  EXPECT_EQ(dart::bin::Directory::EXISTS, r);
+
+  r = dart::bin::Directory::Exists(name);
+  EXPECT_EQ(dart::bin::Directory::DOES_NOT_EXIST, r);
+
+  EXPECT(dart::bin::Directory::Delete(new_name, false));
+  delete[] name;
+  delete[] new_name;
+}
+
+}  // namespace dart
diff --git a/runtime/bin/fuchsia_test.cc b/runtime/bin/fuchsia_test.cc
deleted file mode 100644
index fef899a..0000000
--- a/runtime/bin/fuchsia_test.cc
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include <dart_api.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "bin/log.h"
-#include "platform/assert.h"
-
-const char* kBuiltinScript =
-    "_printString(String line) native \"Builtin_PrintString\";\n"
-    "_getPrintClosure() => _printString;\n";
-
-const char* kHelloWorldScript = "main() { print(\"Hello, Fuchsia!\"); }";
-
-namespace dart {
-namespace bin {
-
-// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
-// link in a snapshot otherwise it is initialized to NULL.
-extern const uint8_t* vm_isolate_snapshot_buffer;
-
-// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
-// snapshot otherwise it is initialized to NULL.
-extern const uint8_t* isolate_snapshot_buffer;
-
-static void Builtin_PrintString(Dart_NativeArguments args) {
-  intptr_t length = 0;
-  uint8_t* chars = NULL;
-  Dart_Handle str = Dart_GetNativeArgument(args, 0);
-  Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
-  if (Dart_IsError(result)) {
-    Dart_PropagateError(result);
-  }
-  // Uses fwrite to support printing NUL bytes.
-  intptr_t res = fwrite(chars, 1, length, stdout);
-  ASSERT(res == length);
-  fputs("\n", stdout);
-  fflush(stdout);
-}
-
-static Dart_NativeFunction NativeLookup(Dart_Handle name,
-                                        int argument_count,
-                                        bool* auto_setup_scope) {
-  const char* function_name = NULL;
-  Dart_Handle err = Dart_StringToCString(name, &function_name);
-  DART_CHECK_VALID(err);
-  *auto_setup_scope = true;
-  if (strcmp(function_name, "Builtin_PrintString") == 0) {
-    return reinterpret_cast<Dart_NativeFunction>(Builtin_PrintString);
-  }
-  return NULL;
-}
-
-static const uint8_t* NativeSymbol(Dart_NativeFunction nf) {
-  if (reinterpret_cast<Dart_NativeFunction>(Builtin_PrintString) == nf) {
-    return reinterpret_cast<const uint8_t*>("Builtin_PrintString");
-  }
-  return NULL;
-}
-
-static Dart_Handle PrepareBuiltinLibrary(const char* script) {
-  Log::Print("Creating builtin library uri\n");
-  Dart_Handle builtin_uri = Dart_NewStringFromCString("builtin_uri");
-  DART_CHECK_VALID(builtin_uri);
-
-  Log::Print("Creating builtin library script string\n");
-  Dart_Handle builtin_script = Dart_NewStringFromCString(script);
-  DART_CHECK_VALID(builtin_script);
-
-  Log::Print("Loading builtin library\n");
-  Dart_Handle status =
-      Dart_LoadLibrary(builtin_uri, Dart_Null(), builtin_script, 0, 0);
-  DART_CHECK_VALID(status);
-
-  Log::Print("Looking up builtin library\n");
-  Dart_Handle builtin_library = Dart_LookupLibrary(builtin_uri);
-  DART_CHECK_VALID(builtin_library);
-
-  Log::Print("Setting up native resolver for builtin library\n");
-  status = Dart_SetNativeResolver(builtin_library, NativeLookup, NativeSymbol);
-  DART_CHECK_VALID(status);
-
-  return builtin_library;
-}
-
-static Dart_Handle PrepareScriptLibrary(const char* script) {
-  Log::Print("Creating script URI string\n");
-  Dart_Handle script_uri = Dart_NewStringFromCString("script_uri");
-  DART_CHECK_VALID(script_uri);
-
-  Log::Print("Creating script string\n");
-  Dart_Handle script_string = Dart_NewStringFromCString(script);
-  DART_CHECK_VALID(script_string);
-
-  Log::Print("Loading script into new library\n");
-  Dart_Handle status =
-      Dart_LoadLibrary(script_uri, Dart_Null(), script_string, 0, 0);
-  DART_CHECK_VALID(status);
-
-  Log::Print("Looking up script library\n");
-  Dart_Handle library = Dart_LookupLibrary(script_uri);
-  DART_CHECK_VALID(library);
-
-  return library;
-}
-
-static Dart_Handle LoadInternalLibrary() {
-  Log::Print("Creating internal library uri string\n");
-  Dart_Handle url = Dart_NewStringFromCString("dart:_internal");
-  DART_CHECK_VALID(url);
-
-  Log::Print("Looking up internal library\n");
-  Dart_Handle internal_library = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(internal_library);
-
-  return internal_library;
-}
-
-static void PreparePrintClosure(Dart_Handle builtin_library,
-                                Dart_Handle internal_library) {
-  Log::Print("Creating _getPrintClosure name string\n");
-  Dart_Handle get_print_closure_name =
-      Dart_NewStringFromCString("_getPrintClosure");
-  DART_CHECK_VALID(get_print_closure_name);
-
-  Log::Print("Invoking _getPrintClosure\n");
-  Dart_Handle print_closure = Dart_Invoke(
-      builtin_library, get_print_closure_name, 0, NULL);
-  DART_CHECK_VALID(print_closure);
-
-  Log::Print("Creating _printClosure name string\n");
-  Dart_Handle print_closure_name = Dart_NewStringFromCString("_printClosure");
-  DART_CHECK_VALID(print_closure_name);
-
-  Log::Print("Setting _printClosure to result of _getPrintClosure\n");
-  Dart_Handle status = Dart_SetField(
-      internal_library, print_closure_name, print_closure);
-  DART_CHECK_VALID(status);
-}
-
-int Main() {
-  Log::Print("Calling Dart_SetVMFlags\n");
-  if (!Dart_SetVMFlags(0, NULL)) {
-    FATAL("Failed to set flags\n");
-  }
-  Log::Print("Calling Dart_Initialize\n");
-  Dart_InitializeParams init_params;
-  memset(&init_params, 0, sizeof(init_params));
-  init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
-  init_params.vm_isolate_snapshot = vm_isolate_snapshot_buffer;
-  char* error = Dart_Initialize(&init_params);
-  if (error != NULL) {
-    FATAL1("VM initialization failed: %s\n", error);
-  }
-
-  Log::Print("Creating Isolate\n");
-  Dart_Isolate isolate = Dart_CreateIsolate(
-      "script_uri",
-      "main",
-      isolate_snapshot_buffer,
-      NULL,
-      NULL,
-      &error);
-  if (isolate == NULL) {
-    FATAL1("Dart_CreateIsolate failed: %s\n", error);
-  }
-
-  Log::Print("Entering Scope\n");
-  Dart_EnterScope();
-
-  Dart_Handle library = PrepareScriptLibrary(kHelloWorldScript);
-
-  Dart_Handle builtin_library = PrepareBuiltinLibrary(kBuiltinScript);
-
-  Log::Print("Finalizing loading\n");
-  Dart_Handle status = Dart_FinalizeLoading(false);
-  DART_CHECK_VALID(status);
-
-  Dart_Handle internal_library = LoadInternalLibrary();
-
-  PreparePrintClosure(builtin_library, internal_library);
-
-  Log::Print("Creating main string\n");
-  Dart_Handle main_name = Dart_NewStringFromCString("main");
-  DART_CHECK_VALID(main_name);
-
-  Log::Print("---- Invoking main() ----\n");
-  status = Dart_Invoke(library, main_name, 0, NULL);
-  DART_CHECK_VALID(status);
-  Log::Print("---- main() returned ----\n");
-
-  Log::Print("Exiting Scope\n");
-  Dart_ExitScope();
-  Log::Print("Shutting down the isolate\n");
-  Dart_ShutdownIsolate();
-
-  Log::Print("Calling Dart_Cleanup\n");
-  error = Dart_Cleanup();
-  if (error != NULL) {
-    FATAL1("VM Cleanup failed: %s\n", error);
-  }
-
-  Log::Print("Success!\n");
-  return 0;
-}
-
-}  // namespace bin
-}  // namespace dart
-
-int main(void) {
-  return dart::bin::Main();
-}
diff --git a/runtime/bin/fuchsia_vm_tests.txt b/runtime/bin/fuchsia_vm_tests.txt
deleted file mode 100644
index 0cbf30a9..0000000
--- a/runtime/bin/fuchsia_vm_tests.txt
+++ /dev/null
@@ -1,930 +0,0 @@
-GetRandomBytes
-CircularLinkedList
-Read
-FileLength
-FilePosition
-Set
-StackAllocatedDestruction
-StackAllocatedLongJump
-StackResourceDestruction
-StackResourceLongJump
-StoreIntoObject
-ReadArgument
-AddressingModes
-JumpAroundCrash
-SimpleLoop
-Cmpb
-Testb
-Increment
-IncrementLong
-Decrement
-DecrementLong
-SignedMultiply
-UnsignedMultiply
-SignedMultiply64
-SignedMultiplyLong
-OverflowSignedMultiply
-SignedMultiply1
-SignedMultiply2
-UnsignedMultiplyLong
-SignedDivide
-UnsignedDivide
-SignedDivideLong
-UnsignedDivideLong
-Negate
-BitScanReverse
-MoveExtend
-MoveExtend32
-MoveExtendMemory
-MoveExtend32Memory
-MoveWord
-MoveWordRex
-LongAddReg
-LongAddImmediate
-LongAddAddress
-LongSubReg
-LongSubImmediate
-LongSubAddress
-AddReg
-AddImmediate
-AddAddress
-SubReg
-SubImmediate
-SubAddress
-Bitwise
-Bitwise64
-LogicalOps
-LogicalOps64
-LogicalTestL
-LogicalTestQ
-CompareSwapEQ
-CompareSwapNEQ
-Exchange
-LargeConstant
-CallSimpleLeaf
-JumpSimpleLeaf
-JumpIndirect
-SingleFPMoves
-SingleFPMoves2
-PackedDoubleAdd
-PackedDoubleSub
-PackedDoubleNegate
-PackedDoubleAbsolute
-PackedDoubleMul
-PackedDoubleDiv
-PackedDoubleSqrt
-PackedDoubleMin
-PackedDoubleMax
-PackedDoubleShuffle
-PackedDoubleToSingle
-PackedSingleToDouble
-SingleFPOperations
-PackedFPOperations
-PackedIntOperations
-PackedIntOperations2
-PackedFPOperations2
-PackedCompareEQ
-PackedCompareNEQ
-PackedCompareLT
-PackedCompareLE
-PackedCompareNLT
-PackedCompareNLE
-PackedNegate
-PackedAbsolute
-PackedSetWZero
-PackedMin
-PackedMax
-PackedLogicalOr
-PackedLogicalAnd
-PackedLogicalNot
-PackedMoveHighLow
-PackedMoveLowHigh
-PackedUnpackLow
-PackedUnpackHigh
-PackedUnpackLowPair
-PackedUnpackHighPair
-DoubleFPMoves
-DoubleFPOperations
-Int32ToDoubleConversion
-Int64ToDoubleConversion
-DoubleToInt64Conversion
-TestObjectCompare
-TestNop
-TestAlign0
-TestAlign1
-TestAlign1Offset1
-TestAlignLarge
-TestAdds
-TestNot
-TestNotInt32
-XorpdZeroing
-XorpdZeroing2
-Pxor
-SquareRootDouble
-DoubleFPUStackMoves
-Sine
-Cosine
-IntToDoubleConversion
-DoubleToDoubleTrunc
-DoubleAbs
-ExtractSignBits
-TestSetCC
-TestRepMovsBytes
-ConditionalMovesCompare
-BitTest
-ConditionalMovesEqual
-ConditionalMovesNoOverflow
-Assert
-Expect
-Fail0
-Fail1
-Fail2
-AstPrinter
-Ast
-FetchAndIncrement
-FetchAndDecrement
-IncrementBy
-DecrementBy
-LoadRelaxed
-CompareAndSwapWord
-CompareAndSwapUint32
-BigintSmi
-BigintInt64
-BigintUint64
-BigintDouble
-BigintHexStrings
-BigintDecStrings
-BigintCompare
-BigintDecimalStrings
-BitSetBasic
-BitVector
-BitFields
-BitmapBuilder
-BoolField
-ClassHierarchyAnalysis
-ClassFinalizer
-ClassFinalize_Cycles
-ClassFinalize_Resolve
-StackmapCodegen
-StackmapGC
-DescriptorList_TokenPositions
-CodeSourceMap_TokenPositions
-SimpleReturnCodegen
-SmiReturnCodegen
-SimpleStaticCallCodegen
-StaticCallReturnParameterCodegen
-StaticCallSmiParamSumCodegen
-SmiAddCodegen
-GenericAddCodegen
-SmiBinaryOpCodegen
-BoolNotCodegen
-BoolAndCodegen
-BinaryOpCodegen
-SmiUnaryOpCodegen
-DoubleUnaryOpCodegen
-StaticCallCodegen
-InstanceCallCodegen
-AllocateNewObjectCodegen
-IcDataAccess
-CompileScript
-CompileFunction
-CompileFunctionOnHelperThread
-RegenerateAllocStubs
-EvalExpression
-EvalExpressionWithLazyCompile
-EvalExpressionExhaustCIDs
-Id
-GetCpuModelTest
-CustomIsolates
-ErrorHandleBasics
-StacktraceInfo
-DeepStacktraceInfo
-StackOverflowStacktraceInfo
-OutOfMemoryStacktraceInfo
-CurrentStacktraceInfo
-ErrorHandleTypes
-UnhandleExceptionError
-Dart_PropagateError
-Dart_Error
-Null
-EmptyString
-IdentityEquals
-IdentityHash
-ObjectEquals
-InstanceValues
-InstanceGetType
-BooleanValues
-BooleanConstants
-DoubleValues
-NumberValues
-IntegerValues
-IntegerFitsIntoInt64
-IntegerFitsIntoUint64
-ArrayValues
-IsString
-NewString
-MalformedStringToUTF8
-ExternalStringCallback
-ExternalStringPretenure
-ExternalTypedDataPretenure
-ListAccess
-MapAccess
-IsFuture
-TypedDataViewListGetAsBytes
-TypedDataViewListIsTypedData
-TypedDataAccess
-ByteBufferAccess
-ByteDataAccess
-ExternalByteDataAccess
-OptimizedExternalByteDataAccess
-TypedDataDirectAccessUnverified
-TypedDataDirectAccessVerified
-TypedDataDirectAccess1Unverified
-TypedDataDirectAccess1Verified
-TypedDataViewDirectAccessUnverified
-TypedDataViewDirectAccessVerified
-ByteDataDirectAccessUnverified
-ByteDataDirectAccessVerified
-ExternalTypedDataAccess
-ExternalClampedTypedDataAccess
-ExternalUint8ClampedArrayAccess
-ExternalTypedDataCallback
-SlowFinalizer
-Float32x4List
-EnterExitScope
-PersistentHandles
-NewPersistentHandle_FromPersistentHandle
-AssignToPersistentHandle
-WeakPersistentHandle
-WeakPersistentHandleCallback
-WeakPersistentHandleNoCallback
-WeakPersistentHandlesCallbackShutdown
-WeakPersistentHandleExternalAllocationSize
-WeakPersistentHandleExternalAllocationSizeNewspaceGC
-WeakPersistentHandleExternalAllocationSizeOldspaceGC
-WeakPersistentHandleExternalAllocationSizeOddReferents
-ImplicitReferencesOldSpace
-ImplicitReferencesNewSpace
-SetGarbageCollectionCallbacks
-SingleGarbageCollectionCallback
-LocalHandles
-LocalZoneMemory
-Isolates
-CurrentIsolateData
-IsolateSetCheckedMode
-DebugName
-SetMessageCallbacks
-TypeGetNonParamtericTypes
-TypeGetParameterizedTypes
-FieldAccess
-SetField_FunnyValue
-InjectNativeFields1
-InjectNativeFields2
-InjectNativeFields3
-InjectNativeFields4
-TestNativeFieldsAccess
-InjectNativeFieldsSuperClass
-NativeFieldAccess
-ImplicitNativeFieldAccess
-NegativeNativeFieldAccess
-NegativeNativeFieldInIsolateMessage
-GetStaticField_RunsInitializer
-GetField_CheckIsolate
-SetField_CheckIsolate
-New
-New_Issue2971
-Invoke
-Invoke_PrivateStatic
-Invoke_FunnyArgs
-Invoke_Null
-InvokeNoSuchMethod
-Invoke_CrossLibrary
-InvokeClosure
-ThrowException
-GetNativeArguments
-GetNativeArgumentCount
-GetType
-InstanceOf
-LoadScript
-RootLibrary
-LoadScript_CompileError
-LookupLibrary
-LibraryName
-LibraryId
-LibraryUrl
-LibraryGetClassNames
-GetFunctionNames
-LibraryImportLibrary
-ImportLibraryWithPrefix
-LoadLibrary
-LoadLibrary_CompileError
-LoadSource
-LoadSource_LateLoad
-LoadPatch
-LoadPatchSignatureMismatch
-ParsePatchLibrary
-SetNativeResolver
-ImportLibrary2
-ImportLibrary3
-ImportLibrary4
-ImportLibrary5
-IllegalNewSendPort
-IllegalPost
-NewNativePort
-NativePortPostInteger
-NativePortReceiveNull
-NativePortReceiveInteger
-RunLoop_Success
-RunLoop_Exception
-IsolateShutdown
-IsolateShutdownRunDartCode
-NativeFunctionClosure
-NativeStaticFunctionClosure
-RangeLimits
-NewString_Null
-InvalidGetSetPeer
-OneNewSpacePeer
-CollectOneNewSpacePeer
-TwoNewSpacePeers
-CollectTwoNewSpacePeers
-CopyNewSpacePeers
-OnePromotedPeer
-OneOldSpacePeer
-CollectOneOldSpacePeer
-TwoOldSpacePeers
-CollectTwoOldSpacePeers
-MakeExternalString
-ExternalizeConstantStrings
-LazyLoadDeoptimizes
-GuardExternalizedString
-ExternalStringDeoptimize
-ExternalStringPolymorphicDeoptimize
-ExternalStringLoadElimination
-ExternalStringGuardFieldDeoptimize
-ExternalStringStaticFieldDeoptimize
-ExternalStringTrimDoubleParse
-ExternalStringDoubleParse
-ExternalStringIndexOf
-StringFromExternalTypedData
-Timeline_Dart_TimelineDuration
-Timeline_Dart_TimelineInstant
-Timeline_Dart_TimelineAsyncDisabled
-Timeline_Dart_TimelineAsync
-Timeline_Dart_TimelineGetTrace
-Timeline_Dart_TimelineGetTraceOnlyDartEvents
-Timeline_Dart_TimelineGetTraceWithDartEvents
-Timeline_Dart_TimelineGetTraceGlobalOverride
-Timeline_Dart_GlobalTimelineGetTrace
-Timeline_Dart_GlobalTimelineGetTrace_Threaded
-Timeline_Dart_EmbedderTimelineStartStopRecording
-Dart_LoadLibraryPatch_1
-Dart_LoadLibraryPatch_Error1
-Dart_LoadLibraryPatch_Error2
-Dart_LoadLibraryPatch_Error3
-DartEntry
-InvokeStatic_CompileError
-InvokeDynamic_CompileError
-Debugger_PrintBreakpointsToJSONArray
-Debugger_PauseEvent
-Debug_Breakpoint
-Debug_InspectStack_NotOptimized
-Debug_InspectStack_Optimized
-Debug_InspectStackWithClosure_NotOptimized
-Debug_InspectStackWithClosure_Optimized
-Debug_StepOut
-Debug_StepInto
-Debug_IgnoreBP
-Debug_DeoptimizeFunction
-Debug_SingleStep
-Debug_ClosureBreakpoint
-Debug_ExprClosureBreakpoint
-Debug_BreakpointStubPatching
-Debug_DeleteBreakpoint
-Debug_InspectStaticField
-Debug_InspectObject
-Debug_IsolateID
-Debug_InterruptIsolate
-Debug_StackTraceDump1
-Debug_StackTraceDump2
-Debug_EvaluateExpr
-Debug_EvaluateInActivationOfEvaluate
-Debug_BreakOnUnhandledException
-Debug_GetClosureInfo
-Debug_GetSupertype
-Debug_ListSuperType
-Debug_ScriptGetTokenInfo_Basic
-Debug_ScriptGetTokenInfo_MultiLineInterpolation
-Disassembler
-UnhandledExceptions
-FindCodeObject
-BasicFlags
-ParseFlags
-SourcePosition_InstanceCalls
-SourcePosition_If
-SourcePosition_ForLoop
-SourcePosition_While
-SourcePosition_WhileContinueBreak
-SourcePosition_LoadIndexed
-SourcePosition_StoreIndexed
-SourcePosition_BitwiseOperations
-SourcePosition_IfElse
-SourcePosition_Switch
-SourcePosition_TryCatchFinally
-SourcePosition_InstanceFields
-SourcePosition_Async
-SourcePosition_SyntheticTokens
-RangeTests
-RangeTestsInfinity
-RangeUtils
-RangeBinaryOp
-RangeAdd
-RangeSub
-RangeAnd
-RangeIntersectionMinMax
-RangeJoinMinMax
-FreeList
-FreeListProtected
-FreeListProtectedTinyObjects
-FreeListProtectedVariableSizeObjects
-GrowableArray
-MallocGrowableArray
-GrowableArraySort
-GrowableHandlePtr
-GuardFieldSimpleTest
-GuardFieldFinalListTest
-GuardFieldFinalVariableLengthListTest
-GuardFieldConstructorTest
-GuardFieldConstructor2Test
-AllocateZoneHandle
-AllocateScopeHandle
-DirectChainedHashMap
-MallocDirectChainedHashMap
-DirectChainedHashMapIterator
-HashTable
-Sets
-Maps
-OldGC
-OldGC_Unsync
-LargeSweep
-ClassHeapStats
-ArrayHeapStats
-FindObject
-IterateReadOnly
-BecomeFowardOldToOld
-BecomeFowardNewToNew
-BecomeFowardOldToNew
-BecomeFowardNewToOld
-BecomeForwardRememberedObject
-InstructionTests
-OptimizationTests
-IsolateReload_FunctionReplacement
-IsolateReload_BadClass
-IsolateReload_StaticValuePreserved
-IsolateReload_SavedClosure
-IsolateReload_TopLevelFieldAdded
-IsolateReload_ClassFieldAdded
-IsolateReload_ClassFieldAdded2
-IsolateReload_ClassFieldRemoved
-IsolateReload_ClassAdded
-IsolateReload_LibraryImportAdded
-IsolateReload_LibraryImportRemoved
-IsolateReload_LibraryDebuggable
-IsolateReload_ImplicitConstructorChanged
-IsolateReload_ConstructorChanged
-IsolateReload_SuperClassChanged
-IsolateReload_Generics
-IsolateReload_TypeIdentity
-IsolateReload_TypeIdentityGeneric
-IsolateReload_TypeIdentityParameter
-IsolateReload_MixinChanged
-IsolateReload_ComplexInheritanceChange
-IsolateReload_LiveStack
-IsolateReload_LibraryLookup
-IsolateReload_LibraryHide
-IsolateReload_LibraryShow
-IsolateReload_SmiFastPathStubs
-IsolateReload_ImportedMixinFunction
-IsolateReload_TopLevelParseError
-IsolateReload_PendingUnqualifiedCall_StaticToInstance
-IsolateReload_PendingUnqualifiedCall_InstanceToStatic
-IsolateReload_PendingConstructorCall_AbstractToConcrete
-IsolateReload_PendingConstructorCall_ConcreteToAbstract
-IsolateReload_PendingStaticCall_DefinedToNSM
-IsolateReload_PendingStaticCall_NSMToDefined
-IsolateReload_PendingSuperCall
-IsolateReload_TearOff_Equality
-IsolateReload_TearOff_List_Set
-IsolateReload_EnumEquality
-IsolateReload_EnumIdentical
-IsolateReload_EnumReorderIdentical
-IsolateReload_EnumAddition
-IsolateReload_EnumToNotEnum
-IsolateReload_NotEnumToEnum
-IsolateReload_EnumDelete
-IsolateReload_EnumIdentityReload
-IsolateReload_ConstantIdentical
-IsolateReload_EnumValuesToString
-IsolateReload_DirectSubclasses_Success
-IsolateReload_DirectSubclasses_GhostSubclass
-IsolateReload_DirectSubclasses_Failure
-IsolateReload_ChangeInstanceFormat0
-IsolateReload_ChangeInstanceFormat1
-IsolateReload_ChangeInstanceFormat2
-IsolateReload_ChangeInstanceFormat3
-IsolateReload_ChangeInstanceFormat4
-IsolateReload_ChangeInstanceFormat5
-IsolateReload_ChangeInstanceFormat6
-IsolateReload_ChangeInstanceFormat7
-IsolateReload_NoLibsModified
-IsolateReload_MainLibModified
-IsolateReload_ImportedLibModified
-IsolateReload_PrefixImportedLibModified
-IsolateCurrent
-IsolateSpawn
-StackLimitInterrupts
-NoOOBMessageScope
-JSON_TextBuffer
-JSON_JSONStream_Primitives
-JSON_JSONStream_Array
-JSON_JSONStream_Object
-JSON_JSONStream_NestedObject
-JSON_JSONStream_ObjectArray
-JSON_JSONStream_ArrayArray
-JSON_JSONStream_Printf
-JSON_JSONStream_ObjectPrintf
-JSON_JSONStream_DartObject
-JSON_JSONStream_EscapedString
-JSON_JSONStream_DartString
-JSON_JSONStream_Params
-JSON_JSONStream_AppendJSONStreamConsumer
-Log_Macro
-Log_Basic
-Log_Block
-LongJump
-NullRegion
-NewRegion
-Subregion
-ExtendedRegion
-MessageHandler_PostMessage
-MessageHandler_HasOOBMessages
-MessageHandler_ClosePort
-MessageHandler_CloseAllPorts
-MessageHandler_HandleNextMessage
-MessageHandler_HandleNextMessage_ProcessOOBAfterError
-MessageHandler_HandleNextMessage_Shutdown
-MessageHandler_HandleOOBMessages
-MessageHandler_Run
-MessageQueue_BasicOperations
-MessageQueue_Clear
-Metric_Simple
-Metric_OnDemand
-ObjectGraph
-ObjectIdRingSerialWrapTest
-ObjectIdRingScavengeMoveTest
-ObjectIdRingOldGCTest
-ObjectIdRingExpiredEntryTest
-Class
-TypeArguments
-TokenStream
-GenerateExactSource
-Class_ComputeEndTokenPos
-InstanceClass
-Smi
-StringCompareTo
-StringEncodeIRI
-StringDecodeIRI
-StringDecodeIRIInvalid
-StringIRITwoByte
-Mint
-Double
-Bigint
-Integer
-String
-StringFormat
-StringConcat
-StringHashConcat
-StringSubStringDifferentWidth
-StringFromUtf8Literal
-StringEqualsUtf8
-StringEqualsUTF32
-ExternalOneByteString
-EscapeSpecialCharactersOneByteString
-EscapeSpecialCharactersExternalOneByteString
-EscapeSpecialCharactersTwoByteString
-EscapeSpecialCharactersExternalTwoByteString
-ExternalTwoByteString
-Symbol
-SymbolUnicode
-Bool
-Array
-ArrayLengthNegativeOne
-ArrayLengthSmiMin
-ArrayLengthOneTooMany
-ArrayLengthMaxElements
-Int8ListLengthNegativeOne
-Int8ListLengthSmiMin
-Int8ListLengthOneTooMany
-Int8ListLengthMaxElements
-StringCodePointIterator
-StringCodePointIteratorRange
-GrowableObjectArray
-InternalTypedData
-ExternalTypedData
-Script
-EmbeddedScript
-Context
-ContextScope
-Closure
-ObjectPrinting
-CheckedHandle
-Code
-CodeImmutability
-EmbedStringInCode
-EmbedSmiInCode
-EmbedSmiIn64BitCode
-ExceptionHandlers
-PcDescriptors
-PcDescriptorsLargeDeltas
-ClassDictionaryIterator
-ICData
-SubtypeTestCache
-FieldTests
-EqualsIgnoringPrivate
-ArrayNew_Overflow_Crash
-StackTraceFormat
-WeakProperty_PreserveCrossGen
-WeakProperty_PreserveRecurse
-WeakProperty_PreserveOne_NewSpace
-WeakProperty_PreserveTwo_NewSpace
-WeakProperty_PreserveTwoShared_NewSpace
-WeakProperty_PreserveOne_OldSpace
-WeakProperty_PreserveTwo_OldSpace
-WeakProperty_PreserveTwoShared_OldSpace
-WeakProperty_ClearOne_NewSpace
-WeakProperty_ClearTwoShared_NewSpace
-WeakProperty_ClearOne_OldSpace
-WeakProperty_ClearTwoShared_OldSpace
-MirrorReference
-FindClosureIndex
-FindInvocationDispatcherFunctionIndex
-Metadata
-FunctionSourceFingerprint
-FunctionWithBreakpointNotInlined
-SpecialClassesHaveEmptyArrays
-PrintJSON
-PrintJSONPrimitives
-InstanceEquality
-HashCode
-LinkedHashMap
-LinkedHashMap_iteration
-Symbols_FromConcatAll
-String_ScrubName
-Sleep
-SNPrint
-SNPrint_BadArgs
-OsFuncs
-OSAlignedAllocate
-Pages
-ParseClassDefinition
-Parser_TopLevel
-Parser_AllocateVariables_CapturedVar
-Parser_AllocateVariables_NestedCapturedVar
-Parser_AllocateVariables_TwoChains
-Parser_AllocateVariables_Issue7681
-Parser_AllocateVariables_CaptureLoopVar
-Parser_AllocateVariables_MiddleChain
-PortMap_CreateAndCloseOnePort
-PortMap_CreateAndCloseTwoPorts
-PortMap_ClosePorts
-PortMap_CreateManyPorts
-PortMap_SetPortState
-PortMap_PostMessage
-PortMap_PostIntegerMessage
-PortMap_PostNullMessage
-PortMap_PostMessageClosedPort
-Profiler_SampleBufferWrapTest
-Profiler_SampleBufferIterateTest
-Profiler_AllocationSampleTest
-Profiler_TrivialRecordAllocation
-Profiler_ToggleRecordAllocation
-Profiler_CodeTicks
-Profiler_FunctionTicks
-Profiler_IntrinsicAllocation
-Profiler_ArrayAllocation
-Profiler_ContextAllocation
-Profiler_ClosureAllocation
-Profiler_TypedArrayAllocation
-Profiler_StringAllocation
-Profiler_StringInterpolation
-Profiler_FunctionInline
-Profiler_InliningIntervalBoundry
-Profiler_ChainedSamples
-Profiler_BasicSourcePosition
-Profiler_BasicSourcePositionOptimized
-Profiler_SourcePosition
-Profiler_SourcePositionOptimized
-Profiler_BinaryOperatorSourcePosition
-Profiler_BinaryOperatorSourcePositionOptimized
-Profiler_GetSourceReport
-RegExp_OneByteString
-RegExp_TwoByteString
-RegExp_ExternalOneByteString
-RegExp_ExternalTwoByteString
-DartStaticResolve
-DartDynamicResolve
-RingBuffer
-Scanner_Test
-ZeroSizeScavenger
-LocalScope
-Service_IdZones
-Service_Code
-Service_TokenStream
-Service_PcDescriptors
-Service_LocalVarDescriptors
-Service_PersistentHandles
-Service_Address
-Service_EmbedderRootHandler
-Service_EmbedderIsolateHandler
-Service_Profile
-SerializeNull
-SerializeSmi1
-SerializeSmi2
-SerializeMints
-SerializeDouble
-SerializeTrue
-SerializeFalse
-SerializeCapability
-SerializeBigint
-SerializeBigint2
-SerializeSingletons
-SerializeString
-SerializeArray
-FailSerializeLargeArray
-FailSerializeLargeNestedArray
-FailSerializeLargeTypedDataInt8
-FailSerializeLargeTypedDataUint8
-FailSerializeLargeExternalTypedData
-SerializeEmptyArray
-SerializeByteArray
-SerializeTypedArray
-SerializeExternalTypedArray
-SerializeEmptyByteArray
-SerializeScript
-CanonicalizationInScriptSnapshots
-GenerateSource
-FullSnapshot
-FullSnapshot1
-ScriptSnapshot
-ScriptSnapshot1
-ScriptSnapshot2
-IntArrayMessage
-DartGeneratedMessages
-DartGeneratedListMessages
-DartGeneratedArrayLiteralMessages
-DartGeneratedListMessagesWithBackref
-DartGeneratedArrayLiteralMessagesWithBackref
-DartGeneratedListMessagesWithTypedData
-PostCObject
-OmittedObjectEncodingLength
-SourceReport_Coverage_NoCalls
-SourceReport_Coverage_SimpleCall
-SourceReport_Coverage_ForceCompile
-SourceReport_Coverage_UnusedClass_NoForceCompile
-SourceReport_Coverage_UnusedClass_ForceCompile
-SourceReport_Coverage_UnusedClass_ForceCompileError
-SourceReport_Coverage_NestedFunctions
-SourceReport_Coverage_RestrictedRange
-SourceReport_Coverage_AllFunctions
-SourceReport_Coverage_AllFunctions_ForceCompile
-SourceReport_CallSites_SimpleCall
-SourceReport_CallSites_PolymorphicCall
-SourceReport_MultipleReports
-SourceReport_PossibleBreakpoints_Simple
-EmptyStackFrameIteration
-EmptyDartStackFrameIteration
-ValidateStackFrameIteration
-ValidateNoSuchMethodStackFrameIteration
-CallRuntimeStubCode
-CallLeafRuntimeStubCode
-ThreadBarrier
-ThreadPool_Create
-ThreadPool_RunOne
-ThreadPool_RunMany
-ThreadPool_WorkerShutdown
-ThreadPool_WorkerTimeout
-ThreadPool_RecursiveSpawn
-Mutex
-Monitor
-ManyTasksWithZones
-ThreadRegistry
-SafepointTestDart
-SafepointTestVM
-RecursiveSafepointTest1
-ThreadIterator_Count
-ThreadIterator_FindSelf
-ThreadIterator_AddFindRemove
-SafepointTestVM2
-RecursiveSafepointTest2
-HelperAllocAndGC
-TimelineEventIsValid
-TimelineEventDuration
-TimelineEventDurationPrintJSON
-TimelineEventArguments
-TimelineEventArgumentsPrintJSON
-TimelineEventBufferPrintJSON
-TimelineEventCallbackRecorderBasic
-TimelineAnalysis_ThreadBlockCount
-TimelineRingRecorderJSONOrder
-TimelinePauses_Basic
-TimelinePauses_BeginEnd
-Utf8Decode
-ParseUri_WithScheme_NoQueryNoUser
-ParseUri_WithScheme_WithQuery
-ParseUri_WithScheme_WithFragment
-ParseUri_WithScheme_WithQueryWithFragment
-ParseUri_WithScheme_WithUser
-ParseUri_WithScheme_ShortPath
-ParseUri_WithScheme_EmptyPath
-ParseUri_WithScheme_Rootless1
-ParseUri_WithScheme_Rootless2
-ParseUri_NoScheme_AbsPath_WithAuthority
-ParseUri_NoScheme_AbsPath_NoAuthority
-ParseUri_NoScheme_AbsPath_StrayColon
-ParseUri_NoScheme_Rootless1
-ParseUri_NoScheme_Rootless2
-ParseUri_NoScheme_Empty
-ParseUri_NoScheme_QueryOnly
-ParseUri_NoScheme_FragmentOnly
-ParseUri_LowerCaseScheme
-ParseUri_NormalizeEscapes_PathQueryFragment
-ParseUri_NormalizeEscapes_UppercaseEscapesPreferred
-ParseUri_NormalizeEscapes_Authority
-ParseUri_NormalizeEscapes_UppercaseEscapeInHost
-ParseUri_BrokenEscapeSequence
-ResolveUri_WithScheme_NoAuthorityNoQuery
-ResolveUri_WithScheme_WithAuthorityWithQuery
-ResolveUri_NoScheme_WithAuthority
-ResolveUri_NoSchemeNoAuthority_AbsolutePath
-ResolveUri_NoSchemeNoAuthority_RelativePath
-ResolveUri_NoSchemeNoAuthority_RelativePathEmptyBasePath
-ResolveUri_NoSchemeNoAuthority_RelativePathWeirdBasePath
-ResolveUri_NoSchemeNoAuthority_EmptyPath
-ResolveUri_NoSchemeNoAuthority_EmptyPathWithQuery
-ResolveUri_NoSchemeNoAuthority_EmptyPathWithFragment
-ResolveUri_RemoveDots_RemoveOneDotSegment
-ResolveUri_RemoveDots_RemoveTwoDotSegments
-ResolveUri_RemoveDots_RemoveOneDotDotSegment
-ResolveUri_RemoveDots_RemoveTwoDotDotSegments
-ResolveUri_RemoveDots_RemoveTooManyDotDotSegments
-ResolveUri_RemoveDots_RemoveDotSegmentsNothingLeft1
-ResolveUri_RemoveDots_RemoveDotSegmentsNothingLeft2
-ResolveUri_RemoveDots_RemoveDotSegmentsInitialPrefix
-ResolveUri_RemoveDots_RemoveDotSegmentsMixed
-ResolveUri_NormalizeEscapes_PathQueryFragment
-ResolveUri_NormalizeEscapes_UppercaseHexPreferred
-ResolveUri_NormalizeEscapes_Authority
-ResolveUri_NormalizeEscapes_BrokenEscapeSequence
-ResolveUri_DataUri
-ResolveUri_RelativeBase_NotImplemented
-ResolveUri_TestUriPerRFCs
-ResolveUri_MoreDotSegmentTests
-Minimum
-Maximum
-IsPowerOfTwo
-ShiftForPowerOfTwo
-IsAligned
-RoundDown
-RoundUp
-RoundUpToPowerOfTwo
-CountOneBits
-CountZeros
-IsInt
-IsUint
-IsAbsoluteUint
-LowBits
-Endianity
-DoublesBitEqual
-AllocateVirtualMemory
-FreeVirtualMemory
-VirtualMemoryCommitPartial
-AllocateZone
-AllocGeneric_Success
-AllocGeneric_Overflow
-ZoneAllocated
-PrintToString
-CorelibCompileAll
-CorelibCompilerStats
-Dart2JSCompilerStats
-CorelibIsolateStartup
-UseDartApi
-DartStringAccess
-Dart2JSCompileAll
-FrameLookup
-CoreSnapshotSize
-StandaloneSnapshotSize
-CreateMirrorSystem
-EnterExitIsolate
-SerializeNull
-SerializeSmi
-SimpleMessage
-LargeMap
diff --git a/runtime/bin/platform.cc b/runtime/bin/platform.cc
index 3dccea7..d09a8be 100644
--- a/runtime/bin/platform.cc
+++ b/runtime/bin/platform.cc
@@ -103,15 +103,19 @@
     if (Dart_IsError(result)) {
       Dart_PropagateError(result);
     }
-    for (intptr_t i = 0; i < count; i++) {
-      Dart_Handle str = DartUtils::NewString(env[i]);
+    intptr_t result_idx = 0;
+    for (intptr_t env_idx = 0; env_idx < count; env_idx++) {
+      Dart_Handle str = DartUtils::NewString(env[env_idx]);
       if (Dart_IsError(str)) {
-        Dart_PropagateError(str);
+        // Silently skip over environment entries that are not valid UTF8
+        // strings.
+        continue;
       }
-      Dart_Handle error = Dart_ListSetAt(result, i, str);
+      Dart_Handle error = Dart_ListSetAt(result, result_idx, str);
       if (Dart_IsError(error)) {
         Dart_PropagateError(error);
       }
+      result_idx++;
     }
     Dart_SetReturnValue(args, result);
   }
diff --git a/runtime/bin/run_vm_tests_fuchsia.cc b/runtime/bin/run_vm_tests_fuchsia.cc
index e98837a..b75881d 100644
--- a/runtime/bin/run_vm_tests_fuchsia.cc
+++ b/runtime/bin/run_vm_tests_fuchsia.cc
@@ -4,9 +4,12 @@
 
 #include <fcntl.h>
 #include <launchpad/launchpad.h>
+#include <launchpad/vmo.h>
 #include <magenta/syscalls.h>
 #include <mxio/util.h>
 #include <pthread.h>
+#include <runtime/status.h>
+#include <runtime/sysinfo.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -16,27 +19,29 @@
 // This program runs Dart VM unit tests. The Dart VM unit tests are contained
 // in a separate binary whose location is defined in kRunVmTestsPath below.
 // That program accepts a command line argument --list to list all the available
-// tests, or the name of a single test to run. This program accepts a single
-// command line argument which is the path to a file containing a list of tests
-// to run, one per line.
+// tests, or the name of a single test to run. This program grabs the list of
+// tests, and then runs them.
 
 // TODO(zra): Make this a command line argument
 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests";
 
-// The simulator only has 512MB;
-const intptr_t kOldGenHeapSizeMB = 256;
-
 // Tests that are invalid, wedge, or cause panics.
 const char* kSkip[] = {
   // These expect a file to exist that we aren't putting in the image.
   "Read",
   "FileLength",
   "FilePosition",
-  // Crash and then Hang.
+  // Crash in abort() and then hang. (MG-252)
   "ArrayLengthMaxElements",
   "Int8ListLengthMaxElements",
-  // Crashes in realloc.
-  "LargeMap",
+  "ArrayNew_Overflow_Crash",
+  "SNPrint_BadArgs",
+  "IsolateReload_PendingUnqualifiedCall_InstanceToStatic",
+  "IsolateReload_PendingUnqualifiedCall_StaticToInstance",
+  "IsolateReload_PendingConstructorCall_AbstractToConcrete",
+  "IsolateReload_PendingConstructorCall_ConcreteToAbstract",
+  "IsolateReload_PendingStaticCall_DefinedToNSM",
+  "IsolateReload_PendingStaticCall_NSMToDefined",
   // The profiler is turned off.
   "Profiler_AllocationSampleTest",
   "Profiler_ArrayAllocation",
@@ -63,35 +68,13 @@
   "Profiler_TypedArrayAllocation",
   "Profiler_GetSourceReport",
   "Service_Profile",
-  // No realpath.
+  // No realpath, files not in image.
   "Dart2JSCompilerStats",
   "Dart2JSCompileAll",
   // Uses too much memory.
   "PrintJSON",
-};
-
-// Expected to fail/crash.
-const char* kExpectFail[] = {
-  "Fail0",
-  "Fail1",
-  "Fail2",
-  "IsolateReload_PendingUnqualifiedCall_InstanceToStatic",
-  "IsolateReload_PendingUnqualifiedCall_StaticToInstance",
-  "IsolateReload_PendingConstructorCall_AbstractToConcrete",
-  "IsolateReload_PendingConstructorCall_ConcreteToAbstract",
-  "IsolateReload_PendingStaticCall_DefinedToNSM",
-  "IsolateReload_PendingStaticCall_NSMToDefined",
-  "ArrayNew_Overflow_Crash",
-  "AllocGeneric_Overflow",
-  "CodeImmutability",
-  "SNPrint_BadArgs",
-};
-
-// Bugs to fix, or things that are not yet impelemnted.
-const char* kBugs[] = {
-  // pthreads not using specified stack size?
-  "StackOverflowStacktraceInfo",
-  // Needs OS::GetCurrentThreadCPUMicros.
+  // Need OS::GetCurrentThreadCPUMicros.
+  // Skipping because they crash and hang. (MG-252)
   "Timeline_Dart_TimelineGetTrace",
   "Timeline_Dart_TimelineGetTraceOnlyDartEvents",
   "Timeline_Dart_TimelineGetTraceWithDartEvents",
@@ -106,13 +89,21 @@
   "TimelineAnalysis_ThreadBlockCount",
   "TimelineRingRecorderJSONOrder",
   "TimelinePauses_BeginEnd",
+};
+
+// Expected to fail/crash.
+const char* kExpectFail[] = {
+  "Fail0",
+  "Fail1",
+  "Fail2",
+  "AllocGeneric_Overflow",
+  "CodeImmutability",
+};
+
+// Bugs to fix, or things that are not yet implemented.
+const char* kBugs[] = {
   // Needs NativeSymbolResolver
   "Service_PersistentHandles",
-  // Crashes in realloc:
-  "FindCodeObject",
-  "SourceReport_Coverage_AllFunctions_ForceCompile",
-  // pthread TLS destructors are not run.
-  "ThreadIterator_AddFindRemove",
 };
 
 
@@ -143,56 +134,168 @@
 }
 
 
-static int run_test(const char* test_name) {
-  const intptr_t kArgc = 3;
+#define RETURN_IF_ERROR(status)                                                \
+  if (status < 0) {                                                            \
+    fprintf(stderr, "%s:%d: Magenta call failed: %s\n",                        \
+        __FILE__, __LINE__, mx_strstatus(static_cast<mx_status_t>(status)));   \
+    fflush(0);                                                                 \
+    return status;                                                             \
+  }                                                                            \
+
+
+// This is mostly taken from //magenta/system/uapp/mxsh with the addtion of
+// launchpad_add_pipe calls to setup pipes for stdout and stderr.
+static mx_status_t lp_setup(launchpad_t** lp_out, mx_handle_t binary_vmo,
+                            int argc, const char* const* argv,
+                            int *stdout_out, int *stderr_out) {
+  if ((lp_out == NULL) || (stdout_out == NULL) || (stderr_out == NULL)) {
+    return ERR_INVALID_ARGS;
+  }
+  launchpad_t* lp;
+  mx_status_t status;
+  status = launchpad_create(argv[0], &lp);
+  RETURN_IF_ERROR(status);
+  status = launchpad_arguments(lp, argc, argv);
+  RETURN_IF_ERROR(status);
+  status = launchpad_clone_mxio_root(lp);
+  RETURN_IF_ERROR(status);
+  status = launchpad_add_pipe(lp, stdout_out, 1);
+  RETURN_IF_ERROR(status);
+  status = launchpad_add_pipe(lp, stderr_out, 2);
+  RETURN_IF_ERROR(status);
+  status = launchpad_elf_load(lp, binary_vmo);
+  RETURN_IF_ERROR(status);
+  status = launchpad_load_vdso(lp, MX_HANDLE_INVALID);
+  RETURN_IF_ERROR(status);
+  *lp_out = lp;
+  return status;
+}
+
+
+// Start the test running and return file descriptors for the stdout and stderr
+// pipes.
+static mx_handle_t start_test(mx_handle_t binary_vmo, const char* test_name,
+                              int* stdout_out, int* stderr_out) {
+  const intptr_t kArgc = 2;
   const char* argv[kArgc];
 
-  char old_gen_arg[64];
-  snprintf(old_gen_arg, sizeof(old_gen_arg), "--old_gen_heap_size=%ld",
-      kOldGenHeapSizeMB);
-
   argv[0] = kRunVmTestsPath;
-  argv[1] = old_gen_arg;
-  argv[2] = test_name;
+  argv[1] = test_name;
 
-  mx_handle_t p = launchpad_launch_mxio(argv[0], kArgc, argv);
-  if (p < 0) {
-    fprintf(stderr, "process failed to start\n");
-    return -1;
+  launchpad_t* lp = NULL;
+  int stdout_pipe = -1;
+  int stderr_pipe = -1;
+  mx_status_t status = lp_setup(
+      &lp, binary_vmo, kArgc, argv, &stdout_pipe, &stderr_pipe);
+  if (status != NO_ERROR) {
+    if (lp != NULL) {
+      launchpad_destroy(lp);
+    }
+    if (stdout_pipe != -1) {
+      close(stdout_pipe);
+    }
+    if (stderr_pipe != -1) {
+      close(stderr_pipe);
+    }
   }
+  RETURN_IF_ERROR(status);
+
+  mx_handle_t p = launchpad_start(lp);
+  launchpad_destroy(lp);
+  if (p < 0) {
+    close(stdout_pipe);
+    close(stderr_pipe);
+  }
+  RETURN_IF_ERROR(p);
+
+  if (stdout_out != NULL) {
+    *stdout_out = stdout_pipe;
+  } else {
+    close(stdout_pipe);
+  }
+  if (stderr_out != NULL) {
+    *stderr_out = stderr_pipe;
+  } else {
+    close(stderr_pipe);
+  }
+  return p;
+}
+
+
+// Drain fd into a buffer pointed to by 'buffer'. Assumes that the data is a
+// C string, and null-terminates it. Returns the number of bytes read.
+static intptr_t drain_fd(int fd, char** buffer) {
+  const intptr_t kDrainInitSize = 64;
+  char* buf = reinterpret_cast<char*>(malloc(kDrainInitSize));
+  intptr_t free_space = kDrainInitSize;
+  intptr_t total_read = 0;
+  intptr_t read_size = 0;
+  while ((read_size = read(fd, buf + total_read, free_space)) != 0) {
+    if (read_size == -1) {
+      break;
+    }
+    total_read += read_size;
+    free_space -= read_size;
+    if (free_space <= 1) {
+      // new_size = size * 1.5.
+      intptr_t new_size = (total_read << 1) - (total_read >> 1);
+      buf = reinterpret_cast<char*>(realloc(buf, new_size));
+      free_space = new_size - total_read;
+    }
+  }
+  buf[total_read] = '\0';
+  close(fd);
+  *buffer = buf;
+  return total_read;
+}
+
+
+// Runs test 'test_name' and gives stdout and stderr for the test in
+// 'test_stdout' and 'test_stderr'. Returns the exit code from the test.
+static int run_test(mx_handle_t binary_vmo, const char* test_name,
+                    char** test_stdout, char** test_stderr) {
+  int stdout_pipe = -1;
+  int stderr_pipe = -1;
+  mx_handle_t p = start_test(binary_vmo, test_name, &stdout_pipe, &stderr_pipe);
+  RETURN_IF_ERROR(p);
+
+  drain_fd(stdout_pipe, test_stdout);
+  drain_fd(stderr_pipe, test_stderr);
 
   mx_signals_state_t state;
   mx_status_t r = mx_handle_wait_one(
       p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state);
-  if (r != NO_ERROR) {
-    fprintf(stderr, "[process(%x): wait failed? %d]\n", p, r);
-    return -1;
-  }
+  RETURN_IF_ERROR(r);
 
   mx_process_info_t proc_info;
-  mx_ssize_t ret = mx_handle_get_info(
+  mx_ssize_t info_size = mx_handle_get_info(
       p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info));
-  if (ret != sizeof(proc_info)) {
-    fprintf(stderr, "[process(%x): handle_get_info failed? %ld]\n", p, ret);
-    return -1;
-  }
+  RETURN_IF_ERROR(info_size);
 
-  mx_handle_close(p);
+  r = mx_handle_close(p);
+  RETURN_IF_ERROR(r);
   return proc_info.return_code;
 }
 
 
-static void handle_result(intptr_t result, const char* test) {
+static void handle_result(
+    intptr_t result, char* test_stdout, char* test_stderr, const char* test) {
   if (result != 0) {
     if (!isExpectFail(test) && !isBug(test)) {
-      printf("******** Test %s FAILED\n", test);
+      printf("**** Test %s FAILED\n\nstdout:\n%s\nstderr:\n%s\n",
+          test, test_stdout, test_stderr);
+    } else {
+      printf("Test %s FAILED and is expected to fail\n", test);
     }
   } else {
     if (isExpectFail(test)) {
-      printf("******** Test %s is expected to fail, but PASSED\n", test);
-    }
-    if (isBug(test)) {
-      printf("******** Test %s is marked as a bug, but PASSED\n", test);
+      printf("**** Test %s is expected to fail, but PASSED\n\n"
+             "stdout:\n%s\nstderr:\n%s\n",
+             test, test_stdout, test_stderr);
+    } else if (isBug(test)) {
+      printf("**** Test %s is marked as a bug, but PASSED\n", test);
+    } else {
+      printf("Test %s PASSED\n", test);
     }
   }
 }
@@ -203,6 +306,7 @@
   char** test_list;
   intptr_t test_list_length;
   intptr_t* test_list_index;
+  mx_handle_t binary_vmo;
 } runner_args_t;
 
 
@@ -210,12 +314,20 @@
   runner_args_t* args = reinterpret_cast<runner_args_t*>(arg);
 
   pthread_mutex_lock(args->test_list_lock);
+  mx_handle_t binary_vmo = args->binary_vmo;
   while (*args->test_list_index < args->test_list_length) {
     const intptr_t index = *args->test_list_index;
     *args->test_list_index = index + 1;
     pthread_mutex_unlock(args->test_list_lock);
+
     const char* test = args->test_list[index];
-    handle_result(run_test(test), test);
+    char* test_stdout = NULL;
+    char* test_stderr = NULL;
+    mx_handle_t vmo_dup = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
+    int test_status = run_test(vmo_dup, test, &test_stdout, &test_stderr);
+    handle_result(test_status, test_stdout, test_stderr, test);
+    free(test_stdout);
+    free(test_stderr);
     pthread_mutex_lock(args->test_list_lock);
   }
   pthread_mutex_unlock(args->test_list_lock);
@@ -224,11 +336,17 @@
 }
 
 
-static void trim(char* line) {
-  const intptr_t line_len = strlen(line);
-  if (line[line_len - 1] == '\n') {
-    line[line_len - 1] = '\0';
+static void run_all_tests(runner_args_t* args) {
+  const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
+  pthread_t* threads =
+    reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t)));
+  for (int i = 0; i < num_cpus; i++) {
+    pthread_create(&threads[i], NULL, test_runner_thread, args);
   }
+  for (int i = 0; i < num_cpus; i++) {
+    pthread_join(threads[i], NULL);
+  }
+  free(threads);
 }
 
 
@@ -237,64 +355,63 @@
 }
 
 
-static intptr_t count_lines(FILE* fp) {
-  intptr_t lines = 0;
-
-  // Make sure we're at the beginning of the file.
-  rewind(fp);
-
-  intptr_t ch;
-  while ((ch = fgetc(fp)) != EOF) {
-    if (ch == '\n') {
-      lines++;
+static char** parse_test_list(char* list_output, intptr_t* length) {
+  const intptr_t list_output_length = strlen(list_output);
+  intptr_t test_count = 0;
+  for (int i = 0; i < list_output_length; i++) {
+    if (list_output[i] == '\n') {
+      test_count++;
     }
   }
-
-  rewind(fp);
-  return lines;
-}
-
-
-static intptr_t read_lines(FILE* fp, char** lines, intptr_t lines_length) {
-  char* test = NULL;
-  size_t len = 0;
-  ssize_t read;
-  intptr_t i = 0;
-  while (((read = getline(&test, &len, fp)) != -1) && (i < lines_length)) {
-    trim(test);
-    if (!should_run(test)) {
-      continue;
+  char** test_list;
+  test_list = reinterpret_cast<char**>(malloc(test_count * sizeof(*test_list)));
+  char* test = list_output;
+  char* strtok_context;
+  intptr_t idx = 0;
+  while ((test = strtok_r(test, "\n", &strtok_context)) != NULL) {
+    if (should_run(test)) {
+      test_list[idx] = strdup(test);
+      idx++;
     }
-    lines[i] = strdup(test);
-    i++;
+    test = NULL;
   }
 
-  if (test != NULL) {
-    free(test);
-  }
-  return i;
+  *length = idx;
+  return test_list;
 }
 
 
 int main(int argc, char** argv) {
-  if (argc <= 1) {
-    fprintf(stderr, "Pass the path to a file containing the list of tests\n");
-    return -1;
-  }
-  const char* tests_path = argv[1];
+  // TODO(zra): Read test binary path from the command line.
 
-  FILE* fp = fopen(tests_path, "r");
-  if (fp == NULL) {
-    fprintf(stderr, "Failed to read the file: %s\n", tests_path);
-    return -1;
+  // Load in the binary.
+  mx_handle_t binary_vmo = launchpad_vmo_from_file(kRunVmTestsPath);
+  RETURN_IF_ERROR(binary_vmo);
+
+  // Run with --list to grab the list of tests.
+  char* list_stdout = NULL;
+  char* list_stderr = NULL;
+  mx_handle_t list_vmo = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
+  RETURN_IF_ERROR(list_vmo);
+  int list_result = run_test(list_vmo, "--list", &list_stdout, &list_stderr);
+  if (list_result != 0) {
+    fprintf(stderr, "Failed to list tests: %s\n%s\n", list_stdout, list_stderr);
+    fflush(0);
+    free(list_stdout);
+    free(list_stderr);
+    return list_result;
   }
 
-  intptr_t lines_count = count_lines(fp);
-  char** test_list =
-      reinterpret_cast<char**>(malloc(sizeof(*test_list) * lines_count));
-  lines_count = read_lines(fp, test_list, lines_count);
-  fclose(fp);
+  // Parse the test list into an array of C strings.
+  intptr_t lines_count;
+  char** test_list = parse_test_list(list_stdout, &lines_count);
+  free(list_stdout);
+  free(list_stderr);
 
+  fprintf(stdout, "Found %ld tests\n", lines_count);
+  fflush(0);
+
+  // Run the tests across a number of threads equal to the number of cores.
   pthread_mutex_t args_mutex;
   pthread_mutex_init(&args_mutex, NULL);
   intptr_t test_list_index = 0;
@@ -303,29 +420,23 @@
   args.test_list = test_list;
   args.test_list_length = lines_count;
   args.test_list_index = &test_list_index;
+  args.binary_vmo = binary_vmo;
+  run_all_tests(&args);
 
-  const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
-  pthread_t* threads =
-    reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t)));
-  for (int i = 0; i < num_cpus; i++) {
-    pthread_create(&threads[i], NULL, test_runner_thread, &args);
-  }
-
-  for (int i = 0; i < num_cpus; i++) {
-    pthread_join(threads[i], NULL);
-  }
-
-  free(threads);
+  // Cleanup.
   for (int i = 0; i < lines_count; i++) {
     free(test_list[i]);
   }
   free(test_list);
   pthread_mutex_destroy(&args_mutex);
+  mx_status_t status = mx_handle_close(binary_vmo);
+  RETURN_IF_ERROR(status);
 
+  // Complain if we didn't try to run all of the tests.
   if (test_list_index != lines_count) {
     fprintf(stderr, "Failed to attempt all the tests!\n");
+    fflush(0);
     return -1;
   }
-
   return 0;
 }
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 4075e8d..43186d1 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -51,7 +51,14 @@
       return;
     }
     try {
-      socket.add(result);
+      if (result is String || result is Uint8List) {
+        socket.add(result);  // String or binary message.
+      } else {
+        // String message as external Uint8List.
+        assert(result is List);
+        Uint8List cstring = result[0];
+        socket.addUtf8Text(cstring);
+      }
     } catch (_) {
       print("Ignoring error posting over WebSocket.");
     }
@@ -79,14 +86,21 @@
     close();
   }
 
-  void post(String result) {
+  void post(dynamic result) {
     if (result == null) {
       close();
       return;
     }
-    request.response..headers.contentType = jsonContentType
-                    ..write(result)
-                    ..close();
+    HttpResponse response = request.response;
+    response.headers.contentType = jsonContentType;
+    if (result is String) {
+      response.write(result);
+    } else {
+      assert(result is List);
+      Uint8List cstring = result[0];  // Already in UTF-8.
+      response.add(cstring);
+    }
+    response.close();
     close();
   }
 
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 49e8ad7..7ae65d4 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -9,6 +9,7 @@
 import 'dart:convert';
 import 'dart:io';
 import 'dart:isolate';
+import 'dart:typed_data';
 import 'dart:_vmservice';
 
 part 'loader.dart';
diff --git a/runtime/lib/compact_hash.dart b/runtime/lib/compact_hash.dart
index 1c2de88..9912d07 100644
--- a/runtime/lib/compact_hash.dart
+++ b/runtime/lib/compact_hash.dart
@@ -123,7 +123,13 @@
     with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase,
          _OperatorEqualsAndHashCode
     implements LinkedHashMap<K, V> {
-  factory _InternalLinkedHashMap() native "LinkedHashMap_allocate";
+  _InternalLinkedHashMap() {
+    _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE);
+    _hashMask = _HashBase._indexSizeToHashMask(_HashBase._INITIAL_INDEX_SIZE);
+    _data = new List(_HashBase._INITIAL_INDEX_SIZE);
+    _usedData = 0;
+    _deletedKeys = 0;
+  }
 }
 
 class _LinkedHashMapMixin<K, V> {  
diff --git a/runtime/lib/core_sources.gypi b/runtime/lib/core_sources.gypi
index dd00af4..5851797 100644
--- a/runtime/lib/core_sources.gypi
+++ b/runtime/lib/core_sources.gypi
@@ -42,7 +42,6 @@
     'object_patch.dart',
     'regexp.cc',
     'regexp_patch.dart',
-    'resource_patch.dart',
     'stacktrace.cc',
     'stacktrace.dart',
     'stacktrace.h',
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 89ade45..77251fe 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -35,6 +35,12 @@
     }
   }
 
+  static void _checkConstAssertion(bool condition, int start, int end) {
+    if (!condition) {
+      _throwNew(start, end);
+    }
+  }
+
   String toString() {
     if (_url == null) {
       return _failedAssertion;
diff --git a/runtime/lib/linked_hash_map.cc b/runtime/lib/linked_hash_map.cc
index 9511841..bc128c7 100644
--- a/runtime/lib/linked_hash_map.cc
+++ b/runtime/lib/linked_hash_map.cc
@@ -13,16 +13,6 @@
 
 namespace dart {
 
-DEFINE_NATIVE_ENTRY(LinkedHashMap_allocate, 1) {
-  const TypeArguments& type_arguments =
-      TypeArguments::CheckedHandle(arguments->NativeArgAt(0));
-  const LinkedHashMap& map =
-    LinkedHashMap::Handle(LinkedHashMap::NewDefault());
-  map.SetTypeArguments(type_arguments);
-  return map.raw();
-}
-
-
 DEFINE_NATIVE_ENTRY(LinkedHashMap_getIndex, 1) {
   const LinkedHashMap& map =
       LinkedHashMap::CheckedHandle(arguments->NativeArgAt(0));
diff --git a/runtime/lib/resource_patch.dart b/runtime/lib/resource_patch.dart
deleted file mode 100644
index 76a7a9c..0000000
--- a/runtime/lib/resource_patch.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-@patch class Resource {
-  @patch const factory Resource(String uri) = _Resource;
-}
-
-class _Resource implements Resource {
-  final String _location;
-
-  const _Resource(this._location);
-
-  Uri get uri => Uri.base.resolve(_location);
-
-  Stream<List<int>> openRead() {
-    if (VMLibraryHooks.resourceReadAsBytes == null) {
-      throw new UnimplementedError("openRead");
-    }
-
-    var controller = new StreamController<List<int>>();
-    // We only need to implement the listener as there is no way to provide
-    // back pressure into the channel.
-    controller.onListen = () {
-      // Once there is a listener, we kick off the loading of the resource.
-      readAsBytes().then((value) {
-        // The resource loading implementation sends all of the data in a
-        // single message. So the stream will only get a single value posted.
-        controller.add(value);
-        controller.close();
-      },
-      onError: (e, s) {
-        // In case the future terminates with an error we propagate it to the
-        // stream.
-        controller.addError(e, s);
-        controller.close();
-      });
-    };
-
-    return controller.stream;
-  }
-
-  Future<List<int>> readAsBytes() {
-    if (VMLibraryHooks.resourceReadAsBytes == null) {
-      throw new UnimplementedError("readAsBytes");
-    }
-
-    return VMLibraryHooks.resourceReadAsBytes(this.uri);
-  }
-
-  Future<String> readAsString({Encoding encoding : UTF8}) {
-    if (VMLibraryHooks.resourceReadAsBytes == null) {
-      throw new UnimplementedError("readAsString");
-    }
-
-    var completer = new Completer<String>();
-
-    readAsBytes().then((bytes) {
-      var str = encoding.decode(bytes);
-      completer.complete(str);
-    },
-    onError: (e, s) {
-      completer.completeError(e,s);
-    });
-
-    return completer.future;
-  }
-}
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 8d39988..4130e60 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -41,13 +41,6 @@
 }
 
 
-static void PeerFinalizer(void* isolate_callback_data,
-                          Dart_WeakPersistentHandle handle,
-                          void* peer) {
-  OS::AlignedFree(peer);
-}
-
-
 DEFINE_NATIVE_ENTRY(TypedData_length, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
   if (instance.IsTypedData()) {
@@ -175,31 +168,8 @@
 }                                                                              \
 
 
-// We check the length parameter against a possible maximum length for the
-// array based on available physical addressable memory on the system. The
-// maximum possible length is a scaled value of kSmiMax which is set up based
-// on whether the underlying architecture is 32-bit or 64-bit.
-// Argument 0 is type arguments and is ignored.
-#define EXT_TYPED_DATA_NEW(name)                                               \
-DEFINE_NATIVE_ENTRY(ExternalTypedData_##name##_new, 2) {                       \
-  const int kAlignment = 16;                                                   \
-  GET_NON_NULL_NATIVE_ARGUMENT(Smi, length, arguments->NativeArgAt(1));        \
-  intptr_t cid = kExternalTypedData##name##Cid;                                \
-  intptr_t len = length.Value();                                               \
-  intptr_t max = ExternalTypedData::MaxElements(cid);                          \
-  LengthCheck(len, max);                                                       \
-  intptr_t len_bytes = len * ExternalTypedData::ElementSizeInBytes(cid);       \
-  uint8_t* data = OS::AllocateAlignedArray<uint8_t>(len_bytes, kAlignment);    \
-  const ExternalTypedData& obj =                                               \
-      ExternalTypedData::Handle(ExternalTypedData::New(cid, data, len));       \
-  obj.AddFinalizer(data, PeerFinalizer);                                       \
-  return obj.raw();                                                            \
-}                                                                              \
-
-
 #define TYPED_DATA_NEW_NATIVE(name)                                            \
   TYPED_DATA_NEW(name)                                                         \
-  EXT_TYPED_DATA_NEW(name)                                                     \
 
 
 CLASS_LIST_TYPED_DATA(TYPED_DATA_NEW_NATIVE)
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index f37cacb..d8b4324 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -1873,10 +1873,6 @@
 
 
 class _ExternalInt8Array extends _TypedList with _IntListMixin implements Int8List {
-  // Factory constructors.
-
-  factory _ExternalInt8Array(int length) native "ExternalTypedData_Int8Array_new";
-
   // Method(s) implementing the List interface.
   int operator[](int index) {
     if (index < 0 || index >= length) {
@@ -1909,10 +1905,6 @@
 
 
 class _ExternalUint8Array extends _TypedList with _IntListMixin implements Uint8List {
-  // Factory constructors.
-
-  factory _ExternalUint8Array(int length) native "ExternalTypedData_Uint8Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -1946,10 +1938,6 @@
 
 
 class _ExternalUint8ClampedArray extends _TypedList with _IntListMixin implements Uint8ClampedList {
-  // Factory constructors.
-
-  factory _ExternalUint8ClampedArray(int length) native "ExternalTypedData_Uint8ClampedArray_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -1983,10 +1971,6 @@
 
 
 class _ExternalInt16Array extends _TypedList with _IntListMixin implements Int16List {
-  // Factory constructors.
-
-  factory _ExternalInt16Array(int length) native "ExternalTypedData_Int16Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2028,10 +2012,6 @@
 
 
 class _ExternalUint16Array extends _TypedList with _IntListMixin implements Uint16List {
-  // Factory constructors.
-
-  factory _ExternalUint16Array(int length) native "ExternalTypedData_Uint16Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2073,10 +2053,6 @@
 
 
 class _ExternalInt32Array extends _TypedList with _IntListMixin implements Int32List {
-  // Factory constructors.
-
-  factory _ExternalInt32Array(int length) native "ExternalTypedData_Int32Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2118,10 +2094,6 @@
 
 
 class _ExternalUint32Array extends _TypedList with _IntListMixin implements Uint32List {
-  // Factory constructors.
-
-  factory _ExternalUint32Array(int length) native "ExternalTypedData_Uint32Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2163,10 +2135,6 @@
 
 
 class _ExternalInt64Array extends _TypedList with _IntListMixin implements Int64List {
-  // Factory constructors.
-
-  factory _ExternalInt64Array(int length) native "ExternalTypedData_Int64Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2208,10 +2176,6 @@
 
 
 class _ExternalUint64Array extends _TypedList with _IntListMixin implements Uint64List {
-  // Factory constructors.
-
-  factory _ExternalUint64Array(int length) native "ExternalTypedData_Uint64Array_new";
-
   // Method(s) implementing the List interface.
 
   int operator[](int index) {
@@ -2253,10 +2217,6 @@
 
 
 class _ExternalFloat32Array extends _TypedList with _DoubleListMixin implements Float32List {
-  // Factory constructors.
-
-  factory _ExternalFloat32Array(int length) native "ExternalTypedData_Float32Array_new";
-
   // Method(s) implementing the List interface.
 
   double operator[](int index) {
@@ -2298,10 +2258,6 @@
 
 
 class _ExternalFloat64Array extends _TypedList with _DoubleListMixin implements Float64List {
-  // Factory constructors.
-
-  factory _ExternalFloat64Array(int length) native "ExternalTypedData_Float64Array_new";
-
   // Method(s) implementing the List interface.
 
   double operator[](int index) {
@@ -2343,10 +2299,6 @@
 
 
 class _ExternalFloat32x4Array extends _TypedList with _Float32x4ListMixin implements Float32x4List {
-  // Factory constructors.
-
-  factory _ExternalFloat32x4Array(int length) native "ExternalTypedData_Float32x4Array_new";
-
   // Method(s) implementing the List interface.
 
   Float32x4 operator[](int index) {
@@ -2388,10 +2340,6 @@
 
 
 class _ExternalInt32x4Array extends _TypedList with _Int32x4ListMixin implements Int32x4List {
-  // Factory constructors.
-
-  factory _ExternalInt32x4Array(int length) native "ExternalTypedData_Int32x4Array_new";
-
   // Method(s) implementing the List interface.
 
   Int32x4 operator[](int index) {
@@ -2433,10 +2381,6 @@
 
 
 class _ExternalFloat64x2Array extends _TypedList with _Float64x2ListMixin implements Float64x2List {
-  // Factory constructors.
-
-  factory _ExternalFloat64x2Array(int length) native "ExternalTypedData_Float64x2Array_new";
-
   // Method(s) implementing the List interface.
 
   Float64x2 operator[](int index) {
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index 05f13ab..efd2cb0 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -5,8 +5,6 @@
 export 'package:observatory/src/elements/class_ref_as_value.dart';
 export 'package:observatory/src/elements/class_view.dart';
 export 'package:observatory/src/elements/code_view.dart';
-export 'package:observatory/src/elements/context_view.dart';
-export 'package:observatory/src/elements/cpu_profile_table.dart';
 export 'package:observatory/src/elements/debugger.dart';
 export 'package:observatory/src/elements/error_view.dart';
 export 'package:observatory/src/elements/eval_box.dart';
@@ -14,8 +12,6 @@
 export 'package:observatory/src/elements/field_view.dart';
 export 'package:observatory/src/elements/function_view.dart';
 export 'package:observatory/src/elements/heap_map.dart';
-export 'package:observatory/src/elements/heap_snapshot.dart';
-export 'package:observatory/src/elements/icdata_view.dart';
 export 'package:observatory/src/elements/instance_view.dart';
 export 'package:observatory/src/elements/isolate_reconnect.dart';
 export 'package:observatory/src/elements/isolate_summary.dart';
@@ -26,13 +22,11 @@
 export 'package:observatory/src/elements/logging.dart';
 export 'package:observatory/src/elements/megamorphiccache_view.dart';
 export 'package:observatory/src/elements/metrics.dart';
-export 'package:observatory/src/elements/object_common.dart';
 export 'package:observatory/src/elements/object_view.dart';
 export 'package:observatory/src/elements/objectpool_view.dart';
 export 'package:observatory/src/elements/objectstore_view.dart';
 export 'package:observatory/src/elements/observatory_element.dart';
 export 'package:observatory/src/elements/persistent_handles.dart';
-export 'package:observatory/src/elements/ports.dart';
 export 'package:observatory/src/elements/script_inset.dart';
 export 'package:observatory/src/elements/script_view.dart';
 export 'package:observatory/src/elements/service_ref.dart';
@@ -51,10 +45,12 @@
 import 'package:observatory/src/elements/code_ref_wrapper.dart';
 import 'package:observatory/src/elements/context_ref.dart';
 import 'package:observatory/src/elements/context_ref_wrapper.dart';
+import 'package:observatory/src/elements/context_view.dart';
 import 'package:observatory/src/elements/containers/virtual_collection.dart';
 import 'package:observatory/src/elements/containers/virtual_tree.dart';
 import 'package:observatory/src/elements/cpu_profile.dart';
 import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+import 'package:observatory/src/elements/cpu_profile_table.dart';
 import 'package:observatory/src/elements/curly_block.dart';
 import 'package:observatory/src/elements/curly_block_wrapper.dart';
 import 'package:observatory/src/elements/error_ref.dart';
@@ -65,7 +61,9 @@
 import 'package:observatory/src/elements/function_ref.dart';
 import 'package:observatory/src/elements/function_ref_wrapper.dart';
 import 'package:observatory/src/elements/general_error.dart';
+import 'package:observatory/src/elements/heap_snapshot.dart';
 import 'package:observatory/src/elements/icdata_ref.dart';
+import 'package:observatory/src/elements/icdata_view.dart';
 import 'package:observatory/src/elements/instance_ref.dart';
 import 'package:observatory/src/elements/instance_ref_wrapper.dart';
 import 'package:observatory/src/elements/isolate_reconnect.dart';
@@ -99,9 +97,12 @@
 import 'package:observatory/src/elements/nav/top_menu_wrapper.dart';
 import 'package:observatory/src/elements/nav/vm_menu.dart';
 import 'package:observatory/src/elements/nav/vm_menu_wrapper.dart';
-import 'package:observatory/src/elements/observatory_application.dart';
 import 'package:observatory/src/elements/objectpool_ref.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import 'package:observatory/src/elements/object_common_wrapper.dart';
+import 'package:observatory/src/elements/observatory_application.dart';
 import 'package:observatory/src/elements/pc_descriptors_ref.dart';
+import 'package:observatory/src/elements/ports.dart';
 import 'package:observatory/src/elements/sample_buffer_control.dart';
 import 'package:observatory/src/elements/script_ref.dart';
 import 'package:observatory/src/elements/script_ref_wrapper.dart';
@@ -124,15 +125,19 @@
 export 'package:observatory/src/elements/containers/virtual_collection.dart';
 export 'package:observatory/src/elements/containers/virtual_tree.dart';
 export 'package:observatory/src/elements/context_ref.dart';
+export 'package:observatory/src/elements/context_view.dart';
 export 'package:observatory/src/elements/cpu_profile.dart';
 export 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+export 'package:observatory/src/elements/cpu_profile_table.dart';
 export 'package:observatory/src/elements/curly_block.dart';
 export 'package:observatory/src/elements/error_ref.dart';
 export 'package:observatory/src/elements/field_ref.dart';
 export 'package:observatory/src/elements/flag_list.dart';
 export 'package:observatory/src/elements/function_ref.dart';
 export 'package:observatory/src/elements/general_error.dart';
+export 'package:observatory/src/elements/heap_snapshot.dart';
 export 'package:observatory/src/elements/icdata_ref.dart';
+export 'package:observatory/src/elements/icdata_view.dart';
 export 'package:observatory/src/elements/instance_ref.dart';
 export 'package:observatory/src/elements/isolate_reconnect.dart';
 export 'package:observatory/src/elements/isolate_ref.dart';
@@ -153,9 +158,11 @@
 export 'package:observatory/src/elements/nav/refresh.dart';
 export 'package:observatory/src/elements/nav/top_menu.dart';
 export 'package:observatory/src/elements/nav/vm_menu.dart';
-export 'package:observatory/src/elements/observatory_application.dart';
 export 'package:observatory/src/elements/objectpool_ref.dart';
+export 'package:observatory/src/elements/object_common.dart';
+export 'package:observatory/src/elements/observatory_application.dart';
 export 'package:observatory/src/elements/pc_descriptors_ref.dart';
+export 'package:observatory/src/elements/ports.dart';
 export 'package:observatory/src/elements/sample_buffer_control.dart';
 export 'package:observatory/src/elements/script_ref.dart';
 export 'package:observatory/src/elements/sentinel_value.dart';
@@ -178,7 +185,9 @@
   CodeRefElementWrapper.tag.ensureRegistration();
   ContextRefElement.tag.ensureRegistration();
   ContextRefElementWrapper.tag.ensureRegistration();
+  ContextViewElement.tag.ensureRegistration();
   CpuProfileElement.tag.ensureRegistration();
+  CpuProfileTableElement.tag.ensureRegistration();
   CpuProfileVirtualTreeElement.tag.ensureRegistration();
   CurlyBlockElement.tag.ensureRegistration();
   CurlyBlockElementWrapper.tag.ensureRegistration();
@@ -190,7 +199,9 @@
   FunctionRefElement.tag.ensureRegistration();
   FunctionRefElementWrapper.tag.ensureRegistration();
   GeneralErrorElement.tag.ensureRegistration();
+  HeapSnapshotElement.tag.ensureRegistration();
   ICDataRefElement.tag.ensureRegistration();
+  ICDataViewElement.tag.ensureRegistration();
   InstanceRefElement.tag.ensureRegistration();
   InstanceRefElementWrapper.tag.ensureRegistration();
   IsolateCounterChartElement.tag.ensureRegistration();
@@ -224,9 +235,12 @@
   NavTopMenuElementWrapper.tag.ensureRegistration();
   NavVMMenuElement.tag.ensureRegistration();
   NavVMMenuElementWrapper.tag.ensureRegistration();
-  ObservatoryApplicationElement.tag.ensureRegistration();
+  ObjectCommonElement.tag.ensureRegistration();
+  ObjectCommonElementWrapper.tag.ensureRegistration();
   ObjectPoolRefElement.tag.ensureRegistration();
+  ObservatoryApplicationElement.tag.ensureRegistration();
   PcDescriptorsRefElement.tag.ensureRegistration();
+  PortsElement.tag.ensureRegistration();
   ScriptRefElement.tag.ensureRegistration();
   SampleBufferControlElement.tag.ensureRegistration();
   ScriptRefElement.tag.ensureRegistration();
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index b022a12..2fcf818 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -2,7 +2,6 @@
 <link rel="import" href="src/elements/class_ref_as_value.html">
 <link rel="import" href="src/elements/class_view.html">
 <link rel="import" href="src/elements/code_view.html">
-<link rel="import" href="src/elements/cpu_profile_table.html">
 <link rel="import" href="src/elements/debugger.html">
 <link rel="import" href="src/elements/error_view.html">
 <link rel="import" href="src/elements/eval_box.html">
@@ -11,7 +10,6 @@
 <link rel="import" href="src/elements/function_view.html">
 <link rel="import" href="src/elements/heap_map.html">
 <link rel="import" href="src/elements/instance_view.html">
-<link rel="import" href="src/elements/icdata_view.html">
 <link rel="import" href="src/elements/isolate_summary.html">
 <link rel="import" href="src/elements/isolate_view.html">
 <link rel="import" href="src/elements/json_view.html">
@@ -20,12 +18,10 @@
 <link rel="import" href="src/elements/logging.html">
 <link rel="import" href="src/elements/megamorphiccache_view.html">
 <link rel="import" href="src/elements/metrics.html">
-<link rel="import" href="src/elements/object_common.html">
 <link rel="import" href="src/elements/object_view.html">
 <link rel="import" href="src/elements/objectpool_view.html">
 <link rel="import" href="src/elements/objectstore_view.html">
 <link rel="import" href="src/elements/persistent_handles.html">
-<link rel="import" href="src/elements/ports.html">
 <link rel="import" href="src/elements/script_inset.html">
 <link rel="import" href="src/elements/script_view.html">
 <link rel="import" href="src/elements/service_ref.html">
diff --git a/runtime/observatory/lib/heap_snapshot.dart b/runtime/observatory/lib/heap_snapshot.dart
new file mode 100644
index 0000000..84bc390
--- /dev/null
+++ b/runtime/observatory/lib/heap_snapshot.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library heap_snapshot;
+
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/object_graph.dart';
+import 'package:observatory/service.dart' as S;
+
+part 'src/heap_snapshot/heap_snapshot.dart';
diff --git a/runtime/observatory/lib/models.dart b/runtime/observatory/lib/models.dart
index 2a48dd9..01178ad 100644
--- a/runtime/observatory/lib/models.dart
+++ b/runtime/observatory/lib/models.dart
@@ -23,7 +23,9 @@
 part 'src/models/objects/function.dart';
 part 'src/models/objects/guarded.dart';
 part 'src/models/objects/heap_space.dart';
+part 'src/models/objects/heap_snapshot.dart';
 part 'src/models/objects/icdata.dart';
+part 'src/models/objects/inbound_references.dart';
 part 'src/models/objects/instance.dart';
 part 'src/models/objects/isolate.dart';
 part 'src/models/objects/library.dart';
@@ -34,6 +36,8 @@
 part 'src/models/objects/object.dart';
 part 'src/models/objects/objectpool.dart';
 part 'src/models/objects/pc_descriptors.dart';
+part 'src/models/objects/ports.dart';
+part 'src/models/objects/retaining_path.dart';
 part 'src/models/objects/sample_profile.dart';
 part 'src/models/objects/script.dart';
 part 'src/models/objects/sentinel.dart';
@@ -46,10 +50,18 @@
 
 part 'src/models/repositories/allocation_profile.dart';
 part 'src/models/repositories/class.dart';
+part 'src/models/repositories/context.dart';
 part 'src/models/repositories/event.dart';
 part 'src/models/repositories/flag.dart';
+part 'src/models/repositories/heap_snapshot.dart';
+part 'src/models/repositories/icdata.dart';
+part 'src/models/repositories/inbound_references.dart';
 part 'src/models/repositories/instance.dart';
 part 'src/models/repositories/notification.dart';
+part 'src/models/repositories/ports.dart';
+part 'src/models/repositories/reachable_size.dart';
+part 'src/models/repositories/retained_size.dart';
+part 'src/models/repositories/retaining_path.dart';
 part 'src/models/repositories/sample_profile.dart';
 part 'src/models/repositories/script.dart';
 part 'src/models/repositories/target.dart';
diff --git a/runtime/observatory/lib/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index 8b491e8..ce6ff65 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -362,41 +362,45 @@
     return result;
   }
 
-  Future process(statusReporter) async {
-    // We build futures here instead of marking the steps as async to avoid the
-    // heavy lifting being inside a transformed method.
+  Stream<List> process() {
+    final controller = new StreamController<List>.broadcast();
+    (() async {
+      // We build futures here instead of marking the steps as async to avoid the
+      // heavy lifting being inside a transformed method.
 
-    statusReporter.add("Remapping $_N objects...");
-    await new Future(() => _remapNodes());
+      controller.add(["Remapping $_N objects...", 0.0]);
+      await new Future(() => _remapNodes());
 
-    statusReporter.add("Remapping $_E references...");
-    await new Future(() => _remapEdges());
+      controller.add(["Remapping $_E references...", 15.0]);
+      await new Future(() => _remapEdges());
 
-    _addrToId = null;
-    _chunks = null;
+      _addrToId = null;
+      _chunks = null;
 
-    statusReporter.add("Finding depth-first order...");
-    await new Future(() => _dfs());
+      controller.add(["Finding depth-first order...", 30.0]);
+      await new Future(() => _dfs());
 
-    statusReporter.add("Finding predecessors...");
-    await new Future(() => _buildPredecessors());
+      controller.add(["Finding predecessors...", 45.0]);
+      await new Future(() => _buildPredecessors());
 
-    statusReporter.add("Finding dominators...");
-    await new Future(() => _buildDominators());
+      controller.add(["Finding dominators...", 60.0]);
+      await new Future(() => _buildDominators());
 
-    _firstPreds = null;
-    _preds = null;
+      _firstPreds = null;
+      _preds = null;
 
-    _semi = null;
-    _parent = null;
+      _semi = null;
+      _parent = null;
 
-    statusReporter.add("Finding retained sizes...");
-    await new Future(() => _calculateRetainedSizes());
+      controller.add(["Finding retained sizes...", 75.0]);
+      await new Future(() => _calculateRetainedSizes());
 
-    _vertex = null;
+      _vertex = null;
 
-    statusReporter.add("Loaded");
-    return this;
+      controller.add(["Loaded", 100.0]);
+      controller.close();
+    }());
+    return controller.stream;
   }
 
   List<ByteData> _chunks;
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
index d566041..cf6d202 100644
--- a/runtime/observatory/lib/repositories.dart
+++ b/runtime/observatory/lib/repositories.dart
@@ -9,6 +9,7 @@
 import 'dart:html';
 import 'package:observatory/allocation_profile.dart';
 import 'package:observatory/cpu_profile.dart';
+import 'package:observatory/heap_snapshot.dart';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/service.dart' as S;
 import 'package:observatory/service_common.dart' as SC;
@@ -16,10 +17,18 @@
 
 part 'src/repositories/allocation_profile.dart';
 part 'src/repositories/class.dart';
+part 'src/repositories/context.dart';
 part 'src/repositories/event.dart';
 part 'src/repositories/flag.dart';
+part 'src/repositories/heap_snapshot.dart';
+part 'src/repositories/icdata.dart';
+part 'src/repositories/inbound_references.dart';
 part 'src/repositories/instance.dart';
 part 'src/repositories/notification.dart';
+part 'src/repositories/ports.dart';
+part 'src/repositories/reachable_size.dart';
+part 'src/repositories/retaining_path.dart';
+part 'src/repositories/retained_size.dart';
 part 'src/repositories/sample_profile.dart';
 part 'src/repositories/script.dart';
 part 'src/repositories/settings.dart';
diff --git a/runtime/observatory/lib/service.dart b/runtime/observatory/lib/service.dart
index c3775a3..787fd2a 100644
--- a/runtime/observatory/lib/service.dart
+++ b/runtime/observatory/lib/service.dart
@@ -12,7 +12,6 @@
 import 'package:logging/logging.dart';
 import 'package:observatory/cpu_profile.dart';
 import 'package:observatory/models.dart' as M;
-import 'package:observatory/object_graph.dart';
 import 'package:observatory/tracer.dart';
 import 'package:observe/observe.dart';
 
diff --git a/runtime/observatory/lib/src/app/page.dart b/runtime/observatory/lib/src/app/page.dart
index bd2fe17..bad6c88 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -6,14 +6,27 @@
 
 AllocationProfileRepository _allocationProfileRepository
     = new AllocationProfileRepository();
+ContextRepository _contextRepository = new ContextRepository();
+HeapSnapshotRepository _heapSnapshotRepository
+    = new HeapSnapshotRepository();
+ICDataRepository _icdataRepository = new ICDataRepository();
+InboundReferencesRepository _inboundReferencesRepository
+    = new InboundReferencesRepository();
+InstanceRepository _instanceRepository = new InstanceRepository();
 IsolateSampleProfileRepository _isolateSampleProfileRepository
     = new IsolateSampleProfileRepository();
+PortsRepository _portsRepository = new PortsRepository();
 
 class IsolateNotFound implements Exception {
   String isolateId;
   IsolateNotFound(this.isolateId);
   String toString() => "IsolateNotFound: $isolateId";
 }
+RetainedSizeRepository _retainedSizeRepository = new RetainedSizeRepository();
+ReachableSizeRepository _reachableSizeRepository
+    = new ReachableSizeRepository();
+RetainingPathRepository _retainingPathRepository
+    = new RetainingPathRepository();
 
 /// A [Page] controls the user interface of Observatory. At any given time
 /// one page will be the current page. Pages are registered at startup.
@@ -144,8 +157,10 @@
   }
 }
 
-class InspectPage extends SimplePage {
-  InspectPage(app) : super('inspect', 'service-view', app);
+class InspectPage extends MatchingPage {
+  InspectPage(app) : super('inspect', app);
+
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
@@ -159,10 +174,42 @@
     });
   }
 
+  void onInstall() {
+    if (element == null) {
+      element = container;
+    }
+    assert(element != null);
+  }
+
   void _visitObject(obj) {
-    if (element != null) {
-      ServiceObjectViewElement serviceElement = element;
+    if (obj is Context) {
+      container.children = [
+        new ContextViewElement(app.vm, obj.isolate, obj, app.events,
+                               app.notifications,
+                               _contextRepository,
+                               _retainedSizeRepository,
+                               _reachableSizeRepository,
+                               _inboundReferencesRepository,
+                               _retainingPathRepository,
+                               _instanceRepository,
+                               queue: app.queue)
+      ];
+    } else if (obj is ICData) {
+      container.children = [
+        new ICDataViewElement(app.vm, obj.isolate, obj, app.events,
+                               app.notifications,
+                               _icdataRepository,
+                               _retainedSizeRepository,
+                               _reachableSizeRepository,
+                               _inboundReferencesRepository,
+                               _retainingPathRepository,
+                               _instanceRepository,
+                               queue: app.queue)
+      ];
+    } else {
+      ServiceObjectViewElement serviceElement =new Element.tag('service-view');
       serviceElement.object = obj;
+      container.children = [serviceElement];
     }
   }
 }
@@ -229,7 +276,7 @@
 class CpuProfilerPage extends MatchingPage {
   CpuProfilerPage(app) : super('profiler', app);
 
-  DivElement container = new DivElement();
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
@@ -250,31 +297,34 @@
   }
 }
 
-class TableCpuProfilerPage extends SimplePage {
-  TableCpuProfilerPage(app)
-      : super('profiler-table', 'cpu-profile-table', app);
+class TableCpuProfilerPage extends MatchingPage {
+  TableCpuProfilerPage(app) : super('profiler-table', app);
+
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
     getIsolate(uri).then((isolate) {
-      if (element != null) {
-        /// Update the page.
-        CpuProfileTableElement page = element;
-        page.isolate = isolate;
-        // TODO(johnmccutchan): Provide a more general mechanism to notify
-        // elements of URI parameter changes. Possibly via a stream off of
-        // LocationManager. With a stream individual elements (not just pages)
-        // could be notified.
-        page.checkParameters();
-      }
+      container.children = [
+        new CpuProfileTableElement(isolate.vm, isolate, app.events,
+                                   app.notifications,
+                                   _isolateSampleProfileRepository)
+      ];
     });
   }
+
+  void onInstall() {
+    if (element == null) {
+      element = container;
+    }
+    assert(element != null);
+  }
 }
 
 class AllocationProfilerPage extends MatchingPage {
   AllocationProfilerPage(app) : super('allocation-profiler', app);
 
-  DivElement container = new DivElement();
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
@@ -301,19 +351,27 @@
   }
 }
 
-class PortsPage extends SimplePage {
-  PortsPage(app)
-      : super('ports', 'ports-page', app);
+class PortsPage extends MatchingPage {
+  PortsPage(app) : super('ports', app);
+
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
     getIsolate(uri).then((isolate) {
-      if (element != null) {
-        PortsPageElement page = element;
-        page.isolate = isolate;
-      }
+      container.children = [
+        new PortsElement(isolate.vm, isolate, app.events, app.notifications,
+                         _portsRepository, _instanceRepository,
+                         queue: app.queue)
+      ];
     });
   }
+
+  void onInstall() {
+    if (element == null) {
+      element = container;
+    }
+  }
 }
 
 class PersistentHandlesPage extends SimplePage {
@@ -346,19 +404,27 @@
   }
 }
 
-class HeapSnapshotPage extends SimplePage {
-  HeapSnapshotPage(app) : super('heap-snapshot', 'heap-snapshot', app);
+class HeapSnapshotPage extends MatchingPage {
+  HeapSnapshotPage(app) : super('heap-snapshot', app);
+
+  final DivElement container = new DivElement();
 
   void _visit(Uri uri) {
     super._visit(uri);
     getIsolate(uri).then((isolate) {
-      if (element != null) {
-        /// Update the page.
-        HeapSnapshotElement page = element;
-        page.isolate = isolate;
-      }
+      container.children = [
+        new HeapSnapshotElement(isolate.vm, isolate, app.events,
+                                app.notifications, _heapSnapshotRepository,
+                                _instanceRepository, queue: app.queue)
+      ];
     });
   }
+
+  void onInstall() {
+    if (element == null) {
+      element = container;
+    }
+  }
 }
 
 
@@ -422,7 +488,7 @@
 class IsolateReconnectPage extends Page {
   IsolateReconnectPage(app) : super(app);
 
-  DivElement container = new DivElement();
+  final DivElement container = new DivElement();
 
   void onInstall() {
     element = container;
diff --git a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
index f96f5db..9cb7ebd 100644
--- a/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
+++ b/runtime/observatory/lib/src/cpu_profile/cpu_profile.dart
@@ -104,7 +104,7 @@
   int _totalCodeTicks = 0;
   int get totalCodesTicks => _totalCodeTicks;
 
-  String get name => profileFunction.function.name;
+  String get name => M.getFunctionFullName(profileFunction.function);
   Object get profileData => profileFunction;
 
   FunctionCallTreeNode(this.profileFunction, int count)
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index b101fbf..d883fb2 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -9,6 +9,7 @@
 import 'sample_buffer_control.dart';
 import 'stack_trace_tree_config.dart';
 import 'cpu_profile/virtual_tree.dart';
+import 'package:observatory/heap_snapshot.dart';
 import 'package:observatory/elements.dart';
 import 'package:observatory/models.dart' as M;
 import 'package:observatory/service.dart';
@@ -40,14 +41,14 @@
     });
   }
 
-  Future<ServiceObject> retainedToplist(var limit) {
-    return cls.isolate.fetchHeapSnapshot(true).last
-      .then((HeapSnapshot snapshot) =>
-          Future.wait(snapshot.getMostRetained(classId: cls.vmCid,
-                                               limit: 10)))
-      .then((List<ServiceObject> most) {
-        mostRetained = new ObservableList.from(most);
-      });
+  Future retainedToplist(var limit) async {
+      final raw = await cls.isolate.fetchHeapSnapshot(true).last;
+      final snapshot = new HeapSnapshot();
+      await snapshot.loadProgress(cls.isolate, raw).last;
+      final most = await Future.wait(snapshot.getMostRetained(cls.isolate,
+                                                              classId: cls.vmCid,
+                                                              limit: 10));
+      mostRetained = new ObservableList.from(most);
   }
 
   // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
diff --git a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
index b6f91b9..d0973e2 100644
--- a/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
+++ b/runtime/observatory/lib/src/elements/containers/virtual_collection.dart
@@ -24,6 +24,7 @@
   VirtualCollectionCreateCallback _createHeader;
   VirtualCollectionUpdateCallback _update;
   double _itemHeight;
+  double _headerHeight = 0.0;
   int _top;
   double _height;
   List _items;
@@ -106,6 +107,13 @@
   /// tail = l / _preload = L * 1 / (_preload + 2) = L * _inverse_preload
   static const double _inverse_preload = 1 / (_preload + 2);
 
+  var _takeIntoView;
+
+  void takeIntoView(item) {
+    _takeIntoView = item;
+    _r.dirty();
+  }
+
   void render() {
     if (children.isEmpty) {
       children = [
@@ -118,14 +126,26 @@
       if (_createHeader != null) {
         _header.children = [_createHeader()];
         _scroller.children.insert(0, _header);
+        _headerHeight = _header.children[0].getBoundingClientRect().height;
       }
       _itemHeight = _shifter.children[0].getBoundingClientRect().height;
       _height = getBoundingClientRect().height;
     }
+
+    if (_takeIntoView != null) {
+      final index = items.indexOf(_takeIntoView);
+      if (index >= 0) {
+        final minScrollTop = _itemHeight * (index + 1) - _height;
+        final maxScrollTop = _itemHeight * index;
+        scrollTop = ((maxScrollTop - minScrollTop) / 2 + minScrollTop).floor();
+      }
+      _takeIntoView = null;
+    }
+
     final top = (scrollTop / _itemHeight).floor();
 
     _header.style.top = '${scrollTop}px';
-    _scroller.style.height = '${_itemHeight*(_items.length)}px';
+    _scroller.style.height = '${_itemHeight*(_items.length)+_headerHeight}px';
     final tail_length = (_height / _itemHeight / _preload).ceil();
     final length = tail_length * 2 + tail_length * _preload;
 
diff --git a/runtime/observatory/lib/src/elements/context_view.dart b/runtime/observatory/lib/src/elements/context_view.dart
index fd990dc..98dcc20 100644
--- a/runtime/observatory/lib/src/elements/context_view.dart
+++ b/runtime/observatory/lib/src/elements/context_view.dart
@@ -2,20 +2,191 @@
 // for 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 context_view_element;
-
 import 'dart:async';
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
+import 'dart:html';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/context_ref.dart';
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/class_menu.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import 'package:observatory/src/elements/view_footer.dart';
 
-@CustomTag('context-view')
-class ContextViewElement extends ObservatoryElement {
-  @published Context context;
+class ContextViewElement  extends HtmlElement implements Renderable {
+  static const tag = const Tag<ContextViewElement>('context-view',
+                                            dependencies: const [
+                                              ContextRefElement.tag,
+                                              CurlyBlockElement.tag,
+                                              NavBarElement.tag,
+                                              NavClassMenuElement.tag,
+                                              NavTopMenuElement.tag,
+                                              NavVMMenuElement.tag,
+                                              NavIsolateMenuElement.tag,
+                                              NavMenuElement.tag,
+                                              NavRefreshElement.tag,
+                                              NavNotifyElement.tag,
+                                              ObjectCommonElement.tag,
+                                              ViewFooterElement.tag
+                                            ]);
+
+  RenderingScheduler<ContextViewElement> _r;
+
+  Stream<RenderedEvent<ContextViewElement>> get onRendered => _r.onRendered;
+
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.Context _context;
+  M.ContextRepository _contexts;
+  M.RetainedSizeRepository _retainedSizes;
+  M.ReachableSizeRepository _reachableSizes;
+  M.InboundReferencesRepository _references;
+  M.RetainingPathRepository _retainingPaths;
+  M.InstanceRepository _instances;
+
+
+  M.VMRef get vm => _vm;
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+  M.Context get context => _context;
+
+  factory ContextViewElement(M.VM vm, M.IsolateRef isolate, M.Context context,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.ContextRepository contexts,
+                            M.RetainedSizeRepository retainedSizes,
+                            M.ReachableSizeRepository reachableSizes,
+                            M.InboundReferencesRepository references,
+                            M.RetainingPathRepository retainingPaths,
+                            M.InstanceRepository instances,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    assert(context != null);
+    assert(contexts != null);
+    assert(retainedSizes != null);
+    assert(reachableSizes != null);
+    assert(references != null);
+    assert(retainingPaths != null);
+    assert(instances != null);
+    ContextViewElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._context = context;
+    e._contexts = contexts;
+    e._retainedSizes = retainedSizes;
+    e._reachableSizes = reachableSizes;
+    e._references = references;
+    e._retainingPaths = retainingPaths;
+    e._instances = instances;
+    return e;
+  }
 
   ContextViewElement.created() : super.created();
 
-  Future refresh() {
-    return context.reload();
+  @override
+  attached() {
+    super.attached();
+    _r.enable();
+  }
+
+  @override
+  detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+  }
+
+  void render() {
+    var content = [
+      new NavBarElement(queue: _r.queue)
+        ..children = [
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+          new NavClassMenuElement(_isolate, _context.clazz, queue: _r.queue),
+          new NavMenuElement('instance', last: true, queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                _context = await _contexts.get(_isolate, _context.id);
+                _r.dirty();
+              }),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ],
+      new DivElement()..classes = const ['content-centered-big']
+        ..children = [
+          new HeadingElement.h2()..text = 'Allocation Profile',
+          new HRElement(),
+          new ObjectCommonElement(_isolate, _context, _retainedSizes,
+                                  _reachableSizes, _references, _retainingPaths,
+                                  _instances, queue: _r.queue)
+        ]
+    ];
+    if (_context.parentContext != null) {
+      content.addAll([
+        new BRElement(),
+        new DivElement()..classes = const ['content-centered-big']
+          ..children = [
+            new DivElement()..classes = ['memberList']
+              ..children = [
+                new DivElement()..classes = ['memberItem']
+                  ..children = [
+                    new DivElement()..classes = ['memberName']
+                      ..text = 'parent context',
+                    new DivElement()..classes = ['memberName']
+                      ..children = [
+                        new ContextRefElement(_isolate, _context.parentContext,
+                                              queue: _r.queue)
+                      ]
+                  ]
+              ]
+          ]
+      ]);
+    }
+    content.add(new HRElement());
+    if (_context.variables.isNotEmpty) {
+      int index = 0;
+      content.addAll([
+        new DivElement()..classes = const ['content-centered-big']
+          ..children = [
+            new SpanElement()..text = 'Variables ',
+            new CurlyBlockElement(expanded: _context.variables.length > 8,
+                                  queue: _r.queue)
+              ..children = [
+                new DivElement()..classes = ['memberList']
+                  ..children = _context.variables.map((variable)
+                    => new DivElement()..classes = ['memberItem']
+                      ..children = [
+                        new DivElement()..classes = ['memberName']
+                          ..text = '[ ${++index} ]',
+                        new DivElement()..classes = ['memberName']
+                          ..children = [
+                            anyRef(_isolate, variable.value, _instances,
+                                   queue: _r.queue)
+                          ]
+                      ]).toList()
+              ]
+          ]
+      ]);
+    }
+    content.add(new DivElement()..classes = const ['content-centered-big']
+      ..children = [new ViewFooterElement(queue: _r.queue)]);
+    children = content;
   }
 }
diff --git a/runtime/observatory/lib/src/elements/context_view.html b/runtime/observatory/lib/src/elements/context_view.html
deleted file mode 100644
index b31ed92..0000000
--- a/runtime/observatory/lib/src/elements/context_view.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="object_common.html">
-
-<polymer-element name="context-view">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <vm-nav-menu vm="{{ context.isolate.vm }}"></vm-nav-menu>
-      <isolate-nav-menu isolate="{{ context.isolate }}"></isolate-nav-menu>
-      <!-- TODO(turnidge): Add library nav menu here. -->
-      <class-nav-menu cls="{{ context.clazz }}"></class-nav-menu>
-      <nav-menu link="." anchor="instance" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-    </nav-bar>
-
-    <template if="{{ !context.isError }}">
-      <div class="content">
-        <h1>instance of Context</h1>
-
-        <object-common object="{{ context }}"></object-common>
-        <br>
-
-        <div class="memberList">
-          <template if="{{ context.parentContext != null }}">
-            <div class="memberItem">
-              <div class="memberName">parent context</div>
-              <div class="memberValue">
-                <any-service-ref ref="{{ context.parentContext }}"></any-service-ref>
-              </div>
-            </div>
-          </template>
-        </div>
-      </div>
-
-      <hr>
-
-      <div class="content">
-        <template if="{{ context.variables.isNotEmpty }}">
-          variables ({{ context.variables.length }})
-          <curly-block expand="{{ context.variables.length <= 8 }}">
-            <div class="memberList">
-              <template repeat="{{ index in context.variables.asMap().keys }}">
-                <div class="memberItem">
-                  <div class="memberName">[{{ index }}]</div>
-                  <div class="memberValue">
-                    <any-service-ref
-                       ref="{{ context.variables[index]['value'] }}">
-                    </any-service-ref>
-                  </div>
-                </div>
-              </template>
-            </div>
-          </curly-block><br><br>
-        </template>
-      </div>
-    </template>
-    <view-footer></view-footer>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="context_view.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.dart b/runtime/observatory/lib/src/elements/cpu_profile.dart
index 014fd80..75e2c07 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile.dart
@@ -131,9 +131,9 @@
             })
             ..onFilterChange.listen((e) {
               _filter = e.element.filter.trim();
-              tree.filter = _filter.isNotEmpty
-                ? (node) { return node.name.contains(_filter); }
-                : null;
+              tree.filters = _filter.isNotEmpty
+                ? [(node) { return node.name.contains(_filter); }]
+                : const [];
             })
             ..onDirectionChange.listen((e) {
               _direction = tree.direction = e.element.direction;
diff --git a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
index 236b395..57c85a9 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile/virtual_tree.dart
@@ -31,19 +31,21 @@
   ProfileTreeMode _mode;
   M.IsolateRef _isolate;
   M.SampleProfile _profile;
-  M.CallTreeNodeFilter _filter;
+  Iterable<M.CallTreeNodeFilter> _filters;
 
   M.ProfileTreeDirection get direction => _direction;
   ProfileTreeMode get mode => _mode;
   M.IsolateRef get isolate => _isolate;
   M.SampleProfile get profile => _profile;
-  M.CallTreeNodeFilter get filter => _filter;
+  Iterable<M.CallTreeNodeFilter> get filters => _filters;
 
   set direction(M.ProfileTreeDirection value) =>
       _direction = _r.checkAndReact(_direction, value);
   set mode(ProfileTreeMode value) => _mode = _r.checkAndReact(_mode, value);
-  set filter(M.CallTreeNodeFilter value) =>
-      _filter = _r.checkAndReact(_filter, value);
+  set filters(Iterable<M.CallTreeNodeFilter> value) {
+    _filters = new List.unmodifiable(value);
+    _r.dirty();
+  }
 
   factory CpuProfileVirtualTreeElement(M.IsolateRef isolate,
       M.SampleProfile profile, {ProfileTreeMode mode: ProfileTreeMode.function,
@@ -94,15 +96,17 @@
       default:
         throw new Exception('Unknown ProfileTreeMode: $mode');
     }
+    if (filters != null) {
+      tree = filters.fold(tree, (tree, filter) {
+        return tree?.filtered(filter);
+      });
+    }
     if (tree == null) {
       children = [
         new HeadingElement.h1()..text = 'No Results'
       ];
       return;
     }
-    if (filter != null) {
-      tree = tree.filtered(filter);
-    }
     _tree = new VirtualTreeElement(_createRow, update, _getChildren,
       items: tree.root.children, queue: _r.queue);
     if (tree.root.children.length == 1) {
diff --git a/runtime/observatory/lib/src/elements/cpu_profile_table.dart b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
index 2a76e17..104b190 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile_table.dart
+++ b/runtime/observatory/lib/src/elements/cpu_profile_table.dart
@@ -6,924 +6,446 @@
 
 import 'dart:async';
 import 'dart:html';
-import 'observatory_element.dart';
-import 'sample_buffer_control.dart';
-import 'stack_trace_tree_config.dart';
-import 'cpu_profile/virtual_tree.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/app.dart';
-import 'package:observatory/cpu_profile.dart';
-import 'package:observatory/elements.dart';
 import 'package:observatory/models.dart' as M;
-import 'package:observatory/repositories.dart';
-import 'package:polymer/polymer.dart';
+import 'package:observatory/src/elements/containers/virtual_collection.dart';
+import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+import 'package:observatory/src/elements/function_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/sample_buffer_control.dart';
+import 'package:observatory/src/elements/stack_trace_tree_config.dart';
+import 'package:observatory/utils.dart';
 
-List<String> sorted(Set<String> attributes) {
-  var list = attributes.toList();
-  list.sort();
-  return list;
+enum _Table {
+  functions,
+  caller,
+  callee
 }
 
-abstract class ProfileTreeRow<T> extends TableTreeRow {
-  final CpuProfile profile;
-  final T node;
-  final String selfPercent;
-  final String percent;
-  bool _infoBoxShown = false;
-  HtmlElement infoBox;
-  HtmlElement infoButton;
+enum _SortingField {
+  exclusive,
+  inclusive,
+  caller,
+  callee,
+  method
+}
 
-  ProfileTreeRow(TableTree tree, TableTreeRow parent,
-                 this.profile, this.node, double selfPercent, double percent)
-      : super(tree, parent),
-        selfPercent = Utils.formatPercentNormalized(selfPercent),
-        percent = Utils.formatPercentNormalized(percent);
+enum _SortingDirection {
+  ascending,
+  descending
+}
 
-  static _addToMemberList(DivElement memberList, Map<String, String> items) {
-    items.forEach((k, v) {
-      var item = new DivElement();
-      item.classes.add('memberItem');
-      var name = new DivElement();
-      name.classes.add('memberName');
-      name.text = k;
-      var value = new DivElement();
-      value.classes.add('memberValue');
-      value.text = v;
-      item.children.add(name);
-      item.children.add(value);
-      memberList.children.add(item);
-    });
-  }
+class CpuProfileTableElement  extends HtmlElement implements Renderable {
+  static const tag = const Tag<CpuProfileTableElement>('cpu-profile-table',
+                                            dependencies: const [
+                                              FunctionRefElement.tag,
+                                              NavBarElement.tag,
+                                              NavTopMenuElement.tag,
+                                              NavVMMenuElement.tag,
+                                              NavIsolateMenuElement.tag,
+                                              NavMenuElement.tag,
+                                              NavRefreshElement.tag,
+                                              NavNotifyElement.tag,
+                                              SampleBufferControlElement.tag,
+                                              StackTraceTreeConfigElement.tag,
+                                              CpuProfileVirtualTreeElement.tag,
+                                              VirtualCollectionElement.tag
+                                            ]);
 
-  makeInfoBox() {
-    if (infoBox != null) {
-      return;
-    }
-    infoBox = new DivElement();
-    infoBox.classes.add('infoBox');
-    infoBox.classes.add('shadow');
-    infoBox.style.display = 'none';
-    listeners.add(infoBox.onClick.listen((e) => e.stopPropagation()));
-  }
+  RenderingScheduler<CpuProfileTableElement> _r;
 
-  makeInfoButton() {
-    infoButton = new SpanElement();
-    infoButton.style.marginLeft = 'auto';
-    infoButton.style.marginRight = '1em';
-    infoButton.children.add(new Element.tag('icon-info-outline'));
-    listeners.add(infoButton.onClick.listen((event) {
-      event.stopPropagation();
-      toggleInfoBox();
-    }));
-  }
+  Stream<RenderedEvent<CpuProfileTableElement>> get onRendered => _r.onRendered;
 
-  static const attributes = const {
-    'optimized' : const ['O', null, 'Optimized'],
-    'unoptimized' : const ['U', null, 'Unoptimized'],
-    'inlined' : const ['I', null, 'Inlined'],
-    'intrinsic' : const ['It', null, 'Intrinsic'],
-    'ffi' : const ['F', null, 'FFI'],
-    'dart' : const ['D', null, 'Dart'],
-    'tag' : const ['T', null, 'Tag'],
-    'native' : const ['N', null, 'Native'],
-    'stub': const ['S', null, 'Stub'],
-    'synthetic' : const ['?', null, 'Synthetic'],
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.IsolateSampleProfileRepository _profiles;
+  Stream<M.SampleProfileLoadingProgressEvent> _progressStream;
+  M.SampleProfileLoadingProgress _progress;
+  final _sortingField = <_Table, _SortingField>{
+    _Table.functions :  _SortingField.exclusive,
+    _Table.caller :  _SortingField.caller,
+    _Table.callee :  _SortingField.callee,
   };
+  final _sortingDirection = <_Table, _SortingDirection>{
+    _Table.functions :  _SortingDirection.descending,
+    _Table.caller :  _SortingDirection.descending,
+    _Table.callee :  _SortingDirection.descending,
+  };
+  String _filter = '';
 
-  HtmlElement newAttributeBox(String attribute) {
-    List attributeDetails = attributes[attribute];
-    if (attributeDetails == null) {
-      print('could not find attribute $attribute');
-      return null;
-    }
-    var element = new SpanElement();
-    element.style.border = 'solid 2px #ECECEC';
-    element.style.height = '100%';
-    element.style.display = 'inline-block';
-    element.style.textAlign = 'center';
-    element.style.minWidth = '1.5em';
-    element.style.fontWeight = 'bold';
-    if (attributeDetails[1] != null) {
-      element.style.backgroundColor = attributeDetails[1];
-    }
-    element.text = attributeDetails[0];
-    element.title = attributeDetails[2];
-    return element;
+
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+  M.IsolateSampleProfileRepository get profiles => _profiles;
+  M.VMRef get vm => _vm;
+
+  factory CpuProfileTableElement(M.VM vm, M.IsolateRef isolate,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.IsolateSampleProfileRepository profiles,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    assert(profiles != null);
+    CpuProfileTableElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._profiles = profiles;
+    return e;
   }
 
-  onHide() {
-    super.onHide();
-    infoBox = null;
-    infoButton = null;
-  }
+  CpuProfileTableElement.created() : super.created();
 
-  showInfoBox() {
-    if ((infoButton == null) || (infoBox == null)) {
-      return;
-    }
-    _infoBoxShown = true;
-    infoBox.style.display = 'block';
-    infoButton.children.clear();
-    infoButton.children.add(new Element.tag('icon-info'));
-  }
-
-  hideInfoBox() {
-    _infoBoxShown = false;
-    if ((infoButton == null) || (infoBox == null)) {
-      return;
-    }
-    infoBox.style.display = 'none';
-    infoButton.children.clear();
-    infoButton.children.add(new Element.tag('icon-info-outline'));
-  }
-
-  toggleInfoBox() {
-   if (_infoBoxShown) {
-     hideInfoBox();
-   } else {
-     showInfoBox();
-   }
-  }
-
-  hideAllInfoBoxes() {
-    final List<ProfileTreeRow> rows = tree.rows;
-    for (var row in rows) {
-      row.hideInfoBox();
-    }
-  }
-
-  onClick(MouseEvent e) {
-    e.stopPropagation();
-    if (e.altKey) {
-      bool show = !_infoBoxShown;
-      hideAllInfoBoxes();
-      if (show) {
-        showInfoBox();
-      }
-      return;
-    }
-    super.onClick(e);
-  }
-
-  HtmlElement newCodeRef(ProfileCode code) {
-    var codeRef = new Element.tag('code-ref');
-    codeRef.ref = code.code;
-    return codeRef;
-  }
-
-  HtmlElement newFunctionRef(ProfileFunction function) {
-    var ref = new Element.tag('function-ref');
-    ref.ref = function.function;
-    return ref;
-  }
-
-  HtmlElement hr() {
-    var element = new HRElement();
-    return element;
-  }
-
-  HtmlElement div(String text) {
-    var element = new DivElement();
-    element.text = text;
-    return element;
-  }
-
-  HtmlElement br() {
-    return new BRElement();
-  }
-
-  HtmlElement span(String text) {
-    var element = new SpanElement();
-    element.style.minWidth = '1em';
-    element.text = text;
-    return element;
-  }
-}
-
-class CodeProfileTreeRow extends ProfileTreeRow<CodeCallTreeNode> {
-  CodeProfileTreeRow(TableTree tree, CodeProfileTreeRow parent,
-                     CpuProfile profile, CodeCallTreeNode node)
-      : super(tree, parent, profile, node,
-              node.profileCode.normalizedExclusiveTicks,
-              node.percentage) {
-    // fill out attributes.
-  }
-
-  bool hasChildren() => node.children.length > 0;
-
-  void onShow() {
-    super.onShow();
-
-    if (children.length == 0) {
-      for (var childNode in node.children) {
-        var row = new CodeProfileTreeRow(tree, this, profile, childNode);
-        children.add(row);
-      }
-    }
-
-    // Fill in method column.
-    var methodColumn = flexColumns[0];
-    methodColumn.style.justifyContent = 'flex-start';
-    methodColumn.style.position = 'relative';
-
-    // Percent.
-    var percentNode = new DivElement();
-    percentNode.text = percent;
-    percentNode.style.minWidth = '5em';
-    percentNode.style.textAlign = 'right';
-    percentNode.title = 'Executing: $selfPercent';
-    methodColumn.children.add(percentNode);
-
-    // Gap.
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    methodColumn.children.add(gap);
-
-    // Code link.
-    var codeRef = newCodeRef(node.profileCode);
-    codeRef.style.alignSelf = 'center';
-    methodColumn.children.add(codeRef);
-
-    gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    methodColumn.children.add(gap);
-
-    for (var attribute in sorted(node.attributes)) {
-      methodColumn.children.add(newAttributeBox(attribute));
-    }
-
-    makeInfoBox();
-    methodColumn.children.add(infoBox);
-
-    infoBox.children.add(span('Code '));
-    infoBox.children.add(newCodeRef(node.profileCode));
-    infoBox.children.add(span(' '));
-    for (var attribute in sorted(node.profileCode.attributes)) {
-      infoBox.children.add(newAttributeBox(attribute));
-    }
-    infoBox.children.add(br());
-    infoBox.children.add(br());
-    var memberList = new DivElement();
-    memberList.classes.add('memberList');
-    infoBox.children.add(br());
-    infoBox.children.add(memberList);
-    ProfileTreeRow._addToMemberList(memberList, {
-        'Exclusive ticks' : node.profileCode.formattedExclusiveTicks,
-        'Cpu time' : node.profileCode.formattedCpuTime,
-        'Inclusive ticks' : node.profileCode.formattedInclusiveTicks,
-        'Call stack time' : node.profileCode.formattedOnStackTime,
-    });
-
-    makeInfoButton();
-    methodColumn.children.add(infoButton);
-
-    // Fill in self column.
-    var selfColumn = flexColumns[1];
-    selfColumn.style.position = 'relative';
-    selfColumn.style.alignItems = 'center';
-    selfColumn.text = selfPercent;
-  }
-}
-
-class FunctionProfileTreeRow extends ProfileTreeRow<FunctionCallTreeNode> {
-  FunctionProfileTreeRow(TableTree tree, FunctionProfileTreeRow parent,
-                         CpuProfile profile, FunctionCallTreeNode node)
-      : super(tree, parent, profile, node,
-              node.profileFunction.normalizedExclusiveTicks,
-              node.percentage) {
-    // fill out attributes.
-  }
-
-  bool hasChildren() => node.children.length > 0;
-
-  onShow() {
-    super.onShow();
-    if (children.length == 0) {
-      for (var childNode in node.children) {
-        var row = new FunctionProfileTreeRow(tree, this, profile, childNode);
-        children.add(row);
-      }
-    }
-
-    var methodColumn = flexColumns[0];
-    methodColumn.style.justifyContent = 'flex-start';
-
-    var codeAndFunctionColumn = new DivElement();
-    codeAndFunctionColumn.classes.add('flex-column');
-    codeAndFunctionColumn.style.justifyContent = 'center';
-    codeAndFunctionColumn.style.width = '100%';
-    methodColumn.children.add(codeAndFunctionColumn);
-
-    var functionRow = new DivElement();
-    functionRow.classes.add('flex-row');
-    functionRow.style.position = 'relative';
-    functionRow.style.justifyContent = 'flex-start';
-    codeAndFunctionColumn.children.add(functionRow);
-
-    // Insert the parent percentage
-    var parentPercent = new SpanElement();
-    parentPercent.text = percent;
-    parentPercent.style.minWidth = '4em';
-    parentPercent.style.alignSelf = 'center';
-    parentPercent.style.textAlign = 'right';
-    parentPercent.title = 'Executing: $selfPercent';
-    functionRow.children.add(parentPercent);
-
-    // Gap.
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.text = ' ';
-    functionRow.children.add(gap);
-
-    var functionRef = new Element.tag('function-ref');
-    functionRef.ref = node.profileFunction.function;
-    functionRef.style.alignSelf = 'center';
-    functionRow.children.add(functionRef);
-
-    gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.text = ' ';
-    functionRow.children.add(gap);
-
-    for (var attribute in sorted(node.attributes)) {
-      functionRow.children.add(newAttributeBox(attribute));
-    }
-
-    makeInfoBox();
-    functionRow.children.add(infoBox);
-
-    if (M.hasDartCode(node.profileFunction.function.kind)) {
-      infoBox.children.add(div('Code for current node'));
-      infoBox.children.add(br());
-      var totalTicks = node.totalCodesTicks;
-      var numCodes = node.codes.length;
-      for (var i = 0; i < numCodes; i++) {
-        var codeRowSpan = new DivElement();
-        codeRowSpan.style.paddingLeft = '1em';
-        infoBox.children.add(codeRowSpan);
-        var nodeCode = node.codes[i];
-        var ticks = nodeCode.ticks;
-        var percentage = Utils.formatPercent(ticks, totalTicks);
-        var percentageSpan = new SpanElement();
-        percentageSpan.style.display = 'inline-block';
-        percentageSpan.text = '$percentage';
-        percentageSpan.style.minWidth = '5em';
-        percentageSpan.style.textAlign = 'right';
-        codeRowSpan.children.add(percentageSpan);
-        var codeRef = new Element.tag('code-ref');
-        codeRef.ref = nodeCode.code.code;
-        codeRef.style.marginLeft = '1em';
-        codeRef.style.marginRight = 'auto';
-        codeRef.style.width = '100%';
-        codeRowSpan.children.add(codeRef);
-      }
-      infoBox.children.add(hr());
-    }
-    infoBox.children.add(span('Function '));
-    infoBox.children.add(newFunctionRef(node.profileFunction));
-    infoBox.children.add(span(' '));
-    for (var attribute in sorted(node.profileFunction.attributes)) {
-      infoBox.children.add(newAttributeBox(attribute));
-    }
-    var memberList = new DivElement();
-    memberList.classes.add('memberList');
-    infoBox.children.add(br());
-    infoBox.children.add(br());
-    infoBox.children.add(memberList);
-    infoBox.children.add(br());
-    ProfileTreeRow._addToMemberList(memberList, {
-        'Exclusive ticks' : node.profileFunction.formattedExclusiveTicks,
-        'Cpu time' : node.profileFunction.formattedCpuTime,
-        'Inclusive ticks' : node.profileFunction.formattedInclusiveTicks,
-        'Call stack time' : node.profileFunction.formattedOnStackTime,
-    });
-
-    if (M.hasDartCode(node.profileFunction.function.kind)) {
-      infoBox.children.add(div('Code containing function'));
-      infoBox.children.add(br());
-      var totalTicks = profile.sampleCount;
-      var codes = node.profileFunction.profileCodes;
-      var numCodes = codes.length;
-      for (var i = 0; i < numCodes; i++) {
-        var codeRowSpan = new DivElement();
-        codeRowSpan.style.paddingLeft = '1em';
-        infoBox.children.add(codeRowSpan);
-        var profileCode = codes[i];
-        var code = profileCode.code;
-        var ticks = profileCode.inclusiveTicks;
-        var percentage = Utils.formatPercent(ticks, totalTicks);
-        var percentageSpan = new SpanElement();
-        percentageSpan.style.display = 'inline-block';
-        percentageSpan.text = '$percentage';
-        percentageSpan.style.minWidth = '5em';
-        percentageSpan.style.textAlign = 'right';
-        percentageSpan.title = 'Inclusive ticks';
-        codeRowSpan.children.add(percentageSpan);
-        var codeRef = new Element.tag('code-ref');
-        codeRef.ref = code;
-        codeRef.style.marginLeft = '1em';
-        codeRef.style.marginRight = 'auto';
-        codeRef.style.width = '100%';
-        codeRowSpan.children.add(codeRef);
-      }
-    }
-
-    makeInfoButton();
-    methodColumn.children.add(infoButton);
-
-    // Fill in self column.
-    var selfColumn = flexColumns[1];
-    selfColumn.style.position = 'relative';
-    selfColumn.style.alignItems = 'center';
-    selfColumn.text = selfPercent;
-  }
-}
-
-class NameSortedTable extends SortedTable {
-  NameSortedTable(columns) : super(columns);
   @override
-  dynamic getSortKeyFor(int row, int col) {
-    if (col == FUNCTION_COLUMN) {
-      // Use name as sort key.
-      return rows[row].values[col].name;
-    }
-    return super.getSortKeyFor(row, col);
-  }
-
-  SortedTableRow rowFromIndex(int tableIndex) {
-    final modelIndex = sortedRows[tableIndex];
-    return rows[modelIndex];
-  }
-
-  static const FUNCTION_SPACER_COLUMNS = const [];
-  static const FUNCTION_COLUMN = 2;
-  TableRowElement _makeFunctionRow() {
-    var tr = new TableRowElement();
-    var cell;
-
-    // Add percentage.
-    cell = tr.insertCell(-1);
-    cell = tr.insertCell(-1);
-
-    // Add function ref.
-    cell = tr.insertCell(-1);
-    var functionRef = new Element.tag('function-ref');
-    cell.children.add(functionRef);
-
-    return tr;
-  }
-
-  static const CALL_SPACER_COLUMNS = const [];
-  static const CALL_FUNCTION_COLUMN = 1;
-  TableRowElement _makeCallRow() {
-    var tr = new TableRowElement();
-    var cell;
-
-    // Add percentage.
-    cell = tr.insertCell(-1);
-    // Add function ref.
-    cell = tr.insertCell(-1);
-    var functionRef = new Element.tag('function-ref');
-    cell.children.add(functionRef);
-    return tr;
-  }
-
-  _updateRow(TableRowElement tr,
-             int rowIndex,
-             List spacerColumns,
-             int refColumn) {
-    var row = rows[rowIndex];
-    // Set reference
-    var ref = tr.children[refColumn].children[0];
-    ref.ref = row.values[refColumn];
-
-    for (var i = 0; i < row.values.length; i++) {
-      if (spacerColumns.contains(i) || (i == refColumn)) {
-        // Skip spacer columns.
-        continue;
-      }
-      var cell = tr.children[i];
-      cell.title = row.values[i].toString();
-      cell.text = getFormattedValue(rowIndex, i);
-    }
-  }
-
-  _updateTableView(HtmlElement table,
-                   HtmlElement makeEmptyRow(),
-                   void onRowClick(TableRowElement tr),
-                   List spacerColumns,
-                   int refColumn) {
-    assert(table != null);
-
-    // Resize DOM table.
-    if (table.children.length > sortedRows.length) {
-      // Shrink the table.
-      var deadRows = table.children.length - sortedRows.length;
-      for (var i = 0; i < deadRows; i++) {
-        table.children.removeLast();
-      }
-    } else if (table.children.length < sortedRows.length) {
-      // Grow table.
-      var newRows = sortedRows.length - table.children.length;
-      for (var i = 0; i < newRows; i++) {
-        var row = makeEmptyRow();
-        row.onClick.listen((e) {
-          e.stopPropagation();
-          e.preventDefault();
-          onRowClick(row);
-        });
-        table.children.add(row);
-      }
-    }
-
-    assert(table.children.length == sortedRows.length);
-
-    // Fill table.
-    for (var i = 0; i < sortedRows.length; i++) {
-      var rowIndex = sortedRows[i];
-      var tr = table.children[i];
-      _updateRow(tr, rowIndex, spacerColumns, refColumn);
-    }
-  }
-}
-
-@CustomTag('cpu-profile-table')
-class CpuProfileTableElement extends ObservatoryElement {
-
-
-  CpuProfileTableElement.created() : super.created() {
-    _updateTask = new Task(update);
-    _renderTask = new Task(render);
-    var columns = [
-        new SortedTableColumn.withFormatter('Executing (%)',
-                                            Utils.formatPercentNormalized),
-        new SortedTableColumn.withFormatter('In stack (%)',
-                                            Utils.formatPercentNormalized),
-        new SortedTableColumn('Method'),
-    ];
-    profileTable = new NameSortedTable(columns);
-    profileTable.sortColumnIndex = 0;
-
-    columns = [
-        new SortedTableColumn.withFormatter('Callees (%)',
-                                            Utils.formatPercentNormalized),
-        new SortedTableColumn('Method')
-    ];
-    profileCalleesTable = new NameSortedTable(columns);
-    profileCalleesTable.sortColumnIndex = 0;
-
-    columns = [
-        new SortedTableColumn.withFormatter('Callers (%)',
-                                            Utils.formatPercentNormalized),
-        new SortedTableColumn('Method')
-    ];
-    profileCallersTable = new NameSortedTable(columns);
-    profileCallersTable.sortColumnIndex = 0;
-  }
-
   attached() {
     super.attached();
-    _updateTask.queue();
-    _resizeSubscription = window.onResize.listen((_) => _updateSize());
-    _updateSize();
+    _r.enable();
+    _request();
   }
 
+  @override
   detached() {
     super.detached();
-    if (_resizeSubscription != null) {
-      _resizeSubscription.cancel();
-    }
+    _r.disable(notify: true);
+    children = [];
   }
 
-  _updateSize() {
-    HtmlElement e = $['main'];
-    final totalHeight = window.innerHeight;
-    final top = e.offset.top;
-    final bottomMargin = 32;
-    final mainHeight = totalHeight - top - bottomMargin;
-    e.style.setProperty('height', '${mainHeight}px');
-  }
-
-  isolateChanged(oldValue) {
-    _updateTask.queue();
-  }
-
-  update() async {
-    _clearView();
-    if (isolate == null) {
-      return;
-    }
-    final stream = _repository.get(isolate, M.SampleProfileTag.none);
-    var progress = (await stream.first).progress;
-    shadowRoot.querySelector('#sampleBufferControl').children = [
-      sampleBufferControlElement =
-        new SampleBufferControlElement(progress, stream, showTag: false,
-          selectedTag: M.SampleProfileTag.none, queue: app.queue)
+  void render() {
+    var content = [
+      new NavBarElement(queue: _r.queue)
+        ..children = [
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+          new NavMenuElement('cpu profile (table)',
+              link: Uris.profiler(_isolate), last: true, queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+              ..onRefresh.listen(_refresh),
+          new NavRefreshElement(label: 'Clear', queue: _r.queue)
+              ..onRefresh.listen(_clearCpuProfile),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ],
     ];
-    if (M.isSampleProcessRunning(progress.status)) {
-      progress = (await stream.last).progress;
-    }
-    if (progress.status == M.SampleProfileLoadingStatus.loaded) {
-      _profile = progress.profile;
-      shadowRoot.querySelector('#stackTraceTreeConfig').children = [
-        stackTraceTreeConfigElement =
-            new StackTraceTreeConfigElement(showMode: false,
-                showDirection: false, mode: ProfileTreeMode.function,
-                direction: M.ProfileTreeDirection.exclusive, queue: app.queue)
-              ..onModeChange.listen((e) {
-                cpuProfileTreeElement.mode = e.element.mode;
-                _renderTask.queue();
-              })
-              ..onDirectionChange.listen((e) {
-                cpuProfileTreeElement.direction = e.element.direction;
-                _renderTask.queue();
-              })
-              ..onFilterChange.listen((e) =>_renderTask.queue())
-      ];
-      shadowRoot.querySelector('#cpuProfileTree').children = [
-        cpuProfileTreeElement =
-            new CpuProfileVirtualTreeElement(isolate, _profile,
-                queue: app.queue)
-      ];
-    }
-    _renderTask.queue();
-  }
-
-  Future clearCpuProfile() async {
-    await isolate.invokeRpc('_clearCpuProfile', { });
-    _updateTask.queue();
-    return new Future.value(null);
-  }
-
-  Future refresh() {
-    _updateTask.queue();
-    return new Future.value(null);
-  }
-
-  render() {
-    _updateView();
-  }
-
-  checkParameters() {
-    if (isolate == null) {
+    if (_progress == null) {
+      children = content;
       return;
     }
-    var functionId = app.locationManager.uri.queryParameters['functionId'];
-    var functionName =
-        app.locationManager.uri.queryParameters['functionName'];
-    if (functionId == '') {
-      // Fallback to searching by name.
-      _focusOnFunction(_findFunction(functionName));
-    } else {
-      if (functionId == null) {
-        _focusOnFunction(null);
-        return;
-      }
-      isolate.getObject(functionId).then((func) => _focusOnFunction(func));
+    content.add(new SampleBufferControlElement(_progress, _progressStream,
+      showTag: false, queue: _r.queue));
+    if (_progress.status == M.SampleProfileLoadingStatus.loaded) {
+      content.add(new BRElement());
+      content.addAll(_createTables());
+      content.add(new BRElement());
+      content.addAll(_createTree());
     }
+    children = content;
   }
 
-  _clearView() {
-    profileTable.clearRows();
-    _renderTable();
-  }
+  M.ProfileFunction _selected;
+  VirtualCollectionElement _functions;
+  VirtualCollectionElement _callers;
+  VirtualCollectionElement _callees;
 
-  _updateView() {
-    _buildFunctionTable();
-    _renderTable();
-    _updateFunctionTreeView();
-  }
-
-  int _findFunctionRow(ServiceFunction function) {
-    for (var i = 0; i < profileTable.sortedRows.length; i++) {
-      var rowIndex = profileTable.sortedRows[i];
-      var row = profileTable.rows[rowIndex];
-      if (row.values[NameSortedTable.FUNCTION_COLUMN] == function) {
-        return i;
-      }
-    }
-    return -1;
-  }
-
-  _scrollToFunction(ServiceFunction function) {
-    TableSectionElement tableBody = $['profile-table'];
-    var row = _findFunctionRow(function);
-    if (row == -1) {
-      return;
-    }
-    tableBody.children[row].classes.remove('shake');
-    // trigger reflow.
-    tableBody.children[row].offsetHeight;
-    tableBody.children[row].scrollIntoView(ScrollAlignment.CENTER);
-    tableBody.children[row].classes.add('shake');
-    // Focus on clicked function.
-    _focusOnFunction(function);
-  }
-
-  _clearFocusedFunction() {
-    TableSectionElement tableBody = $['profile-table'];
-    // Clear current focus.
-    if (focusedRow != null) {
-      tableBody.children[focusedRow].classes.remove('focused');
-    }
-    focusedRow = null;
-    focusedFunction = null;
-  }
-
-  ServiceFunction _findFunction(String functionName) {
-    for (var func in _profile.functions) {
-      if (func.function.name == functionName) {
-        return func.function;
-      }
-    }
-    return null;
-  }
-
-  _focusOnFunction(ServiceFunction function) {
-    if (focusedFunction == function) {
-      // Do nothing.
-      return;
-    }
-
-    _clearFocusedFunction();
-
-    if (function == null) {
-      _updateFunctionTreeView();
-      _clearCallTables();
-      return;
-    }
-
-    var row = _findFunctionRow(function);
-    if (row == -1) {
-      _updateFunctionTreeView();
-      _clearCallTables();
-      return;
-    }
-
-    focusedRow = row;
-    focusedFunction = function;
-
-    TableSectionElement tableBody = $['profile-table'];
-    tableBody.children[focusedRow].classes.add('focused');
-    _updateFunctionTreeView();
-    _buildCallersTable(focusedFunction);
-    _buildCalleesTable(focusedFunction);
-  }
-
-  _onRowClick(TableRowElement tr) {
-    var tableBody = $['profile-table'];
-    var row = profileTable.rowFromIndex(tableBody.children.indexOf(tr));
-    var function = row.values[NameSortedTable.FUNCTION_COLUMN];
-    app.locationManager.goReplacingParameters(
-        {
-          'functionId': function.id,
-          'functionName': function.vmName
-        }
+  List<Element> _createTables() {
+    _functions = _functions ?? new VirtualCollectionElement(
+        _createFunction,
+        _updateFunction,
+        createHeader: _createFunctionHeader,
+        queue: _r.queue
     );
-  }
-
-  _renderTable() {
-    profileTable._updateTableView($['profile-table'],
-                                  profileTable._makeFunctionRow,
-                                  _onRowClick,
-                                  NameSortedTable.FUNCTION_SPACER_COLUMNS,
-                                  NameSortedTable.FUNCTION_COLUMN);
-  }
-
-  _buildFunctionTable() {
-    for (var func in _profile.functions) {
-      if ((func.exclusiveTicks == 0) && (func.inclusiveTicks == 0)) {
-        // Skip.
-        continue;
-      }
-      var row = [
-        func.normalizedExclusiveTicks,
-        func.normalizedInclusiveTicks,
-        func.function,
-      ];
-      profileTable.addRow(new SortedTableRow(row));
+    _functions.items = _progress.profile.functions.toList()
+        ..sort(_createSorter(_Table.functions));
+    _functions.takeIntoView(_selected);
+    _callers = _callers ?? new VirtualCollectionElement(
+        _createCaller,
+        _updateCaller,
+        createHeader: _createCallerHeader,
+        queue: _r.queue
+    );
+    _callees = _callees ?? new VirtualCollectionElement(
+        _createCallee,
+        _updateCallee,
+        createHeader: _createCalleeHeader,
+        queue: _r.queue
+    );
+    if (_selected != null) {
+      _callers.items = _selected.callers.keys.toList()
+          ..sort(_createSorter(_Table.caller));
+      _callees.items = _selected.callees.keys.toList()
+          ..sort(_createSorter(_Table.callee));
+    } else {
+      _callers.items = const [];
+      _callees.items = const [];
     }
-    profileTable.sort();
+    return [
+      new DivElement()..classes = ['profile-trees']
+        ..children = [
+          new DivElement()..classes = ['profile-trees-all']
+            ..children = [_functions],
+          new DivElement()..classes = ['profile-trees-current']
+            ..children = [
+              new DivElement()..classes = ['profile-trees-caller']
+                ..children = [_callers],
+              new DivElement()..classes = ['profile-trees-selected']
+                ..children = _selected == null
+                    ? [new SpanElement()..text = 'No element selected']
+                    : [new FunctionRefElement(_isolate, _selected.function,
+                                             queue : _r.queue)],
+              new DivElement()..classes = ['profile-trees-callee']
+                ..children = [_callees]
+            ]
+        ]
+    ];
   }
 
-  _renderCallTable(TableSectionElement view,
-                   NameSortedTable model,
-                   void onRowClick(TableRowElement tr)) {
-    model._updateTableView(view,
-                           model._makeCallRow,
-                           onRowClick,
-                           NameSortedTable.CALL_SPACER_COLUMNS,
-                           NameSortedTable.CALL_FUNCTION_COLUMN);
-  }
-
-  _buildCallTable(Map<ProfileFunction, int> calls,
-                  NameSortedTable model) {
-    model.clearRows();
-    if (calls == null) {
-      return;
-    }
-    var sum = 0;
-    calls.values.forEach((i) => sum += i);
-    calls.forEach((func, count) {
-      var row = [
-          count / sum,
-          func.function,
+  Element _createFunction() {
+    final element = new DivElement()
+      ..classes = const ['function-item']
+      ..children = [
+        new SpanElement()..classes = const ['exclusive']
+          ..text = '0%',
+        new SpanElement()..classes = const ['inclusive']
+          ..text = '0%',
+        new SpanElement()..classes = const ['name']
       ];
-      model.addRow(new SortedTableRow(row));
+    element.onClick.listen((_) {
+      _selected = _functions.getItemFromElement(element);
+      _r.dirty();
     });
-    model.sort();
+    return element;
   }
 
-  _clearCallTables() {
-    _buildCallersTable(null);
-    _buildCalleesTable(null);
+  void _updateFunction(Element e, M.ProfileFunction item, int index) {
+    if (item == _selected) {
+      e.classes = const ['function-item', 'selected'];
+    } else {
+      e.classes = const ['function-item'];
+    }
+    e.children[0].text = Utils.formatPercentNormalized(_getExclusiveT(item));
+    e.children[1].text = Utils.formatPercentNormalized(_getInclusiveT(item));
+    e.children[2] = new FunctionRefElement(_isolate, item.function,
+        queue: _r.queue)..classes = const ['name'];
   }
 
-  _onCallersClick(TableRowElement tr) {
-    var table = $['callers-table'];
-    final row = profileCallersTable.rowFromIndex(table.children.indexOf(tr));
-    var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
-    _scrollToFunction(function);
-  }
+  Element _createFunctionHeader() =>
+    new DivElement()
+      ..classes = const ['function-item']
+        ..children = [
+          _createHeaderButton(const ['exclusive'], 'Execution(%)',
+                              _Table.functions,
+                              _SortingField.exclusive,
+                              _SortingDirection.descending),
+          _createHeaderButton(const ['inclusive'], 'Stack(%)',
+                              _Table.functions,
+                              _SortingField.inclusive,
+                              _SortingDirection.descending),
+          _createHeaderButton(const ['name'], 'Method',
+                              _Table.functions,
+                              _SortingField.method,
+                              _SortingDirection.descending),
+      ];
 
-  _buildCallersTable(ServiceFunction function) {
-    var calls = (function != null) ? function.profile.callers : null;
-    var table = $['callers-table'];
-    _buildCallTable(calls, profileCallersTable);
-    _renderCallTable(table, profileCallersTable, _onCallersClick);
-  }
-
-  _onCalleesClick(TableRowElement tr) {
-    var table = $['callees-table'];
-    final row = profileCalleesTable.rowFromIndex(table.children.indexOf(tr));
-    var function = row.values[NameSortedTable.CALL_FUNCTION_COLUMN];
-    _scrollToFunction(function);
-  }
-
-  _buildCalleesTable(ServiceFunction function) {
-    var calls = (function != null) ? function.profile.callees : null;
-    var table = $['callees-table'];
-    _buildCallTable(calls, profileCalleesTable);
-    _renderCallTable(table, profileCalleesTable, _onCalleesClick);
-  }
-
-  _changeSort(Element target, NameSortedTable table) {
-    if (target is TableCellElement) {
-      if (table.sortColumnIndex != target.cellIndex) {
-        table.sortColumnIndex = target.cellIndex;
-        table.sortDescending = true;
+    void _setSorting(_Table table,
+                     _SortingField field,
+                     _SortingDirection defaultDirection) {
+      if (_sortingField[table] == field) {
+        switch (_sortingDirection[table]) {
+          case _SortingDirection.descending:
+            _sortingDirection[table] = _SortingDirection.ascending;
+            break;
+          case _SortingDirection.ascending:
+            _sortingDirection[table] = _SortingDirection.descending;
+            break;
+        }
       } else {
-        table.sortDescending = !profileTable.sortDescending;
+        _sortingDirection[table] = defaultDirection;
+        _sortingField[table] = field;
       }
-      table.sort();
+      _r.dirty();
+    }
+
+  Element _createCallee() {
+    final element = new DivElement()
+      ..classes = const ['function-item']
+      ..children = [
+        new SpanElement()..classes = const ['inclusive']
+          ..text = '0%',
+        new SpanElement()..classes = const ['name']
+      ];
+    element.onClick.listen((_) {
+      _selected = _callees.getItemFromElement(element);
+      _r.dirty();
+    });
+    return element;
+  }
+
+  void _updateCallee(Element e, item, int index) {
+    e.children[0].text = Utils.formatPercentNormalized(_getCalleeT(item));
+    e.children[1] = new FunctionRefElement(_isolate, item.function,
+        queue: _r.queue)..classes = const ['name'];
+  }
+
+  Element _createCalleeHeader() =>
+    new DivElement()
+      ..classes = const ['function-item']
+        ..children = [
+          _createHeaderButton(const ['inclusive'], 'Callees(%)',
+                              _Table.callee,
+                              _SortingField.callee,
+                              _SortingDirection.descending),
+          _createHeaderButton(const ['name'], 'Method',
+                              _Table.callee,
+                              _SortingField.method,
+                              _SortingDirection.descending),
+      ];
+
+  Element _createCaller() {
+    final element = new DivElement()
+      ..classes = const ['function-item']
+      ..children = [
+        new SpanElement()..classes = const ['inclusive']
+          ..text = '0%',
+        new SpanElement()..classes = const ['name']
+      ];
+    element.onClick.listen((_) {
+      _selected = _callers.getItemFromElement(element);
+      _r.dirty();
+    });
+    return element;
+  }
+
+  void _updateCaller(Element e, item, int index) {
+    e.children[0].text = Utils.formatPercentNormalized(_getCallerT(item));
+    e.children[1] = new FunctionRefElement(_isolate, item.function,
+        queue: _r.queue)..classes = const ['name'];
+  }
+
+  Element _createCallerHeader() =>
+    new DivElement()
+      ..classes = const ['function-item']
+        ..children = [
+          _createHeaderButton(const ['inclusive'], 'Callers(%)',
+                              _Table.caller,
+                              _SortingField.caller,
+                              _SortingDirection.descending),
+          _createHeaderButton(const ['name'], 'Method',
+                              _Table.caller,
+                              _SortingField.method,
+                              _SortingDirection.descending),
+      ];
+
+  ButtonElement _createHeaderButton(List<String> classes,
+                                    String text,
+                                    _Table table,
+                                    _SortingField field,
+                                    _SortingDirection direction) =>
+      new ButtonElement()..classes = classes
+          ..text = _sortingField[table] != field ? text :
+                     _sortingDirection[table] == _SortingDirection.ascending
+                     ? '$textâ–¼' : '$textâ–²'
+          ..onClick.listen((_) => _setSorting(table, field, direction));
+
+  List<Element> _createTree() {
+    CpuProfileVirtualTreeElement tree;
+    return [
+      new StackTraceTreeConfigElement(showMode: false,
+        showDirection: false, mode: ProfileTreeMode.function,
+        direction: M.ProfileTreeDirection.exclusive, filter: _filter,
+        queue: _r.queue)
+        ..onFilterChange.listen((e) {
+          _filter = e.element.filter.trim();
+          tree.filters = _filter.isNotEmpty
+            ? [_filterTree, (node) { return node.name.contains(_filter); }]
+            : [_filterTree];
+        }),
+      new BRElement(),
+      tree = new CpuProfileVirtualTreeElement(_isolate, _progress.profile,
+        mode: ProfileTreeMode.function,
+        direction: M.ProfileTreeDirection.exclusive,
+        queue: _r.queue)
+          ..filters = _filter.isNotEmpty
+            ? [_filterTree, (node) { return node.name.contains(_filter); }]
+            : [_filterTree]
+    ];
+  }
+
+  bool _filterTree(M.FunctionCallTreeNode node) =>
+      node.profileFunction == _selected;
+
+  Future _request({bool clear: false, bool forceFetch: false}) async {
+    _progress = null;
+    _progressStream = _profiles.get(isolate, M.SampleProfileTag.none,
+        clear: clear, forceFetch: forceFetch);
+    _r.dirty();
+    _progress = (await _progressStream.first).progress;
+    _r.dirty();
+    if (M.isSampleProcessRunning(_progress.status)) {
+      _progress = (await _progressStream.last).progress;
+      _r.dirty();
     }
   }
 
-  changeSortProfile(Event e, var detail, Element target) {
-    _changeSort(target, profileTable);
-    _renderTable();
+  Future _clearCpuProfile(RefreshEvent e) async {
+    e.element.disabled = true;
+    await _request(clear: true);
+    e.element.disabled = false;
   }
 
-  changeSortCallers(Event e, var detail, Element target) {
-    _changeSort(target, profileCallersTable);
-    _renderCallTable($['callers-table'], profileCallersTable, _onCallersClick);
+  Future _refresh(e) async {
+    e.element.disabled = true;
+    await _request(forceFetch: true);
+    e.element.disabled = false;
   }
 
-  changeSortCallees(Event e, var detail, Element target) {
-    _changeSort(target, profileCalleesTable);
-    _renderCallTable($['callees-table'], profileCalleesTable, _onCalleesClick);
-  }
-
-  //////
-  ///
-  /// Function tree.
-  ///
-  TableTree functionTree;
-  _updateFunctionTreeView() {
-    if (cpuProfileTreeElement == null) {
-      return;
+  _createSorter(_Table table) {
+    var getter;
+    switch (_sortingField[table]) {
+      case _SortingField.exclusive:
+        getter = _getExclusiveT;
+        break;
+      case _SortingField.inclusive:
+        getter = _getInclusiveT;
+        break;
+      case _SortingField.callee:
+        getter = _getCalleeT;
+        break;
+      case _SortingField.caller:
+        getter = _getCallerT;
+        break;
+      case _SortingField.method:
+        getter = (M.ProfileFunction s) =>
+          M.getFunctionFullName(s.function);
+        break;
     }
-    cpuProfileTreeElement.filter = (FunctionCallTreeNode node) {
-      return node.profileFunction.function == focusedFunction;
-    };
+    switch (_sortingDirection[table]) {
+      case _SortingDirection.ascending:
+        return (a, b) => getter(a).compareTo(getter(b));
+      case _SortingDirection.descending:
+        return (a, b) => getter(b).compareTo(getter(a));
+    }
   }
 
-  @published Isolate isolate;
-  @observable NameSortedTable profileTable;
-  @observable NameSortedTable profileCallersTable;
-  @observable NameSortedTable profileCalleesTable;
-  @observable ServiceFunction focusedFunction;
-  @observable int focusedRow;
-
-
-  StreamSubscription _resizeSubscription;
-  Task _updateTask;
-  Task _renderTask;
-
-  IsolateSampleProfileRepository _repository =
-      new IsolateSampleProfileRepository();
-  CpuProfile _profile;
-  SampleBufferControlElement sampleBufferControlElement;
-  StackTraceTreeConfigElement stackTraceTreeConfigElement;
-  CpuProfileVirtualTreeElement cpuProfileTreeElement;
+  static double _getExclusiveT(M.ProfileFunction f) =>
+      f.normalizedExclusiveTicks;
+  static double _getInclusiveT(M.ProfileFunction f) =>
+      f.normalizedInclusiveTicks;
+  double _getCalleeT(M.ProfileFunction f) =>
+      _selected.callees[f] / _selected.callees.values.reduce((a, b) => a + b);
+  double _getCallerT(M.ProfileFunction f) =>
+      _selected.callers[f] / _selected.callers.values.reduce((a, b) => a + b);
 }
diff --git a/runtime/observatory/lib/src/elements/cpu_profile_table.html b/runtime/observatory/lib/src/elements/cpu_profile_table.html
deleted file mode 100644
index b95c0bc..0000000
--- a/runtime/observatory/lib/src/elements/cpu_profile_table.html
+++ /dev/null
@@ -1,218 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="cpu-profile-table">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
-      <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ makeLink('/profiler-table', isolate) }}" anchor="cpu profile (table)" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-refresh callback="{{ clearCpuProfile }}" label="Clear"></nav-refresh>
-      <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-    </nav-bar>
-    <style>
-      /* general */
-      .well {
-        background-color: #ECECEC;
-        padding: 0.2em;
-      }
-      .center {
-        align-items: center;
-        justify-content: center;
-      }
-
-      /* status messages */
-      .statusMessage {
-        font-size: 150%;
-        font-weight: bold;
-      }
-      .statusBox {
-        height: 100%;
-        padding: 1em;
-      }
-
-      /* tables */
-      .table {
-        border-collapse: collapse!important;
-        table-layout: fixed;
-        height: 100%;
-      }
-      .th, .td {
-        padding: 8px;
-        vertical-align: top;
-      }
-      .table thead > tr > th {
-        vertical-align: bottom;
-        text-align: left;
-        border-bottom:2px solid #ddd;
-      }
-      .spacer {
-        width: 16px;
-      }
-      .left-border-spacer {
-        width: 16px;
-        border-left: 1px solid;
-      }
-      .clickable {
-        color: #0489c3;
-        text-decoration: none;
-        cursor: pointer;
-        min-width: 8em;
-      }
-      .clickable:hover {
-        text-decoration: underline;
-        cursor: pointer;
-      }
-      tr:hover:not(.focused) > td {
-        background-color: #FAFAFA;
-      }
-      .focused {
-        background-color: #F4C7C3;
-      }
-      .scroll {
-        overflow: scroll;
-      }
-      .outlined {
-        -webkit-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        -moz-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        margin: 4px;
-      }
-      .centered {
-        margin-left: auto;
-        margin-right: auto;
-        justify-content: center;
-      }
-      .full-height {
-        height: 100%;
-      }
-      .mostly-full-height {
-        height: 80%;
-      }
-      .full-width {
-        width: 100%;
-      }
-      .focused-function-label {
-        flex: 0 1 auto;
-        margin-left: auto;
-        margin-right: auto;
-        justify-content: center;
-      }
-      .call-table {
-        flex: 1 1 auto;
-      }
-
-      .tree {
-        border-spacing: 0px;
-        width: 100%;
-        margin-bottom: 20px
-        vertical-align: middle;
-      }
-
-      .tree tbody tr {
-        animation: fadeIn 0.5s;
-        -moz-animation: fadeIn 0.5s;
-        -webkit-animation: fadeIn 0.5s;
-      }
-
-      .tree tbody tr:hover {
-        background-color: #FAFAFA;
-      }
-
-      .tree tr td:first-child,
-      .tree tr th:first-child {
-        width: 100%;
-      }
-
-      .tree thead > tr > th {
-        padding: 8px;
-        vertical-align: bottom;
-        text-align: left;
-        border-bottom: 1px solid #ddd;
-      }
-
-    </style>
-    <div id="sampleBufferControl"></div>
-    <br>
-    <hr>
-    <div id="main" class="flex-row centered">
-      <div class="flex-item-45-percent full-height outlined scroll">
-        <table id="main-table" class="flex-item-100-percent table">
-          <thead>
-          <tr>
-            <th on-click="{{changeSortProfile}}" class="clickable" title="Executing (%)">{{ profileTable.getColumnLabel(0) }}</th>
-            <th on-click="{{changeSortProfile}}" class="clickable" title="In stack (%)">{{ profileTable.getColumnLabel(1) }}</th>
-            <th on-click="{{changeSortProfile}}" class="clickable" title="Method">{{ profileTable.getColumnLabel(2) }}</th>
-          </tr>
-          </thead>
-          <tbody id="profile-table">
-          </tbody>
-        </table>
-      </div>
-      <div class="flex-item-45-percent full-height outlined">
-        <div class="flex-column full-height">
-          <div class="focused-function-label">
-            <template if="{{ focusedFunction != null }}">
-              <span>Focused on: </span>
-              <function-ref ref="{{ focusedFunction }}"></function-ref>
-            </template>
-            <template if="{{ focusedFunction == null }}">
-              <span>No focused function</span>
-            </template>
-          </div>
-          <hr>
-          <div class="call-table scroll">
-            <table class="full-width table">
-              <thead>
-              <tr>
-                <th on-click="{{changeSortCallers}}" class="clickable" title="Callers (%)">{{ profileCallersTable.getColumnLabel(0) }}</th>
-                <th on-click="{{changeSortCallers}}" class="clickable" title="Method">{{ profileCallersTable.getColumnLabel(1) }}</th>
-              </tr>
-              </thead>
-              <tbody id="callers-table">
-              </tbody>
-            </table>
-          </div>
-          <hr>
-          <div class="call-table scroll">
-            <table class="full-width table">
-              <thead>
-              <tr>
-                <th on-click="{{changeSortCallees}}" class="clickable" title="Callees (%)">{{ profileCalleesTable.getColumnLabel(0) }}</th>
-                <th on-click="{{changeSortCallees}}" class="clickable" title="Method">{{ profileCalleesTable.getColumnLabel(1) }}</th>
-              </tr>
-              </thead>
-              <tbody id="callees-table">
-              </tbody>
-            </table>
-          </div>
-        </div>
-      </div>
-    </div>
-    <br>
-    <div id="stackTraceTreeConfig"></div>
-    <br>
-    <div class="content-centered-big">
-      <div class="focused-function-label">
-        <template if="{{ focusedFunction != null }}">
-          <span>Filtered tree: </span>
-          <function-ref ref="{{ focusedFunction }}"></function-ref>
-        </template>
-        <template if="{{ focusedFunction == null }}">
-          <span>No focused function</span>
-        </template>
-      </div>
-    </div>
-    <br>
-    <br>
-    <div class="flex-row centered">
-      <div class="flex-item-90-percent outlined" style="margin: 16px; margin-left: 8px; margin-right: 8px">
-        <div id="cpuProfileTree"></div>
-      </div>
-    </div>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="cpu_profile.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index aeb5827..d378e68 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -587,6 +587,139 @@
   right: 0;
 }
 
+/* cpu-profile-table */
+
+cpu-profile-table {
+  position: relative;
+  display: block;
+  height: 100%;
+}
+cpu-profile-table cpu-profile-virtual-tree {
+  height: 100%;
+  min-height: 600px;
+  padding-top: 250px;
+  margin-top: -250px;
+}
+cpu-profile-table .profile-trees {
+  vertical-align: text-top;
+  min-width: 100%;
+  height: 100%;
+  padding-top: 160px;
+  margin-top: -160px;
+  padding-bottom: 100px;
+  margin-bottom: -100px;
+  padding-left: 5%;
+  padding-right: 5%;
+  min-height: 600px;
+}
+cpu-profile-table .profile-trees virtual-collection {
+  height: 100%;
+  width: 100%;
+  border: solid 1px #888888;
+  box-shadow: 2px 2px 5px #888888;
+}
+cpu-profile-table .profile-trees > .profile-trees-all {
+  vertical-align: text-top;
+  display: inline-block;
+  width: 50%;
+  height: 100%;
+  padding: 5px;
+}
+cpu-profile-table .profile-trees > .profile-trees-current {
+  vertical-align: text-top;
+  display: inline-block;
+  width: 50%;
+  height: 100%;
+}
+cpu-profile-table .profile-trees .profile-trees-caller {
+  vertical-align: text-top;
+  display: inline-block;
+  width: 100%;
+  height: 50%;
+  padding: 5px;
+  margin-top: -17px;
+  padding-top: 22px;
+}
+cpu-profile-table .profile-trees .profile-trees-selected {
+  vertical-align: text-top;
+  display: block;
+  height: 24px;
+  line-height: 24px;
+  margin: 5px;
+  border: solid 1px #888888;
+  box-shadow: 2px 2px 5px #888888;
+  padding-left: 5px;
+  padding-right: 5px;
+}
+cpu-profile-table .profile-trees .profile-trees-selected > * {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  overflow: hidden;
+  display: inline-block;
+  width: 100%;
+}
+cpu-profile-table .profile-trees .profile-trees-callee {
+  vertical-align: text-top;
+  display: inline-block;
+  width: 100%;
+  height: 50%;
+  padding: 5px;
+  margin-bottom: -17px;
+  padding-bottom: 22px;
+}
+cpu-profile-table .function-item {
+  box-sizing: border-box;
+  line-height: 20px;
+}
+cpu-profile-table .header {
+  box-sizing: border-box;
+  line-height: 20px;
+}
+cpu-profile-table .header .function-item:last-child {
+  margin-bottom: -3px;
+  border-bottom: solid 1px #AAAAAA;
+}
+cpu-profile-table .function-item .inclusive,
+cpu-profile-table .function-item .exclusive {
+  display: inline-block;
+  width: 7em;
+  text-align: right;
+  padding-right: 0.5em;
+  line-height: 20px;
+}
+cpu-profile-table .shifter .function-item .inclusive {
+  background-color: #EEEEEE;
+}
+cpu-profile-table .shifter .function-item.selected .inclusive {
+  background-color: #51a3fb;
+}
+cpu-profile-table .shifter .function-item:hover .inclusive {
+  background-color: #afd5fd;
+}
+cpu-profile-table .header .function-item .inclusive {
+  background-color: #DDDDDD;
+}
+cpu-profile-table .shifter .function-item.selected {
+  background-color: #60abfb;
+}
+cpu-profile-table .shifter .function-item:hover {
+  background-color: #d2e7fe;
+}
+cpu-profile-table .function-item .exclusive {
+}
+cpu-profile-table .function-item .name {
+  padding-left: 0.5em;
+}
+cpu-profile-table .function-item > button,
+cpu-profile-table .function-item > button:active {
+  background-color: transparent;
+  color: #0489c3;
+  border-style: none;
+}
+cpu-profile-table .function-item > button:hover {
+  text-decoration: underline;
+}
+
 /* cpu-profile-virtual-tree */
 
 cpu-profile-virtual-tree {
@@ -666,10 +799,112 @@
   text-decoration: none;
 }
 
+/* heap-snapshot */
+
+
+heap-snapshot .statusMessage {
+  font-size: 150%;
+  font-weight: bold;
+}
+
+heap-snapshot .statusBox {
+  height: 100%;
+  padding: 1em;
+}
+heap-snapshot .explanation {
+  display: block;
+  display: -webkit-box;
+  -webkit-line-clamp: 4;
+  -webkit-box-orient: vertical;
+  max-height: 80px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+heap-snapshot virtual-tree {
+  position: absolute;
+  height: auto;
+  top: 250px;
+  bottom: 0;
+  left: 0;
+  right: 0;
+}
+heap-snapshot .tree-item {
+  box-sizing: border-box;
+  line-height: 30px;
+  height: 30px;
+  padding-left: 5%;
+  padding-right: 5%;
+}
+heap-snapshot .tree-item > .size,
+heap-snapshot .tree-item > .percentage {
+  display: inline-block;
+  text-align: right;
+  width: 4em;
+  margin-left: 0.25em;
+  margin-right: 0.25em;
+}
+
+heap-snapshot .tree-item > .name {
+  display: inline;
+  margin-left: 0.5em;
+}
+
+
+/* icdata-ref */
+
+icdata-ref > a[href]:hover {
+    text-decoration: underline;
+}
+
+icdata-ref > a[href] {
+    color: #0489c3;
+    text-decoration: none;
+}
+
+icdata-ref > a[href] * {
+    color: inherit;
+}
+
+/* inbound-reference */
+
+inbound-reference > a[href]:hover {
+  text-decoration: underline;
+}
+inbound-reference > a[href] {
+  color: #0489c3;
+  text-decoration: none;
+}
+
+inbound-reference .indent {
+  margin-left: 1.5em;
+  font: 400 14px 'Montserrat', sans-serif;
+  line-height: 150%;
+}
+inbound-reference .stackTraceBox {
+  margin-left: 1.5em;
+  background-color: #f5f5f5;
+  border: 1px solid #ccc;
+  padding: 10px;
+  font-family: consolas, courier, monospace;
+  font-size: 12px;
+  white-space: pre;
+  overflow-x: auto;
+}
+
 /* instance-ref */
 /* TODO(cbernaschina) fix instance-ref-wrapped to instance-ref when wrapper
 removed */
 
+instance-ref-wrapped > a[href]:hover {
+  text-decoration: underline;
+}
+instance-ref-wrapped > a[href] {
+  color: #0489c3;
+  text-decoration: none;
+}
+instance-ref-wrapped > a[href] * {
+  color: inherit;
+}
 instance-ref-wrapped .empathize {
   font-style: italic;
 }
@@ -882,6 +1117,40 @@
   margin: 0;
 }
 
+/* object-common */
+/* TODO(cbernaschina) fix object-common-wrapped to object-common when wrapper
+removed */
+
+object-common-wrapped button:hover {
+  background-color: transparent;
+  border: none;
+  text-decoration: underline;
+}
+object-common-wrapped button {
+  background-color: transparent;
+  border: none;
+  color: #0489c3;
+  padding: 0;
+  margin: -8px 4px;
+  font-size: 20px;
+  text-decoration: none;
+}
+
+/* object-pool-ref */
+
+object-pool-ref > a[href]:hover {
+    text-decoration: underline;
+}
+
+object-pool-ref > a[href] {
+    color: #0489c3;
+    text-decoration: none;
+}
+
+object-pool-ref > a[href] * {
+    color: inherit;
+}
+
 /* observatory-application */
 
 observatory-application {
@@ -894,6 +1163,12 @@
   height: 100%;
 }
 
+/* ports-page */
+
+ports-page .port-number {
+  font-weight: bold;
+}
+
 /* script-ref */
 /* TODO(cbernaschina) fix script-ref-wrapped to script-ref when wrapper
 removed */
diff --git a/runtime/observatory/lib/src/elements/field_ref_wrapper.dart b/runtime/observatory/lib/src/elements/field_ref_wrapper.dart
index aded8f4..35aa76e 100644
--- a/runtime/observatory/lib/src/elements/field_ref_wrapper.dart
+++ b/runtime/observatory/lib/src/elements/field_ref_wrapper.dart
@@ -54,7 +54,7 @@
             text-decoration: none;
         }''',
       new FieldRefElement(_field.isolate, _field,
-                          new InstanceRepository(_field.isolate),
+                          new InstanceRepository(),
                           queue: ObservatoryApplication.app.queue)
     ];
   }
diff --git a/runtime/observatory/lib/src/elements/function_ref.dart b/runtime/observatory/lib/src/elements/function_ref.dart
index 204169d..2f18c91 100644
--- a/runtime/observatory/lib/src/elements/function_ref.dart
+++ b/runtime/observatory/lib/src/elements/function_ref.dart
@@ -7,7 +7,8 @@
 import 'dart:html';
 import 'dart:async';
 import 'package:observatory/models.dart' as M
-  show IsolateRef, FunctionRef, isSyntheticFunction, ClassRef, ObjectRef;
+  show IsolateRef, FunctionRef, isSyntheticFunction, ClassRef, ObjectRef,
+       getFunctionFullName;
 import 'package:observatory/src/elements/class_ref.dart';
 import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
 import 'package:observatory/src/elements/helpers/tag.dart';
@@ -53,12 +54,13 @@
   void detached() {
     super.detached();
     children = [];
+    title = '';
     _r.disable(notify: true);
   }
 
   void render() {
     var content = <Element>[
-      new AnchorElement(href: M.isSyntheticFunction(function.kind) ? null
+      new AnchorElement(href: M.isSyntheticFunction(_function.kind) ? null
         : Uris.inspect(_isolate, object: _function))
         ..text = _function.name
     ];
@@ -82,5 +84,6 @@
       }
     }
     children = content.reversed.toList(growable: false);
+    title = M.getFunctionFullName(_function);
   }
 }
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.dart b/runtime/observatory/lib/src/elements/heap_snapshot.dart
index fbfb9eb..0913e1e 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.dart
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.dart
@@ -2,469 +2,416 @@
 // for 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 heap_snapshot_element;
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
 import 'dart:html';
-import 'class_ref_wrapper.dart';
-import 'observatory_element.dart';
-import 'package:observatory/app.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/elements.dart';
-import 'package:observatory/object_graph.dart';
-import 'package:polymer/polymer.dart';
-import 'package:logging/logging.dart';
+import 'dart:math' as Math;
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/containers/virtual_tree.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/utils.dart';
 
-class DominatorTreeRow extends TableTreeRow {
-  final ObjectVertex vertex;
-  final HeapSnapshot snapshot;
+enum HeapSnapshotTreeMode {
+  dominatorTree,
+  groupByClass
+}
 
-  var _domTreeChildren;
-  get domTreeChildren {
-    if (_domTreeChildren == null) {
-      _domTreeChildren = vertex.dominatorTreeChildren();
+class HeapSnapshotElement  extends HtmlElement implements Renderable {
+  static const tag = const Tag<HeapSnapshotElement>('heap-snapshot',
+                                          dependencies: const [
+                                            ClassRefElement.tag,
+                                            NavBarElement.tag,
+                                            NavTopMenuElement.tag,
+                                            NavVMMenuElement.tag,
+                                            NavIsolateMenuElement.tag,
+                                            NavMenuElement.tag,
+                                            NavRefreshElement.tag,
+                                            NavNotifyElement.tag,
+                                            VirtualTreeElement.tag,
+                                          ]);
+
+  RenderingScheduler<HeapSnapshotElement> _r;
+
+  Stream<RenderedEvent<HeapSnapshotElement>> get onRendered => _r.onRendered;
+
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.HeapSnapshotRepository _snapshots;
+  M.InstanceRepository _instances;
+  M.HeapSnapshot _snapshot;
+  Stream<M.HeapSnapshotLoadingProgressEvent> _progressStream;
+  M.HeapSnapshotLoadingProgress _progress;
+  HeapSnapshotTreeMode _mode = HeapSnapshotTreeMode.dominatorTree;
+
+
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+  M.HeapSnapshotRepository get profiles => _snapshots;
+  M.VMRef get vm => _vm;
+
+  factory HeapSnapshotElement(M.VM vm, M.IsolateRef isolate,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.HeapSnapshotRepository snapshots,
+                            M.InstanceRepository instances,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    assert(snapshots != null);
+    assert(instances != null);
+    HeapSnapshotElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._snapshots = snapshots;
+    e._instances = instances;
+    return e;
+  }
+
+  HeapSnapshotElement.created() : super.created();
+
+  @override
+  attached() {
+    super.attached();
+    _r.enable();
+    _refresh();
+  }
+
+  @override
+  detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+  }
+
+  void render() {
+    final content = [
+      new NavBarElement(queue: _r.queue)
+        ..children = [
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+          new NavMenuElement('heap snapshot', link: Uris.profiler(_isolate),
+              last: true, queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+              ..disabled = M.isHeapSnapshotProgressRunning(_progress?.status)
+              ..onRefresh.listen((e) {
+                _refresh();
+              }),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ],
+    ];
+    if (_progress == null) {
+      children = content;
+      return;
     }
-    return _domTreeChildren;
+    switch (_progress.status) {
+      case M.HeapSnapshotLoadingStatus.fetching :
+        content.addAll(_createStatusMessage('Fetching snapshot from VM...',
+            description: _progress.stepDescription,
+            progress: _progress.progress));
+        break;
+      case M.HeapSnapshotLoadingStatus.loading :
+        content.addAll(_createStatusMessage('Loading snapshot...',
+            description: _progress.stepDescription,
+            progress: _progress.progress));
+        break;
+      case M.HeapSnapshotLoadingStatus.loaded:
+        content.addAll(_createReport());
+        break;
+    }
+    children = content;
   }
 
-  DominatorTreeRow(TableTree tree,
-                   TableTreeRow parent,
-                   this.vertex,
-                   this.snapshot)
-      : super(tree, parent) {
+  Future _refresh() async {
+    _progress = null;
+    _progressStream = _snapshots.get(isolate);
+    _r.dirty();
+    _progressStream.listen((e) {
+      _progress = e.progress;
+      _r.dirty();
+    });
+    _progress = (await _progressStream.first).progress;
+    _r.dirty();
+    if (M.isHeapSnapshotProgressRunning(_progress.status)) {
+      _progress = (await _progressStream.last).progress;
+      _snapshot = _progress.snapshot;
+      _r.dirty();
+    }
   }
 
-  bool hasChildren() {
-    return domTreeChildren.length > 0;
+  static List<Element> _createStatusMessage(String message,
+      {String description: '', double progress: 0.0}) {
+    return [
+      new DivElement()..classes = ['content-centered-big']
+        ..children = [
+          new DivElement()..classes = ['statusBox', 'shadow', 'center']
+            ..children = [
+              new DivElement()..classes = ['statusMessage']
+                ..text = message,
+              new DivElement()..classes = ['statusDescription']
+                ..text = description,
+              new DivElement()..style.background = '#0489c3'
+                ..style.width = '$progress%'
+                ..style.height = '15px'
+                ..style.borderRadius = '4px'
+            ]
+        ]
+    ];
+  }
+
+  VirtualTreeElement _tree;
+
+  List<Element> _createReport() {
+    var report = [
+      new DivElement()..classes = ['content-centered-big']
+        ..children = [
+          new DivElement()..classes = ['memberList']
+            ..children = [
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'Refreshed ',
+                  new DivElement()..classes = ['memberName']
+                    ..text = Utils.formatDateTime(_snapshot.timestamp)
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'Objects ',
+                  new DivElement()..classes = ['memberName']
+                    ..text = '${_snapshot.objects}'
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'References ',
+                  new DivElement()..classes = ['memberName']
+                    ..text = '${_snapshot.references}'
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'Size ',
+                  new DivElement()..classes = ['memberName']
+                    ..text = Utils.formatSize(_snapshot.size)
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'Analysis ',
+                  new DivElement()..classes = ['memberName']
+                    ..children = _createModeSelect()
+                ]
+            ]
+        ],
+    ];
+    switch (_mode) {
+      case HeapSnapshotTreeMode.dominatorTree:
+        _tree = new VirtualTreeElement(_createDominator, _updateDominator,
+            _getChildrenDominator,
+            items: _getChildrenDominator(_snapshot.dominatorTree),
+            queue: _r.queue);
+        _tree.expand(_snapshot.dominatorTree);
+        final text = 'In a heap dominator tree, an object X is a parent of '
+                     'object Y if every path from the root to Y goes through '
+                     'X. This allows you to find "choke points" that are '
+                     'holding onto a lot of memory. If an object becomes '
+                     'garbage, all its children in the dominator tree become '
+                     'garbage as well. '
+                     'The retained size of an object is the sum of the '
+                     'retained sizes of its children in the dominator tree '
+                     'plus its own shallow size, and is the amount of memory '
+                     'that would be freed if the object became garbage.';
+        report.addAll([
+          new DivElement()..classes = ['content-centered-big', 'explanation']
+            ..text = text
+            ..title = text,
+          _tree
+        ]);
+        break;
+      case HeapSnapshotTreeMode.groupByClass:
+        final items = _snapshot.classReferences.toList();
+        items.sort((a, b) => b.shallowSize - a.shallowSize);
+        _tree = new VirtualTreeElement(_createGroup, _updateGroup,
+            _getChildrenGroup, items: items, queue: _r.queue);
+        _tree.expand(_snapshot.dominatorTree);
+        report.add(_tree);
+        break;
+      default:
+        break;
+    }
+    return report;
+  }
+
+  static Element _createDominator(toggle) {
+    return new DivElement()
+      ..classes = const ['tree-item']
+      ..children = [
+        new SpanElement()..classes = const ['size']
+          ..title = 'retained size',
+        new SpanElement()..classes = const ['lines'],
+        new ButtonElement()..classes = const ['expander']
+          ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
+        new SpanElement()..classes = const ['percentage']
+          ..title = 'percentage of heap being retained',
+        new SpanElement()..classes = const ['name']
+      ];
+  }
+
+  static Element _createGroup(toggle) {
+    return new DivElement()
+      ..classes = const ['tree-item']
+      ..children = [
+        new SpanElement()..classes = const ['size']
+          ..title = 'shallow size',
+        new SpanElement()..classes = const ['lines'],
+        new ButtonElement()..classes = const ['expander']
+          ..onClick.listen((_) => toggle(autoToggleSingleChildNodes: true)),
+        new SpanElement()..classes = const ['count']
+          ..title = 'shallow size',
+        new SpanElement()..classes = const ['name']
+      ];
   }
 
   static const int kMaxChildren = 100;
   static const int kMinRetainedSize = 4096;
 
-  void onShow() {
-    super.onShow();
-    if (children.length == 0) {
-      domTreeChildren.sort((a, b) => b.retainedSize - a.retainedSize);
-      int includedChildren = 0;
-      for (var childVertex in domTreeChildren) {
-        if (childVertex.retainedSize >= kMinRetainedSize) {
-          if (++includedChildren <= kMaxChildren) {
-            var row = new DominatorTreeRow(tree, this, childVertex, snapshot);
-            children.add(row);
-          }
-        }
+  static _getChildrenDominator(M.HeapSnapshotDominatorNode node) {
+    final list = node.children.toList();
+    list.sort((a, b) => b.retainedSize - a.retainedSize);
+    return list.where((child) => child.retainedSize >= kMinRetainedSize)
+               .take(kMaxChildren);
+  }
+
+  static _getChildrenGroup(item) {
+    if (item is M.HeapSnapshotClassReferences) {
+      if (item.inbounds.isNotEmpty || item.outbounds.isNotEmpty) {
+        return [item.inbounds, item.outbounds];
       }
+    } else if (item is Iterable) {
+      return item.toList()..sort((a, b) => b.shallowSize - a.shallowSize);
     }
-
-    var firstColumn = flexColumns[0];
-    firstColumn.style.justifyContent = 'flex-start';
-    firstColumn.style.position = 'relative';
-    firstColumn.style.alignItems = 'center';
-    firstColumn.style.setProperty('overflow-x', 'hidden');
-
-    var percentRetained = vertex.retainedSize / snapshot.graph.size;
-    var percentNode = new SpanElement();
-    percentNode.text =  Utils.formatPercentNormalized(percentRetained);
-    percentNode.style.minWidth = '5em';
-    percentNode.style.textAlign = 'right';
-    percentNode.title = "Percent of heap being retained";
-    percentNode.style.display = 'inline-block';
-    firstColumn.children.add(percentNode);
-
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.style.display = 'inline-block';
-    firstColumn.children.add(gap);
-
-    AnyServiceRefElement objectRef = new Element.tag("any-service-ref");
-    snapshot.isolate.getObjectByAddress(vertex.address).then((obj) {
-      objectRef.ref = obj;
-    });
-    objectRef.style.alignSelf = 'center';
-    firstColumn.children.add(objectRef);
-
-    var secondColumn = flexColumns[1];
-    secondColumn.style.justifyContent = 'flex-end';
-    secondColumn.style.position = 'relative';
-    secondColumn.style.alignItems = 'center';
-    secondColumn.style.paddingRight = '0.5em';
-    secondColumn.text = Utils.formatSize(vertex.retainedSize);
-  }
-}
-
-
-class MergedVerticesRow extends TableTreeRow {
-  final Isolate isolate;
-  final List<MergedVertex> mergedVertices;
-
-  MergedVerticesRow(TableTree tree,
-                   TableTreeRow parent,
-                   this.isolate,
-                   this.mergedVertices)
-      : super(tree, parent) {
+    return const [];
   }
 
-  bool hasChildren() {
-    return mergedVertices.length > 0;
-  }
-
-  void onShow() {
-    super.onShow();
-
-    if (children.length == 0) {
-      mergedVertices.sort((a, b) => b.shallowSize - a.shallowSize);
-      for (var mergedVertex in mergedVertices) {
-        if (mergedVertex.instances > 0) {
-          var row = new MergedVertexRow(tree, this, isolate, mergedVertex);
-          children.add(row);
-        }
-      }
-    }
-  }
-}
-
-class MergedVertexRow extends TableTreeRow {
-  final Isolate isolate;
-  final MergedVertex vertex;
-
-  MergedVertexRow(TableTree tree,
-                  TableTreeRow parent,
-                  this.isolate,
-                  this.vertex)
-      : super(tree, parent) {
-  }
-
-  bool hasChildren() {
-    return vertex.outgoingEdges.length > 0 ||
-           vertex.incomingEdges.length > 0;
-  }
-
-  void onShow() {
-    super.onShow();
-    if (children.length == 0) {
-      children.add(new MergedEdgesRow(tree, this, isolate, vertex, true));
-      children.add(new MergedEdgesRow(tree, this, isolate, vertex, false));
-    }
-
-
-    var firstColumn = flexColumns[0];
-    firstColumn.style.justifyContent = 'flex-start';
-    firstColumn.style.position = 'relative';
-    firstColumn.style.alignItems = 'center';
-
-    var percentNode = new SpanElement();
-    percentNode.text = "${vertex.instances} instances of";
-    percentNode.style.minWidth = '5em';
-    percentNode.style.textAlign = 'right';
-    firstColumn.children.add(percentNode);
-
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.style.display = 'inline-block';
-    firstColumn.children.add(gap);
-
-    ClassRefElementWrapper classRef = new Element.tag("class-ref");
-    classRef.ref = isolate.getClassByCid(vertex.cid);
-    classRef.style.alignSelf = 'center';
-    firstColumn.children.add(classRef);
-
-    var secondColumn = flexColumns[1];
-    secondColumn.style.justifyContent = 'flex-end';
-    secondColumn.style.position = 'relative';
-    secondColumn.style.alignItems = 'center';
-    secondColumn.style.paddingRight = '0.5em';
-    secondColumn.text = Utils.formatSize(vertex.shallowSize);
-  }
-}
-
-class MergedEdgesRow extends TableTreeRow {
-  final Isolate isolate;
-  final MergedVertex vertex;
-  final bool outgoing;
-
-  MergedEdgesRow(TableTree tree,
-                 TableTreeRow parent,
-                 this.isolate,
-                 this.vertex,
-                 this.outgoing)
-      : super(tree, parent) {
-  }
-
-  bool hasChildren() {
-    return outgoing
-            ? vertex.outgoingEdges.length > 0
-            : vertex.incomingEdges.length > 0;
-  }
-
-  void onShow() {
-    super.onShow();
-    if (children.length == 0) {
-      if (outgoing) {
-        var outgoingEdges = vertex.outgoingEdges.values.toList();
-        outgoingEdges.sort((a, b) => b.shallowSize - a.shallowSize);
-        for (var edge in outgoingEdges) {
-          if (edge.count > 0) {
-            var row = new MergedEdgeRow(tree, this, isolate, edge, true);
-            children.add(row);
-          }
-        }
-      } else {
-        vertex.incomingEdges.sort((a, b) => b.shallowSize - a.shallowSize);
-        for (var edge in vertex.incomingEdges) {
-          if (edge.count > 0) {
-            var row = new MergedEdgeRow(tree, this, isolate, edge, false);
-            children.add(row);
-          }
-        }
-      }
-    }
-
-    var count = 0;
-    var shallowSize = 0;
-    var edges = outgoing ? vertex.outgoingEdges.values : vertex.incomingEdges;
-    for (var edge in edges) {
-      count += edge.count;
-      shallowSize += edge.shallowSize;
-    }
-
-    var firstColumn = flexColumns[0];
-    firstColumn.style.justifyContent = 'flex-start';
-    firstColumn.style.position = 'relative';
-    firstColumn.style.alignItems = 'center';
-
-    var countNode = new SpanElement();
-    countNode.text = "$count";
-    countNode.style.minWidth = '5em';
-    countNode.style.textAlign = 'right';
-    firstColumn.children.add(countNode);
-
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.style.display = 'inline-block';
-    firstColumn.children.add(gap);
-
-    var labelNode = new SpanElement();
-    labelNode.text = outgoing ? "Outgoing references" : "Incoming references";
-    firstColumn.children.add(labelNode);
-
-    var secondColumn = flexColumns[1];
-    secondColumn.style.justifyContent = 'flex-end';
-    secondColumn.style.position = 'relative';
-    secondColumn.style.alignItems = 'center';
-    secondColumn.style.paddingRight = '0.5em';
-    secondColumn.text = Utils.formatSize(shallowSize);
-  }
-}
-
-class MergedEdgeRow extends TableTreeRow {
-  final Isolate isolate;
-  final MergedEdge edge;
-  final bool outgoing;
-
-  MergedEdgeRow(TableTree tree,
-                TableTreeRow parent,
-                this.isolate,
-                this.edge,
-                this.outgoing)
-      : super(tree, parent) {
-  }
-
-  bool hasChildren() => false;
-
-  void onShow() {
-    super.onShow();
-
-    var firstColumn = flexColumns[0];
-    firstColumn.style.justifyContent = 'flex-start';
-    firstColumn.style.position = 'relative';
-    firstColumn.style.alignItems = 'center';
-
-    var percentNode = new SpanElement();
-    var preposition = outgoing ? "to" : "from";
-    percentNode.text = "${edge.count} references $preposition instances of";
-    percentNode.style.minWidth = '5em';
-    percentNode.style.textAlign = 'right';
-    firstColumn.children.add(percentNode);
-
-    var gap = new SpanElement();
-    gap.style.minWidth = '1em';
-    gap.style.display = 'inline-block';
-    firstColumn.children.add(gap);
-
-    MergedVertex v = outgoing ? edge.target : edge.source;
-    if (v.cid == 0) {
-      var rootName = new SpanElement();
-      rootName.text = '<root>';
-      firstColumn.children.add(rootName);
+  void _updateDominator(HtmlElement element, M.HeapSnapshotDominatorNode node,
+      int depth) {
+    element.children[0].text = Utils.formatSize(node.retainedSize);
+    _updateLines(element.children[1].children, depth);
+    if (_getChildrenDominator(node).isNotEmpty) {
+      element.children[2].text = _tree.isExpanded(node) ? 'â–¼' : 'â–º';
     } else {
-      ClassRefElementWrapper classRef = new Element.tag("class-ref");
-      classRef.ref = isolate.getClassByCid(v.cid);
-      classRef.style.alignSelf = 'center';
-      firstColumn.children.add(classRef);
+      element.children[2].text = '';
     }
-
-    var secondColumn = flexColumns[1];
-    secondColumn.style.justifyContent = 'flex-end';
-    secondColumn.style.position = 'relative';
-    secondColumn.style.alignItems = 'center';
-    secondColumn.style.paddingRight = '0.5em';
-    secondColumn.text = Utils.formatSize(edge.shallowSize);
-  }
-}
-
-
-class MergedEdge {
-  final MergedVertex source;
-  final MergedVertex target;
-  int count = 0;
-  int shallowSize = 0;
-  int retainedSize = 0;
-
-  MergedEdge(this.source, this.target);
-}
-
-class MergedVertex {
-  final int cid;
-  int instances = 0;
-  int shallowSize = 0;
-  int retainedSize = 0;
-
-  List<MergedEdge> incomingEdges = new List<MergedEdge>();
-  Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>();
-
-  MergedVertex(this.cid);
-}
-
-
-Future<List<MergedVertex>> buildMergedVertices(ObjectGraph graph) async {
-  Logger.root.info("Start merge vertices");
-
-  var cidToMergedVertex = {};
-
-  for (var vertex in graph.vertices) {
-    var cid = vertex.vmCid;
-    MergedVertex source = cidToMergedVertex[cid];
-    if (source == null) {
-      cidToMergedVertex[cid] = source = new MergedVertex(cid);
-    }
-
-    source.instances++;
-    source.shallowSize += (vertex.shallowSize == null ? 0 : vertex.shallowSize);
-
-    for (var vertex2 in vertex.successors) {
-      var cid2 = vertex2.vmCid;
-      MergedEdge edge = source.outgoingEdges[cid2];
-      if (edge == null) {
-        MergedVertex target = cidToMergedVertex[cid2];
-        if (target == null) {
-          cidToMergedVertex[cid2] = target = new MergedVertex(cid2);
-        }
-        edge = new MergedEdge(source, target);
-        source.outgoingEdges[cid2] = edge;
-        target.incomingEdges.add(edge);
-      }
-      edge.count++;
-      // An over-estimate if there are multiple references to the same object.
-      edge.shallowSize += vertex2.shallowSize == null ? 0 : vertex2.shallowSize;
-    }
+    element.children[3].text = Utils.formatPercentNormalized(
+        node.retainedSize * 1.0 / _snapshot.size);
+    final wrapper = new SpanElement()..classes = const ['name']
+                                     ..text = 'Loading...';
+    element.children[4] = wrapper;
+    node.object.then((object) {
+      wrapper..text = ''
+        ..children = [anyRef(_isolate, object, _instances, queue: _r.queue)];
+    });
   }
 
-  Logger.root.info("End merge vertices");
-
-  return cidToMergedVertex.values.toList();
-}
-
-@CustomTag('heap-snapshot')
-class HeapSnapshotElement extends ObservatoryElement {
-  @published Isolate isolate;
-  @observable HeapSnapshot snapshot;
-
-  @published String state = 'Requested';
-  @published String analysisSelector = 'DominatorTree';
-
-  HeapSnapshotElement.created() : super.created();
-
-  void analysisSelectorChanged(oldValue) {
-    _update();
-  }
-
-  void isolateChanged(oldValue) {
-    if (isolate == null) return;
-
-    if (isolate.latestSnapshot == null) {
-      _getHeapSnapshot();
-    } else {
-      snapshot = isolate.latestSnapshot;
-      state = 'Loaded';
-      _update();
-    }
-  }
-
-  Future refresh() {
-    return _getHeapSnapshot();
-  }
-
-  Future _getHeapSnapshot() {
-    var completer = new Completer();
-    state = "Requesting heap snapshot...";
-    isolate.getClassRefs();
-
-    bool collectGarbage =
-        app.locationManager.getBoolParameter('collectGarbage', true);
-
-    var stopwatch = new Stopwatch()..start();
-    isolate.fetchHeapSnapshot(collectGarbage).listen((event) {
-      if (event is String) {
-        print("${stopwatch.elapsedMilliseconds} $event");
-        state = event;
-      } else if (event is HeapSnapshot) {
-        snapshot = event;
-        state = 'Loaded';
-        completer.complete(snapshot);
-        _update();
+  void _updateGroup(HtmlElement element, item, int depth) {
+    _updateLines(element.children[1].children, depth);
+    if (item is M.HeapSnapshotClassReferences) {
+      element.children[0].text = Utils.formatSize(item.shallowSize);
+      element.children[2].text = _tree.isExpanded(item) ? 'â–¼' : 'â–º';
+      element.children[3].text = '${item.instances} instances of ';
+      element.children[4] = new ClassRefElement(_isolate, item.clazz,
+          queue: _r.queue)..classes = const ['name'];
+    } else if (item is Iterable) {
+      element.children[0].text = '';
+      if (item.isNotEmpty) {
+        element.children[2].text = _tree.isExpanded(item) ? 'â–¼' : 'â–º';
       } else {
-        throw "Unexpected event $event";
+        element.children[2].text = '';
       }
-    });
-    return completer.future;
-  }
-
-  void _update() {
-    if (snapshot == null) {
-      return;
-    }
-
-    switch(analysisSelector) {
-    case 'DominatorTree':
-      _buildDominatorTree();
-      break;
-    case 'MergeByClass':
-      _buildMergedVertices();
-      break;
+      element.children[3].text = '';
+      if (item is Iterable<M.HeapSnapshotClassInbound>) {
+        element.children[4] = new SpanElement()..classes = const ['name']
+            ..text = '${item.length} Incoming references';
+      } else {
+        element.children[4] = new SpanElement()..classes = const ['name']
+            ..text = '${item.length} Outgoing references';
+      }
+    } else {
+      element.children[0].text = '';
+      element.children[2].text = '';
+      element.children[3].text = '';
+      element.children[4] = new SpanElement()..classes = const ['name'];
+      if (item is M.HeapSnapshotClassInbound){
+        element.children[3].text =
+            '${item.count} references from instances of ';
+        element.children[4].children = [
+          new ClassRefElement(_isolate, item.source,
+            queue: _r.queue)
+        ];
+      } else if (item is M.HeapSnapshotClassOutbound){
+        element.children[3]..text = '${item.count} references to instances of ';
+        element.children[4].children = [
+          new ClassRefElement(_isolate, item.target,
+            queue: _r.queue)
+        ];
+      }
     }
   }
 
-  void _buildDominatorTree() {
-    var tableBody = shadowRoot.querySelector('#treeBody');
-    var tree = new TableTree(tableBody, 2);
-    var rootRow =
-        new DominatorTreeRow(tree, null, snapshot.graph.root, snapshot);
-    tree.initialize(rootRow);
-    return;
+  static _updateLines(List<Element> lines, int n) {
+    n = Math.max(0, n);
+    while (lines.length > n) {
+      lines.removeLast();
+    }
+    while (lines.length < n) {
+      lines.add(new SpanElement());
+    }
   }
 
-  void _buildMergedVertices() {
-    state = 'Grouping...';
-    var tableBody = shadowRoot.querySelector('#treeBody');
-    var tree = new TableTree(tableBody, 2);
-    tableBody.children.clear();
+  static String modeToString(HeapSnapshotTreeMode mode) {
+    switch (mode) {
+      case HeapSnapshotTreeMode.dominatorTree: return 'Dominator tree';
+      case HeapSnapshotTreeMode.groupByClass: return 'Group by class';
+    }
+    throw new Exception('Unknown ProfileTreeMode');
+  }
 
-    new Future.delayed(const Duration(milliseconds: 500), () {
-      buildMergedVertices(snapshot.graph).then((vertices) {
-        state = 'Loaded';
-        var rootRow = new MergedVerticesRow(tree, null, isolate, vertices);
-        tree.initialize(rootRow);
-      });
-    });
+  List<Element> _createModeSelect() {
+    var s;
+    return [
+      s = new SelectElement()..classes = ['analysis-select']
+        ..value = modeToString(_mode)
+        ..children = HeapSnapshotTreeMode.values.map((mode) {
+            return new OptionElement(value: modeToString(mode),
+                selected: _mode == mode)
+              ..text = modeToString(mode);
+          }).toList(growable: false)
+        ..onChange.listen((_) {
+            _mode = HeapSnapshotTreeMode.values[s.selectedIndex];
+            _r.dirty();
+          })
+    ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.html b/runtime/observatory/lib/src/elements/heap_snapshot.html
deleted file mode 100644
index 46e73d5..0000000
--- a/runtime/observatory/lib/src/elements/heap_snapshot.html
+++ /dev/null
@@ -1,198 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="heap-snapshot">
-<template>
-  <link rel="stylesheet" href="css/shared.css">
-  <nav-bar>
-    <top-nav-menu></top-nav-menu>
-    <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
-    <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-    <nav-menu link="{{ makeLink('/heap-snapshot', isolate) }}" anchor="heap snapshot" last="{{ true }}"></nav-menu>
-    <nav-refresh callback="{{ refresh }}"></nav-refresh>
-    <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-  </nav-bar>
-  <style>
-      /* general */
-      .well {
-        background-color: #ECECEC;
-        padding: 0.2em;
-      }
-      .center {
-        align-items: center;
-        justify-content: center;
-      }
-
-      /* status messages */
-      .statusMessage {
-        font-size: 150%;
-        font-weight: bold;
-      }
-      .statusBox {
-        height: 100%;
-        padding: 1em;
-      }
-
-      /* tables */
-      .table {
-        border-collapse: collapse!important;
-        table-layout: fixed;
-        height: 100%;
-      }
-      .th, .td {
-        padding: 8px;
-        vertical-align: top;
-      }
-      .table thead > tr > th {
-        vertical-align: bottom;
-        text-align: left;
-        border-bottom:2px solid #ddd;
-      }
-      .spacer {
-        width: 16px;
-      }
-      .left-border-spacer {
-        width: 16px;
-        border-left: 1px solid;
-      }
-      .clickable {
-        color: #0489c3;
-        text-decoration: none;
-        cursor: pointer;
-        min-width: 8em;
-      }
-      .clickable:hover {
-        text-decoration: underline;
-        cursor: pointer;
-      }
-      tr:hover:not(.focused) > td {
-        background-color: #FAFAFA;
-      }
-      .focused {
-        background-color: #F4C7C3;
-      }
-      .scroll {
-        overflow: scroll;
-      }
-      .outlined {
-        -webkit-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        -moz-box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        box-shadow: 0px 0px 2px 1px rgba(0,0,0,0.75);
-        margin: 4px;
-      }
-      .centered {
-        margin-left: auto;
-        margin-right: auto;
-        justify-content: center;
-      }
-      .full-height {
-        height: 100%;
-      }
-      .mostly-full-height {
-        height: 80%;
-      }
-      .full-width {
-        width: 100%;
-      }
-      .focused-function-label {
-        flex: 0 1 auto;
-        margin-left: auto;
-        margin-right: auto;
-        justify-content: center;
-      }
-      .call-table {
-        flex: 1 1 auto;
-      }
-
-      .tree {
-        border-spacing: 0px;
-        width: 100%;
-        margin-bottom: 20px
-        vertical-align: middle;
-      }
-
-      .tree tbody tr {
-        animation: fadeIn 0.5s;
-        -moz-animation: fadeIn 0.5s;
-        -webkit-animation: fadeIn 0.5s;
-      }
-
-      .tree tbody tr:hover {
-        background-color: #FAFAFA;
-      }
-
-      .tree tr td:first-child,
-      .tree tr th:first-child {
-        width: 100%;
-      }
-
-      .tree thead > tr > th {
-        padding: 8px;
-        vertical-align: bottom;
-        text-align: left;
-        border-bottom: 1px solid #ddd;
-      }
-  </style>
-  <div class="content-centered-big">
-    <h1>Heap Snapshot (Experimental)</h1>
-    <hr>
-    <template if="{{ state != 'Loaded' }}">
-      <div class="statusBox shadow center">
-        <div class="statusMessage">{{state}}</div>
-      </div>
-    </template>
-    <template if="{{ state == 'Loaded' }}">
-      <div class="memberList">
-        <div class="memberItem">
-          <div class="memberName">Refreshed at </div>
-          <div class="memberValue">{{ snapshot.timeStamp }}</div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">Objects </div>
-          <div class="memberValue">{{ snapshot.graph.vertexCount }}</div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">References </div>
-          <div class="memberValue">{{ snapshot.graph.edgeCount }}</div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">Size </div>
-          <div class="memberValue">{{ snapshot.graph.size | formatSize }}</div>
-        </div>
-        <div class="memberItem">
-           <div class="memberName">Analysis </div>
-           <div class="memberValue">
-             <select value="{{analysisSelector}}">
-               <option value="DominatorTree">Dominator tree</option>
-               <option value="MergeByClass">Group by class</option>
-             </select>
-           </div>
-        </div>
-      </div>
-      <template if="{{analysisSelector == 'DominatorTree'}}"><p>In a heap dominator tree, an object X is a parent of object Y if every path from the root to Y goes through X. This allows you to find "choke points" that are holding onto a lot memory. If an object becomes garbage, all its children in the dominator tree become garbage as well. The retained size of an object is the sum of the retained sizes of its children in the dominator tree plus its own shallow size, and is the amount of memory that would be freed if the object became garbage.</p></template>
-    </template>
-  </div>
-  <br>
-  <div class="content-centered-big">
-    <div class="tableWell shadow">
-      <table class="full-width tree">
-        <thead id="treeHeader">
-        <tr>
-          <th>
-            <template if="{{analysisSelector == 'DominatorTree'}}">Object</template>
-            <template if="{{analysisSelector == 'MergeByClass'}}">Class</template>
-          </th>
-          <th style="white-space: nowrap">
-            <template if="{{analysisSelector == 'DominatorTree'}}">Retained Size</template>
-            <template if="{{analysisSelector == 'MergeByClass'}}">Shallow Size</template>
-          </th>
-        </tr>
-        </thead>
-          <tbody id="treeBody"></tbody>
-      </table>
-    </div>
-  </div>
-  <view-footer></view-footer>
-</template>
-</polymer-element>
-
-<script type="application/dart" src="heap_snapshot.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/helpers/any_ref.dart b/runtime/observatory/lib/src/elements/helpers/any_ref.dart
index d59018f..285b476 100644
--- a/runtime/observatory/lib/src/elements/helpers/any_ref.dart
+++ b/runtime/observatory/lib/src/elements/helpers/any_ref.dart
@@ -23,7 +23,7 @@
 import 'package:observatory/src/elements/token_stream_ref.dart';
 import 'package:observatory/src/elements/unknown_ref.dart';
 
-Element anyRef(M.Isolate isolate, ref, M.InstanceRepository instances,
+Element anyRef(M.IsolateRef isolate, ref, M.InstanceRepository instances,
     {RenderingQueue queue}) {
   if (ref is M.Guarded) {
     return anyRef(isolate, ref.asSentinel ?? ref.asValue, instances,
diff --git a/runtime/observatory/lib/src/elements/icdata_view.dart b/runtime/observatory/lib/src/elements/icdata_view.dart
index d69f672..557de5b 100644
--- a/runtime/observatory/lib/src/elements/icdata_view.dart
+++ b/runtime/observatory/lib/src/elements/icdata_view.dart
@@ -1,21 +1,179 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
-library icdata_view;
-
 import 'dart:async';
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
+import 'dart:html';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import 'package:observatory/src/elements/view_footer.dart';
 
-@CustomTag('icdata-view')
-class ICDataViewElement extends ObservatoryElement {
-  @published ICData icData;
+class ICDataViewElement  extends HtmlElement implements Renderable {
+  static const tag = const Tag<ICDataViewElement>('icdata-view',
+                                            dependencies: const [
+                                              CurlyBlockElement.tag,
+                                              NavBarElement.tag,
+                                              NavTopMenuElement.tag,
+                                              NavVMMenuElement.tag,
+                                              NavIsolateMenuElement.tag,
+                                              NavMenuElement.tag,
+                                              NavRefreshElement.tag,
+                                              NavNotifyElement.tag,
+                                              ObjectCommonElement.tag,
+                                              ViewFooterElement.tag
+                                            ]);
+
+  RenderingScheduler<ICDataViewElement> _r;
+
+  Stream<RenderedEvent<ICDataViewElement>> get onRendered => _r.onRendered;
+
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.ICData _icdata;
+  M.ICDataRepository _icdatas;
+  M.RetainedSizeRepository _retainedSizes;
+  M.ReachableSizeRepository _reachableSizes;
+  M.InboundReferencesRepository _references;
+  M.RetainingPathRepository _retainingPaths;
+  M.InstanceRepository _instances;
+
+
+  M.VMRef get vm => _vm;
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+  M.ICData get icdata => _icdata;
+
+  factory ICDataViewElement(M.VM vm, M.IsolateRef isolate, M.ICData icdata,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.ICDataRepository icdatas,
+                            M.RetainedSizeRepository retainedSizes,
+                            M.ReachableSizeRepository reachableSizes,
+                            M.InboundReferencesRepository references,
+                            M.RetainingPathRepository retainingPaths,
+                            M.InstanceRepository instances,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    assert(icdata != null);
+    assert(icdatas != null);
+    assert(retainedSizes != null);
+    assert(reachableSizes != null);
+    assert(references != null);
+    assert(retainingPaths != null);
+    assert(instances != null);
+    ICDataViewElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._icdata = icdata;
+    e._icdatas = icdatas;
+    e._retainedSizes = retainedSizes;
+    e._reachableSizes = reachableSizes;
+    e._references = references;
+    e._retainingPaths = retainingPaths;
+    e._instances = instances;
+    return e;
+  }
 
   ICDataViewElement.created() : super.created();
 
-  Future refresh() {
-    return icData.reload();
+  @override
+  attached() {
+    super.attached();
+    _r.enable();
+  }
+
+  @override
+  detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
+  }
+
+  void render() {
+    children = [
+      new NavBarElement(queue: _r.queue)
+        ..children = [
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+          new NavMenuElement('instance', last: true, queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+              ..onRefresh.listen((e) async {
+                e.element.disabled = true;
+                _icdata = await _icdatas.get(_isolate, _icdata.id);
+                _r.dirty();
+              }),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ],
+
+      new DivElement()..classes = const ['content-centered-big']
+        ..children = [
+          new HeadingElement.h2()..text = 'ICData',
+          new HRElement(),
+          new ObjectCommonElement(_isolate, _icdata, _retainedSizes,
+                                  _reachableSizes, _references, _retainingPaths,
+                                  _instances, queue: _r.queue),
+          new DivElement()..classes = ['memberList']
+            ..children = [
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'owner',
+                  new DivElement()..classes = ['memberName']
+                    ..children = [
+                      _icdata.dartOwner == null
+                        ? (new SpanElement()..text = '<none>')
+                        : anyRef(_isolate, _icdata.dartOwner, _instances,
+                                queue: _r.queue)
+                    ]
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'argumentsDescriptor',
+                  new DivElement()..classes = ['memberName']
+                    ..children = [
+                      _icdata.argumentsDescriptor == null
+                        ? (new SpanElement()..text = '<none>')
+                        : anyRef(_isolate, _icdata.argumentsDescriptor,
+                                 _instances, queue: _r.queue)
+                    ]
+                ],
+              new DivElement()..classes = ['memberItem']
+                ..children = [
+                  new DivElement()..classes = ['memberName']
+                    ..text = 'entries',
+                  new DivElement()..classes = ['memberName']
+                    ..children = [
+                      _icdata.entries == null
+                        ? (new SpanElement()..text = '<none>')
+                        : anyRef(_isolate, _icdata.entries, _instances,
+                                 queue: _r.queue)
+                    ]
+                ]
+            ],
+            new HRElement(),
+            new ViewFooterElement(queue: _r.queue)
+        ]
+    ];
   }
 }
diff --git a/runtime/observatory/lib/src/elements/icdata_view.html b/runtime/observatory/lib/src/elements/icdata_view.html
deleted file mode 100644
index 60f5b6e..0000000
--- a/runtime/observatory/lib/src/elements/icdata_view.html
+++ /dev/null
@@ -1,58 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="error_view.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="object_common.html">
-<link rel="import" href="eval_link.html">
-
-<polymer-element name="icdata-view">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <vm-nav-menu vm="{{ icData.isolate.vm }}"></vm-nav-menu>
-      <isolate-nav-menu isolate="{{ icData.isolate }}"></isolate-nav-menu>
-      <nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-    </nav-bar>
-
-    <div class="content">
-      <object-common object="{{ icData }}"></object-common>
-
-      <br><br>
-
-      <div class="memberList">
-        <div class="memberItem">
-          <div class="memberName">selector</div>
-          <div class="memberValue">
-            {{ icData.selector }}
-          </div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">owner</div>
-          <div class="memberValue">
-            <any-service-ref ref="{{ icData.dartOwner }}"></any-service-ref>
-          </div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">argumentsDescriptor</div>
-          <div class="memberValue">
-            <any-service-ref ref="{{ icData.argumentsDescriptor }}"></any-service-ref>
-          </div>
-        </div>
-        <div class="memberItem">
-          <div class="memberName">entries</div>
-          <div class="memberValue">
-            <any-service-ref ref="{{ icData.entries }}"></any-service-ref>
-          </div>
-        </div>
-      </div>
-
-    </div>
-
-    <hr>
-    <view-footer></view-footer>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="icdata_view.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/inbound_reference.dart b/runtime/observatory/lib/src/elements/inbound_reference.dart
deleted file mode 100644
index c291cf6..0000000
--- a/runtime/observatory/lib/src/elements/inbound_reference.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library inbound_reference_element;
-
-import 'dart:async';
-import 'package:polymer/polymer.dart';
-import 'package:observatory/service.dart';
-import 'observatory_element.dart';
-
-@CustomTag('inbound-reference')
-class InboundReferenceElement extends ObservatoryElement {
-  @published ObservableMap ref;
-  InboundReferenceElement.created() : super.created();
-
-  // I.e., inbound references to 'source' for recursive pointer chasing.
-  @observable ObservableList inboundReferences;
-  Future<ServiceObject> fetchInboundReferences(arg) {
-    var source = ref['source'];
-    return source.isolate.getInboundReferences(source, arg)
-        .then((ServiceMap response) {
-          inboundReferences = new ObservableList.from(response['references']);
-        });
-  }
-
-  // TODO(turnidge): This is here to workaround vm/dart2js differences.
-  dynamic expander() {
-    return expandEvent;
-  }
-
-  void expandEvent(bool expand, Function onDone) {
-    if (expand) {
-      fetchInboundReferences(100).then((result) {
-        notifyPropertyChange(#ref, 0, 1);
-      }).whenComplete(onDone);
-    } else {
-      inboundReferences = null;
-      onDone();
-    }
-  }
-}
diff --git a/runtime/observatory/lib/src/elements/inbound_reference.html b/runtime/observatory/lib/src/elements/inbound_reference.html
deleted file mode 100644
index 2c3ce90..0000000
--- a/runtime/observatory/lib/src/elements/inbound_reference.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="inbound-reference">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <div>
-      <template if="{{ ref['parentField'] != null }}">
-        from <any-service-ref ref="{{ ref['parentField'] }}"></any-service-ref>
-      </template>
-      <template if="{{ ref['parentListIndex'] != null }}">
-        from [{{ ref['parentListIndex'] }}] of
-      </template>
-      <template if="{{ ref['_parentWordOffset'] != null }}">
-        from word[{{ ref['_parentWordOffset'] }}] of
-      </template>
-      <any-service-ref ref="{{ ref['source'] }}"></any-service-ref>
-      <curly-block callback="{{ expander() }}">
-        <div class="memberList">
-          <div class="memberItem">
-            <div class="memberName">
-              <template repeat="{{ reference in inboundReferences }}">
-                <inbound-reference ref="{{ reference }}"></inbound-reference>
-              </template>
-            </div>
-          </div>
-        </div>
-      </curly-block>
-    </div>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="inbound_reference.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/inbound_references.dart b/runtime/observatory/lib/src/elements/inbound_references.dart
new file mode 100644
index 0000000..91e9f48
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/inbound_references.dart
@@ -0,0 +1,125 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+class InboundReferencesElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<InboundReferencesElement>('inbound-references',
+    dependencies: const [
+        CurlyBlockElement.tag,
+        InstanceRefElement.tag
+    ]);
+
+  RenderingScheduler<InboundReferencesElement> _r;
+
+  Stream<RenderedEvent<InboundReferencesElement>> get onRendered =>
+    _r.onRendered;
+
+  M.IsolateRef _isolate;
+  M.ObjectRef _object;
+  M.InboundReferencesRepository _references;
+  M.InstanceRepository _instances;
+  M.InboundReferences _inbounds;
+  bool _expanded = false;
+
+  M.IsolateRef get isolate => _isolate;
+  M.ObjectRef get object => _object;
+
+  factory InboundReferencesElement(M.IsolateRef isolate, M.ObjectRef object,
+      M.InboundReferencesRepository references, M.InstanceRepository instances,
+      {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(object != null);
+    assert(references != null);
+    assert(instances != null);
+    InboundReferencesElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._object = object;
+    e._references = references;
+    e._instances = instances;
+    return e;
+  }
+
+  InboundReferencesElement.created() : super.created();
+
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
+  }
+
+  @override
+  void detached() {
+    super.detached();
+    children = [];
+    _r.disable(notify: true);
+  }
+
+  void render() {
+    children = [
+      new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
+        ..children = _createContent()
+        ..onToggle.listen((e) async {
+          _expanded = e.control.expanded;
+          if (_expanded) {
+            e.control.disabled = true;
+            await _refresh();
+            e.control.disabled = false;
+          }
+        })
+    ];
+  }
+
+  Future _refresh() async {
+    _inbounds = await _references.get(_isolate, _object.id);
+    _r.dirty();
+  }
+
+  List<Element> _createContent() {
+    if (_inbounds == null) {
+      return const [];
+    }
+    return _inbounds.elements.map(_createItem).toList();
+  }
+
+  Element _createItem(M.InboundReference reference) {
+    final content = <Element>[];
+
+    if (reference.parentField != null) {
+      content.addAll([
+        new SpanElement()..text = 'from ',
+        anyRef(_isolate, reference.parentField, _instances,
+                            queue: _r.queue),
+        new SpanElement()..text = ' of '
+      ]);
+    } else if (reference.parentListIndex != null) {
+      content.add(
+        new SpanElement()
+          ..text = 'from [ ${reference.parentListIndex} ] of '
+      );
+    } else if (reference.parentWordOffset != null) {
+      content.add(
+        new SpanElement()
+          ..text = 'from word [ ${reference.parentWordOffset} ] of '
+      );
+    }
+
+    content.addAll([
+      anyRef(_isolate, reference.source, _instances, queue: _r.queue),
+      new SpanElement()..text = ' referenced by ',
+      new InboundReferencesElement(_isolate, reference.source, _references,
+                                   _instances, queue: _r.queue )
+    ]);
+
+    return new DivElement()..classes = ['indent']..children = content;
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index 861aede..2e15a88 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -83,7 +83,7 @@
   }
 
   Future _refresh() async {
-    _loadedInstance = await _instances.get(_instance.id);
+    _loadedInstance = await _instances.get(_isolate, _instance.id);
     _r.dirty();
   }
 
@@ -96,7 +96,8 @@
       ..text = 'show next ${count}';
     button.onClick.listen((_) async {
       button.disabled = true;
-      _loadedInstance = await _instances.get(_instance.id, count: count * 2);
+      _loadedInstance = await _instances.get(_isolate, _instance.id,
+                                             count: count * 2);
       _r.dirty();
     });
     return [button];
diff --git a/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart b/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart
index 98b37eb..22f1414 100644
--- a/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref_wrapper.dart
@@ -72,7 +72,7 @@
           overflow-x: auto;
         }''',
       new InstanceRefElement(_instance.isolate, _instance,
-                             new InstanceRepository(_instance.isolate),
+                             new InstanceRepository(),
                              queue: ObservatoryApplication.app.queue)
     ];
   }
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index 54e5637..b7c9e13 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -2,8 +2,6 @@
 <link rel="import" href="error_view.html">
 <link rel="import" href="eval_box.html">
 <link rel="import" href="eval_link.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="object_common.html">
 
 <polymer-element name="instance-view">
   <template>
@@ -118,7 +116,7 @@
             <div class="memberItem">
               <div class="memberName">closure function</div>
               <div class="memberValue">
-                <function-ref ref="{{ instance.function }}">
+                <function-ref ref="{{ instance.closureFunction }}">
                 </function-ref>
               </div>
             </div>
@@ -360,7 +358,7 @@
 
       <div class="content-centered-big">
         <template if="{{ instance.isClosure }}">
-          <source-inset location="{{ instance.function.location }}"></source-inset>
+          <source-inset location="{{ instance.closureFunction.location }}"></source-inset>
         </template>
         <template if="{{ instance.typeClass != null }}">
           <source-inset location="{{ instance.typeClass.location }}"></source-inset>
diff --git a/runtime/observatory/lib/src/elements/megamorphiccache_view.html b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
index f25ab3d..3f2c804 100644
--- a/runtime/observatory/lib/src/elements/megamorphiccache_view.html
+++ b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
@@ -1,7 +1,5 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
 <link rel="import" href="error_view.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="object_common.html">
 <link rel="import" href="eval_link.html">
 
 <polymer-element name="megamorphiccache-view">
diff --git a/runtime/observatory/lib/src/elements/object_common.dart b/runtime/observatory/lib/src/elements/object_common.dart
index 1deb5d6..6426032 100644
--- a/runtime/observatory/lib/src/elements/object_common.dart
+++ b/runtime/observatory/lib/src/elements/object_common.dart
@@ -2,52 +2,213 @@
 // for 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 object_common_element;
-
+import 'dart:html';
 import 'dart:async';
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/inbound_references.dart';
+import 'package:observatory/src/elements/retaining_path.dart';
+import 'package:observatory/src/elements/sentinel_value.dart';
+import 'package:observatory/utils.dart';
 
-@CustomTag('object-common')
-class ObjectCommonElement extends ObservatoryElement {
-  @published ServiceObject object;
-  @published ServiceMap path;
-  @published ServiceMap inboundReferences;
-  @observable int retainedBytes = null;
-  @observable int reachableBytes = null;
+class ObjectCommonElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<ObjectCommonElement>('object-common-wrapped',
+      dependencies: const [
+        ClassRefElement.tag,
+        InboundReferencesElement.tag,
+        RetainingPathElement.tag,
+        SentinelValueElement.tag
+      ]);
+
+  RenderingScheduler<ObjectCommonElement> _r;
+
+  Stream<RenderedEvent<ObjectCommonElement>> get onRendered => _r.onRendered;
+
+  M.IsolateRef _isolate;
+  M.Object _object;
+  M.RetainedSizeRepository _retainedSizes;
+  M.ReachableSizeRepository _reachableSizes;
+  M.InboundReferencesRepository _references;
+  M.RetainingPathRepository _retainingPaths;
+  M.InstanceRepository _instances;
+  M.Guarded<M.Instance> _retainedSize = null;
+  bool _loadingRetainedBytes = false;
+  M.Guarded<M.Instance> _reachableSize = null;
+  bool _loadingReachableBytes = false;
+
+  M.IsolateRef get isolate => _isolate;
+  M.Object get object => _object;
+
+  factory ObjectCommonElement(M.IsolateRef isolate, M.Object object,
+                              M.RetainedSizeRepository retainedSizes,
+                              M.ReachableSizeRepository reachableSizes,
+                              M.InboundReferencesRepository references,
+                              M.RetainingPathRepository retainingPaths,
+                              M.InstanceRepository instances,
+                              {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(object != null);
+    assert(retainedSizes != null);
+    assert(reachableSizes != null);
+    assert(references != null);
+    assert(retainingPaths != null);
+    assert(instances != null);
+    ObjectCommonElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._object = object;
+    e._retainedSizes = retainedSizes;
+    e._reachableSizes = reachableSizes;
+    e._references = references;
+    e._instances = instances;
+    e._retainingPaths = retainingPaths;
+    return e;
+  }
 
   ObjectCommonElement.created() : super.created();
 
-  // TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
-  Future<ServiceObject> reachableSize(var dummy) {
-    return object.isolate.getReachableSize(object).then((Instance obj) {
-      // TODO(turnidge): Handle collected/expired objects gracefully.
-      reachableBytes = int.parse(obj.valueAsString);
-    });
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
   }
 
-  Future<ServiceObject> retainedSize(var dummy) {
-    return object.isolate.getRetainedSize(object).then((Instance obj) {
-      // TODO(turnidge): Handle collected/expired objects gracefully.
-      retainedBytes = int.parse(obj.valueAsString);
-    });
+  @override
+  void detached() {
+    super.detached();
+    _r.disable(notify: true);
+    children = [];
   }
 
-  Future<ServiceObject> retainingPath(var limit) {
-    return object.isolate.getRetainingPath(object, limit).then((ServiceObject obj) {
-      path = obj;
-    });
+  RetainingPathElement _path;
+  InboundReferencesElement _inbounds;
+
+  void render() {
+    _path = _path ?? new RetainingPathElement(_isolate, _object,
+                                              _retainingPaths, _instances,
+                                              queue: _r.queue);
+    _inbounds = _inbounds ?? new InboundReferencesElement(_isolate, _object,
+                                                          _references,
+                                                          _instances,
+                                                          queue: _r.queue);
+    children = [
+      new DivElement()..classes = const ['memberList']
+        ..children = [
+          new DivElement()..classes = const ['memberItem']
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Class ',
+              new DivElement()..classes = const ['memberValue']
+                ..children = [
+                  new ClassRefElement(_isolate, _object.clazz, queue: _r.queue)
+                ]
+            ],
+          new DivElement()..classes = const ['memberItem']
+            ..title = 'Space for this object in memory'
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Shallow size ',
+              new DivElement()..classes = const ['memberValue']
+                ..text = Utils.formatSize(_object.size ?? 0)
+            ],
+          new DivElement()..classes = const ['memberItem']
+            ..title = 'Space reachable from this object, '
+                      'excluding class references'
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Reachable size ',
+              new DivElement()..classes = const ['memberValue']
+                ..children = _createReachableSizeValue()
+            ],
+          new DivElement()..classes = const ['memberItem']
+            ..title = 'Space that would be reclaimed if references to this '
+                      'object were replaced with null'
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Retained size ',
+              new DivElement()..classes = const ['memberValue']
+                ..children = _createRetainedSizeValue()
+            ],
+          new DivElement()..classes = const ['memberItem']
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Retaining path ',
+              new DivElement()..classes = const ['memberValue']
+                ..children = [_path]
+            ],
+          new DivElement()..classes = const ['memberItem']
+            ..title = 'Objects which directly reference this object'
+            ..children = [
+              new DivElement()..classes = const ['memberName']
+                ..text = 'Inbound references ',
+              new DivElement()..classes = const ['memberValue']
+                ..children = [_inbounds]
+            ]
+        ]
+    ];
   }
 
-  Future<ServiceObject> fetchInboundReferences(var limit) {
-    return object.isolate.getInboundReferences(object, limit)
-        .then((ServiceObject obj) {
-           inboundReferences = obj;
-        });
+  List<Element> _createReachableSizeValue() {
+    final content = <Element>[];
+    if (_reachableSize != null) {
+      if (_reachableSize.isSentinel) {
+        content.add(
+          new SentinelValueElement(_reachableSize.asSentinel, queue: _r.queue)
+        );
+      } else {
+        content.add(
+          new SpanElement()..text = Utils.formatSize(int.parse(
+              _reachableSize.asValue.valueAsString))
+        );
+      }
+    } else {
+      content.add(
+        new SpanElement()..text = '...'
+      );
+    }
+    final button = new ButtonElement()..classes = ['reachable_size']
+      ..disabled = _loadingReachableBytes
+      ..text = '↺';
+    button.onClick.listen((_) async {
+        button.disabled = true;
+        _loadingReachableBytes = true;
+        _reachableSize = await _reachableSizes.get(_isolate, _object.id);
+        _r.dirty();
+      });
+    content.add(button);
+    return content;
   }
 
-  Future refresh() {
-    return object.reload();
+  List<Element> _createRetainedSizeValue() {
+    final content = <Element>[];
+    if (_retainedSize != null) {
+      if (_retainedSize.isSentinel) {
+        content.add(
+          new SentinelValueElement(_retainedSize.asSentinel, queue: _r.queue)
+        );
+      } else {
+        content.add(
+          new SpanElement()..text = Utils.formatSize(int.parse(
+              _retainedSize.asValue.valueAsString))
+        );
+      }
+    } else {
+      content.add(
+        new SpanElement()..text = '...'
+      );
+    }
+    final button = new ButtonElement()..classes = ['retained_size']
+      ..disabled = _loadingRetainedBytes
+      ..text = '↺';
+    button.onClick.listen((_) async {
+        button.disabled = true;
+        _loadingRetainedBytes = true;
+        _retainedSize = await _retainedSizes.get(_isolate, _object.id);
+        _r.dirty();
+      });
+    content.add(button);
+    return content;
   }
 }
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
deleted file mode 100644
index 38bbe21..0000000
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ /dev/null
@@ -1,120 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="error_view.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="eval_link.html">
-
-<polymer-element name="object-common">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <div class="memberList">
-
-      <div class="memberItem">
-        <div class="memberName">class</div>
-        <div class="memberValue">
-          <class-ref ref="{{ object.clazz }}"></class-ref>
-        </div>
-      </div>
-
-      <div class="memberItem" title="Space for this object in memory">
-        <div class="memberName">shallow size</div>
-        <div class="memberValue">{{ object.size | formatSize }}</div>
-      </div>
-
-      <div class="memberItem" title="Space reachable from this object, excluding class references">
-        <div class="memberName">reachable size</div>
-        <div class="memberValue">
-          <template if="{{ reachableBytes == null }}">
-            <eval-link callback="{{ reachableSize }}"
-                       label="[calculate]">
-            </eval-link>
-          </template>
-          <template if="{{ reachableBytes != null }}">
-            {{ reachableBytes | formatSize }}
-          </template>
-        </div>
-      </div>
-
-      <div class="memberItem" title="Space that would be reclaimed if references to this object were replaced with null">
-        <div class="memberName">retained size</div>
-        <div class="memberValue">
-          <template if="{{ retainedBytes == null }}">
-            <eval-link callback="{{ retainedSize }}"
-                       label="[calculate]">
-            </eval-link>
-          </template>
-          <template if="{{ retainedBytes != null }}">
-            {{ retainedBytes | formatSize }}
-          </template>
-        </div>
-      </div>
-
-      <div class="memberItem">
-        <div class="memberName">retaining path</div>
-        <div class="memberValue">
-          <template if="{{ path == null }}">
-            <eval-link callback="{{ retainingPath }}"
-                       label="[find]"
-                       expr="20">
-            </eval-link>
-          </template>
-          <template if="{{ path != null }}">
-            <template if="{{ path['length'] == 0 }}">
-              &lt;root&gt;
-            </template>
-            <template repeat="{{ element in path['elements'] }}">
-            <div class="memberItem">
-              <div class="memberName">[{{ path['elements'].indexOf(element) }}]</div>
-              <div class="memberValue">
-                <template if="{{ element['parentField'] != null }}">
-                  from <any-service-ref ref="{{ element['parentField'] }}"></any-service-ref> of
-                </template>
-                <template if="{{ element['parentListIndex'] != null }}">
-                  from [{{ element['parentListIndex'] }}] of
-                </template>
-                <template if="{{ element['parentMapKey'] != null }}">
-                  from [<any-service-ref ref="{{ element['parentMapKey'] }}"></any-service-ref>] of
-                </template>
-                <template if="{{ element['_parentWordOffset'] != null }}">
-                  from word[{{ element['_parentWordOffset'] }}] of
-                </template>
-                <any-service-ref ref="{{ element['value'] }}"></any-service-ref>
-              </div>
-              </div>
-            </template>
-            <template if="{{ path['length'] > path['elements'].length }}">
-              showing {{ path['elements'].length }} of {{ path['length'] }}
-              <eval-link
-                callback="{{ retainingPath }}"
-                label="[find more]"
-                expr="{{ path['elements'].length * 2 }}">
-              </eval-link>
-            </template>
-          </template>
-        </div>
-      </div>
-
-      <div class="memberItem" title="Objects which directly reference this object">
-        <div class="memberName">inbound references</div>
-        <div class="memberValue">
-          <template if="{{ inboundReferences == null }}">
-            <eval-link callback="{{ fetchInboundReferences }}"
-                       label="[find]"
-                       expr="100">
-            </eval-link>
-          </template>
-          <template if="{{ inboundReferences != null }}">
-            <template if="{{ inboundReferences['references'].length == 0 }}">
-              &lt;root&gt;
-            </template>
-            <template repeat="{{ reference in inboundReferences['references'] }}">
-              <inbound-reference ref="{{ reference }}"></inbound-reference>
-            </template>
-          </template>
-        </div>
-      </div>
-
-   </div>
-  </template>
-</polymer-element>
-
-<script type="application/dart" src="object_common.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/object_common_wrapper.dart b/runtime/observatory/lib/src/elements/object_common_wrapper.dart
new file mode 100644
index 0000000..248280b
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/object_common_wrapper.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service.dart';
+import 'package:observatory/repositories.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+@bindable
+class ObjectCommonElementWrapper extends HtmlElement {
+
+  static const binder = const Binder<ObjectCommonElementWrapper>(const {
+      'object': #object
+    });
+
+  static const tag = const Tag<ObjectCommonElementWrapper>('object-common');
+
+  HeapObject _object;
+
+  HeapObject get object => _object;
+
+  void set object(HeapObject value) {
+    _object = value;
+    render();
+  }
+
+  ObjectCommonElementWrapper.created() : super.created() {
+    binder.registerCallback(this);
+    createShadowRoot();
+    render();
+  }
+
+  @override
+  void attached() {
+    super.attached();
+    render();
+  }
+
+  void render() {
+    shadowRoot.children = [];
+    if (_object == null) {
+      return;
+    }
+
+    shadowRoot.children = [
+      new StyleElement()
+        ..text = '''
+        object-common-wrapped a[href]:hover {
+            text-decoration: underline;
+        }
+        object-common-wrapped a[href] {
+            color: #0489c3;
+            text-decoration: none;
+        }
+        object-common-wrapped .memberList {
+          display: table;
+        }
+        object-common-wrapped .memberItem {
+          display: table-row;
+        }
+        object-common-wrapped .memberName,
+        object-common-wrapped .memberValue {
+          display: table-cell;
+          vertical-align: top;
+          padding: 3px 0 3px 1em;
+          font: 400 14px 'Montserrat', sans-serif;
+        }
+        object-common-wrapped button:hover {
+          background-color: transparent;
+          border: none;
+          text-decoration: underline;
+        }
+
+        object-common-wrapped button {
+          background-color: transparent;
+          border: none;
+          color: #0489c3;
+          padding: 0;
+          margin: -8px 4px;
+          font-size: 20px;
+          text-decoration: none;
+        }
+        object-common-wrapped .indent {
+          margin-left: 1.5em;
+          font: 400 14px 'Montserrat', sans-serif;
+          line-height: 150%;
+        }
+        object-common-wrapped .stackTraceBox {
+          margin-left: 1.5em;
+          background-color: #f5f5f5;
+          border: 1px solid #ccc;
+          padding: 10px;
+          font-family: consolas, courier, monospace;
+          font-size: 12px;
+          white-space: pre;
+          overflow-x: auto;
+        }''',
+      new ObjectCommonElement(_object.isolate, _object,
+                          new RetainedSizeRepository(),
+                          new ReachableSizeRepository(),
+                          new InboundReferencesRepository(),
+                          new RetainingPathRepository(),
+                          new InstanceRepository(),
+                          queue: ObservatoryApplication.app.queue)
+    ];
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/object_view.html b/runtime/observatory/lib/src/elements/object_view.html
index 9be06e8..7092ed5 100644
--- a/runtime/observatory/lib/src/elements/object_view.html
+++ b/runtime/observatory/lib/src/elements/object_view.html
@@ -1,7 +1,5 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
 <link rel="import" href="error_view.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="object_common.html">
 <link rel="import" href="eval_link.html">
 
 <polymer-element name="object-view">
diff --git a/runtime/observatory/lib/src/elements/objectpool_view.html b/runtime/observatory/lib/src/elements/objectpool_view.html
index 236fb84..555ddb4 100644
--- a/runtime/observatory/lib/src/elements/objectpool_view.html
+++ b/runtime/observatory/lib/src/elements/objectpool_view.html
@@ -1,7 +1,5 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
 <link rel="import" href="error_view.html">
-<link rel="import" href="inbound_reference.html">
-<link rel="import" href="object_common.html">
 <link rel="import" href="eval_link.html">
 
 <polymer-element name="objectpool-view">
diff --git a/runtime/observatory/lib/src/elements/ports.dart b/runtime/observatory/lib/src/elements/ports.dart
index 8f9cb39..183b686 100644
--- a/runtime/observatory/lib/src/elements/ports.dart
+++ b/runtime/observatory/lib/src/elements/ports.dart
@@ -2,31 +2,146 @@
 // for 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 ports;
-
+import 'dart:html';
 import 'dart:async';
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:polymer/polymer.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/view_footer.dart';
 
-@CustomTag('ports-page')
-class PortsPageElement extends ObservatoryElement {
-  PortsPageElement.created() : super.created();
+class PortsElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<PortsElement>('ports-page',
+                                             dependencies: const [
+                                               NavBarElement.tag,
+                                               NavTopMenuElement.tag,
+                                               NavVMMenuElement.tag,
+                                               NavIsolateMenuElement.tag,
+                                               NavMenuElement.tag,
+                                               NavRefreshElement.tag,
+                                               NavNotifyElement.tag,
+                                               InstanceRefElement.tag,
+                                               ViewFooterElement.tag
+                                             ]);
 
-  @observable Isolate isolate;
-  @observable var /*ObservableList | ServiceObject*/ ports;
+  RenderingScheduler<PortsElement> _r;
 
-  void isolateChanged(oldValue) {
-    if (isolate != null) {
-      isolate.getPorts().then(_refreshView);
+  Stream<RenderedEvent<PortsElement>> get onRendered => _r.onRendered;
+
+  M.VM _vm;
+  M.IsolateRef _isolate;
+  M.EventRepository _events;
+  M.NotificationRepository _notifications;
+  M.PortsRepository _ports;
+  M.InstanceRepository _instances;
+  M.Ports _isolatePorts;
+
+
+  M.IsolateRef get isolate => _isolate;
+  M.NotificationRepository get notifications => _notifications;
+  M.PortsRepository get ports => _ports;
+  M.VMRef get vm => _vm;
+
+  factory PortsElement(M.VM vm, M.IsolateRef isolate,
+                            M.EventRepository events,
+                            M.NotificationRepository notifications,
+                            M.PortsRepository ports,
+                            M.InstanceRepository instances,
+                            {RenderingQueue queue}) {
+    assert(vm != null);
+    assert(isolate != null);
+    assert(events != null);
+    assert(notifications != null);
+    assert(ports != null);
+    assert(instances != null);
+    PortsElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._vm = vm;
+    e._isolate = isolate;
+    e._events = events;
+    e._notifications = notifications;
+    e._ports = ports;
+    e._instances = instances;
+    return e;
+  }
+
+  PortsElement.created() : super.created();
+
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
+    _refresh();
+  }
+
+  @override
+  void detached() {
+    super.detached();
+    children = [];
+    _r.disable(notify: true);
+  }
+
+  void render() {
+    children = [
+      new NavBarElement(queue: _r.queue)
+        ..children = [
+          new NavTopMenuElement(queue: _r.queue),
+          new NavVMMenuElement(_vm, _events, queue: _r.queue),
+          new NavIsolateMenuElement(_isolate, _events, queue: _r.queue),
+          new NavMenuElement('ports', link: Uris.ports(_isolate), last: true,
+                             queue: _r.queue),
+          new NavRefreshElement(queue: _r.queue)
+            ..onRefresh.listen((_) => _refresh()),
+          new NavNotifyElement(_notifications, queue: _r.queue)
+        ],
+      new DivElement()
+        ..classes = ['content-centered']
+        ..children = [
+          new HeadingElement.h1()..text = 'Ports',
+          new BRElement(), new HRElement(),
+          new DivElement()
+            ..children = _createList(),
+          new HRElement()
+        ],
+      new ViewFooterElement(queue: _r.queue)
+    ];
+  }
+
+  List<Element> _createList() {
+    if (_isolatePorts == null) {
+      return const [];
     }
+    int i = 0;
+    return _isolatePorts.elements.map((port) =>
+      new DivElement()..classes = ['memberItem']
+        ..children = [
+          new DivElement()..classes = ['memberName']
+            ..children = [
+              new SpanElement()..classes = ['port-number']
+                ..text = '[ ${++i} ] ',
+              new SpanElement()..text = '${port.name}'
+            ],
+          new DivElement()..classes = ['memberValue']
+            ..children = [
+              anyRef(_isolate, port.handler, _instances, queue: _r.queue)
+            ]
+        ]
+    ).toList();
   }
 
-  Future refresh() {
-    return isolate.getPorts().then(_refreshView);
-  }
-
-  _refreshView(/*ObservableList | ServiceObject*/ object) {
-    ports = object['ports'];
+  Future _refresh() async {
+    _isolatePorts = null;
+    _r.dirty();
+    _isolatePorts = await _ports.get(_isolate);
+    _r.dirty();
   }
 }
diff --git a/runtime/observatory/lib/src/elements/ports.html b/runtime/observatory/lib/src/elements/ports.html
deleted file mode 100644
index af2adfb..0000000
--- a/runtime/observatory/lib/src/elements/ports.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="ports-page">
-  <template>
-    <link rel="stylesheet" href="css/shared.css">
-    <style>
-      ul li:hover:not(.selected) {
-        background-color: #FFF3E3;
-      }
-      .selected {
-        background-color: #0489c3;
-      }
-      .graph {
-        min-height: 600px;
-      }
-    </style>
-    <nav-bar>
-      <top-nav-menu></top-nav-menu>
-      <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
-      <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
-      <nav-menu link="{{ makeLink('/ports', isolate) }}" anchor="ports" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refresh }}"></nav-refresh>
-      <nav-notify notifications="{{ app.notifications }}"></nav-notify>
-    </nav-bar>
-    <div class="content">
-      <h1>Ports ({{ports.length}})</h1>
-      <hr>
-      <div class="memberList">
-        <template repeat="{{ port in ports }}">
-          <div class="memberItem">
-            <div class="memberName">{{ port['name'] }}</div>
-            <div class="memberValue">
-              <any-service-ref ref="{{ port['handler'] }}"></any-service-ref>
-            </div>
-          </div>
-        </template>
-      </div>
-      <hr>
-      <view-footer></view-footer>
-    </div>
-  </template>
-</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/retaining_path.dart b/runtime/observatory/lib/src/elements/retaining_path.dart
new file mode 100644
index 0000000..b0f2ea0
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/retaining_path.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import 'package:observatory/src/elements/helpers/any_ref.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+
+class RetainingPathElement extends HtmlElement implements Renderable {
+  static const tag = const Tag<RetainingPathElement>('retaining-path',
+    dependencies: const [
+        CurlyBlockElement.tag,
+        InstanceRefElement.tag
+    ]);
+
+  RenderingScheduler<RetainingPathElement> _r;
+
+  Stream<RenderedEvent<RetainingPathElement>> get onRendered =>
+    _r.onRendered;
+
+  M.IsolateRef _isolate;
+  M.ObjectRef _object;
+  M.RetainingPathRepository _retainingPaths;
+  M.InstanceRepository _instances;
+  M.RetainingPath _path;
+  bool _expanded = false;
+
+  M.IsolateRef get isolate => _isolate;
+  M.ObjectRef get object => _object;
+
+  factory RetainingPathElement(M.IsolateRef isolate, M.ObjectRef object,
+      M.RetainingPathRepository retainingPaths, M.InstanceRepository instances,
+      {RenderingQueue queue}) {
+    assert(isolate != null);
+    assert(object != null);
+    assert(retainingPaths != null);
+    assert(instances != null);
+    RetainingPathElement e = document.createElement(tag.name);
+    e._r = new RenderingScheduler(e, queue: queue);
+    e._isolate = isolate;
+    e._object = object;
+    e._retainingPaths = retainingPaths;
+    e._instances = instances;
+    return e;
+  }
+
+  RetainingPathElement.created() : super.created();
+
+  @override
+  void attached() {
+    super.attached();
+    _r.enable();
+  }
+
+  @override
+  void detached() {
+    super.detached();
+    children = [];
+    _r.disable(notify: true);
+  }
+
+  void render() {
+    children = [
+      new CurlyBlockElement(expanded: _expanded, queue: _r.queue)
+        ..children = _createContent()
+        ..onToggle.listen((e) async {
+          _expanded = e.control.expanded;
+          if (_expanded) {
+            e.control.disabled = true;
+            await _refresh();
+            e.control.disabled = false;
+          }
+        })
+    ];
+  }
+
+  Future _refresh() async {
+    _path = null;
+    _path = await _retainingPaths.get(_isolate, _object.id);
+    _r.dirty();
+  }
+
+  List<Element> _createContent() {
+    if (_path == null) {
+      return [
+        new SpanElement()..text = 'Loading'
+      ];
+    }
+    return _path.elements.map(_createItem).toList();
+  }
+
+  Element _createItem(M.RetainingPathItem item) {
+    final content = <Element>[];
+
+    if (item.parentField != null) {
+      content.add(
+        new SpanElement()
+          ..children = [
+              new SpanElement()..text = 'from ',
+              anyRef(_isolate, item.parentField, _instances, queue: _r.queue),
+              new SpanElement()..text = ' of ',
+          ]);
+    } else if (item.parentListIndex != null) {
+      content.add(
+        new SpanElement()
+          ..text = 'from [ ${item.parentListIndex} ] of ');
+    } else if (item.parentWordOffset != null) {
+      content.add(
+        new SpanElement()
+          ..text = 'from word [ ${item.parentWordOffset} ] of ');
+    } else {
+      content.add(new SpanElement()..text = 'from ');
+    }
+
+    content.add(
+      anyRef(_isolate, item.source, _instances, queue: _r.queue)
+    );
+
+    return new DivElement()..classes = ['indent']..children = content;
+  }
+}
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 7a93447..1c48f86 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -153,7 +153,7 @@
         break;
       default:
         element = anyRef(obj.isolate, obj,
-            new InstanceRepository(obj.isolate), queue: app.queue);
+            new InstanceRepository(), queue: app.queue);
         break;
     }
     if (element == null) {
diff --git a/runtime/observatory/lib/src/elements/service_view.dart b/runtime/observatory/lib/src/elements/service_view.dart
index a8aa312..6bf3808 100644
--- a/runtime/observatory/lib/src/elements/service_view.dart
+++ b/runtime/observatory/lib/src/elements/service_view.dart
@@ -30,10 +30,6 @@
         CodeViewElement element = new Element.tag('code-view');
         element.code = object;
         return element;
-      case 'Context':
-        ContextViewElement element = new Element.tag('context-view');
-        element.context = object;
-        return element;
       case 'Error':
         ErrorViewElement element = new Element.tag('error-view');
         element.error = object;
@@ -53,10 +49,6 @@
       case 'Object':
         return (object) {
           switch (object.vmType) {
-            case 'ICData':
-              ICDataViewElement element = new Element.tag('icdata-view');
-              element.icData = object;
-              return element;
             case 'MegamorphicCache':
               MegamorphicCacheViewElement element =
                   new Element.tag('megamorphiccache-view');
diff --git a/runtime/observatory/lib/src/elements/service_view.html b/runtime/observatory/lib/src/elements/service_view.html
index 23c5597..6bd7e63 100644
--- a/runtime/observatory/lib/src/elements/service_view.html
+++ b/runtime/observatory/lib/src/elements/service_view.html
@@ -1,15 +1,12 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
 <link rel="import" href="class_view.html">
 <link rel="import" href="code_view.html">
-<link rel="import" href="context_view.html">
 <link rel="import" href="error_view.html">
 <link rel="import" href="field_view.html">
 <link rel="import" href="function_view.html">
 <link rel="import" href="heap_map.html">
 <link rel="import" href="instance_view.html">
 <link rel="import" href="library_view.html">
-<link rel="import" href="heap_snapshot.html">
-
 <link rel="import" href="script_view.html">
 <link rel="import" href="vm_view.html">
 <polymer-element name="service-view">
diff --git a/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
new file mode 100644
index 0000000..06241f9
--- /dev/null
+++ b/runtime/observatory/lib/src/heap_snapshot/heap_snapshot.dart
@@ -0,0 +1,230 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of heap_snapshot;
+
+class HeapSnapshot implements M.HeapSnapshot {
+  ObjectGraph graph;
+  DateTime timestamp;
+  int get objects => graph.vertexCount;
+  int get references => graph.edgeCount;
+  int get size => graph.size;
+  HeapSnapshotDominatorNode dominatorTree;
+  List<MergedVertex> classReferences;
+
+  static Future sleep([Duration duration = const Duration(microseconds: 0)]) {
+    final Completer completer = new Completer();
+    new Timer(duration, () => completer.complete() );
+    return completer.future;
+  }
+
+  Stream<List> loadProgress(S.Isolate isolate, S.RawHeapSnapshot raw) {
+    final progress = new StreamController<List>.broadcast();
+    progress.add(['', 0.0]);
+    graph = new ObjectGraph(raw.chunks, raw.count);
+    var signal = (String description, double p) {
+      progress.add([description, p]);
+      return sleep();
+    };
+    (() async {
+      timestamp = new DateTime.now();
+      final stream = graph.process();
+      stream.listen((status) {
+        status[1] /= 2.0;
+        progress.add(status);
+      });
+      await stream.last;
+      dominatorTree = new HeapSnapshotDominatorNode(isolate, graph.root);
+      classReferences = await buildMergedVertices(isolate, graph, signal);
+      progress.close();
+    }());
+    return progress.stream;
+  }
+
+  Future<List<MergedVertex>> buildMergedVertices(S.Isolate isolate,
+                                                 ObjectGraph graph,
+                                                 signal) async {
+    final cidToMergedVertex = {};
+
+    int count = 0;
+    final Stopwatch watch = new Stopwatch();
+    watch.start();
+    var needToUpdate = () {
+      count++;
+      if (((count % 256) == 0) && (watch.elapsedMilliseconds > 16)) {
+        watch.reset();
+        return true;
+      }
+      return false;
+    };
+    final length = graph.vertices.length;
+    for (final vertex in graph.vertices) {
+      if (vertex.vmCid == 0) {
+        continue;
+      }
+      if (needToUpdate()) {
+        await signal('', count * 50.0 / length + 50);
+      }
+      final cid = vertex.vmCid;
+      MergedVertex source = cidToMergedVertex[cid];
+      if (source == null) {
+        cidToMergedVertex[cid] = source = new MergedVertex(isolate, cid);
+      }
+
+      source.instances++;
+      source.shallowSize += vertex.shallowSize ?? 0;
+
+      for (final vertex2 in vertex.successors) {
+        if (vertex2.vmCid == 0) {
+          continue;
+        }
+        final cid2 = vertex2.vmCid;
+        MergedEdge edge = source.outgoingEdges[cid2];
+        if (edge == null) {
+          MergedVertex target = cidToMergedVertex[cid2];
+          if (target == null) {
+            cidToMergedVertex[cid2] = target = new MergedVertex(isolate, cid2);
+          }
+          edge = new MergedEdge(source, target);
+          source.outgoingEdges[cid2] = edge;
+          target.incomingEdges.add(edge);
+        }
+        edge.count++;
+        // An over-estimate if there are multiple references to the same object.
+        edge.shallowSize += vertex2.shallowSize ?? 0;
+      }
+    }
+    return cidToMergedVertex.values.toList();
+  }
+
+  List<Future<S.ServiceObject>> getMostRetained(S.Isolate isolate,
+                                                {int classId, int limit}) {
+    var result = [];
+    for (ObjectVertex v in graph.getMostRetained(classId: classId,
+                                                 limit: limit)) {
+      result.add(isolate.getObjectByAddress(v.address)
+                        .then((S.ServiceObject obj) {
+        if (obj is S.HeapObject) {
+          obj.retainedSize = v.retainedSize;
+        } else {
+          print("${obj.runtimeType} should be a HeapObject");
+        }
+        return obj;
+      }));
+    }
+    return result;
+  }
+}
+
+class HeapSnapshotDominatorNode implements M.HeapSnapshotDominatorNode {
+  final ObjectVertex v;
+  final S.Isolate isolate;
+  S.HeapObject _preloaded;
+
+  Future<S.HeapObject> get object {
+    if (_preloaded != null) {
+      return new Future.value(_preloaded);
+    } else {
+      return isolate.getObjectByAddress(v.address).then((S.HeapObject obj) {
+        return _preloaded = obj;
+      });
+    }
+  }
+  Iterable<HeapSnapshotDominatorNode> _children;
+  Iterable<HeapSnapshotDominatorNode> get children {
+    if (_children != null) {
+      return _children;
+    } else {
+      return _children = new List.unmodifiable(
+        v.dominatorTreeChildren().map((v) {
+          return new HeapSnapshotDominatorNode(isolate, v);
+        })
+      );
+    }
+  }
+  int get retainedSize => v.retainedSize;
+  int get shallowSize => v.shallowSize;
+
+  HeapSnapshotDominatorNode(S.Isolate isolate, ObjectVertex vertex)
+    : isolate = isolate,
+      v = vertex;
+}
+
+class MergedEdge {
+  final MergedVertex sourceVertex;
+  final MergedVertex targetVertex;
+  int count = 0;
+  int shallowSize = 0;
+  int retainedSize = 0;
+
+  MergedEdge(this.sourceVertex, this.targetVertex);
+}
+
+class MergedVertex implements M.HeapSnapshotClassReferences {
+  final int cid;
+  final S.Isolate isolate;
+  S.Class get clazz => isolate.getClassByCid(cid);
+  int instances = 0;
+  int shallowSize = 0;
+  int retainedSize = 0;
+
+  List<MergedEdge> incomingEdges = new List<MergedEdge>();
+  Map<int, MergedEdge> outgoingEdges = new Map<int, MergedEdge>();
+
+  Iterable<HeapSnapshotClassInbound> _inbounds;
+  Iterable<HeapSnapshotClassInbound> get inbounds {
+    if (_inbounds != null) {
+      return _inbounds;
+    } else {
+      // It is important to keep the template.
+      // https://github.com/dart-lang/sdk/issues/27144
+      return _inbounds = new List<HeapSnapshotClassInbound>.unmodifiable(
+        incomingEdges.map((edge) {
+          return new HeapSnapshotClassInbound(this, edge);
+        })
+      );
+    }
+  }
+
+  Iterable<HeapSnapshotClassOutbound> _outbounds;
+  Iterable<HeapSnapshotClassOutbound> get outbounds {
+    if (_outbounds != null) {
+      return _outbounds;
+    } else {
+      // It is important to keep the template.
+      // https://github.com/dart-lang/sdk/issues/27144
+      return _outbounds = new List<HeapSnapshotClassOutbound>.unmodifiable(
+        outgoingEdges.values.map((edge) {
+          return new HeapSnapshotClassOutbound(this, edge);
+        })
+      );
+    }
+  }
+
+  MergedVertex(this.isolate, this.cid);
+}
+
+class HeapSnapshotClassInbound implements M.HeapSnapshotClassInbound {
+  final MergedVertex vertex;
+  final MergedEdge edge;
+  S.Class get source => edge.sourceVertex != vertex ? edge.sourceVertex.clazz
+                                                    : edge.targetVertex.clazz;
+  int get count => edge.count;
+  int get shallowSize => edge.shallowSize;
+  int get retainedSize => edge.retainedSize;
+
+  HeapSnapshotClassInbound(this.vertex, this.edge);
+}
+
+class HeapSnapshotClassOutbound implements M.HeapSnapshotClassOutbound {
+  final MergedVertex vertex;
+  final MergedEdge edge;
+  S.Class get target => edge.sourceVertex != vertex ? edge.sourceVertex.clazz
+                                                    : edge.targetVertex.clazz;
+  int get count => edge.count;
+  int get shallowSize => edge.shallowSize;
+  int get retainedSize => edge.retainedSize;
+
+  HeapSnapshotClassOutbound(this.vertex, this.edge);
+}
diff --git a/runtime/observatory/lib/src/models/objects/context.dart b/runtime/observatory/lib/src/models/objects/context.dart
index 46d0a12..7378086 100644
--- a/runtime/observatory/lib/src/models/objects/context.dart
+++ b/runtime/observatory/lib/src/models/objects/context.dart
@@ -14,5 +14,9 @@
   Context get parentContext;
 
   // The variables in this context object.
-  //Iterable<ContextElement> get variables;
+  Iterable<ContextElement> get variables;
+}
+
+abstract class ContextElement {
+  Guarded<InstanceRef> get value;
 }
diff --git a/runtime/observatory/lib/src/models/objects/function.dart b/runtime/observatory/lib/src/models/objects/function.dart
index e52c564..933954f 100644
--- a/runtime/observatory/lib/src/models/objects/function.dart
+++ b/runtime/observatory/lib/src/models/objects/function.dart
@@ -42,6 +42,22 @@
 bool hasDartCode(FunctionKind kind) =>
     isDartFunction(kind) || isStubFunction(kind);
 
+String getFunctionFullName(FunctionRef function) {
+  var content = <String>[
+    function.name
+  ];
+  ObjectRef owner = function.dartOwner;
+  while (owner is FunctionRef) {
+    FunctionRef function = (owner as FunctionRef);
+    content.add(function.name);
+    owner = function.dartOwner;
+  }
+  if (owner is ClassRef) {
+    content.add(owner.name);
+  }
+  return content.reversed.join('.');
+}
+
 abstract class FunctionRef extends ObjectRef {
   /// The name of this class.
   String get name;
diff --git a/runtime/observatory/lib/src/models/objects/heap_snapshot.dart b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
new file mode 100644
index 0000000..19392f9
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/heap_snapshot.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of models;
+
+abstract class HeapSnapshot {
+  DateTime get timestamp;
+  int get objects;
+  int get references;
+  int get size;
+  HeapSnapshotDominatorNode get dominatorTree;
+  Iterable<HeapSnapshotClassReferences> get classReferences;
+}
+
+abstract class HeapSnapshotDominatorNode {
+  int get shallowSize;
+  int get retainedSize;
+  Future<ObjectRef> get object;
+  Iterable<HeapSnapshotDominatorNode> get children;
+}
+
+abstract class HeapSnapshotClassReferences {
+  ClassRef get clazz;
+  int get instances;
+  int get shallowSize;
+  int get retainedSize;
+  Iterable<HeapSnapshotClassInbound> get inbounds;
+  Iterable<HeapSnapshotClassOutbound> get outbounds;
+}
+
+abstract class HeapSnapshotClassInbound {
+  ClassRef get source;
+  int get count;
+  int get shallowSize;
+  int get retainedSize;
+}
+
+abstract class HeapSnapshotClassOutbound {
+  ClassRef get target;
+  int get count;
+  int get shallowSize;
+  int get retainedSize;
+}
diff --git a/runtime/observatory/lib/src/models/objects/icdata.dart b/runtime/observatory/lib/src/models/objects/icdata.dart
index 0dcb9e9..d975301 100644
--- a/runtime/observatory/lib/src/models/objects/icdata.dart
+++ b/runtime/observatory/lib/src/models/objects/icdata.dart
@@ -7,3 +7,9 @@
 abstract class ICDataRef extends ObjectRef {
   String get selector;
 }
+
+abstract class ICData extends Object implements ICDataRef {
+  ObjectRef get dartOwner;
+  InstanceRef get argumentsDescriptor;
+  InstanceRef get entries;
+}
diff --git a/runtime/observatory/lib/src/models/objects/inbound_references.dart b/runtime/observatory/lib/src/models/objects/inbound_references.dart
new file mode 100644
index 0000000..13c3c03
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/inbound_references.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of models;
+
+abstract class InboundReferences {
+  Iterable<InboundReference> get elements;
+}
+
+abstract class InboundReference {
+  ObjectRef get source;
+  /// [optional]
+  ObjectRef get parentField;
+  /// [optional]
+  int get parentListIndex;
+  /// [optional]
+  int get parentWordOffset;
+}
diff --git a/runtime/observatory/lib/src/models/objects/ports.dart b/runtime/observatory/lib/src/models/objects/ports.dart
new file mode 100644
index 0000000..209357e
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/ports.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of models;
+
+abstract class Ports {
+  Iterable<Port> get elements;
+}
+
+abstract class Port {
+  String get name;
+  ObjectRef get handler;
+}
diff --git a/runtime/observatory/lib/src/models/objects/retaining_path.dart b/runtime/observatory/lib/src/models/objects/retaining_path.dart
new file mode 100644
index 0000000..d16112e
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/retaining_path.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of models;
+
+abstract class RetainingPath {
+  Iterable<RetainingPathItem> get elements;
+}
+
+abstract class RetainingPathItem {
+  ObjectRef get source;
+  /// [optional]
+  /// FieldRef or InstanceRef (null)
+  ObjectRef get parentField;
+  /// [optional]
+  int get parentListIndex;
+  /// [optional]
+  int get parentWordOffset;
+}
diff --git a/runtime/observatory/lib/src/models/objects/sample_profile.dart b/runtime/observatory/lib/src/models/objects/sample_profile.dart
index 5c5a983..cd0a805 100644
--- a/runtime/observatory/lib/src/models/objects/sample_profile.dart
+++ b/runtime/observatory/lib/src/models/objects/sample_profile.dart
@@ -14,6 +14,8 @@
   int get stackDepth;
   double get sampleRate;
   double get timeSpan;
+  Iterable<ProfileCode> get codes;
+  Iterable<ProfileFunction> get functions;
 
   FunctionCallTree loadFunctionTree(ProfileTreeDirection direction);
   CodeCallTree loadCodeTree(ProfileTreeDirection direction);
@@ -26,10 +28,14 @@
 
 abstract class ProfileCode extends Profile {
   CodeRef get code;
+  Map<ProfileCode, int> get callers;
+  Map<ProfileCode, int> get callees;
 }
 
 abstract class ProfileFunction extends Profile {
   FunctionRef get function;
+  Map<ProfileFunction, int> get callers;
+  Map<ProfileFunction, int> get callees;
 }
 
 typedef bool CallTreeNodeFilter(CallTreeNode);
diff --git a/runtime/observatory/lib/src/models/repositories/context.dart b/runtime/observatory/lib/src/models/repositories/context.dart
new file mode 100644
index 0000000..7565d68
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/context.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ContextRepository{
+  Future<Context> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/heap_snapshot.dart b/runtime/observatory/lib/src/models/repositories/heap_snapshot.dart
new file mode 100644
index 0000000..66dc5b8
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/heap_snapshot.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+enum HeapSnapshotLoadingStatus {
+  fetching,
+  loading,
+  loaded
+}
+
+bool isHeapSnapshotProgressRunning(HeapSnapshotLoadingStatus status) {
+  switch (status) {
+    case HeapSnapshotLoadingStatus.fetching:
+    case HeapSnapshotLoadingStatus.loading:
+      return true;
+    default:
+      return false;
+  }
+}
+
+abstract class HeapSnapshotLoadingProgressEvent {
+  HeapSnapshotLoadingProgress get progress;
+}
+
+abstract class HeapSnapshotLoadingProgress {
+  HeapSnapshotLoadingStatus get status;
+  String get stepDescription;
+  double get progress;
+  Duration get fetchingTime;
+  Duration get loadingTime;
+  HeapSnapshot get snapshot;
+}
+
+abstract class HeapSnapshotRepository {
+  Stream<HeapSnapshotLoadingProgressEvent> get(IsolateRef isolate,
+                                               {bool gc: false});
+}
diff --git a/runtime/observatory/lib/src/models/repositories/icdata.dart b/runtime/observatory/lib/src/models/repositories/icdata.dart
new file mode 100644
index 0000000..7b3b752
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/icdata.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ICDataRepository {
+  Future<ICData> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/inbound_references.dart b/runtime/observatory/lib/src/models/repositories/inbound_references.dart
new file mode 100644
index 0000000..09cdcca
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/inbound_references.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class InboundReferencesRepository {
+  Future<InboundReferences> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/instance.dart b/runtime/observatory/lib/src/models/repositories/instance.dart
index 673d6b6..ab30965 100644
--- a/runtime/observatory/lib/src/models/repositories/instance.dart
+++ b/runtime/observatory/lib/src/models/repositories/instance.dart
@@ -5,5 +5,5 @@
 part of models;
 
 abstract class InstanceRepository{
-  Future<Instance> get(String id, {int count});
+  Future<Instance> get(IsolateRef isolate, String id, {int count});
 }
diff --git a/runtime/observatory/lib/src/models/repositories/ports.dart b/runtime/observatory/lib/src/models/repositories/ports.dart
new file mode 100644
index 0000000..bbb8c80
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/ports.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class PortsRepository {
+  Future<Ports> get(IsolateRef isolate);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/reachable_size.dart b/runtime/observatory/lib/src/models/repositories/reachable_size.dart
new file mode 100644
index 0000000..fc1292fb
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/reachable_size.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ReachableSizeRepository {
+  Future<Guarded<Instance>> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/retained_size.dart b/runtime/observatory/lib/src/models/repositories/retained_size.dart
new file mode 100644
index 0000000..3b4fe8e
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/retained_size.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class RetainedSizeRepository {
+  Future<Guarded<Instance>> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/models/repositories/retaining_path.dart b/runtime/observatory/lib/src/models/repositories/retaining_path.dart
new file mode 100644
index 0000000..1999846
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/retaining_path.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class RetainingPathRepository {
+  Future<RetainingPath> get(IsolateRef isolate, String id);
+}
diff --git a/runtime/observatory/lib/src/repositories/context.dart b/runtime/observatory/lib/src/repositories/context.dart
new file mode 100644
index 0000000..a088428
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/context.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class ContextRepository extends M.ContextRepository {
+  ContextRepository();
+
+  Future<M.Context> get(M.IsolateRef i, String id) async{
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    return (await isolate.getObject(id)) as S.Context;
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/heap_snapshot.dart b/runtime/observatory/lib/src/repositories/heap_snapshot.dart
new file mode 100644
index 0000000..0489197
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/heap_snapshot.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class HeapSnapshotLoadingProgressEvent
+  implements M.HeapSnapshotLoadingProgressEvent {
+  final HeapSnapshotLoadingProgress progress;
+  HeapSnapshotLoadingProgressEvent(this.progress);
+}
+
+class HeapSnapshotLoadingProgress extends M.HeapSnapshotLoadingProgress {
+  StreamController<HeapSnapshotLoadingProgressEvent> _onProgress =
+      new StreamController<HeapSnapshotLoadingProgressEvent>.broadcast();
+  Stream<HeapSnapshotLoadingProgressEvent> get onProgress =>
+      _onProgress.stream;
+
+  final S.Isolate isolate;
+  final bool gc;
+
+  M.HeapSnapshotLoadingStatus _status = M.HeapSnapshotLoadingStatus.fetching;
+  String _stepDescription = '';
+  double _progress = 0.0;
+  final Stopwatch _fetchingTime = new Stopwatch();
+  final Stopwatch  _loadingTime = new Stopwatch();
+  HeapSnapshot _snapshot;
+
+  M.HeapSnapshotLoadingStatus get status => _status;
+  String get stepDescription => _stepDescription;
+  double get progress => _progress;
+  Duration get fetchingTime => _fetchingTime.elapsed;
+  Duration get loadingTime => _loadingTime.elapsed;
+  HeapSnapshot get snapshot => _snapshot;
+
+  HeapSnapshotLoadingProgress(this.isolate, this.gc) {
+      _run();
+  }
+
+  Future _run() async {
+    _fetchingTime.start();
+    try {
+      _status = M.HeapSnapshotLoadingStatus.fetching;
+      _triggerOnProgress();
+
+      await isolate.getClassRefs();
+
+      final stream = isolate.fetchHeapSnapshot(gc);
+
+      stream.listen((status) {
+        if (status is List) {
+          _progress = status[0] * 100.0 / status[1];
+          _stepDescription = 'Receiving snapshot chunk ${status[0] + 1}'
+                            ' of ${status[1]}...';
+          _triggerOnProgress();
+        }
+      });
+
+      final response = await stream.last;
+
+      _fetchingTime.stop();
+      _loadingTime.start();
+      _status = M.HeapSnapshotLoadingStatus.loading;
+      _stepDescription = '';
+      _triggerOnProgress();
+
+      HeapSnapshot snapshot = new HeapSnapshot();
+
+      Stream<List> progress = snapshot.loadProgress(isolate, response);
+      progress.listen((value) {
+        _stepDescription = value[0];
+        _progress = value[1];
+        _triggerOnProgress();
+      });
+
+      await progress.drain();
+
+      _snapshot = snapshot;
+
+      _loadingTime.stop();
+      _status = M.HeapSnapshotLoadingStatus.loaded;
+      _triggerOnProgress();
+    } finally {
+      _onProgress.close();
+    }
+  }
+
+  void _triggerOnProgress() {
+    _onProgress.add(new HeapSnapshotLoadingProgressEvent(this));
+  }
+
+  void reuse() {
+    _onProgress =
+      new StreamController<HeapSnapshotLoadingProgressEvent>.broadcast();
+    (() async {
+      _triggerOnProgress();
+      _onProgress.close();
+    }());
+  }
+}
+
+class HeapSnapshotRepository
+    implements M.HeapSnapshotRepository {
+
+  Stream<HeapSnapshotLoadingProgressEvent> get(M.IsolateRef i,
+                                               {bool gc: false}) {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    assert(gc != null);
+    return new HeapSnapshotLoadingProgress(isolate, gc).onProgress;
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/icdata.dart b/runtime/observatory/lib/src/repositories/icdata.dart
new file mode 100644
index 0000000..18ce814
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/icdata.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class ICDataRepository extends M.ICDataRepository {
+  ICDataRepository();
+
+  Future<M.ICData> get(M.IsolateRef i, String id) async{
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    return (await isolate.getObject(id)) as S.ICData;
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/inbound_references.dart b/runtime/observatory/lib/src/repositories/inbound_references.dart
new file mode 100644
index 0000000..28fd850
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/inbound_references.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class InboundReferencesRepository implements M.InboundReferencesRepository {
+  Future<M.InboundReferences> get(M.IsolateRef i, String id) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    final response = await isolate.invokeRpc('_getInboundReferences', {
+        'targetId' : id,
+        'limit': 100
+    });
+    return new S.InboundReferences(response);
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/instance.dart b/runtime/observatory/lib/src/repositories/instance.dart
index 4f416bd..8f2b756 100644
--- a/runtime/observatory/lib/src/repositories/instance.dart
+++ b/runtime/observatory/lib/src/repositories/instance.dart
@@ -5,11 +5,12 @@
 part of repositories;
 
 class InstanceRepository extends M.InstanceRepository {
-  final S.Isolate isolate;
+  InstanceRepository();
 
-  InstanceRepository(this.isolate);
-
-  Future<M.Instance> get(String id, {int count: S.kDefaultFieldLimit}) async{
+  Future<M.Instance> get(M.IsolateRef i, String id,
+                         {int count: S.kDefaultFieldLimit}) async{
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
     assert(count != null);
     return (await isolate.getObject(id, count: count)) as S.Instance;
   }
diff --git a/runtime/observatory/lib/src/repositories/ports.dart b/runtime/observatory/lib/src/repositories/ports.dart
new file mode 100644
index 0000000..324ef74
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/ports.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class PortsRepository implements M.PortsRepository {
+  Future<M.Ports> get(M.IsolateRef i) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    final response = await isolate.invokeRpc('_getPorts', {});
+    return new S.Ports(response);
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/reachable_size.dart b/runtime/observatory/lib/src/repositories/reachable_size.dart
new file mode 100644
index 0000000..945cd9f
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/reachable_size.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class ReachableSizeRepository implements M.ReachableSizeRepository {
+
+  Future<M.Guarded<M.Instance>> get(M.IsolateRef i, String id) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    final response = await isolate.invokeRpc('_getReachableSize', {
+        'targetId' : id
+    });
+    return new S.Guarded<S.Instance>(response);
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/retained_size.dart b/runtime/observatory/lib/src/repositories/retained_size.dart
new file mode 100644
index 0000000..b81da34
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/retained_size.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class RetainedSizeRepository implements M.RetainedSizeRepository {
+
+  Future<M.Guarded<M.Instance>> get(M.IsolateRef i, String id) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    final response = await isolate.invokeRpc('_getRetainedSize', {
+        'targetId' : id
+    });
+    return new S.Guarded<S.Instance>(response);
+  }
+}
diff --git a/runtime/observatory/lib/src/repositories/retaining_path.dart b/runtime/observatory/lib/src/repositories/retaining_path.dart
new file mode 100644
index 0000000..c658f91
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/retaining_path.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class RetainingPathRepository implements M.RetainingPathRepository {
+
+  Future<M.RetainingPath> get(M.IsolateRef i, String id) async {
+    S.Isolate isolate = i as S.Isolate;
+    assert(isolate != null);
+    final response = await isolate.invokeRpc('_getRetainingPath', {
+        'targetId' : id,
+        'limit': 100
+    });
+    return new S.RetainingPath(response);
+  }
+}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 2d563dd..0ebf02e 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -93,7 +93,7 @@
 }
 
 /// A [ServiceObject] represents a persistent object within the vm.
-abstract class ServiceObject extends Observable implements M.ObjectRef {
+abstract class ServiceObject extends Observable {
   static int LexicalSortName(ServiceObject o1, ServiceObject o2) {
     return o1.name.compareTo(o2.name);
   }
@@ -380,7 +380,7 @@
   }
 }
 
-abstract class HeapObject extends ServiceObject {
+abstract class HeapObject extends ServiceObject implements M.Object {
   @observable Class clazz;
   @observable int size;
   @observable int retainedSize;
@@ -1078,6 +1078,65 @@
   }
 }
 
+class InboundReferences implements M.InboundReferences {
+  final Iterable<InboundReference> elements;
+
+  InboundReferences(ServiceMap map)
+    : this.elements = map['references']
+        .map((rmap) => new InboundReference(rmap));
+}
+
+class InboundReference implements M.InboundReference {
+  final HeapObject source;
+  final Instance parentField;
+  final int parentListIndex;
+  final int parentWordOffset;
+
+  InboundReference(ServiceMap map)
+    : source = map['source'],
+      parentField = map['parentField'],
+      parentListIndex = map['parentListIndex'],
+      parentWordOffset = map['_parentWordOffset'];
+}
+
+class RetainingPath implements M.RetainingPath {
+  final Iterable<RetainingPathItem> elements;
+
+  RetainingPath(ServiceMap map)
+    : this.elements = map['elements']
+        .map((rmap) => new RetainingPathItem(rmap));
+}
+
+class RetainingPathItem implements M.RetainingPathItem {
+  final HeapObject source;
+  final Instance parentField;
+  final int parentListIndex;
+  final int parentWordOffset;
+
+  RetainingPathItem(ServiceMap map)
+    : source = map['value'],
+      parentField = map['parentField'],
+      parentListIndex = map['parentListIndex'],
+      parentWordOffset = map['_parentWordOffset'];
+}
+
+class Ports implements M.Ports {
+  final Iterable<Port> elements;
+
+  Ports(ServiceMap map)
+    : this.elements = map['ports']
+        .map((rmap) => new Port(rmap));
+}
+
+class Port implements M.Port {
+  final String name;
+  final HeapObject handler;
+
+  Port(ServiceMap map)
+    : name = map['name'],
+      handler = map['handler'];
+}
+
 class HeapSpace extends Observable implements M.HeapSpace {
   @observable int used = 0;
   @observable int capacity = 0;
@@ -1113,31 +1172,10 @@
   }
 }
 
-class HeapSnapshot {
-  final ObjectGraph graph;
-  final DateTime timeStamp;
-  final Isolate isolate;
-
-  HeapSnapshot(this.isolate, chunks, nodeCount) :
-      graph = new ObjectGraph(chunks, nodeCount),
-      timeStamp = new DateTime.now();
-
-  List<Future<ServiceObject>> getMostRetained({int classId, int limit}) {
-    var result = [];
-    for (ObjectVertex v in graph.getMostRetained(classId: classId,
-                                                 limit: limit)) {
-      result.add(isolate.getObjectByAddress(v.address)
-                        .then((ServiceObject obj) {
-        if (obj is HeapObject) {
-          obj.retainedSize = v.retainedSize;
-        } else {
-          print("${obj.runtimeType} should be a HeapObject");
-        }
-        return obj;
-      }));
-    }
-    return result;
-  }
+class RawHeapSnapshot {
+  final chunks;
+  final count;
+  RawHeapSnapshot(this.chunks, this.count);
 }
 
 /// State for a running isolate.
@@ -1376,7 +1414,6 @@
   @observable String fileAndLine;
 
   @observable DartError error;
-  @observable HeapSnapshot latestSnapshot;
   StreamController _snapshotFetch;
 
   List<ByteData> _chunksInProgress;
@@ -1396,8 +1433,7 @@
       _chunksInProgress = new List(chunkCount);
     }
     _chunksInProgress[chunkIndex] = event.data;
-    _snapshotFetch.add("Receiving snapshot chunk ${chunkIndex + 1}"
-                       " of $chunkCount...");
+    _snapshotFetch.add([chunkIndex, chunkCount]);
 
     for (var i = 0; i < chunkCount; i++) {
       if (_chunksInProgress[i] == null) return;
@@ -1406,18 +1442,16 @@
     var loadedChunks = _chunksInProgress;
     _chunksInProgress = null;
 
-    latestSnapshot = new HeapSnapshot(this, loadedChunks, event.nodeCount);
     if (_snapshotFetch != null) {
-      latestSnapshot.graph.process(_snapshotFetch).then((graph) {
-        _snapshotFetch.add(latestSnapshot);
-        _snapshotFetch.close();
-      });
+      _snapshotFetch.add(
+          new RawHeapSnapshot(loadedChunks, event.nodeCount));
+      _snapshotFetch.close();
     }
   }
 
   Stream fetchHeapSnapshot(collectGarbage) {
     if (_snapshotFetch == null || _snapshotFetch.isClosed) {
-      _snapshotFetch = new StreamController();
+      _snapshotFetch = new StreamController.broadcast();
       // isolate.vm.streamListen('_Graph');
       isolate.invokeRpcNoUpgrade('_requestHeapSnapshot',
                                  {'collectGarbage': collectGarbage});
@@ -2546,10 +2580,10 @@
 
   @observable Iterable<BoundField> fields;
   @observable var nativeFields;
-  @observable Iterable<Guarded<ServiceObject>> elements;  // If a List.
+  @observable Iterable<Guarded<HeapObject>> elements;  // If a List.
   @observable Iterable<MapAssociation> associations;  // If a Map.
   @observable Iterable<dynamic> typedElements;  // If a TypedData.
-  @observable ServiceObject referent;  // If a MirrorReference.
+  @observable HeapObject referent;  // If a MirrorReference.
   @observable Instance key;  // If a WeakProperty.
   @observable Instance value;  // If a WeakProperty.
   @observable Breakpoint activationBreakpoint;  // If a Closure.
@@ -2729,7 +2763,7 @@
 class Context extends HeapObject implements M.Context {
   @observable Context parentContext;
   @observable int length;
-  @observable var variables;
+  @observable Iterable<ContextElement> variables;
 
   Context._empty(ServiceObjectOwner owner) : super._empty(owner);
 
@@ -2745,7 +2779,8 @@
       return;
     }
 
-    variables = map['variables'];
+    variables = (map['variables'] ?? const []).map((element) =>
+      new ContextElement(element));
 
     // We are fully loaded.
     _loaded = true;
@@ -2754,6 +2789,13 @@
   String toString() => 'Context($length)';
 }
 
+class ContextElement extends M.ContextElement {
+  final Guarded<Instance> value;
+
+  ContextElement(ObservableMap map)
+    : value = new Guarded<Instance>(map['value']);
+}
+
 M.FunctionKind stringToFunctionKind(String value) {
   switch(value) {
     case 'RegularFunction': return M.FunctionKind.regular;
@@ -2904,7 +2946,7 @@
 
 class Field extends HeapObject implements M.FieldRef {
   // Library or Class.
-  @observable ServiceObject dartOwner;
+  @observable HeapObject dartOwner;
   @observable Library library;
   @observable Instance declaredType;
   @observable bool isStatic;
@@ -3552,8 +3594,8 @@
   }
 }
 
-class ICData extends HeapObject implements M.ICDataRef {
-  @observable ServiceObject dartOwner;
+class ICData extends HeapObject implements M.ICData {
+  @observable HeapObject dartOwner;
   @observable String selector;
   @observable Instance argumentsDescriptor;
   @observable Instance entries;
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index 19ba5cb..89113b9 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -1,4 +1,4 @@
-# Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
@@ -12,6 +12,7 @@
     'lib/debugger.dart',
     'lib/elements.dart',
     'lib/elements.html',
+    'lib/heap_snapshot.dart',
     'lib/models.dart',
     'lib/object_graph.dart',
     'lib/repositories.dart',
@@ -36,9 +37,9 @@
     'lib/src/elements/action_link.html',
     'lib/src/elements/allocation_profile.dart',
     'lib/src/elements/class_ref.dart',
-    'lib/src/elements/class_ref_wrapper.dart',
     'lib/src/elements/class_ref_as_value.dart',
     'lib/src/elements/class_ref_as_value.html',
+    'lib/src/elements/class_ref_wrapper.dart',
     'lib/src/elements/class_tree.dart',
     'lib/src/elements/class_view.dart',
     'lib/src/elements/class_view.html',
@@ -46,16 +47,14 @@
     'lib/src/elements/code_ref_wrapper.dart',
     'lib/src/elements/code_view.dart',
     'lib/src/elements/code_view.html',
+    'lib/src/elements/containers/virtual_collection.dart',
+    'lib/src/elements/containers/virtual_tree.dart',
     'lib/src/elements/context_ref.dart',
     'lib/src/elements/context_ref_wrapper.dart',
     'lib/src/elements/context_view.dart',
-    'lib/src/elements/context_view.html',
-    'lib/src/elements/containers/virtual_collection.dart',
-    'lib/src/elements/containers/virtual_tree.dart',
-    'lib/src/elements/cpu_profile_table.dart',
-    'lib/src/elements/cpu_profile_table.html',
     'lib/src/elements/cpu_profile.dart',
     'lib/src/elements/cpu_profile/virtual_tree.dart',
+    'lib/src/elements/cpu_profile_table.dart',
     'lib/src/elements/css/shared.css',
     'lib/src/elements/curly_block.dart',
     'lib/src/elements/curly_block_wrapper.dart',
@@ -82,7 +81,6 @@
     'lib/src/elements/heap_map.dart',
     'lib/src/elements/heap_map.html',
     'lib/src/elements/heap_snapshot.dart',
-    'lib/src/elements/heap_snapshot.html',
     'lib/src/elements/helpers/any_ref.dart',
     'lib/src/elements/helpers/rendering_queue.dart',
     'lib/src/elements/helpers/rendering_scheduler.dart',
@@ -90,22 +88,20 @@
     'lib/src/elements/helpers/uris.dart',
     'lib/src/elements/icdata_ref.dart',
     'lib/src/elements/icdata_view.dart',
-    'lib/src/elements/icdata_view.html',
     'lib/src/elements/img/chromium_icon.png',
     'lib/src/elements/img/dart_icon.png',
     'lib/src/elements/img/isolate_icon.png',
-    'lib/src/elements/inbound_reference.dart',
-    'lib/src/elements/inbound_reference.html',
+    'lib/src/elements/inbound_references.dart',
     'lib/src/elements/instance_ref.dart',
     'lib/src/elements/instance_ref_wrapper.dart',
     'lib/src/elements/instance_view.dart',
     'lib/src/elements/instance_view.html',
+    'lib/src/elements/isolate/counter_chart.dart',
+    'lib/src/elements/isolate/shared_summary.dart',
+    'lib/src/elements/isolate/shared_summary_wrapper.dart',
     'lib/src/elements/isolate_reconnect.dart',
     'lib/src/elements/isolate_ref.dart',
     'lib/src/elements/isolate_ref_wrapper.dart',
-    'lib/src/elements/isolate/counter_chart.dart',
-    'lib/src/elements/isolate/shared_summary_wrapper.dart',
-    'lib/src/elements/isolate/shared_summary.dart',
     'lib/src/elements/isolate_summary.dart',
     'lib/src/elements/isolate_summary.html',
     'lib/src/elements/isolate_view.dart',
@@ -113,9 +109,9 @@
     'lib/src/elements/json_view.dart',
     'lib/src/elements/json_view.html',
     'lib/src/elements/library_ref.dart',
-    'lib/src/elements/library_ref_wrapper.dart',
     'lib/src/elements/library_ref_as_value.dart',
     'lib/src/elements/library_ref_as_value.html',
+    'lib/src/elements/library_ref_wrapper.dart',
     'lib/src/elements/library_view.dart',
     'lib/src/elements/library_view.html',
     'lib/src/elements/local_var_descriptors_ref.dart',
@@ -133,13 +129,13 @@
     'lib/src/elements/nav/isolate_menu_wrapper.dart',
     'lib/src/elements/nav/library_menu.dart',
     'lib/src/elements/nav/library_menu_wrapper.dart',
+    'lib/src/elements/nav/menu.dart',
     'lib/src/elements/nav/menu_item.dart',
     'lib/src/elements/nav/menu_item_wrapper.dart',
-    'lib/src/elements/nav/menu.dart',
     'lib/src/elements/nav/menu_wrapper.dart',
+    'lib/src/elements/nav/notify.dart',
     'lib/src/elements/nav/notify_event.dart',
     'lib/src/elements/nav/notify_exception.dart',
-    'lib/src/elements/nav/notify.dart',
     'lib/src/elements/nav/notify_wrapper.dart',
     'lib/src/elements/nav/refresh.dart',
     'lib/src/elements/nav/refresh_wrapper.dart',
@@ -148,7 +144,7 @@
     'lib/src/elements/nav/vm_menu.dart',
     'lib/src/elements/nav/vm_menu_wrapper.dart',
     'lib/src/elements/object_common.dart',
-    'lib/src/elements/object_common.html',
+    'lib/src/elements/object_common_wrapper.dart',
     'lib/src/elements/object_view.dart',
     'lib/src/elements/object_view.html',
     'lib/src/elements/objectpool_ref.dart',
@@ -162,31 +158,33 @@
     'lib/src/elements/persistent_handles.dart',
     'lib/src/elements/persistent_handles.html',
     'lib/src/elements/ports.dart',
-    'lib/src/elements/ports.html',
+    'lib/src/elements/retaining_path.dart',
     'lib/src/elements/sample_buffer_control.dart',
     'lib/src/elements/script_inset.dart',
     'lib/src/elements/script_inset.html',
-    'lib/src/elements/script_ref_wrapper.dart',
     'lib/src/elements/script_ref.dart',
+    'lib/src/elements/script_ref_wrapper.dart',
     'lib/src/elements/script_view.dart',
     'lib/src/elements/script_view.html',
+    'lib/src/elements/sentinel_value.dart',
     'lib/src/elements/service_ref.dart',
     'lib/src/elements/service_ref.html',
     'lib/src/elements/service_view.dart',
     'lib/src/elements/service_view.html',
-    'lib/src/elements/source_link_wrapper.dart',
-    'lib/src/elements/source_link.dart',
     'lib/src/elements/shims/binding.dart',
+    'lib/src/elements/source_link.dart',
+    'lib/src/elements/source_link_wrapper.dart',
     'lib/src/elements/stack_trace_tree_config.dart',
     'lib/src/elements/timeline_page.dart',
     'lib/src/elements/timeline_page.html',
     'lib/src/elements/token_stream_ref.dart',
     'lib/src/elements/unknown_ref.dart',
     'lib/src/elements/view_footer.dart',
-    'lib/src/elements/vm_connect_target.dart',
     'lib/src/elements/vm_connect.dart',
+    'lib/src/elements/vm_connect_target.dart',
     'lib/src/elements/vm_view.dart',
     'lib/src/elements/vm_view.html',
+    'lib/src/heap_snapshot/heap_snapshot.dart',
     'lib/src/models/exceptions.dart',
     'lib/src/models/objects/allocation_profile.dart',
     'lib/src/models/objects/bound_field.dart',
@@ -201,8 +199,11 @@
     'lib/src/models/objects/flag.dart',
     'lib/src/models/objects/frame.dart',
     'lib/src/models/objects/function.dart',
+    'lib/src/models/objects/guarded.dart',
+    'lib/src/models/objects/heap_snapshot.dart',
     'lib/src/models/objects/heap_space.dart',
     'lib/src/models/objects/icdata.dart',
+    'lib/src/models/objects/inbound_references.dart',
     'lib/src/models/objects/instance.dart',
     'lib/src/models/objects/isolate.dart',
     'lib/src/models/objects/library.dart',
@@ -213,29 +214,48 @@
     'lib/src/models/objects/object.dart',
     'lib/src/models/objects/objectpool.dart',
     'lib/src/models/objects/pc_descriptors.dart',
+    'lib/src/models/objects/ports.dart',
+    'lib/src/models/objects/retaining_path.dart',
     'lib/src/models/objects/sample_profile.dart',
     'lib/src/models/objects/script.dart',
     'lib/src/models/objects/sentinel.dart',
     'lib/src/models/objects/source_location.dart',
-    'lib/src/models/objects/unknown.dart',
     'lib/src/models/objects/target.dart',
     'lib/src/models/objects/timeline_event.dart',
     'lib/src/models/objects/token_stream.dart',
+    'lib/src/models/objects/unknown.dart',
     'lib/src/models/objects/vm.dart',
     'lib/src/models/repositories/allocation_profile.dart',
     'lib/src/models/repositories/class.dart',
+    'lib/src/models/repositories/context.dart',
     'lib/src/models/repositories/event.dart',
     'lib/src/models/repositories/flag.dart',
+    'lib/src/models/repositories/heap_snapshot.dart',
+    'lib/src/models/repositories/icdata.dart',
+    'lib/src/models/repositories/inbound_references.dart',
     'lib/src/models/repositories/instance.dart',
     'lib/src/models/repositories/notification.dart',
+    'lib/src/models/repositories/ports.dart',
+    'lib/src/models/repositories/reachable_size.dart',
+    'lib/src/models/repositories/retained_size.dart',
+    'lib/src/models/repositories/retaining_path.dart',
     'lib/src/models/repositories/sample_profile.dart',
     'lib/src/models/repositories/script.dart',
     'lib/src/models/repositories/target.dart',
+    'lib/src/repositories/allocation_profile.dart',
     'lib/src/repositories/class.dart',
+    'lib/src/repositories/context.dart',
     'lib/src/repositories/event.dart',
     'lib/src/repositories/flag.dart',
+    'lib/src/repositories/heap_snapshot.dart',
+    'lib/src/repositories/icdata.dart',
+    'lib/src/repositories/inbound_references.dart',
     'lib/src/repositories/instance.dart',
     'lib/src/repositories/notification.dart',
+    'lib/src/repositories/ports.dart',
+    'lib/src/repositories/reachable_size.dart',
+    'lib/src/repositories/retained_size.dart',
+    'lib/src/repositories/retaining_path.dart',
     'lib/src/repositories/sample_profile.dart',
     'lib/src/repositories/script.dart',
     'lib/src/repositories/settings.dart',
@@ -250,5 +270,5 @@
     'web/timeline.html',
     'web/timeline.js',
     'web/timeline_message_handler.js',
-  ],
+  ]
 }
diff --git a/runtime/observatory/tests/observatory_ui/context_view/element_test.dart b/runtime/observatory/tests/observatory_ui/context_view/element_test.dart
new file mode 100644
index 0000000..428aefd
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/context_view/element_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/context_view.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import '../mocks.dart';
+
+main() {
+  ContextViewElement.tag.ensureRegistration();
+
+  final cTag = ObjectCommonElement.tag.name;
+  final rTag = NavRefreshElement.tag.name;
+
+  const vm = const VMMock();
+  const isolate = const IsolateRefMock();
+  final events = new EventRepositoryMock();
+  final notifs = new NotificationRepositoryMock();
+  final context = const ContextMock();
+  final contexts = new ContextRepositoryMock();
+  final reachableSizes = new ReachableSizeRepositoryMock();
+  final retainedSizes = new RetainedSizeRepositoryMock();
+  final inbounds = new InboundReferencesRepositoryMock();
+  final paths = new RetainingPathRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new ContextViewElement(vm, isolate, context, events, notifs,
+                                     contexts, retainedSizes, reachableSizes,
+                                     inbounds, paths, instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.context, equals(context));
+  });
+  test('elements created after attachment', () async {
+    final contexts = new ContextRepositoryMock(
+      getter: expectAsync((i, id) async {
+        expect(i, equals(isolate));
+        expect(id, equals(context.id));
+        return context;
+      }, count: 1)
+    );
+    final e = new ContextViewElement(vm, isolate, context, events, notifs,
+                                     contexts, retainedSizes, reachableSizes,
+                                     inbounds, paths, instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(cTag).length, equals(1));
+    (e.querySelector(rTag) as NavRefreshElement).refresh();
+    await e.onRendered.first;
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/context_view/element_test.html b/runtime/observatory/tests/observatory_ui/context_view/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/context_view/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.dart b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.dart
new file mode 100644
index 0000000..abe2db4
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/cpu_profile_table.dart';
+import 'package:observatory/src/elements/cpu_profile/virtual_tree.dart';
+import 'package:observatory/src/elements/stack_trace_tree_config.dart';
+import 'package:observatory/src/elements/sample_buffer_control.dart';
+import '../mocks.dart';
+
+main() {
+  CpuProfileTableElement.tag.ensureRegistration();
+
+  final sTag = SampleBufferControlElement.tag.name;
+  final cTag = StackTraceTreeConfigElement.tag.name;
+  final tTag = CpuProfileVirtualTreeElement.tag.name;
+
+  const vm = const VMMock();
+  const isolate = const IsolateRefMock();
+  final events = new EventRepositoryMock();
+  final notifs = new NotificationRepositoryMock();
+  test('instantiation', () {
+    final profiles = new IsolateSampleProfileRepositoryMock();
+    final e = new CpuProfileTableElement(vm, isolate, events, notifs, profiles);
+    expect(e, isNotNull, reason: 'element correctly created');
+  });
+  test('elements created', () async {
+    final controller
+        = new StreamController<M.SampleProfileLoadingProgressEvent>.broadcast();
+    final profiles = new IsolateSampleProfileRepositoryMock(
+      getter: (M.IsolateRef i, M.SampleProfileTag t, bool clear,
+          bool forceFetch) {
+        expect(i, equals(isolate));
+        expect(t, isNotNull);
+        expect(clear, isFalse);
+        expect(forceFetch, isFalse);
+        return controller.stream;
+      }
+    );
+    final e = new CpuProfileTableElement(vm, isolate, events, notifs, profiles);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(sTag).length, isZero);
+    expect(e.querySelectorAll(cTag).length, isZero);
+    expect(e.querySelectorAll(tTag).length, isZero);
+    controller.add(new SampleProfileLoadingProgressEventMock(
+      progress: new SampleProfileLoadingProgressMock(
+        status: M.SampleProfileLoadingStatus.fetching
+      )
+    ));
+    await e.onRendered.first;
+    expect(e.querySelectorAll(sTag).length, equals(1));
+    expect(e.querySelectorAll(cTag).length, isZero);
+    expect(e.querySelectorAll(tTag).length, isZero);
+    controller.add(new SampleProfileLoadingProgressEventMock(
+      progress: new SampleProfileLoadingProgressMock(
+        status: M.SampleProfileLoadingStatus.loading
+      )
+    ));
+    controller.add(new SampleProfileLoadingProgressEventMock(
+      progress: new SampleProfileLoadingProgressMock(
+        status: M.SampleProfileLoadingStatus.loaded,
+        profile: new SampleProfileMock()
+      )
+    ));
+    controller.close();
+    await e.onRendered.first;
+    expect(e.querySelectorAll(sTag).length, equals(1));
+    expect(e.querySelectorAll(cTag).length, equals(1));
+    expect(e.querySelectorAll(tTag).length, equals(1));
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/cpu_profile_table/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.dart b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.dart
new file mode 100644
index 0000000..1136e39
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/containers/virtual_tree.dart';
+import 'package:observatory/src/elements/heap_snapshot.dart';
+import '../mocks.dart';
+
+main() {
+  HeapSnapshotElement.tag.ensureRegistration();
+
+  final tTag = VirtualTreeElement.tag.name;
+
+  const vm = const VMMock();
+  const isolate = const IsolateRefMock();
+  final events = new EventRepositoryMock();
+  final notifs = new NotificationRepositoryMock();
+  final snapshots = new HeapSnapshotRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new HeapSnapshotElement(vm, isolate, events, notifs, snapshots,
+                                      instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+  });
+  test('elements created', () async {
+    final controller
+        = new StreamController<M.HeapSnapshotLoadingProgressEvent>.broadcast();
+    final snapshots = new HeapSnapshotRepositoryMock(
+      getter: (M.IsolateRef i, bool gc) {
+        expect(i, equals(isolate));
+        expect(gc, isFalse);
+        return controller.stream;
+      }
+    );
+    final e = new HeapSnapshotElement(vm, isolate, events, notifs, snapshots,
+                                      instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(tTag).length, isZero);
+    controller.add(const HeapSnapshotLoadingProgressEventMock(
+      progress: const HeapSnapshotLoadingProgressMock(
+        status: M.HeapSnapshotLoadingStatus.fetching
+      )
+    ));
+    await e.onRendered.first;
+    expect(e.querySelectorAll(tTag).length, isZero);
+    controller.add(const HeapSnapshotLoadingProgressEventMock(
+      progress: const HeapSnapshotLoadingProgressMock(
+        status: M.HeapSnapshotLoadingStatus.loading
+      )
+    ));
+    controller.add(new HeapSnapshotLoadingProgressEventMock(
+      progress: new HeapSnapshotLoadingProgressMock(
+        status: M.HeapSnapshotLoadingStatus.loaded,
+        snapshot: new HeapSnapshotMock(timestamp: new DateTime.now())
+      )
+    ));
+    controller.close();
+    await e.onRendered.first;
+    expect(e.querySelectorAll(tTag).length, equals(1));
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/heap_snapshot/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/icdata_view/element_test.dart b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.dart
new file mode 100644
index 0000000..cde932c
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/icdata_view.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import '../mocks.dart';
+
+main() {
+  ICDataViewElement.tag.ensureRegistration();
+
+  final cTag = ObjectCommonElement.tag.name;
+  final rTag = NavRefreshElement.tag.name;
+
+  const vm = const VMMock();
+  const isolate = const IsolateRefMock();
+  final events = new EventRepositoryMock();
+  final notifs = new NotificationRepositoryMock();
+  final icdata = const ICDataMock();
+  final icdatas = new ICDataRepositoryMock();
+  final reachableSizes = new ReachableSizeRepositoryMock();
+  final retainedSizes = new RetainedSizeRepositoryMock();
+  final inbounds = new InboundReferencesRepositoryMock();
+  final paths = new RetainingPathRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new ICDataViewElement(vm, isolate, icdata, events, notifs,
+                                     icdatas, retainedSizes, reachableSizes,
+                                     inbounds, paths, instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.icdata, equals(icdata));
+  });
+  test('elements created after attachment', () async {
+    final icdatas = new ICDataRepositoryMock(
+      getter: expectAsync((i, id) async {
+        expect(i, equals(isolate));
+        expect(id, equals(icdata.id));
+        return icdata;
+      }, count: 1)
+    );
+    final e = new ICDataViewElement(vm, isolate, icdata, events, notifs,
+                                     icdatas, retainedSizes, reachableSizes,
+                                     inbounds, paths, instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(cTag).length, equals(1));
+    (e.querySelector(rTag) as NavRefreshElement).refresh();
+    await e.onRendered.first;
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/icdata_view/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/inbound_references/element_test.dart b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.dart
new file mode 100644
index 0000000..324d5e5
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/inbound_references.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import '../mocks.dart';
+
+main() {
+  InboundReferencesElement.tag.ensureRegistration();
+
+  final cTag = CurlyBlockElement.tag.name;
+  final iTag = InstanceRefElement.tag.name;
+  final rTag = InboundReferencesElement.tag.name;
+
+  const isolate = const IsolateRefMock();
+  const object = const InstanceRefMock();
+  final inbounds = new InboundReferencesRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new InboundReferencesElement(isolate, object, inbounds,
+                                           instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.object, equals(object));
+  });
+  test('elements created after attachment', () async {
+    const source = const InstanceRefMock(id: 'source-id', name: 'source_name');
+    const references = const InboundReferencesMock(elements: const [
+      const InboundReferenceMock(source: source)
+    ]);
+    bool invoked = false;
+    final inbounds = new InboundReferencesRepositoryMock(
+      getter: expectAsync((i, id) async {
+        expect(i, equals(isolate));
+        expect(id, equals(object.id));
+        invoked = true;
+        return references;
+      }, count: 1)
+    );
+    final instances = new InstanceRepositoryMock();
+    final e = new InboundReferencesElement(isolate, object, inbounds,
+                                           instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(invoked, isFalse);
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(iTag).length, isZero);
+    (e.querySelector(cTag) as CurlyBlockElement).toggle();
+    await e.onRendered.first;
+    expect(invoked, isTrue);
+    expect(e.querySelectorAll(iTag).length, equals(1));
+    expect(e.querySelectorAll(rTag).length, equals(1));
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/inbound_references/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/mocks.dart b/runtime/observatory/tests/observatory_ui/mocks.dart
index c2e1427..28bc264 100644
--- a/runtime/observatory/tests/observatory_ui/mocks.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks.dart
@@ -19,8 +19,11 @@
 part 'mocks/objects/field.dart';
 part 'mocks/objects/flag.dart';
 part 'mocks/objects/function.dart';
+part 'mocks/objects/guarded.dart';
+part 'mocks/objects/heap_snapshot.dart';
 part 'mocks/objects/heap_space.dart';
 part 'mocks/objects/icdata.dart';
+part 'mocks/objects/inbound_references.dart';
 part 'mocks/objects/instance.dart';
 part 'mocks/objects/isolate.dart';
 part 'mocks/objects/library.dart';
@@ -29,6 +32,8 @@
 part 'mocks/objects/notification.dart';
 part 'mocks/objects/objectpool.dart';
 part 'mocks/objects/pc_descriptors.dart';
+part 'mocks/objects/ports.dart';
+part 'mocks/objects/retaining_path.dart';
 part 'mocks/objects/sample_profile.dart';
 part 'mocks/objects/script.dart';
 part 'mocks/objects/sentinel.dart';
@@ -40,10 +45,18 @@
 
 part 'mocks/repositories/allocation_profile.dart';
 part 'mocks/repositories/class.dart';
+part 'mocks/repositories/context.dart';
 part 'mocks/repositories/event.dart';
 part 'mocks/repositories/flag.dart';
+part 'mocks/repositories/heap_snapshot.dart';
+part 'mocks/repositories/icdata.dart';
+part 'mocks/repositories/inbound_references.dart';
 part 'mocks/repositories/instance.dart';
 part 'mocks/repositories/notification.dart';
+part 'mocks/repositories/ports.dart';
+part 'mocks/repositories/reachable_size.dart';
+part 'mocks/repositories/retained_size.dart';
+part 'mocks/repositories/retaining_path.dart';
 part 'mocks/repositories/sample_profile.dart';
 part 'mocks/repositories/script.dart';
 part 'mocks/repositories/target.dart';
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/context.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/context.dart
index 2ac5e5e..0ece445 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/context.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/context.dart
@@ -8,7 +8,7 @@
   final String id;
   final int length;
 
-  const ContextRefMock({this.id, this.length: 0});
+  const ContextRefMock({this.id: 'context-id', this.length});
 }
 
 class ContextMock implements M.Context {
@@ -17,7 +17,16 @@
   final int size;
   final int length;
   final M.Context parentContext;
+  final Iterable<M.ContextElement> variables;
 
-  const ContextMock({this.id, this.clazz, this.size, this.length: 0,
-                     this.parentContext});
+  const ContextMock({this.id: 'context-id', this.clazz: const ClassMock(),
+                     this.size: 0, this.length, this.parentContext,
+                     this.variables: const []});
+}
+
+class ContextElementMock implements M.ContextElement {
+  final GuardedMock<M.InstanceRef> value;
+
+  const ContextElementMock({this.value: const GuardedMock.fromValue(
+      const InstanceRefMock())});
 }
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/guarded.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/guarded.dart
new file mode 100644
index 0000000..95de862
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/guarded.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+class GuardedMock<T> implements M.Guarded {
+  bool get isSentinel => asSentinel != null;
+  bool get isValue => asValue != null;
+  final T asValue;
+  final M.Sentinel asSentinel;
+
+  const GuardedMock.fromValue(this.asValue)
+    : asSentinel = null;
+
+  const GuardedMock.fromSentinel(this.asSentinel)
+    : asValue = null;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/heap_snapshot.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/heap_snapshot.dart
new file mode 100644
index 0000000..1763ba3
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/heap_snapshot.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+class HeapSnapshotMock implements M.HeapSnapshot {
+  final DateTime timestamp;
+  final int objects;
+  final int references;
+  final int size;
+  final M.HeapSnapshotDominatorNode dominatorTree;
+  final Iterable<M.HeapSnapshotClassReferences> classReferences;
+
+  const HeapSnapshotMock({this.timestamp, this.objects: 0,
+      this.references: 0, this.size: 0,
+      this.dominatorTree: const HeapSnapshotDominatorNodeMock(),
+      this.classReferences: const []});
+}
+
+class HeapSnapshotDominatorNodeMock implements M.HeapSnapshotDominatorNode {
+  final int shallowSize;
+  final int retainedSize;
+  final Future<M.ObjectRef> object;
+  final Iterable<M.HeapSnapshotDominatorNode> children;
+
+  const HeapSnapshotDominatorNodeMock({this.shallowSize: 1,
+                                       this.retainedSize: 1,
+                                       this.object, this.children: const []});
+}
+
+class HeapSnapshotClassReferencesMock implements M.HeapSnapshotClassReferences {
+  final M.ClassRef clazz;
+  final int instances;
+  final int shallowSize;
+  final int retainedSize;
+  final Iterable<M.HeapSnapshotClassInbound> inbounds;
+  final Iterable<M.HeapSnapshotClassOutbound> outbounds;
+
+  const HeapSnapshotClassReferencesMock({this.clazz: const ClassRefMock(),
+                                         this.instances: 1, this.shallowSize: 1,
+                                         this.retainedSize: 2,
+                                         this.inbounds: const [],
+                                         this.outbounds: const []});
+}
+
+class HeapSnapshotClassInboundMock implements M.HeapSnapshotClassInbound {
+  final M.ClassRef source;
+  final int count;
+  final int shallowSize;
+  final int retainedSize;
+
+  const HeapSnapshotClassInboundMock({this.source: const ClassRefMock(),
+                                      this.count: 1, this.shallowSize: 1,
+                                      this.retainedSize: 2});
+}
+
+class HeapSnapshotClassOutboundMock implements M.HeapSnapshotClassOutbound {
+  final M.ClassRef target;
+  final int count;
+  final int shallowSize;
+  final int retainedSize;
+  const HeapSnapshotClassOutboundMock({this.target: const ClassRefMock(),
+                                       this.count: 1, this.shallowSize: 1,
+                                       this.retainedSize: 2});
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/icdata.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/icdata.dart
index b7a3510..3b4483f 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/icdata.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/icdata.dart
@@ -10,3 +10,17 @@
 
   const ICDataRefMock({this.id: 'icdata-id', this.selector});
 }
+
+class ICDataMock implements M.ICData {
+  final String id;
+  final M.ClassRef clazz;
+  final int size;
+  final String selector;
+  final M.ObjectRef dartOwner;
+  final M.InstanceRef argumentsDescriptor;
+  final M.InstanceRef entries;
+
+  const ICDataMock({this.id: 'icdata-id', this.clazz: const ClassRefMock(),
+                    this.size: 0, this.selector, this.dartOwner,
+                    this.argumentsDescriptor, this.entries});
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/inbound_references.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/inbound_references.dart
new file mode 100644
index 0000000..1f746e3
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/inbound_references.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+class InboundReferencesMock implements M.InboundReferences {
+  final Iterable<M.InboundReference> elements;
+
+  const InboundReferencesMock({this.elements: const []});
+}
+
+class InboundReferenceMock implements M.InboundReference {
+  final M.ObjectRef source;
+  final M.ObjectRef parentField;
+  final int parentListIndex;
+  final int parentWordOffset;
+
+  const InboundReferenceMock({this.source: const InstanceRefMock(),
+                              this.parentField, this.parentListIndex,
+                              this.parentWordOffset});
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/instance.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/instance.dart
index d40059a..bb8f6c2 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/instance.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/instance.dart
@@ -49,7 +49,8 @@
   final M.InstanceRef referent;
 
   const InstanceMock({this.id: 'instance-id', this.name: 'instance-name',
-                      this.kind: M.InstanceKind.vNull, this.clazz, this.size,
+                      this.kind: M.InstanceKind.vNull,
+                      this.clazz: const ClassRefMock(), this.size: 0,
                       this.valueAsString: 'null', this.valueAsStringIsTruncated,
                       this.length, this.typeClass, this.parameterizedClass,
                       this.pattern, this.closureFunction, this.offset,
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/ports.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/ports.dart
new file mode 100644
index 0000000..a9d4a5b
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/ports.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+class PortsMock implements M.Ports {
+  final Iterable<M.Port> elements;
+
+  const PortsMock({this.elements: const []});
+}
+
+class PortMock implements M.Port {
+  final String name;
+  final M.ObjectRef handler;
+
+  const PortMock({this.name: 'port-name',
+                  this.handler: const InstanceRefMock()});
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/retaining_path.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/retaining_path.dart
new file mode 100644
index 0000000..6f6c733
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/retaining_path.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+class RetainingPathMock implements M.RetainingPath {
+  final Iterable<M.RetainingPathItem> elements;
+
+  const RetainingPathMock({this.elements: const []});
+}
+
+class RetainingPathItemMock implements M.RetainingPathItem {
+  final M.ObjectRef source;
+  final M.ObjectRef parentField;
+  final int parentListIndex;
+  final int parentWordOffset;
+
+  const RetainingPathItemMock({this.source: const InstanceRefMock(),
+                               this.parentField, this.parentListIndex,
+                               this.parentWordOffset});
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/sample_profile.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/sample_profile.dart
index 4e8441c..843fd03 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/sample_profile.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/sample_profile.dart
@@ -13,11 +13,12 @@
   final SampleProfileMockLoadFunctionTreeCallback _loadFunctionTree;
   final SampleProfileMockLoadCodeTreeCallback _loadCodeTree;
 
-
   final int sampleCount;
   final int stackDepth;
   final double sampleRate;
   final double timeSpan;
+  final Iterable<M.ProfileCode> codes;
+  final Iterable<M.ProfileFunction> functions;
 
   M.FunctionCallTree loadFunctionTree(M.ProfileTreeDirection direction) {
     if (_loadFunctionTree != null) {
@@ -34,6 +35,7 @@
 
   SampleProfileMock({this.sampleCount: 0, this.stackDepth: 0,
       this.sampleRate: 1.0, this.timeSpan: 1.0,
+      this.codes: const [], this.functions: const [],
       SampleProfileMockLoadFunctionTreeCallback loadFunctionTree,
       SampleProfileMockLoadCodeTreeCallback loadCodeTree})
     : _loadFunctionTree = loadFunctionTree,
diff --git a/runtime/observatory/tests/observatory_ui/mocks/objects/sentinel.dart b/runtime/observatory/tests/observatory_ui/mocks/objects/sentinel.dart
index 1d77a35..5fb6a8a 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/objects/sentinel.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/objects/sentinel.dart
@@ -4,10 +4,10 @@
 
 part of mocks;
 
-class Sentinel implements M.Sentinel {
+class SentinelMock implements M.Sentinel {
   final M.SentinelKind kind;
   final String valueAsString;
 
-  const Sentinel({this.kind: M.SentinelKind.collected,
+  const SentinelMock({this.kind: M.SentinelKind.collected,
                   this.valueAsString: 'sentinel-value'});
 }
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/context.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/context.dart
new file mode 100644
index 0000000..11d8dfa
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/context.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+typedef Future<M.Context> ContextRepositoryMockCallback(M.IsolateRef isolate,
+                                                          String id);
+
+class ContextRepositoryMock implements M.ContextRepository {
+  final ContextRepositoryMockCallback _get;
+
+  ContextRepositoryMock({ContextRepositoryMockCallback getter})
+    : _get = getter;
+
+  Future<M.Context> get(M.IsolateRef isolate, String id){
+    if (_get != null) {
+      return _get(isolate, id);
+    }
+    return new Future.value(null);
+  }
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/heap_snapshot.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/heap_snapshot.dart
new file mode 100644
index 0000000..42f93e3
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/heap_snapshot.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class HeapSnapshotLoadingProgressEventMock
+    implements M.HeapSnapshotLoadingProgressEvent {
+  final M.HeapSnapshotLoadingProgress progress;
+
+  const HeapSnapshotLoadingProgressEventMock(
+      {this.progress: const HeapSnapshotLoadingProgressMock()});
+}
+
+class HeapSnapshotLoadingProgressMock implements M.HeapSnapshotLoadingProgress {
+  final M.HeapSnapshotLoadingStatus status;
+  final String stepDescription;
+  final double progress;
+  final Duration fetchingTime;
+  final Duration loadingTime;
+  final M.HeapSnapshot snapshot;
+
+  const HeapSnapshotLoadingProgressMock({
+      this.status : M.HeapSnapshotLoadingStatus.fetching, this.progress: 0.0,
+      this.stepDescription: '', this.fetchingTime, this.loadingTime,
+      this.snapshot});
+}
+
+typedef Stream<M.HeapSnapshotLoadingProgressEvent>
+    HeapSnapshotRepositoryMockCallback(M.IsolateRef cls, bool gc);
+
+class HeapSnapshotRepositoryMock
+    implements M.HeapSnapshotRepository {
+  final HeapSnapshotRepositoryMockCallback _get;
+
+  Stream<M.HeapSnapshotLoadingProgressEvent> get(M.IsolateRef isolate,
+                                               {bool gc: false}) {
+    if (_get != null) {
+      return _get(isolate, gc);
+    }
+    return null;
+  }
+
+  HeapSnapshotRepositoryMock(
+      {HeapSnapshotRepositoryMockCallback getter})
+    : _get = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/icdata.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/icdata.dart
new file mode 100644
index 0000000..2f132f3
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/icdata.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of mocks;
+
+typedef Future<M.ICData> ICDataRepositoryMockCallback(M.IsolateRef isolate,
+                                                      String id);
+
+class ICDataRepositoryMock implements M.ICDataRepository {
+  final ICDataRepositoryMockCallback _get;
+
+  ICDataRepositoryMock({ICDataRepositoryMockCallback getter})
+    : _get = getter;
+
+  Future<M.ICData> get(M.IsolateRef isolate, String id, {int count}){
+    if (_get != null) {
+      return _get(isolate, id);
+    }
+    return new Future.value(null);
+  }
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/inbound_references.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/inbound_references.dart
new file mode 100644
index 0000000..44c3314
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/inbound_references.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+typedef Future<M.InboundReferences>
+        InboundReferencesRepositoryMockGetter(M.IsolateRef i, String id);
+
+class InboundReferencesRepositoryMock implements M.InboundReferencesRepository {
+  final InboundReferencesRepositoryMockGetter _getter;
+
+  Future<M.InboundReferences> get(M.IsolateRef i, String id) {
+    if (_getter != null) {
+      return _getter(i, id);
+    }
+    return new Future.value(new InboundReferencesMock());
+  }
+
+  InboundReferencesRepositoryMock(
+      {InboundReferencesRepositoryMockGetter getter})
+    : _getter = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/instance.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/instance.dart
index 21ecf16..168c8e6 100644
--- a/runtime/observatory/tests/observatory_ui/mocks/repositories/instance.dart
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/instance.dart
@@ -4,7 +4,8 @@
 
 part of mocks;
 
-typedef Future<M.Instance> InstanceRepositoryMockCallback(String id);
+typedef Future<M.Instance> InstanceRepositoryMockCallback(M.IsolateRef isolate,
+                                                          String id);
 
 class InstanceRepositoryMock implements M.InstanceRepository {
   final InstanceRepositoryMockCallback _get;
@@ -12,9 +13,9 @@
   InstanceRepositoryMock({InstanceRepositoryMockCallback getter})
     : _get = getter;
 
-  Future<M.Instance> get(String id, {int count}){
+  Future<M.Instance> get(M.IsolateRef isolate, String id, {int count}){
     if (_get != null) {
-      return _get(id);
+      return _get(isolate, id);
     }
     return new Future.value(null);
   }
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/ports.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/ports.dart
new file mode 100644
index 0000000..71eeb67
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/ports.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+typedef Future<M.Ports> PortsRepositoryMockGetter(M.IsolateRef i);
+
+class PortsRepositoryMock implements M.PortsRepository {
+  final PortsRepositoryMockGetter _getter;
+
+  Future<M.Ports> get(M.IsolateRef i) {
+    if (_getter != null) {
+      return _getter(i);
+    }
+    return new Future.value(new PortsMock());
+  }
+
+  PortsRepositoryMock({PortsRepositoryMockGetter getter})
+    : _getter = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/reachable_size.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/reachable_size.dart
new file mode 100644
index 0000000..db93100
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/reachable_size.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+typedef Future<M.Guarded<M.Instance>>
+        ReachableSizeRepositoryMockGetter(M.IsolateRef i, String id);
+
+class ReachableSizeRepositoryMock implements M.ReachableSizeRepository {
+  final ReachableSizeRepositoryMockGetter _getter;
+
+  Future<M.Guarded<M.Instance>> get(M.IsolateRef i, String id) {
+    if (_getter != null) {
+      return _getter(i, id);
+    }
+    return new Future.value(
+      new GuardedMock<M.Instance>.fromSentinel(new SentinelMock())
+    );
+  }
+
+  ReachableSizeRepositoryMock({ReachableSizeRepositoryMockGetter getter})
+    : _getter = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/retained_size.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/retained_size.dart
new file mode 100644
index 0000000..9f56299
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/retained_size.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+typedef Future<M.Guarded<M.Instance>>
+        RetainedSizeRepositoryMockGetter(M.IsolateRef i, String id);
+
+class RetainedSizeRepositoryMock implements M.RetainedSizeRepository {
+  final RetainedSizeRepositoryMockGetter _getter;
+
+  Future<M.Guarded<M.Instance>> get(M.IsolateRef i, String id) {
+    if (_getter != null) {
+      return _getter(i, id);
+    }
+    return new Future.value(
+      new GuardedMock<M.Instance>.fromSentinel(new SentinelMock())
+    );
+  }
+
+  RetainedSizeRepositoryMock({RetainedSizeRepositoryMockGetter getter})
+    : _getter = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/mocks/repositories/retaining_path.dart b/runtime/observatory/tests/observatory_ui/mocks/repositories/retaining_path.dart
new file mode 100644
index 0000000..28bd4b3
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/mocks/repositories/retaining_path.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+typedef Future<M.RetainingPath>
+        RetainingPathRepositoryMockGetter(M.IsolateRef i, String id);
+
+class RetainingPathRepositoryMock implements M.RetainingPathRepository {
+  final RetainingPathRepositoryMockGetter _getter;
+
+  Future<M.RetainingPath> get(M.IsolateRef i, String id) {
+    if (_getter != null) {
+      return _getter(i, id);
+    }
+    return new Future.value(new RetainingPathMock());
+  }
+
+  RetainingPathRepositoryMock({RetainingPathRepositoryMockGetter getter})
+    : _getter = getter;
+}
diff --git a/runtime/observatory/tests/observatory_ui/object_common/element_test.dart b/runtime/observatory/tests/observatory_ui/object_common/element_test.dart
new file mode 100644
index 0000000..bb83bc5
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/object_common/element_test.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/class_ref.dart';
+import 'package:observatory/src/elements/inbound_references.dart';
+import 'package:observatory/src/elements/object_common.dart';
+import 'package:observatory/src/elements/retaining_path.dart';
+import '../mocks.dart';
+
+main() {
+  ObjectCommonElement.tag.ensureRegistration();
+
+  final cTag = ClassRefElement.tag.name;
+  final iTag = InboundReferencesElement.tag.name;
+  final rTag = RetainingPathElement.tag.name;
+
+  const isolate = const IsolateRefMock();
+  const object = const InstanceMock();
+  final reachableSizes = new ReachableSizeRepositoryMock();
+  final retainedSizes = new RetainedSizeRepositoryMock();
+  final inbounds = new InboundReferencesRepositoryMock();
+  final paths = new RetainingPathRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new ObjectCommonElement(isolate, object, retainedSizes,
+                                      reachableSizes, inbounds, paths,
+                                      instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.object, equals(object));
+  });
+  group('elements', () {
+    test('created after attachment', () async {
+      final e = new ObjectCommonElement(isolate, object, retainedSizes,
+                                        reachableSizes, inbounds, paths,
+                                        instances);
+      document.body.append(e);
+      await e.onRendered.first;
+      expect(e.children.length, isNonZero, reason: 'has elements');
+      expect(e.querySelectorAll(cTag).length, equals(1));
+      expect(e.querySelectorAll(iTag).length, equals(1));
+      expect(e.querySelectorAll(rTag).length, equals(1));
+      e.remove();
+      await e.onRendered.first;
+      expect(e.children.length, isZero, reason: 'is empty');
+    });
+    test('created after attachment', () async {
+      const value = const GuardedMock<InstanceMock>.fromValue(
+        const InstanceMock(valueAsString: '10')
+      );
+      bool invoked = false;
+      final reachableSizes = new ReachableSizeRepositoryMock(
+        getter: expectAsync((i, id) async {
+          expect(i, equals(isolate));
+          expect(id, equals(object.id));
+          invoked = true;
+          return value;
+        }, count: 1)
+      );
+      final e = new ObjectCommonElement(isolate, object, retainedSizes,
+                                        reachableSizes, inbounds, paths,
+                                        instances);
+      document.body.append(e);
+      await e.onRendered.first;
+      expect(invoked, isFalse);
+      expect(e.children.length, isNonZero, reason: 'has elements');
+      expect(e.querySelectorAll(cTag).length, equals(1));
+      expect(e.querySelectorAll(iTag).length, equals(1));
+      expect(e.querySelectorAll(rTag).length, equals(1));
+      e.querySelector('.reachable_size').click();
+      await e.onRendered.first;
+      expect(invoked, isTrue);
+      e.remove();
+      await e.onRendered.first;
+      expect(e.children.length, isZero, reason: 'is empty');
+    });
+    test('created after attachment', () async {
+      const value = const GuardedMock<InstanceMock>.fromValue(
+        const InstanceMock(valueAsString: '10')
+      );
+      bool invoked = false;
+      final retainedSizes = new RetainedSizeRepositoryMock(
+        getter: expectAsync((i, id) async {
+          expect(i, equals(isolate));
+          expect(id, equals(object.id));
+          invoked = true;
+          return value;
+        }, count: 1)
+      );
+      final e = new ObjectCommonElement(isolate, object, retainedSizes,
+                                        reachableSizes, inbounds, paths,
+                                        instances);
+      document.body.append(e);
+      await e.onRendered.first;
+      expect(invoked, isFalse);
+      expect(e.children.length, isNonZero, reason: 'has elements');
+      expect(e.querySelectorAll(cTag).length, equals(1));
+      expect(e.querySelectorAll(iTag).length, equals(1));
+      expect(e.querySelectorAll(rTag).length, equals(1));
+      e.querySelector('.retained_size').click();
+      await e.onRendered.first;
+      expect(invoked, isTrue);
+      e.remove();
+      await e.onRendered.first;
+      expect(e.children.length, isZero, reason: 'is empty');
+    });
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/object_common/element_test.html b/runtime/observatory/tests/observatory_ui/object_common/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/object_common/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/observatory_ui.status b/runtime/observatory/tests/observatory_ui/observatory_ui.status
index f1cbd44..e307635 100644
--- a/runtime/observatory/tests/observatory_ui/observatory_ui.status
+++ b/runtime/observatory/tests/observatory_ui/observatory_ui.status
@@ -8,3 +8,7 @@
 [ $runtime == dartium ]
 isolate/*: Skip
 allocation_profile: Skip
+
+[ $runtime == ff || $runtime == safari ]
+allocation_profile: Skip
+cpu_profile_table: Skip
diff --git a/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.dart b/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.dart
index ec10960..472df2b 100644
--- a/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.dart
+++ b/runtime/observatory/tests/observatory_ui/pc_descriptors_ref/element_test.dart
@@ -10,7 +10,7 @@
 main() {
   SentinelValueElement.tag.ensureRegistration();
 
-  const sentinel = const Sentinel();
+  const sentinel = const SentinelMock();
   test('instantiation', () {
     final e = new SentinelValueElement(sentinel);
     expect(e, isNotNull, reason: 'element correctly created');
diff --git a/runtime/observatory/tests/observatory_ui/ports/element_test.dart b/runtime/observatory/tests/observatory_ui/ports/element_test.dart
new file mode 100644
index 0000000..9f7807b
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/ports/element_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/ports.dart';
+import '../mocks.dart';
+
+main() {
+  PortsElement.tag.ensureRegistration();
+
+  const vm = const VMMock();
+  const isolate = const IsolateRefMock();
+  final events = new EventRepositoryMock();
+  final notifs = new NotificationRepositoryMock();
+  final ports = new PortsRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new PortsElement(vm, isolate, events, notifs, ports, instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.ports, equals(ports));
+  });
+  test('elements created after attachment', () async {
+    const elements = const [
+      const PortMock(name: 'port-1'),
+      const PortMock(name: 'port-2'),
+      const PortMock(name: 'port-3')
+    ];
+    const isolatePorts = const PortsMock(elements: elements);
+    final ports = new PortsRepositoryMock(
+      getter: expectAsync((i) async {
+        expect(i, equals(isolate));
+        return isolatePorts;
+      }, count: 1)
+    );
+    final instances = new InstanceRepositoryMock();
+    final e = new PortsElement(vm, isolate, events, notifs, ports, instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll('.port-number').length, equals(elements.length));
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/ports/element_test.html b/runtime/observatory/tests/observatory_ui/ports/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/ports/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/retaining_path/element_test.dart b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.dart
new file mode 100644
index 0000000..6bf7b71
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/instance_ref.dart';
+import 'package:observatory/src/elements/retaining_path.dart';
+import '../mocks.dart';
+
+main() {
+  RetainingPathElement.tag.ensureRegistration();
+
+  final cTag = CurlyBlockElement.tag.name;
+  final iTag = InstanceRefElement.tag.name;
+
+  const isolate = const IsolateRefMock();
+  const object = const InstanceRefMock();
+  final paths = new RetainingPathRepositoryMock();
+  final instances = new InstanceRepositoryMock();
+  test('instantiation', () {
+    final e = new RetainingPathElement(isolate, object, paths, instances);
+    expect(e, isNotNull, reason: 'element correctly created');
+    expect(e.isolate, equals(isolate));
+    expect(e.object, equals(object));
+  });
+  test('elements created after attachment', () async {
+    const source = const InstanceRefMock(id: 'source-id', name: 'source_name');
+    const path = const RetainingPathMock(elements: const [
+      const RetainingPathItemMock(source: source)
+    ]);
+    bool invoked = false;
+    final paths = new RetainingPathRepositoryMock(
+      getter: expectAsync((i, id) async {
+        expect(i, equals(isolate));
+        expect(id, equals(object.id));
+        invoked = true;
+        return path;
+      }, count: 1)
+    );
+    final instances = new InstanceRepositoryMock();
+    final e = new RetainingPathElement(isolate, object, paths, instances);
+    document.body.append(e);
+    await e.onRendered.first;
+    expect(invoked, isFalse);
+    expect(e.children.length, isNonZero, reason: 'has elements');
+    expect(e.querySelectorAll(iTag).length, isZero);
+    (e.querySelector(cTag) as CurlyBlockElement).toggle();
+    await e.onRendered.first;
+    expect(invoked, isTrue);
+    expect(e.querySelectorAll(iTag).length, equals(1));
+    e.remove();
+    await e.onRendered.first;
+    expect(e.children.length, isZero, reason: 'is empty');
+  });
+}
diff --git a/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/retaining_path/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
+  <style>
+     .unittest-table { font-family:monospace; border:1px; }
+     .unittest-pass { background: #6b3;}
+     .unittest-fail { background: #d55;}
+     .unittest-error { background: #a11;}
+  </style>
+  <script src="/packages/web_components/webcomponents.js"></script>
+  <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+  <script type="text/javascript"
+      src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/service/contexts_test.dart b/runtime/observatory/tests/service/contexts_test.dart
index 12bbbfb..c91bfce 100644
--- a/runtime/observatory/tests/service/contexts_test.dart
+++ b/runtime/observatory/tests/service/contexts_test.dart
@@ -74,8 +74,9 @@
         expect(block.context.isContext, isTrue);
         expect(block.context.length, equals(1));
         return block.context.load().then((Context ctxt) {
-          expect(ctxt.variables.single['value'].isString, isTrue);
-          expect(ctxt.variables.single['value'].valueAsString, equals('I could be copied into the block'));
+          expect(ctxt.variables.single.value.asValue.isString, isTrue);
+          expect(ctxt.variables.single.value.asValue.valueAsString,
+              equals('I could be copied into the block'));
           expect(ctxt.parentContext.isContext, isTrue);
           expect(ctxt.parentContext.length, equals(0));
           return ctxt.parentContext.load().then((Context outerCtxt) {
@@ -94,9 +95,9 @@
         expect(block.isClosure, isTrue);
         expect(block.context.isContext, isTrue);
         expect(block.context.length, equals(1));
-        return block.context.load().then((ctxt) {
-          expect(ctxt.variables.single['value'].isInt, isTrue);
-          expect(ctxt.variables.single['value'].valueAsString, equals('43'));
+        return block.context.load().then((Context ctxt) {
+          expect(ctxt.variables.single.value.asValue.isInt, isTrue);
+          expect(ctxt.variables.single.value.asValue.valueAsString, equals('43'));
           expect(ctxt.parentContext.isContext, isTrue);
           expect(ctxt.parentContext.length, equals(0));
           return ctxt.parentContext.load().then((Context outerCtxt) {
@@ -116,13 +117,15 @@
         expect(block.context.isContext, isTrue);
         expect(block.context.length, equals(1));
         return block.context.load().then((Context ctxt) {
-          expect(ctxt.variables.single['value'].isInt, isTrue);
-          expect(ctxt.variables.single['value'].valueAsString, equals('4201'));
+          expect(ctxt.variables.single.value.asValue.isInt, isTrue);
+          expect(ctxt.variables.single.value.asValue.valueAsString,
+              equals('4201'));
           expect(ctxt.parentContext.isContext, isTrue);
           expect(ctxt.parentContext.length, equals(1));
           return ctxt.parentContext.load().then((Context outerCtxt) {
-            expect(outerCtxt.variables.single['value'].isInt, isTrue);
-            expect(outerCtxt.variables.single['value'].valueAsString, equals('421'));
+            expect(outerCtxt.variables.single.value.asValue.isInt, isTrue);
+            expect(outerCtxt.variables.single.value.asValue.valueAsString,
+                equals('421'));
             expect(outerCtxt.parentContext.isContext, isTrue);
             expect(outerCtxt.parentContext.length, equals(0));
             return outerCtxt.parentContext.load().then((Context outerCtxt2) {
diff --git a/runtime/observatory/tests/service/dominator_tree_test.dart b/runtime/observatory/tests/service/dominator_tree_test.dart
index 5c279c9..037fbeb 100644
--- a/runtime/observatory/tests/service/dominator_tree_test.dart
+++ b/runtime/observatory/tests/service/dominator_tree_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 // VMOptions=--error_on_bad_type --error_on_bad_override
 
+import 'package:observatory/heap_snapshot.dart';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 import 'test_helper.dart';
@@ -56,8 +57,10 @@
 
 var tests = [
 (Isolate isolate) async {
-  var rootLib = await isolate.rootLibrary.load();
-  var snapshot = await isolate.fetchHeapSnapshot(false).last;
+  final rootLib = await isolate.rootLibrary.load();
+  final raw = await isolate.fetchHeapSnapshot(false).last;
+  final snapshot = new HeapSnapshot();
+  await snapshot.loadProgress(isolate, raw).last;
 
   node(String className) {
     var cls = rootLib.classes.singleWhere((cls) => cls.name == className);
diff --git a/runtime/observatory/tests/service/graph_test.dart b/runtime/observatory/tests/service/graph_test.dart
index 424747b..85556ba 100644
--- a/runtime/observatory/tests/service/graph_test.dart
+++ b/runtime/observatory/tests/service/graph_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 // VMOptions=--error_on_bad_type --error_on_bad_override
 
+import 'package:observatory/heap_snapshot.dart';
 import 'package:observatory/object_graph.dart';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
@@ -42,7 +43,9 @@
   Class fooClass = lib.classes.first;
   fooId = fooClass.vmCid;
 
-  HeapSnapshot snapshot = await isolate.fetchHeapSnapshot(false).last;
+  RawHeapSnapshot raw = await isolate.fetchHeapSnapshot(false).last;
+  HeapSnapshot snapshot = new HeapSnapshot();
+  await snapshot.loadProgress(isolate, raw).last;
   ObjectGraph graph = snapshot.graph;
 
   expect(fooId, isNotNull);
diff --git a/runtime/observatory/update_sources.py b/runtime/observatory/update_sources.py
new file mode 100755
index 0000000..92752e9
--- /dev/null
+++ b/runtime/observatory/update_sources.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# Updates the list of Observatory source files.
+
+import os
+import sys
+from datetime import date
+
+def getDir(rootdir, target):
+    sources = []
+    for root, subdirs, files in os.walk(rootdir):
+        subdirs.sort()
+        files.sort()
+        for f in files:
+            sources.append(root + '/' + f)
+    return sources
+
+def main():
+    target = open('observatory_sources.gypi', 'w')
+    target.write('# Copyright (c) ')
+    target.write(str(date.today().year))
+    target.write(', the Dart project authors.  Please see the AUTHORS file\n');
+    target.write('# for details. All rights reserved. Use of this source code is governed by a\n');
+    target.write('# BSD-style license that can be found in the LICENSE file.\n');
+    target.write('\n');
+    target.write('# This file contains all dart, css, and html sources for Observatory.\n');
+    target.write('{\n  \'sources\': [\n')
+    sources = []
+    for rootdir in ['lib', 'web']:
+        sources.extend(getDir(rootdir, target))
+    sources.sort()
+    for s in sources:
+        if (s[-9:] != 'README.md'):
+            target.write('    \'' + s + '\',\n')
+    target.write('  ]\n}\n')
+    target.close()
+
+if __name__ == "__main__":
+   main()
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
index 5b4cc05..44152e6 100644
--- a/runtime/platform/text_buffer.cc
+++ b/runtime/platform/text_buffer.cc
@@ -32,8 +32,8 @@
 }
 
 
-const char* TextBuffer::Steal() {
-  const char* r = buf_;
+char* TextBuffer::Steal() {
+  char* r = buf_;
   buf_ = NULL;
   buf_size_ = 0;
   msg_len_ = 0;
diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h
index 6155cc4..973ca7e 100644
--- a/runtime/platform/text_buffer.h
+++ b/runtime/platform/text_buffer.h
@@ -34,7 +34,7 @@
 
   // Steal ownership of the buffer pointer.
   // NOTE: TextBuffer is empty afterwards.
-  const char* Steal();
+  char* Steal();
 
  private:
   void EnsureCapacity(intptr_t len);
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index 3d4b07f..2dc0be48a 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -266,262 +266,6 @@
 }
 
 
-static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
-  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
-  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
-    return instr;
-  }
-  return NULL;
-}
-
-
-static bool IsPositiveOrZeroSmiConst(Definition* d) {
-  ConstantInstr* const_instr = d->AsConstant();
-  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
-    return Smi::Cast(const_instr->value()).Value() >= 0;
-  }
-  return false;
-}
-
-
-void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
-    Definition* bit_and_instr,
-    Definition* left_instr,
-    Definition* right_instr) {
-  ASSERT(bit_and_instr != NULL);
-  ASSERT((left_instr != NULL) && (right_instr != NULL));
-
-  // Check for pattern, smi_shift_left must be single-use.
-  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
-  if (!is_positive_or_zero) {
-    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
-  }
-  if (!is_positive_or_zero) return;
-
-  BinarySmiOpInstr* smi_shift_left = NULL;
-  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
-    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
-  }
-  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
-    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
-  }
-  if (smi_shift_left == NULL) return;
-
-  // Pattern recognized.
-  smi_shift_left->mark_truncating();
-  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
-  if (bit_and_instr->IsBinaryMintOp()) {
-    // Replace Mint op with Smi op.
-    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
-        Token::kBIT_AND,
-        new(Z) Value(left_instr),
-        new(Z) Value(right_instr),
-        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
-    bit_and_instr->ReplaceWith(smi_op, current_iterator());
-  }
-}
-
-
-void AotOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
-                                                   intptr_t index,
-                                                   Representation rep,
-                                                   intptr_t cid) {
-  ExtractNthOutputInstr* extract =
-      new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
-  instr->ReplaceUsesWith(extract);
-  flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
-}
-
-
-// Dart:
-//  var x = d % 10;
-//  var y = d ~/ 10;
-//  var z = x + y;
-//
-// IL:
-//  v4 <- %(v2, v3)
-//  v5 <- ~/(v2, v3)
-//  v6 <- +(v4, v5)
-//
-// IL optimized:
-//  v4 <- DIVMOD(v2, v3);
-//  v5 <- LoadIndexed(v4, 0); // ~/ result
-//  v6 <- LoadIndexed(v4, 1); // % result
-//  v7 <- +(v5, v6)
-// Because of the environment it is important that merged instruction replaces
-// first original instruction encountered.
-void AotOptimizer::TryMergeTruncDivMod(
-    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
-  if (merge_candidates->length() < 2) {
-    // Need at least a TRUNCDIV and a MOD.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
-           (curr_instr->op_kind() == Token::kMOD));
-    // Check if there is kMOD/kTRUNDIV binop with same inputs.
-    const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
-        Token::kMOD : Token::kTRUNCDIV;
-    Definition* left_def = curr_instr->left()->definition();
-    Definition* right_def = curr_instr->right()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
-      // 'other_binop' can be NULL if it was already merged.
-      if ((other_binop != NULL) &&
-          (other_binop->op_kind() == other_kind) &&
-          (other_binop->left()->definition() == left_def) &&
-          (other_binop->right()->definition() == right_def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(
-            curr_instr,
-            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
-            kTagged, kSmiCid);
-        ASSERT(other_binop->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_binop,
-            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
-            kTagged, kSmiCid);
-
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
-        args->Add(new(Z) Value(curr_instr->left()->definition()));
-        args->Add(new(Z) Value(curr_instr->right()->definition()));
-
-        // Replace with TruncDivMod.
-        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
-            args,
-            curr_instr->deopt_id(),
-            MergedMathInstr::kTruncDivMod);
-        curr_instr->ReplaceWith(div_mod, current_iterator());
-        other_binop->ReplaceUsesWith(div_mod);
-        other_binop->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
-        break;
-      }
-    }
-  }
-}
-
-
-// Tries to merge MathUnary operations, in this case sinus and cosinus.
-void AotOptimizer::TryMergeMathUnary(
-    GrowableArray<MathUnaryInstr*>* merge_candidates) {
-  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
-      !FLAG_merge_sin_cos) {
-    return;
-  }
-  if (merge_candidates->length() < 2) {
-    // Need at least a SIN and a COS.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    const intptr_t kind = curr_instr->kind();
-    ASSERT((kind == MathUnaryInstr::kSin) ||
-           (kind == MathUnaryInstr::kCos));
-    // Check if there is sin/cos binop with same inputs.
-    const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
-        MathUnaryInstr::kCos : MathUnaryInstr::kSin;
-    Definition* def = curr_instr->value()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      MathUnaryInstr* other_op = (*merge_candidates)[k];
-      // 'other_op' can be NULL if it was already merged.
-      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
-          (other_op->value()->definition() == def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(curr_instr,
-                                        MergedMathInstr::OutputIndexOf(kind),
-                                        kUnboxedDouble, kDoubleCid);
-        ASSERT(other_op->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_op,
-            MergedMathInstr::OutputIndexOf(other_kind),
-            kUnboxedDouble, kDoubleCid);
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
-        args->Add(new(Z) Value(curr_instr->value()->definition()));
-        // Replace with SinCos.
-        MergedMathInstr* sin_cos =
-            new(Z) MergedMathInstr(args,
-                                   curr_instr->DeoptimizationTarget(),
-                                   MergedMathInstr::kSinCos);
-        curr_instr->ReplaceWith(sin_cos, current_iterator());
-        other_op->ReplaceUsesWith(sin_cos);
-        other_op->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of sin/cos into sincos.
-        break;
-      }
-    }
-  }
-}
-
-
-// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
-// shift can be a truncating Smi shift-left and result is always Smi.
-// Merging occurs only per basic-block.
-void AotOptimizer::TryOptimizePatterns() {
-  if (!FLAG_truncating_left_shift) return;
-  ASSERT(current_iterator_ == NULL);
-  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
-  GrowableArray<MathUnaryInstr*> sin_cos_merge;
-  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
-       !block_it.Done();
-       block_it.Advance()) {
-    // Merging only per basic-block.
-    div_mod_merge.Clear();
-    sin_cos_merge.Clear();
-    ForwardInstructionIterator it(block_it.Current());
-    current_iterator_ = &it;
-    for (; !it.Done(); it.Advance()) {
-      if (it.Current()->IsBinarySmiOp()) {
-        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
-        if (binop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(binop,
-                                       binop->left()->definition(),
-                                       binop->right()->definition());
-        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
-                   (binop->op_kind() == Token::kMOD)) {
-          if (binop->HasUses()) {
-            div_mod_merge.Add(binop);
-          }
-        }
-      } else if (it.Current()->IsBinaryMintOp()) {
-        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
-        if (mintop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(mintop,
-                                       mintop->left()->definition(),
-                                       mintop->right()->definition());
-        }
-      } else if (it.Current()->IsMathUnary()) {
-        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
-        if ((math_unary->kind() == MathUnaryInstr::kSin) ||
-            (math_unary->kind() == MathUnaryInstr::kCos)) {
-          if (math_unary->HasUses()) {
-            sin_cos_merge.Add(math_unary);
-          }
-        }
-      }
-    }
-    TryMergeTruncDivMod(&div_mod_merge);
-    TryMergeMathUnary(&sin_cos_merge);
-    current_iterator_ = NULL;
-  }
-}
-
-
 static bool ClassIdIsOneOf(intptr_t class_id,
                            const GrowableArray<intptr_t>& class_ids) {
   for (intptr_t i = 0; i < class_ids.length(); i++) {
@@ -1332,182 +1076,6 @@
 }
 
 
-bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
-                                         MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kFloat32x4Shuffle) ||
-      (getter == MethodRecognizer::kFloat32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kFloat32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kFloat32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kFloat32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle)  ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleW));
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
-                                         MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  if ((getter == MethodRecognizer::kFloat64x2GetX) ||
-      (getter == MethodRecognizer::kFloat64x2GetY)) {
-    Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        0,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
-                                       MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kInt32x4Shuffle) ||
-      (getter == MethodRecognizer::kInt32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kInt32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kInt32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kInt32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4Shuffle) {
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-}
-
-
 bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
                                            Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
@@ -1648,28 +1216,6 @@
 }
 
 
-static bool IsSupportedByteArrayViewCid(intptr_t cid) {
-  switch (cid) {
-    case kTypedDataInt8ArrayCid:
-    case kTypedDataUint8ArrayCid:
-    case kExternalTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
-    case kExternalTypedDataUint8ClampedArrayCid:
-    case kTypedDataInt16ArrayCid:
-    case kTypedDataUint16ArrayCid:
-    case kTypedDataInt32ArrayCid:
-    case kTypedDataUint32ArrayCid:
-    case kTypedDataFloat32ArrayCid:
-    case kTypedDataFloat64ArrayCid:
-    case kTypedDataFloat32x4ArrayCid:
-    case kTypedDataInt32x4ArrayCid:
-      return true;
-    default:
-      return false;
-  }
-}
-
-
 // Inline only simple, frequently called core library methods.
 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
@@ -1685,48 +1231,6 @@
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(target);
 
-  if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
-      (recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
-      (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
-      ASSERT((class_ids[0] == kOneByteStringCid) ||
-             (class_ids[0] == kTwoByteStringCid) ||
-             (class_ids[0] == kExternalOneByteStringCid) ||
-             (class_ids[0] == kExternalTwoByteStringCid));
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (class_ids[0] == kOneByteStringCid) {
-    if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
-      // This is an internal method, no need to check argument types nor
-      // range.
-      Definition* str = call->ArgumentAt(0);
-      Definition* index = call->ArgumentAt(1);
-      Definition* value = call->ArgumentAt(2);
-      StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
-          new(Z) Value(str),
-          new(Z) Value(index),
-          new(Z) Value(value),
-          kNoStoreBarrier,
-          1,  // Index scale
-          kOneByteStringCid,
-          call->deopt_id(),
-          call->token_pos());
-      ReplaceCall(call, store_op);
-      return true;
-    }
-    return false;
-  }
-
   if (CanUnboxDouble() &&
       (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
     if (class_ids[0] == kSmiCid) {
@@ -1785,87 +1289,13 @@
           ReplaceCall(call, d2d_instr);
         }
         return true;
-      case MethodRecognizer::kDoubleAdd:
-      case MethodRecognizer::kDoubleSub:
-      case MethodRecognizer::kDoubleMul:
-      case MethodRecognizer::kDoubleDiv:
-        return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-            flow_graph_, current_iterator(), call);
       default:
-        // Unsupported method.
-        return false;
+        break;
     }
   }
 
-  if (IsSupportedByteArrayViewCid(class_ids[0])) {
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (class_ids[0] == kFloat32x4Cid) {
-    return TryInlineFloat32x4Method(call, recognized_kind);
-  }
-
-  if (class_ids[0] == kInt32x4Cid) {
-    return TryInlineInt32x4Method(call, recognized_kind);
-  }
-
-  if (class_ids[0] == kFloat64x2Cid) {
-    return TryInlineFloat64x2Method(call, recognized_kind);
-  }
-
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineFloat32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompiled_mode);
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineFloat64x2Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompiled_mode);
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineInt32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  ASSERT(FLAG_precompiled_mode);
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineFloat32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineFloat64x2Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  return false;
-}
-
-
-bool AotOptimizer::TryInlineInt32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  // Cannot handle unboxed instructions.
-  return false;
+  return FlowGraphInliner::TryReplaceInstanceCallWithInline(
+      flow_graph_, current_iterator(), call);
 }
 
 
@@ -2522,68 +1952,44 @@
 
 
 void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
-  if (!CanUnboxDouble()) {
+  if (!IsAllowedForInlining(call->deopt_id())) {
+    // Inlining disabled after a speculative inlining attempt.
     return;
   }
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(call->function());
-  MathUnaryInstr::MathUnaryKind unary_kind;
   switch (recognized_kind) {
-    case MethodRecognizer::kMathSqrt:
-      unary_kind = MathUnaryInstr::kSqrt;
-      break;
-    case MethodRecognizer::kMathSin:
-      unary_kind = MathUnaryInstr::kSin;
-      break;
-    case MethodRecognizer::kMathCos:
-      unary_kind = MathUnaryInstr::kCos;
-      break;
-    default:
-      unary_kind = MathUnaryInstr::kIllegal;
-      break;
-  }
-  if (unary_kind != MathUnaryInstr::kIllegal) {
-    ASSERT(FLAG_precompiled_mode);
-    // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
-    return;
-  }
-
-  switch (recognized_kind) {
+    case MethodRecognizer::kObjectConstructor:
+    case MethodRecognizer::kObjectArrayAllocate:
     case MethodRecognizer::kFloat32x4Zero:
     case MethodRecognizer::kFloat32x4Splat:
     case MethodRecognizer::kFloat32x4Constructor:
     case MethodRecognizer::kFloat32x4FromFloat64x2:
-      TryInlineFloat32x4Constructor(call, recognized_kind);
-      break;
     case MethodRecognizer::kFloat64x2Constructor:
     case MethodRecognizer::kFloat64x2Zero:
     case MethodRecognizer::kFloat64x2Splat:
     case MethodRecognizer::kFloat64x2FromFloat32x4:
-      TryInlineFloat64x2Constructor(call, recognized_kind);
-      break;
     case MethodRecognizer::kInt32x4BoolConstructor:
     case MethodRecognizer::kInt32x4Constructor:
-      TryInlineInt32x4Constructor(call, recognized_kind);
+    case MethodRecognizer::kMathSqrt:
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathSin:
+    case MethodRecognizer::kMathCos:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2:
+      FlowGraphInliner::TryReplaceStaticCallWithInline(
+          flow_graph_, current_iterator(), call);
       break;
-    case MethodRecognizer::kObjectConstructor: {
-      // Remove the original push arguments.
-      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-        PushArgumentInstr* push = call->PushArgumentAt(i);
-        push->ReplaceUsesWith(push->value()->definition());
-        push->RemoveFromGraph();
-      }
-      // Manually replace call with global null constant. ReplaceCall can't
-      // be used for definitions that are already in the graph.
-      call->ReplaceUsesWith(flow_graph_->constant_null());
-      ASSERT(current_iterator()->Current() == call);
-      current_iterator()->RemoveCurrentFromGraph();
-      break;
-    }
     case MethodRecognizer::kMathMin:
     case MethodRecognizer::kMathMax: {
       // We can handle only monomorphic min/max call sites with both arguments
       // being either doubles or smis.
-      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+      if (CanUnboxDouble() &&
+          call->HasICData() &&
+          (call->ic_data()->NumberOfChecks() == 1)) {
         const ICData& ic_data = *call->ic_data();
         intptr_t result_cid = kIllegalCid;
         if (ICDataHasReceiverArgumentClassIds(ic_data,
@@ -2617,16 +2023,6 @@
       }
       break;
     }
-    case MethodRecognizer::kMathDoublePow:
-    case MethodRecognizer::kMathTan:
-    case MethodRecognizer::kMathAsin:
-    case MethodRecognizer::kMathAcos:
-    case MethodRecognizer::kMathAtan:
-    case MethodRecognizer::kMathAtan2: {
-      ASSERT(FLAG_precompiled_mode);
-      // No UnboxDouble instructions allowed.
-      return;
-    }
     case MethodRecognizer::kDoubleFromInteger: {
       if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
         const ICData& ic_data = *call->ic_data();
@@ -2648,35 +2044,8 @@
       }
       break;
     }
-    default: {
-      if (call->function().IsFactory()) {
-        const Class& function_class =
-            Class::Handle(Z, call->function().Owner());
-        if ((function_class.library() == Library::CoreLibrary()) ||
-            (function_class.library() == Library::TypedDataLibrary())) {
-          intptr_t cid = FactoryRecognizer::ResultCid(call->function());
-          switch (cid) {
-            case kArrayCid: {
-              Value* type = new(Z) Value(call->ArgumentAt(0));
-              Value* num_elements = new(Z) Value(call->ArgumentAt(1));
-              if (num_elements->BindsToConstant() &&
-                  num_elements->BoundConstant().IsSmi()) {
-                intptr_t length =
-                    Smi::Cast(num_elements->BoundConstant()).Value();
-                if (length >= 0 && length <= Array::kMaxElements) {
-                  CreateArrayInstr* create_array =
-                      new(Z) CreateArrayInstr(
-                          call->token_pos(), type, num_elements);
-                  ReplaceCall(call, create_array);
-                }
-              }
-            }
-            default:
-              break;
-          }
-        }
-      }
-    }
+    default:
+      break;
   }
 }
 
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index 6c4586e..972a71c 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -41,11 +41,6 @@
   // Use propagated class ids to optimize, replace or eliminate instructions.
   void ApplyClassIds();
 
-  // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
-  // shift can be a truncating Smi shift-left and result is always Smi.
-  // Merge instructions (only per basic-block).
-  void TryOptimizePatterns();
-
   void ReplaceArrayBoundChecks();
 
   virtual void VisitStaticCall(StaticCallInstr* instr);
@@ -78,18 +73,6 @@
                                const ICData& unary_ic_data);
 
   bool TryInlineInstanceMethod(InstanceCallInstr* call);
-  bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Constructor(StaticCallInstr* call,
-                                    MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat32x4Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Method(InstanceCallInstr* call,
-                               MethodRecognizer::Kind recognized_kind);
   void ReplaceWithInstanceOf(InstanceCallInstr* instr);
   bool TypeCheckAsClassEquality(const AbstractType& type);
   void ReplaceWithTypeCast(InstanceCallInstr* instr);
@@ -127,12 +110,6 @@
   bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
                                    RawFunction::Kind kind) const;
 
-  bool InlineFloat32x4Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineFloat64x2Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineInt32x4Getter(InstanceCallInstr* call,
-                            MethodRecognizer::Kind getter);
   bool InlineFloat32x4BinaryOp(InstanceCallInstr* call,
                                Token::Kind op_kind);
   bool InlineInt32x4BinaryOp(InstanceCallInstr* call,
@@ -148,14 +125,6 @@
   void ReplaceWithMathCFunction(InstanceCallInstr* call,
                                 MethodRecognizer::Kind recognized_kind);
 
-  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
-                                    Definition* left_instr,
-                                    Definition* right_instr);
-  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
-  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
-
-  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
-                                       Representation rep, intptr_t cid);
   bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
 
   RawField* GetField(intptr_t class_id, const String& field_name);
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
index 0850584..5424805 100644
--- a/runtime/vm/become.cc
+++ b/runtime/vm/become.cc
@@ -261,6 +261,13 @@
     }
 
     ForwardObjectTo(before_obj, after_obj);
+
+    // Forward the identity hash too if it has one.
+    intptr_t hash = heap->GetHash(before_obj);
+    if (hash != 0) {
+      ASSERT(heap->GetHash(after_obj) == 0);
+      heap->SetHash(after_obj, hash);
+    }
   }
 
   {
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 161d0b2..d7cb2b2 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -182,20 +182,6 @@
   V(TypedData_Float32x4Array_new, 2)                                           \
   V(TypedData_Int32x4Array_new, 2)                                             \
   V(TypedData_Float64x2Array_new, 2)                                           \
-  V(ExternalTypedData_Int8Array_new, 2)                                        \
-  V(ExternalTypedData_Uint8Array_new, 2)                                       \
-  V(ExternalTypedData_Uint8ClampedArray_new, 2)                                \
-  V(ExternalTypedData_Int16Array_new, 2)                                       \
-  V(ExternalTypedData_Uint16Array_new, 2)                                      \
-  V(ExternalTypedData_Int32Array_new, 2)                                       \
-  V(ExternalTypedData_Uint32Array_new, 2)                                      \
-  V(ExternalTypedData_Int64Array_new, 2)                                       \
-  V(ExternalTypedData_Uint64Array_new, 2)                                      \
-  V(ExternalTypedData_Float32Array_new, 2)                                     \
-  V(ExternalTypedData_Float64Array_new, 2)                                     \
-  V(ExternalTypedData_Float32x4Array_new, 2)                                   \
-  V(ExternalTypedData_Int32x4Array_new, 2)                                     \
-  V(ExternalTypedData_Float64x2Array_new, 2)                                   \
   V(TypedData_length, 1)                                                       \
   V(TypedData_setRange, 7)                                                     \
   V(TypedData_GetInt8, 2)                                                      \
@@ -330,7 +316,6 @@
   V(Internal_makeListFixedLength, 1)                                           \
   V(Internal_makeFixedListUnmodifiable, 1)                                     \
   V(Internal_inquireIs64Bit, 0)                                                \
-  V(LinkedHashMap_allocate, 1)                                                 \
   V(LinkedHashMap_getIndex, 1)                                                 \
   V(LinkedHashMap_setIndex, 2)                                                 \
   V(LinkedHashMap_getData, 1)                                                  \
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index ca1ba0b..d780981 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1086,7 +1086,7 @@
 
   // Patch to call through stub.
   const Code& stub =
-      Code::Handle(zone, StubCode::ICLookupThroughCode_entry()->code());
+      Code::Handle(zone, StubCode::ICCallThroughCode_entry()->code());
   ASSERT(!Isolate::Current()->compilation_allowed());
   CodePatcher::PatchSwitchableCallAt(caller_frame->pc(),
                                      caller_code,
@@ -1190,7 +1190,7 @@
         const Code& caller_code =
             Code::Handle(zone, caller_frame->LookupDartCode());
         const Code& stub =
-            Code::Handle(zone, StubCode::MegamorphicLookup_entry()->code());
+            Code::Handle(zone, StubCode::MegamorphicCall_entry()->code());
 
         CodePatcher::PatchSwitchableCallAt(caller_frame->pc(), caller_code,
                                            cache, stub);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index ace33b0..4fee793 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -806,7 +806,7 @@
 
         // Optimize (a << b) & c patterns, merge operations.
         // Run early in order to have more opportunity to optimize left shifts.
-        optimizer.TryOptimizePatterns();
+        flow_graph->TryOptimizePatterns();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         FlowGraphInliner::SetInliningId(flow_graph, 0);
@@ -953,7 +953,7 @@
         // Optimize (a << b) & c patterns, merge operations.
         // Run after CSE in order to have more opportunity to merge
         // instructions that have same inputs.
-        optimizer.TryOptimizePatterns();
+        flow_graph->TryOptimizePatterns();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h
index 3f950df..f5b2117 100644
--- a/runtime/vm/constants_dbc.h
+++ b/runtime/vm/constants_dbc.h
@@ -197,10 +197,10 @@
 //    the immediately following instruction is skipped. These instructions
 //    expect their operands to be Smis, but don't check that they are.
 //
-//  - ShrImm rA, rB, rC
+//  - ShlImm rA, rB, rC
 //
-//    FP[rA] <- FP[rB] >> rC. Shifts the Smi in FP[rB] right by rC. rC is
-//    assumed to be a legal positive number by which righ-shifting is possible.
+//    FP[rA] <- FP[rB] << rC. Shifts the Smi in FP[rB] left by rC. rC is
+//    assumed to be a legal positive number by which left-shifting is possible.
 //
 //  - Min, Max rA, rB, rC
 //
@@ -243,6 +243,20 @@
 //    FP[rD] is not a double or a Smi. When FP[rD] is a Smi, converts it to a
 //    double.
 //
+//  - UnboxInt32 rA, rB, C
+//
+//    Unboxes the integer in FP[rB] into FP[rA]. If C == 1, the value may be
+//    truncated. If FP[rA] is successfully unboxed the following instruction is
+//    skipped.
+//
+//  - BoxInt32 rA, rD
+//
+//    Boxes the unboxed signed 32-bit integer in FP[rD] into FP[rA].
+//
+//  - BoxUint32 rA, rD
+//
+//    Boxes the unboxed unsigned 32-bit integer in FP[rD] into FP[rA].
+//
 //  - SmiToDouble rA, rD
 //
 //    Convert the Smi in FP[rD] to an unboxed double in FP[rA].
@@ -313,20 +327,36 @@
 //    Store FP[rC] into array FP[rA] at index FP[rB]. No typechecking is done.
 //    FP[rA] is assumed to be a RawArray, FP[rB] to be a smi.
 //
-//  - StoreFloat64Indexed rA, rB, rC
+//  - StoreIndexed{N}{Float64, Uint8, OneByteString} rA, rB, rC
 //
-//    Store the unboxed double in FP[rC] into the typed data array at FP[rA]
-//    at index FP[rB].
+//    Where N is '' or '8'. N may only be '8' for Float64.
+//
+//    Store the unboxed double or tagged Smi in FP[rC] into the typed data array
+//    at FP[rA] at index FP[rB]. If N is not '', the index is assumed to be
+//    already scaled by N.
+//
+//  - StoreIndexedExternalUint8 rA, rB, rC
+//
+//    Similar to StoreIndexedUint8 but FP[rA] is an external typed data aray.
 //
 //  - LoadIndexed rA, rB, rC
 //
 //    Loads from array FP[rB] at index FP[rC] into FP[rA]. No typechecking is
 //    done. FP[rB] is assumed to be a RawArray, and to contain a Smi at FP[rC].
 //
-//  - Load{Float64, OneByteString, TwoByteString}Indexed rA, rB, rC
+//  - LoadIndexed{N}{Type} rA, rB, rC
+//
+//    Where Type is Float64, OneByteString, TwoByteString, Uint8, or Int8,
+//    and N is '' or '8'. N may only be '8' for Float64.
 //
 //    Loads from typed data array FP[rB] at index FP[rC] into an unboxed double,
-//    or tagged Smi in FP[rA] as indicated by the type in the name.
+//    or tagged Smi in FP[rA] as indicated by the type in the name. If N is not
+//    '', the index is assumed to be already scaled by N.
+//
+//  - LoadIndexedExternal{Int8, Uint8} rA, rB, rC
+//
+//    Loads from the external typed data array FP[rB] at index FP[rC] into
+//    FP[rA]. No typechecking is done.
 //
 //  - StoreField rA, B, rC
 //
@@ -340,6 +370,10 @@
 //
 //    Load value at offset (in words) C from object FP[rB] into FP[rA].
 //
+//  - LoadUntagged rA, rB, C
+//
+//    Like LoadField, but assumes that FP[rB] is untagged.
+//
 //  - LoadFieldTOS D
 //
 //    Push value at offset (in words) D from object SP[0].
@@ -594,7 +628,7 @@
   V(Mod,                         A_B_C, reg, reg, reg) \
   V(Shl,                         A_B_C, reg, reg, reg) \
   V(Shr,                         A_B_C, reg, reg, reg) \
-  V(ShrImm,                      A_B_C, reg, reg, num) \
+  V(ShlImm,                      A_B_C, reg, reg, num) \
   V(Neg,                           A_D, reg, reg, ___) \
   V(BitOr,                       A_B_C, reg, reg, reg) \
   V(BitAnd,                      A_B_C, reg, reg, reg) \
@@ -605,6 +639,9 @@
   V(WriteIntoDouble,               A_D, reg, reg, ___) \
   V(UnboxDouble,                   A_D, reg, reg, ___) \
   V(CheckedUnboxDouble,            A_D, reg, reg, ___) \
+  V(UnboxInt32,                  A_B_C, reg, reg, num) \
+  V(BoxInt32,                      A_D, reg, reg, ___) \
+  V(BoxUint32,                     A_D, reg, reg, ___) \
   V(SmiToDouble,                   A_D, reg, reg, ___) \
   V(DoubleToSmi,                   A_D, reg, reg, ___) \
   V(DAdd,                        A_B_C, reg, reg, reg) \
@@ -651,14 +688,27 @@
   V(AllocateT,                       0, ___, ___, ___) \
   V(StoreIndexedTOS,                 0, ___, ___, ___) \
   V(StoreIndexed,                A_B_C, reg, reg, reg) \
-  V(StoreFloat64Indexed,         A_B_C, reg, reg, reg) \
+  V(StoreIndexedUint8,           A_B_C, reg, reg, reg) \
+  V(StoreIndexedExternalUint8,   A_B_C, reg, reg, reg) \
+  V(StoreIndexedOneByteString,   A_B_C, reg, reg, reg) \
+  V(StoreIndexedUint32,          A_B_C, reg, reg, reg) \
+  V(StoreIndexedFloat64,         A_B_C, reg, reg, reg) \
+  V(StoreIndexed8Float64,        A_B_C, reg, reg, reg) \
   V(LoadIndexed,                 A_B_C, reg, reg, reg) \
-  V(LoadFloat64Indexed,          A_B_C, reg, reg, reg) \
-  V(LoadOneByteStringIndexed,    A_B_C, reg, reg, reg) \
-  V(LoadTwoByteStringIndexed,    A_B_C, reg, reg, reg) \
+  V(LoadIndexedUint8,            A_B_C, reg, reg, reg) \
+  V(LoadIndexedInt8,             A_B_C, reg, reg, reg) \
+  V(LoadIndexedInt32,            A_B_C, reg, reg, reg) \
+  V(LoadIndexedUint32,           A_B_C, reg, reg, reg) \
+  V(LoadIndexedExternalUint8,    A_B_C, reg, reg, reg) \
+  V(LoadIndexedExternalInt8,     A_B_C, reg, reg, reg) \
+  V(LoadIndexedFloat64,          A_B_C, reg, reg, reg) \
+  V(LoadIndexed8Float64,         A_B_C, reg, reg, reg) \
+  V(LoadIndexedOneByteString,    A_B_C, reg, reg, reg) \
+  V(LoadIndexedTwoByteString,    A_B_C, reg, reg, reg) \
   V(StoreField,                  A_B_C, reg, num, reg) \
   V(StoreFieldTOS,                   D, num, ___, ___) \
   V(LoadField,                   A_B_C, reg, reg, num) \
+  V(LoadUntagged,                A_B_C, reg, reg, num) \
   V(LoadFieldTOS,                    D, num, ___, ___) \
   V(BooleanNegateTOS,                0, ___, ___, ___) \
   V(BooleanNegate,                 A_D, reg, reg, ___) \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 61bd28f..e64c399 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6127,7 +6127,7 @@
   // Steal output from JSONStream.
   char* output = NULL;
   intptr_t output_length = 0;
-  js->Steal(const_cast<const char**>(&output), &output_length);
+  js->Steal(&output, &output_length);
   if (output_length < 3) {
     // Empty JSON array.
     free(output);
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 8d913dc..d8a9299 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -6653,7 +6653,7 @@
       "part of library1_name;\n"
       "external int foo();";
   const char* kPatchChars =
-      "@patch int foo() => 42;";
+      "patch int foo() => 42;";
 
   // Load up a library.
   Dart_Handle url = NewString("library1_url");
@@ -6698,8 +6698,8 @@
       "}";
   const char* kPatchChars =
       "const _UNDEFINED = const Object();\n"
-      "@patch foo([x=_UNDEFINED]) => identical(x, _UNDEFINED) ? 42 : x;\n"
-      "@patch class Foo {\n"
+      "patch foo([x=_UNDEFINED]) => identical(x, _UNDEFINED) ? 42 : x;\n"
+      "patch class Foo {\n"
       "  static addDefault10([x=_UNDEFINED, y=_UNDEFINED]) {\n"
       "    if (identical(x, _UNDEFINED)) x = 10;\n"
       "    if (identical(y, _UNDEFINED)) y = 10;\n"
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index ed04af0..18fee76 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -1186,9 +1186,8 @@
         return false;
       }
 
-      Utf8::Type type;
+      Utf8::Type type = Utf8::kLatin1;
       intptr_t len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type);
-      ASSERT(len > 0);
       if (len > String::kMaxElements) {
         return false;
       }
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 7daddd9..d23492c 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -94,6 +94,8 @@
   "Ratio of getter/setter usage used for double field unboxing heuristics")    \
 P(guess_icdata_cid, bool, true,                                                \
   "Artificially create type feedback for arithmetic etc. operations")          \
+P(huge_method_cutoff_in_tokens, int, 20000,                                    \
+  "Huge method cutoff in tokens: Disables optimizations for huge methods.")    \
 P(interpret_irregexp, bool, USING_DBC,                                         \
   "Use irregexp bytecode interpreter")                                         \
 P(lazy_dispatchers, bool, true,                                                \
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 4ab5652..89ed20d 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -2054,4 +2054,264 @@
 }
 
 
+// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
+// shift can be a truncating Smi shift-left and result is always Smi.
+// Merging occurs only per basic-block.
+void FlowGraph::TryOptimizePatterns() {
+  if (!FLAG_truncating_left_shift) return;
+  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
+  GrowableArray<InvokeMathCFunctionInstr*> sin_cos_merge;
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    // Merging only per basic-block.
+    div_mod_merge.Clear();
+    sin_cos_merge.Clear();
+    ForwardInstructionIterator it(block_it.Current());
+    for (; !it.Done(); it.Advance()) {
+      if (it.Current()->IsBinarySmiOp()) {
+        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
+        if (binop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(&it,
+                                       binop,
+                                       binop->left()->definition(),
+                                       binop->right()->definition());
+        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
+                   (binop->op_kind() == Token::kMOD)) {
+          if (binop->HasUses()) {
+            div_mod_merge.Add(binop);
+          }
+        }
+      } else if (it.Current()->IsBinaryMintOp()) {
+        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
+        if (mintop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(&it,
+                                       mintop,
+                                       mintop->left()->definition(),
+                                       mintop->right()->definition());
+        }
+      } else if (it.Current()->IsInvokeMathCFunction()) {
+        InvokeMathCFunctionInstr* math_unary =
+            it.Current()->AsInvokeMathCFunction();
+        if ((math_unary->recognized_kind() == MethodRecognizer::kMathSin) ||
+            (math_unary->recognized_kind() == MethodRecognizer::kMathCos)) {
+          if (math_unary->HasUses()) {
+            sin_cos_merge.Add(math_unary);
+          }
+        }
+      }
+    }
+    TryMergeTruncDivMod(&div_mod_merge);
+    TryMergeMathUnary(&sin_cos_merge);
+  }
+}
+
+
+static bool IsPositiveOrZeroSmiConst(Definition* d) {
+  ConstantInstr* const_instr = d->AsConstant();
+  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
+    return Smi::Cast(const_instr->value()).Value() >= 0;
+  }
+  return false;
+}
+
+
+static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
+  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
+  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
+    return instr;
+  }
+  return NULL;
+}
+
+
+void FlowGraph::OptimizeLeftShiftBitAndSmiOp(
+    ForwardInstructionIterator* current_iterator,
+    Definition* bit_and_instr,
+    Definition* left_instr,
+    Definition* right_instr) {
+  ASSERT(bit_and_instr != NULL);
+  ASSERT((left_instr != NULL) && (right_instr != NULL));
+
+  // Check for pattern, smi_shift_left must be single-use.
+  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
+  if (!is_positive_or_zero) {
+    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
+  }
+  if (!is_positive_or_zero) return;
+
+  BinarySmiOpInstr* smi_shift_left = NULL;
+  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
+    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
+  }
+  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
+    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
+  }
+  if (smi_shift_left == NULL) return;
+
+  // Pattern recognized.
+  smi_shift_left->mark_truncating();
+  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
+  if (bit_and_instr->IsBinaryMintOp()) {
+    // Replace Mint op with Smi op.
+    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
+        Token::kBIT_AND,
+        new(Z) Value(left_instr),
+        new(Z) Value(right_instr),
+        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
+    bit_and_instr->ReplaceWith(smi_op, current_iterator);
+  }
+}
+
+
+// Dart:
+//  var x = d % 10;
+//  var y = d ~/ 10;
+//  var z = x + y;
+//
+// IL:
+//  v4 <- %(v2, v3)
+//  v5 <- ~/(v2, v3)
+//  v6 <- +(v4, v5)
+//
+// IL optimized:
+//  v4 <- DIVMOD(v2, v3);
+//  v5 <- LoadIndexed(v4, 0); // ~/ result
+//  v6 <- LoadIndexed(v4, 1); // % result
+//  v7 <- +(v5, v6)
+// Because of the environment it is important that merged instruction replaces
+// first original instruction encountered.
+void FlowGraph::TryMergeTruncDivMod(
+    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
+  if (merge_candidates->length() < 2) {
+    // Need at least a TRUNCDIV and a MOD.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
+           (curr_instr->op_kind() == Token::kMOD));
+    // Check if there is kMOD/kTRUNDIV binop with same inputs.
+    const Token::Kind other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
+        Token::kMOD : Token::kTRUNCDIV;
+    Definition* left_def = curr_instr->left()->definition();
+    Definition* right_def = curr_instr->right()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
+      // 'other_binop' can be NULL if it was already merged.
+      if ((other_binop != NULL) &&
+          (other_binop->op_kind() == other_kind) &&
+          (other_binop->left()->definition() == left_def) &&
+          (other_binop->right()->definition() == right_def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(
+            curr_instr,
+            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
+            kTagged, kSmiCid);
+        ASSERT(other_binop->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_binop,
+            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
+            kTagged, kSmiCid);
+
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
+        args->Add(new(Z) Value(curr_instr->left()->definition()));
+        args->Add(new(Z) Value(curr_instr->right()->definition()));
+
+        // Replace with TruncDivMod.
+        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
+            args,
+            curr_instr->deopt_id(),
+            MergedMathInstr::kTruncDivMod);
+        curr_instr->ReplaceWith(div_mod, NULL);
+        other_binop->ReplaceUsesWith(div_mod);
+        other_binop->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
+        break;
+      }
+    }
+  }
+}
+
+
+// Tries to merge MathUnary operations, in this case sine and cosine.
+void FlowGraph::TryMergeMathUnary(
+    GrowableArray<InvokeMathCFunctionInstr*>* merge_candidates) {
+  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
+      !FLAG_merge_sin_cos) {
+    return;
+  }
+  if (merge_candidates->length() < 2) {
+    // Need at least a SIN and a COS.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    InvokeMathCFunctionInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    const MethodRecognizer::Kind kind = curr_instr->recognized_kind();
+    ASSERT((kind == MethodRecognizer::kMathSin) ||
+           (kind == MethodRecognizer::kMathCos));
+    // Check if there is sin/cos binop with same inputs.
+    const MethodRecognizer::Kind other_kind =
+        (kind == MethodRecognizer::kMathSin)
+        ? MethodRecognizer::kMathCos : MethodRecognizer::kMathSin;
+    Definition* def = curr_instr->InputAt(0)->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      InvokeMathCFunctionInstr* other_op = (*merge_candidates)[k];
+      // 'other_op' can be NULL if it was already merged.
+      if ((other_op != NULL) && (other_op->recognized_kind() == other_kind) &&
+          (other_op->InputAt(0)->definition() == def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(curr_instr,
+                                        MergedMathInstr::OutputIndexOf(kind),
+                                        kUnboxedDouble, kDoubleCid);
+        ASSERT(other_op->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_op,
+            MergedMathInstr::OutputIndexOf(other_kind),
+            kUnboxedDouble, kDoubleCid);
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
+        args->Add(new(Z) Value(curr_instr->InputAt(0)->definition()));
+        // Replace with SinCos.
+        MergedMathInstr* sin_cos =
+            new(Z) MergedMathInstr(args,
+                                   curr_instr->DeoptimizationTarget(),
+                                   MergedMathInstr::kSinCos);
+        curr_instr->ReplaceWith(sin_cos, NULL);
+        other_op->ReplaceUsesWith(sin_cos);
+        other_op->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of sin/cos into sincos.
+        break;
+      }
+    }
+  }
+}
+
+
+void FlowGraph::AppendExtractNthOutputForMerged(Definition* instr,
+                                                intptr_t index,
+                                                Representation rep,
+                                                intptr_t cid) {
+  ExtractNthOutputInstr* extract =
+      new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
+  instr->ReplaceUsesWith(extract);
+  InsertAfter(instr, extract, NULL, FlowGraph::kValue);
+}
+
+
+
+
 }  // namespace dart
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 0c7aa52..e4a0a3c 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -305,6 +305,11 @@
 
   bool IsReceiver(Definition* def) const;
 
+  // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
+  // shift can be a truncating Smi shift-left and result is always Smi.
+  // Merge instructions (only per basic-block).
+  void TryOptimizePatterns();
+
  private:
   friend class IfConverter;
   friend class BranchSimplifier;
@@ -361,6 +366,19 @@
   void ComputeIsReceiverRecursive(PhiInstr* phi,
                                   GrowableArray<PhiInstr*>* unmark) const;
 
+  void OptimizeLeftShiftBitAndSmiOp(
+      ForwardInstructionIterator* current_iterator,
+      Definition* bit_and_instr,
+      Definition* left_instr,
+      Definition* right_instr);
+
+  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
+  void TryMergeMathUnary(
+      GrowableArray<InvokeMathCFunctionInstr*>* merge_candidates);
+
+  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
+                                       Representation rep, intptr_t cid);
+
   Thread* thread_;
 
   // DiscoverBlocks computes parent_ and assigned_vars_ which are then used
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 09be30f..dadc66a 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -389,11 +389,8 @@
   } else {
     __ b(is_not_instance_lbl, EQ);
   }
-  // Compare if the classes are equal.
   const Register kClassIdReg = R2;
   __ LoadClassId(kClassIdReg, kInstanceReg);
-  __ CompareImmediate(kClassIdReg, type_class.id());
-  __ b(is_instance_lbl, EQ);
   // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
   // interfaces.
   // Bool interface can be implemented only by core class Bool.
@@ -403,15 +400,9 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsDartFunctionType()) {
-    // Check if instance is a closure.
-    __ CompareImmediate(kClassIdReg, kClosureCid);
-    __ b(is_instance_lbl, EQ);
-  }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
-  if (type.IsSubtypeOf(
-        Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -420,6 +411,17 @@
     GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
     return false;
   }
+  if (type.IsDartFunctionType()) {
+    // Check if instance is a closure.
+    __ CompareImmediate(kClassIdReg, kClosureCid);
+    __ b(is_instance_lbl, EQ);
+    return true;  // Fall through
+  }
+  // Compare if the classes are equal.
+  if (!type_class.is_abstract()) {
+    __ CompareImmediate(kClassIdReg, type_class.id());
+    __ b(is_instance_lbl, EQ);
+  }
   // Otherwise fallthrough.
   return true;
 }
@@ -1332,7 +1334,7 @@
     __ Comment("Slow case: megamorphic call");
   }
   __ LoadObject(R9, cache);
-  __ ldr(LR, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
+  __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset()));
   __ blx(LR);
 
   __ Bind(&done);
@@ -1373,7 +1375,7 @@
     LocationSummary* locs) {
   ASSERT(ic_data.NumArgsTested() == 1);
   const Code& initial_stub = Code::ZoneHandle(
-      StubCode::ICLookupThroughFunction_entry()->code());
+      StubCode::ICCallThroughFunction_entry()->code());
 
   __ Comment("SwitchableCall");
 
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index 5dd2308..304dcb3 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -382,11 +382,8 @@
   } else {
     __ b(is_not_instance_lbl, EQ);
   }
-  // Compare if the classes are equal.
   const Register kClassIdReg = R2;
   __ LoadClassId(kClassIdReg, kInstanceReg);
-  __ CompareImmediate(kClassIdReg, type_class.id());
-  __ b(is_instance_lbl, EQ);
   // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
   // interfaces.
   // Bool interface can be implemented only by core class Bool.
@@ -396,15 +393,9 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsDartFunctionType()) {
-    // Check if instance is a closure.
-    __ CompareImmediate(kClassIdReg, kClosureCid);
-    __ b(is_instance_lbl, EQ);
-  }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
-  if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -413,6 +404,17 @@
     GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
     return false;
   }
+  if (type.IsDartFunctionType()) {
+    // Check if instance is a closure.
+    __ CompareImmediate(kClassIdReg, kClosureCid);
+    __ b(is_instance_lbl, EQ);
+    return true;  // Fall through
+  }
+  // Compare if the classes are equal.
+  if (!type_class.is_abstract()) {
+    __ CompareImmediate(kClassIdReg, type_class.id());
+    __ b(is_instance_lbl, EQ);
+  }
   // Otherwise fallthrough.
   return true;
 }
@@ -1314,7 +1316,7 @@
   }
 
   __ LoadObject(R5, cache);
-  __ ldr(LR, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
+  __ ldr(LR, Address(THR, Thread::megamorphic_call_checked_entry_offset()));
   __ blr(LR);
 
   __ Bind(&done);
@@ -1354,7 +1356,7 @@
     LocationSummary* locs) {
   ASSERT(ic_data.NumArgsTested() == 1);
   const Code& initial_stub = Code::ZoneHandle(
-      StubCode::ICLookupThroughFunction_entry()->code());
+      StubCode::ICCallThroughFunction_entry()->code());
   __ Comment("SwitchableCall");
 
   __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index fbfe34c..461785a 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -390,11 +390,8 @@
   } else {
     __ j(ZERO, is_not_instance_lbl);
   }
-  // Compare if the classes are equal.
   const Register kClassIdReg = ECX;
   __ LoadClassId(kClassIdReg, kInstanceReg);
-  __ cmpl(kClassIdReg, Immediate(type_class.id()));
-  __ j(EQUAL, is_instance_lbl);
   // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
   // interfaces.
   // Bool interface can be implemented only by core class Bool.
@@ -404,15 +401,9 @@
     __ jmp(is_not_instance_lbl);
     return false;
   }
-  if (type.IsDartFunctionType()) {
-    // Check if instance is a closure.
-    __ cmpl(kClassIdReg, Immediate(kClosureCid));
-    __ j(EQUAL, is_instance_lbl);
-  }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
-  if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -421,6 +412,17 @@
     GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
     return false;
   }
+  if (type.IsDartFunctionType()) {
+    // Check if instance is a closure.
+    __ cmpl(kClassIdReg, Immediate(kClosureCid));
+    __ j(EQUAL, is_instance_lbl);
+    return true;  // Fall through
+  }
+  // Compare if the classes are equal.
+  if (!type_class.is_abstract()) {
+    __ cmpl(kClassIdReg, Immediate(type_class.id()));
+    __ j(EQUAL, is_instance_lbl);
+  }
   // Otherwise fallthrough.
   return true;
 }
@@ -1309,7 +1311,7 @@
     __ Comment("Slow case: megamorphic call");
   }
   __ LoadObject(ECX, cache);
-  __ call(Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
+  __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset()));
   __ call(EBX);
 
   __ Bind(&done);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 8e568c9..f27c80a 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -381,11 +381,8 @@
   } else {
     __ beq(T0, ZR, is_not_instance_lbl);
   }
-  // Compare if the classes are equal.
   const Register kClassIdReg = T0;
   __ LoadClassId(kClassIdReg, kInstanceReg);
-  __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl);
-
   // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
   // interfaces.
   // Bool interface can be implemented only by core class Bool.
@@ -394,14 +391,9 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsDartFunctionType()) {
-    // Check if instance is a closure.
-    __ BranchEqual(kClassIdReg, Immediate(kClosureCid), is_instance_lbl);
-  }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
-  if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -410,6 +402,15 @@
     GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
     return false;
   }
+  if (type.IsDartFunctionType()) {
+    // Check if instance is a closure.
+    __ BranchEqual(kClassIdReg, Immediate(kClosureCid), is_instance_lbl);
+    return true;  // Fall through
+  }
+  // Compare if the classes are equal.
+  if (!type_class.is_abstract()) {
+  __ BranchEqual(kClassIdReg, Immediate(type_class.id()), is_instance_lbl);
+  }
   // Otherwise fallthrough.
   return true;
 }
@@ -1339,7 +1340,7 @@
     __ Comment("Slow case: megamorphic call");
   }
   __ LoadObject(S5, cache);
-  __ lw(T9, Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
+  __ lw(T9, Address(THR, Thread::megamorphic_call_checked_entry_offset()));
   __ jalr(T9);
 
   __ Bind(&done);
@@ -1379,7 +1380,7 @@
     LocationSummary* locs) {
   ASSERT(ic_data.NumArgsTested() == 1);
   const Code& initial_stub = Code::ZoneHandle(
-      StubCode::ICLookupThroughFunction_entry()->code());
+      StubCode::ICCallThroughFunction_entry()->code());
 
   __ Comment("SwitchableCall");
   __ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 9118bb12..fb521bf 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -387,11 +387,8 @@
   } else {
     __ j(ZERO, is_not_instance_lbl);
   }
-  // Compare if the classes are equal.
   const Register kClassIdReg = R10;
   __ LoadClassId(kClassIdReg, kInstanceReg);
-  __ cmpl(kClassIdReg, Immediate(type_class.id()));
-  __ j(EQUAL, is_instance_lbl);
   // See ClassFinalizer::ResolveSuperTypeAndInterfaces for list of restricted
   // interfaces.
   // Bool interface can be implemented only by core class Bool.
@@ -401,15 +398,9 @@
     __ jmp(is_not_instance_lbl);
     return false;
   }
-  if (type.IsDartFunctionType()) {
-    // Check if instance is a closure.
-    __ cmpq(kClassIdReg, Immediate(kClosureCid));
-    __ j(EQUAL, is_instance_lbl);
-  }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
-  if (type.IsSubtypeOf(
-      Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType()) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -418,6 +409,17 @@
     GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
     return false;
   }
+  if (type.IsDartFunctionType()) {
+    // Check if instance is a closure.
+    __ cmpq(kClassIdReg, Immediate(kClosureCid));
+    __ j(EQUAL, is_instance_lbl);
+    return true;
+  }
+  // Compare if the classes are equal.
+  if (!type_class.is_abstract()) {
+    __ cmpl(kClassIdReg, Immediate(type_class.id()));
+    __ j(EQUAL, is_instance_lbl);
+  }
   // Otherwise fallthrough.
   return true;
 }
@@ -1339,7 +1341,7 @@
     __ Comment("Slow case: megamorphic call");
   }
   __ LoadObject(RBX, cache);
-  __ call(Address(THR, Thread::megamorphic_lookup_checked_entry_offset()));
+  __ call(Address(THR, Thread::megamorphic_call_checked_entry_offset()));
 
   __ Bind(&done);
   RecordSafepoint(locs, slow_path_argument_count);
@@ -1378,7 +1380,7 @@
     LocationSummary* locs) {
   ASSERT(ic_data.NumArgsTested() == 1);
   const Code& initial_stub = Code::ZoneHandle(
-      StubCode::ICLookupThroughFunction_entry()->code());
+      StubCode::ICCallThroughFunction_entry()->code());
 
   __ Comment("SwitchableCall");
   __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 8ee6739..1601565 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -844,7 +844,7 @@
 
             // Optimize (a << b) & c patterns, merge instructions. Must occur
             // before 'SelectRepresentations' which inserts conversion nodes.
-            optimizer.TryOptimizePatterns();
+            callee_graph->TryOptimizePatterns();
             DEBUG_ASSERT(callee_graph->VerifyUseLists());
           } else {
             JitOptimizer optimizer(callee_graph);
@@ -860,7 +860,7 @@
 
             // Optimize (a << b) & c patterns, merge instructions. Must occur
             // before 'SelectRepresentations' which inserts conversion nodes.
-            optimizer.TryOptimizePatterns();
+            callee_graph->TryOptimizePatterns();
             DEBUG_ASSERT(callee_graph->VerifyUseLists());
           }
         }
@@ -2352,6 +2352,9 @@
                            Instruction* call,
                            TargetEntryInstr** entry,
                            Definition** last) {
+  if (!CanUnboxDouble()) {
+    return false;
+  }
   Definition* left = call->ArgumentAt(0);
   Definition* right = call->ArgumentAt(1);
 
@@ -2421,7 +2424,7 @@
 }
 
 
-static intptr_t PrepareInlineByteArrayBaseOp(
+static void PrepareInlineByteArrayBaseOp(
     FlowGraph* flow_graph,
     Instruction* call,
     intptr_t array_cid,
@@ -2499,7 +2502,6 @@
                                    FlowGraph::kValue);
     *array = elements;
   }
-  return array_cid;
 }
 
 
@@ -2518,13 +2520,13 @@
   (*entry)->InheritDeoptTarget(Z, call);
   Instruction* cursor = *entry;
 
-  array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
-                                           call,
-                                           array_cid,
-                                           view_cid,
-                                           &array,
-                                           index,
-                                           &cursor);
+  PrepareInlineByteArrayBaseOp(flow_graph,
+                               call,
+                               array_cid,
+                               view_cid,
+                               &array,
+                               index,
+                               &cursor);
 
   intptr_t deopt_id = Thread::kNoDeoptId;
   if ((array_cid == kTypedDataInt32ArrayCid) ||
@@ -2572,13 +2574,13 @@
   (*entry)->InheritDeoptTarget(Z, call);
   Instruction* cursor = *entry;
 
-  array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
-                                           call,
-                                           array_cid,
-                                           view_cid,
-                                           &array,
-                                           index,
-                                           &cursor);
+  PrepareInlineByteArrayBaseOp(flow_graph,
+                               call,
+                               array_cid,
+                               view_cid,
+                               &array,
+                               index,
+                               &cursor);
 
   // Extract the instance call so we can use the function_name in the stored
   // value check ICData.
@@ -2847,47 +2849,535 @@
 
   TargetEntryInstr* entry;
   Definition* last;
-  if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph,
-                                                   receiver_cid,
-                                                   target,
-                                                   call,
-                                                   call->ArgumentAt(0),
-                                                   call->token_pos(),
-                                                   *call->ic_data(),
-                                                   &entry, &last)) {
+  if (FlowGraphInliner::TryInlineRecognizedMethod(flow_graph,
+                                                  receiver_cid,
+                                                  target,
+                                                  call,
+                                                  call->ArgumentAt(0),
+                                                  call->token_pos(),
+                                                  *call->ic_data(),
+                                                  &entry, &last)) {
+    // Insert receiver class check if needed.
+    if (MethodRecognizer::PolymorphicTarget(target) ||
+        flow_graph->InstanceCallNeedsClassCheck(call, target.kind())) {
+      Instruction* check = GetCheckClass(
+          flow_graph,
+          call->ArgumentAt(0),
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
+          call->deopt_id(),
+          call->token_pos());
+      flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect);
+    }
+
+    // Remove the original push arguments.
+    for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+      PushArgumentInstr* push = call->PushArgumentAt(i);
+      push->ReplaceUsesWith(push->value()->definition());
+      push->RemoveFromGraph();
+    }
+    // Replace all uses of this definition with the result.
+    if (call->HasUses()) {
+      call->ReplaceUsesWith(last);
+    }
+    // Finally insert the sequence other definition in place of this one in the
+    // graph.
+    if (entry->next() != NULL) {
+      call->previous()->LinkTo(entry->next());
+    }
+    entry->UnuseAllInputs();  // Entry block is not in the graph.
+    if (last != NULL) {
+      last->LinkTo(call);
+    }
+    // Remove through the iterator.
+    ASSERT(iterator->Current() == call);
+    iterator->RemoveCurrentFromGraph();
+    call->set_previous(NULL);
+    call->set_next(NULL);
+    return true;
+  }
+  return false;
+}
+
+
+bool FlowGraphInliner::TryReplaceStaticCallWithInline(
+    FlowGraph* flow_graph,
+    ForwardInstructionIterator* iterator,
+    StaticCallInstr* call) {
+  TargetEntryInstr* entry;
+  Definition* last;
+  if (FlowGraphInliner::TryInlineRecognizedMethod(flow_graph,
+                                                  kIllegalCid,
+                                                  call->function(),
+                                                  call,
+                                                  call->ArgumentAt(0),
+                                                  call->token_pos(),
+                                                  *call->ic_data(),
+                                                  &entry, &last)) {
+    // Remove the original push arguments.
+    for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+      PushArgumentInstr* push = call->PushArgumentAt(i);
+      push->ReplaceUsesWith(push->value()->definition());
+      push->RemoveFromGraph();
+    }
+    // Replace all uses of this definition with the result.
+    if (call->HasUses()) {
+      call->ReplaceUsesWith(last);
+    }
+    // Finally insert the sequence other definition in place of this one in the
+    // graph.
+    if (entry->next() != NULL) {
+      call->previous()->LinkTo(entry->next());
+    }
+    entry->UnuseAllInputs();  // Entry block is not in the graph.
+    if (last != NULL) {
+      last->LinkTo(call);
+    }
+    // Remove through the iterator.
+    ASSERT(iterator->Current() == call);
+    iterator->RemoveCurrentFromGraph();
+    call->set_previous(NULL);
+    call->set_next(NULL);
+    return true;
+  }
+  return false;
+}
+
+
+static bool InlineFloat32x4Method(FlowGraph* flow_graph,
+                                  Instruction* call,
+                                  MethodRecognizer::Kind kind,
+                                  TargetEntryInstr** entry,
+                                  Definition** last) {
+  if (!ShouldInlineSimd()) {
     return false;
   }
-
-  // Insert receiver class check if needed.
-  if (MethodRecognizer::PolymorphicTarget(target) ||
-      flow_graph->InstanceCallNeedsClassCheck(call, target.kind())) {
-    Instruction* check = GetCheckClass(
-        flow_graph,
-        call->ArgumentAt(0),
-        ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
-        call->deopt_id(),
-        call->token_pos());
-    flow_graph->InsertBefore(call, check, call->env(), FlowGraph::kEffect);
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  switch (kind) {
+    case MethodRecognizer::kFloat32x4ShuffleX:
+    case MethodRecognizer::kFloat32x4ShuffleY:
+    case MethodRecognizer::kFloat32x4ShuffleZ:
+    case MethodRecognizer::kFloat32x4ShuffleW: {
+      *last = new(Z) Simd32x4ShuffleInstr(kind,
+                                          new(Z) Value(call->ArgumentAt(0)),
+                                          0,  // mask ignored.
+                                          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4GetSignMask: {
+      *last = new(Z) Simd32x4GetSignMaskInstr(kind,
+                                              new(Z) Value(call->ArgumentAt(0)),
+                                              call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Equal:
+    case MethodRecognizer::kFloat32x4GreaterThan:
+    case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
+    case MethodRecognizer::kFloat32x4LessThan:
+    case MethodRecognizer::kFloat32x4LessThanOrEqual:
+    case MethodRecognizer::kFloat32x4NotEqual: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      *last = new(Z) Float32x4ComparisonInstr(kind,
+                                              new(Z) Value(left),
+                                              new(Z) Value(right),
+                                              call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Min:
+    case MethodRecognizer::kFloat32x4Max: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      *last = new(Z) Float32x4MinMaxInstr(kind,
+                                          new(Z) Value(left),
+                                          new(Z) Value(right),
+                                          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Scale: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Left and right values are swapped when handed to the instruction,
+      // this is done so that the double value is loaded into the output
+      // register and can be destroyed.
+      *last = new(Z) Float32x4ScaleInstr(kind,
+                                         new(Z) Value(right),
+                                         new(Z) Value(left),
+                                         call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Sqrt:
+    case MethodRecognizer::kFloat32x4ReciprocalSqrt:
+    case MethodRecognizer::kFloat32x4Reciprocal: {
+      Definition* left = call->ArgumentAt(0);
+      *last = new(Z) Float32x4SqrtInstr(kind,
+                                        new(Z) Value(left),
+                                        call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4WithX:
+    case MethodRecognizer::kFloat32x4WithY:
+    case MethodRecognizer::kFloat32x4WithZ:
+    case MethodRecognizer::kFloat32x4WithW: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      *last = new(Z) Float32x4WithInstr(kind,
+                                        new(Z) Value(left),
+                                        new(Z) Value(right),
+                                        call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Absolute:
+    case MethodRecognizer::kFloat32x4Negate: {
+      Definition* left = call->ArgumentAt(0);
+      *last = new(Z) Float32x4ZeroArgInstr(kind,
+                                           new(Z) Value(left),
+                                           call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat32x4Clamp: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* lower = call->ArgumentAt(1);
+      Definition* upper = call->ArgumentAt(2);
+      *last = new(Z) Float32x4ClampInstr(
+          new(Z) Value(left),
+          new(Z) Value(lower),
+          new(Z) Value(upper),
+          call->deopt_id());
+      break;
+    }
+    default:
+      UNREACHABLE();
+      return false;
   }
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
 
-  // Remove the original push arguments.
-  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-    PushArgumentInstr* push = call->PushArgumentAt(i);
-    push->ReplaceUsesWith(push->value()->definition());
-    push->RemoveFromGraph();
+
+static bool CheckMask(Definition* definition, intptr_t* mask_ptr) {
+  if (!definition->IsConstant()) return false;
+  ConstantInstr* constant_instruction = definition->AsConstant();
+  const Object& constant_mask = constant_instruction->value();
+  if (!constant_mask.IsSmi()) return false;
+  const intptr_t mask = Smi::Cast(constant_mask).Value();
+  if ((mask < 0) || (mask > 255)) {
+    return false;  // Not a valid mask.
   }
-  // Replace all uses of this definition with the result.
-  call->ReplaceUsesWith(last);
-  // Finally insert the sequence other definition in place of this one in the
-  // graph.
-  call->previous()->LinkTo(entry->next());
-  entry->UnuseAllInputs();  // Entry block is not in the graph.
-  last->LinkTo(call);
-  // Remove through the iterator.
-  ASSERT(iterator->Current() == call);
-  iterator->RemoveCurrentFromGraph();
-  call->set_previous(NULL);
-  call->set_next(NULL);
+  *mask_ptr = mask;
+  return true;
+}
+
+
+static bool InlineSimdShuffleMethod(FlowGraph* flow_graph,
+                                    Instruction* call,
+                                    MethodRecognizer::Kind kind,
+                                    TargetEntryInstr** entry,
+                                    Definition** last) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  Definition* mask_definition = call->ArgumentAt(1);
+  intptr_t mask = 0;
+  if (!CheckMask(mask_definition, &mask)) {
+    return false;
+  }
+  *last = new(Z) Simd32x4ShuffleInstr(
+      kind,
+      new(Z) Value(call->ArgumentAt(0)),
+      mask,
+      call->deopt_id());
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
+
+
+static bool InlineSimdShuffleMixMethod(FlowGraph* flow_graph,
+                                       Instruction* call,
+                                       MethodRecognizer::Kind kind,
+                                       TargetEntryInstr** entry,
+                                       Definition** last) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  Definition* mask_definition = call->ArgumentAt(2);
+  intptr_t mask = 0;
+  if (!CheckMask(mask_definition, &mask)) {
+    return false;
+  }
+  *last = new(Z) Simd32x4ShuffleMixInstr(
+      kind,
+      new(Z) Value(call->ArgumentAt(0)),
+      new(Z) Value(call->ArgumentAt(1)),
+      mask,
+      call->deopt_id());
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
+
+
+
+static bool InlineInt32x4Method(FlowGraph* flow_graph,
+                                Instruction* call,
+                                MethodRecognizer::Kind kind,
+                                TargetEntryInstr** entry,
+                                Definition** last) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  switch (kind) {
+    case MethodRecognizer::kInt32x4GetFlagX:
+    case MethodRecognizer::kInt32x4GetFlagY:
+    case MethodRecognizer::kInt32x4GetFlagZ:
+    case MethodRecognizer::kInt32x4GetFlagW: {
+      *last = new(Z) Int32x4GetFlagInstr(
+          kind,
+          new(Z) Value(call->ArgumentAt(0)),
+          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kInt32x4GetSignMask: {
+      *last = new(Z) Simd32x4GetSignMaskInstr(
+          kind,
+          new(Z) Value(call->ArgumentAt(0)),
+          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kInt32x4Select: {
+      Definition* mask = call->ArgumentAt(0);
+      Definition* trueValue = call->ArgumentAt(1);
+      Definition* falseValue = call->ArgumentAt(2);
+      *last = new(Z) Int32x4SelectInstr(
+          new(Z) Value(mask),
+          new(Z) Value(trueValue),
+          new(Z) Value(falseValue),
+          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kInt32x4WithFlagX:
+    case MethodRecognizer::kInt32x4WithFlagY:
+    case MethodRecognizer::kInt32x4WithFlagZ:
+    case MethodRecognizer::kInt32x4WithFlagW: {
+      *last = new(Z) Int32x4SetFlagInstr(
+          kind,
+          new(Z) Value(call->ArgumentAt(0)),
+          new(Z) Value(call->ArgumentAt(1)),
+          call->deopt_id());
+      break;
+    }
+    default:
+      return false;
+  }
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
+
+
+static bool InlineFloat64x2Method(FlowGraph* flow_graph,
+                                  Instruction* call,
+                                  MethodRecognizer::Kind kind,
+                                  TargetEntryInstr** entry,
+                                  Definition** last) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  switch (kind) {
+    case MethodRecognizer::kFloat64x2GetX:
+    case MethodRecognizer::kFloat64x2GetY: {
+      *last = new(Z) Simd64x2ShuffleInstr(
+          kind,
+          new(Z) Value(call->ArgumentAt(0)),
+          0,  // mask is ignored.
+          call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat64x2Negate:
+    case MethodRecognizer::kFloat64x2Abs:
+    case MethodRecognizer::kFloat64x2Sqrt:
+    case MethodRecognizer::kFloat64x2GetSignMask: {
+      *last = new(Z) Float64x2ZeroArgInstr(
+          kind, new(Z) Value(call->ArgumentAt(0)), call->deopt_id());
+      break;
+    }
+    case MethodRecognizer::kFloat64x2Scale:
+    case MethodRecognizer::kFloat64x2WithX:
+    case MethodRecognizer::kFloat64x2WithY:
+    case MethodRecognizer::kFloat64x2Min:
+    case MethodRecognizer::kFloat64x2Max: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      *last = new(Z) Float64x2OneArgInstr(kind,
+                                          new(Z) Value(left),
+                                          new(Z) Value(right),
+                                          call->deopt_id());
+      break;
+    }
+    default:
+      UNREACHABLE();
+      return false;
+  }
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
+
+
+static bool InlineSimdConstructor(FlowGraph* flow_graph,
+                                  Instruction* call,
+                                  MethodRecognizer::Kind kind,
+                                  TargetEntryInstr** entry,
+                                  Definition** last) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  switch (kind) {
+    case MethodRecognizer::kFloat32x4Zero:
+      *last = new(Z) Float32x4ZeroInstr();
+      break;
+    case MethodRecognizer::kFloat32x4Splat:
+      *last = new(Z) Float32x4SplatInstr(new(Z) Value(call->ArgumentAt(1)),
+                                         call->deopt_id());
+      break;
+    case MethodRecognizer::kFloat32x4Constructor:
+      *last = new(Z) Float32x4ConstructorInstr(
+          new(Z) Value(call->ArgumentAt(1)),
+          new(Z) Value(call->ArgumentAt(2)),
+          new(Z) Value(call->ArgumentAt(3)),
+          new(Z) Value(call->ArgumentAt(4)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kFloat32x4FromInt32x4Bits:
+      *last = new(Z) Int32x4ToFloat32x4Instr(new(Z) Value(call->ArgumentAt(1)),
+                                             call->deopt_id());
+      break;
+    case  MethodRecognizer::kFloat32x4FromFloat64x2:
+      *last = new(Z) Float64x2ToFloat32x4Instr(
+          new(Z) Value(call->ArgumentAt(1)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kFloat64x2Zero:
+      *last = new(Z) Float64x2ZeroInstr();
+      break;
+    case MethodRecognizer::kFloat64x2Splat:
+      *last = new(Z) Float64x2SplatInstr(new(Z) Value(call->ArgumentAt(1)),
+                                         call->deopt_id());
+      break;
+    case MethodRecognizer::kFloat64x2Constructor:
+      *last = new(Z) Float64x2ConstructorInstr(
+          new(Z) Value(call->ArgumentAt(1)),
+          new(Z) Value(call->ArgumentAt(2)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kFloat64x2FromFloat32x4:
+      *last = new(Z) Float32x4ToFloat64x2Instr(
+          new(Z) Value(call->ArgumentAt(1)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kInt32x4BoolConstructor:
+      *last = new(Z) Int32x4BoolConstructorInstr(
+          new(Z) Value(call->ArgumentAt(1)),
+          new(Z) Value(call->ArgumentAt(2)),
+          new(Z) Value(call->ArgumentAt(3)),
+          new(Z) Value(call->ArgumentAt(4)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kInt32x4Constructor:
+      *last = new(Z) Int32x4ConstructorInstr(
+          new(Z) Value(call->ArgumentAt(1)),
+          new(Z) Value(call->ArgumentAt(2)),
+          new(Z) Value(call->ArgumentAt(3)),
+          new(Z) Value(call->ArgumentAt(4)),
+          call->deopt_id());
+      break;
+    case MethodRecognizer::kInt32x4FromFloat32x4Bits:
+      *last = new(Z) Float32x4ToInt32x4Instr(new(Z) Value(call->ArgumentAt(1)),
+                                             call->deopt_id());
+      break;
+    default:
+      UNREACHABLE();
+      return false;
+  }
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
+  return true;
+}
+
+
+static bool InlineMathCFunction(FlowGraph* flow_graph,
+                                Instruction* call,
+                                MethodRecognizer::Kind kind,
+                                TargetEntryInstr** entry,
+                                Definition** last) {
+  if (!CanUnboxDouble()) {
+    return false;
+  }
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+
+  switch (kind) {
+    case MethodRecognizer::kMathSqrt: {
+      *last = new(Z) MathUnaryInstr(MathUnaryInstr::kSqrt,
+                                    new(Z) Value(call->ArgumentAt(0)),
+                                    call->deopt_id());
+      break;
+    }
+    default: {
+      ZoneGrowableArray<Value*>* args =
+          new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
+      for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+        args->Add(new(Z) Value(call->ArgumentAt(i)));
+      }
+      *last = new(Z) InvokeMathCFunctionInstr(args,
+                                              call->deopt_id(),
+                                              kind,
+                                              call->token_pos());
+      break;
+    }
+  }
+  flow_graph->AppendTo(cursor, *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                       call->env() : NULL,
+                       FlowGraph::kValue);
   return true;
 }
 
@@ -2895,7 +3385,7 @@
 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
                                                  intptr_t receiver_cid,
                                                  const Function& target,
-                                                 Instruction* call,
+                                                 Definition* call,
                                                  Definition* receiver,
                                                  TokenPosition token_pos,
                                                  const ICData& ic_data,
@@ -3145,6 +3635,148 @@
           call, entry, last);
     case MethodRecognizer::kSmi_bitAndFromSmi:
       return InlineSmiBitAndFromSmi(flow_graph, call, entry, last);
+
+    case MethodRecognizer::kFloat32x4ShuffleX:
+    case MethodRecognizer::kFloat32x4ShuffleY:
+    case MethodRecognizer::kFloat32x4ShuffleZ:
+    case MethodRecognizer::kFloat32x4ShuffleW:
+    case MethodRecognizer::kFloat32x4GetSignMask:
+    case MethodRecognizer::kFloat32x4Equal:
+    case MethodRecognizer::kFloat32x4GreaterThan:
+    case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
+    case MethodRecognizer::kFloat32x4LessThan:
+    case MethodRecognizer::kFloat32x4LessThanOrEqual:
+    case MethodRecognizer::kFloat32x4NotEqual:
+    case MethodRecognizer::kFloat32x4Min:
+    case MethodRecognizer::kFloat32x4Max:
+    case MethodRecognizer::kFloat32x4Scale:
+    case MethodRecognizer::kFloat32x4Sqrt:
+    case MethodRecognizer::kFloat32x4ReciprocalSqrt:
+    case MethodRecognizer::kFloat32x4Reciprocal:
+    case MethodRecognizer::kFloat32x4WithX:
+    case MethodRecognizer::kFloat32x4WithY:
+    case MethodRecognizer::kFloat32x4WithZ:
+    case MethodRecognizer::kFloat32x4WithW:
+    case MethodRecognizer::kFloat32x4Absolute:
+    case MethodRecognizer::kFloat32x4Negate:
+    case MethodRecognizer::kFloat32x4Clamp:
+      return InlineFloat32x4Method(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kFloat32x4ShuffleMix:
+    case MethodRecognizer::kInt32x4ShuffleMix:
+      return InlineSimdShuffleMixMethod(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kFloat32x4Shuffle:
+    case MethodRecognizer::kInt32x4Shuffle:
+      return InlineSimdShuffleMethod(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kInt32x4GetFlagX:
+    case MethodRecognizer::kInt32x4GetFlagY:
+    case MethodRecognizer::kInt32x4GetFlagZ:
+    case MethodRecognizer::kInt32x4GetFlagW:
+    case MethodRecognizer::kInt32x4GetSignMask:
+    case MethodRecognizer::kInt32x4Select:
+    case MethodRecognizer::kInt32x4WithFlagX:
+    case MethodRecognizer::kInt32x4WithFlagY:
+    case MethodRecognizer::kInt32x4WithFlagZ:
+    case MethodRecognizer::kInt32x4WithFlagW:
+      return InlineInt32x4Method(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kFloat64x2GetX:
+    case MethodRecognizer::kFloat64x2GetY:
+    case MethodRecognizer::kFloat64x2Negate:
+    case MethodRecognizer::kFloat64x2Abs:
+    case MethodRecognizer::kFloat64x2Sqrt:
+    case MethodRecognizer::kFloat64x2GetSignMask:
+    case MethodRecognizer::kFloat64x2Scale:
+    case MethodRecognizer::kFloat64x2WithX:
+    case MethodRecognizer::kFloat64x2WithY:
+    case MethodRecognizer::kFloat64x2Min:
+    case MethodRecognizer::kFloat64x2Max:
+      return InlineFloat64x2Method(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kFloat32x4Zero:
+    case MethodRecognizer::kFloat32x4Splat:
+    case MethodRecognizer::kFloat32x4Constructor:
+    case MethodRecognizer::kFloat32x4FromFloat64x2:
+    case MethodRecognizer::kFloat64x2Constructor:
+    case MethodRecognizer::kFloat64x2Zero:
+    case MethodRecognizer::kFloat64x2Splat:
+    case MethodRecognizer::kFloat64x2FromFloat32x4:
+    case MethodRecognizer::kInt32x4BoolConstructor:
+    case MethodRecognizer::kInt32x4Constructor:
+    case MethodRecognizer::kInt32x4FromFloat32x4Bits:
+      return InlineSimdConstructor(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kMathSqrt:
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathSin:
+    case MethodRecognizer::kMathCos:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2:
+      return InlineMathCFunction(flow_graph, call, kind, entry, last);
+
+    case MethodRecognizer::kObjectConstructor: {
+      *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                       call->GetBlock()->try_index());
+      (*entry)->InheritDeoptTarget(Z, call);
+      ASSERT(!call->HasUses());
+      *last = NULL;  // Empty body.
+      return true;
+    }
+
+    case MethodRecognizer::kObjectArrayAllocate: {
+      Value* num_elements = new(Z) Value(call->ArgumentAt(1));
+      if (num_elements->BindsToConstant() &&
+          num_elements->BoundConstant().IsSmi()) {
+        intptr_t length =
+            Smi::Cast(num_elements->BoundConstant()).Value();
+        if (length >= 0 && length <= Array::kMaxElements) {
+          Value* type = new(Z) Value(call->ArgumentAt(0));
+          *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                           call->GetBlock()->try_index());
+          (*entry)->InheritDeoptTarget(Z, call);
+          *last =
+              new(Z) CreateArrayInstr(call->token_pos(), type, num_elements);
+          flow_graph->AppendTo(*entry, *last,
+                               call->deopt_id() != Thread::kNoDeoptId ?
+                               call->env() : NULL,
+                               FlowGraph::kValue);
+          return true;
+        }
+      }
+      return false;
+    }
+
+    case MethodRecognizer::kOneByteStringSetAt: {
+      // This is an internal method, no need to check argument types nor
+      // range.
+      *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                       call->GetBlock()->try_index());
+      (*entry)->InheritDeoptTarget(Z, call);
+      Definition* str = call->ArgumentAt(0);
+      Definition* index = call->ArgumentAt(1);
+      Definition* value = call->ArgumentAt(2);
+      *last = new(Z) StoreIndexedInstr(
+          new(Z) Value(str),
+          new(Z) Value(index),
+          new(Z) Value(value),
+          kNoStoreBarrier,
+          1,  // Index scale
+          kOneByteStringCid,
+          call->deopt_id(),
+          call->token_pos());
+      flow_graph->AppendTo(*entry,
+                           *last,
+                           call->deopt_id() != Thread::kNoDeoptId ?
+                              call->env() : NULL,
+                           FlowGraph::kEffect);
+      return true;
+    }
+
     default:
       return false;
   }
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index 04bca93..77a903a 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -17,6 +17,7 @@
 class Function;
 class InstanceCallInstr;
 class Instruction;
+class StaticCallInstr;
 class TargetEntryInstr;
 
 class FlowGraphInliner : ValueObject {
@@ -49,10 +50,15 @@
       ForwardInstructionIterator* iterator,
       InstanceCallInstr* call);
 
+  static bool TryReplaceStaticCallWithInline(
+      FlowGraph* flow_graph,
+      ForwardInstructionIterator* iterator,
+      StaticCallInstr* call);
+
   static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
                                         intptr_t receiver_cid,
                                         const Function& target,
-                                        Instruction* call,
+                                        Definition* call,
                                         Definition* receiver,
                                         TokenPosition token_pos,
                                         const ICData& ic_data,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index d1f8f92..a390ed6 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -469,40 +469,6 @@
 }
 
 
-bool Value::BindsTo32BitMaskConstant() const {
-  if (!definition()->IsUnboxInt64() || !definition()->IsUnboxUint32()) {
-    return false;
-  }
-  // Two cases to consider: UnboxInt64 and UnboxUint32.
-  if (definition()->IsUnboxInt64()) {
-    UnboxInt64Instr* instr = definition()->AsUnboxInt64();
-    if (!instr->value()->BindsToConstant()) {
-      return false;
-    }
-    const Object& obj = instr->value()->BoundConstant();
-    if (!obj.IsMint()) {
-      return false;
-    }
-    Mint& mint = Mint::Handle();
-    mint ^= obj.raw();
-    return mint.value() == kMaxUint32;
-  } else if (definition()->IsUnboxUint32()) {
-    UnboxUint32Instr* instr = definition()->AsUnboxUint32();
-    if (!instr->value()->BindsToConstant()) {
-      return false;
-    }
-    const Object& obj = instr->value()->BoundConstant();
-    if (!obj.IsMint()) {
-      return false;
-    }
-    Mint& mint = Mint::Handle();
-    mint ^= obj.raw();
-    return mint.value() == kMaxUint32;
-  }
-  return false;
-}
-
-
 // Returns true if the value represents a constant.
 bool Value::BindsToConstant() const {
   return definition()->IsConstant();
@@ -3841,24 +3807,9 @@
 }
 
 
-const RuntimeEntry& MathUnaryInstr::TargetFunction() const {
-  switch (kind()) {
-    case MathUnaryInstr::kSin:
-      return kLibcSinRuntimeEntry;
-    case MathUnaryInstr::kCos:
-      return kLibcCosRuntimeEntry;
-    default:
-      UNREACHABLE();
-  }
-  return kLibcSinRuntimeEntry;
-}
-
-
 const char* MathUnaryInstr::KindToCString(MathUnaryKind kind) {
   switch (kind) {
     case kIllegal:       return "illegal";
-    case kSin:           return "sin";
-    case kCos:           return "cos";
     case kSqrt:          return "sqrt";
     case kDoubleSquare:  return "double-square";
   }
@@ -3887,10 +3838,10 @@
 }
 
 
-intptr_t MergedMathInstr::OutputIndexOf(intptr_t kind) {
+intptr_t MergedMathInstr::OutputIndexOf(MethodRecognizer::Kind kind) {
   switch (kind) {
-    case MathUnaryInstr::kSin: return 1;
-    case MathUnaryInstr::kCos: return 0;
+    case MethodRecognizer::kMathSin: return 1;
+    case MethodRecognizer::kMathCos: return 0;
     default: UNIMPLEMENTED(); return -1;
   }
 }
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index bfcb8a7..2dd0711 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -341,9 +341,6 @@
 
   bool IsSmiValue() { return Type()->ToCid() == kSmiCid; }
 
-  // Returns true if this value binds to the constant: 0xFFFFFFFF.
-  bool BindsTo32BitMaskConstant() const;
-
   // Return true if the value represents a constant.
   bool BindsToConstant() const;
 
@@ -5103,8 +5100,6 @@
  public:
   enum MathUnaryKind {
     kIllegal,
-    kSin,
-    kCos,
     kSqrt,
     kDoubleSquare,
   };
@@ -5115,7 +5110,6 @@
 
   Value* value() const { return inputs_[0]; }
   MathUnaryKind kind() const { return kind_; }
-  const RuntimeEntry& TargetFunction() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -7697,7 +7691,7 @@
     return (*inputs_)[i];
   }
 
-  static intptr_t OutputIndexOf(intptr_t kind);
+  static intptr_t OutputIndexOf(MethodRecognizer::Kind kind);
   static intptr_t OutputIndexOf(Token::Kind token);
 
   virtual CompileType ComputeType() const;
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index aac4891..b4e27f0 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -5266,21 +5266,6 @@
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
-  if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
-    const intptr_t kNumInputs = 1;
-    const intptr_t kNumTemps = TargetCPUFeatures::hardfp_supported() ? 0 : 4;
-    LocationSummary* summary = new(zone) LocationSummary(
-        zone, kNumInputs, kNumTemps, LocationSummary::kCall);
-    summary->set_in(0, Location::FpuRegisterLocation(Q0));
-    summary->set_out(0, Location::FpuRegisterLocation(Q0));
-    if (!TargetCPUFeatures::hardfp_supported()) {
-      summary->set_temp(0, Location::RegisterLocation(R0));
-      summary->set_temp(1, Location::RegisterLocation(R1));
-      summary->set_temp(2, Location::RegisterLocation(R2));
-      summary->set_temp(3, Location::RegisterLocation(R3));
-    }
-    return summary;
-  }
   ASSERT((kind() == MathUnaryInstr::kSqrt) ||
          (kind() == MathUnaryInstr::kDoubleSquare));
   const intptr_t kNumInputs = 1;
@@ -5303,20 +5288,7 @@
     const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
     __ vmuld(result, val, val);
   } else {
-    ASSERT((kind() == MathUnaryInstr::kSin) ||
-           (kind() == MathUnaryInstr::kCos));
-    if (TargetCPUFeatures::hardfp_supported()) {
-      __ CallRuntime(TargetFunction(), InputCount());
-    } else {
-      // If we aren't doing "hardfp", then we have to move the double arguments
-      // to the integer registers, and take the results from the integer
-      // registers.
-      __ vmovrrd(R0, R1, D0);
-      __ vmovrrd(R2, R3, D1);
-      __ CallRuntime(TargetFunction(), InputCount());
-      __ vmovdrr(D0, R0, R1);
-      __ vmovdrr(D1, R2, R3);
-    }
+    UNREACHABLE();
   }
 }
 
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index c4f0fdc..b5f235f 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -4465,15 +4465,6 @@
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
-  if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
-    const intptr_t kNumInputs = 1;
-    const intptr_t kNumTemps = 0;
-    LocationSummary* summary = new(zone) LocationSummary(
-        zone, kNumInputs, kNumTemps, LocationSummary::kCall);
-    summary->set_in(0, Location::FpuRegisterLocation(V0));
-    summary->set_out(0, Location::FpuRegisterLocation(V0));
-    return summary;
-  }
   ASSERT((kind() == MathUnaryInstr::kSqrt) ||
          (kind() == MathUnaryInstr::kDoubleSquare));
   const intptr_t kNumInputs = 1;
@@ -4496,9 +4487,7 @@
     const VRegister result = locs()->out(0).fpu_reg();
     __ fmuld(result, val, val);
   } else {
-    ASSERT((kind() == MathUnaryInstr::kSin) ||
-           (kind() == MathUnaryInstr::kCos));
-    __ CallRuntime(TargetFunction(), InputCount());
+    UNREACHABLE();
   }
 }
 
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index d2fb113..08f05d7 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -31,8 +31,6 @@
 // List of instructions that are still unimplemented by DBC backend.
 #define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M)                                  \
   M(LoadCodeUnits)                                                             \
-  M(LoadUntagged)                                                              \
-  M(AllocateUninitializedContext)                                              \
   M(BinaryInt32Op)                                                             \
   M(Int32ToDouble)                                                             \
   M(DoubleToInteger)                                                           \
@@ -49,8 +47,6 @@
   M(ShiftUint32Op)                                                             \
   M(UnaryUint32Op)                                                             \
   M(UnboxedIntConverter)                                                       \
-  M(BoxInteger32)                                                              \
-  M(UnboxInteger32)                                                            \
 
 // List of instructions that are not used by DBC.
 // Things we aren't planning to implement for DBC:
@@ -700,69 +696,105 @@
 
 EMIT_NATIVE_CODE(StoreIndexed, 3, Location::NoLocation(),
                  LocationSummary::kNoCall, 1) {
-  if (compiler->is_optimizing()) {
-    if (IsExternal()) {
-      Unsupported(compiler);
-      UNREACHABLE();
-    }
-    const Register array = locs()->in(kArrayPos).reg();
-    const Register index = locs()->in(kIndexPos).reg();
-    const Register value = locs()->in(kValuePos).reg();
-    const Register temp = locs()->temp(0).reg();
-    switch (class_id()) {
-      case kArrayCid:
-        __ StoreIndexed(array, index, value);
-        break;
-      case kTypedDataFloat64ArrayCid:
-        if ((index_scale() != 8) && (index_scale() != 1)) {
-          Unsupported(compiler);
-          UNREACHABLE();
-        }
-        if (index_scale() == 1) {
-          __ ShrImm(temp, index, 3);
-        } else {
-          __ Move(temp, index);
-        }
-        __ StoreFloat64Indexed(array, temp, value);
-        break;
-      default:
-        Unsupported(compiler);
-        UNREACHABLE();
-        break;
-    }
-  } else {
+  if (!compiler->is_optimizing()) {
     ASSERT(class_id() == kArrayCid);
     __ StoreIndexedTOS();
+    return;
   }
-}
-
-
-EMIT_NATIVE_CODE(LoadIndexed, 2, Location::RequiresRegister()) {
-  ASSERT(compiler->is_optimizing());
-  if (IsExternal()) {
-    Unsupported(compiler);
-    UNREACHABLE();
-  }
-  const Register array = locs()->in(0).reg();
-  const Register index = locs()->in(1).reg();
-  const Register result = locs()->out(0).reg();
+  const Register array = locs()->in(kArrayPos).reg();
+  const Register index = locs()->in(kIndexPos).reg();
+  const Register value = locs()->in(kValuePos).reg();
+  const Register temp = locs()->temp(0).reg();
   switch (class_id()) {
     case kArrayCid:
-      __ LoadIndexed(result, array, index);
+      __ StoreIndexed(array, index, value);
       break;
-    case kTypedDataFloat64ArrayCid:
-      if ((index_scale() != 8) && (index_scale() != 1)) {
+    case kTypedDataUint8ArrayCid:
+    case kTypedDataInt8ArrayCid:
+    case kExternalOneByteStringCid:
+    case kExternalTypedDataUint8ArrayCid:
+      ASSERT(index_scale() == 1);
+      if (IsExternal()) {
+        __ StoreIndexedExternalUint8(array, index, value);
+      } else {
+        __ StoreIndexedUint8(array, index, value);
+      }
+      break;
+    case kOneByteStringCid:
+      ASSERT(index_scale() == 1);
+      __ StoreIndexedOneByteString(array, index, value);
+      break;
+    case kTypedDataInt32ArrayCid:
+    case kTypedDataUint32ArrayCid: {
+      if (IsExternal()) {
         Unsupported(compiler);
         UNREACHABLE();
       }
       if (index_scale() == 1) {
-        __ ShrImm(index, index, 3);
+        __ StoreIndexedUint32(array, index, value);
+      } else {
+        __ ShlImm(temp, index, Utils::ShiftForPowerOfTwo(index_scale()));
+        __ StoreIndexedUint32(array, temp, value);
       }
-      __ LoadFloat64Indexed(result, array, index);
+      break;
+    }
+    case kTypedDataFloat64ArrayCid:
+      if (IsExternal()) {
+        Unsupported(compiler);
+        UNREACHABLE();
+      }
+      if (index_scale() == 1) {
+        __ StoreIndexedFloat64(array, index, value);
+      } else if (index_scale() == 8) {
+        __ StoreIndexed8Float64(array, index, value);
+      } else {
+        __ ShlImm(temp, index, Utils::ShiftForPowerOfTwo(index_scale()));
+        __ StoreIndexedFloat64(array, temp, value);
+      }
+      break;
+    default:
+      Unsupported(compiler);
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+EMIT_NATIVE_CODE(LoadIndexed, 2, Location::RequiresRegister(),
+                 LocationSummary::kNoCall, 1) {
+  ASSERT(compiler->is_optimizing());
+  const Register array = locs()->in(0).reg();
+  const Register index = locs()->in(1).reg();
+  const Register temp = locs()->temp(0).reg();
+  const Register result = locs()->out(0).reg();
+  switch (class_id()) {
+    case kArrayCid:
+    case kImmutableArrayCid:
+      __ LoadIndexed(result, array, index);
+      break;
+    case kTypedDataUint8ArrayCid:
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalOneByteStringCid:
+    case kExternalTypedDataUint8ArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+      ASSERT(index_scale() == 1);
+      if (IsExternal()) {
+        __ LoadIndexedExternalUint8(result, array, index);
+      } else {
+        __ LoadIndexedUint8(result, array, index);
+      }
+      break;
+    case kTypedDataInt8ArrayCid:
+      ASSERT(index_scale() == 1);
+      if (IsExternal()) {
+        __ LoadIndexedExternalInt8(result, array, index);
+      } else {
+        __ LoadIndexedInt8(result, array, index);
+      }
       break;
     case kOneByteStringCid:
       ASSERT(index_scale() == 1);
-      __ LoadOneByteStringIndexed(result, array, index);
+      __ LoadIndexedOneByteString(result, array, index);
       break;
     case kTwoByteStringCid:
       if (index_scale() != 2) {
@@ -770,7 +802,35 @@
         Unsupported(compiler);
         UNREACHABLE();
       }
-      __ LoadTwoByteStringIndexed(result, array, index);
+      __ LoadIndexedTwoByteString(result, array, index);
+      break;
+    case kTypedDataInt32ArrayCid:
+      ASSERT(representation() == kUnboxedInt32);
+      if (index_scale() == 1) {
+        __ LoadIndexedInt32(result, array, index);
+      } else {
+        __ ShlImm(temp, index, Utils::ShiftForPowerOfTwo(index_scale()));
+        __ LoadIndexedInt32(result, array, temp);
+      }
+      break;
+    case kTypedDataUint32ArrayCid:
+      ASSERT(representation() == kUnboxedUint32);
+      if (index_scale() == 1) {
+        __ LoadIndexedUint32(result, array, index);
+      } else {
+        __ ShlImm(temp, index, Utils::ShiftForPowerOfTwo(index_scale()));
+        __ LoadIndexedUint32(result, array, temp);
+      }
+      break;
+    case kTypedDataFloat64ArrayCid:
+      if (index_scale() == 1) {
+        __ LoadIndexedFloat64(result, array, index);
+      } else if (index_scale() == 8) {
+        __ LoadIndexed8Float64(result, array, index);
+      } else {
+        __ ShlImm(temp, index, Utils::ShiftForPowerOfTwo(index_scale()));
+        __ LoadIndexedFloat64(result, array, temp);
+      }
       break;
     default:
       Unsupported(compiler);
@@ -894,6 +954,18 @@
 }
 
 
+EMIT_NATIVE_CODE(LoadUntagged, 1, Location::RequiresRegister()) {
+  const Register obj = locs()->in(0).reg();
+  const Register result = locs()->out(0).reg();
+  if (object()->definition()->representation() == kUntagged) {
+    __ LoadUntagged(result, obj, offset() / kWordSize);
+  } else {
+    ASSERT(object()->definition()->representation() == kTagged);
+    __ LoadField(result, obj, offset() / kWordSize);
+  }
+}
+
+
 EMIT_NATIVE_CODE(BooleanNegate, 1, Location::RequiresRegister()) {
   if (compiler->is_optimizing()) {
     __ BooleanNegate(locs()->out(0).reg(), locs()->in(0).reg());
@@ -915,15 +987,33 @@
 }
 
 
+EMIT_NATIVE_CODE(AllocateUninitializedContext,
+                 0, Location::RequiresRegister(),
+                 LocationSummary::kCall) {
+  ASSERT(compiler->is_optimizing());
+  __ AllocateContext(num_context_variables());
+  compiler->RecordSafepoint(locs());
+  compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+                                 Thread::kNoDeoptId,
+                                 token_pos());
+  __ PopLocal(locs()->out(0).reg());
+}
+
+
 EMIT_NATIVE_CODE(CloneContext,
                  1, Location::RequiresRegister(),
                  LocationSummary::kCall) {
-  ASSERT(!compiler->is_optimizing());
+  if (compiler->is_optimizing()) {
+    __ Push(locs()->in(0).reg());
+  }
   __ CloneContext();
   compiler->RecordSafepoint(locs());
   compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
                                  Thread::kNoDeoptId,
                                  token_pos());
+  if (compiler->is_optimizing()) {
+    __ PopLocal(locs()->out(0).reg());
+  }
 }
 
 
@@ -1356,6 +1446,41 @@
 }
 
 
+EMIT_NATIVE_CODE(UnboxInteger32, 1, Location::RequiresRegister()) {
+#if defined(ARCH_IS_64_BIT)
+  const Register out = locs()->out(0).reg();
+  const Register value = locs()->in(0).reg();
+  const bool may_truncate = is_truncating() || !CanDeoptimize();
+  __ UnboxInt32(out, value, may_truncate);
+  if (CanDeoptimize()) {
+    compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptUnboxInteger);
+  } else {
+    __ Nop(0);
+  }
+#else
+  Unsupported(compiler);
+  UNREACHABLE();
+#endif  // defined(ARCH_IS_64_BIT)
+}
+
+
+EMIT_NATIVE_CODE(BoxInteger32, 1, Location::RequiresRegister()) {
+#if defined(ARCH_IS_64_BIT)
+  const Register out = locs()->out(0).reg();
+  const Register value = locs()->in(0).reg();
+  if (from_representation() == kUnboxedInt32) {
+    __ BoxInt32(out, value);
+  } else {
+    ASSERT(from_representation() == kUnboxedUint32);
+    __ BoxUint32(out, value);
+  }
+#else
+  Unsupported(compiler);
+  UNREACHABLE();
+#endif  // defined(ARCH_IS_64_BIT)
+}
+
+
 EMIT_NATIVE_CODE(DoubleToSmi, 1, Location::RequiresRegister()) {
   const Register value = locs()->in(0).reg();
   const Register result = locs()->out(0).reg();
@@ -1399,10 +1524,6 @@
     __ DSqrt(result, value);
   } else if (kind() == MathUnaryInstr::kDoubleSquare) {
     __ DMul(result, value, value);
-  } else if (kind() == MathUnaryInstr::kSin) {
-    __ DSin(result, value);
-  } else if (kind() == MathUnaryInstr::kCos) {
-    __ DCos(result, value);
   } else {
     Unsupported(compiler);
     UNREACHABLE();
@@ -1420,6 +1541,10 @@
   } else if (recognized_kind() == MethodRecognizer::kDoubleMod) {
     const Register right = locs()->in(1).reg();
     __ DMod(result, left, right);
+  } else if (recognized_kind() == MethodRecognizer::kMathSin) {
+    __ DSin(result, left);
+  } else if (recognized_kind() == MethodRecognizer::kMathCos) {
+    __ DCos(result, left);
   } else {
     Unsupported(compiler);
     UNREACHABLE();
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 3ccb078..1595297 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -4904,18 +4904,6 @@
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
-  if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
-    const intptr_t kNumInputs = 1;
-    const intptr_t kNumTemps = 1;
-    LocationSummary* summary = new(zone) LocationSummary(
-        zone, kNumInputs, kNumTemps, LocationSummary::kCall);
-    summary->set_in(0, Location::FpuRegisterLocation(XMM1));
-    // EDI is chosen because it is callee saved so we do not need to back it
-    // up before calling into the runtime.
-    summary->set_temp(0, Location::RegisterLocation(EDI));
-    summary->set_out(0, Location::FpuRegisterLocation(XMM1));
-    return summary;
-  }
   ASSERT((kind() == MathUnaryInstr::kSqrt) ||
          (kind() == MathUnaryInstr::kDoubleSquare));
   const intptr_t kNumInputs = 1;
@@ -4940,17 +4928,7 @@
     __ mulsd(value_reg, value_reg);
     ASSERT(value_reg == locs()->out(0).fpu_reg());
   } else {
-    ASSERT((kind() == MathUnaryInstr::kSin) ||
-           (kind() == MathUnaryInstr::kCos));
-    // Save ESP.
-    __ movl(locs()->temp(0).reg(), ESP);
-    __ ReserveAlignedFrameSpace(kDoubleSize * InputCount());
-    __ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
-    __ CallRuntime(TargetFunction(), InputCount());
-    __ fstpl(Address(ESP, 0));
-    __ movsd(locs()->out(0).fpu_reg(), Address(ESP, 0));
-    // Restore ESP.
-    __ movl(ESP, locs()->temp(0).reg());
+    UNREACHABLE();
   }
 }
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 645273f..612d97e 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -4063,15 +4063,6 @@
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
-  if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
-    const intptr_t kNumInputs = 1;
-    const intptr_t kNumTemps = 0;
-    LocationSummary* summary = new(zone) LocationSummary(
-        zone, kNumInputs, kNumTemps, LocationSummary::kCall);
-    summary->set_in(0, Location::FpuRegisterLocation(D6));
-    summary->set_out(0, Location::FpuRegisterLocation(D0));
-    return summary;
-  }
   ASSERT((kind() == MathUnaryInstr::kSqrt) ||
          (kind() == MathUnaryInstr::kDoubleSquare));
   const intptr_t kNumInputs = 1;
@@ -4092,7 +4083,7 @@
     DRegister result = locs()->out(0).fpu_reg();
     __ muld(result, val, val);
   } else {
-    __ CallRuntime(TargetFunction(), InputCount());
+    UNREACHABLE();
   }
 }
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index c908d1e..b4eefbf 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -4747,22 +4747,6 @@
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
-  if ((kind() == MathUnaryInstr::kSin) || (kind() == MathUnaryInstr::kCos)) {
-    // Calling convention on x64 uses XMM0 and XMM1 to pass the first two
-    // double arguments and XMM0 to return the result. Unfortunately
-    // currently we can't specify these registers because ParallelMoveResolver
-    // assumes that XMM0 is free at all times.
-    // TODO(vegorov): allow XMM0 to be used.
-    const intptr_t kNumTemps = 1;
-    LocationSummary* summary = new(zone) LocationSummary(
-        zone, InputCount(), kNumTemps, LocationSummary::kCall);
-    summary->set_in(0, Location::FpuRegisterLocation(XMM1));
-    // R13 is chosen because it is callee saved so we do not need to back it
-    // up before calling into the runtime.
-    summary->set_temp(0, Location::RegisterLocation(R13));
-    summary->set_out(0, Location::FpuRegisterLocation(XMM1));
-    return summary;
-  }
   ASSERT((kind() == MathUnaryInstr::kSqrt) ||
          (kind() == MathUnaryInstr::kDoubleSquare));
   const intptr_t kNumInputs = 1;
@@ -4787,16 +4771,7 @@
     __ mulsd(value_reg, value_reg);
     ASSERT(value_reg == locs()->out(0).fpu_reg());
   } else {
-    ASSERT((kind() == MathUnaryInstr::kSin) ||
-           (kind() == MathUnaryInstr::kCos));
-    // Save RSP.
-    __ movq(locs()->temp(0).reg(), RSP);
-    __ ReserveAlignedFrameSpace(0);
-    __ movaps(XMM0, locs()->in(0).fpu_reg());
-    __ CallRuntime(TargetFunction(), InputCount());
-    __ movaps(locs()->out(0).fpu_reg(), XMM0);
-    // Restore RSP.
-    __ movq(RSP, locs()->temp(0).reg());
+    UNREACHABLE();
   }
 }
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index e6e1564..3c6c88b 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2192,12 +2192,10 @@
           "[+%" Pd64 "ms] Isolate %s : _runExtension complete for %s\n",
           Dart::timestamp(), name(), method_name.ToCString());
     }
+    // Propagate the error.
     if (result.IsError()) {
-      if (result.IsUnwindError()) {
-        // Propagate the unwind error. Remaining service extension calls
-        // are dropped.
-        return result.raw();
-      } else {
+      // Remaining service extension calls are dropped.
+      if (!result.IsUnwindError()) {
         // Send error back over the protocol.
         Service::PostError(method_name,
                            parameter_keys,
@@ -2206,9 +2204,13 @@
                            id,
                            Error::Cast(result));
       }
+      return result.raw();
     }
+    // Drain the microtask queue.
     result = DartLibraryCalls::DrainMicrotaskQueue();
+    // Propagate the error.
     if (result.IsError()) {
+      // Remaining service extension calls are dropped.
       return result.raw();
     }
   }
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 018ed1c..4543baa 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -2816,6 +2816,65 @@
 }
 
 
+TEST_CASE(IsolateReload_ShapeChangeRetainsHash) {
+  const char* kScript =
+      "class A{\n"
+      "  var x;\n"
+      "}\n"
+      "var a, hash1, hash2;\n"
+      "main() {\n"
+      "  a = new A();\n"
+      "  hash1 = a.hashCode;\n"
+      "  return 'okay';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "class A{\n"
+      "  var x, y, z;\n"
+      "}\n"
+      "var a, hash1, hash2;\n"
+      "main() {\n"
+      "  hash2 = a.hashCode;\n"
+      "  return (hash1 == hash2).toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_StaticTearOffRetainsHash) {
+  const char* kScript =
+      "foo() {}\n"
+      "var hash1, hash2;\n"
+      "main() {\n"
+      "  hash1 = foo.hashCode;\n"
+      "  return 'okay';\n"
+      "}\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("okay", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript =
+      "foo() {}\n"
+      "var hash1, hash2;\n"
+      "main() {\n"
+      "  hash2 = foo.hashCode;\n"
+      "  return (hash1 == hash2).toString();\n"
+      "}\n";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
 static bool NothingModifiedCallback(const char* url, int64_t since) {
   return false;
 }
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
index 56074a2..00f1588 100644
--- a/runtime/vm/jit_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -261,262 +261,6 @@
 }
 
 
-static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
-  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
-  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
-    return instr;
-  }
-  return NULL;
-}
-
-
-static bool IsPositiveOrZeroSmiConst(Definition* d) {
-  ConstantInstr* const_instr = d->AsConstant();
-  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
-    return Smi::Cast(const_instr->value()).Value() >= 0;
-  }
-  return false;
-}
-
-
-void JitOptimizer::OptimizeLeftShiftBitAndSmiOp(
-    Definition* bit_and_instr,
-    Definition* left_instr,
-    Definition* right_instr) {
-  ASSERT(bit_and_instr != NULL);
-  ASSERT((left_instr != NULL) && (right_instr != NULL));
-
-  // Check for pattern, smi_shift_left must be single-use.
-  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
-  if (!is_positive_or_zero) {
-    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
-  }
-  if (!is_positive_or_zero) return;
-
-  BinarySmiOpInstr* smi_shift_left = NULL;
-  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
-    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
-  }
-  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
-    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
-  }
-  if (smi_shift_left == NULL) return;
-
-  // Pattern recognized.
-  smi_shift_left->mark_truncating();
-  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
-  if (bit_and_instr->IsBinaryMintOp()) {
-    // Replace Mint op with Smi op.
-    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
-        Token::kBIT_AND,
-        new(Z) Value(left_instr),
-        new(Z) Value(right_instr),
-        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
-    bit_and_instr->ReplaceWith(smi_op, current_iterator());
-  }
-}
-
-
-void JitOptimizer::AppendExtractNthOutputForMerged(Definition* instr,
-                                                   intptr_t index,
-                                                   Representation rep,
-                                                   intptr_t cid) {
-  ExtractNthOutputInstr* extract =
-      new(Z) ExtractNthOutputInstr(new(Z) Value(instr), index, rep, cid);
-  instr->ReplaceUsesWith(extract);
-  flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
-}
-
-
-// Dart:
-//  var x = d % 10;
-//  var y = d ~/ 10;
-//  var z = x + y;
-//
-// IL:
-//  v4 <- %(v2, v3)
-//  v5 <- ~/(v2, v3)
-//  v6 <- +(v4, v5)
-//
-// IL optimized:
-//  v4 <- DIVMOD(v2, v3);
-//  v5 <- LoadIndexed(v4, 0); // ~/ result
-//  v6 <- LoadIndexed(v4, 1); // % result
-//  v7 <- +(v5, v6)
-// Because of the environment it is important that merged instruction replaces
-// first original instruction encountered.
-void JitOptimizer::TryMergeTruncDivMod(
-    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
-  if (merge_candidates->length() < 2) {
-    // Need at least a TRUNCDIV and a MOD.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
-           (curr_instr->op_kind() == Token::kMOD));
-    // Check if there is kMOD/kTRUNDIV binop with same inputs.
-    const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
-        Token::kMOD : Token::kTRUNCDIV;
-    Definition* left_def = curr_instr->left()->definition();
-    Definition* right_def = curr_instr->right()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
-      // 'other_binop' can be NULL if it was already merged.
-      if ((other_binop != NULL) &&
-          (other_binop->op_kind() == other_kind) &&
-          (other_binop->left()->definition() == left_def) &&
-          (other_binop->right()->definition() == right_def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(
-            curr_instr,
-            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
-            kTagged, kSmiCid);
-        ASSERT(other_binop->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_binop,
-            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
-            kTagged, kSmiCid);
-
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
-        args->Add(new(Z) Value(curr_instr->left()->definition()));
-        args->Add(new(Z) Value(curr_instr->right()->definition()));
-
-        // Replace with TruncDivMod.
-        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
-            args,
-            curr_instr->deopt_id(),
-            MergedMathInstr::kTruncDivMod);
-        curr_instr->ReplaceWith(div_mod, current_iterator());
-        other_binop->ReplaceUsesWith(div_mod);
-        other_binop->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
-        break;
-      }
-    }
-  }
-}
-
-
-// Tries to merge MathUnary operations, in this case sinus and cosinus.
-void JitOptimizer::TryMergeMathUnary(
-    GrowableArray<MathUnaryInstr*>* merge_candidates) {
-  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
-      !FLAG_merge_sin_cos) {
-    return;
-  }
-  if (merge_candidates->length() < 2) {
-    // Need at least a SIN and a COS.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    const intptr_t kind = curr_instr->kind();
-    ASSERT((kind == MathUnaryInstr::kSin) ||
-           (kind == MathUnaryInstr::kCos));
-    // Check if there is sin/cos binop with same inputs.
-    const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
-        MathUnaryInstr::kCos : MathUnaryInstr::kSin;
-    Definition* def = curr_instr->value()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      MathUnaryInstr* other_op = (*merge_candidates)[k];
-      // 'other_op' can be NULL if it was already merged.
-      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
-          (other_op->value()->definition() == def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(curr_instr,
-                                        MergedMathInstr::OutputIndexOf(kind),
-                                        kUnboxedDouble, kDoubleCid);
-        ASSERT(other_op->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_op,
-            MergedMathInstr::OutputIndexOf(other_kind),
-            kUnboxedDouble, kDoubleCid);
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
-        args->Add(new(Z) Value(curr_instr->value()->definition()));
-        // Replace with SinCos.
-        MergedMathInstr* sin_cos =
-            new(Z) MergedMathInstr(args,
-                                   curr_instr->DeoptimizationTarget(),
-                                   MergedMathInstr::kSinCos);
-        curr_instr->ReplaceWith(sin_cos, current_iterator());
-        other_op->ReplaceUsesWith(sin_cos);
-        other_op->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of sin/cos into sincos.
-        break;
-      }
-    }
-  }
-}
-
-
-// Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
-// shift can be a truncating Smi shift-left and result is always Smi.
-// Merging occurs only per basic-block.
-void JitOptimizer::TryOptimizePatterns() {
-  if (!FLAG_truncating_left_shift) return;
-  ASSERT(current_iterator_ == NULL);
-  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
-  GrowableArray<MathUnaryInstr*> sin_cos_merge;
-  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
-       !block_it.Done();
-       block_it.Advance()) {
-    // Merging only per basic-block.
-    div_mod_merge.Clear();
-    sin_cos_merge.Clear();
-    ForwardInstructionIterator it(block_it.Current());
-    current_iterator_ = &it;
-    for (; !it.Done(); it.Advance()) {
-      if (it.Current()->IsBinarySmiOp()) {
-        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
-        if (binop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(binop,
-                                       binop->left()->definition(),
-                                       binop->right()->definition());
-        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
-                   (binop->op_kind() == Token::kMOD)) {
-          if (binop->HasUses()) {
-            div_mod_merge.Add(binop);
-          }
-        }
-      } else if (it.Current()->IsBinaryMintOp()) {
-        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
-        if (mintop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(mintop,
-                                       mintop->left()->definition(),
-                                       mintop->right()->definition());
-        }
-      } else if (it.Current()->IsMathUnary()) {
-        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
-        if ((math_unary->kind() == MathUnaryInstr::kSin) ||
-            (math_unary->kind() == MathUnaryInstr::kCos)) {
-          if (math_unary->HasUses()) {
-            sin_cos_merge.Add(math_unary);
-          }
-        }
-      }
-    }
-    TryMergeTruncDivMod(&div_mod_merge);
-    TryMergeMathUnary(&sin_cos_merge);
-    current_iterator_ = NULL;
-  }
-}
-
-
 static bool ClassIdIsOneOf(intptr_t class_id,
                            const GrowableArray<intptr_t>& class_ids) {
   for (intptr_t i = 0; i < class_ids.length(); i++) {
@@ -1338,182 +1082,6 @@
 }
 
 
-bool JitOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
-                                         MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kFloat32x4Shuffle) ||
-      (getter == MethodRecognizer::kFloat32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kFloat32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kFloat32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kFloat32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle)  ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleW));
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
-                                         MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  if ((getter == MethodRecognizer::kFloat64x2GetX) ||
-      (getter == MethodRecognizer::kFloat64x2GetY)) {
-    Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        0,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool JitOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
-                                       MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kInt32x4Shuffle) ||
-      (getter == MethodRecognizer::kInt32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kInt32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kInt32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kInt32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4Shuffle) {
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-}
-
-
 bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
                                            Token::Kind op_kind) {
   if (!ShouldInlineSimd()) {
@@ -1654,28 +1222,6 @@
 }
 
 
-static bool IsSupportedByteArrayViewCid(intptr_t cid) {
-  switch (cid) {
-    case kTypedDataInt8ArrayCid:
-    case kTypedDataUint8ArrayCid:
-    case kExternalTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
-    case kExternalTypedDataUint8ClampedArrayCid:
-    case kTypedDataInt16ArrayCid:
-    case kTypedDataUint16ArrayCid:
-    case kTypedDataInt32ArrayCid:
-    case kTypedDataUint32ArrayCid:
-    case kTypedDataFloat32ArrayCid:
-    case kTypedDataFloat64ArrayCid:
-    case kTypedDataFloat32x4ArrayCid:
-    case kTypedDataInt32x4ArrayCid:
-      return true;
-    default:
-      return false;
-  }
-}
-
-
 // Inline only simple, frequently called core library methods.
 bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
   ASSERT(call->HasICData());
@@ -1691,48 +1237,6 @@
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(target);
 
-  if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
-      (recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
-      (recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
-      (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
-      ASSERT((class_ids[0] == kOneByteStringCid) ||
-             (class_ids[0] == kTwoByteStringCid) ||
-             (class_ids[0] == kExternalOneByteStringCid) ||
-             (class_ids[0] == kExternalTwoByteStringCid));
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (class_ids[0] == kOneByteStringCid) {
-    if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
-      // This is an internal method, no need to check argument types nor
-      // range.
-      Definition* str = call->ArgumentAt(0);
-      Definition* index = call->ArgumentAt(1);
-      Definition* value = call->ArgumentAt(2);
-      StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
-          new(Z) Value(str),
-          new(Z) Value(index),
-          new(Z) Value(value),
-          kNoStoreBarrier,
-          1,  // Index scale
-          kOneByteStringCid,
-          call->deopt_id(),
-          call->token_pos());
-      ReplaceCall(call, store_op);
-      return true;
-    }
-    return false;
-  }
-
   if (CanUnboxDouble() &&
       (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
     if (class_ids[0] == kSmiCid) {
@@ -1791,376 +1295,13 @@
           ReplaceCall(call, d2d_instr);
         }
         return true;
-      case MethodRecognizer::kDoubleAdd:
-      case MethodRecognizer::kDoubleSub:
-      case MethodRecognizer::kDoubleMul:
-      case MethodRecognizer::kDoubleDiv:
-        return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-            flow_graph_, current_iterator(), call);
       default:
-        // Unsupported method.
-        return false;
+        break;
     }
   }
 
-  if (IsSupportedByteArrayViewCid(class_ids[0])) {
-    return FlowGraphInliner::TryReplaceInstanceCallWithInline(
-        flow_graph_, current_iterator(), call);
-  }
-
-  if (class_ids[0] == kFloat32x4Cid) {
-    return TryInlineFloat32x4Method(call, recognized_kind);
-  }
-
-  if (class_ids[0] == kInt32x4Cid) {
-    return TryInlineInt32x4Method(call, recognized_kind);
-  }
-
-  if (class_ids[0] == kFloat64x2Cid) {
-    return TryInlineFloat64x2Method(call, recognized_kind);
-  }
-
-  return false;
-}
-
-
-bool JitOptimizer::TryInlineFloat32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
-    Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr();
-    ReplaceCall(call, zero);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
-    Float32x4SplatInstr* splat =
-        new(Z) Float32x4SplatInstr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, splat);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
-    Float32x4ConstructorInstr* con =
-        new(Z) Float32x4ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) {
-    Int32x4ToFloat32x4Instr* cast =
-        new(Z) Int32x4ToFloat32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) {
-    Float64x2ToFloat32x4Instr* cast =
-        new(Z) Float64x2ToFloat32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  }
-  return false;
-}
-
-
-bool JitOptimizer::TryInlineFloat64x2Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kFloat64x2Zero) {
-    Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr();
-    ReplaceCall(call, zero);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) {
-    Float64x2SplatInstr* splat =
-        new(Z) Float64x2SplatInstr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, splat);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) {
-    Float64x2ConstructorInstr* con =
-        new(Z) Float64x2ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) {
-    Float32x4ToFloat64x2Instr* cast =
-        new(Z) Float32x4ToFloat64x2Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  }
-  return false;
-}
-
-
-bool JitOptimizer::TryInlineInt32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) {
-    Int32x4BoolConstructorInstr* con =
-        new(Z) Int32x4BoolConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) {
-    Float32x4ToInt32x4Instr* cast =
-        new(Z) Float32x4ToInt32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) {
-    Int32x4ConstructorInstr* con =
-        new(Z) Int32x4ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  }
-  return false;
-}
-
-
-bool JitOptimizer::TryInlineFloat32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kFloat32x4ShuffleX:
-    case MethodRecognizer::kFloat32x4ShuffleY:
-    case MethodRecognizer::kFloat32x4ShuffleZ:
-    case MethodRecognizer::kFloat32x4ShuffleW:
-    case MethodRecognizer::kFloat32x4GetSignMask:
-      ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineFloat32x4Getter(call, recognized_kind);
-
-    case MethodRecognizer::kFloat32x4Equal:
-    case MethodRecognizer::kFloat32x4GreaterThan:
-    case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
-    case MethodRecognizer::kFloat32x4LessThan:
-    case MethodRecognizer::kFloat32x4LessThanOrEqual:
-    case MethodRecognizer::kFloat32x4NotEqual: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      Float32x4ComparisonInstr* cmp =
-          new(Z) Float32x4ComparisonInstr(recognized_kind,
-                                          new(Z) Value(left),
-                                          new(Z) Value(right),
-                                          call->deopt_id());
-      ReplaceCall(call, cmp);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Min:
-    case MethodRecognizer::kFloat32x4Max: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      Float32x4MinMaxInstr* minmax =
-          new(Z) Float32x4MinMaxInstr(
-              recognized_kind,
-              new(Z) Value(left),
-              new(Z) Value(right),
-              call->deopt_id());
-      ReplaceCall(call, minmax);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Scale: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Left and right values are swapped when handed to the instruction,
-      // this is done so that the double value is loaded into the output
-      // register and can be destroyed.
-      Float32x4ScaleInstr* scale =
-          new(Z) Float32x4ScaleInstr(recognized_kind,
-                                     new(Z) Value(right),
-                                     new(Z) Value(left),
-                                     call->deopt_id());
-      ReplaceCall(call, scale);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Sqrt:
-    case MethodRecognizer::kFloat32x4ReciprocalSqrt:
-    case MethodRecognizer::kFloat32x4Reciprocal: {
-      Definition* left = call->ArgumentAt(0);
-      Float32x4SqrtInstr* sqrt =
-          new(Z) Float32x4SqrtInstr(recognized_kind,
-                                    new(Z) Value(left),
-                                    call->deopt_id());
-      ReplaceCall(call, sqrt);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4WithX:
-    case MethodRecognizer::kFloat32x4WithY:
-    case MethodRecognizer::kFloat32x4WithZ:
-    case MethodRecognizer::kFloat32x4WithW: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind,
-                                                           new(Z) Value(left),
-                                                           new(Z) Value(right),
-                                                           call->deopt_id());
-      ReplaceCall(call, with);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Absolute:
-    case MethodRecognizer::kFloat32x4Negate: {
-      Definition* left = call->ArgumentAt(0);
-      Float32x4ZeroArgInstr* zeroArg =
-          new(Z) Float32x4ZeroArgInstr(
-              recognized_kind, new(Z) Value(left), call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Clamp: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* lower = call->ArgumentAt(1);
-      Definition* upper = call->ArgumentAt(2);
-      Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr(
-          new(Z) Value(left),
-          new(Z) Value(lower),
-          new(Z) Value(upper),
-          call->deopt_id());
-      ReplaceCall(call, clamp);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4ShuffleMix:
-    case MethodRecognizer::kFloat32x4Shuffle: {
-      return InlineFloat32x4Getter(call, recognized_kind);
-    }
-    default:
-      return false;
-  }
-}
-
-
-bool JitOptimizer::TryInlineFloat64x2Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kFloat64x2GetX:
-    case MethodRecognizer::kFloat64x2GetY:
-      ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineFloat64x2Getter(call, recognized_kind);
-    case MethodRecognizer::kFloat64x2Negate:
-    case MethodRecognizer::kFloat64x2Abs:
-    case MethodRecognizer::kFloat64x2Sqrt:
-    case MethodRecognizer::kFloat64x2GetSignMask: {
-      Definition* left = call->ArgumentAt(0);
-      Float64x2ZeroArgInstr* zeroArg =
-          new(Z) Float64x2ZeroArgInstr(
-              recognized_kind, new(Z) Value(left), call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    case MethodRecognizer::kFloat64x2Scale:
-    case MethodRecognizer::kFloat64x2WithX:
-    case MethodRecognizer::kFloat64x2WithY:
-    case MethodRecognizer::kFloat64x2Min:
-    case MethodRecognizer::kFloat64x2Max: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      Float64x2OneArgInstr* zeroArg =
-          new(Z) Float64x2OneArgInstr(recognized_kind,
-                                      new(Z) Value(left),
-                                      new(Z) Value(right),
-                                      call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    default:
-      return false;
-  }
-}
-
-
-bool JitOptimizer::TryInlineInt32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kInt32x4ShuffleMix:
-    case MethodRecognizer::kInt32x4Shuffle:
-    case MethodRecognizer::kInt32x4GetFlagX:
-    case MethodRecognizer::kInt32x4GetFlagY:
-    case MethodRecognizer::kInt32x4GetFlagZ:
-    case MethodRecognizer::kInt32x4GetFlagW:
-    case MethodRecognizer::kInt32x4GetSignMask:
-      ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineInt32x4Getter(call, recognized_kind);
-
-    case MethodRecognizer::kInt32x4Select: {
-      Definition* mask = call->ArgumentAt(0);
-      Definition* trueValue = call->ArgumentAt(1);
-      Definition* falseValue = call->ArgumentAt(2);
-      // Type check left.
-      AddCheckClass(mask,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr(
-          new(Z) Value(mask),
-          new(Z) Value(trueValue),
-          new(Z) Value(falseValue),
-          call->deopt_id());
-      ReplaceCall(call, select);
-      return true;
-    }
-    case MethodRecognizer::kInt32x4WithFlagX:
-    case MethodRecognizer::kInt32x4WithFlagY:
-    case MethodRecognizer::kInt32x4WithFlagZ:
-    case MethodRecognizer::kInt32x4WithFlagW: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* flag = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr(
-          recognized_kind,
-          new(Z) Value(left),
-          new(Z) Value(flag),
-          call->deopt_id());
-      ReplaceCall(call, setFlag);
-      return true;
-    }
-    default:
-      return false;
-  }
+  return FlowGraphInliner::TryReplaceInstanceCallWithInline(
+      flow_graph_, current_iterator(), call);
 }
 
 
@@ -2604,70 +1745,40 @@
 
 
 void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
-  if (!CanUnboxDouble()) {
-    return;
-  }
   MethodRecognizer::Kind recognized_kind =
       MethodRecognizer::RecognizeKind(call->function());
-  MathUnaryInstr::MathUnaryKind unary_kind;
   switch (recognized_kind) {
-    case MethodRecognizer::kMathSqrt:
-      unary_kind = MathUnaryInstr::kSqrt;
-      break;
-    case MethodRecognizer::kMathSin:
-      unary_kind = MathUnaryInstr::kSin;
-      break;
-    case MethodRecognizer::kMathCos:
-      unary_kind = MathUnaryInstr::kCos;
-      break;
-    default:
-      unary_kind = MathUnaryInstr::kIllegal;
-      break;
-  }
-  if (unary_kind != MathUnaryInstr::kIllegal) {
-    MathUnaryInstr* math_unary =
-        new(Z) MathUnaryInstr(unary_kind,
-                              new(Z) Value(call->ArgumentAt(0)),
-                              call->deopt_id());
-    ReplaceCall(call, math_unary);
-    return;
-  }
-  switch (recognized_kind) {
+    case MethodRecognizer::kObjectConstructor:
+    case MethodRecognizer::kObjectArrayAllocate:
     case MethodRecognizer::kFloat32x4Zero:
     case MethodRecognizer::kFloat32x4Splat:
     case MethodRecognizer::kFloat32x4Constructor:
     case MethodRecognizer::kFloat32x4FromFloat64x2:
-      TryInlineFloat32x4Constructor(call, recognized_kind);
-      break;
     case MethodRecognizer::kFloat64x2Constructor:
     case MethodRecognizer::kFloat64x2Zero:
     case MethodRecognizer::kFloat64x2Splat:
     case MethodRecognizer::kFloat64x2FromFloat32x4:
-      TryInlineFloat64x2Constructor(call, recognized_kind);
-      break;
     case MethodRecognizer::kInt32x4BoolConstructor:
     case MethodRecognizer::kInt32x4Constructor:
-      TryInlineInt32x4Constructor(call, recognized_kind);
+    case MethodRecognizer::kMathSqrt:
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathSin:
+    case MethodRecognizer::kMathCos:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2:
+      FlowGraphInliner::TryReplaceStaticCallWithInline(
+          flow_graph_, current_iterator(), call);
       break;
-    case MethodRecognizer::kObjectConstructor: {
-      // Remove the original push arguments.
-      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-        PushArgumentInstr* push = call->PushArgumentAt(i);
-        push->ReplaceUsesWith(push->value()->definition());
-        push->RemoveFromGraph();
-      }
-      // Manually replace call with global null constant. ReplaceCall can't
-      // be used for definitions that are already in the graph.
-      call->ReplaceUsesWith(flow_graph_->constant_null());
-      ASSERT(current_iterator()->Current() == call);
-      current_iterator()->RemoveCurrentFromGraph();
-      break;
-    }
     case MethodRecognizer::kMathMin:
     case MethodRecognizer::kMathMax: {
       // We can handle only monomorphic min/max call sites with both arguments
       // being either doubles or smis.
-      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+      if (CanUnboxDouble() &&
+          call->HasICData() &&
+          (call->ic_data()->NumberOfChecks() == 1)) {
         const ICData& ic_data = *call->ic_data();
         intptr_t result_cid = kIllegalCid;
         if (ICDataHasReceiverArgumentClassIds(ic_data,
@@ -2701,27 +1812,7 @@
       }
       break;
     }
-    case MethodRecognizer::kMathDoublePow:
-    case MethodRecognizer::kMathTan:
-    case MethodRecognizer::kMathAsin:
-    case MethodRecognizer::kMathAcos:
-    case MethodRecognizer::kMathAtan:
-    case MethodRecognizer::kMathAtan2: {
-      // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
-      // instructions contain type checks and conversions to double.
-      ZoneGrowableArray<Value*>* args =
-          new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
-      for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
-        args->Add(new(Z) Value(call->ArgumentAt(i)));
-      }
-      InvokeMathCFunctionInstr* invoke =
-          new(Z) InvokeMathCFunctionInstr(args,
-                                          call->deopt_id(),
-                                          recognized_kind,
-                                          call->token_pos());
-      ReplaceCall(call, invoke);
-      break;
-    }
+
     case MethodRecognizer::kDoubleFromInteger: {
       if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
         const ICData& ic_data = *call->ic_data();
@@ -2743,35 +1834,8 @@
       }
       break;
     }
-    default: {
-      if (call->function().IsFactory()) {
-        const Class& function_class =
-            Class::Handle(Z, call->function().Owner());
-        if ((function_class.library() == Library::CoreLibrary()) ||
-            (function_class.library() == Library::TypedDataLibrary())) {
-          intptr_t cid = FactoryRecognizer::ResultCid(call->function());
-          switch (cid) {
-            case kArrayCid: {
-              Value* type = new(Z) Value(call->ArgumentAt(0));
-              Value* num_elements = new(Z) Value(call->ArgumentAt(1));
-              if (num_elements->BindsToConstant() &&
-                  num_elements->BoundConstant().IsSmi()) {
-                intptr_t length =
-                    Smi::Cast(num_elements->BoundConstant()).Value();
-                if (length >= 0 && length <= Array::kMaxElements) {
-                  CreateArrayInstr* create_array =
-                      new(Z) CreateArrayInstr(
-                          call->token_pos(), type, num_elements);
-                  ReplaceCall(call, create_array);
-                }
-              }
-            }
-            default:
-              break;
-          }
-        }
-      }
-    }
+    default:
+      break;
   }
 }
 
diff --git a/runtime/vm/jit_optimizer.h b/runtime/vm/jit_optimizer.h
index ebddc78..21a7855 100644
--- a/runtime/vm/jit_optimizer.h
+++ b/runtime/vm/jit_optimizer.h
@@ -30,11 +30,6 @@
   // Use propagated class ids to optimize, replace or eliminate instructions.
   void ApplyClassIds();
 
-  // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
-  // shift can be a truncating Smi shift-left and result is always Smi.
-  // Merge instructions (only per basic-block).
-  void TryOptimizePatterns();
-
   virtual void VisitStaticCall(StaticCallInstr* instr);
   virtual void VisitInstanceCall(InstanceCallInstr* instr);
   virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
@@ -69,18 +64,6 @@
                                const ICData& unary_ic_data);
 
   bool TryInlineInstanceMethod(InstanceCallInstr* call);
-  bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Constructor(StaticCallInstr* call,
-                                    MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat32x4Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Method(InstanceCallInstr* call,
-                               MethodRecognizer::Kind recognized_kind);
   void ReplaceWithInstanceOf(InstanceCallInstr* instr);
   bool TypeCheckAsClassEquality(const AbstractType& type);
   void ReplaceWithTypeCast(InstanceCallInstr* instr);
@@ -118,12 +101,6 @@
   bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
                                    RawFunction::Kind kind) const;
 
-  bool InlineFloat32x4Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineFloat64x2Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineInt32x4Getter(InstanceCallInstr* call,
-                            MethodRecognizer::Kind getter);
   bool InlineFloat32x4BinaryOp(InstanceCallInstr* call,
                                Token::Kind op_kind);
   bool InlineInt32x4BinaryOp(InstanceCallInstr* call,
@@ -139,14 +116,6 @@
   void ReplaceWithMathCFunction(InstanceCallInstr* call,
                                 MethodRecognizer::Kind recognized_kind);
 
-  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
-                                    Definition* left_instr,
-                                    Definition* right_instr);
-  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
-  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
-
-  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
-                                       Representation rep, intptr_t cid);
   bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
 
   RawField* GetField(intptr_t class_id, const String& field_name);
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index f94e32a..e26c915 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -4,12 +4,14 @@
 
 #include "platform/assert.h"
 
+#include "include/dart_native_api.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/json_stream.h"
 #include "vm/message.h"
 #include "vm/metrics.h"
 #include "vm/object.h"
+#include "vm/safepoint.h"
 #include "vm/service.h"
 #include "vm/service_event.h"
 #include "vm/timeline.h"
@@ -193,18 +195,19 @@
 }
 
 
-static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
-  void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
-  return reinterpret_cast<uint8_t*>(new_ptr);
-}
-
-
 void JSONStream::PostNullReply(Dart_Port port) {
   PortMap::PostMessage(new Message(
       port, Object::null(), Message::kNormalPriority));
 }
 
 
+static void Finalizer(void* isolate_callback_data,
+                      Dart_WeakPersistentHandle handle,
+                      void* buffer) {
+  free(buffer);
+}
+
+
 void JSONStream::PostReply() {
   Dart_Port port = reply_port();
   ASSERT(port != ILLEGAL_PORT);
@@ -226,15 +229,33 @@
   }
   buffer_.AddChar('}');
 
-  const String& reply = String::Handle(String::New(ToCString()));
-  ASSERT(!reply.IsNull());
+  char* cstr;
+  intptr_t length;
+  Steal(&cstr, &length);
 
-  uint8_t* data = NULL;
-  MessageWriter writer(&data, &allocator, false);
-  writer.WriteMessage(reply);
-  bool result = PortMap::PostMessage(new Message(port, data,
-                                                 writer.BytesWritten(),
-                                                 Message::kNormalPriority));
+  bool result;
+  {
+    TransitionVMToNative transition(Thread::Current());
+    Dart_CObject bytes;
+    bytes.type = Dart_CObject_kExternalTypedData;
+    bytes.value.as_external_typed_data.type = Dart_TypedData_kUint8;
+    bytes.value.as_external_typed_data.length = length;
+    bytes.value.as_external_typed_data.data = reinterpret_cast<uint8_t*>(cstr);
+    bytes.value.as_external_typed_data.peer = cstr;
+    bytes.value.as_external_typed_data.callback = Finalizer;
+    Dart_CObject* elements[1];
+    elements[0] = &bytes;
+    Dart_CObject message;
+    message.type = Dart_CObject_kArray;
+    message.value.as_array.length = 1;
+    message.value.as_array.values = elements;
+    result = Dart_PostCObject(port, &message);
+  }
+
+  if (!result) {
+    free(cstr);
+  }
+
   if (FLAG_trace_service) {
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
@@ -672,7 +693,7 @@
 }
 
 
-void JSONStream::Steal(const char** buffer, intptr_t* buffer_length) {
+void JSONStream::Steal(char** buffer, intptr_t* buffer_length) {
   ASSERT(buffer != NULL);
   ASSERT(buffer_length != NULL);
   *buffer_length = buffer_.length();
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index eec69b0..2dac1c7 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -60,6 +60,7 @@
   kFileSystemDoesNotExist    = 1002,
   kFileDoesNotExist          = 1003,
   kIsolateReloadFailed       = 1004,
+  kIsolateReloadBarred       = 1005,
 };
 
 // Expected that user_data is a JSONStream*.
@@ -97,7 +98,7 @@
   TextBuffer* buffer() { return &buffer_; }
   const char* ToCString() { return buffer_.buf(); }
 
-  void Steal(const char** buffer, intptr_t* buffer_length);
+  void Steal(char** buffer, intptr_t* buffer_length);
 
   void set_reply_port(Dart_Port port);
 
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index e3d34dd..1fdd8e2 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -5,6 +5,7 @@
 #include "vm/megamorphic_cache_table.h"
 
 #include <stdlib.h>
+#include "vm/handles_impl.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/stub_code.h"
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index f72b629..3ad9de1 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -51,8 +51,6 @@
 
 DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000,
     "Huge method cutoff in unoptimized code size (in bytes).");
-DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000,
-    "Huge method cutoff in tokens: Disables optimizations for huge methods.");
 DEFINE_FLAG(bool, overlap_type_arguments, true,
     "When possible, partially or fully overlap the type arguments of a type "
     "with the type arguments of its super type.");
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index 3b9ac0d..c36c8ed 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -64,23 +64,6 @@
   // NOTE: This function will return -1 on OSs that are not supported.
   static int64_t GetCurrentThreadCPUMicros();
 
-  // Returns a cleared aligned array of type T with n entries.
-  // Alignment must be >= 16 and a power of two.
-  template<typename T>
-  static T* AllocateAlignedArray(intptr_t n, intptr_t alignment) {
-    T* result = reinterpret_cast<T*>(OS::AlignedAllocate(n * sizeof(*result),
-                                                         alignment));
-    memset(result, 0, n * sizeof(*result));
-    return result;
-  }
-
-  // Returns an aligned pointer in the C heap with room for size bytes.
-  // Alignment must be >= 16 and a power of two.
-  static void* AlignedAllocate(intptr_t size, intptr_t alignment);
-
-  // Frees a pointer returned from AlignedAllocate.
-  static void AlignedFree(void* ptr);
-
   // Returns the activation frame alignment constraint or one if
   // the platform doesn't care. Guaranteed to be a power of two.
   static intptr_t ActivationFrameAlignment();
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index c7cc8c5..92fcfd9 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -181,23 +181,6 @@
 }
 
 
-void* OS::AlignedAllocate(intptr_t size, intptr_t alignment) {
-  const int kMinimumAlignment = 16;
-  ASSERT(Utils::IsPowerOfTwo(alignment));
-  ASSERT(alignment >= kMinimumAlignment);
-  void* p = memalign(alignment, size);
-  if (p == NULL) {
-    UNREACHABLE();
-  }
-  return p;
-}
-
-
-void OS::AlignedFree(void* ptr) {
-  free(ptr);
-}
-
-
 // TODO(5411554):  May need to hoist these architecture dependent code
 // into a architecture specific file e.g: os_ia32_linux.cc
 intptr_t OS::ActivationFrameAlignment() {
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index af41362..48181f7 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -84,23 +84,6 @@
 }
 
 
-void* OS::AlignedAllocate(intptr_t size, intptr_t alignment) {
-  const int kMinimumAlignment = 16;
-  ASSERT(Utils::IsPowerOfTwo(alignment));
-  ASSERT(alignment >= kMinimumAlignment);
-  void* p = memalign(alignment, size);
-  if (p == NULL) {
-    UNREACHABLE();
-  }
-  return p;
-}
-
-
-void OS::AlignedFree(void* ptr) {
-  free(ptr);
-}
-
-
 // TODO(5411554):  May need to hoist these architecture dependent code
 // into a architecture specific file e.g: os_ia32_fuchsia.cc
 intptr_t OS::ActivationFrameAlignment() {
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 58efa89..12dd646 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -188,23 +188,6 @@
 }
 
 
-void* OS::AlignedAllocate(intptr_t size, intptr_t alignment) {
-  const int kMinimumAlignment = 16;
-  ASSERT(Utils::IsPowerOfTwo(alignment));
-  ASSERT(alignment >= kMinimumAlignment);
-  void* p = memalign(alignment, size);
-  if (p == NULL) {
-    UNREACHABLE();
-  }
-  return p;
-}
-
-
-void OS::AlignedFree(void* ptr) {
-  free(ptr);
-}
-
-
 // TODO(5411554):  May need to hoist these architecture dependent code
 // into a architecture specific file e.g: os_ia32_linux.cc
 intptr_t OS::ActivationFrameAlignment() {
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index cecee6f..db3adbb 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -166,24 +166,6 @@
 }
 
 
-void* OS::AlignedAllocate(intptr_t size, intptr_t alignment) {
-  const int kMinimumAlignment = 16;
-  ASSERT(Utils::IsPowerOfTwo(alignment));
-  ASSERT(alignment >= kMinimumAlignment);
-  // Temporary workaround until xcode is upgraded.
-  // Mac guarantees malloc returns a 16 byte aligned memory chunk.
-  // Currently we only allocate with 16-bye alignment.
-  ASSERT(alignment == 16);
-  // TODO(johnmccutchan): Remove hack and switch to posix_memalign.
-  return malloc(size);
-}
-
-
-void OS::AlignedFree(void* ptr) {
-  free(ptr);
-}
-
-
 intptr_t OS::ActivationFrameAlignment() {
 #if TARGET_OS_IOS
 #if TARGET_ARCH_ARM
diff --git a/runtime/vm/os_test.cc b/runtime/vm/os_test.cc
index d7239a6..fe01609 100644
--- a/runtime/vm/os_test.cc
+++ b/runtime/vm/os_test.cc
@@ -53,28 +53,4 @@
   EXPECT_LE(1, procs);
 }
 
-
-UNIT_TEST_CASE(OSAlignedAllocate) {
-  // TODO(johnmccutchan): Test other alignments, once we support
-  // alignments != 16 on Mac.
-  void* p1 = OS::AlignedAllocate(1023, 16);
-  void* p2 = OS::AlignedAllocate(1025, 16);
-  void* p3 = OS::AlignedAllocate(1025, 16);
-  void* p4 = OS::AlignedAllocate(1, 16);
-  void* p5 = OS::AlignedAllocate(2, 16);
-  void* p6 = OS::AlignedAllocate(4, 16);
-  EXPECT((reinterpret_cast<intptr_t>(p1) & 15) == 0);
-  EXPECT((reinterpret_cast<intptr_t>(p2) & 15) == 0);
-  EXPECT((reinterpret_cast<intptr_t>(p3) & 15) == 0);
-  EXPECT((reinterpret_cast<intptr_t>(p4) & 15) == 0);
-  EXPECT((reinterpret_cast<intptr_t>(p5) & 15) == 0);
-  EXPECT((reinterpret_cast<intptr_t>(p6) & 15) == 0);
-  OS::AlignedFree(p1);
-  OS::AlignedFree(p2);
-  OS::AlignedFree(p3);
-  OS::AlignedFree(p4);
-  OS::AlignedFree(p5);
-  OS::AlignedFree(p6);
-}
-
 }  // namespace dart
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index 809b0ad..129dcd1 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -190,23 +190,6 @@
 }
 
 
-void* OS::AlignedAllocate(intptr_t size, intptr_t alignment) {
-  const int kMinimumAlignment = 16;
-  ASSERT(Utils::IsPowerOfTwo(alignment));
-  ASSERT(alignment >= kMinimumAlignment);
-  void* p = _aligned_malloc(size, alignment);
-  if (p == NULL) {
-    UNREACHABLE();
-  }
-  return p;
-}
-
-
-void OS::AlignedFree(void* ptr) {
-  _aligned_free(ptr);
-}
-
-
 intptr_t OS::ActivationFrameAlignment() {
 #ifdef _WIN64
   // Windows 64-bit ABI requires the stack to be 16-byte aligned.
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index e9e6e93..4617d2a 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -48,6 +48,7 @@
 // committed to the current version.
 DEFINE_FLAG(bool, conditional_directives, true,
     "Enable conditional directives");
+DEFINE_FLAG(bool, generic_method_syntax, false, "Enable generic functions.");
 DEFINE_FLAG(bool, initializing_formal_access, false,
     "Make initializing formal parameters visible in initializer list.");
 DEFINE_FLAG(bool, warn_super, false,
@@ -55,6 +56,8 @@
 DEFINE_FLAG(bool, warn_patch, false, "Warn on old-style patch syntax.");
 DEFINE_FLAG(bool, await_is_keyword, false,
     "await and yield are treated as proper keywords in synchronous code.");
+DEFINE_FLAG(bool, assert_initializer, false,
+    "Allow asserts in initializer lists.");
 
 DECLARE_FLAG(bool, profile_vm);
 DECLARE_FLAG(bool, trace_service);
@@ -125,6 +128,25 @@
 };
 
 
+// Helper class to save and restore token position.
+class Parser::TokenPosScope : public ValueObject {
+ public:
+  explicit TokenPosScope(Parser *p) : p_(p) {
+    saved_pos_ = p_->TokenPos();
+  }
+  TokenPosScope(Parser *p, TokenPosition pos) : p_(p), saved_pos_(pos) {
+  }
+  ~TokenPosScope() {
+    p_->SetPosition(saved_pos_);
+  }
+
+ private:
+  Parser* p_;
+  TokenPosition saved_pos_;
+  DISALLOW_COPY_AND_ASSIGN(TokenPosScope);
+};
+
+
 class RecursionChecker : public ValueObject {
  public:
   explicit RecursionChecker(Parser* p) : parser_(p) {
@@ -2065,7 +2087,7 @@
     }
   }
 
-  if (CurrentToken() == Token::kLPAREN) {
+  if (IsParameterPart()) {
     // This parameter is probably a closure. If we saw the keyword 'var'
     // or 'final', a closure is not legal here and we ignore the
     // opening parens.
@@ -2079,6 +2101,18 @@
           AbstractType::Handle(Z, parameter.type->raw());
 
       // Finish parsing the function type parameter.
+      if (CurrentToken() == Token::kLT) {
+        // TODO(hausner): handle generic function types.
+        if (!FLAG_generic_method_syntax) {
+          ReportError("generic function types not supported");
+        }
+        TokenPosition type_param_pos = TokenPos();
+        if (!TryParseTypeParameters()) {
+          ReportError(type_param_pos, "error in type parameters");
+        }
+      }
+
+      ASSERT(CurrentToken() == Token::kLPAREN);
       ParamList func_params;
 
       // Add implicit closure object parameter.
@@ -2668,6 +2702,9 @@
                                   GrowableArray<Field*>* initialized_fields) {
   TRACE_PARSER("ParseInitializer");
   const TokenPosition field_pos = TokenPos();
+  if (FLAG_assert_initializer && CurrentToken() == Token::kASSERT) {
+    return ParseAssertStatement(current_function().is_const());
+  }
   if (CurrentToken() == Token::kTHIS) {
     ConsumeToken();
     ExpectToken(Token::kPERIOD);
@@ -2957,7 +2994,9 @@
         AstNode* init_statement =
             ParseInitializer(cls, receiver, initialized_fields);
         super_init_is_last = false;
-        current_block_->statements->Add(init_statement);
+        if (init_statement != NULL) {
+          current_block_->statements->Add(init_statement);
+        }
       }
     } while (CurrentToken() == Token::kCOMMA);
   }
@@ -3659,6 +3698,10 @@
       }
       CheckToken(Token::kLPAREN);
       SkipToMatchingParenthesis();
+    } else if (FLAG_assert_initializer && (CurrentToken() == Token::kASSERT)) {
+      ConsumeToken();
+      CheckToken(Token::kLPAREN);
+      SkipToMatchingParenthesis();
     } else {
       SkipIf(Token::kTHIS);
       SkipIf(Token::kPERIOD);
@@ -3716,7 +3759,10 @@
 
 void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) {
   TRACE_PARSER("ParseMethodOrConstructor");
-  ASSERT(CurrentToken() == Token::kLPAREN || method->IsGetter());
+  // We are at the beginning of the formal parameters list.
+  ASSERT(CurrentToken() == Token::kLPAREN ||
+         CurrentToken() == Token::kLT ||
+         method->IsGetter());
   ASSERT(method->type != NULL);
   ASSERT(current_member_ == method);
 
@@ -3741,6 +3787,25 @@
     current_class().set_is_const();
   }
 
+  if (CurrentToken() == Token::kLT) {
+    // Parse type parameters, but ignore them.
+    // TODO(hausner): handle type parameters.
+    if (!FLAG_generic_method_syntax) {
+      ReportError("generic type arguments not supported.");
+    }
+    TokenPosition type_param_pos = TokenPos();
+    if (method->IsFactoryOrConstructor()) {
+      ReportError(method->name_pos, "constructor cannot be generic");
+    }
+    if (method->IsGetter() || method->IsSetter()) {
+      ReportError(type_param_pos, "%s cannot be generic",
+          method->IsGetter() ? "getter" : "setter");
+    }
+    if (!TryParseTypeParameters()) {
+      ReportError(type_param_pos, "error in type parameters");
+    }
+  }
+
   // Parse the formal parameters.
   const bool are_implicitly_final = method->has_const;
   const bool allow_explicit_default_values = true;
@@ -4341,6 +4406,7 @@
     member.has_static = true;
     // The result type depends on the name of the factory method.
   }
+
   // Optionally parse a type.
   if (CurrentToken() == Token::kVOID) {
     if (member.has_var || member.has_factory) {
@@ -4349,29 +4415,24 @@
     ConsumeToken();
     ASSERT(member.type == NULL);
     member.type = &Object::void_type();
-  } else if (CurrentToken() == Token::kIDENT) {
-    // This is either a type name or the name of a method/constructor/field.
-    if ((member.type == NULL) && !member.has_factory) {
-      // We have not seen a member type yet, so we check if the next
-      // identifier could represent a type before parsing it.
-      Token::Kind follower = LookaheadToken(1);
-      // We have an identifier followed by a 'follower' token.
-      // We either parse a type or assume that no type is specified.
-      if ((follower == Token::kLT) ||  // Parameterized type.
-          (follower == Token::kGET) ||  // Getter following a type.
-          (follower == Token::kSET) ||  // Setter following a type.
-          (follower == Token::kOPERATOR) ||  // Operator following a type.
-          (Token::IsIdentifier(follower)) ||  // Member name following a type.
-          ((follower == Token::kPERIOD) &&    // Qualified class name of type,
-           (LookaheadToken(3) != Token::kLPAREN))) {  // but not a named constr.
-        ASSERT(is_top_level_);
-        // The declared type of fields is never ignored, even in unchecked mode,
-        // because getters and setters could be closurized at some time (not
-        // supported yet).
-        member.type = &AbstractType::ZoneHandle(Z,
-            ParseType(ClassFinalizer::kResolveTypeParameters));
+  } else {
+    bool found_type = false;
+    {
+      // Lookahead to determine whether the next tokens are a return type.
+      TokenPosScope saved_pos(this);
+      if (TryParseReturnType()) {
+        if (IsIdentifier() ||
+           (CurrentToken() == Token::kGET) ||
+           (CurrentToken() == Token::kSET) ||
+           (CurrentToken() == Token::kOPERATOR)) {
+          found_type = true;
+        }
       }
     }
+    if (found_type) {
+      member.type = &AbstractType::ZoneHandle(Z,
+          ParseType(ClassFinalizer::kResolveTypeParameters));
+    }
   }
 
   // Optionally parse a (possibly named) constructor name or factory.
@@ -4422,6 +4483,7 @@
     CheckToken(Token::kLPAREN);
   } else if ((CurrentToken() == Token::kGET) && !member.has_var &&
              (LookaheadToken(1) != Token::kLPAREN) &&
+             (LookaheadToken(1) != Token::kLT) &&
              (LookaheadToken(1) != Token::kASSIGN) &&
              (LookaheadToken(1) != Token::kCOMMA)  &&
              (LookaheadToken(1) != Token::kSEMICOLON)) {
@@ -4432,6 +4494,7 @@
     // If the result type was not specified, it will be set to DynamicType.
   } else if ((CurrentToken() == Token::kSET) && !member.has_var &&
              (LookaheadToken(1) != Token::kLPAREN) &&
+             (LookaheadToken(1) != Token::kLT) &&
              (LookaheadToken(1) != Token::kASSIGN) &&
              (LookaheadToken(1) != Token::kCOMMA)  &&
              (LookaheadToken(1) != Token::kSEMICOLON))  {
@@ -4450,6 +4513,8 @@
              (LookaheadToken(1) != Token::kASSIGN) &&
              (LookaheadToken(1) != Token::kCOMMA)  &&
              (LookaheadToken(1) != Token::kSEMICOLON)) {
+    // TODO(hausner): handle the case of a generic function named 'operator':
+    // eg: T operator<T>(a, b) => ...
     ConsumeToken();
     if (!Token::CanBeOverloaded(CurrentToken())) {
       ReportError("invalid operator overloading");
@@ -4473,7 +4538,7 @@
   }
 
   ASSERT(member.name != NULL);
-  if (CurrentToken() == Token::kLPAREN || member.IsGetter()) {
+  if (IsParameterPart() || member.IsGetter()) {
     // Constructor or method.
     if (member.type == NULL) {
       member.type = &Object::dynamic_type();
@@ -4569,6 +4634,14 @@
     is_patch = true;
     metadata_pos = TokenPosition::kNoSource;
     declaration_pos = TokenPos();
+  } else if (is_patch_source() &&
+      (CurrentToken() == Token::kIDENT) &&
+      CurrentLiteral()->Equals("patch")) {
+    if (FLAG_warn_patch) {
+      ReportWarning("deprecated use of patch 'keyword'");
+    }
+    ConsumeToken();
+    is_patch = true;
   } else if (CurrentToken() == Token::kABSTRACT) {
     is_abstract = true;
     ConsumeToken();
@@ -4753,7 +4826,11 @@
   is_top_level_ = true;
   String& class_name = String::Handle(Z, cls.Name());
   SkipMetadata();
-  if (CurrentToken() == Token::kABSTRACT) {
+  if (is_patch_source() &&
+      (CurrentToken() == Token::kIDENT) &&
+      CurrentLiteral()->Equals("patch")) {
+    ConsumeToken();
+  } else if (CurrentToken() == Token::kABSTRACT) {
     ConsumeToken();
   }
   ExpectToken(Token::kCLASS);
@@ -5128,16 +5205,14 @@
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
     return true;
   }
-  const TokenPosition saved_pos = TokenPos();
-  bool is_alias_name = false;
+  const TokenPosScope saved_pos(this);
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
     ConsumeToken();
     if (TryParseTypeParameters() && (CurrentToken() == Token::kLPAREN)) {
-      is_alias_name = true;
+      return true;
     }
   }
-  SetPosition(saved_pos);
-  return is_alias_name;
+  return false;
 }
 
 
@@ -5147,16 +5222,14 @@
   if (IsIdentifier() && (LookaheadToken(1) == Token::kASSIGN)) {
     return true;
   }
-  const TokenPosition saved_pos = TokenPos();
-  bool is_mixin_def = false;
+  const TokenPosScope saved_pos(this);
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
     ConsumeToken();
     if (TryParseTypeParameters() && (CurrentToken() == Token::kASSIGN)) {
-      is_mixin_def = true;
+      return true;
     }
   }
-  SetPosition(saved_pos);
-  return is_mixin_def;
+  return false;
 }
 
 
@@ -5263,9 +5336,9 @@
 }
 
 
-// Consumes exactly one right angle bracket. If the current token is a single
-// bracket token, it is consumed normally. However, if it is a double or triple
-// bracket, it is replaced by a single or double bracket token without
+// Consumes exactly one right angle bracket. If the current token is
+// a single bracket token, it is consumed normally. However, if it is
+// a double bracket, it is replaced by a single bracket token without
 // incrementing the token index.
 void Parser::ConsumeRightAngleBracket() {
   if (token_kind_ == Token::kGT) {
@@ -5282,12 +5355,10 @@
   if (pos == TokenPosition::kNoSource) {
     return false;
   }
-  TokenPosition saved_pos = TokenPos();
+  TokenPosScope saved_pos(this);
   SetPosition(pos);
   ExpectToken(Token::kAT);
-  bool is_patch = IsSymbol(Symbols::Patch());
-  SetPosition(saved_pos);
-  return is_patch;
+  return IsSymbol(Symbols::Patch());
 }
 
 
@@ -5636,6 +5707,15 @@
   if (is_patch_source() && IsPatchAnnotation(metadata_pos)) {
     is_patch = true;
     metadata_pos = TokenPosition::kNoSource;
+  } else if (is_patch_source() &&
+      (CurrentToken() == Token::kIDENT) &&
+      CurrentLiteral()->Equals("patch") &&
+      (LookaheadToken(1) != Token::kLPAREN)) {
+    if (FLAG_warn_patch) {
+      ReportWarning("deprecated use of patch 'keyword'");
+    }
+    ConsumeToken();
+    is_patch = true;
   } else if (CurrentToken() == Token::kEXTERNAL) {
     ConsumeToken();
     is_external = true;
@@ -5645,8 +5725,7 @@
     result_type = Type::VoidType();
   } else {
     // Parse optional type.
-    if ((CurrentToken() == Token::kIDENT) &&
-        (LookaheadToken(1) != Token::kLPAREN)) {
+    if (IsFunctionReturnType()) {
       result_type = ParseType(ClassFinalizer::kResolveTypeParameters);
     }
   }
@@ -5668,6 +5747,18 @@
   // A setter named x= may co-exist with a function named x, thus we do
   // not need to check setters.
 
+  if (CurrentToken() == Token::kLT) {
+    // Type parameters of generic function.
+    // TODO(hausner): handle type parameters.
+    if (!FLAG_generic_method_syntax) {
+      ReportError("generic functions not supported");
+    }
+    TokenPosition type_arg_pos = TokenPos();
+    if (!TryParseTypeParameters()) {
+      ReportError(type_arg_pos, "error in type parameters");
+    }
+  }
+
   CheckToken(Token::kLPAREN);
   const TokenPosition function_pos = TokenPos();
   ParamList params;
@@ -5756,6 +5847,14 @@
   if (is_patch_source() && IsPatchAnnotation(metadata_pos)) {
     is_patch = true;
     metadata_pos = TokenPosition::kNoSource;
+  } else if (is_patch_source() &&
+      (CurrentToken() == Token::kIDENT) &&
+      CurrentLiteral()->Equals("patch")) {
+    if (FLAG_warn_patch) {
+      ReportWarning("deprecated use of patch 'keyword'");
+    }
+    ConsumeToken();
+    is_patch = true;
   } else if (CurrentToken() == Token::kEXTERNAL) {
     ConsumeToken();
     is_external = true;
@@ -6299,6 +6398,9 @@
     } else if ((CurrentToken() == Token::kABSTRACT) &&
         (LookaheadToken(1) == Token::kCLASS)) {
       ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
+    } else if (is_patch_source() && IsSymbol(Symbols::Patch()) &&
+               (LookaheadToken(1) == Token::kCLASS)) {
+      ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
     } else {
       set_current_class(toplevel_class);
       if (IsVariableDeclaration()) {
@@ -7760,15 +7862,14 @@
   const TokenPosition function_pos = TokenPos();
   TokenPosition metadata_pos = TokenPosition::kNoSource;
   if (is_literal) {
-    ASSERT(CurrentToken() == Token::kLPAREN);
+    ASSERT(CurrentToken() == Token::kLPAREN || CurrentToken() == Token::kLT);
     function_name = &Symbols::AnonymousClosure();
   } else {
     metadata_pos = SkipMetadata();
     if (CurrentToken() == Token::kVOID) {
       ConsumeToken();
       result_type = Type::VoidType();
-    } else if ((CurrentToken() == Token::kIDENT) &&
-               (LookaheadToken(1) != Token::kLPAREN)) {
+    } else if (IsFunctionReturnType()) {
       result_type = ParseType(ClassFinalizer::kCanonicalize);
     }
     const TokenPosition name_pos = TokenPos();
@@ -7790,6 +7891,18 @@
                   line_number);
     }
   }
+
+  if (CurrentToken() == Token::kLT) {
+    if (!FLAG_generic_method_syntax) {
+      ReportError("generic functions not supported");
+    }
+    TokenPosition type_arg_pos = TokenPos();
+    // TODO(hausner): handle type parameters of generic function.
+    if (!TryParseTypeParameters()) {
+      ReportError(type_arg_pos, "error in type parameters");
+    }
+  }
+
   CheckToken(Token::kLPAREN);
 
   // Check whether we have parsed this closure function before, in a previous
@@ -7963,37 +8076,113 @@
 // Returns true if the current and next tokens can be parsed as type
 // parameters. Current token position is not saved and restored.
 bool Parser::TryParseTypeParameters() {
-  if (CurrentToken() == Token::kLT) {
-    // We are possibly looking at type parameters. Find closing ">".
-    int nesting_level = 0;
-    do {
-      if (CurrentToken() == Token::kLT) {
-        nesting_level++;
-      } else if (CurrentToken() == Token::kGT) {
-        nesting_level--;
-      } else if (CurrentToken() == Token::kSHR) {
-        nesting_level -= 2;
-      } else if (CurrentToken() == Token::kIDENT) {
-        // Check to see if it is a qualified identifier.
-        if (LookaheadToken(1) == Token::kPERIOD) {
-          // Consume the identifier, the period will be consumed below.
-          ConsumeToken();
-        }
-      } else if (CurrentToken() != Token::kCOMMA &&
-                 CurrentToken() != Token::kEXTENDS) {
-        // We are looking at something other than type parameters.
-        return false;
+  ASSERT(CurrentToken() == Token::kLT);
+  int nesting_level = 0;
+  do {
+    Token::Kind ct = CurrentToken();
+    if (ct == Token::kLT) {
+      nesting_level++;
+    } else if (ct == Token::kGT) {
+      nesting_level--;
+    } else if (ct == Token::kSHR) {
+      nesting_level -= 2;
+    } else if (ct == Token::kIDENT) {
+      // Check to see if it is a qualified identifier.
+      if (LookaheadToken(1) == Token::kPERIOD) {
+        // Consume the identifier, the period will be consumed below.
+        ConsumeToken();
       }
-      ConsumeToken();
-    } while (nesting_level > 0);
-    if (nesting_level < 0) {
+    } else if ((ct != Token::kCOMMA) &&
+               (ct != Token::kEXTENDS) &&
+               (!FLAG_generic_method_syntax || (ct != Token::kSUPER))) {
+      // We are looking at something other than type parameters.
       return false;
     }
+    ConsumeToken();
+  } while (nesting_level > 0);
+  if (nesting_level < 0) {
+    return false;
   }
   return true;
 }
 
 
+// Returns true if the next tokens can be parsed as type parameters.
+bool Parser::IsTypeParameters() {
+  if (CurrentToken() == Token::kLT) {
+    TokenPosScope param_pos(this);
+    if (!TryParseTypeParameters()) {
+      return false;
+    }
+    return true;
+  }
+  return false;
+}
+
+
+// Returns true if the next tokens are [ typeParameters ] '('.
+bool Parser::IsParameterPart() {
+  if (CurrentToken() == Token::kLPAREN) {
+    return true;
+  }
+  if (CurrentToken() == Token::kLT) {
+    TokenPosScope type_arg_pos(this);
+    if (!TryParseTypeParameters()) {
+      return false;
+    }
+    return CurrentToken() == Token::kLPAREN;
+  }
+  return false;
+}
+
+
+// Returns true if the current and next tokens can be parsed as type
+// arguments. Current token position is not saved and restored.
+bool Parser::TryParseTypeArguments() {
+  ASSERT(CurrentToken() == Token::kLT);
+  int nesting_level = 0;
+  do {
+    Token::Kind ct = CurrentToken();
+    if (ct == Token::kLT) {
+      nesting_level++;
+    } else if (ct == Token::kGT) {
+      nesting_level--;
+    } else if (ct == Token::kSHR) {
+      nesting_level -= 2;
+    } else if (ct == Token::kIDENT) {
+      // Check to see if it is a qualified identifier.
+      if (LookaheadToken(1) == Token::kPERIOD) {
+        // Consume the identifier, the period will be consumed below.
+        ConsumeToken();
+      }
+    } else if (ct != Token::kCOMMA) {
+      return false;
+    }
+    ConsumeToken();
+  } while (nesting_level > 0);
+  if (nesting_level < 0) {
+    return false;
+  }
+  return true;
+}
+
+
+// Returns true if the next tokens are [ typeArguments ] '('.
+bool Parser::IsArgumentPart() {
+  if (CurrentToken() == Token::kLPAREN) {
+    return true;
+  }
+  if (CurrentToken() == Token::kLT) {
+    TokenPosScope type_arg_pos(this);
+    if (!TryParseTypeArguments()) {
+      return false;
+    }
+    return CurrentToken() == Token::kLPAREN;
+  }
+  return false;
+}
+
+
 bool Parser::IsSimpleLiteral(const AbstractType& type, Instance* value) {
   // Assigning null never causes a type error.
   if (CurrentToken() == Token::kNULL) {
@@ -8157,84 +8346,116 @@
 }
 
 
-// Look ahead to detect whether the next tokens should be parsed as
-// a function declaration. Token position remains unchanged.
-bool Parser::IsFunctionDeclaration() {
-  const TokenPosition saved_pos = TokenPos();
-  bool is_external = false;
-  SkipMetadata();
-  if (is_top_level_ && (CurrentToken() == Token::kEXTERNAL)) {
-    // Skip over 'external' for top-level function declarations.
-    is_external = true;
-    ConsumeToken();
-  }
-  if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
-    // Possibly a function without explicit return type.
-    ConsumeToken();  // Consume function identifier.
-  } else if (TryParseReturnType()) {
-    if (!IsIdentifier()) {
-      SetPosition(saved_pos);
-      return false;
-    }
-    ConsumeToken();  // Consume function identifier.
-  } else {
-    SetPosition(saved_pos);
-    return false;
-  }
-  // Check parameter list and the following token.
-  if (CurrentToken() == Token::kLPAREN) {
-    SkipToMatchingParenthesis();
-    if ((CurrentToken() == Token::kLBRACE) ||
-        (CurrentToken() == Token::kARROW) ||
-        (is_top_level_ && IsSymbol(Symbols::Native())) ||
-        is_external ||
-        IsSymbol(Symbols::Async()) ||
-        IsSymbol(Symbols::Sync())) {
-      SetPosition(saved_pos);
+// Look ahead to see if the following tokens are a return type followed
+// by an identifier.
+bool Parser::IsFunctionReturnType() {
+  TokenPosScope decl_pos(this);
+  if (TryParseReturnType()) {
+    if (IsIdentifier()) {
+      // Return type followed by function name.
       return true;
     }
   }
-  SetPosition(saved_pos);
+  return false;
+}
+
+
+// Look ahead to detect whether the next tokens should be parsed as
+// a function declaration. Token position remains unchanged.
+bool Parser::IsFunctionDeclaration() {
+  bool is_external = false;
+  TokenPosScope decl_pos(this);
+  SkipMetadata();
+  if (is_top_level_) {
+    if (is_patch_source() &&
+        (CurrentToken() == Token::kIDENT) &&
+        CurrentLiteral()->Equals("patch") &&
+        (LookaheadToken(1) != Token::kLPAREN)) {
+      // Skip over 'patch' for top-level function declarations in patch sources.
+      ConsumeToken();
+    } else if (CurrentToken() == Token::kEXTERNAL) {
+      // Skip over 'external' for top-level function declarations.
+      is_external = true;
+      ConsumeToken();
+    }
+  }
+  const TokenPosition type_or_name_pos = TokenPos();
+  if (TryParseReturnType()) {
+    if (!IsIdentifier()) {
+      SetPosition(type_or_name_pos);
+    }
+  } else {
+    SetPosition(type_or_name_pos);
+  }
+  // Check for function name followed by optional type parameters.
+  if (!IsIdentifier()) {
+    return false;
+  }
+  ConsumeToken();
+  if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) {
+    return false;
+  }
+
+  // Optional type, function name and optinal type parameters are parsed.
+  if (CurrentToken() != Token::kLPAREN) {
+    return false;
+  }
+
+  // Check parameter list and the following token.
+  SkipToMatchingParenthesis();
+  if ((CurrentToken() == Token::kLBRACE) ||
+      (CurrentToken() == Token::kARROW) ||
+      (is_top_level_ && IsSymbol(Symbols::Native())) ||
+      is_external ||
+      IsSymbol(Symbols::Async()) ||
+      IsSymbol(Symbols::Sync())) {
+    return true;
+  }
   return false;
 }
 
 
 bool Parser::IsTopLevelAccessor() {
-  const TokenPosition saved_pos = TokenPos();
-  if (CurrentToken() == Token::kEXTERNAL) {
+  const TokenPosScope saved_pos(this);
+  if (is_patch_source() && IsSymbol(Symbols::Patch())) {
+    ConsumeToken();
+  } else if (CurrentToken() == Token::kEXTERNAL) {
     ConsumeToken();
   }
   if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) {
-    SetPosition(saved_pos);
     return true;
   }
   if (TryParseReturnType()) {
     if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) {
       if (Token::IsIdentifier(LookaheadToken(1))) {  // Accessor name.
-        SetPosition(saved_pos);
         return true;
       }
     }
   }
-  SetPosition(saved_pos);
   return false;
 }
 
 
 bool Parser::IsFunctionLiteral() {
-  if (CurrentToken() != Token::kLPAREN || !allow_function_literals_) {
+  if (!allow_function_literals_) {
     return false;
   }
-  const TokenPosition saved_pos = TokenPos();
-  bool is_function_literal = false;
-  SkipToMatchingParenthesis();
-  ParseFunctionModifier();
-  if ((CurrentToken() == Token::kLBRACE) ||
-      (CurrentToken() == Token::kARROW)) {
-    is_function_literal = true;
+  if ((CurrentToken() == Token::kLPAREN) || (CurrentToken() == Token::kLT)) {
+    TokenPosScope saved_pos(this);
+    if ((CurrentToken() == Token::kLT) && !TryParseTypeParameters()) {
+      return false;
+    }
+    if (CurrentToken() != Token::kLPAREN) {
+      return false;
+    }
+    SkipToMatchingParenthesis();
+    ParseFunctionModifier();
+    if ((CurrentToken() == Token::kLBRACE) ||
+        (CurrentToken() == Token::kARROW)) {
+       return true;
+    }
   }
-  SetPosition(saved_pos);
-  return is_function_literal;
+  return false;
 }
 
 
@@ -8242,8 +8463,7 @@
 // statement. Returns true if we recognize a for ( .. in expr)
 // statement.
 bool Parser::IsForInStatement() {
-  const TokenPosition saved_pos = TokenPos();
-  bool result = false;
+  const TokenPosScope saved_pos(this);
   // Allow const modifier as well when recognizing a for-in statement
   // pattern. We will get an error later if the loop variable is
   // declared with const.
@@ -8254,16 +8474,15 @@
   }
   if (IsIdentifier()) {
     if (LookaheadToken(1) == Token::kIN) {
-      result = true;
+      return true;
     } else if (TryParseOptionalType()) {
       if (IsIdentifier()) {
         ConsumeToken();
       }
-      result = (CurrentToken() == Token::kIN);
+      return CurrentToken() == Token::kIN;
     }
   }
-  SetPosition(saved_pos);
-  return result;
+  return false;
 }
 
 
@@ -9288,7 +9507,7 @@
 }
 
 
-AstNode* Parser::ParseAssertStatement() {
+AstNode* Parser::ParseAssertStatement(bool is_const) {
   TRACE_PARSER("ParseAssertStatement");
   ConsumeToken();  // Consume assert keyword.
   ExpectToken(Token::kLPAREN);
@@ -9299,6 +9518,10 @@
     return NULL;
   }
   AstNode* condition = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
+  if (is_const && !condition->IsPotentiallyConst()) {
+    ReportError(condition_pos,
+                "initializer assert expression must be compile time constant.");
+  }
   const TokenPosition condition_end = TokenPos();
   ExpectToken(Token::kRPAREN);
 
@@ -9308,9 +9531,12 @@
       Integer::ZoneHandle(Z, Integer::New(condition_pos.value(), Heap::kOld))));
   arguments->Add(new(Z) LiteralNode(condition_end,
       Integer::ZoneHandle(Z, Integer::New(condition_end.value(), Heap::kOld))));
-  return MakeStaticCall(Symbols::AssertionError(),
-                        Library::PrivateCoreLibName(Symbols::CheckAssertion()),
-                        arguments);
+  AstNode* assert_throw = MakeStaticCall(Symbols::AssertionError(),
+      Library::PrivateCoreLibName(is_const ? Symbols::CheckConstAssertion()
+                                           : Symbols::CheckAssertion()),
+      arguments);
+
+  return assert_throw;
 }
 
 
@@ -11663,8 +11889,17 @@
       }
       const TokenPosition ident_pos = TokenPos();
       String* ident = ExpectIdentifier("identifier expected");
-      if (CurrentToken() == Token::kLPAREN) {
-        // Identifier followed by a opening paren: method call.
+      if (IsArgumentPart()) {
+        // Identifier followed by optional type arguments and opening paren:
+        // method call.
+        if (CurrentToken() == Token::kLT) {
+          // Type arguments.
+          if (!FLAG_generic_method_syntax) {
+            ReportError("generic type arguments not supported.");
+          }
+          // TODO(hausner): handle type arguments.
+          ParseTypeArguments(ClassFinalizer::kIgnore);
+        }
         if (left->IsPrimaryNode() &&
             left->AsPrimaryNode()->primary().IsClass()) {
           // Static method call prefixed with class name.
@@ -11756,7 +11991,15 @@
       }
       selector =  new(Z) LoadIndexedNode(
           bracket_pos, array, index, Class::ZoneHandle(Z));
-    } else if (CurrentToken() == Token::kLPAREN) {
+    } else if (IsArgumentPart()) {
+      if (CurrentToken() == Token::kLT) {
+        // Type arguments.
+        if (!FLAG_generic_method_syntax) {
+          ReportError("generic type arguments not supported.");
+        }
+        // TODO(hausner): handle type arguments.
+        ParseTypeArguments(ClassFinalizer::kIgnore);
+      }
       if (left->IsPrimaryNode()) {
         PrimaryNode* primary_node = left->AsPrimaryNode();
         const TokenPosition primary_pos = primary_node->token_pos();
@@ -14377,6 +14620,9 @@
 
 
 void Parser::SkipActualParameters() {
+  if (CurrentToken() == Token::kLT) {
+    SkipTypeArguments();
+  }
   ExpectToken(Token::kLPAREN);
   while (CurrentToken() != Token::kRPAREN) {
     if (IsIdentifier() && (LookaheadToken(1) == Token::kCOLON)) {
@@ -14544,7 +14790,7 @@
       ConsumeToken();
       SkipNestedExpr();
       ExpectToken(Token::kRBRACK);
-    } else if (current_token == Token::kLPAREN) {
+    } else if (IsArgumentPart()) {
       SkipActualParameters();
     } else {
       break;
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index d2644b7..224ae25 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -285,6 +285,7 @@
 
   struct Block;
   class TryStack;
+  class TokenPosScope;
 
   Parser(const Script& script,
          const Library& library,
@@ -667,7 +668,7 @@
                                  AstNode* object,
                                  const String& name);
 
-  AstNode* ParseAssertStatement();
+  AstNode* ParseAssertStatement(bool is_const = false);
   AstNode* ParseJump(String* label_name);
   AstNode* ParseIfStatement(String* label_name);
   AstNode* ParseWhileStatement(String* label_name);
@@ -752,9 +753,14 @@
   bool IsMixinAppAlias();
   bool TryParseQualIdent();
   bool TryParseTypeParameters();
+  bool TryParseTypeArguments();
+  bool IsTypeParameters();
+  bool IsArgumentPart();
+  bool IsParameterPart();
   bool TryParseOptionalType();
   bool TryParseReturnType();
   bool IsVariableDeclaration();
+  bool IsFunctionReturnType();
   bool IsFunctionDeclaration();
   bool IsFunctionLiteral();
   bool IsForInStatement();
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index e919a52..4fa23bc 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -1905,7 +1905,7 @@
   // the ic data array instead indirectly through a Function in the ic data
   // array. Iterate all the object pools and rewrite the ic data from
   // (cid, target function, count) to (cid, target code, entry point), and
-  // replace the ICLookupThroughFunction stub with ICLookupThroughCode.
+  // replace the ICCallThroughFunction stub with ICCallThroughCode.
 
   class SwitchICCallsVisitor : public FunctionVisitor {
    public:
@@ -1934,8 +1934,8 @@
           ic_ ^= entry_.raw();
           ic_.ResetSwitchable(zone_);
         } else if (entry_.raw() ==
-                   StubCode::ICLookupThroughFunction_entry()->code()) {
-          target_code_ = StubCode::ICLookupThroughCode_entry()->code();
+                   StubCode::ICCallThroughFunction_entry()->code()) {
+          target_code_ = StubCode::ICCallThroughCode_entry()->code();
           pool_.SetObjectAt(i, target_code_);
         }
       }
@@ -2426,7 +2426,7 @@
 
         // Optimize (a << b) & c patterns, merge operations.
         // Run early in order to have more opportunity to optimize left shifts.
-        optimizer.TryOptimizePatterns();
+        flow_graph->TryOptimizePatterns();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         FlowGraphInliner::SetInliningId(flow_graph, 0);
@@ -2586,7 +2586,7 @@
         // Optimize (a << b) & c patterns, merge operations.
         // Run after CSE in order to have more opportunity to merge
         // instructions that have same inputs.
-        optimizer.TryOptimizePatterns();
+        flow_graph->TryOptimizePatterns();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index ddd5b26..d6fcec3 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -529,8 +529,9 @@
       return NextExit();
     }
     uword* new_fp = CallerFP();
-    if (new_fp <= fp_) {
-      // FP didn't move to a higher address.
+    if (!IsCalleeFrameOf(reinterpret_cast<uword>(new_fp),
+                         reinterpret_cast<uword>(fp_))) {
+      // FP didn't move to a caller (higher address on most architectures).
       return false;
     }
     // Success, update fp and pc.
@@ -859,10 +860,18 @@
     return false;
   }
 #endif
+
+#if defined(TARGET_ARCH_DBC)
+  if (!in_dart_code && (sp > *stack_lower)) {
+    // The stack pointer gives us a tighter lower bound.
+    *stack_lower = sp;
+  }
+#else
   if (sp > *stack_lower) {
     // The stack pointer gives us a tighter lower bound.
     *stack_lower = sp;
   }
+#endif
 
   if (*stack_lower >= *stack_upper) {
     // Stack boundary is invalid.
@@ -1125,11 +1134,6 @@
 
 void Profiler::SampleThread(Thread* thread,
                             const InterruptedThreadState& state) {
-#if defined(TARGET_ARCH_DBC)
-  // TODO(vegorov) implement simulator stack sampling.
-  return;
-#endif
-
   ASSERT(thread != NULL);
   OSThread* os_thread = thread->os_thread();
   ASSERT(os_thread != NULL);
@@ -1155,14 +1159,17 @@
   uintptr_t sp = 0;
   uintptr_t fp = state.fp;
   uintptr_t pc = state.pc;
-#if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC)
+#if defined(USING_SIMULATOR)
   Simulator* simulator = NULL;
 #endif
 
   if (in_dart_code) {
     // If we're in Dart code, use the Dart stack pointer.
 #if defined(TARGET_ARCH_DBC)
-    UNIMPLEMENTED();
+    simulator = isolate->simulator();
+    sp = simulator->get_sp();
+    fp = simulator->get_fp();
+    pc = simulator->get_pc();
 #elif defined(USING_SIMULATOR)
     simulator = isolate->simulator();
     sp = simulator->get_register(SPREG);
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index eb99c43..6aed93c 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -5,6 +5,7 @@
 #include "vm/profiler_service.h"
 
 #include "vm/growable_array.h"
+#include "vm/handles_impl.h"
 #include "vm/hash_map.h"
 #include "vm/log.h"
 #include "vm/native_symbol.h"
diff --git a/runtime/vm/redundancy_elimination.cc b/runtime/vm/redundancy_elimination.cc
index 32fe07b..f7bc9b7 100644
--- a/runtime/vm/redundancy_elimination.cc
+++ b/runtime/vm/redundancy_elimination.cc
@@ -1549,6 +1549,15 @@
       FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph);
     }
 
+    // For now, bail out for large functions to avoid OOM situations.
+    // TODO(fschneider): Fix the memory consumption issue.
+    intptr_t function_length =
+        graph->function().end_token_pos().Pos() -
+        graph->function().token_pos().Pos();
+    if (function_length >= FLAG_huge_method_cutoff_in_tokens) {
+      return false;
+    }
+
     DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
     AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads);
     if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
@@ -2514,6 +2523,15 @@
       FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph);
     }
 
+    // For now, bail out for large functions to avoid OOM situations.
+    // TODO(fschneider): Fix the memory consumption issue.
+    intptr_t function_length =
+        graph->function().end_token_pos().Pos() -
+        graph->function().token_pos().Pos();
+    if (function_length >= FLAG_huge_method_cutoff_in_tokens) {
+      return;
+    }
+
     DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
     AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores);
     if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index a6864b3..fe73042 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -29,6 +29,7 @@
 #include "vm/port.h"
 #include "vm/profiler_service.h"
 #include "vm/reusable_handles.h"
+#include "vm/safepoint.h"
 #include "vm/service_event.h"
 #include "vm/service_isolate.h"
 #include "vm/source_report.h"
@@ -838,6 +839,7 @@
   Thread* T = Thread::Current();
   ASSERT(I == T->isolate());
   ASSERT(I != NULL);
+  ASSERT(T->execution_state() == Thread::kThreadInVM);
   ASSERT(!msg.IsNull());
   ASSERT(msg.Length() == 6);
 
@@ -964,69 +966,86 @@
 }
 
 
+static void Finalizer(void* isolate_callback_data,
+                      Dart_WeakPersistentHandle handle,
+                      void* buffer) {
+  free(buffer);
+}
+
+
 void Service::SendEvent(const char* stream_id,
                         const char* event_type,
-                        const Object& event_message) {
+                        uint8_t* bytes,
+                        intptr_t bytes_length) {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   ASSERT(!ServiceIsolate::IsServiceIsolateDescendant(isolate));
-  if (!ServiceIsolate::IsRunning()) {
-    return;
-  }
-  HANDLESCOPE(thread);
 
-  const Array& list = Array::Handle(Array::New(2));
-  ASSERT(!list.IsNull());
-  const String& stream_id_str = String::Handle(String::New(stream_id));
-  list.SetAt(0, stream_id_str);
-  list.SetAt(1, event_message);
-
-  // Push the event to port_.
-  uint8_t* data = NULL;
-  MessageWriter writer(&data, &allocator, false);
-  writer.WriteMessage(list);
-  intptr_t len = writer.BytesWritten();
   if (FLAG_trace_service) {
     OS::Print("vm-service: Pushing ServiceEvent(isolate='%s', kind='%s',"
               " len=%" Pd ") to stream %s\n",
-              isolate->name(), event_type, len, stream_id);
+              isolate->name(), event_type, bytes_length, stream_id);
   }
-  // TODO(turnidge): For now we ignore failure to send an event.  Revisit?
-  PortMap::PostMessage(
-      new Message(ServiceIsolate::Port(), data, len, Message::kNormalPriority));
+
+  bool result;
+  {
+    TransitionVMToNative transition(thread);
+    Dart_CObject cbytes;
+    cbytes.type = Dart_CObject_kExternalTypedData;
+    cbytes.value.as_external_typed_data.type = Dart_TypedData_kUint8;
+    cbytes.value.as_external_typed_data.length = bytes_length;
+    cbytes.value.as_external_typed_data.data = bytes;
+    cbytes.value.as_external_typed_data.peer = bytes;
+    cbytes.value.as_external_typed_data.callback = Finalizer;
+
+    Dart_CObject cstream_id;
+    cstream_id.type = Dart_CObject_kString;
+    cstream_id.value.as_string = const_cast<char*>(stream_id);
+
+    Dart_CObject* elements[2];
+    elements[0] = &cstream_id;
+    elements[1] = &cbytes;
+    Dart_CObject message;
+    message.type = Dart_CObject_kArray;
+    message.value.as_array.length = 2;
+    message.value.as_array.values = elements;
+    result = Dart_PostCObject(ServiceIsolate::Port(), &message);
+  }
+
+  if (!result) {
+    free(bytes);
+  }
 }
 
 
-// TODO(turnidge): Rewrite this method to use Post_CObject instead.
 void Service::SendEventWithData(const char* stream_id,
                                 const char* event_type,
-                                const String& meta,
+                                const char* metadata,
+                                intptr_t metadata_size,
                                 const uint8_t* data,
-                                intptr_t size) {
-  // Bitstream: [meta data size (big-endian 64 bit)] [meta data (UTF-8)] [data]
-  const intptr_t meta_bytes = Utf8::Length(meta);
-  const intptr_t total_bytes = sizeof(uint64_t) + meta_bytes + size;
-  const TypedData& message = TypedData::Handle(
-      TypedData::New(kTypedDataUint8ArrayCid, total_bytes));
+                                intptr_t data_size) {
+  // Bitstream: [metadata size (big-endian 64 bit)] [metadata (UTF-8)] [data]
+  const intptr_t total_bytes = sizeof(uint64_t) + metadata_size + data_size;
+
+  uint8_t* message = static_cast<uint8_t*>(malloc(total_bytes));
   intptr_t offset = 0;
-  // TODO(koda): Rename these methods SetHostUint64, etc.
-  message.SetUint64(0, Utils::HostToBigEndian64(meta_bytes));
+
+  // Metadata size.
+  reinterpret_cast<uint64_t*>(message)[0] =
+      Utils::HostToBigEndian64(metadata_size);
   offset += sizeof(uint64_t);
-  {
-    NoSafepointScope no_safepoint;
-    meta.ToUTF8(static_cast<uint8_t*>(message.DataAddr(offset)), meta_bytes);
-    offset += meta_bytes;
-  }
-  // TODO(koda): It would be nice to avoid this copy (requires changes to
-  // MessageWriter code).
-  {
-    NoSafepointScope no_safepoint;
-    memmove(message.DataAddr(offset), data, size);
-    offset += size;
-  }
+
+  // Metadata.
+  memmove(&message[offset], metadata, metadata_size);
+  offset += metadata_size;
+
+  // Data.
+  memmove(&message[offset], data, data_size);
+  offset += data_size;
+
   ASSERT(offset == total_bytes);
-  SendEvent(stream_id, event_type, message);
+  SendEvent(stream_id, event_type, message, total_bytes);
 }
 
 
@@ -1195,8 +1214,12 @@
   Dart_ServiceRequestCallback callback = handler->callback();
   ASSERT(callback != NULL);
   const char* response = NULL;
-  bool success = callback(js->method(), js->param_keys(), js->param_values(),
-                          js->num_params(), handler->user_data(), &response);
+  bool success;
+  {
+    TransitionVMToNative transition(Thread::Current());
+    success = callback(js->method(), js->param_keys(), js->param_values(),
+                       js->num_params(), handler->user_data(), &response);
+  }
   ASSERT(response != NULL);
   if (!success) {
     js->SetupError();
@@ -1403,9 +1426,10 @@
       }
     }
   }
-  const String& message = String::Handle(String::New(js.ToCString()));
   uint8_t data[] = {0, 128, 255};
-  SendEventWithData(echo_stream.id(), "_Echo", message, data, sizeof(data));
+  SendEventWithData(echo_stream.id(), "_Echo",
+                    js.buffer()->buf(), js.buffer()->length(),
+                    data, sizeof(data));
 }
 
 
@@ -1937,13 +1961,16 @@
         intptr_t element_index = slot_offset.Value();
         jselement.AddProperty("_parentWordOffset", element_index);
       }
-
-      // We nil out the array after generating the response to prevent
-      // reporting suprious references when repeatedly looking for the
-      // references to an object.
-      path.SetAt(i * 2, Object::null_object());
     }
   }
+
+  // We nil out the array after generating the response to prevent
+  // reporting suprious references when repeatedly looking for the
+  // references to an object.
+  for (intptr_t i = 0; i < path.Length(); i++) {
+    path.SetAt(i, Object::null_object());
+  }
+
   return true;
 }
 
@@ -2055,8 +2082,8 @@
   // We nil out the array after generating the response to prevent
   // reporting spurious references when looking for inbound references
   // after looking for a retaining path.
-  for (intptr_t i = 0; i < limit; ++i) {
-    path.SetAt(i * 2, Object::null_object());
+  for (intptr_t i = 0; i < path.Length(); i++) {
+    path.SetAt(i, Object::null_object());
   }
 
   return true;
@@ -2362,23 +2389,24 @@
   ObjectGraph graph(thread);
   graph.IterateObjects(&visitor);
   intptr_t count = visitor.count();
-  if (count < limit) {
-    // Truncate the list using utility method for GrowableObjectArray.
-    GrowableObjectArray& wrapper = GrowableObjectArray::Handle(
-        GrowableObjectArray::New(storage));
-    wrapper.SetLength(count);
-    storage = Array::MakeArray(wrapper);
-  }
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "InstanceSet");
   jsobj.AddProperty("totalCount", count);
   {
     JSONArray samples(&jsobj, "samples");
-    for (int i = 0; i < storage.Length(); i++) {
+    for (int i = 0; (i < storage.Length()) && (i < count); i++) {
       const Object& sample = Object::Handle(storage.At(i));
       samples.AddValue(sample);
     }
   }
+
+  // We nil out the array after generating the response to prevent
+  // reporting spurious references when looking for inbound references
+  // after looking at allInstances.
+  for (intptr_t i = 0; i < storage.Length(); i++) {
+    storage.SetAt(i, Object::null_object());
+  }
+
   return true;
 }
 
@@ -2496,6 +2524,13 @@
                    "A library tag handler must be installed.");
     return true;
   }
+  if ((isolate->sticky_error() != Error::null()) ||
+      (Thread::Current()->sticky_error() != Error::null())) {
+    js->PrintError(kIsolateReloadBarred,
+                   "This isolate cannot reload sources anymore because there "
+                   "was an unhandled exception error. Restart the isolate.");
+    return true;
+  }
   if (isolate->IsReloading()) {
     js->PrintError(kIsolateIsReloading,
                    "This isolate is being reloaded.");
@@ -3335,14 +3370,13 @@
       }
     }
 
-    const String& message = String::Handle(String::New(js.ToCString()));
-
     uint8_t* chunk_start = buffer + (i * kChunkSize);
     intptr_t chunk_size = (i + 1 == num_chunks)
         ? stream.bytes_written() - (i * kChunkSize)
         : kChunkSize;
 
-    SendEventWithData(graph_stream.id(), "_Graph", message,
+    SendEventWithData(graph_stream.id(), "_Graph",
+                      js.buffer()->buf(), js.buffer()->length(),
                       chunk_start, chunk_size);
   }
 }
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 420ff62..6f9d1d6 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -180,16 +180,19 @@
                                        const Array& parameter_values,
                                        const Instance& reply_port,
                                        const Instance& id);
+  // Takes ownership of 'bytes'.
   static void SendEvent(const char* stream_id,
                         const char* event_type,
-                        const Object& eventMessage);
+                        uint8_t* bytes,
+                        intptr_t bytes_length);
 
   // Does not take ownership of 'data'.
   static void SendEventWithData(const char* stream_id,
                                 const char* event_type,
-                                const String& meta,
+                                const char* metadata,
+                                intptr_t metadata_size,
                                 const uint8_t* data,
-                                intptr_t size);
+                                intptr_t data_size);
 
   static void PostEvent(Isolate* isolate,
                         const char* stream_id,
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 8a19298..ee534ef 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -13,6 +13,7 @@
 #include "vm/object_id_ring.h"
 #include "vm/os.h"
 #include "vm/port.h"
+#include "vm/safepoint.h"
 #include "vm/service.h"
 #include "vm/unit_test.h"
 
@@ -37,7 +38,6 @@
     }
 
     // Parse the message.
-    String& response = String::Handle();
     Object& response_obj = Object::Handle();
     if (message->IsRaw()) {
       response_obj = message->raw_obj();
@@ -46,8 +46,20 @@
       MessageSnapshotReader reader(message->data(), message->len(), thread);
       response_obj = reader.ReadObject();
     }
-    response ^= response_obj.raw();
-    _msg = strdup(response.ToCString());
+    if (response_obj.IsString()) {
+      String& response = String::Handle();
+      response ^= response_obj.raw();
+      _msg = strdup(response.ToCString());
+    } else {
+      ASSERT(response_obj.IsArray());
+      Array& response_array = Array::Handle();
+      response_array ^= response_obj.raw();
+      ASSERT(response_array.Length() == 1);
+      ExternalTypedData& response = ExternalTypedData::Handle();
+      response ^= response_array.At(0);
+      _msg = strdup(reinterpret_cast<char*>(response.DataAddr(0)));
+    }
+
     return kOK;
   }
 
@@ -115,6 +127,18 @@
 }
 
 
+static void HandleIsolateMessage(Isolate* isolate, const Array& msg) {
+  TransitionNativeToVM transition(Thread::Current());
+  Service::HandleIsolateMessage(isolate, msg);
+}
+
+
+static void HandleRootMessage(const Array& message) {
+  TransitionNativeToVM transition(Thread::Current());
+  Service::HandleRootMessage(message);
+}
+
+
 TEST_CASE(Service_IsolateStickyError) {
   const char* kScript =
       "main() => throw 'HI THERE STICKY';\n";
@@ -245,7 +269,7 @@
   // Request an invalid code object.
   service_msg =
       Eval(lib, "[0, port, '0', 'getObject', ['objectId'], ['code/0']]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
@@ -255,7 +279,7 @@
                       "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp,
                       entry);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"type\":\"Code\"", handler.msg());
   {
@@ -276,7 +300,7 @@
                       "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp,
                       address);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
@@ -287,7 +311,7 @@
                       "['objectId'], ['code/%" Px64"-%" Px "']]",
                       compile_timestamp - 1,
                       address);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
@@ -296,7 +320,7 @@
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['code/native-%" Px "']]",
                       address);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // TODO(turnidge): It is pretty broken to return an Instance here.  Fix.
   EXPECT_SUBSTRING("\"kind\":\"Null\"",
@@ -306,7 +330,7 @@
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', ['objectId'], "
                       "['code/native%" Px "']]",
                       address);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 }
@@ -349,7 +373,7 @@
   // Fetch object.
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
 
   // Check type.
@@ -412,7 +436,7 @@
   // Fetch object.
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Check type.
   EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
@@ -474,7 +498,7 @@
   // Fetch object.
   service_msg = EvalF(lib, "[0, port, '0', 'getObject', "
                       "['objectId'], ['objects/%" Pd "']]", id);
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Check type.
   EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
@@ -534,7 +558,7 @@
 
   // Get persistent handles.
   service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Look for a heart beat.
   EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
@@ -549,7 +573,7 @@
 
   // Get persistent handles (again).
   service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
   // Verify that old persistent handles are not present.
@@ -595,7 +619,7 @@
                    "['address'], ['%" Px "']]"),
                 addr);
     service_msg = Eval(lib, buf);
-    Service::HandleIsolateMessage(isolate, service_msg);
+    HandleIsolateMessage(isolate, service_msg);
     EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
     EXPECT_SUBSTRING(ref ? "\"type\":\"@Instance\"" :
                            "\"type\":\"Instance\"",
@@ -606,7 +630,7 @@
   // Expect null when no object is found.
   service_msg = Eval(lib, "[0, port, '0', '_getObjectByAddress', "
                      "['address'], ['7']]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // TODO(turnidge): Should this be a ServiceException instead?
   EXPECT_SUBSTRING("{\"type\":\"Sentinel\",\"kind\":\"Free\","
@@ -667,12 +691,12 @@
 
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
-  Service::HandleRootMessage(service_msg);
+  HandleRootMessage(service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
                handler.msg());
   service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
-  Service::HandleRootMessage(service_msg);
+  HandleRootMessage(service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"error\":beta,\"id\":1}",
                handler.msg());
@@ -707,12 +731,12 @@
 
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"0\"}",
                handler.msg());
   service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"error\":beta,\"id\":\"0\"}",
                handler.msg());
@@ -747,21 +771,21 @@
 
   Array& service_msg = Array::Handle();
   service_msg = Eval(lib, "[0, port, '0', '_getCpuProfile', [], []]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect error (tags required).
   EXPECT_SUBSTRING("\"error\"", handler.msg());
 
   service_msg =
       Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['None']]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect profile
   EXPECT_SUBSTRING("\"type\":\"_CpuProfile\"", handler.msg());
 
   service_msg =
       Eval(lib, "[0, port, '0', '_getCpuProfile', ['tags'], ['Bogus']]");
-  Service::HandleIsolateMessage(isolate, service_msg);
+  HandleIsolateMessage(isolate, service_msg);
   EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
   // Expect error.
   EXPECT_SUBSTRING("\"error\"", handler.msg());
diff --git a/runtime/vm/signal_handler_macos.cc b/runtime/vm/signal_handler_macos.cc
index 75c9c09..36643c2 100644
--- a/runtime/vm/signal_handler_macos.cc
+++ b/runtime/vm/signal_handler_macos.cc
@@ -79,25 +79,17 @@
 uintptr_t SignalHandler::GetLinkRegister(const mcontext_t& mcontext) {
   uintptr_t lr = 0;
 
-#if defined(TARGET_ARCH_IA32)
+#if defined(HOST_ARCH_IA32)
   lr = 0;
-#elif defined(TARGET_ARCH_X64)
+#elif defined(HOST_ARCH_X64)
   lr = 0;
-#elif defined(TARGET_ARCH_MIPS) && defined(USING_SIMULATOR)
-  lr = 0;
-#elif defined(TARGET_ARCH_ARM) && defined(USING_SIMULATOR)
-  lr = 0;
-#elif defined(TARGET_ARCH_ARM64) && defined(USING_SIMULATOR)
-  lr = 0;
-#elif defined(TARGET_ARCH_ARM)
-  lr = 0;
-#elif defined(TARGET_ARCH_ARM64)
-  lr = 0;
-#elif defined(TARGET_ARCH_MIPS)
-  lr = 0;
+#elif defined(HOST_ARCH_ARM)
+  lr = static_cast<uintptr_t>(mcontext->__ss.__lr);
+#elif defined(HOST_ARCH_ARM64)
+  lr = static_cast<uintptr_t>(mcontext->__ss.__lr);
 #else
-  UNIMPLEMENTED();
-#endif  // TARGET_ARCH_...
+#error Unsupported architecture.
+#endif  // HOST_ARCH_...
 
   return lr;
 }
diff --git a/runtime/vm/simulator_arm.h b/runtime/vm/simulator_arm.h
index ce18ac0..c163a62 100644
--- a/runtime/vm/simulator_arm.h
+++ b/runtime/vm/simulator_arm.h
@@ -83,7 +83,7 @@
   // Accessor to the instruction counter.
   uint64_t get_icount() const { return icount_; }
 
-  // The isolate's top_exit_frame_info refers to a Dart frame in the simulator
+  // The thread's top_exit_frame_info refers to a Dart frame in the simulator
   // stack. The simulator's top_exit_frame_info refers to a C++ frame in the
   // native stack.
   uword top_exit_frame_info() const { return top_exit_frame_info_; }
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index 78c1812..de49dd9 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -80,7 +80,7 @@
   // Accessor to the instruction counter.
   uint64_t get_icount() const { return icount_; }
 
-  // The isolate's top_exit_frame_info refers to a Dart frame in the simulator
+  // The thread's top_exit_frame_info refers to a Dart frame in the simulator
   // stack. The simulator's top_exit_frame_info refers to a C++ frame in the
   // native stack.
   uword top_exit_frame_info() const { return top_exit_frame_info_; }
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index c26cb75..2e271c7 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -249,6 +249,17 @@
     ASSERT(GetClassId(code) == kCodeCid);
     FP[kPcMarkerSlotFromFp] = code;
   }
+
+  DART_FORCE_INLINE static uint8_t* GetTypedData(
+      RawObject* obj, RawObject* index, intptr_t scale) {
+    ASSERT(RawObject::IsTypedDataClassId(obj->GetClassId()));
+    RawTypedData* array = reinterpret_cast<RawTypedData*>(obj);
+    const intptr_t byte_offset = Smi::Value(RAW_CAST(Smi, index));
+    ASSERT(byte_offset >= 0);
+    ASSERT(((byte_offset + (1 << scale)) >> scale) <=
+               Smi::Value(array->ptr()->length_));
+    return array->ptr()->data() + byte_offset;
+  }
 };
 
 
@@ -542,6 +553,7 @@
   callee_fp[kSavedCallerFpSlotFromFp] = reinterpret_cast<RawObject*>(*FP);
   *pp = code->ptr()->object_pool_->ptr();
   *pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
+  pc_ = reinterpret_cast<uword>(*pc);  // For the profiler.
   *FP = callee_fp;
   *SP = *FP - 1;
 }
@@ -694,6 +706,7 @@
     thread->set_vm_tag(reinterpret_cast<uword>(drt));
     drt(args);
     thread->set_vm_tag(VMTag::kDartTagId);
+    thread->set_top_exit_frame_info(0);
     return true;
   } else {
     return false;
@@ -711,6 +724,7 @@
     thread->set_vm_tag(reinterpret_cast<uword>(f));
     f(args);
     thread->set_vm_tag(VMTag::kDartTagId);
+    thread->set_top_exit_frame_info(0);
     return true;
   } else {
     return false;
@@ -729,6 +743,7 @@
     NativeEntry::NativeCallWrapper(reinterpret_cast<Dart_NativeArguments>(args),
                                    f);
     thread->set_vm_tag(VMTag::kDartTagId);
+    thread->set_top_exit_frame_info(0);
     return true;
   } else {
     return false;
@@ -930,6 +945,7 @@
 
   // Save outer top_exit_frame_info.
   fp_[0] = reinterpret_cast<RawObject*>(thread->top_exit_frame_info());
+  thread->set_top_exit_frame_info(0);
 
   // Copy arguments and setup the Dart frame.
   const intptr_t argc = arguments.Length();
@@ -948,6 +964,7 @@
   // Ready to start executing bytecode. Load entry point and corresponding
   // object pool.
   pc = reinterpret_cast<uint32_t*>(code.raw()->ptr()->entry_point_);
+  pc_ = reinterpret_cast<uword>(pc);  // For the profiler.
   pp = code.object_pool()->ptr();
 
   // Cache some frequently used values in the frame.
@@ -1169,6 +1186,7 @@
       SimulatorHelpers::SetFrameCode(FP, code);
       pp = code->ptr()->object_pool_->ptr();
       pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
+      pc_ = reinterpret_cast<uword>(pc);  // For the profiler.
     }
     DISPATCH();
   }
@@ -1198,6 +1216,7 @@
         SimulatorHelpers::SetFrameCode(FP, code);
         pp = code->ptr()->object_pool_->ptr();
         pc = reinterpret_cast<uint32_t*>(code->ptr()->entry_point_);
+        pc_ = reinterpret_cast<uword>(pc);  // For the profiler.
       }
     }
     DISPATCH();
@@ -1757,10 +1776,10 @@
   }
 
   {
-    BYTECODE(ShrImm, A_B_C);
+    BYTECODE(ShlImm, A_B_C);
     const uint8_t shift = rC;
-    const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]) >> kSmiTagSize;
-    *reinterpret_cast<intptr_t*>(&FP[rA]) = (lhs >> shift) << kSmiTagSize;
+    const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
+    FP[rA] = reinterpret_cast<RawObject*>(lhs << shift);
     DISPATCH();
   }
 
@@ -1780,6 +1799,29 @@
     DISPATCH();
   }
 
+  {
+    BYTECODE(UnboxInt32, A_B_C);
+    const intptr_t box_cid = SimulatorHelpers::GetClassId(FP[rB]);
+    const bool may_truncate = rC == 1;
+    if (box_cid == kSmiCid) {
+      const intptr_t value = reinterpret_cast<intptr_t>(FP[rB]) >> kSmiTagSize;
+      const int32_t value32 = static_cast<int32_t>(value);
+      if (may_truncate || (value == static_cast<intptr_t>(value32))) {
+        FP[rA] = reinterpret_cast<RawObject*>(value);
+        pc++;
+      }
+    } else if (box_cid == kMintCid) {
+      RawMint* mint = RAW_CAST(Mint, FP[rB]);
+      const int64_t value = mint->ptr()->value_;
+      const int32_t value32 = static_cast<int32_t>(value);
+      if (may_truncate || (value == static_cast<int64_t>(value32))) {
+        FP[rA] = reinterpret_cast<RawObject*>(value);
+        pc++;
+      }
+    }
+    DISPATCH();
+  }
+
 #if defined(ARCH_IS_64_BIT)
   {
     BYTECODE(WriteIntoDouble, A_D);
@@ -1930,24 +1972,57 @@
   }
 
   {
-    BYTECODE(LoadFloat64Indexed, A_B_C);
-    ASSERT(RawObject::IsTypedDataClassId(FP[rB]->GetClassId()));
-    RawTypedData* array = reinterpret_cast<RawTypedData*>(FP[rB]);
-    RawSmi* index = RAW_CAST(Smi, FP[rC]);
-    ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
-    double* data = reinterpret_cast<double*>(array->ptr()->data());
-    FP[rA] = bit_cast<RawObject*, double>(data[Smi::Value(index)]);
+    BYTECODE(LoadIndexedFloat64, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rB], FP[rC], 3);
+    *reinterpret_cast<uint64_t*>(&FP[rA]) = *reinterpret_cast<uint64_t*>(data);
     DISPATCH();
   }
 
   {
-    BYTECODE(StoreFloat64Indexed, A_B_C);
+    BYTECODE(LoadIndexed8Float64, A_B_C);
+    ASSERT(RawObject::IsTypedDataClassId(FP[rB]->GetClassId()));
+    RawTypedData* array = reinterpret_cast<RawTypedData*>(FP[rB]);
+    RawSmi* index = RAW_CAST(Smi, FP[rC]);
+    ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+    const int64_t value =
+        reinterpret_cast<int64_t*>(array->ptr()->data())[Smi::Value(index)];
+    FP[rA] = reinterpret_cast<RawObject*>(value);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexedFloat64, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rA], FP[rB], 3);
+    *reinterpret_cast<uint64_t*>(data) = reinterpret_cast<uint64_t>(FP[rC]);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexed8Float64, A_B_C);
     ASSERT(RawObject::IsTypedDataClassId(FP[rA]->GetClassId()));
     RawTypedData* array = reinterpret_cast<RawTypedData*>(FP[rA]);
     RawSmi* index = RAW_CAST(Smi, FP[rB]);
     ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
-    double* data = reinterpret_cast<double*>(array->ptr()->data());
-    data[Smi::Value(index)] = bit_cast<double, RawObject*>(FP[rC]);
+    const int64_t value = reinterpret_cast<int64_t>(FP[rC]);
+    reinterpret_cast<int64_t*>(array->ptr()->data())[Smi::Value(index)] = value;
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(BoxInt32, A_D);
+    // Casts sign-extend high 32 bits from low 32 bits.
+    const intptr_t value = reinterpret_cast<intptr_t>(FP[rD]);
+    const int32_t value32 = static_cast<int32_t>(value);
+    FP[rA] = Smi::New(static_cast<intptr_t>(value32));
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(BoxUint32, A_D);
+    // Casts to zero out high 32 bits.
+    const uintptr_t value = reinterpret_cast<uintptr_t>(FP[rD]);
+    const uint32_t value32 = static_cast<uint32_t>(value);
+    FP[rA] = Smi::New(static_cast<intptr_t>(value32));
     DISPATCH();
   }
 #else  // defined(ARCH_IS_64_BIT)
@@ -2054,13 +2129,37 @@
   }
 
   {
-    BYTECODE(LoadFloat64Indexed, A_B_C);
+    BYTECODE(LoadIndexedFloat64, A_B_C);
     UNREACHABLE();
     DISPATCH();
   }
 
   {
-    BYTECODE(StoreFloat64Indexed, A_B_C);
+    BYTECODE(LoadIndexed8Float64, A_B_C);
+    UNREACHABLE();
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexedFloat64, A_B_C);
+    UNREACHABLE();
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexed8Float64, A_B_C);
+    UNREACHABLE();
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(BoxInt32, A_D);
+    UNREACHABLE();
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(BoxUint32, A_D);
     UNREACHABLE();
     DISPATCH();
   }
@@ -2090,6 +2189,7 @@
   ReturnImpl:
     // Restore caller PC.
     pc = SavedCallerPC(FP);
+    pc_ = reinterpret_cast<uword>(pc);  // For the profiler.
 
     // Check if it is a fake PC marking the entry frame.
     if ((reinterpret_cast<uword>(pc) & 2) != 0) {
@@ -2166,6 +2266,15 @@
   }
 
   {
+    BYTECODE(LoadUntagged, A_B_C);
+    const uint16_t instance_reg = rB;
+    const uint16_t offset_in_words = rC;
+    RawInstance* instance = reinterpret_cast<RawInstance*>(FP[instance_reg]);
+    FP[rA] = reinterpret_cast<RawObject**>(instance)[offset_in_words];
+    DISPATCH();
+  }
+
+  {
     BYTECODE(LoadFieldTOS, A_D);
     const uint16_t offset_in_words = rD;
     RawInstance* instance = static_cast<RawInstance*>(SP[0]);
@@ -2844,8 +2953,44 @@
   }
 
   {
+    BYTECODE(StoreIndexedUint8, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rA], FP[rB], 0);
+    *data = Smi::Value(RAW_CAST(Smi, FP[rC]));
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexedExternalUint8, A_B_C);
+    uint8_t* array = reinterpret_cast<uint8_t*>(FP[rA]);
+    RawSmi* index = RAW_CAST(Smi, FP[rB]);
+    RawSmi* value = RAW_CAST(Smi, FP[rC]);
+    array[Smi::Value(index)] = Smi::Value(value);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexedOneByteString, A_B_C);
+    RawOneByteString* array = RAW_CAST(OneByteString, FP[rA]);
+    RawSmi* index = RAW_CAST(Smi, FP[rB]);
+    RawSmi* value = RAW_CAST(Smi, FP[rC]);
+    ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+    array->ptr()->data()[Smi::Value(index)] = Smi::Value(value);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(StoreIndexedUint32, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rA], FP[rB], 2);
+    const uintptr_t value = reinterpret_cast<uintptr_t>(FP[rC]);
+    *reinterpret_cast<uint32_t*>(data) = static_cast<uint32_t>(value);
+    DISPATCH();
+  }
+
+  {
     BYTECODE(LoadIndexed, A_B_C);
-    RawArray* array = RAW_CAST(Array, FP[rB]);
+    RawObject* obj = FP[rB];
+    ASSERT(obj->IsArray() || obj->IsImmutableArray());
+    RawArray* array = reinterpret_cast<RawArray*>(obj);
     RawSmi* index = RAW_CAST(Smi, FP[rC]);
     ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
     FP[rA] = array->ptr()->data()[Smi::Value(index)];
@@ -2853,7 +2998,51 @@
   }
 
   {
-    BYTECODE(LoadOneByteStringIndexed, A_B_C);
+    BYTECODE(LoadIndexedUint8, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rB], FP[rC], 0);
+    FP[rA] = Smi::New(*data);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedInt8, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rB], FP[rC], 0);
+    FP[rA] = Smi::New(*reinterpret_cast<int8_t*>(data));
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedUint32, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rB], FP[rC], 2);
+    FP[rA] = reinterpret_cast<RawObject*>(*reinterpret_cast<uintptr_t*>(data));
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedInt32, A_B_C);
+    uint8_t* data = SimulatorHelpers::GetTypedData(FP[rB], FP[rC], 2);
+    FP[rA] = reinterpret_cast<RawObject*>(*reinterpret_cast<intptr_t*>(data));
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedExternalUint8, A_B_C);
+    uint8_t* data = reinterpret_cast<uint8_t*>(FP[rB]);
+    RawSmi* index = RAW_CAST(Smi, FP[rC]);
+    FP[rA] = Smi::New(data[Smi::Value(index)]);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedExternalInt8, A_B_C);
+    int8_t* data = reinterpret_cast<int8_t*>(FP[rB]);
+    RawSmi* index = RAW_CAST(Smi, FP[rC]);
+    FP[rA] = Smi::New(data[Smi::Value(index)]);
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(LoadIndexedOneByteString, A_B_C);
     RawOneByteString* array = RAW_CAST(OneByteString, FP[rB]);
     RawSmi* index = RAW_CAST(Smi, FP[rC]);
     ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
@@ -2862,7 +3051,7 @@
   }
 
   {
-    BYTECODE(LoadTwoByteStringIndexed, A_B_C);
+    BYTECODE(LoadIndexedTwoByteString, A_B_C);
     RawTwoByteString* array = RAW_CAST(TwoByteString, FP[rB]);
     RawSmi* index = RAW_CAST(Smi, FP[rC]);
     ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
@@ -2917,6 +3106,7 @@
 
     // Restore caller PC.
     pc = SavedCallerPC(FP);
+    pc_ = reinterpret_cast<uword>(pc);  // For the profiler.
 
     // Check if it is a fake PC marking the entry frame.
     ASSERT((reinterpret_cast<uword>(pc) & 2) == 0);
diff --git a/runtime/vm/simulator_dbc.h b/runtime/vm/simulator_dbc.h
index 2cbadce..bb875bb 100644
--- a/runtime/vm/simulator_dbc.h
+++ b/runtime/vm/simulator_dbc.h
@@ -50,7 +50,7 @@
   uword StackBase() const { return reinterpret_cast<uword>(stack_); }
   uword StackTop() const;
 
-  // The isolate's top_exit_frame_info refers to a Dart frame in the simulator
+  // The thread's top_exit_frame_info refers to a Dart frame in the simulator
   // stack. The simulator's top_exit_frame_info refers to a C++ frame in the
   // native stack.
   uword top_exit_frame_info() const { return top_exit_frame_info_; }
@@ -71,9 +71,9 @@
                RawObject* raw_stacktrace,
                Thread* thread);
 
-  uword get_sp() const {
-    return reinterpret_cast<uword>(sp_);
-  }
+  uword get_sp() const { return reinterpret_cast<uword>(sp_); }
+  uword get_fp() const { return reinterpret_cast<uword>(fp_); }
+  uword get_pc() const { return reinterpret_cast<uword>(pc_); }
 
   enum IntrinsicId {
 #define V(test_class_name, test_function_name, enum_name, type, fp) \
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index 700b1f5..cbda735 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -99,7 +99,7 @@
   // Accessor to the instruction counter.
   uint64_t get_icount() const { return icount_; }
 
-  // The isolate's top_exit_frame_info refers to a Dart frame in the simulator
+  // The thread's top_exit_frame_info refers to a Dart frame in the simulator
   // stack. The simulator's top_exit_frame_info refers to a C++ frame in the
   // native stack.
   uword top_exit_frame_info() const { return top_exit_frame_info_; }
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 915358a..adc8e1f 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -2925,7 +2925,7 @@
       "  var port = new RawReceivePort();\n"
       "  var sendPort = port.sendPort;\n"
       "  port.handler = (message) {\n"
-      "    if (messageCount < 8) {\n"
+      "    if (messageCount < 9) {\n"
       "      exception = '$exception${message}';\n"
       "    } else {\n"
       "      exception = '$exception${message.length}';\n"
@@ -2934,7 +2934,7 @@
       "      }\n"
       "    }\n"
       "    messageCount++;\n"
-      "    if (messageCount == 9) throw new Exception(exception);\n"
+      "    if (messageCount == 10) throw new Exception(exception);\n"
       "  };\n"
       "  return sendPort;\n"
       "}\n";
@@ -2973,6 +2973,10 @@
   object.value.as_string = const_cast<char*>("æøå");
   EXPECT(Dart_PostCObject(port_id, &object));
 
+  object.type = Dart_CObject_kString;
+  object.value.as_string = const_cast<char*>("");
+  EXPECT(Dart_PostCObject(port_id, &object));
+
   object.type = Dart_CObject_kDouble;
   object.value.as_double = 3.14;
   EXPECT(Dart_PostCObject(port_id, &object));
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index bb971e2..72e3608 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -37,9 +37,9 @@
   V(OptimizeFunction)                                                          \
   V(InvokeDartCode)                                                            \
   V(DebugStepCheck)                                                            \
-  V(ICLookupThroughFunction)                                                   \
-  V(ICLookupThroughCode)                                                       \
-  V(MegamorphicLookup)                                                         \
+  V(ICCallThroughFunction)                                                     \
+  V(ICCallThroughCode)                                                         \
+  V(MegamorphicCall)                                                           \
   V(MonomorphicMiss)                                                           \
   V(FixAllocationStubTarget)                                                   \
   V(Deoptimize)                                                                \
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 59bd06f..4faf29e 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1989,10 +1989,10 @@
 // Called from megamorphic calls.
 //  R0: receiver
 //  R9: MegamorphicCache (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code
 //  R4: arguments descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   __ LoadTaggedClassIdMayBeSmi(R0, R0);
@@ -2046,10 +2046,10 @@
 // Called from switchable IC calls.
 //  R0: receiver
 //  R9: ICData (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code object
 //  R4: arguments descriptor
-void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
@@ -2086,7 +2086,7 @@
 }
 
 
-void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index fc092bd..3f9663c 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -2031,10 +2031,10 @@
 // Called from megamorphic calls.
 //  R0: receiver
 //  R5: MegamorphicCache (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code
 //  R4: arguments descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   // Jump if receiver is a smi.
@@ -2106,10 +2106,10 @@
 // Called from switchable IC calls.
 //  R0: receiver
 //  R5: ICData (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code object
 //  R4: arguments descriptor
-void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
@@ -2146,7 +2146,7 @@
 }
 
 
-void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 15b8aa9..bf0f987 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1962,10 +1962,10 @@
 // Called from megamorphic calls.
 //  EBX: receiver
 //  ECX: MegamorphicCache (preserved)
-// Result:
+// Passed to target:
 //  EBX: target entry point
 //  EDX: argument descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
   // Jump if receiver is a smi.
   Label smi_case;
   // Check if object (in tmp) is a Smi.
@@ -2032,14 +2032,14 @@
 // Called from switchable IC calls.
 //  EBX: receiver
 //  ECX: ICData (preserved)
-// Result:
+// Passed to target:
 //  EDX: arguments descriptor
-void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
   __ int3();
 }
 
 
-void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
   __ int3();
 }
 
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index dc5788b..e98ce2b 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -2149,9 +2149,10 @@
 // Called from megamorphic calls.
 //  T0: receiver
 //  S5: MegamorphicCache (preserved)
-// Result:
+// Passed to target:
+//  CODE_REG: target Code object
 //  S4: arguments descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   __ LoadTaggedClassIdMayBeSmi(T0, T0);
@@ -2201,10 +2202,10 @@
 // Called from switchable IC calls.
 //  T0: receiver
 //  S5: ICData (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code object
 //  S4: arguments descriptor
-void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
@@ -2240,7 +2241,7 @@
 }
 
 
-void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 251d463..329d3f1 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -2011,10 +2011,10 @@
 // Called from megamorphic calls.
 //  RDI: receiver
 //  RBX: MegamorphicCache (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code
 //  R10: arguments descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
+void StubCode::GenerateMegamorphicCallStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   // Jump if receiver is a smi.
@@ -2084,10 +2084,10 @@
 // Called from switchable IC calls.
 //  RDI: receiver
 //  RBX: ICData (preserved)
-// Result:
+// Passed to target:
 //  CODE_REG: target Code object
 //  R10: arguments descriptor
-void StubCode::GenerateICLookupThroughFunctionStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughFunctionStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
@@ -2127,7 +2127,7 @@
 }
 
 
-void StubCode::GenerateICLookupThroughCodeStub(Assembler* assembler) {
+void StubCode::GenerateICCallThroughCodeStub(Assembler* assembler) {
   __ NoMonomorphicCheckedEntry();
 
   Label loop, found, miss;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 97d74af..567f95b 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -72,6 +72,7 @@
   V(ThrowNew, "_throwNew")                                                     \
   V(ThrowNewIfNotLoaded, "_throwNewIfNotLoaded")                               \
   V(CheckAssertion, "_checkAssertion")                                         \
+  V(CheckConstAssertion, "_checkConstAssertion")                               \
   V(Symbol, "Symbol")                                                          \
   V(SymbolCtor, "Symbol.")                                                     \
   V(List, "List")                                                              \
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 2e56a8e..83bf04b 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -90,7 +90,7 @@
   V(RawCode*, monomorphic_miss_stub_,                                          \
     StubCode::MonomorphicMiss_entry()->code(), NULL)                           \
   V(RawCode*, ic_lookup_through_code_stub_,                                    \
-    StubCode::ICLookupThroughCode_entry()->code(), NULL)                       \
+    StubCode::ICCallThroughCode_entry()->code(), NULL)                         \
 
 #endif
 
@@ -109,8 +109,8 @@
     StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)                      \
   V(uword, call_to_runtime_entry_point_,                                       \
     StubCode::CallToRuntime_entry()->EntryPoint(), 0)                          \
-  V(uword, megamorphic_lookup_checked_entry_,                                  \
-    StubCode::MegamorphicLookup_entry()->CheckedEntryPoint(), 0)               \
+  V(uword, megamorphic_call_checked_entry_,                                    \
+    StubCode::MegamorphicCall_entry()->CheckedEntryPoint(), 0)                 \
 
 #endif
 
@@ -329,6 +329,9 @@
   uword top_exit_frame_info() const {
     return top_exit_frame_info_;
   }
+  void set_top_exit_frame_info(uword top_exit_frame_info) {
+    top_exit_frame_info_ = top_exit_frame_info;
+  }
   static intptr_t top_exit_frame_info_offset() {
     return OFFSET_OF(Thread, top_exit_frame_info_);
   }
@@ -727,10 +730,6 @@
     zone_ = zone;
   }
 
-  void set_top_exit_frame_info(uword top_exit_frame_info) {
-    top_exit_frame_info_ = top_exit_frame_info;
-  }
-
   void set_safepoint_state(uint32_t value) {
     safepoint_state_ = value;
   }
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index f4c62a8..7e9ba2d 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -1180,7 +1180,7 @@
   // Steal output from JSONStream.
   char* output = NULL;
   intptr_t output_length = 0;
-  js.Steal(const_cast<const char**>(&output), &output_length);
+  js.Steal(&output, &output_length);
   (*file_write)(output, output_length, file);
   // Free the stolen output.
   free(output);
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 129ce01..5d84791 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -19,7 +19,6 @@
                               patch_lazy,
                               patch_startup,
                               Primitives,
-                              readHttp,
                               stringJoinUnchecked,
                               getTraceFromException;
 
@@ -640,12 +639,6 @@
   }
 }
 
-@patch
-class Resource {
-  @patch
-  const factory Resource(String uri) = _Resource;
-}
-
 Uri _resolvePackageUri(Uri packageUri) {
   assert(packageUri.scheme == "package");
   if (packageUri.hasAuthority) {
@@ -655,92 +648,6 @@
   return resolved;
 }
 
-class _Resource implements Resource {
-  final String _location;
-
-  const _Resource(String uri) : _location = uri;
-
-  Uri get uri => Uri.base.resolve(_location);
-
-  Stream<List<int>> openRead() {
-    Uri uri = this.uri;
-    if (uri.scheme == "package") {
-      uri = _resolvePackageUri(uri);
-    }
-    if (uri.scheme == "http" || uri.scheme == "https") {
-      return _readAsStream(uri);
-    }
-    throw new StateError("Unable to find resource, unknown scheme: $_location");
-  }
-
-  Future<List<int>> readAsBytes() {
-    Uri uri = this.uri;
-    if (uri.scheme == "package") {
-      uri = _resolvePackageUri(uri);
-    }
-    if (uri.scheme == "http" || uri.scheme == "https") {
-      return _readAsBytes(uri);
-    }
-    throw new StateError("Unable to find resource, unknown scheme: $_location");
-  }
-
-  Future<String> readAsString({Encoding encoding: UTF8}) {
-    Uri uri = this.uri;
-    if (uri.scheme == "package") {
-      uri = _resolvePackageUri(uri);
-    }
-    if (uri.scheme == "http" || uri.scheme == "https") {
-      return _readAsString(uri, encoding);
-    }
-    throw new StateError("Unable to find resource, unknown scheme: $_location");
-  }
-
-  // TODO(het): Use a streaming XHR request instead of returning the entire
-  // payload in one event.
-  Stream<List<int>> _readAsStream(Uri uri) {
-    var controller = new StreamController.broadcast();
-    // We only need to implement the listener as there is no way to provide
-    // back pressure into the channel.
-    controller.onListen = () {
-      // Once there is a listener, we kick off the loading of the resource.
-      _readAsBytes(uri).then((value) {
-        // The resource loading implementation sends all of the data in a
-        // single message. So the stream will only get a single value posted.
-        controller.add(value);
-        controller.close();
-      },
-      onError: (e, s) {
-        // In case the future terminates with an error we propagate it to the
-        // stream.
-        controller.addError(e, s);
-        controller.close();
-      });
-    };
-
-    return controller.stream;
-  }
-
-  Future<List<int>> _readAsBytes(Uri uri) {
-    return readHttp('$uri').then((data) {
-      if (data is NativeUint8List) return data;
-      if (data is String) return data.codeUnits;
-      throw new StateError(
-          "Unable to read Resource, data could not be decoded");
-    });
-  }
-
-  Future<String> _readAsString(Uri uri, Encoding encoding) {
-    return readHttp('$uri').then((data) {
-      if (data is String) return data;
-      if (data is NativeUint8List) {
-        return encoding.decode(data);
-      };
-      throw new StateError(
-          "Unable to read Resource, data could not be decoded");
-    });
-  }
-}
-
 @patch
 class StackTrace {
   @patch
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 7354ca2..011e45e 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -4024,58 +4024,6 @@
   return completer.future;
 }
 
-// Performs an HTTP GET of the given URI and returns the response. The response
-// is either a String or a ByteBuffer.
-Future<dynamic> readHttp(String uri) {
-  Completer completer = new Completer();
-
-  void failure([error, StackTrace stackTrace]) {
-    completer.completeError(
-        new Exception("Loading $uri failed: $error"),
-        stackTrace);
-  }
-
-  enterJsAsync();
-  completer.future.whenComplete(leaveJsAsync);
-
-  var xhr = JS('var', 'new XMLHttpRequest()');
-  JS('void', '#.open("GET", #)', xhr, uri);
-  JS('void', '#.addEventListener("load", #, false)',
-     xhr, convertDartClosureToJS((event) {
-    int status = JS('int', '#.status', xhr);
-    if (status != 200) {
-      failure("Status code: $status");
-      return;
-    }
-    String responseType = JS('String', '#.responseType', xhr);
-    var data;
-    if (responseType.isEmpty || responseType == 'text') {
-      data = JS('String', '#.response', xhr);
-      completer.complete(data);
-    } else if (responseType == 'document' || responseType == 'json') {
-      data = JS('String', '#.responseText', xhr);
-      completer.complete(data);
-    } else if (responseType == 'arraybuffer') {
-      data = JS('var', '#.response', xhr);
-      completer.complete(data);
-    } else if (responseType == 'blob') {
-      var reader = JS('var', 'new FileReader()');
-      JS('void', '#.addEventListener("loadend", #, false)',
-          reader, convertDartClosureToJS((event) {
-            data = JS('var', '#.result', reader);
-            completer.complete(data);
-          }, 1));
-    } else {
-      failure('Result had unexpected type: $responseType');
-    }
-  }, 1));
-
-  JS('void', '#.addEventListener("error", #, false)', xhr, failure);
-  JS('void', '#.addEventListener("abort", #, false)', xhr, failure);
-  JS('void', '#.send()', xhr);
-  return completer.future;
-}
-
 class MainError extends Error implements NoSuchMethodError {
   final String _message;
 
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
index 65ae257..3ec79b8 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
@@ -134,10 +134,6 @@
   return rti == null ? null : getIndex(rti, index);
 }
 
-void copyTypeArguments(Object source, Object target) {
-  JS('var', r'#.$builtinTypeInfo = #.$builtinTypeInfo', target, source);
-}
-
 /**
  * Retrieves the class name from type information stored on the constructor
  * of [object].
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index b4d9c24..c64e1c5 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -287,32 +287,51 @@
       }
     }
 
-    // As each future completes, put its value into the corresponding
-    // position in the list of values.
-    for (Future future in futures) {
-      int pos = remaining++;
-      future.then((Object/*=T*/ value) {
-        remaining--;
-        if (values != null) {
-          values[pos] = value;
-          if (remaining == 0) {
-            result._completeWithValue(values);
+    try {
+      // As each future completes, put its value into the corresponding
+      // position in the list of values.
+      for (Future future in futures) {
+        int pos = remaining;
+        future.then((Object/*=T*/ value) {
+          remaining--;
+          if (values != null) {
+            values[pos] = value;
+            if (remaining == 0) {
+              result._completeWithValue(values);
+            }
+          } else {
+            if (cleanUp != null && value != null) {
+              // Ensure errors from cleanUp are uncaught.
+              new Future.sync(() { cleanUp(value); });
+            }
+            if (remaining == 0 && !eagerError) {
+              result._completeError(error, stackTrace);
+            }
           }
-        } else {
-          if (cleanUp != null && value != null) {
-            // Ensure errors from cleanUp are uncaught.
-            new Future.sync(() { cleanUp(value); });
-          }
-          if (remaining == 0 && !eagerError) {
-            result._completeError(error, stackTrace);
-          }
-        }
-      }, onError: handleError);
+        }, onError: handleError);
+        // Increment the 'remaining' after the call to 'then'.
+        // If that call throws, we don't expect any future callback from
+        // the future, and we also don't increment remaining.
+        remaining++;
+      }
+      if (remaining == 0) {
+        return new Future.value(const []);
+      }
+      values = new List/*<T>*/(remaining);
+    } catch (e, st) {
+      // The error must have been thrown while iterating over the futures
+      // list, or while installing a callback handler on the future.
+      if (remaining == 0 || eagerError) {
+        // Just complete the error immediately.
+        result._completeError(e, st);
+      } else {
+        // Don't allocate a list for values, thus indicating that there was an
+        // error.
+        // Set error to the caught exception.
+        error = e;
+        stackTrace = st;
+      }
     }
-    if (remaining == 0) {
-      return new Future.value(const []);
-    }
-    values = new List/*<T>*/(remaining);
     return result;
   }
 
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 3bd3dab..24c9814 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -157,9 +157,8 @@
 import "dart:_internal" as internal show Symbol;
 import "dart:convert" show
   Encoding, ASCII, LATIN1, UTF8,
-  BASE64, StringConversionSink, ChunkedConversionSink;
+  BASE64, StringConversionSink;
 import "dart:math" show Random;  // Used by List.shuffle.
-import "dart:async" show Stream, Future;  // Used by Resource.
 import "dart:typed_data" show Uint8List;
 
 part "annotations.dart";
@@ -185,7 +184,6 @@
 part "pattern.dart";
 part "print.dart";
 part "regexp.dart";
-part "resource.dart";
 part "set.dart";
 part "sink.dart";
 part "stacktrace.dart";
diff --git a/sdk/lib/core/core_sources.gypi b/sdk/lib/core/core_sources.gypi
index 6cd311f..2c12762 100644
--- a/sdk/lib/core/core_sources.gypi
+++ b/sdk/lib/core/core_sources.gypi
@@ -29,7 +29,6 @@
     'pattern.dart',
     'print.dart',
     'regexp.dart',
-    'resource.dart',
     'set.dart',
     'sink.dart',
     'stacktrace.dart',
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index b5e9c3c..b792ac2 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -664,10 +664,14 @@
   external int get microsecondsSinceEpoch;
 
   /**
-   * The time zone name provided by the platform.
+   * The time zone name.
    *
-   * On Unix-like systems this will probably be an abbreviation. On Windows
-   * this will probably be the full-name, e.g. "Pacific Standard Time".
+   * This value is provided by the operating system and may be an
+   * abbreviation or a full name.
+   *
+   * In the browser or on Unix-like systems commonly returns abbreviations,
+   * such as "CET" or "CEST". On Windows returns the full name, for example
+   * "Pacific Standard Time".
    */
   external String get timeZoneName;
 
diff --git a/sdk/lib/core/resource.dart b/sdk/lib/core/resource.dart
deleted file mode 100644
index e8c9c67..0000000
--- a/sdk/lib/core/resource.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.core;
-
-/**
- * DEPRECATED. A resource that can be read into the program.
- *
- * WARNING: This API is _deprecated_,
- * and it will be removed in 1.14. Please use
- * https://pub.dartlang.org/packages/resource instead.
- *
- * A resource is data that can be located using a URI and read into
- * the program at runtime.
- * The URI may use the `package` scheme to read resources provided
- * along with package sources.
- */
-@Deprecated('1.14')
-abstract class Resource {
-  /**
-   * Creates a resource object with the given [uri] as location.
-   *
-   * The `uri` is a string containing a valid URI.
-   * If the string is not a valid URI, using any of the functions on
-   * the resource object will fail.
-   *
-   * The URI may be relative, in which case it will be resolved
-   * against [Uri.base] before being used.
-   *
-   * The URI may use the `package` scheme, which is always supported.
-   * Other schemes may also be supported where possible.
-   */
-  external const factory Resource(String uri);
-
-  /**
-   * The location `uri` of this resource.
-   *
-   * This is a [Uri] of the `uri` parameter given to the constructor.
-   * If the parameter was not a valid URI, reading `uri` may fail.
-   */
-  Uri get uri;
-
-  /** Read the resource content as a stream of bytes. */
-  Stream<List<int>> openRead();
-
-  /** Read the resource content. */
-  Future<List<int>> readAsBytes();
-
-  /**
-   * Read the resource content as a string.
-   *
-   * The content is decoded into a string using an [Encoding].
-   * If no other encoding is provided, it defaults to UTF-8.
-   */
-  Future<String> readAsString({Encoding encoding});
-}
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index 7527844..92d5699 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.dart
@@ -66,6 +66,9 @@
             ? new _CaseInsensitiveStringMap<String>()
             : new Map<String, String>();
         for (var str in env) {
+          if (str == null) {
+            continue;
+          }
           // The Strings returned by [_environment()] are expected to be
           // valid environment entries, but exceptions have been seen
           // (e.g., an entry of just '=' has been seen on OS/X).
diff --git a/sdk/lib/io/websocket.dart b/sdk/lib/io/websocket.dart
index df6c8cf..42c3562 100644
--- a/sdk/lib/io/websocket.dart
+++ b/sdk/lib/io/websocket.dart
@@ -402,6 +402,14 @@
    * must be either `String`s, or `List<int>`s holding bytes.
    */
   Future addStream(Stream stream);
+
+  /**
+   * Sends a text message with the text represented by [bytes].
+   *
+   * The [bytes] should be valid UTF-8 encoded Unicode characters. If they are
+   * not, the receiving end will close the connection.
+   */
+  void addUtf8Text(List<int> bytes);
 }
 
 class WebSocketException implements IOException {
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index d593b58..047cf69 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -36,6 +36,11 @@
   static const int RESERVED_F = 15;
 }
 
+class _EncodedString {
+  final List<int> bytes;
+  _EncodedString(this.bytes);
+}
+
 /**
  *  Stores the header and integer value derived from negotiation of
  *  client_max_window_bits and server_max_window_bits. headerValue will be
@@ -670,13 +675,14 @@
       if (message is String) {
         opcode = _WebSocketOpcode.TEXT;
         data = UTF8.encode(message);
+      } else if (message is List<int>) {
+        opcode = _WebSocketOpcode.BINARY;
+        data = message;
+      } else if (message is _EncodedString) {
+        opcode = _WebSocketOpcode.TEXT;
+        data = message.bytes;
       } else {
-        if (message is List<int>) {
-          opcode = _WebSocketOpcode.BINARY;
-          data = message;
-        } else {
-          throw new ArgumentError(message);
-        }
+        throw new ArgumentError(message);
       }
 
       if (_deflateHelper != null) {
@@ -1176,6 +1182,12 @@
   String get closeReason => _closeReason;
 
   void add(data) { _sink.add(data); }
+  void addUtf8Text(List<int> bytes) {
+    if (bytes is! List<int>) {
+      throw new ArgumentError.value(bytes, "bytes", "Is not a list of bytes");
+    }
+    _sink.add(new _EncodedString(bytes));
+  }
   void addError(error, [StackTrace stackTrace]) {
     _sink.addError(error, stackTrace);
   }
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 25ceb6a..a56c293 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -330,6 +330,15 @@
     return encodeSuccess(message);
   }
 
+  static responseAsJson(portResponse) {
+    if (portResponse is String) {
+      return JSON.decode(portResponse);
+    } else {
+      var cstring = portResponse[0];
+      return JSON.fuse(UTF8).decode(cstring);
+    }
+  }
+
   // TODO(johnmccutchan): Turn this into a command line tool that uses the
   // service library.
   Future<String> _getCrashDump(Message message) async {
@@ -353,13 +362,13 @@
 
     // Request VM.
     var getVM = Uri.parse('getVM');
-    var getVmResponse = JSON.decode(
+    var getVmResponse = responseAsJson(
         await new Message.fromUri(client, getVM).sendToVM());
     responses[getVM.toString()] = getVmResponse['result'];
 
     // Request command line flags.
     var getFlagList = Uri.parse('getFlagList');
-    var getFlagListResponse = JSON.decode(
+    var getFlagListResponse = responseAsJson(
         await new Message.fromUri(client, getFlagList).sendToVM());
     responses[getFlagList.toString()] = getFlagListResponse['result'];
 
@@ -369,13 +378,13 @@
         var message = new Message.forIsolate(client, request, isolate);
         // Decode the JSON and and insert it into the map. The map key
         // is the request Uri.
-        var response = JSON.decode(await isolate.route(message));
+        var response = responseAsJson(await isolate.route(message));
         responses[message.toUri().toString()] = response['result'];
       }
       // Dump the object id ring requests.
       var message =
           new Message.forIsolate(client, Uri.parse('_dumpIdZone'), isolate);
-      var response = JSON.decode(await isolate.route(message));
+      var response = responseAsJson(await isolate.route(message));
       // Insert getObject requests into responses map.
       for (var object in response['result']['objects']) {
         final requestUri =
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index 123ae7e..0bb8f37 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -219,7 +219,7 @@
       var expectedTypes = f(compiler);
       var signature = element.functionSignature;
       int index = 0;
-      var inferrer = compiler.typesTask.typesInferrer;
+      var inferrer = compiler.globalInference.typesInferrer;
       signature.forEachParameter((Element element) {
         Expect.equals(expectedTypes[index++],
             simplify(inferrer.getTypeOfElement(element), compiler),
@@ -239,47 +239,47 @@
 }
 
 void test() {
-  runTest(TEST_1, (compiler) => [compiler.typesTask.stringType]);
-  runTest(TEST_2, (compiler) => [compiler.typesTask.uint31Type]);
-  runTest(TEST_3, (compiler) => [compiler.typesTask.intType]);
-  runTest(TEST_4, (compiler) => [compiler.typesTask.numType]);
-  runTest(TEST_5, (compiler) => [compiler.typesTask.numType]);
-  runTest(TEST_6, (compiler) => [compiler.typesTask.numType]);
+  runTest(TEST_1, (compiler) => [compiler.commonMasks.stringType]);
+  runTest(TEST_2, (compiler) => [compiler.commonMasks.uint31Type]);
+  runTest(TEST_3, (compiler) => [compiler.commonMasks.intType]);
+  runTest(TEST_4, (compiler) => [compiler.commonMasks.numType]);
+  runTest(TEST_5, (compiler) => [compiler.commonMasks.numType]);
+  runTest(TEST_6, (compiler) => [compiler.commonMasks.numType]);
   runTest(TEST_7a, (compiler) => [subclassOfInterceptor(compiler)]);
   runTest(TEST_7b,
-      (compiler) => [compiler.typesTask.dynamicType.nonNullable()]);
+      (compiler) => [compiler.commonMasks.dynamicType.nonNullable()]);
 
-  runTest(TEST_8, (compiler) => [compiler.typesTask.uint31Type,
-                                 subclassOfInterceptor(compiler),
-                                 compiler.typesTask.dynamicType.nonNullable()]);
-  runTest(TEST_9, (compiler) => [compiler.typesTask.uint31Type,
-                                 compiler.typesTask.uint31Type]);
-  runTest(TEST_10, (compiler) => [compiler.typesTask.uint31Type,
-                                 compiler.typesTask.uint31Type]);
+  runTest(TEST_8, (compiler) => [compiler.commonMasks.uint31Type,
+      subclassOfInterceptor(compiler),
+      compiler.commonMasks.dynamicType.nonNullable()]);
+  runTest(TEST_9, (compiler) => [compiler.commonMasks.uint31Type,
+      compiler.commonMasks.uint31Type]);
+  runTest(TEST_10, (compiler) => [compiler.commonMasks.uint31Type,
+      compiler.commonMasks.uint31Type]);
   runTest(TEST_11, (compiler) => [subclassOfInterceptor(compiler),
-                                  subclassOfInterceptor(compiler)]);
+      subclassOfInterceptor(compiler)]);
 
-  runTest(TEST_12, (compiler) => [compiler.typesTask.stringType,
-                                  compiler.typesTask.uint31Type]);
+  runTest(TEST_12, (compiler) => [compiler.commonMasks.stringType,
+      compiler.commonMasks.uint31Type]);
 
-  runTest(TEST_13, (compiler) => [compiler.typesTask.numType]);
+  runTest(TEST_13, (compiler) => [compiler.commonMasks.numType]);
 
-  runTest(TEST_14, (compiler) => [compiler.typesTask.uint31Type,
-                                  compiler.typesTask.stringType]);
+  runTest(TEST_14, (compiler) => [compiler.commonMasks.uint31Type,
+      compiler.commonMasks.stringType]);
 
-  runTest(TEST_15, (compiler) => [compiler.typesTask.stringType,
-                                  compiler.typesTask.boolType]);
+  runTest(TEST_15, (compiler) => [compiler.commonMasks.stringType,
+      compiler.commonMasks.boolType]);
 
-  runTest(TEST_16, (compiler) => [compiler.typesTask.uint31Type,
-                                  compiler.typesTask.uint31Type,
-                                  compiler.typesTask.stringType]);
+  runTest(TEST_16, (compiler) => [compiler.commonMasks.uint31Type,
+      compiler.commonMasks.uint31Type,
+      compiler.commonMasks.stringType]);
 
-  runTest(TEST_17, (compiler) => [compiler.typesTask.uint31Type,
-                                  compiler.typesTask.boolType,
-                                  compiler.typesTask.doubleType]);
+  runTest(TEST_17, (compiler) => [compiler.commonMasks.uint31Type,
+      compiler.commonMasks.boolType,
+      compiler.commonMasks.doubleType]);
 
   runTest(TEST_18, (compiler) => [subclassOfInterceptor(compiler),
-                                  subclassOfInterceptor(compiler)]);
+      subclassOfInterceptor(compiler)]);
 }
 
 void main() {
diff --git a/tests/compiler/dart2js/closure_tracer_test.dart b/tests/compiler/dart2js/closure_tracer_test.dart
index 86d1e2f..f8718e4 100644
--- a/tests/compiler/dart2js/closure_tracer_test.dart
+++ b/tests/compiler/dart2js/closure_tracer_test.dart
@@ -154,8 +154,8 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkType(String name, type) {
       var element = findElement(compiler, name);
@@ -163,18 +163,18 @@
       Expect.equals(type.nullable(), simplify(mask, compiler), name);
     }
 
-    checkType('testFunctionStatement', typesTask.uint31Type);
-    checkType('testFunctionExpression', typesTask.uint31Type);
-    checkType('testStoredInInstance', typesTask.uint31Type);
-    checkType('testStoredInStatic', typesTask.uint31Type);
-    checkType('testStoredInMapOfList', typesTask.uint31Type);
-    checkType('testStoredInListOfList', typesTask.uint31Type);
-    checkType('testStoredInListOfListUsingInsert', typesTask.uint31Type);
-    checkType('testStoredInListOfListUsingAdd', typesTask.uint31Type);
-    checkType('testPassedInParameter', typesTask.uint31Type);
-    checkType('testStaticClosure1', typesTask.uint31Type);
-    checkType('testStaticClosure2', typesTask.numType);
-    checkType('testStaticClosure3', typesTask.uint31Type);
-    checkType('testStaticClosure4', typesTask.numType);
+    checkType('testFunctionStatement', commonMasks.uint31Type);
+    checkType('testFunctionExpression', commonMasks.uint31Type);
+    checkType('testStoredInInstance', commonMasks.uint31Type);
+    checkType('testStoredInStatic', commonMasks.uint31Type);
+    checkType('testStoredInMapOfList', commonMasks.uint31Type);
+    checkType('testStoredInListOfList', commonMasks.uint31Type);
+    checkType('testStoredInListOfListUsingInsert', commonMasks.uint31Type);
+    checkType('testStoredInListOfListUsingAdd', commonMasks.uint31Type);
+    checkType('testPassedInParameter', commonMasks.uint31Type);
+    checkType('testStaticClosure1', commonMasks.uint31Type);
+    checkType('testStaticClosure2', commonMasks.numType);
+    checkType('testStaticClosure3', commonMasks.uint31Type);
+    checkType('testStaticClosure4', commonMasks.numType);
   }));
 }
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 2c1684e..cff4c52 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -213,7 +213,7 @@
     element = compiler.backend.helpers.interceptorsLibrary.find(sourceName);
   }
   if (element == null) {
-    element = compiler.coreLibrary.find(sourceName);
+    element = compiler.commonElements.coreLibrary.find(sourceName);
   }
   Expect.isNotNull(element, 'Could not locate $name');
   switch (how) {
diff --git a/tests/compiler/dart2js/concrete_type_inference_test.dart b/tests/compiler/dart2js/concrete_type_inference_test.dart
index c245deb..de673f8 100644
--- a/tests/compiler/dart2js/concrete_type_inference_test.dart
+++ b/tests/compiler/dart2js/concrete_type_inference_test.dart
@@ -24,7 +24,8 @@
       (compiler, printElement) {
         var parameter =
           printElement.functionSignature.requiredParameters.first;
-        var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
+        var type =
+            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
 
@@ -34,7 +35,8 @@
       (compiler, printElement) {
         var parameter =
           printElement.functionSignature.requiredParameters.first;
-        var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
+        var type =
+            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
 
@@ -44,7 +46,8 @@
       (compiler, printElement) {
         var parameter =
           printElement.functionSignature.requiredParameters.first;
-        var type = compiler.typesTask.getGuaranteedTypeOfElement(parameter);
+        var type =
+            compiler.globalInference.getGuaranteedTypeOfElement(parameter);
         checkType(compiler, type);
       }));
 }
@@ -52,24 +55,24 @@
 void testBasicTypes() {
   checkPrintType('true', (compiler, type) {
     if (type.isForwarding) type = type.forwardTo;
-    Expect.identical(compiler.typesTask.boolType, type);
+    Expect.identical(compiler.commonMasks.boolType, type);
   });
   checkPrintType('1.5', (compiler, type) {
-    Expect.identical(compiler.typesTask.doubleType, type);
+    Expect.identical(compiler.commonMasks.doubleType, type);
   });
   checkPrintType('1', (compiler, type) {
-    Expect.identical(compiler.typesTask.uint31Type, type);
+    Expect.identical(compiler.commonMasks.uint31Type, type);
   });
   checkPrintType('[]', (compiler, type) {
     if (type.isForwarding) type = type.forwardTo;
-    Expect.identical(compiler.typesTask.growableListType, type);
+    Expect.identical(compiler.commonMasks.growableListType, type);
   });
   checkPrintType('null', (compiler, type) {
-    Expect.identical(compiler.typesTask.nullType, type);
+    Expect.identical(compiler.commonMasks.nullType, type);
   });
   checkPrintType('"foo"', (compiler, type) {
     Expect.isTrue(
-        compiler.typesTask.stringType.containsOnlyString(compiler.world));
+        compiler.commonMasks.stringType.containsOnlyString(compiler.world));
   });
 }
 
@@ -84,16 +87,17 @@
           .optionalParameters[0];
         var thirdParameter = fiskElement.functionSignature
           .optionalParameters[1];
-        var typesTask = compiler.typesTask;
+        var commonMasks = compiler.commonMasks;
+        var inference = compiler.globalInference;
         Expect.identical(
-            typesTask.uint31Type,
-            typesTask.getGuaranteedTypeOfElement(firstParameter));
+            commonMasks.uint31Type,
+            inference.getGuaranteedTypeOfElement(firstParameter));
         Expect.identical(
-            typesTask.nullType,
-            typesTask.getGuaranteedTypeOfElement(secondParameter));
+            commonMasks.nullType,
+            inference.getGuaranteedTypeOfElement(secondParameter));
         Expect.identical(
-            typesTask.nullType,
-            typesTask.getGuaranteedTypeOfElement(thirdParameter));
+            commonMasks.nullType,
+            inference.getGuaranteedTypeOfElement(thirdParameter));
       });
 }
 
diff --git a/tests/compiler/dart2js/container_mask_equal_test.dart b/tests/compiler/dart2js/container_mask_equal_test.dart
index 96834e9..e56167b 100644
--- a/tests/compiler/dart2js/container_mask_equal_test.dart
+++ b/tests/compiler/dart2js/container_mask_equal_test.dart
@@ -30,7 +30,7 @@
   asyncTest(() async {
     var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
     var compiler = result.compiler;
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     var element = compiler.mainApp.find('a');
     var mask1 = typesInferrer.getReturnTypeOfElement(element);
diff --git a/tests/compiler/dart2js/dictionary_types_test.dart b/tests/compiler/dart2js/dictionary_types_test.dart
index f173c23..afe9db5 100644
--- a/tests/compiler/dart2js/dictionary_types_test.dart
+++ b/tests/compiler/dart2js/dictionary_types_test.dart
@@ -137,14 +137,14 @@
       memorySourceFiles: SOURCES,
       beforeRun: (compiler) { compiler.stopAfterTypeInference = !createCode; });
   var compiler = result.compiler;
-  var typesTask = compiler.typesTask;
-  var typesInferrer = typesTask.typesInferrer;
+  var commonMasks = compiler.commonMasks;
+  var typesInferrer = compiler.globalInference.typesInferrer;
   getType(String name) {
     var element = findElement(compiler, name);
     return typesInferrer.getTypeOfElement(element);
   }
   if (!createCode) {
-    checker(typesTask, getType, compiler);
+    checker(commonMasks, getType, compiler);
   } else {
     var element = compiler.mainFunction;
     var code = compiler.backend.getGeneratedCode(element);
diff --git a/tests/compiler/dart2js/expect_annotations_test.dart b/tests/compiler/dart2js/expect_annotations_test.dart
index 7c4605a..8e2abcd 100644
--- a/tests/compiler/dart2js/expect_annotations_test.dart
+++ b/tests/compiler/dart2js/expect_annotations_test.dart
@@ -94,17 +94,18 @@
            expectAssumeDynamic,
            backend.annotations.assumeDynamic(method),
            "Unexpected annotation of @AssumeDynamic on '$method'.");
-       TypesInferrer inferrer = compiler.typesTask.typesInferrer;
+       TypesInferrer inferrer = compiler.globalInference.typesInferrer;
        if (expectTrustTypeAnnotations && expectedParameterType != null) {
          testTypeMatch(method, expectedParameterType, expectedReturnType,
              inferrer);
        } else if (expectAssumeDynamic) {
-         testTypeMatch(method, compiler.typesTask.dynamicType, null, inferrer);
+         testTypeMatch(method,
+             compiler.commonMasks.dynamicType, null, inferrer);
        }
     }
 
-    TypeMask jsStringType = compiler.typesTask.stringType;
-    TypeMask jsIntType = compiler.typesTask.intType;
+    TypeMask jsStringType = compiler.commonMasks.stringType;
+    TypeMask jsIntType = compiler.commonMasks.intType;
     TypeMask coreStringType = new TypeMask.subtype(
         compiler.coreClasses.stringClass, compiler.world);
 
diff --git a/tests/compiler/dart2js/field_type_simple_inferer_test.dart b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
index 534a7ed..ad28778 100644
--- a/tests/compiler/dart2js/field_type_simple_inferer_test.dart
+++ b/tests/compiler/dart2js/field_type_simple_inferer_test.dart
@@ -483,8 +483,8 @@
       name,
       disableInlining,
       (compiler, field) {
-        TypeMask type = f(compiler.typesTask);
-        var inferrer = compiler.typesTask.typesInferrer;
+        TypeMask type = f(compiler.commonMasks);
+        var inferrer = compiler.globalInference.typesInferrer;
         TypeMask inferredType =
             simplify(inferrer.getTypeOfElement(field), inferrer.compiler);
         Expect.equals(type, inferredType, test);
diff --git a/tests/compiler/dart2js/issue13354_test.dart b/tests/compiler/dart2js/issue13354_test.dart
index c275bfe..14d26ca 100644
--- a/tests/compiler/dart2js/issue13354_test.dart
+++ b/tests/compiler/dart2js/issue13354_test.dart
@@ -29,8 +29,8 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -47,10 +47,10 @@
           simplify(typesInferrer.getReturnTypeOfElement(element), compiler));
     }
 
-    checkReturn('bar', typesTask.uint31Type);
-    checkReturn('baz', typesTask.functionType);
+    checkReturn('bar', commonMasks.uint31Type);
+    checkReturn('baz', commonMasks.functionType);
 
-    checkReturnInClass('A', 'foo', typesTask.uint31Type);
-    checkReturnInClass('B', 'foo', typesTask.functionType);
+    checkReturnInClass('A', 'foo', commonMasks.uint31Type);
+    checkReturnInClass('B', 'foo', commonMasks.functionType);
   }));
 }
diff --git a/tests/compiler/dart2js/kernel/empty_test.dart b/tests/compiler/dart2js/kernel/empty_test.dart
new file mode 100644
index 0000000..f3fe00b
--- /dev/null
+++ b/tests/compiler/dart2js/kernel/empty_test.dart
@@ -0,0 +1,9 @@
+import 'package:test/test.dart';
+
+import 'helper.dart' show check;
+
+main() {
+  test('compile empty function', () {
+    return check("main() {}");
+  });
+}
diff --git a/tests/compiler/dart2js/kernel/helper.dart b/tests/compiler/dart2js/kernel/helper.dart
new file mode 100644
index 0000000..37dfe15
--- /dev/null
+++ b/tests/compiler/dart2js/kernel/helper.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:compiler/src/compiler.dart' show Compiler;
+import 'package:compiler/src/elements/elements.dart' show Element;
+import 'package:compiler/src/js_backend/backend.dart' as js show JavaScriptBackend;
+import 'package:compiler/src/commandline_options.dart' show Flags;
+import 'package:test/test.dart';
+
+import '../memory_compiler.dart';
+
+Future<String> compile(String code, {String entry: 'main',
+    bool useKernel: true}) async {
+  List<String> options = <String>[
+    Flags.disableTypeInference,
+    Flags.disableInlining,
+  ];
+  if (useKernel) options.add(Flags.useKernel);
+
+  if (entry != 'main' && !code.contains('main')) {
+    code = "$code\n\nmain() => $entry;";
+  }
+  CompilationResult result = await runCompiler(
+      memorySourceFiles: {'main.dart': code},
+      options: options);
+  expect(result.isSuccess, isTrue);
+  Compiler compiler = result.compiler;
+  Element element = compiler.mainApp.find(entry);
+  js.JavaScriptBackend backend = compiler.backend;
+  return backend.getGeneratedCode(element);
+}
+
+Future check(String code, {String entry: 'main'}) async {
+  var original = await compile(code, entry: entry, useKernel: false);
+  var kernel = await compile(code, entry: entry, useKernel: true);
+  expect(original, kernel);
+}
diff --git a/tests/compiler/dart2js/list_tracer2_test.dart b/tests/compiler/dart2js/list_tracer2_test.dart
index 76ee4b5a..040ffb2 100644
--- a/tests/compiler/dart2js/list_tracer2_test.dart
+++ b/tests/compiler/dart2js/list_tracer2_test.dart
@@ -25,7 +25,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkType(String name, type) {
       var element = findElement(compiler, name);
@@ -33,6 +33,6 @@
       Expect.equals(type, simplify(mask.elementType, compiler), name);
     }
 
-    checkType('myList', compiler.typesTask.uint31Type);
+    checkType('myList', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/list_tracer3_test.dart b/tests/compiler/dart2js/list_tracer3_test.dart
index 3ef45d2..ee0bc06 100644
--- a/tests/compiler/dart2js/list_tracer3_test.dart
+++ b/tests/compiler/dart2js/list_tracer3_test.dart
@@ -28,7 +28,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkType(String name, type) {
       var element = findElement(compiler, name);
diff --git a/tests/compiler/dart2js/list_tracer_test.dart b/tests/compiler/dart2js/list_tracer_test.dart
index 24d7ae0..cff8c88 100644
--- a/tests/compiler/dart2js/list_tracer_test.dart
+++ b/tests/compiler/dart2js/list_tracer_test.dart
@@ -199,8 +199,8 @@
   var compiler = compilerFor(generateTest(allocation), uri,
       expectedErrors: 0, expectedWarnings: 1);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkType(String name, type) {
       var element = findElement(compiler, name);
@@ -209,31 +209,31 @@
       Expect.equals(type, simplify(mask.elementType, compiler), name);
     }
 
-    checkType('listInField', typesTask.numType);
-    checkType('listPassedToMethod', typesTask.numType);
-    checkType('listReturnedFromMethod', typesTask.numType);
-    checkType('listUsedWithCascade', typesTask.numType);
-    checkType('listUsedInClosure', typesTask.numType);
-    checkType('listPassedToSelector', typesTask.numType);
-    checkType('listReturnedFromSelector', typesTask.numType);
-    checkType('listUsedWithAddAndInsert', typesTask.numType);
-    checkType('listUsedWithConstraint', typesTask.positiveIntType);
-    checkType('listEscapingFromSetter', typesTask.numType);
-    checkType('listUsedInLocal', typesTask.numType);
-    checkType('listEscapingInSetterValue', typesTask.numType);
-    checkType('listEscapingInIndex', typesTask.numType);
-    checkType('listEscapingInIndexSet', typesTask.uint31Type);
-    checkType('listEscapingTwiceInIndexSet', typesTask.numType);
-    checkType('listSetInNonFinalField', typesTask.numType);
-    checkType('listWithChangedLength', typesTask.uint31Type.nullable());
+    checkType('listInField', commonMasks.numType);
+    checkType('listPassedToMethod', commonMasks.numType);
+    checkType('listReturnedFromMethod', commonMasks.numType);
+    checkType('listUsedWithCascade', commonMasks.numType);
+    checkType('listUsedInClosure', commonMasks.numType);
+    checkType('listPassedToSelector', commonMasks.numType);
+    checkType('listReturnedFromSelector', commonMasks.numType);
+    checkType('listUsedWithAddAndInsert', commonMasks.numType);
+    checkType('listUsedWithConstraint', commonMasks.positiveIntType);
+    checkType('listEscapingFromSetter', commonMasks.numType);
+    checkType('listUsedInLocal', commonMasks.numType);
+    checkType('listEscapingInSetterValue', commonMasks.numType);
+    checkType('listEscapingInIndex', commonMasks.numType);
+    checkType('listEscapingInIndexSet', commonMasks.uint31Type);
+    checkType('listEscapingTwiceInIndexSet', commonMasks.numType);
+    checkType('listSetInNonFinalField', commonMasks.numType);
+    checkType('listWithChangedLength', commonMasks.uint31Type.nullable());
 
-    checkType('listPassedToClosure', typesTask.dynamicType);
-    checkType('listReturnedFromClosure', typesTask.dynamicType);
-    checkType('listUsedWithNonOkSelector', typesTask.dynamicType);
-    checkType('listPassedAsOptionalParameter', typesTask.numType);
-    checkType('listPassedAsNamedParameter', typesTask.numType);
-    checkType('listStoredInList', typesTask.uint31Type);
-    checkType('listStoredInListButEscapes', typesTask.dynamicType);
+    checkType('listPassedToClosure', commonMasks.dynamicType);
+    checkType('listReturnedFromClosure', commonMasks.dynamicType);
+    checkType('listUsedWithNonOkSelector', commonMasks.dynamicType);
+    checkType('listPassedAsOptionalParameter', commonMasks.numType);
+    checkType('listPassedAsNamedParameter', commonMasks.numType);
+    checkType('listStoredInList', commonMasks.uint31Type);
+    checkType('listStoredInListButEscapes', commonMasks.dynamicType);
 
     if (!allocation.contains('filled')) {
       checkType('listUnset', new TypeMask.nonNullEmpty());
diff --git a/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart b/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
index 77aa786..594d26f 100644
--- a/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
+++ b/tests/compiler/dart2js/list_tracer_typed_data_length_test.dart
@@ -29,7 +29,7 @@
   asyncTest(() async {
     CompilationResult result = await runCompiler(memorySourceFiles: TEST);
     Compiler compiler = result.compiler;
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkType(String name, type, length) {
       var element = findElement(compiler, name);
@@ -40,7 +40,7 @@
       Expect.equals(container.length, length);
     }
 
-    checkType('myList', compiler.typesTask.numType, 42);
-    checkType('myOtherList', compiler.typesTask.uint31Type, 32);
+    checkType('myList', compiler.commonMasks.numType, 42);
+    checkType('myOtherList', compiler.commonMasks.uint31Type, 32);
   });
 }
diff --git a/tests/compiler/dart2js/map_tracer_const_test.dart b/tests/compiler/dart2js/map_tracer_const_test.dart
index 1365349..1bb6ca0 100644
--- a/tests/compiler/dart2js/map_tracer_const_test.dart
+++ b/tests/compiler/dart2js/map_tracer_const_test.dart
@@ -34,10 +34,10 @@
       expectedErrors: 0, expectedWarnings: 0);
   compiler.stopAfterTypeInference = true;
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, 'closure');
     var mask = typesInferrer.getReturnTypeOfElement(element);
-    Expect.equals(typesTask.numType, simplify(mask, compiler));
+    Expect.equals(commonMasks.numType, simplify(mask, compiler));
   }));
 }
diff --git a/tests/compiler/dart2js/map_tracer_keys_test.dart b/tests/compiler/dart2js/map_tracer_keys_test.dart
index da6f9fa..4f429d3 100644
--- a/tests/compiler/dart2js/map_tracer_keys_test.dart
+++ b/tests/compiler/dart2js/map_tracer_keys_test.dart
@@ -55,21 +55,21 @@
   var compiler = compilerFor(generateTest(key, value, initial), uri,
       expectedErrors: 0, expectedWarnings: 0);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var aDoubleType =
         typesInferrer.getTypeOfElement(findElement(compiler, 'aDouble'));
     var aListType =
         typesInferrer.getTypeOfElement(findElement(compiler, 'aList'));
 
-    Expect.equals(aDoubleType, typesTask.doubleType);
+    Expect.equals(aDoubleType, commonMasks.doubleType);
     Expect.isTrue(aListType is ContainerTypeMask);
     ContainerTypeMask container = aListType;
     TypeMask elementType = container.elementType;
     if (bail) {
-      Expect.equals(elementType, typesTask.dynamicType);
+      Expect.equals(elementType, commonMasks.dynamicType);
     } else {
-      Expect.equals(elementType, typesTask.uint31Type);
+      Expect.equals(elementType, commonMasks.uint31Type);
     }
   }));
 }
diff --git a/tests/compiler/dart2js/map_tracer_test.dart b/tests/compiler/dart2js/map_tracer_test.dart
index d7aa366..1f313da 100644
--- a/tests/compiler/dart2js/map_tracer_test.dart
+++ b/tests/compiler/dart2js/map_tracer_test.dart
@@ -217,8 +217,8 @@
   var classWorld = compiler.world;
   asyncTest(() => compiler.run(uri).then((_) {
     var keyType, valueType;
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var emptyType = new TypeMask.nonNullEmpty();
     var aKeyType =
         typesInferrer.getTypeOfElement(findElement(compiler, 'aKey'));
@@ -244,39 +244,40 @@
     V(TypeMask other) =>
         simplify(valueType.union(other, classWorld), compiler).nullable();
 
-    checkType('mapInField', K(aKeyType), V(typesTask.numType));
-    checkType('mapPassedToMethod', K(aKeyType), V(typesTask.numType));
-    checkType('mapReturnedFromMethod', K(aKeyType), V(typesTask.numType));
-    checkType('mapUsedWithCascade', K(aKeyType), V(typesTask.numType));
-    checkType('mapUsedInClosure', K(aKeyType), V(typesTask.numType));
-    checkType('mapPassedToSelector', K(aKeyType), V(typesTask.numType));
-    checkType('mapReturnedFromSelector', K(aKeyType), V(typesTask.numType));
-    checkType('mapUsedWithConstraint', K(aKeyType), V(typesTask.uint31Type));
-    checkType('mapEscapingFromSetter', K(aKeyType), V(typesTask.numType));
-    checkType('mapUsedInLocal', K(aKeyType), V(typesTask.numType));
-    checkType('mapEscapingInSetterValue', K(aKeyType), V(typesTask.numType));
-    checkType('mapEscapingInIndex', K(aKeyType), V(typesTask.numType));
-    checkType('mapEscapingInIndexSet', K(aKeyType), V(typesTask.uint31Type));
-    checkType('mapEscapingTwiceInIndexSet', K(aKeyType), V(typesTask.numType));
-    checkType('mapSetInNonFinalField', K(aKeyType), V(typesTask.numType));
+    checkType('mapInField', K(aKeyType), V(commonMasks.numType));
+    checkType('mapPassedToMethod', K(aKeyType), V(commonMasks.numType));
+    checkType('mapReturnedFromMethod', K(aKeyType), V(commonMasks.numType));
+    checkType('mapUsedWithCascade', K(aKeyType), V(commonMasks.numType));
+    checkType('mapUsedInClosure', K(aKeyType), V(commonMasks.numType));
+    checkType('mapPassedToSelector', K(aKeyType), V(commonMasks.numType));
+    checkType('mapReturnedFromSelector', K(aKeyType), V(commonMasks.numType));
+    checkType('mapUsedWithConstraint', K(aKeyType), V(commonMasks.uint31Type));
+    checkType('mapEscapingFromSetter', K(aKeyType), V(commonMasks.numType));
+    checkType('mapUsedInLocal', K(aKeyType), V(commonMasks.numType));
+    checkType('mapEscapingInSetterValue', K(aKeyType), V(commonMasks.numType));
+    checkType('mapEscapingInIndex', K(aKeyType), V(commonMasks.numType));
+    checkType('mapEscapingInIndexSet', K(aKeyType), V(commonMasks.uint31Type));
+    checkType('mapEscapingTwiceInIndexSet',
+        K(aKeyType), V(commonMasks.numType));
+    checkType('mapSetInNonFinalField', K(aKeyType), V(commonMasks.numType));
 
-    checkType('mapPassedToClosure', K(typesTask.dynamicType),
-                                    V(typesTask.dynamicType));
-    checkType('mapReturnedFromClosure', K(typesTask.dynamicType),
-                                        V(typesTask.dynamicType));
-    checkType('mapUsedWithNonOkSelector', K(typesTask.dynamicType),
-                                          V(typesTask.dynamicType));
+    checkType('mapPassedToClosure', K(commonMasks.dynamicType),
+                                    V(commonMasks.dynamicType));
+    checkType('mapReturnedFromClosure', K(commonMasks.dynamicType),
+                                        V(commonMasks.dynamicType));
+    checkType('mapUsedWithNonOkSelector', K(commonMasks.dynamicType),
+                                          V(commonMasks.dynamicType));
     checkType('mapPassedAsOptionalParameter', K(aKeyType),
-                                              V(typesTask.numType));
+                                              V(commonMasks.numType));
     checkType('mapPassedAsNamedParameter', K(aKeyType),
-                                           V(typesTask.numType));
+                                           V(commonMasks.numType));
     checkType('mapStoredInList', K(aKeyType),
-                                 V(typesTask.uint31Type));
-    checkType('mapStoredInListButEscapes', K(typesTask.dynamicType),
-                                           V(typesTask.dynamicType));
-    checkType('mapStoredInMap', K(aKeyType), V(typesTask.uint31Type));
-    checkType('mapStoredInMapButEscapes', K(typesTask.dynamicType),
-                                          V(typesTask.dynamicType));
+                                 V(commonMasks.uint31Type));
+    checkType('mapStoredInListButEscapes', K(commonMasks.dynamicType),
+                                           V(commonMasks.dynamicType));
+    checkType('mapStoredInMap', K(aKeyType), V(commonMasks.uint31Type));
+    checkType('mapStoredInMapButEscapes', K(commonMasks.dynamicType),
+                                          V(commonMasks.dynamicType));
 
     checkType('mapUnset', K(emptyType), V(emptyType));
     checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType));
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 411257b..baa0102 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -120,7 +120,11 @@
   if (packageRoot == null &&
       packageConfig == null &&
       packagesDiscoveryProvider == null) {
-    packageRoot = Uri.base.resolve(Platform.packageRoot);
+    if (Platform.packageRoot != null) {
+      packageRoot = Uri.base.resolve(Platform.packageRoot);
+    } else if (Platform.packageConfig != null) {
+      packageConfig = Uri.base.resolve(Platform.packageConfig);
+    }
   }
 
   MemorySourceFileProvider provider;
@@ -159,8 +163,6 @@
           packagesDiscoveryProvider: packagesDiscoveryProvider));
 
   if (cachedCompiler != null) {
-    compiler.coreLibrary =
-        cachedCompiler.libraryLoader.lookupLibrary(Uri.parse('dart:core'));
     compiler.types = cachedCompiler.types.copy(compiler.resolution);
     Map copiedLibraries = {};
     cachedCompiler.libraryLoader.libraries.forEach((library) {
@@ -183,12 +185,6 @@
 
     compiler.backend.constantCompilerTask.copyConstantValues(
         cachedCompiler.backend.constantCompilerTask);
-    compiler.mirrorSystemClass = cachedCompiler.mirrorSystemClass;
-    compiler.mirrorsUsedClass = cachedCompiler.mirrorsUsedClass;
-    compiler.mirrorSystemGetNameFunction =
-        cachedCompiler.mirrorSystemGetNameFunction;
-    compiler.mirrorsUsedConstructor = cachedCompiler.mirrorsUsedConstructor;
-    compiler.deferredLibraryClass = cachedCompiler.deferredLibraryClass;
 
     Iterable cachedTreeElements =
         cachedCompiler.enqueuer.resolution.processedElements;
@@ -209,7 +205,7 @@
     cachedCompiler.resolver = null;
     cachedCompiler.closureToClassMapper = null;
     cachedCompiler.checker = null;
-    cachedCompiler.typesTask = null;
+    cachedCompiler.globalInference = null;
     cachedCompiler.backend = null;
     // Don't null out the enqueuer as it prevents us from using cachedCompiler
     // more than once.
diff --git a/tests/compiler/dart2js/minimal_resolution_test.dart b/tests/compiler/dart2js/minimal_resolution_test.dart
index ddc1eaf..8c35948 100644
--- a/tests/compiler/dart2js/minimal_resolution_test.dart
+++ b/tests/compiler/dart2js/minimal_resolution_test.dart
@@ -15,7 +15,7 @@
 main() {
   asyncTest(() async {
     await analyze('main() {}');
-    await analyze('main() => proxy;', proxyConstant: true);
+    await analyze('main() => proxy;', proxyConstantComputed: true);
     await analyze('@deprecated main() {}');
     await analyze('@deprecated main() => deprecated;', deprecatedClass: true);
     await analyze('main() => deprecated;', deprecatedClass: true);
@@ -34,18 +34,21 @@
 }
 
 analyze(String code,
-    {bool proxyConstant: false, bool deprecatedClass: false}) async {
+    {bool proxyConstantComputed: false, bool deprecatedClass: false}) async {
   CompilationResult result = await runCompiler(
       memorySourceFiles: {'main.dart': code}, options: ['--analyze-only']);
   Expect.isTrue(result.isSuccess);
   Compiler compiler = result.compiler;
-  Expect.equals(proxyConstant, compiler.resolution.proxyConstant != null,
+  Expect.equals(proxyConstantComputed,
+      compiler.resolution.wasProxyConstantComputedTestingOnly,
       "Unexpected computation of proxy constant.");
 
   checkInstantiated(
-      compiler, compiler.coreLibrary.find('_Proxy'), proxyConstant);
+      compiler, compiler.commonElements.coreLibrary.find('_Proxy'),
+      proxyConstantComputed);
   checkInstantiated(
-      compiler, compiler.coreLibrary.find('Deprecated'), deprecatedClass);
+      compiler, compiler.commonElements.coreLibrary.find('Deprecated'),
+      deprecatedClass);
 
   LibraryElement jsHelperLibrary =
       compiler.libraryLoader.lookupLibrary(BackendHelpers.DART_JS_HELPER);
diff --git a/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart b/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
index 20411b7..09de1ab 100644
--- a/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
+++ b/tests/compiler/dart2js/mirror_final_field_inferrer2_test.dart
@@ -28,9 +28,9 @@
     var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
     var compiler = result.compiler;
     var element = findElement(compiler, 'field');
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
-    Expect.equals(typesTask.uint31Type,
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
+    Expect.equals(commonMasks.uint31Type,
                   simplify(typesInferrer.getTypeOfElement(element), compiler),
                   'field');
   });
diff --git a/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart b/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
index 54252ec..7663d51 100644
--- a/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
+++ b/tests/compiler/dart2js/mirror_final_field_inferrer_test.dart
@@ -28,9 +28,9 @@
     var result = await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
     var compiler = result.compiler;
     var element = findElement(compiler, 'field');
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
-    Expect.equals(typesTask.uint31Type,
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
+    Expect.equals(commonMasks.uint31Type,
                   simplify(typesInferrer.getTypeOfElement(element), compiler),
                   'field');
   });
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 24c42e4..3e64f10 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -166,7 +166,6 @@
   'ConstantMap': 'class ConstantMap<K, V> {}',
   'ConstantProtoMap': 'class ConstantProtoMap<K, V> {}',
   'ConstantStringMap': 'class ConstantStringMap<K, V> {}',
-  'copyTypeArguments': 'copyTypeArguments(source, target) {}',
   'createInvocationMirror': 'createInvocationMirror(a0, a1, a2, a3, a4, a5) {}',
   'createRuntimeType': 'createRuntimeType(a) {}',
   'doubleTypeCast': 'doubleTypeCast(value) {}',
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 607fae9..00245a7 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -130,9 +130,9 @@
   var compiler = await applyPatch(
       "external test();",
       "@patch test() { return 'string'; } ");
-  ensure(compiler, "test", compiler.coreLibrary.find,
+  ensure(compiler, "test", compiler.commonElements.coreLibrary.find,
          expectIsPatched: true, checkHasBody: true);
-  ensure(compiler, "test", compiler.coreLibrary.patch.find,
+  ensure(compiler, "test", compiler.commonElements.coreLibrary.patch.find,
          expectIsPatch: true, checkHasBody: true);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
@@ -152,10 +152,12 @@
       const _b = 1;
       @patch @_b test() {}
       """);
-  Element origin = ensure(compiler, "test", compiler.coreLibrary.find,
-         expectIsPatched: true, checkHasBody: true);
-  Element patch = ensure(compiler, "test", compiler.coreLibrary.patch.find,
-         expectIsPatch: true, checkHasBody: true);
+  Element origin = ensure(compiler, "test",
+      compiler.commonElements.coreLibrary.find,
+      expectIsPatched: true, checkHasBody: true);
+  Element patch = ensure(compiler, "test",
+      compiler.commonElements.coreLibrary.patch.find,
+      expectIsPatch: true, checkHasBody: true);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
   Expect.isTrue(collector.warnings.isEmpty,
@@ -193,13 +195,13 @@
         $patchSource
         """,
         patchVersion: patchVersion).then((compiler) {
-        Element origin =
-            ensure(compiler, "test", compiler.coreLibrary.find,
-                 expectIsPatched: expectIsPatched, checkHasBody: true);
+        Element origin = ensure(compiler, "test",
+            compiler.commonElements.coreLibrary.find,
+            expectIsPatched: expectIsPatched, checkHasBody: true);
         if (expectIsPatched) {
-          AstElement patch =
-              ensure(compiler, "test", compiler.coreLibrary.patch.find,
-                  expectIsPatch: true, checkHasBody: true);
+          AstElement patch = ensure(compiler, "test",
+              compiler.commonElements.coreLibrary.patch.find,
+              expectIsPatch: true, checkHasBody: true);
           Expect.equals(origin.patch, patch);
           Expect.equals(patch.origin, origin);
           Expect.equals(patchText, patch.node.toString());
@@ -249,11 +251,11 @@
         @patch Class();
       }
       """);
-  var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
+  var classOrigin = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   classOrigin.ensureResolved(compiler.resolution);
-  var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-                          expectIsPatch: true);
+  var classPatch = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.patch.find, expectIsPatch: true);
 
   Expect.equals(classPatch, classOrigin.patch);
   Expect.equals(classOrigin, classPatch.origin);
@@ -289,12 +291,12 @@
         @patch Class._(x, y) { print('$x,$y'); }
       }
       """);
-  var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
-                           expectIsPatched: true);
+  var classOrigin = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   classOrigin.ensureResolved(compiler.resolution);
 
-  var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
-                          expectIsPatch: true);
+  var classPatch = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.patch.find, expectIsPatch: true);
 
   Expect.equals(classOrigin, classPatch.origin);
   Expect.equals(classPatch, classOrigin.patch);
@@ -334,10 +336,10 @@
         @patch String toString() => 'string';
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
-  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+  ensure(compiler, "Class", compiler.commonElements.coreLibrary.patch.find,
          expectIsPatch: true);
 
   ensure(compiler, "toString", container.lookupLocalMember,
@@ -364,8 +366,8 @@
         @patch int get field => 5;
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
   ensure(compiler,
          "field",
@@ -398,10 +400,10 @@
       @patch class Class {
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
-  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+  ensure(compiler, "Class", compiler.commonElements.coreLibrary.patch.find,
          expectIsPatch: true);
 
   ensure(compiler, "regular", container.lookupLocalMember,
@@ -427,10 +429,10 @@
         void _injected() {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
-  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+  ensure(compiler, "Class", compiler.commonElements.coreLibrary.patch.find,
          expectIsPatch: true);
 
   ensure(compiler, "_injected", container.lookupLocalMember,
@@ -456,10 +458,10 @@
         void injected() {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
-  ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+  ensure(compiler, "Class", compiler.commonElements.coreLibrary.patch.find,
          expectIsPatch: true);
 
   ensure(compiler, "injected", container.lookupLocalMember,
@@ -483,11 +485,11 @@
       "int _function() => 5;");
   ensure(compiler,
          "_function",
-         compiler.coreLibrary.find,
+         compiler.commonElements.coreLibrary.find,
          expectIsFound: false);
   ensure(compiler,
          "_function",
-         compiler.coreLibrary.patch.find,
+         compiler.commonElements.coreLibrary.patch.find,
          checkHasBody: true, expectIsRegular: true);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
@@ -503,11 +505,11 @@
       "int function() => 5;");
   ensure(compiler,
          "function",
-         compiler.coreLibrary.find,
+         compiler.commonElements.coreLibrary.find,
          expectIsFound: false);
   ensure(compiler,
          "function",
-         compiler.coreLibrary.patch.find,
+         compiler.commonElements.coreLibrary.patch.find,
          checkHasBody: true, expectIsRegular: true);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
@@ -552,8 +554,8 @@
         @patch void method11({int str}) {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.ensureResolved(compiler.resolution);
   container.parseNode(compiler.parsingContext);
   DiagnosticCollector collector = compiler.diagnosticCollector;
@@ -607,7 +609,8 @@
       """
       // @patch void foo() {}
       """);
-  var function = ensure(compiler, "foo", compiler.coreLibrary.find);
+  var function = ensure(compiler, "foo",
+      compiler.commonElements.coreLibrary.find);
   compiler.resolver.resolve(function);
   DiagnosticCollector collector = compiler.diagnosticCollector;
   Expect.isTrue(collector.warnings.isEmpty,
@@ -633,8 +636,8 @@
         // @patch void foo() {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
   DiagnosticCollector collector = compiler.diagnosticCollector;
   collector.clear();
@@ -659,8 +662,8 @@
       """
       @patch class A {}
       """);
-  ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
-                            expectIsPatched: true);
+  ClassElement cls = ensure(compiler, "A",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   ClassElement patch = cls.patch;
   Expect.isTrue(cls != patch);
   Expect.isTrue(cls.isSubclassOf(patch));
@@ -694,8 +697,8 @@
         @patch void foo() {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
   DiagnosticCollector collector = compiler.diagnosticCollector;
 
@@ -715,7 +718,7 @@
       """
       @patch var foo;
       """);
-  ensure(compiler, "foo", compiler.coreLibrary.find);
+  ensure(compiler, "foo", compiler.commonElements.coreLibrary.find);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
   Expect.isTrue(collector.warnings.isEmpty,
@@ -734,7 +737,7 @@
       """
       @patch get foo => 0;
       """);
-  ensure(compiler, "foo", compiler.coreLibrary.find);
+  ensure(compiler, "foo", compiler.commonElements.coreLibrary.find);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
   Expect.isTrue(collector.warnings.isEmpty,
@@ -782,8 +785,8 @@
         @patch void foo() {}
       }
       """);
-  var container = ensure(compiler, "Class", compiler.coreLibrary.find,
-                         expectIsPatched: true);
+  var container = ensure(compiler, "Class",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   container.parseNode(compiler.parsingContext);
 
   DiagnosticCollector collector = compiler.diagnosticCollector;
@@ -944,8 +947,8 @@
   World world = compiler.world;
   world.populate();
 
-  ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
-                            expectIsPatched: true);
+  ClassElement cls = ensure(compiler, "A",
+      compiler.commonElements.coreLibrary.find, expectIsPatched: true);
   cls.ensureResolved(compiler.resolution);
 
   ensure(compiler, "method", cls.patch.lookupLocalMember,
@@ -978,7 +981,7 @@
 
   // Check that the declaration method in the declaration class is a target
   // for a typed selector on a subclass.
-  cls = ensure(compiler, "B", compiler.coreLibrary.find);
+  cls = ensure(compiler, "B", compiler.commonElements.coreLibrary.find);
   cls.ensureResolved(compiler.resolution);
   typeMask = new TypeMask.exact(cls, world);
   Expect.isTrue(selector.applies(method, world));
@@ -1054,8 +1057,8 @@
 
   var compiler = await applyPatch(origin, patch, analyzeAll: true,
                  analyzeOnly: true, runCompiler: true);
-  ClassElement clsA = compiler.coreLibrary.find("A");
-  ClassElement clsB = compiler.coreLibrary.find("B");
+  ClassElement clsA = compiler.commonElements.coreLibrary.find("A");
+  ClassElement clsB = compiler.commonElements.coreLibrary.find("B");
 
   ConstructorElement forward = clsA.lookupConstructor("forward");
   ConstructorElement target = forward.effectiveTarget;
diff --git a/tests/compiler/dart2js/serialization/test_data.dart b/tests/compiler/dart2js/serialization/test_data.dart
index 065bf66..9038877 100644
--- a/tests/compiler/dart2js/serialization/test_data.dart
+++ b/tests/compiler/dart2js/serialization/test_data.dart
@@ -693,6 +693,75 @@
 main() => a;
 ''',
   }),
+
+  const Test('Erroneous constructor', const {},
+      preserializedSourceFiles: const {
+    'main.dart': '''
+main() => new Null();
+'''}),
+
+  const Test('Metadata on imports', const {},
+      preserializedSourceFiles: const {
+        'main.dart': '''
+@deprecated
+import 'main.dart';
+
+main() {}
+'''}),
+
+  const Test('Metadata on exports', const {},
+      preserializedSourceFiles: const {
+        'main.dart': '''
+@deprecated
+export 'main.dart';
+
+main() {}
+'''}),
+
+  const Test('Metadata on part tags', const {},
+      preserializedSourceFiles: const {
+        'main.dart': '''
+library main;
+
+@deprecated
+part 'a.dart';
+
+main() {}
+'''},
+      unserializedSourceFiles: const {
+        'a.dart': '''
+part of main;
+'''}),
+
+  const Test('Metadata on part-of tags', const {},
+      preserializedSourceFiles: const {
+        'main.dart': '''
+library main;
+
+part 'a.dart';
+
+main() {}
+'''},
+      unserializedSourceFiles: const {
+        'a.dart': '''
+@deprecated
+part of main;
+'''}),
+
+  const Test('Ambiguous elements', const {},
+      preserializedSourceFiles: const {
+        'main.dart': '''
+import 'a.dart';
+import 'b.dart';
+
+main() => new foo();
+''',
+        'a.dart': '''
+var foo;
+''',
+        'b.dart': '''
+var foo;
+''',}),
 ];
 
 class Test {
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 306392c..e5a11bc 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -97,7 +97,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -111,13 +111,13 @@
     checkReturn('returnDyn1', subclassOfInterceptor);
     checkReturn('returnDyn2', subclassOfInterceptor);
     checkReturn('returnDyn3', subclassOfInterceptor);
-    checkReturn('returnDyn4', compiler.typesTask.dynamicType.nonNullable());
-    checkReturn('returnDyn5', compiler.typesTask.dynamicType.nonNullable());
-    checkReturn('returnDyn6', compiler.typesTask.dynamicType.nonNullable());
+    checkReturn('returnDyn4', compiler.commonMasks.dynamicType.nonNullable());
+    checkReturn('returnDyn5', compiler.commonMasks.dynamicType.nonNullable());
+    checkReturn('returnDyn6', compiler.commonMasks.dynamicType.nonNullable());
     checkReturn('returnDyn7', subclassOfInterceptor);
     checkReturn('returnDyn7b', subclassOfInterceptor);
     checkReturn('returnDyn8', subclassOfInterceptor);
     checkReturn('returnDyn9', subclassOfInterceptor);
-    checkReturn('returnString', compiler.typesTask.stringType);
+    checkReturn('returnString', compiler.commonMasks.stringType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_callers_test.dart b/tests/compiler/dart2js/simple_inferrer_callers_test.dart
index 2242d55..b4f4c2a 100644
--- a/tests/compiler/dart2js/simple_inferrer_callers_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_callers_test.dart
@@ -29,15 +29,15 @@
 // Create our own type inferrer to avoid clearing out the internal
 // data structures.
 class MyInferrer extends TypeGraphInferrer {
-  MyInferrer(compiler) : super(compiler);
+  MyInferrer(compiler, commonMasks) : super(compiler, commonMasks);
   clear() {}
 }
 
 void main() {
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
-  var inferrer = new MyInferrer(compiler);
-  compiler.typesTask.typesInferrer = inferrer;
+  var inferrer = new MyInferrer(compiler, compiler.commonMasks);
+  compiler.globalInference.typesInferrer = inferrer;
   asyncTest(() => compiler.run(uri).then((_) {
     var mainElement = findElement(compiler, 'main');
     var classA = findElement(compiler, 'A');
diff --git a/tests/compiler/dart2js/simple_inferrer_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
index 9eaefa2..e9fc517 100644
--- a/tests/compiler/dart2js/simple_inferrer_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
@@ -119,7 +119,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -128,16 +128,16 @@
           name);
     }
 
-    checkReturn('returnInt1', compiler.typesTask.uint31Type);
-    checkReturn('returnInt2', compiler.typesTask.uint31Type);
-    checkReturn('returnInt3', compiler.typesTask.uint31Type);
-    checkReturn('returnInt4', compiler.typesTask.uint31Type);
-    checkReturn('returnIntOrNull', compiler.typesTask.uint31Type.nullable());
+    checkReturn('returnInt1', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt2', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt3', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt4', compiler.commonMasks.uint31Type);
+    checkReturn('returnIntOrNull', compiler.commonMasks.uint31Type.nullable());
 
-    checkReturn('returnDyn1', compiler.typesTask.dynamicType.nonNullable());
-    checkReturn('returnDyn2', compiler.typesTask.dynamicType.nonNullable());
-    checkReturn('returnDyn3', compiler.typesTask.dynamicType.nonNullable());
-    checkReturn('returnNum1', compiler.typesTask.numType);
+    checkReturn('returnDyn1', compiler.commonMasks.dynamicType.nonNullable());
+    checkReturn('returnDyn2', compiler.commonMasks.dynamicType.nonNullable());
+    checkReturn('returnDyn3', compiler.commonMasks.dynamicType.nonNullable());
+    checkReturn('returnNum1', compiler.commonMasks.numType);
 
     checkReturnInClass(String className, String methodName, type) {
       var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
index c12eff3..4ea68a9 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
@@ -29,7 +29,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -38,7 +38,7 @@
           name);
     }
 
-    checkReturn('method', compiler.typesTask.numType);
-    checkReturn('returnNum', compiler.typesTask.numType);
+    checkReturn('method', compiler.commonMasks.numType);
+    checkReturn('returnNum', compiler.commonMasks.numType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
index 225d204..f7f759e 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
@@ -29,7 +29,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkArgument(String functionName, type) {
       var functionElement = findElement(compiler, functionName);
@@ -40,6 +40,6 @@
           functionName);
     }
 
-    checkArgument('method', compiler.typesTask.uint31Type);
+    checkArgument('method', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
index b52e17a..8728cfb 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
@@ -30,7 +30,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkArgument(String functionName, type) {
       var functionElement = findElement(compiler, functionName);
@@ -41,7 +41,7 @@
           functionName);
     }
 
-    checkArgument('method', compiler.typesTask.numType);
-    checkArgument('returnNum', compiler.typesTask.numType);
+    checkArgument('method', compiler.commonMasks.numType);
+    checkArgument('returnNum', compiler.commonMasks.numType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
index 9b550e5..834ccd7 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
@@ -30,7 +30,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkArgument(String functionName, type) {
       var functionElement = findElement(compiler, functionName);
@@ -41,6 +41,6 @@
           functionName);
     }
 
-    checkArgument('method', compiler.typesTask.numType);
+    checkArgument('method', compiler.commonMasks.numType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure_default_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure_default_test.dart
index f83a4d9..33fdc43 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure_default_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure_default_test.dart
@@ -45,7 +45,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkArgument(String functionName, type) {
       var functionElement = findElement(compiler, functionName);
@@ -67,18 +67,18 @@
           functionName);
     }
 
-    checkArgument('foo1', compiler.typesTask.functionType);   /// 01: ok
-    checkArgument('foo2', compiler.typesTask.functionType);   /// 02: ok
-    checkArgument('foo3', compiler.typesTask.functionType);   /// 03: ok
-    checkArgument('foo4', compiler.typesTask.functionType);   /// 04: ok
-    checkArgument('foo5', compiler.typesTask.dynamicType);    /// 05: ok
-    checkArgument('foo6', compiler.typesTask.dynamicType);    /// 06: ok
+    checkArgument('foo1', compiler.commonMasks.functionType);   /// 01: ok
+    checkArgument('foo2', compiler.commonMasks.functionType);   /// 02: ok
+    checkArgument('foo3', compiler.commonMasks.functionType);   /// 03: ok
+    checkArgument('foo4', compiler.commonMasks.functionType);   /// 04: ok
+    checkArgument('foo5', compiler.commonMasks.dynamicType);    /// 05: ok
+    checkArgument('foo6', compiler.commonMasks.dynamicType);    /// 06: ok
 
-    checkArgument('defaultFn1', compiler.typesTask.uint31Type);   /// 07: ok
-    checkArgument('defaultFn2', compiler.typesTask.uint31Type);   /// 08: ok
-    checkArgument('defaultFn3', compiler.typesTask.uint31Type);   /// 09: ok
-    checkArgument('defaultFn4', compiler.typesTask.uint31Type);   /// 10: ok
-    checkArgument('defaultFn5', compiler.typesTask.uint31Type);   /// 11: ok
-    checkArgument('defaultFn6', compiler.typesTask.uint31Type);   /// 12: ok
+    checkArgument('defaultFn1', compiler.commonMasks.uint31Type);   /// 07: ok
+    checkArgument('defaultFn2', compiler.commonMasks.uint31Type);   /// 08: ok
+    checkArgument('defaultFn3', compiler.commonMasks.uint31Type);   /// 09: ok
+    checkArgument('defaultFn4', compiler.commonMasks.uint31Type);   /// 10: ok
+    checkArgument('defaultFn5', compiler.commonMasks.uint31Type);   /// 11: ok
+    checkArgument('defaultFn6', compiler.commonMasks.uint31Type);   /// 12: ok
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
index 3f3056c..411269f 100644
--- a/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
@@ -38,7 +38,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -47,10 +47,10 @@
           name);
     }
 
-    checkReturn('method1', compiler.typesTask.uint31Type);
-    checkReturn('returnInt1', compiler.typesTask.uint31Type);
+    checkReturn('method1', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt1', compiler.commonMasks.uint31Type);
 
-    checkReturn('method2', compiler.typesTask.uint31Type);
-    checkReturn('returnInt2', compiler.typesTask.uint31Type);
+    checkReturn('method2', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt2', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
index 8147f14..1045fb3 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field2_test.dart
@@ -28,7 +28,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkFieldTypeInClass(String className, String fieldName, type) {
       var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
index ffb277d..0d25714 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field3_test.dart
@@ -27,7 +27,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkFieldTypeInClass(String className, String fieldName, type) {
       var cls = findElement(compiler, className);
diff --git a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
index 1b74240..a3a2516 100644
--- a/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_final_field_test.dart
@@ -31,7 +31,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkFieldTypeInClass(String className, String fieldName, type) {
       var cls = findElement(compiler, className);
@@ -40,11 +40,11 @@
           simplify(typesInferrer.getTypeOfElement(element), compiler));
     }
 
-    checkFieldTypeInClass('A', 'intField', compiler.typesTask.uint31Type);
+    checkFieldTypeInClass('A', 'intField', compiler.commonMasks.uint31Type);
     checkFieldTypeInClass('A', 'giveUpField1',
         findTypeMask(compiler, 'Interceptor', 'nonNullSubclass'));
     checkFieldTypeInClass('A', 'giveUpField2',
-        compiler.typesTask.dynamicType.nonNullable());
-    checkFieldTypeInClass('A', 'fieldParameter', compiler.typesTask.uint31Type);
+        compiler.commonMasks.dynamicType.nonNullable());
+    checkFieldTypeInClass('A', 'fieldParameter', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
index 07156f81..cd5715d 100644
--- a/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
@@ -29,7 +29,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkArgument(String functionName, type) {
       var functionElement = findElement(compiler, functionName);
@@ -40,6 +40,6 @@
           functionName);
     }
 
-    checkArgument('method', compiler.typesTask.uint31Type);
+    checkArgument('method', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
index bfae05a..06bb0c4 100644
--- a/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
@@ -38,7 +38,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -47,10 +47,10 @@
           name);
     }
 
-    checkReturn('method1', compiler.typesTask.uint31Type);
-    checkReturn('returnInt1', compiler.typesTask.uint31Type);
+    checkReturn('method1', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt1', compiler.commonMasks.uint31Type);
 
-    checkReturn('method2', compiler.typesTask.uint31Type);
-    checkReturn('returnInt2', compiler.typesTask.uint31Type);
+    checkReturn('method2', compiler.commonMasks.uint31Type);
+    checkReturn('returnInt2', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
index 3dc9993..0e6a7a3 100644
--- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -164,7 +164,7 @@
   Uri uri = new Uri(scheme: 'source');
 
   checkReturn(MockCompiler compiler, String name, type) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, name);
     Expect.equals(
         type,
@@ -174,50 +174,51 @@
 
   var compiler1 = compilerFor(TEST1, uri);
   asyncTest(() => compiler1.run(uri).then((_) {
-    checkReturn(compiler1, 'test1', compiler1.typesTask.uint31Type);
+    checkReturn(compiler1, 'test1', compiler1.commonMasks.uint31Type);
     checkReturn(compiler1, 'test2',
-        compiler1.typesTask.dynamicType.nonNullable());
-    checkReturn(compiler1, 'test3', compiler1.typesTask.uint31Type);
-    checkReturn(compiler1, 'test4', compiler1.typesTask.mapType);
+        compiler1.commonMasks.dynamicType.nonNullable());
+    checkReturn(compiler1, 'test3', compiler1.commonMasks.uint31Type);
+    checkReturn(compiler1, 'test4', compiler1.commonMasks.mapType);
     checkReturn(compiler1, 'test5',
-        compiler1.typesTask.dynamicType.nonNullable());
+        compiler1.commonMasks.dynamicType.nonNullable());
     checkReturn(compiler1, 'test6',
-        compiler1.typesTask.dynamicType.nonNullable());
+        compiler1.commonMasks.dynamicType.nonNullable());
   }));
 
   var compiler2 = compilerFor(TEST2, uri);
   asyncTest(() => compiler2.run(uri).then((_) {
-    checkReturn(compiler2, 'test1', compiler2.typesTask.mapType.nonNullable());
-    checkReturn(compiler2, 'test2', compiler2.typesTask.mapType);
-    checkReturn(compiler2, 'test3', compiler2.typesTask.mapType);
-    checkReturn(compiler2, 'test4', compiler2.typesTask.mapType);
-    checkReturn(compiler2, 'test5', compiler2.typesTask.mapType);
+    checkReturn(compiler2, 'test1',
+        compiler2.commonMasks.mapType.nonNullable());
+    checkReturn(compiler2, 'test2', compiler2.commonMasks.mapType);
+    checkReturn(compiler2, 'test3', compiler2.commonMasks.mapType);
+    checkReturn(compiler2, 'test4', compiler2.commonMasks.mapType);
+    checkReturn(compiler2, 'test5', compiler2.commonMasks.mapType);
 
-    checkReturn(compiler2, 'test6', compiler2.typesTask.numType);
-    checkReturn(compiler2, 'test7', compiler2.typesTask.uint31Type);
-    checkReturn(compiler2, 'test8', compiler2.typesTask.uint31Type);
-    checkReturn(compiler2, 'test9', compiler2.typesTask.uint31Type);
-    checkReturn(compiler2, 'test10', compiler2.typesTask.numType);
-    checkReturn(compiler2, 'test11', compiler2.typesTask.doubleType);
+    checkReturn(compiler2, 'test6', compiler2.commonMasks.numType);
+    checkReturn(compiler2, 'test7', compiler2.commonMasks.uint31Type);
+    checkReturn(compiler2, 'test8', compiler2.commonMasks.uint31Type);
+    checkReturn(compiler2, 'test9', compiler2.commonMasks.uint31Type);
+    checkReturn(compiler2, 'test10', compiler2.commonMasks.numType);
+    checkReturn(compiler2, 'test11', compiler2.commonMasks.doubleType);
   }));
 
   var compiler3 = compilerFor(TEST3, uri);
   asyncTest(() => compiler3.run(uri).then((_) {
     checkReturn(compiler3, 'test1', const TypeMask.nonNullEmpty());
-    checkReturn(compiler3, 'test2', compiler3.typesTask.mapType);
-    checkReturn(compiler3, 'test3', compiler3.typesTask.mapType);
-    checkReturn(compiler3, 'test4', compiler3.typesTask.mapType);
-    checkReturn(compiler3, 'test5', compiler3.typesTask.mapType);
-    checkReturn(compiler3, 'test6', compiler3.typesTask.mapType);
+    checkReturn(compiler3, 'test2', compiler3.commonMasks.mapType);
+    checkReturn(compiler3, 'test3', compiler3.commonMasks.mapType);
+    checkReturn(compiler3, 'test4', compiler3.commonMasks.mapType);
+    checkReturn(compiler3, 'test5', compiler3.commonMasks.mapType);
+    checkReturn(compiler3, 'test6', compiler3.commonMasks.mapType);
   }));
 
   var compiler4 = compilerFor(TEST4, uri);
   asyncTest(() => compiler4.run(uri).then((_) {
     checkReturn(compiler4, 'test1', const TypeMask.nonNullEmpty());
-    checkReturn(compiler4, 'test2', compiler4.typesTask.mapType);
-    checkReturn(compiler4, 'test3', compiler4.typesTask.mapType);
-    checkReturn(compiler4, 'test4', compiler4.typesTask.mapType);
-    checkReturn(compiler4, 'test5', compiler4.typesTask.mapType);
-    checkReturn(compiler4, 'test6', compiler4.typesTask.mapType);
+    checkReturn(compiler4, 'test2', compiler4.commonMasks.mapType);
+    checkReturn(compiler4, 'test3', compiler4.commonMasks.mapType);
+    checkReturn(compiler4, 'test4', compiler4.commonMasks.mapType);
+    checkReturn(compiler4, 'test5', compiler4.commonMasks.mapType);
+    checkReturn(compiler4, 'test6', compiler4.commonMasks.mapType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
index f55f609..2a94b4b 100644
--- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -66,8 +66,8 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturnInClass(String className, String methodName, type) {
       var cls = findElement(compiler, className);
@@ -80,18 +80,18 @@
     var subclassOfInterceptor =
         findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
 
-    checkReturnInClass('A', 'returnNum1', typesTask.numType);
-    checkReturnInClass('A', 'returnNum2', typesTask.numType);
-    checkReturnInClass('A', 'returnNum3', typesTask.numType);
-    checkReturnInClass('A', 'returnNum4', typesTask.numType);
+    checkReturnInClass('A', 'returnNum1', commonMasks.numType);
+    checkReturnInClass('A', 'returnNum2', commonMasks.numType);
+    checkReturnInClass('A', 'returnNum3', commonMasks.numType);
+    checkReturnInClass('A', 'returnNum4', commonMasks.numType);
     checkReturnInClass('A', 'returnEmpty1', const TypeMask.nonNullEmpty());
     checkReturnInClass('A', 'returnEmpty2', const TypeMask.nonNullEmpty());
     checkReturnInClass('A', 'returnDynamic1', subclassOfInterceptor);
     checkReturnInClass('A', 'returnDynamic2', subclassOfInterceptor);
     checkReturnInClass('A', 'returnEmpty3', const TypeMask.nonNullEmpty());
 
-    checkReturnInClass('B', 'returnString1', typesTask.stringType);
-    checkReturnInClass('B', 'returnString2', typesTask.stringType);
+    checkReturnInClass('B', 'returnString1', commonMasks.stringType);
+    checkReturnInClass('B', 'returnString2', commonMasks.stringType);
     checkReturnInClass('B', 'returnDynamic1', const TypeMask.nonNullEmpty());
     checkReturnInClass('B', 'returnDynamic2', const TypeMask.nonNullEmpty());
     checkReturnInClass('B', 'returnDynamic3', const TypeMask.nonNullEmpty());
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index d552ccd..295784a 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -727,8 +727,8 @@
   var compiler = compilerFor(TEST, uri);
   compiler.diagnosticHandler = createHandler(compiler, TEST);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var world = compiler.world;
 
     checkReturn(String name, type) {
@@ -741,20 +741,20 @@
     var interceptorType =
         findTypeMask(compiler, 'Interceptor', 'nonNullSubclass');
 
-    checkReturn('returnNum1', typesTask.numType);
-    checkReturn('returnNum2', typesTask.numType);
-    checkReturn('returnInt1', typesTask.uint31Type);
-    checkReturn('returnInt2', typesTask.uint31Type);
-    checkReturn('returnDouble', typesTask.doubleType);
+    checkReturn('returnNum1', commonMasks.numType);
+    checkReturn('returnNum2', commonMasks.numType);
+    checkReturn('returnInt1', commonMasks.uint31Type);
+    checkReturn('returnInt2', commonMasks.uint31Type);
+    checkReturn('returnDouble', commonMasks.doubleType);
     checkReturn('returnGiveUp', interceptorType);
-    checkReturn('returnInt5', typesTask.uint32Type);  // uint31+uint31->uint32
-    checkReturn('returnInt6', typesTask.uint32Type);  // uint31+uint31->uint32
-    checkReturn('returnIntOrNull', typesTask.uint31Type.nullable());
-    checkReturn('returnInt3', typesTask.uint31Type);
-    checkReturn('returnDynamic', typesTask.dynamicType);
-    checkReturn('returnInt4', typesTask.uint31Type);
-    checkReturn('returnInt7', typesTask.positiveIntType);
-    checkReturn('returnInt8', typesTask.positiveIntType);
+    checkReturn('returnInt5', commonMasks.uint32Type);  // uint31+uint31->uint32
+    checkReturn('returnInt6', commonMasks.uint32Type);  // uint31+uint31->uint32
+    checkReturn('returnIntOrNull', commonMasks.uint31Type.nullable());
+    checkReturn('returnInt3', commonMasks.uint31Type);
+    checkReturn('returnDynamic', commonMasks.dynamicType);
+    checkReturn('returnInt4', commonMasks.uint31Type);
+    checkReturn('returnInt7', commonMasks.positiveIntType);
+    checkReturn('returnInt8', commonMasks.positiveIntType);
     checkReturn('returnEmpty1', const TypeMask.nonNullEmpty());
     checkReturn('returnEmpty2', const TypeMask.nonNullEmpty());
     TypeMask intType = new TypeMask.nonNullSubtype(
@@ -764,61 +764,61 @@
     checkReturn('testIsCheck3', intType.nullable());
     checkReturn('testIsCheck4', intType);
     checkReturn('testIsCheck5', intType);
-    checkReturn('testIsCheck6', typesTask.dynamicType);
+    checkReturn('testIsCheck6', commonMasks.dynamicType);
     checkReturn('testIsCheck7', intType);
-    checkReturn('testIsCheck8', typesTask.dynamicType);
+    checkReturn('testIsCheck8', commonMasks.dynamicType);
     checkReturn('testIsCheck9', intType);
-    checkReturn('testIsCheck10', typesTask.dynamicType);
+    checkReturn('testIsCheck10', commonMasks.dynamicType);
     checkReturn('testIsCheck11', intType);
-    checkReturn('testIsCheck12', typesTask.dynamicType);
+    checkReturn('testIsCheck12', commonMasks.dynamicType);
     checkReturn('testIsCheck13', intType);
-    checkReturn('testIsCheck14', typesTask.dynamicType);
+    checkReturn('testIsCheck14', commonMasks.dynamicType);
     checkReturn('testIsCheck15', intType);
-    checkReturn('testIsCheck16', typesTask.dynamicType);
+    checkReturn('testIsCheck16', commonMasks.dynamicType);
     checkReturn('testIsCheck17', intType);
-    checkReturn('testIsCheck18', typesTask.dynamicType);
-    checkReturn('testIsCheck19', typesTask.dynamicType);
+    checkReturn('testIsCheck18', commonMasks.dynamicType);
+    checkReturn('testIsCheck19', commonMasks.dynamicType);
     checkReturn('testIsCheck20', interceptorType);
-    checkReturn('testIsCheck21', typesTask.dynamicType);
-    checkReturn('testIsCheck22', typesTask.dynamicType);
+    checkReturn('testIsCheck21', commonMasks.dynamicType);
+    checkReturn('testIsCheck22', commonMasks.dynamicType);
     checkReturn('testIsCheck23', intType);
     checkReturn('testIsCheck24', intType);
-    checkReturn('testIsCheck25', typesTask.dynamicType);
+    checkReturn('testIsCheck25', commonMasks.dynamicType);
     checkReturn('testIsCheck26', intType);
     checkReturn('testIsCheck27', intType);
-    checkReturn('testIsCheck28', typesTask.dynamicType);
-    checkReturn('testIsCheck29', typesTask.dynamicType);
-    checkReturn('testIf1', typesTask.uint31Type.nullable());
-    checkReturn('testIf2', typesTask.uint31Type.nullable());
+    checkReturn('testIsCheck28', commonMasks.dynamicType);
+    checkReturn('testIsCheck29', commonMasks.dynamicType);
+    checkReturn('testIf1', commonMasks.uint31Type.nullable());
+    checkReturn('testIf2', commonMasks.uint31Type.nullable());
     checkReturn('returnAsString', new TypeMask.subtype(
         compiler.coreClasses.stringClass, compiler.world));
-    checkReturn('returnIntAsNum', typesTask.uint31Type);
-    checkReturn('returnAsTypedef', typesTask.functionType.nullable());
-    checkReturn('returnTopLevelGetter', typesTask.uint31Type);
-    checkReturn('testDeadCode', typesTask.uint31Type);
-    checkReturn('testLabeledIf', typesTask.uint31Type.nullable());
+    checkReturn('returnIntAsNum', commonMasks.uint31Type);
+    checkReturn('returnAsTypedef', commonMasks.functionType.nullable());
+    checkReturn('returnTopLevelGetter', commonMasks.uint31Type);
+    checkReturn('testDeadCode', commonMasks.uint31Type);
+    checkReturn('testLabeledIf', commonMasks.uint31Type.nullable());
     checkReturn('testSwitch1', simplify(
-        typesTask.intType
-            .union(typesTask.doubleType, compiler.world)
+        commonMasks.intType
+            .union(commonMasks.doubleType, compiler.world)
             .nullable(),
         compiler));
-    checkReturn('testSwitch2', typesTask.uint31Type);
+    checkReturn('testSwitch2', commonMasks.uint31Type);
     checkReturn('testSwitch3', interceptorType.nullable());
-    checkReturn('testSwitch4', typesTask.uint31Type);
-    checkReturn('testSwitch5', typesTask.uint31Type);
+    checkReturn('testSwitch4', commonMasks.uint31Type);
+    checkReturn('testSwitch5', commonMasks.uint31Type);
     checkReturn('testContinue1', interceptorType.nullable());
     checkReturn('testBreak1', interceptorType.nullable());
     checkReturn('testContinue2', interceptorType.nullable());
-    checkReturn('testBreak2', typesTask.uint32Type.nullable());
-    checkReturn('testReturnElementOfConstList1', typesTask.uint31Type);
-    checkReturn('testReturnElementOfConstList2', typesTask.uint31Type);
-    checkReturn('testReturnItselfOrInt', typesTask.uint31Type);
-    checkReturn('testReturnInvokeDynamicGetter', typesTask.dynamicType);
+    checkReturn('testBreak2', commonMasks.uint32Type.nullable());
+    checkReturn('testReturnElementOfConstList1', commonMasks.uint31Type);
+    checkReturn('testReturnElementOfConstList2', commonMasks.uint31Type);
+    checkReturn('testReturnItselfOrInt', commonMasks.uint31Type);
+    checkReturn('testReturnInvokeDynamicGetter', commonMasks.dynamicType);
 
-    checkReturn('testDoWhile1', typesTask.stringType);
-    checkReturn('testDoWhile2', typesTask.nullType);
-    checkReturn('testDoWhile3', typesTask.uint31Type);
-    checkReturn('testDoWhile4', typesTask.numType);
+    checkReturn('testDoWhile1', commonMasks.stringType);
+    checkReturn('testDoWhile2', commonMasks.nullType);
+    checkReturn('testDoWhile3', commonMasks.uint31Type);
+    checkReturn('testDoWhile4', commonMasks.numType);
 
     checkReturnInClass(String className, String methodName, type) {
       var cls = findElement(compiler, className);
@@ -828,30 +828,30 @@
           '$className:$methodName');
     }
 
-    checkReturnInClass('A', 'returnInt1', typesTask.uint32Type);
-    checkReturnInClass('A', 'returnInt2', typesTask.uint32Type);
-    checkReturnInClass('A', 'returnInt3', typesTask.uint32Type);
-    checkReturnInClass('A', 'returnInt4', typesTask.uint32Type);
-    checkReturnInClass('A', 'returnInt5', typesTask.uint32Type);
-    checkReturnInClass('A', 'returnInt6', typesTask.uint32Type);
+    checkReturnInClass('A', 'returnInt1', commonMasks.uint32Type);
+    checkReturnInClass('A', 'returnInt2', commonMasks.uint32Type);
+    checkReturnInClass('A', 'returnInt3', commonMasks.uint32Type);
+    checkReturnInClass('A', 'returnInt4', commonMasks.uint32Type);
+    checkReturnInClass('A', 'returnInt5', commonMasks.uint32Type);
+    checkReturnInClass('A', 'returnInt6', commonMasks.uint32Type);
     checkReturnInClass('A', '==', interceptorType);
 
-    checkReturnInClass('B', 'returnInt1', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt2', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt3', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt4', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt5', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt6', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt7', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt8', typesTask.uint32Type);
-    checkReturnInClass('B', 'returnInt9', typesTask.uint31Type);
+    checkReturnInClass('B', 'returnInt1', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt2', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt3', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt4', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt5', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt6', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt7', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt8', commonMasks.uint32Type);
+    checkReturnInClass('B', 'returnInt9', commonMasks.uint31Type);
 
-    checkReturnInClass('C', 'returnInt1', typesTask.positiveIntType);
-    checkReturnInClass('C', 'returnInt2', typesTask.positiveIntType);
-    checkReturnInClass('C', 'returnInt3', typesTask.positiveIntType);
-    checkReturnInClass('C', 'returnInt4', typesTask.positiveIntType);
-    checkReturnInClass('C', 'returnInt5', typesTask.positiveIntType);
-    checkReturnInClass('C', 'returnInt6', typesTask.positiveIntType);
+    checkReturnInClass('C', 'returnInt1', commonMasks.positiveIntType);
+    checkReturnInClass('C', 'returnInt2', commonMasks.positiveIntType);
+    checkReturnInClass('C', 'returnInt3', commonMasks.positiveIntType);
+    checkReturnInClass('C', 'returnInt4', commonMasks.positiveIntType);
+    checkReturnInClass('C', 'returnInt5', commonMasks.positiveIntType);
+    checkReturnInClass('C', 'returnInt6', commonMasks.positiveIntType);
 
     checkFactoryConstructor(String className, String factoryName) {
       var cls = findElement(compiler, className);
@@ -861,18 +861,18 @@
     }
     checkFactoryConstructor('A', '');
 
-    checkReturn('testCascade1', typesTask.growableListType);
+    checkReturn('testCascade1', commonMasks.growableListType);
     checkReturn('testCascade2', new TypeMask.nonNullExact(
         findElement(compiler, 'CascadeHelper'), world));
-    checkReturn('testSpecialization1', typesTask.numType);
-    checkReturn('testSpecialization2', typesTask.dynamicType);
-    checkReturn('testSpecialization3', typesTask.uint31Type.nullable());
-    checkReturn('testReturnNull1', typesTask.nullType);
-    checkReturn('testReturnNull2', typesTask.nullType);
-    checkReturn('testReturnNull3', typesTask.dynamicType);
-    checkReturn('testReturnNull4', typesTask.nullType);
-    checkReturn('testReturnNull5', typesTask.nullType);
-    checkReturn('testReturnNull6', typesTask.dynamicType);
-    checkReturn('testReturnNotEquals', typesTask.boolType);
+    checkReturn('testSpecialization1', commonMasks.numType);
+    checkReturn('testSpecialization2', commonMasks.dynamicType);
+    checkReturn('testSpecialization3', commonMasks.uint31Type.nullable());
+    checkReturn('testReturnNull1', commonMasks.nullType);
+    checkReturn('testReturnNull2', commonMasks.nullType);
+    checkReturn('testReturnNull3', commonMasks.dynamicType);
+    checkReturn('testReturnNull4', commonMasks.nullType);
+    checkReturn('testReturnNull5', commonMasks.nullType);
+    checkReturn('testReturnNull6', commonMasks.dynamicType);
+    checkReturn('testReturnNotEquals', commonMasks.boolType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
index 82ec5ed..fb8ea18 100644
--- a/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_try_catch_test.dart
@@ -169,8 +169,8 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturn(String name, type) {
       var element = findElement(compiler, name);
@@ -178,11 +178,11 @@
           simplify(typesInferrer.getReturnTypeOfElement(element), compiler));
     }
 
-    checkReturn('returnInt1', typesTask.uint31Type);
-    checkReturn('returnInt2', typesTask.uint31Type);
-    checkReturn('returnInt3', typesTask.uint31Type);
-    checkReturn('returnInt4', typesTask.uint31Type);
-    checkReturn('returnInt5', typesTask.uint31Type);
+    checkReturn('returnInt1', commonMasks.uint31Type);
+    checkReturn('returnInt2', commonMasks.uint31Type);
+    checkReturn('returnInt3', commonMasks.uint31Type);
+    checkReturn('returnInt4', commonMasks.uint31Type);
+    checkReturn('returnInt5', commonMasks.uint31Type);
     checkReturn('returnInt6', new TypeMask.nonNullSubtype(
         compiler.coreClasses.intClass, compiler.world));
 
@@ -194,6 +194,6 @@
     checkReturn('returnDyn3', subclassOfInterceptor);
     checkReturn('returnDyn4', subclassOfInterceptor);
     checkReturn('returnDyn5', subclassOfInterceptor);
-    checkReturn('returnDyn6', typesTask.dynamicType);
+    checkReturn('returnDyn6', commonMasks.dynamicType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
index 6cf04020..96cce73 100644
--- a/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_unregister_call_test.dart
@@ -33,7 +33,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     checkReturnInClass(String className, String methodName, type) {
       var cls = findElement(compiler, className);
@@ -41,6 +41,6 @@
       Expect.equals(type, typesInferrer.getReturnTypeOfElement(element));
     }
 
-    checkReturnInClass('A', '+', compiler.typesTask.uint31Type);
+    checkReturnInClass('A', '+', compiler.commonMasks.uint31Type);
   }));
 }
diff --git a/tests/compiler/dart2js/trust_type_annotations_test.dart b/tests/compiler/dart2js/trust_type_annotations_test.dart
index f165166..a90d7e5 100644
--- a/tests/compiler/dart2js/trust_type_annotations_test.dart
+++ b/tests/compiler/dart2js/trust_type_annotations_test.dart
@@ -50,7 +50,7 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri, trustTypeAnnotations: true);
   asyncTest(() => compiler.run(uri).then((_) {
-    var typesInferrer = compiler.typesTask.typesInferrer;
+    var typesInferrer = compiler.globalInference.typesInferrer;
 
     ClassElement classA = findElement(compiler, "A");
 
diff --git a/tests/compiler/dart2js/type_combination_test.dart b/tests/compiler/dart2js/type_combination_test.dart
index 3aef5f8..5c72f356 100644
--- a/tests/compiler/dart2js/type_combination_test.dart
+++ b/tests/compiler/dart2js/type_combination_test.dart
@@ -768,7 +768,7 @@
 
     // Grab hold of a supertype for String so we can produce potential
     // string types.
-    patternClass = compiler.coreLibrary.find('Pattern');
+    patternClass = compiler.commonElements.coreLibrary.find('Pattern');
 
     nonPrimitive1 = new TypeMask.nonNullSubtype(
         compiler.coreClasses.mapClass, world);
diff --git a/tests/compiler/dart2js/type_inference6_test.dart b/tests/compiler/dart2js/type_inference6_test.dart
index bfee36c..7eaf0a5 100644
--- a/tests/compiler/dart2js/type_inference6_test.dart
+++ b/tests/compiler/dart2js/type_inference6_test.dart
@@ -24,11 +24,11 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST, uri);
   return compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, "foo");
     var mask = typesInferrer.getReturnTypeOfElement(element);
-    Expect.equals(typesTask.uint31Type, simplify(mask, compiler));
+    Expect.equals(commonMasks.uint31Type, simplify(mask, compiler));
   });
 }
 
diff --git a/tests/compiler/dart2js/type_inference7_test.dart b/tests/compiler/dart2js/type_inference7_test.dart
index 072d42d..af867cc 100644
--- a/tests/compiler/dart2js/type_inference7_test.dart
+++ b/tests/compiler/dart2js/type_inference7_test.dart
@@ -23,19 +23,19 @@
     // Assertions enabled:
     var compiler = compilerFor(TEST, uri, enableUserAssertions: true);
     await compiler.run(uri);
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var foo = findElement(compiler, "foo");
     // Return type is null|bool.
     var mask = typesInferrer.getReturnTypeOfElement(foo);
     Expect.isTrue(mask.isNullable);
-    Expect.equals(typesTask.boolType, simplify(mask.nonNullable(), compiler));
+    Expect.equals(commonMasks.boolType, simplify(mask.nonNullable(), compiler));
     // First parameter is uint31|String|bool.
     var mask1 = typesInferrer.getTypeOfElement(foo.parameters[0]);
     Expect.isTrue(mask1.isUnion);
-    var expectedTypes = new Set.from([typesTask.uint31Type,
-                                      typesTask.stringType,
-                                      typesTask.boolType]);
+    var expectedTypes = new Set.from([commonMasks.uint31Type,
+                                      commonMasks.stringType,
+                                      commonMasks.boolType]);
     for (var typeMask in mask1.disjointMasks) {
       Expect.isFalse(typeMask.isNullable);
       var simpleType = simplify(typeMask, compiler);
@@ -45,15 +45,16 @@
     // Second parameter is bool or null.
     var mask2 = typesInferrer.getTypeOfElement(foo.parameters[1]);
     Expect.isTrue(mask2.isNullable);
-    Expect.equals(typesTask.boolType, simplify(mask2.nonNullable(), compiler));
+    Expect.equals(
+        commonMasks.boolType, simplify(mask2.nonNullable(), compiler));
   }
 
   {
     // Assertions disabled:
     var compiler = compilerFor(TEST, uri, enableUserAssertions: false);
     await compiler.run(uri);
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var foo = findElement(compiler, "foo");
     // Return type is null.
     var mask = typesInferrer.getReturnTypeOfElement(foo);
@@ -62,7 +63,7 @@
     // First parameter is uint31.
     var mask1 = typesInferrer.getTypeOfElement(foo.parameters[0]);
     Expect.isFalse(mask1.isNullable);
-    Expect.equals(typesTask.uint31Type, simplify(mask1, compiler));
+    Expect.equals(commonMasks.uint31Type, simplify(mask1, compiler));
     // Second parameter is null.
     var mask2 = typesInferrer.getTypeOfElement(foo.parameters[1]);
     Expect.isTrue(mask2.isNullable);
diff --git a/tests/compiler/dart2js/type_inference8_test.dart b/tests/compiler/dart2js/type_inference8_test.dart
index 001b1aa..bcae368 100644
--- a/tests/compiler/dart2js/type_inference8_test.dart
+++ b/tests/compiler/dart2js/type_inference8_test.dart
@@ -34,12 +34,12 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST1, uri);
   return compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, "foo");
     var mask = typesInferrer.getReturnTypeOfElement(element);
     var falseType =
-        new ValueTypeMask(typesTask.boolType, new FalseConstantValue());
+        new ValueTypeMask(commonMasks.boolType, new FalseConstantValue());
     // 'foo' should always return false
     Expect.equals(falseType, mask);
     // the argument to 'bar' is always false
@@ -77,17 +77,17 @@
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(TEST2, uri);
   return compiler.run(uri).then((_) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, "foo");
     var mask = typesInferrer.getReturnTypeOfElement(element);
     // Can't infer value for foo's return type, it could be either true or false
-    Expect.identical(typesTask.boolType, mask);
+    Expect.identical(commonMasks.boolType, mask);
     var bar = findElement(compiler, "bar");
     var barArg = bar.parameters.first;
     var barArgMask = typesInferrer.getTypeOfElement(barArg);
     // The argument to bar should have the same type as the return type of foo
-    Expect.identical(typesTask.boolType, barArgMask);
+    Expect.identical(commonMasks.boolType, barArgMask);
     var barCode = compiler.backend.getGeneratedCode(bar);
     Expect.isTrue(barCode.contains('"bbb"'));
     // Still must output the print for "aaa"
diff --git a/tests/compiler/dart2js/type_inference_switch_test.dart b/tests/compiler/dart2js/type_inference_switch_test.dart
index 795684c..bac1abd 100644
--- a/tests/compiler/dart2js/type_inference_switch_test.dart
+++ b/tests/compiler/dart2js/type_inference_switch_test.dart
@@ -135,15 +135,15 @@
   var compiler = compilerFor(test, uri);
 
   checkTypeOf(String name, TypeMask type) {
-    var typesTask = compiler.typesTask;
-    var typesInferrer = typesTask.typesInferrer;
+    var commonMasks = compiler.commonMasks;
+    var typesInferrer = compiler.globalInference.typesInferrer;
     var element = findElement(compiler, name);
     var mask = typesInferrer.getReturnTypeOfElement(element);
     Expect.equals(type, simplify(mask, compiler));
   }
 
   return compiler.run(uri).then((_) {
-    checker(compiler.typesTask, checkTypeOf);
+    checker(compiler.commonMasks, checkTypeOf);
   });
 }
 
diff --git a/tests/corelib/data_resource_test.dart b/tests/corelib/data_resource_test.dart
deleted file mode 100644
index 3b9703e..0000000
--- a/tests/corelib/data_resource_test.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-const sampleText = "Sample text file.";
-
-main() async {
-  var uriEncoded = sampleText.replaceAll(' ', '%20');
-  await testUri("data:application/dart;charset=utf-8,$uriEncoded");
-  // TODO: Support other data: URI formats too.
-  // See: https://github.com/dart-lang/sdk/issues/24030
-  // await testUri("data:text/plain;charset=utf-8,$uriEncoded");
-  var base64Encoded = "U2FtcGxlIHRleHQgZmlsZS4=";
-  // await testUri("data:application/dart;charset=utf-8;base64,$base64Encoded");
-  // await testUri("data:text/plain;charset=utf-8;base64,$base64Encoded");
-}
-
-testUri(uriText) async {
-  var resource = new Resource(uriText);
-
-  if (resource.uri != Uri.parse(uriText)) {
-    throw "uriText: Incorrect URI: ${resource.uri}";
-  }
-
-  var text = await resource.readAsString();
-  if (text != sampleText) {
-    throw "uriText: Incorrect reading of text file: $text";
-  }
-
-  var bytes = await resource.readAsBytes();
-  if (!compareBytes(bytes, sampleText.codeUnits)) {
-    throw "uriText: Incorrect reading of bytes: $bytes";
-  }
-
-  var streamBytes = [];
-  await for (var byteSlice in resource.openRead()) {
-    streamBytes.addAll(byteSlice);
-  }
-  if (!compareBytes(streamBytes, sampleText.codeUnits)) {
-    throw "uriText: Incorrect reading of bytes: $bytes";
-  }
-}
-
-/// Checks that [bytes] and [expectedBytes] have the same contents.
-bool compareBytes(bytes, expectedBytes) {
-  if (bytes.length != expectedBytes.length) return false;
-  for (int i = 0; i < expectedBytes.length; i++) {
-    if (bytes[i] != expectedBytes[i]) return false;
-  }
-  return true;
-}
diff --git a/tests/corelib/file_resource_test.dart b/tests/corelib/file_resource_test.dart
deleted file mode 100644
index c9da8f7..0000000
--- a/tests/corelib/file_resource_test.dart
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-
-const sampleText = "Sample text file.";
-
-main() async {
-  var file = await createFile();
-  var uri = new Uri.file(file.path);
-
-  var resource = new Resource(uri.toString());
-
-  if (resource.uri != uri) {
-    throw "Incorrect URI: ${resource.uri}";
-  }
-
-  var text = await resource.readAsString();
-  if (text != sampleText) {
-    throw "Incorrect reading of text file: $text";
-  }
-
-  var bytes = await resource.readAsBytes();
-  if (!compareBytes(bytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  var streamBytes = [];
-  await for (var byteSlice in resource.openRead()) {
-    streamBytes.addAll(byteSlice);
-  }
-  if (!compareBytes(streamBytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  await deleteFile(file);
-}
-
-/// Checks that [bytes] and [expectedBytes] have the same contents.
-bool compareBytes(bytes, expectedBytes) {
-  if (bytes.length != expectedBytes.length) return false;
-  for (int i = 0; i < expectedBytes.length; i++) {
-    if (bytes[i] != expectedBytes[i]) return false;
-  }
-  return true;
-}
-
-createFile() async {
-  var tempDir = await Directory.systemTemp.createTemp("sample");
-  var filePath = tempDir.path + Platform.pathSeparator + "sample.txt";
-  var file = new File(filePath);
-  await file.create();
-  await file.writeAsString(sampleText);
-  return file;
-}
-
-deleteFile(File file) async {
-  // Removes the file and the temporary directory it's in.
-  var parentDir = new Directory(file.path.substring(0,
-                                file.path.lastIndexOf(Platform.pathSeparator)));
-  await parentDir.delete(recursive: true);
-}
diff --git a/tests/corelib/http_resource_test.dart b/tests/corelib/http_resource_test.dart
deleted file mode 100644
index 815fe9b..0000000
--- a/tests/corelib/http_resource_test.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:io";
-
-const sampleText = "Sample text file.";
-
-main() async {
-  var server = await startServer();
-  var uriText = "http://localhost:${server.port}/sample.txt?query#fragment";
-  var resource = new Resource(uriText);
-
-  if (resource.uri != Uri.parse(uriText)) {
-    throw "Incorrect URI: ${resource.uri}";
-  }
-
-  var text = await resource.readAsString();
-  if (text != sampleText) {
-    throw "Incorrect reading of text file: $text";
-  }
-
-  var bytes = await resource.readAsBytes();
-  if (!compareBytes(bytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  var streamBytes = [];
-  await for (var byteSlice in resource.openRead()) {
-    streamBytes.addAll(byteSlice);
-  }
-  if (!compareBytes(streamBytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  await server.close();
-}
-
-/// Checks that [bytes] and [expectedBytes] have the same contents.
-bool compareBytes(bytes, expectedBytes) {
-  if (bytes.length != expectedBytes.length) return false;
-  for (int i = 0; i < expectedBytes.length; i++) {
-    if (bytes[i] != expectedBytes[i]) return false;
-  }
-  return true;
-}
-
-startServer() async {
-  var server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0);
-  var expectedUri = new Uri(path: "/sample.txt", query: "query");
-  server.forEach((request) async {
-    await request.drain();
-    var response = request.response;
-    if (request.uri == expectedUri) {
-      response.write(sampleText);
-    } else {
-      response.write("INCORRECT PATH!: ${request.uri}");
-    }
-    response.close();
-  });
-  return server;
-}
diff --git a/tests/corelib/package_resource_test.dart b/tests/corelib/package_resource_test.dart
deleted file mode 100644
index 767cd8b..0000000
--- a/tests/corelib/package_resource_test.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-const sampleText = "Sample text file.";
-
-main() async {
-  const uriText = "package:package_test_data/resources/sample.txt";
-  const resource = const Resource(uriText);
-
-  if (resource.uri != Uri.parse(uriText)) {
-    throw "Incorrect URI: ${resource.uri}";
-  }
-
-  var text = await resource.readAsString();
-  if (!text.startsWith("Sample text file.")) {
-    throw "Incorrect reading of text file: $text";
-  }
-
-  var bytes = await resource.readAsBytes();
-  if (!compareBytes(bytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  var streamBytes = [];
-  await for (var byteSlice in resource.openRead()) {
-    streamBytes.addAll(byteSlice);
-  }
-  if (!compareBytes(streamBytes, sampleText.codeUnits)) {
-    throw "Incorrect reading of bytes: $bytes";
-  }
-
-  if (!compareBytes(streamBytes, bytes)) {
-    throw "Inconsistent reading of bytes: $bytes / $streamBytes";
-  }
-}
-
-/// Checks that [bytes] starts with [expectedBytes].
-///
-/// The bytes may be longer (because the test file is a text file and its
-/// terminating line ending may be mangled on some platforms).
-bool compareBytes(bytes, expectedBytes) {
-  if (bytes.length < expectedBytes.length) return false;
-  for (int i = 0; i < expectedBytes.length; i++) {
-    if (bytes[i] != expectedBytes[i]) return false;
-  }
-  return true;
-}
diff --git a/tests/html/resource_data.txt b/tests/html/resource_data.txt
deleted file mode 100644
index 37308e5..0000000
--- a/tests/html/resource_data.txt
+++ /dev/null
@@ -1 +0,0 @@
-This file was read by a Resource!
\ No newline at end of file
diff --git a/tests/html/resource_http_test.dart b/tests/html/resource_http_test.dart
deleted file mode 100644
index 042e8b3..0000000
--- a/tests/html/resource_http_test.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library resource_http_test;
-import 'dart:async';
-import 'package:unittest/html_individual_config.dart';
-import 'package:unittest/unittest.dart';
-
-main() {
-  useHtmlIndividualConfiguration();
-  // Cache blocker is a workaround for:
-  // https://code.google.com/p/dart/issues/detail?id=11834
-  var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
-  var url = '/root_dart/tests/html/resource_data.txt?cacheBlock=$cacheBlocker';
-
-  void validateResponse(data) {
-    expect(data, equals('This file was read by a Resource!'));
-  }
-
-  group('resource', () {
-    test('readAsString', () async {
-      Resource r = new Resource(url);
-      var data = await r.readAsString();
-      validateResponse(data);
-    });
-    test('readAsBytes', () async {
-      Resource r = new Resource(url);
-      var data = await r.readAsBytes();
-      validateResponse(new String.fromCharCodes(data));
-    });
-    test('openRead', () async {
-      Resource r = new Resource(url);
-      var bytes = [];
-      await for (var b in r.openRead()) {
-        bytes.addAll(b);
-      }
-      validateResponse(new String.fromCharCodes(bytes));
-    });
-  });
-}
diff --git a/tests/language/assert_initializer_test.dart b/tests/language/assert_initializer_test.dart
new file mode 100644
index 0000000..115403a
--- /dev/null
+++ b/tests/language/assert_initializer_test.dart
@@ -0,0 +1,228 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--assert_initializer
+import "package:expect/expect.dart";
+
+bool assertsEnabled = false;
+
+main() {
+  assert((assertsEnabled = true));
+  runtimeAsserts();  /// none: ok
+
+  // Passing const expressions.
+  const c00 = const AssertArgument.constFirst(true, 0, 1);
+  const c01 = const AssertArgument.constLast(true, 0, 1);
+  const c02 = const AssertArgument.constMiddle(true, 0, 1);
+  const c03 = const AssertArgument.constMulti(true, 0, 1);
+  const c04 = const AssertArgument.constFirstSuper(true, 0, 1);
+  const c05 = const AssertArgument.constLastSuper(true, 0, 1);
+  const c06 = const AssertArgument.constMiddleSuper(true, 0, 1);
+  const c07 = const AssertArgument.constMultiSuper(true, 0, 1);
+
+  const c08 = const AssertCompare.constFirst(1, 2);
+  const c09 = const AssertCompare.constLast(1, 2);
+  const c10 = const AssertCompare.constMiddle(1, 2);
+  const c11 = const AssertCompare.constMulti(1, 2);
+  const c12 = const AssertCompare.constFirstSuper(1, 2);
+  const c13 = const AssertCompare.constLastSuper(1, 2);
+  const c14 = const AssertCompare.constMiddleSuper(1, 2);
+  const c15 = const AssertCompare.constMultiSuper(1, 2);
+
+  // Failing const expressions
+
+  const c = const AssertArgument.constFirst(false, 0, 1);       /// 01: compile-time error
+  const c = const AssertArgument.constLast(false, 0, 1);        /// 02: compile-time error
+  const c = const AssertArgument.constMiddle(false, 0, 1);      /// 03: compile-time error
+  const c = const AssertArgument.constMulti(false, 0, 1);       /// 04: compile-time error
+  const c = const AssertArgument.constFirstSuper(false, 0, 1);  /// 05: compile-time error
+  const c = const AssertArgument.constLastSuper(false, 0, 1);   /// 06: compile-time error
+  const c = const AssertArgument.constMiddleSuper(false, 0, 1); /// 07: compile-time error
+  const c = const AssertArgument.constMultiSuper(false, 0, 1);  /// 08: compile-time error
+
+  const c = const AssertArgument.constFirst("str", 0, 1);       /// 11: compile-time error
+  const c = const AssertArgument.constLast("str", 0, 1);        /// 12: compile-time error
+  const c = const AssertArgument.constMiddle("str", 0, 1);      /// 13: compile-time error
+  const c = const AssertArgument.constMulti("str", 0, 1);       /// 14: compile-time error
+  const c = const AssertArgument.constFirstSuper("str", 0, 1);  /// 15: compile-time error
+  const c = const AssertArgument.constLastSuper("str", 0, 1);   /// 16: compile-time error
+  const c = const AssertArgument.constMiddleSuper("str", 0, 1); /// 17: compile-time error
+  const c = const AssertArgument.constMultiSuper("str", 0, 1);  /// 18: compile-time error
+
+  const c = const AssertCompare.constFirst(3, 2);               /// 21: compile-time error
+  const c = const AssertCompare.constLast(3, 2);                /// 22: compile-time error
+  const c = const AssertCompare.constMiddle(3, 2);              /// 23: compile-time error
+  const c = const AssertCompare.constMulti(3, 2);               /// 24: compile-time error
+  const c = const AssertCompare.constFirstSuper(3, 2);          /// 25: compile-time error
+  const c = const AssertCompare.constLastSuper(3, 2);           /// 26: compile-time error
+  const c = const AssertCompare.constMiddleSuper(3, 2);         /// 27: compile-time error
+  const c = const AssertCompare.constMultiSuper(3, 2);          /// 28: compile-time error
+
+  // Functions not allowed in asserts in const execution.
+  const c = const AssertArgument.constFirst(kTrue, 0, 1);       /// 31: compile-time error
+  const c = const AssertArgument.constLast(kTrue, 0, 1);        /// 32: compile-time error
+  const c = const AssertArgument.constMiddle(kTrue, 0, 1);      /// 33: compile-time error
+  const c = const AssertArgument.constMulti(kTrue, 0, 1);       /// 34: compile-time error
+  const c = const AssertArgument.constFirstSuper(kTrue, 0, 1);  /// 35: compile-time error
+  const c = const AssertArgument.constLastSuper(kTrue, 0, 1);   /// 36: compile-time error
+  const c = const AssertArgument.constMiddleSuper(kTrue, 0, 1); /// 37: compile-time error
+  const c = const AssertArgument.constMultiSuper(kTrue, 0, 1);  /// 38: compile-time error
+
+  const cTrue = const TrickCompare(true);
+  // Value must be integer for potential-const expression to be actually const.
+  const c = const AssertCompare.constFirst(cTrue, 2);           /// 41: compile-time error
+  const c = const AssertCompare.constLast(cTrue, 2);            /// 42: compile-time error
+  const c = const AssertCompare.constMiddle(cTrue, 2);          /// 43: compile-time error
+  const c = const AssertCompare.constMulti(cTrue, 2);           /// 44: compile-time error
+  const c = const AssertCompare.constFirstSuper(cTrue, 2);      /// 45: compile-time error
+  const c = const AssertCompare.constLastSuper(cTrue, 2);       /// 46: compile-time error
+  const c = const AssertCompare.constMiddleSuper(cTrue, 2);     /// 47: compile-time error
+  const c = const AssertCompare.constMultiSuper(cTrue, 2);      /// 48: compile-time error
+}
+
+
+void runtimeAsserts() {
+
+  testAssertArgumentCombinations(value, test, [testConst]) {
+    test(() => new AssertArgument.first(value, 0, 1));
+    test(() => new AssertArgument.last(value, 0, 1));
+    test(() => new AssertArgument.middle(value, 0, 1));
+    test(() => new AssertArgument.multi(value, 0, 1));
+    test(() => new AssertArgument.firstSuper(value, 0, 1));
+    test(() => new AssertArgument.lastSuper(value, 0, 1));
+    test(() => new AssertArgument.middleSuper(value, 0, 1));
+    test(() => new AssertArgument.multiSuper(value, 0, 1));
+    testConst ??= test;
+    testConst(() => new AssertArgument.constFirst(value, 0, 1));
+    testConst(() => new AssertArgument.constLast(value, 0, 1));
+    testConst(() => new AssertArgument.constMiddle(value, 0, 1));
+    testConst(() => new AssertArgument.constMulti(value, 0, 1));
+    testConst(() => new AssertArgument.constFirstSuper(value, 0, 1));
+    testConst(() => new AssertArgument.constLastSuper(value, 0, 1));
+    testConst(() => new AssertArgument.constMiddleSuper(value, 0, 1));
+    testConst(() => new AssertArgument.constMultiSuper(value, 0, 1));
+  }
+
+  testAssertCompareCombinations(v1, v2, test, [testConst]) {
+    test(() => new AssertCompare.first(v1, v2));
+    test(() => new AssertCompare.last(v1, v2));
+    test(() => new AssertCompare.middle(v1, v2));
+    test(() => new AssertCompare.multi(v1, v2));
+    test(() => new AssertCompare.firstSuper(v1, v2));
+    test(() => new AssertCompare.lastSuper(v1, v2));
+    test(() => new AssertCompare.middleSuper(v1, v2));
+    test(() => new AssertCompare.multiSuper(v1, v2));
+    testConst ??= test;
+    testConst(() => new AssertCompare.constFirst(v1, v2));
+    testConst(() => new AssertCompare.constLast(v1, v2));
+    testConst(() => new AssertCompare.constMiddle(v1, v2));
+    testConst(() => new AssertCompare.constMulti(v1, v2));
+    testConst(() => new AssertCompare.constFirstSuper(v1, v2));
+    testConst(() => new AssertCompare.constLastSuper(v1, v2));
+    testConst(() => new AssertCompare.constMiddleSuper(v1, v2));
+    testConst(() => new AssertCompare.constMultiSuper(v1, v2));
+  }
+
+  testAssertArgumentCombinations(true, pass);
+  testAssertArgumentCombinations(kTrue, pass, failType);
+  testAssertArgumentCombinations(false, failAssert);
+  testAssertArgumentCombinations(kFalse, failAssert, failType);
+  testAssertArgumentCombinations(42, failType);
+  testAssertArgumentCombinations(null, failAssert);
+
+  testAssertCompareCombinations(1, 2, pass);
+  testAssertCompareCombinations(3, 2, failAssert);
+  var TrickCompareInt = const TrickCompare(42);
+  testAssertCompareCombinations(TrickCompareInt, 0, failType);
+  var TrickCompareTrueFun = const TrickCompare(kTrue);
+  testAssertCompareCombinations(TrickCompareTrueFun, 0, pass, failType);
+  var TrickCompareFalseFun = const TrickCompare(kFalse);
+  testAssertCompareCombinations(TrickCompareFalseFun, 0, failAssert, failType);
+}
+
+
+void pass(void action()) {
+  action();
+}
+
+void failAssert(void action()) {
+  if (assertsEnabled) {
+    Expect.throws(action, (e) => e is AssertionError && e is! TypeError);
+  } else {
+    action();
+  }
+}
+
+void failType(void action()) {
+  if (assertsEnabled) {
+    Expect.throws(action, (e) => e is TypeError);
+  } else {
+    action();
+  }
+}
+
+bool kTrue() => true;
+bool kFalse() => false;
+
+class AssertArgument {
+  final y;
+  final z;
+  AssertArgument.first(x, y, z) : assert(x), y = y, z = z;
+  AssertArgument.last(x, y, z) : y = y, z = z, assert(x);
+  AssertArgument.middle(x, y, z) : y = y, assert(x), z = z;
+  AssertArgument.multi(x, y, z)
+      : assert(x), y = y, assert(x), z = z, assert(x);
+  AssertArgument.firstSuper(x, y, z) : assert(x), y = y, z = z, super();
+  AssertArgument.lastSuper(x, y, z) : y = y, z = z, assert(x), super();
+  AssertArgument.middleSuper(x, y, z) : y = y, assert(x), z = z, super();
+  AssertArgument.multiSuper(x, y, z)
+      : assert(x), y = y, assert(x), z = z, assert(x), super();
+  const AssertArgument.constFirst(x, y, z) : assert(x), y = y, z = z;
+  const AssertArgument.constLast(x, y, z) : y = y, z = z, assert(x);
+  const AssertArgument.constMiddle(x, y, z) : y = y, assert(x), z = z;
+  const AssertArgument.constMulti(x, y, z)
+      : assert(x), y = y, assert(x), z = z, assert(x);
+  const AssertArgument.constFirstSuper(x, y, z)
+      : assert(x), y = y, z = z, super();
+  const AssertArgument.constLastSuper(x, y, z)
+      : y = y, z = z, assert(x), super();
+  const AssertArgument.constMiddleSuper(x, y, z)
+      : y = y, assert(x), z = z, super();
+  const AssertArgument.constMultiSuper(x, y, z)
+      : assert(x), y = y, assert(x), z = z, assert(x), super();
+}
+
+class AssertCompare {
+  final y;
+  final z;
+  AssertCompare.first(y, z) : assert(y < z), y = y, z = z;
+  AssertCompare.last(y, z) : y = y, z = z, assert(y < z);
+  AssertCompare.middle(y, z) : y = y, assert(y < z), z = z;
+  AssertCompare.multi(y, z)
+      : assert(y < z), y = y, assert(y < z), z = z, assert(y < z);
+  AssertCompare.firstSuper(y, z) : assert(y < z), y = y, z = z, super();
+  AssertCompare.lastSuper(y, z) : y = y, z = z, assert(y < z), super();
+  AssertCompare.middleSuper(y, z) : y = y, assert(y < z), z = z, super();
+  AssertCompare.multiSuper(y, z)
+      : assert(y < z), y = y, assert(y < z), z = z, assert(y < z), super();
+  const AssertCompare.constFirst(y, z) : assert(y < z), y = y, z = z;
+  const AssertCompare.constLast(y, z) : y = y, z = z, assert(y < z);
+  const AssertCompare.constMiddle(y, z) : y = y, assert(y < z), z = z;
+  const AssertCompare.constMulti(y, z)
+      : assert(y < z), y = y, assert(y < z), z = z, assert(y < z);
+  const AssertCompare.constFirstSuper(y, z)
+      : assert(y < z), y = y, z = z, super();
+  const AssertCompare.constLastSuper(y, z)
+      : y = y, z = z, assert(y < z), super();
+  const AssertCompare.constMiddleSuper(y, z)
+      : y = y, assert(y < z), z = z, super();
+  const AssertCompare.constMultiSuper(y, z)
+      : assert(y < z), y = y, assert(y < z), z = z, assert(y < z), super();
+}
+
+class TrickCompare {
+  final result;
+  const TrickCompare(this.result);
+  operator<(other) => result;  // Nyah-nyah!
+}
diff --git a/tests/language/generic_functions_test.dart b/tests/language/generic_functions_test.dart
index c9628a6..0e6d5b3 100644
--- a/tests/language/generic_functions_test.dart
+++ b/tests/language/generic_functions_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// function declarations and function invocations. Variant of code from
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 47496a6..1b363d1 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// local function declarations, and declarations of function parameters.
diff --git a/tests/language/generic_metadata_test.dart b/tests/language/generic_metadata_test.dart
new file mode 100644
index 0000000..69ea463
--- /dev/null
+++ b/tests/language/generic_metadata_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+ 
+// Check that annotations cannot use type arguments, but can be raw.
+
+class C<T> {
+  const C();
+}
+
+@C()          /// 01: ok
+@C<dynamic>() /// 02: compile-time error
+@C<int>()     /// 03: compile-time error
+main() {}
\ No newline at end of file
diff --git a/tests/language/generic_methods_function_type_test.dart b/tests/language/generic_methods_function_type_test.dart
index 17a4c1a..23c1992 100644
--- a/tests/language/generic_methods_function_type_test.dart
+++ b/tests/language/generic_methods_function_type_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in a function typed
 /// parameter declaration.
diff --git a/tests/language/generic_methods_new_test.dart b/tests/language/generic_methods_new_test.dart
index ea23b94..0836fd5 100644
--- a/tests/language/generic_methods_new_test.dart
+++ b/tests/language/generic_methods_new_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in object creation. With
 /// '--generic-method-syntax', the type argument is available at runtime,
@@ -21,6 +22,8 @@
 
 List<T> f2<T>(T t) => <T>[t];
 
+Map<T, String> f3<T>(T t) => <T, String>{t: 'hi'};
+
 main() {
   C c = f1<int>(42);
   List i = f2<String>("Hello!");
@@ -28,4 +31,9 @@
   Expect.isTrue(i is List<String> && i is List<int>); // List<dynamic>.
   Expect.equals(c.e, 42);
   Expect.equals(i[0], "Hello!");
+
+  Map m1 = f3<int>(1);
+  Expect.isTrue(m1 is Map<int, String> && m1 is Map<String, String>);
+  Expect.isFalse(m1 is Map<int, int>);
+  Expect.equals('hi', m1[1]);
 }
diff --git a/tests/language/generic_methods_test.dart b/tests/language/generic_methods_test.dart
index fba394a..ec7d488 100644
--- a/tests/language/generic_methods_test.dart
+++ b/tests/language/generic_methods_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle type parameterization of
 /// method declarations and method invocations. Slightly adjusted version of
diff --git a/tests/language/generic_methods_type_expression_test.dart b/tests/language/generic_methods_type_expression_test.dart
index cbe0802..dd98c7a 100644
--- a/tests/language/generic_methods_type_expression_test.dart
+++ b/tests/language/generic_methods_type_expression_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test on the usage of method type arguments in type expressions. With
 /// '--generic-method-syntax', the type argument is available at runtime,
@@ -32,6 +33,13 @@
 
 Type f8<T>() => new TypeValue<List<T>>().value;
 
+bool f9<T>(Object o) => o is Map<T, String>;
+
+class IsMap<A> {
+  @NoInline()
+  bool check<B>(o) => o is Map<A, B>;
+}
+
 main() {
   String s = "Hello!";
   List<String> ss = <String>[s];
@@ -49,4 +57,11 @@
   Expect.equals(f6<int>(ss), ss); // `as List<dynamic>` succeeds.
   Expect.throws(() => f7<int>(), (e) => e is TypeError);
   Expect.equals(f8<int>(), List); // Returns `List<dynamic>`.
+
+  Expect.isTrue(f9<int>(<int,String>{}));
+  Expect.isTrue(f9<int>(<bool,String>{})); // `is Map<dynamic, String>` is true.
+  Expect.isFalse(f9<int>(<int,int>{}));
+
+  Expect.isTrue(new IsMap<int>().check<String>(<int,String>{}));
+  Expect.isTrue(new IsMap<int>().check<int>(<int,String>{}));
 }
diff --git a/tests/language/generic_sends_test.dart b/tests/language/generic_sends_test.dart
index 332439c7..75c7dc9 100644
--- a/tests/language/generic_sends_test.dart
+++ b/tests/language/generic_sends_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // DartOptions=--generic-method-syntax
+// VMOptions=--generic-method-syntax
 
 /// Dart test verifying that the parser can handle certain cases where
 /// grammar ambiguity is resolved in favor of generic sends, not
diff --git a/tests/language/language.status b/tests/language/language.status
index bd95b58..ce7e840 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -45,13 +45,16 @@
 async_star_cancel_while_paused_test: RuntimeError
 
 # Experimental feature: Syntactic support for generic methods.
-generic_methods_test: CompiletimeError # Issue 25869
-generic_functions_test: CompiletimeError # Issue 25869
-generic_local_functions_test: CompiletimeError # Issue 25869
-generic_sends_test: CompiletimeError # Issue 25869
-generic_methods_new_test: CompiletimeError # Issue 25869
-generic_methods_function_type_test: CompiletimeError # Issue 25869
-generic_methods_type_expression_test: CompiletimeError # Issue 25869
+generic_methods_type_expression_test: RuntimeError # Issue 25869
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app || $compiler == dart2appjit) && $checked ]
+# The generic functions tests fail in checked mode because the parsed type parameters
+# are ignored.
+generic_methods_function_type_test: RuntimeError # Issue 25869
+generic_methods_test: RuntimeError # Issue 25869
+generic_methods_new_test: RuntimeError # Issue 25869
+generic_local_functions_test: RuntimeError # Issue 25869
+generic_functions_test: RuntimeError # Issue 25869
 
 [ ($compiler == none || $compiler == precompiler || $compiler == dart2app || $compiler == dart2appjit) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_app) ]
 
@@ -100,13 +103,14 @@
 initializing_formal_type_test: Skip
 
 # Experimental feature: Syntactic support for generic methods.
-generic_methods_test: RuntimeError # Issue 25869
-generic_functions_test: RuntimeError # Issue 25869
-generic_local_functions_test: RuntimeError # Issue 25869
-generic_sends_test: RuntimeError # Issue 25869
-generic_methods_new_test: RuntimeError # Issue 25869
-generic_methods_function_type_test: RuntimeError # Issue 25869
-generic_methods_type_expression_test: RuntimeError # Issue 25869
+# Skip these in dartium, because the test framework can't pass VM flags to
+generic_methods_test: Skip # Issue 25869
+generic_functions_test: Skip # Issue 25869
+generic_local_functions_test: Skip # Issue 25869
+generic_sends_test: Skip # Issue 25869
+generic_methods_new_test: Skip # Issue 25869
+generic_methods_function_type_test: Skip # Issue 25869
+generic_methods_type_expression_test: Skip # Issue 25869
 
 config_import_test: Skip  # Issue 26250
 
@@ -274,3 +278,15 @@
 regress_23408_test: Crash # Requires deferred libraries
 regress_22443_test: Crash # Requires deferred libraries
 tearoff_basic_test: Crash # Requires deferred libraries
+
+[$runtime != vm || $compiler != none]
+assert_initializer_test: SKIP  # not implemented yet, experiment is VM only.
+
+[$runtime == vm && $compiler == none && $unchecked]
+assert_initializer_test/*: MissingCompileTimeError, OK  # asserts shouldn't fail in unchecked mode.
+assert_initializer_test/none: pass
+
+[$runtime == vm && $compiler == none && $checked]
+# The VM doesn't enforce that potentially const expressions are actually
+# const expressions when the constructor is called with `const`.
+assert_initializer_test/4*: MissingCompileTimeError # Issue 392.
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 52185f2..71c509b 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -876,6 +876,26 @@
   });
 }
 
+void testWaitSyncError() {
+  var cms = const Duration(milliseconds: 100);
+  var cleanups = new List.filled(3, false);
+  var uncaughts = new List.filled(3, false);
+  asyncStart();
+  asyncStart();
+  runZoned(() {
+    Future.wait(new Iterable.generate(5, (i) {
+      if (i != 3) return new Future.delayed(cms * (i + 1), () => i);
+      throw "throwing synchronously in iterable";
+    }), cleanUp: (index) {
+      Expect.isFalse(cleanups[index]);
+      cleanups[index] = true;
+      if (cleanups.every((x) => x)) asyncEnd();
+    });
+  }, onError: (e, s) {
+    asyncEnd();
+  });
+}
+
 void testBadFuture() {
   var bad = new BadFuture();
   // Completing with bad future (then call throws) puts error in result.
@@ -1075,6 +1095,7 @@
 
   testWaitCleanUp();
   testWaitCleanUpError();
+  testWaitSyncError();
 
   testBadFuture();
 
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index ba34bed..b9c7e9b 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -105,7 +105,8 @@
       Expect.fail("No server connection expected.");
     },
     onError: (error) {
-      Expect.isTrue(error is HandshakeException);
+      Expect.isTrue(error is SocketException ||
+                    error is HandshakeException);
       clientEndFuture.then((_) {
         if (!cancelOnError) server.close();
         asyncEnd();
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index d3e2d1c..2af0510 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -116,7 +116,8 @@
       // TODO(whesse): When null context is supported, disallow
       // the ArgumentError type here.
       Expect.isTrue(error is ArgumentError ||
-                    error is HandshakeException);
+                    error is HandshakeException ||
+                    error is SocketException);
       clientEndFuture.then((_) {
         if (!cancelOnError) server.close();
         asyncEnd();
diff --git a/tools/VERSION b/tools/VERSION
index 53737b9..4f34f59 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
 #
 CHANNEL dev
 MAJOR 1
-MINOR 19
+MINOR 20
 PATCH 0
-PRERELEASE 7
-PRERELEASE_PATCH 3
+PRERELEASE 0
+PRERELEASE_PATCH 0
diff --git a/tools/list_pkg_directories.py b/tools/list_pkg_directories.py
old mode 100644
new mode 100755
diff --git a/tools/make_links.py b/tools/make_links.py
old mode 100644
new mode 100755
index 157008a..d49af30
--- a/tools/make_links.py
+++ b/tools/make_links.py
@@ -38,26 +38,35 @@
   result.add_option("--timestamp_file", "",
       help='Create a timestamp file when done creating the links.',
       default='')
+  result.add_option("-q", "--quiet",
+      help="Don't print any messages",
+      action="store_true",
+      dest="quiet",
+      default=False)
   return result.parse_args()
 
-def make_link(source, target, orig_source):
+def make_link(quiet, source, target, orig_source):
   if os.path.islink(target):
-    print 'Removing %s' % target
+    if not quiet:
+      print 'Removing %s' % target
     sys.stdout.flush()
     os.unlink(target)
 
   if os.path.isdir(target):
-    print 'Removing %s' % target
+    if not quiet:
+      print 'Removing %s' % target
     sys.stdout.flush()
     os.rmdir(target)
 
   if os.path.isfile(orig_source):
-    print 'Copying file from %s to %s' % (orig_source, target)
+    if not quiet:
+      print 'Copying file from %s to %s' % (orig_source, target)
     sys.stdout.flush()
     shutil.copyfile(orig_source, target)
     return 0
   else:
-    print 'Creating link from %s to %s' % (source, target)
+    if not quiet:
+      print 'Creating link from %s to %s' % (source, target)
     sys.stdout.flush()
 
     if utils.GuessOS() == 'win32':
@@ -90,7 +99,7 @@
         os.remove(full_link)
   else:
     os.makedirs(target)
-  linked_names = {}; 
+  linked_names = {};
   for source in args[1:]:
     # Assume the source directory is named ".../NAME/lib".
     split = source.split(':')
@@ -117,7 +126,8 @@
       source = os.path.relpath(source)
     else:
       source = os.path.relpath(source, start=target)
-    exit_code = make_link(source, os.path.join(target, name), orig_source)
+    exit_code = make_link(
+        options.quiet, source, os.path.join(target, name), orig_source)
     if exit_code != 0:
       return exit_code
   create_timestamp_file(options)
diff --git a/tools/sdks/linux/dart-sdk.tar.gz.sha1 b/tools/sdks/linux/dart-sdk.tar.gz.sha1
index 3a4aab2..22e70b3 100644
--- a/tools/sdks/linux/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/linux/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-0c27d9ced0e84a07ee98f99d5057121744138ac9
\ No newline at end of file
+cfffe4b391ce4e907b7ed9a2e876ca6e077b7be3
\ No newline at end of file
diff --git a/tools/sdks/mac/dart-sdk.tar.gz.sha1 b/tools/sdks/mac/dart-sdk.tar.gz.sha1
index 5e27c0c..98b4d2c 100644
--- a/tools/sdks/mac/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/mac/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-78d5d490650f7cb834a6e67ba882be106dd6324f
\ No newline at end of file
+ca26cc2413c9ad174794e17fbbb0797815591138
\ No newline at end of file
diff --git a/tools/sdks/win/dart-sdk.tar.gz.sha1 b/tools/sdks/win/dart-sdk.tar.gz.sha1
index 060bbb7..cca45ed 100644
--- a/tools/sdks/win/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/win/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-6c0d135f57ac07f8ad70f21b29a3645bce2edb50
\ No newline at end of file
+e6b6200db59ebb84570f0ed995c7c5e3b0b47c7b
\ No newline at end of file
diff --git a/tools/test.dart b/tools/test.dart
index e00357d..76e4928 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -41,7 +41,8 @@
   var environment = Platform.environment;
   if (environment['DART_TESTING_DELETE_TEMPORARY_DIRECTORIES'] == '1') {
     LeftOverTempDirPrinter.getLeftOverTemporaryDirectories().listen(
-        (Directory tempDirectory) {
+        (FileSystemEntity tempEntity) {
+          Directory tempDirectory = tempEntity as Directory;
           try {
             tempDirectory.deleteSync(recursive: true);
           } catch (error) {
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index f6ac871..e008e71 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -57,6 +57,7 @@
     bool useBlobs = configuration['use_blobs'];
     bool hotReload = configuration['hot_reload'];
     bool hotReloadRollback = configuration['hot_reload_rollback'];
+    bool useFastStartup = configuration['fast_startup'];
 
     switch (compiler) {
       case 'dart2analyzer':
@@ -74,6 +75,7 @@
             useCps: useCps,
             useSdk: useSdk,
             isCsp: isCsp,
+            useFastStartup: useFastStartup,
             extraDart2jsOptions:
                 TestUtils.getExtraOptions(configuration, 'dart2js_options'));
       case 'dart2app':
@@ -264,6 +266,7 @@
 class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration {
   final bool isCsp;
   final bool useCps;
+  final bool useFastStartup;
   final List<String> extraDart2jsOptions;
   // We cache the extended environment to save memory.
   static Map<String, String> cpsFlagCache;
@@ -276,6 +279,7 @@
       bool useSdk,
       bool this.useCps,
       bool this.isCsp,
+      bool this.useFastStartup,
       this.extraDart2jsOptions})
       : super('dart2js',
             isDebug: isDebug,
@@ -299,6 +303,9 @@
       Map<String, String> environmentOverrides) {
     List compilerArguments = new List.from(arguments)
       ..addAll(extraDart2jsOptions);
+    if (useFastStartup) {
+      compilerArguments.add('--fast-startup');
+    }
     return new CommandArtifact(<Command>[
       this.computeCompilationCommand('$tempDir/out.js', buildDir,
           CommandBuilder.instance, compilerArguments, environmentOverrides)
diff --git a/tools/testing/dart/multitest.dart b/tools/testing/dart/multitest.dart
index eb85c1a..b714e71 100644
--- a/tools/testing/dart/multitest.dart
+++ b/tools/testing/dart/multitest.dart
@@ -245,7 +245,7 @@
   ExtractTestsFromMultitest(filePath, tests, outcomes);
 
   Path sourceDir = filePath.directoryPath;
-  Path targetDir = CreateMultitestDirectory(outputDir, suiteDir);
+  Path targetDir = createMultitestDirectory(outputDir, suiteDir, sourceDir);
   assert(targetDir != null);
 
   // Copy all the relative imports of the multitest.
@@ -295,24 +295,19 @@
   });
 }
 
-Path CreateMultitestDirectory(String outputDir, Path suiteDir) {
-  Directory generatedTestDir = new Directory('$outputDir/generated_tests');
-  if (!new Directory(outputDir).existsSync()) {
-    new Directory(outputDir).createSync();
-  }
-  if (!generatedTestDir.existsSync()) {
-    generatedTestDir.createSync();
-  }
+String suiteNameFromPath(Path suiteDir) {
   var split = suiteDir.segments();
+  // co19 test suite is at tests/co19/src.
   if (split.last == 'src') {
-    // TODO(sigmund): remove this once all tests are migrated to use
-    // TestSuite.forDirectory.
     split.removeLast();
   }
-  String path = '${generatedTestDir.path}/${split.last}';
-  Directory dir = new Directory(path);
-  if (!dir.existsSync()) {
-    dir.createSync();
-  }
-  return new Path(new File(path).absolute.path);
+  return split.last;
+}
+
+Path createMultitestDirectory(String outputDir, Path suiteDir, Path sourceDir) {
+  Path relative = sourceDir.relativeTo(suiteDir);
+  Path path = new Path(outputDir).append('generated_tests')
+      .append(suiteNameFromPath(suiteDir)).join(relative);
+  TestUtils.mkdirRecursive(TestUtils.currentWorkingDirectory, path);
+  return new Path(new File(path.toNativePath()).absolute.path);
 }
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 922e386..917e236 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -190,6 +190,10 @@
           'noopt', 'Run an in-place precompilation', ['--noopt'], [], false,
           type: 'bool'),
       new _TestOptionSpecification(
+          'fast_startup', 'Pass the --fast-startup flag to dart2js',
+          ['--fast-startup'], [], false,
+          type: 'bool'),
+      new _TestOptionSpecification(
           'hot_reload', 'Run hot reload stress tests', ['--hot-reload'], [],
           false, type: 'bool'),
       new _TestOptionSpecification(
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 14910fa..f09372a 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -488,7 +488,7 @@
     }
   }
 
-  static Stream<Directory> getLeftOverTemporaryDirectories() {
+  static Stream<FileSystemEntity> getLeftOverTemporaryDirectories() {
     var regExp = _getTemporaryDirectoryRegexp();
     return Directory.systemTemp.list().where((FileSystemEntity fse) {
       if (fse is Directory) {