Version 1.13.0-dev.1.0

Merge commit '07d68c5c3acc4a148de07a801b346eff3b673244' into dev
diff --git a/DEPS b/DEPS
index 8b2d8d8..a111db0 100644
--- a/DEPS
+++ b/DEPS
@@ -108,7 +108,7 @@
   "utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
   "unittest_tag": "@0.11.6",
   "usage_rev": "@b5080dac0d26a5609b266f8fdb0d053bc4c1c638",
-  "watcher_tag": "@0.9.6",
+  "watcher_tag": "@0.9.7",
   "when_tag": "@0.2.0+2",
   "which_tag": "@0.1.3+1",
   "web_components_rev": "@0e636b534d9b12c9e96f841e6679398e91a986ec",
@@ -370,8 +370,8 @@
       '--no_resume',
       '--bucket',
       'dart-dependencies',
-      '-d',
-      '-r',
+      '--recursive',
+      '--directory',
       Var('dart_root') + '/tools/testing/bin',
     ],
   },
@@ -384,10 +384,25 @@
       '--no_resume',
       '--bucket',
       'dart-dependencies',
-      '-d',
-      '-r',
+      '--recursive',
+      '--directory',
       Var('dart_root') + '/third_party/d8',
     ],
   },
-
+  {
+    "name": "checked_in_dart_sdks",
+    "pattern": ".",
+    "action": [
+      "download_from_google_storage",
+      "--no_auth",
+      "--no_resume",
+      "--bucket",
+      "dart-dependencies",
+      "--recursive",
+      "--auto_platform",
+      "--extract",
+      "--directory",
+      Var('dart_root') + "/tools/sdks",
+    ],
+  },
 ]
diff --git a/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart
new file mode 100644
index 0000000..c708d9a
--- /dev/null
+++ b/pkg/analysis_server/lib/analysis/navigation/navigation_core.dart
@@ -0,0 +1,40 @@
+// 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 analysis_server.analysis.navigation.navigation_core;
+
+import 'package:analysis_server/src/protocol.dart'
+    show ElementKind, Location, NavigationRegion, NavigationTarget;
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/src/generated/source.dart' show Source;
+
+/**
+ * An object used to produce navigation regions.
+ *
+ * Clients are expected to subtype this class when implementing plugins.
+ */
+abstract class NavigationContributor {
+  /**
+   * Contribute navigation regions for a part of the given [source] into the
+   * given [holder]. The part is specified by the [offset] and [length].
+   * The [context] can be used to get analysis results.
+   */
+  void computeNavigation(NavigationHolder holder, AnalysisContext context,
+      Source source, int offset, int length);
+}
+
+/**
+ * An object that [NavigationContributor]s use to record navigation regions
+ * into.
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class NavigationHolder {
+  /**
+   * Record a new navigation region with the given [offset] and [length] that
+   * should navigation to the given [targetLocation].
+   */
+  void addRegion(
+      int offset, int length, ElementKind targetKind, Location targetLocation);
+}
diff --git a/pkg/analysis_server/lib/plugin/navigation.dart b/pkg/analysis_server/lib/plugin/navigation.dart
new file mode 100644
index 0000000..23603f0
--- /dev/null
+++ b/pkg/analysis_server/lib/plugin/navigation.dart
@@ -0,0 +1,22 @@
+// 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.
+
+/**
+ * Support for client code that extends the analysis server by adding new
+ * navigation contributors.
+ */
+library analysis_server.plugin.navigation;
+
+import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * The identifier of the extension point that allows plugins to register
+ * navigation contributors. The object used as an extension must be
+ * a [NavigationContributor].
+ */
+final String NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
+    ServerPlugin.UNIQUE_IDENTIFIER,
+    ServerPlugin.NAVIGATION_CONTRIBUTOR_EXTENSION_POINT);
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 87c6509..5d0fb7d 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -961,6 +961,9 @@
         // Dart unit notifications.
         if (AnalysisEngine.isDartFileName(file)) {
           Source source = contextSource.source;
+          // TODO(scheglov) This way to get resolved information is very Dart
+          // specific. OTOH as it is planned now Angular results are not
+          // flushable.
           CompilationUnit dartUnit =
               _getResolvedCompilationUnitToResendNotification(context, source);
           if (dartUnit != null) {
@@ -969,8 +972,7 @@
                 sendAnalysisNotificationHighlights(this, file, dartUnit);
                 break;
               case AnalysisService.NAVIGATION:
-                // TODO(scheglov) consider support for one unit in 2+ libraries
-                sendAnalysisNotificationNavigation(this, file, dartUnit);
+                sendAnalysisNotificationNavigation(this, context, source);
                 break;
               case AnalysisService.OCCURRENCES:
                 sendAnalysisNotificationOccurrences(this, file, dartUnit);
diff --git a/pkg/analysis_server/lib/src/collections.dart b/pkg/analysis_server/lib/src/collections.dart
index 8ab3da8..1a1ba38 100644
--- a/pkg/analysis_server/lib/src/collections.dart
+++ b/pkg/analysis_server/lib/src/collections.dart
@@ -28,3 +28,20 @@
   }
   return list;
 }
+
+/// A pair of values.
+class Pair<E, F> {
+  final E first;
+  final F last;
+
+  Pair(this.first, this.last);
+
+  int get hashCode => first.hashCode ^ last.hashCode;
+
+  bool operator ==(other) {
+    if (other is! Pair) return false;
+    return other.first == first && other.last == last;
+  }
+
+  String toString() => '($first, $last)';
+}
diff --git a/pkg/analysis_server/lib/src/computer/computer_outline.dart b/pkg/analysis_server/lib/src/computer/computer_outline.dart
index 81e9b50..a052b13 100644
--- a/pkg/analysis_server/lib/src/computer/computer_outline.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_outline.dart
@@ -137,7 +137,7 @@
     }
     // unit or class member
     if (parent is CompilationUnit) {
-      firstOffset = 0;
+      firstOffset = node.offset;
       siblings = parent.declarations;
     } else if (parent is ClassDeclaration) {
       firstOffset = parent.leftBracket.end;
@@ -160,7 +160,10 @@
     SimpleIdentifier nameNode = node.name;
     String name = nameNode.name;
     _SourceRegion sourceRegion = _getSourceRegion(node);
-    Element element = new Element(ElementKind.CLASS, name, Element.makeFlags(
+    Element element = new Element(
+        ElementKind.CLASS,
+        name,
+        Element.makeFlags(
             isPrivate: Identifier.isPrivateName(name),
             isDeprecated: _isDeprecated(node),
             isAbstract: node.isAbstract),
@@ -174,11 +177,13 @@
     SimpleIdentifier nameNode = node.name;
     String name = nameNode.name;
     _SourceRegion sourceRegion = _getSourceRegion(node);
-    Element element = new Element(ElementKind.CLASS_TYPE_ALIAS, name, Element
-            .makeFlags(
-                isPrivate: Identifier.isPrivateName(name),
-                isDeprecated: _isDeprecated(node),
-                isAbstract: node.isAbstract),
+    Element element = new Element(
+        ElementKind.CLASS_TYPE_ALIAS,
+        name,
+        Element.makeFlags(
+            isPrivate: Identifier.isPrivateName(name),
+            isDeprecated: _isDeprecated(node),
+            isAbstract: node.isAbstract),
         location: _getLocationNode(nameNode),
         typeParameters: _getTypeParametersStr(node.typeParameters));
     return new Outline(element, sourceRegion.offset, sourceRegion.length);
@@ -201,9 +206,11 @@
     _SourceRegion sourceRegion = _getSourceRegion(constructor);
     FormalParameterList parameters = constructor.parameters;
     String parametersStr = parameters != null ? parameters.toSource() : '';
-    Element element = new Element(ElementKind.CONSTRUCTOR, name, Element
-            .makeFlags(
-                isPrivate: isPrivate, isDeprecated: _isDeprecated(constructor)),
+    Element element = new Element(
+        ElementKind.CONSTRUCTOR,
+        name,
+        Element.makeFlags(
+            isPrivate: isPrivate, isDeprecated: _isDeprecated(constructor)),
         location: _getLocationOffsetLength(offset, length),
         parameters: parametersStr);
     List<Outline> contents = _addLocalFunctionOutlines(constructor.body);
@@ -217,10 +224,12 @@
     SimpleIdentifier nameNode = node.name;
     String name = nameNode.name;
     _SourceRegion sourceRegion = _getSourceRegion(node);
-    Element element = new Element(ElementKind.ENUM_CONSTANT, name, Element
-            .makeFlags(
-                isPrivate: Identifier.isPrivateName(name),
-                isDeprecated: _isDeprecated(node)),
+    Element element = new Element(
+        ElementKind.ENUM_CONSTANT,
+        name,
+        Element.makeFlags(
+            isPrivate: Identifier.isPrivateName(name),
+            isDeprecated: _isDeprecated(node)),
         location: _getLocationNode(nameNode));
     return new Outline(element, sourceRegion.offset, sourceRegion.length);
   }
@@ -229,7 +238,10 @@
     SimpleIdentifier nameNode = node.name;
     String name = nameNode.name;
     _SourceRegion sourceRegion = _getSourceRegion(node);
-    Element element = new Element(ElementKind.ENUM, name, Element.makeFlags(
+    Element element = new Element(
+        ElementKind.ENUM,
+        name,
+        Element.makeFlags(
             isPrivate: Identifier.isPrivateName(name),
             isDeprecated: _isDeprecated(node)),
         location: _getLocationNode(nameNode));
@@ -254,7 +266,10 @@
     _SourceRegion sourceRegion = _getSourceRegion(function);
     String parametersStr = parameters != null ? parameters.toSource() : '';
     String returnTypeStr = returnType != null ? returnType.toSource() : '';
-    Element element = new Element(kind, name, Element.makeFlags(
+    Element element = new Element(
+        kind,
+        name,
+        Element.makeFlags(
             isPrivate: Identifier.isPrivateName(name),
             isDeprecated: _isDeprecated(function),
             isStatic: isStatic),
@@ -276,10 +291,12 @@
     FormalParameterList parameters = node.parameters;
     String parametersStr = parameters != null ? parameters.toSource() : '';
     String returnTypeStr = returnType != null ? returnType.toSource() : '';
-    Element element = new Element(ElementKind.FUNCTION_TYPE_ALIAS, name, Element
-            .makeFlags(
-                isPrivate: Identifier.isPrivateName(name),
-                isDeprecated: _isDeprecated(node)),
+    Element element = new Element(
+        ElementKind.FUNCTION_TYPE_ALIAS,
+        name,
+        Element.makeFlags(
+            isPrivate: Identifier.isPrivateName(name),
+            isDeprecated: _isDeprecated(node)),
         location: _getLocationNode(nameNode),
         parameters: parametersStr,
         returnType: returnTypeStr,
@@ -303,7 +320,10 @@
     _SourceRegion sourceRegion = _getSourceRegion(method);
     String parametersStr = parameters != null ? parameters.toSource() : null;
     String returnTypeStr = returnType != null ? returnType.toSource() : '';
-    Element element = new Element(kind, name, Element.makeFlags(
+    Element element = new Element(
+        kind,
+        name,
+        Element.makeFlags(
             isPrivate: Identifier.isPrivateName(name),
             isDeprecated: _isDeprecated(method),
             isAbstract: method.isAbstract,
@@ -338,13 +358,17 @@
     SimpleIdentifier nameNode = variable.name;
     String name = nameNode.name;
     _SourceRegion sourceRegion = _getSourceRegion(variable);
-    Element element = new Element(kind, name, Element.makeFlags(
+    Element element = new Element(
+        kind,
+        name,
+        Element.makeFlags(
             isPrivate: Identifier.isPrivateName(name),
             isDeprecated: _isDeprecated(variable),
             isStatic: isStatic,
             isConst: variable.isConst,
             isFinal: variable.isFinal),
-        location: _getLocationNode(nameNode), returnType: typeName);
+        location: _getLocationNode(nameNode),
+        returnType: typeName);
     Outline outline =
         new Outline(element, sourceRegion.offset, sourceRegion.length);
     return outline;
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index c0492bf..655ca2f 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -9,12 +9,13 @@
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/computer/computer_hover.dart';
-import 'package:analysis_server/src/computer/computer_navigation.dart';
 import 'package:analysis_server/src/constants.dart';
+import 'package:analysis_server/src/domains/analysis/navigation.dart';
 import 'package:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart' as engine;
 
 /**
@@ -125,15 +126,15 @@
           if (units.isEmpty) {
             server.sendResponse(new Response.getNavigationInvalidFile(request));
           } else {
-            DartUnitNavigationComputer computer =
-                new DartUnitNavigationComputer();
-            _GetNavigationAstVisitor visitor = new _GetNavigationAstVisitor(
-                params.offset, params.offset + params.length, computer);
-            for (CompilationUnit unit in units) {
-              unit.accept(visitor);
-            }
+            CompilationUnitElement unitElement = units.first.element;
+            NavigationHolderImpl holder = computeNavigation(
+                server,
+                unitElement.context,
+                unitElement.source,
+                params.offset,
+                params.length);
             server.sendResponse(new AnalysisGetNavigationResult(
-                    computer.files, computer.targets, computer.regions)
+                    holder.files, holder.targets, holder.regions)
                 .toResponse(request.id));
           }
           break;
@@ -290,36 +291,3 @@
     return new AnalysisUpdateOptionsResult().toResponse(request.id);
   }
 }
-
-/**
- * An AST visitor that computer navigation regions in the givne region.
- */
-class _GetNavigationAstVisitor extends UnifyingAstVisitor {
-  final int rangeStart;
-  final int rangeEnd;
-  final DartUnitNavigationComputer computer;
-
-  _GetNavigationAstVisitor(this.rangeStart, this.rangeEnd, this.computer);
-
-  bool isInRange(int offset) {
-    return rangeStart <= offset && offset <= rangeEnd;
-  }
-
-  @override
-  visitNode(AstNode node) {
-    // The node ends before the range starts.
-    if (node.end < rangeStart) {
-      return;
-    }
-    // The node starts after the range ends.
-    if (node.offset > rangeEnd) {
-      return;
-    }
-    // The node starts or ends in the range.
-    if (isInRange(node.offset) || isInRange(node.end)) {
-      computer.compute(node);
-      return;
-    }
-    super.visitNode(node);
-  }
-}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart
new file mode 100644
index 0000000..8cb08ae
--- /dev/null
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library domains.analysis.navigation;
+
+import 'dart:collection';
+
+import 'package:analysis_server/analysis/navigation/navigation_core.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/collections.dart';
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analyzer/src/generated/engine.dart'
+    show AnalysisContext, AnalysisEngine;
+import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
+import 'package:analyzer/src/generated/source.dart' show Source;
+
+/**
+ * Compute all known navigation information for the given part of [source].
+ */
+NavigationHolderImpl computeNavigation(AnalysisServer server,
+    AnalysisContext context, Source source, int offset, int length) {
+  NavigationHolderImpl holder = new NavigationHolderImpl();
+  List<NavigationContributor> contributors =
+      server.serverPlugin.navigationContributors;
+  for (NavigationContributor contributor in contributors) {
+    try {
+      contributor.computeNavigation(holder, context, source, offset, length);
+    } catch (exception, stackTrace) {
+      AnalysisEngine.instance.logger.logError(
+          'Exception from navigation contributor: ${contributor.runtimeType}',
+          new CaughtException(exception, stackTrace));
+    }
+  }
+  return holder;
+}
+
+/**
+ * A concrete implementation of  [NavigationHolder].
+ */
+class NavigationHolderImpl implements NavigationHolder {
+  /**
+   * A list of navigation regions.
+   */
+  final List<protocol.NavigationRegion> regions = <protocol.NavigationRegion>[];
+
+  /**
+   * All the unique targets referenced by [regions].
+   */
+  final List<protocol.NavigationTarget> targets = <protocol.NavigationTarget>[];
+  final Map<Pair<protocol.ElementKind, protocol.Location>, int> targetMap =
+      new HashMap<Pair<protocol.ElementKind, protocol.Location>, int>();
+
+  /**
+   * All the unique files referenced by [targets].
+   */
+  final List<String> files = <String>[];
+  final Map<String, int> fileMap = new HashMap<String, int>();
+
+  @override
+  void addRegion(int offset, int length, protocol.ElementKind targetKind,
+      protocol.Location targetLocation) {
+    int targetIndex = _addTarget(targetKind, targetLocation);
+    protocol.NavigationRegion region =
+        new protocol.NavigationRegion(offset, length, <int>[targetIndex]);
+    regions.add(region);
+  }
+
+  int _addFile(String file) {
+    int index = fileMap[file];
+    if (index == null) {
+      index = files.length;
+      files.add(file);
+      fileMap[file] = index;
+    }
+    return index;
+  }
+
+  int _addTarget(protocol.ElementKind kind, protocol.Location location) {
+    var pair =
+        new Pair<protocol.ElementKind, protocol.Location>(kind, location);
+    int index = targetMap[pair];
+    if (index == null) {
+      String file = location.file;
+      int fileIndex = _addFile(file);
+      index = targets.length;
+      protocol.NavigationTarget target = new protocol.NavigationTarget(
+          kind,
+          fileIndex,
+          location.offset,
+          location.length,
+          location.startLine,
+          location.startColumn);
+      targets.add(target);
+      targetMap[pair] = index;
+    }
+    return index;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
similarity index 72%
rename from pkg/analysis_server/lib/src/computer/computer_navigation.dart
rename to pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index b1caf9b..37aaac1b 100644
--- a/pkg/analysis_server/lib/src/computer/computer_navigation.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -2,99 +2,47 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library computer.navigation;
+library domains.analysis.navigation_dart;
 
-import 'dart:collection';
-
+import 'package:analysis_server/analysis/navigation/navigation_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
  * A computer for navigation regions in a Dart [CompilationUnit].
  */
-class DartUnitNavigationComputer {
-  final List<String> files = <String>[];
-  final Map<String, int> fileMap = new HashMap<String, int>();
-  final List<protocol.NavigationTarget> targets = <protocol.NavigationTarget>[];
-  final Map<Element, int> targetMap = new HashMap<Element, int>();
-  final List<protocol.NavigationRegion> regions = <protocol.NavigationRegion>[];
-
-  /**
-   * Computes [regions], [targets] and [files].
-   */
-  void compute(AstNode node) {
-    node.accept(new _DartUnitNavigationComputerVisitor(this));
-  }
-
-  int _addFile(String file) {
-    int index = fileMap[file];
-    if (index == null) {
-      index = files.length;
-      files.add(file);
-      fileMap[file] = index;
+class DartNavigationComputer implements NavigationContributor {
+  @override
+  void computeNavigation(NavigationHolder holder, AnalysisContext context,
+      Source source, int offset, int length) {
+    List<Source> libraries = context.getLibrariesContaining(source);
+    if (libraries.isNotEmpty) {
+      CompilationUnit unit =
+          context.getResolvedCompilationUnit2(source, libraries.first);
+      if (unit != null) {
+        _DartNavigationHolder dartHolder = new _DartNavigationHolder(holder);
+        _DartNavigationComputerVisitor visitor =
+            new _DartNavigationComputerVisitor(dartHolder);
+        if (offset == null || length == null) {
+          unit.accept(visitor);
+        } else {
+          _DartRangeAstVisitor partVisitor =
+              new _DartRangeAstVisitor(offset, offset + length, visitor);
+          unit.accept(partVisitor);
+        }
+      }
     }
-    return index;
-  }
-
-  void _addRegion(int offset, int length, Element element) {
-    if (element is FieldFormalParameterElement) {
-      element = (element as FieldFormalParameterElement).field;
-    }
-    if (element == null || element == DynamicElementImpl.instance) {
-      return;
-    }
-    if (element.location == null) {
-      return;
-    }
-    int targetIndex = _addTarget(element);
-    regions
-        .add(new protocol.NavigationRegion(offset, length, <int>[targetIndex]));
-  }
-
-  void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) {
-    int offset = a.offset;
-    int length = b.end - offset;
-    _addRegion(offset, length, element);
-  }
-
-  void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) {
-    int offset = a.offset;
-    int length = b.end - offset;
-    _addRegion(offset, length, element);
-  }
-
-  void _addRegionForNode(AstNode node, Element element) {
-    int offset = node.offset;
-    int length = node.length;
-    _addRegion(offset, length, element);
-  }
-
-  void _addRegionForToken(Token token, Element element) {
-    int offset = token.offset;
-    int length = token.length;
-    _addRegion(offset, length, element);
-  }
-
-  int _addTarget(Element element) {
-    int index = targetMap[element];
-    if (index == null) {
-      index = targets.length;
-      protocol.NavigationTarget target =
-          protocol.newNavigationTarget_fromElement(element, _addFile);
-      targets.add(target);
-      targetMap[element] = index;
-    }
-    return index;
   }
 }
 
-class _DartUnitNavigationComputerVisitor extends RecursiveAstVisitor {
-  final DartUnitNavigationComputer computer;
+class _DartNavigationComputerVisitor extends RecursiveAstVisitor {
+  final _DartNavigationHolder computer;
 
-  _DartUnitNavigationComputerVisitor(this.computer);
+  _DartNavigationComputerVisitor(this.computer);
 
   @override
   visitAssignmentExpression(AssignmentExpression node) {
@@ -273,3 +221,90 @@
     }
   }
 }
+
+/**
+ * A Dart specific wrapper around [NavigationHolder].
+ */
+class _DartNavigationHolder {
+  final NavigationHolder holder;
+
+  _DartNavigationHolder(this.holder);
+
+  void _addRegion(int offset, int length, Element element) {
+    if (element is FieldFormalParameterElement) {
+      element = (element as FieldFormalParameterElement).field;
+    }
+    if (element == null || element == DynamicElementImpl.instance) {
+      return;
+    }
+    if (element.location == null) {
+      return;
+    }
+    protocol.ElementKind kind =
+        protocol.newElementKind_fromEngine(element.kind);
+    protocol.Location location = protocol.newLocation_fromElement(element);
+    if (location == null) {
+      return;
+    }
+    holder.addRegion(offset, length, kind, location);
+  }
+
+  void _addRegion_nodeStart_nodeEnd(AstNode a, AstNode b, Element element) {
+    int offset = a.offset;
+    int length = b.end - offset;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegion_tokenStart_nodeEnd(Token a, AstNode b, Element element) {
+    int offset = a.offset;
+    int length = b.end - offset;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegionForNode(AstNode node, Element element) {
+    int offset = node.offset;
+    int length = node.length;
+    _addRegion(offset, length, element);
+  }
+
+  void _addRegionForToken(Token token, Element element) {
+    int offset = token.offset;
+    int length = token.length;
+    _addRegion(offset, length, element);
+  }
+}
+
+/**
+ * An AST visitor that forwards nodes intersecting with the range from
+ * [start] to [end] to the given [visitor].
+ */
+class _DartRangeAstVisitor extends UnifyingAstVisitor {
+  final int start;
+  final int end;
+  final AstVisitor visitor;
+
+  _DartRangeAstVisitor(this.start, this.end, this.visitor);
+
+  bool isInRange(int offset) {
+    return start <= offset && offset <= end;
+  }
+
+  @override
+  visitNode(AstNode node) {
+    // The node ends before the range starts.
+    if (node.end < start) {
+      return;
+    }
+    // The node starts after the range ends.
+    if (node.offset > end) {
+      return;
+    }
+    // The node starts or ends in the range.
+    if (isInRange(node.offset) || isInRange(node.end)) {
+      node.accept(visitor);
+      return;
+    }
+    // Go deeper.
+    super.visitNode(node);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 70b1e9b..f18ad32 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -7,10 +7,10 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/computer/computer_highlights.dart';
 import 'package:analysis_server/src/computer/computer_highlights2.dart';
-import 'package:analysis_server/src/computer/computer_navigation.dart';
 import 'package:analysis_server/src/computer/computer_occurrences.dart';
 import 'package:analysis_server/src/computer/computer_outline.dart';
 import 'package:analysis_server/src/computer/computer_overrides.dart';
+import 'package:analysis_server/src/domains/analysis/navigation.dart';
 import 'package:analysis_server/src/operation/operation.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/services/dependencies/library_dependencies.dart';
@@ -53,9 +53,14 @@
  * Schedules sending notifications for the given [file] using the resolved
  * [resolvedDartUnit].
  */
-void scheduleNotificationOperations(AnalysisServer server, String file,
-    LineInfo lineInfo, AnalysisContext context, CompilationUnit parsedDartUnit,
-    CompilationUnit resolvedDartUnit, List<AnalysisError> errors) {
+void scheduleNotificationOperations(
+    AnalysisServer server,
+    String file,
+    LineInfo lineInfo,
+    AnalysisContext context,
+    CompilationUnit parsedDartUnit,
+    CompilationUnit resolvedDartUnit,
+    List<AnalysisError> errors) {
   // If the file belongs to any analysis root, check whether we're in it now.
   AnalysisContext containingContext = server.getContainingContext(file);
   if (containingContext != null && context != containingContext) {
@@ -162,12 +167,13 @@
 }
 
 void sendAnalysisNotificationNavigation(
-    AnalysisServer server, String file, CompilationUnit dartUnit) {
+    AnalysisServer server, AnalysisContext context, Source source) {
   _sendNotification(server, () {
-    var computer = new DartUnitNavigationComputer();
-    computer.compute(dartUnit);
+    NavigationHolderImpl holder =
+        computeNavigation(server, context, source, null, null);
+    String file = source.fullName;
     var params = new protocol.AnalysisNavigationParams(
-        file, computer.regions, computer.targets, computer.files);
+        file, holder.regions, holder.targets, holder.files);
     server.sendNotification(params.toNotification());
   });
 }
@@ -381,7 +387,8 @@
 
   @override
   void perform(AnalysisServer server) {
-    sendAnalysisNotificationNavigation(server, file, unit);
+    Source source = unit.element.source;
+    sendAnalysisNotificationNavigation(server, context, source);
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index be413c6..6139725 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -5,17 +5,20 @@
 library analysis_server.src.plugin.server_plugin;
 
 import 'package:analysis_server/analysis/index/index_core.dart';
+import 'package:analysis_server/analysis/navigation/navigation_core.dart';
 import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/edit/assist/assist_core.dart';
 import 'package:analysis_server/edit/fix/fix_core.dart';
 import 'package:analysis_server/plugin/analyzed_files.dart';
 import 'package:analysis_server/plugin/assist.dart';
 import 'package:analysis_server/plugin/fix.dart';
+import 'package:analysis_server/plugin/navigation.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/domain_server.dart';
+import 'package:analysis_server/src/domains/analysis/navigation_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
@@ -74,6 +77,13 @@
   static const String INDEX_CONTRIBUTOR_EXTENSION_POINT = 'indexContributor';
 
   /**
+   * The simple identifier of the extension point that allows plugins to
+   * register navigation contributors.
+   */
+  static const String NAVIGATION_CONTRIBUTOR_EXTENSION_POINT =
+      'navigationContributor';
+
+  /**
    * The unique identifier of this plugin.
    */
   static const String UNIQUE_IDENTIFIER = 'analysis_server.core';
@@ -113,6 +123,11 @@
   ExtensionPoint indexContributorExtensionPoint;
 
   /**
+   * The extension point that allows plugins to register navigation contributors.
+   */
+  ExtensionPoint navigationContributorExtensionPoint;
+
+  /**
    * Initialize a newly created plugin.
    */
   ServerPlugin();
@@ -151,6 +166,13 @@
   List<IndexContributor> get indexContributors =>
       indexContributorExtensionPoint.extensions;
 
+  /**
+   * Return a list containing all of the navigation contributors that were
+   * contributed.
+   */
+  List<NavigationContributor> get navigationContributors =>
+      navigationContributorExtensionPoint.extensions;
+
   @override
   String get uniqueIdentifier => UNIQUE_IDENTIFIER;
 
@@ -183,6 +205,9 @@
         FIX_CONTRIBUTOR_EXTENSION_POINT, _validateFixContributorExtension);
     indexContributorExtensionPoint = registerExtensionPoint(
         INDEX_CONTRIBUTOR_EXTENSION_POINT, _validateIndexContributorExtension);
+    navigationContributorExtensionPoint = registerExtensionPoint(
+        NAVIGATION_CONTRIBUTOR_EXTENSION_POINT,
+        _validateNavigationContributorExtension);
   }
 
   @override
@@ -190,7 +215,8 @@
     //
     // Register analyze file functions.
     //
-    registerExtension(ANALYZE_FILE_EXTENSION_POINT_ID,
+    registerExtension(
+        ANALYZE_FILE_EXTENSION_POINT_ID,
         (File file) => AnalysisEngine.isDartFileName(file.path) ||
             AnalysisEngine.isHtmlFileName(file.path));
     //
@@ -204,6 +230,11 @@
     // TODO(brianwilkerson) Register the completion contributors.
 //    registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
     //
+    // Register navigation contributors.
+    //
+    registerExtension(NAVIGATION_CONTRIBUTOR_EXTENSION_POINT_ID,
+        new DartNavigationComputer());
+    //
     // Register domains.
     //
     String domainId = Plugin.join(UNIQUE_IDENTIFIER, DOMAIN_EXTENSION_POINT);
@@ -300,4 +331,16 @@
       throw new ExtensionError('Extensions to $id must be an IndexContributor');
     }
   }
+
+  /**
+   * Validate the given extension by throwing an [ExtensionError] if it is not a
+   * valid navigation contributor.
+   */
+  void _validateNavigationContributorExtension(Object extension) {
+    if (extension is! NavigationContributor) {
+      String id = navigationContributorExtensionPoint.uniqueIdentifier;
+      throw new ExtensionError(
+          'Extensions to $id must be an NavigationContributor');
+    }
+  }
 }
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index ea94457..ff98970 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -257,16 +257,6 @@
   return _locationForArgs(context, source, range);
 }
 
-NavigationTarget newNavigationTarget_fromElement(
-    engine.Element element, int fileToIndex(String file)) {
-  ElementKind kind = newElementKind_fromEngine(element.kind);
-  Location location = newLocation_fromElement(element);
-  String file = location.file;
-  int fileIndex = fileToIndex(file);
-  return new NavigationTarget(kind, fileIndex, location.offset, location.length,
-      location.startLine, location.startColumn);
-}
-
 /**
  * Construct based on an element from the analyzer engine.
  */
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index b3a78e6..6186079 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -16,7 +16,7 @@
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/completion_target.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
-import 'package:analysis_server/src/services/completion/import_uri_contributor.dart';
+import 'package:analysis_server/src/services/completion/uri_contributor.dart';
 import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
 import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
 import 'package:analysis_server/src/services/completion/local_reference_contributor.dart';
@@ -92,7 +92,7 @@
         new ArgListContributor(),
         new CombinatorContributor(),
         new PrefixedElementContributor(),
-        new ImportUriContributor(),
+        new UriContributor(),
       ];
     }
     if (commonUsageComputer == null) {
diff --git a/pkg/analysis_server/lib/src/services/completion/import_uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
similarity index 95%
rename from pkg/analysis_server/lib/src/services/completion/import_uri_contributor.dart
rename to pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
index 498c289..cb32012 100644
--- a/pkg/analysis_server/lib/src/services/completion/import_uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
@@ -22,12 +22,12 @@
  * A contributor for calculating uri suggestions
  * for import and part directives.
  */
-class ImportUriContributor extends DartCompletionContributor {
-  _ImportUriSuggestionBuilder builder;
+class UriContributor extends DartCompletionContributor {
+  _UriSuggestionBuilder builder;
 
   @override
   bool computeFast(DartCompletionRequest request) {
-    builder = new _ImportUriSuggestionBuilder(request);
+    builder = new _UriSuggestionBuilder(request);
     return builder.computeFast(request.target.containingNode);
   }
 
@@ -37,10 +37,10 @@
   }
 }
 
-class _ImportUriSuggestionBuilder extends SimpleAstVisitor {
+class _UriSuggestionBuilder extends SimpleAstVisitor {
   final DartCompletionRequest request;
 
-  _ImportUriSuggestionBuilder(this.request);
+  _UriSuggestionBuilder(this.request);
 
   bool computeFast(AstNode node) {
     node.accept(this);
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index 012b7a1..b22d74d 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -151,7 +151,8 @@
 
   @override
   Future<SourceChange> createChange() async {
-    change = new SourceChange(refactoringName);
+    String changeName = "$refactoringName '$oldName' to '$newName'";
+    change = new SourceChange(changeName);
     await fillChange();
     return change;
   }
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index 2d459ac..fdac6b5 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -577,6 +577,8 @@
 
   test_sourceRange_inUnit() {
     addTestFile('''
+library lib;
+/// My first class.
 class A {
 } // endA
 class B {
@@ -593,7 +595,7 @@
         expect(element.kind, ElementKind.CLASS);
         expect(element.name, "A");
         {
-          int offset = 0;
+          int offset = testCode.indexOf("/// My first class.");
           int end = testCode.indexOf(" // endA");
           expect(outline.offset, offset);
           expect(outline.length, end - offset);
diff --git a/pkg/analysis_server/test/services/completion/test_all.dart b/pkg/analysis_server/test/services/completion/test_all.dart
index d2035b8..34d49c2 100644
--- a/pkg/analysis_server/test/services/completion/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/test_all.dart
@@ -13,7 +13,6 @@
 import 'completion_computer_test.dart' as completion_computer_test;
 import 'completion_manager_test.dart' as completion_manager_test;
 import 'completion_target_test.dart' as completion_target_test;
-import 'import_uri_contributor_test.dart' as import_uri_test;
 import 'imported_reference_contributor_test.dart' as imported_test;
 import 'keyword_contributor_test.dart' as keyword_test;
 import 'local_declaration_visitor_test.dart' as local_declaration_visitor_test;
@@ -21,6 +20,7 @@
     as local_reference_contributor_test;
 import 'optype_test.dart' as optype_test;
 import 'prefixed_element_contributor_test.dart' as invocation_test;
+import 'uri_contributor_test.dart' as uri_contributor_test;
 
 /// Utility for manually running all tests.
 main() {
@@ -32,12 +32,12 @@
     completion_computer_test.main();
     completion_manager_test.main();
     completion_target_test.main();
-    import_uri_test.main();
     imported_test.main();
     invocation_test.main();
     keyword_test.main();
     local_declaration_visitor_test.main();
     local_reference_contributor_test.main();
     optype_test.main();
+    uri_contributor_test.main();
   });
 }
diff --git a/pkg/analysis_server/test/services/completion/import_uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
similarity index 97%
rename from pkg/analysis_server/test/services/completion/import_uri_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/uri_contributor_test.dart
index 527410e..9742dbd 100644
--- a/pkg/analysis_server/test/services/completion/import_uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/import_uri_contributor.dart';
+import 'package:analysis_server/src/services/completion/uri_contributor.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:path/path.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -17,15 +17,15 @@
 
 main() {
   initializeTestEnvironment();
-  defineReflectiveTests(ImportUriContributorTest);
-  defineReflectiveTests(ImportUriContributorWindowsTest);
+  defineReflectiveTests(UriContributorTest);
+  defineReflectiveTests(UriContributorWindowsTest);
 }
 
 @reflectiveTest
-class ImportUriContributorTest extends AbstractCompletionTest {
+class UriContributorTest extends AbstractCompletionTest {
   @override
   void setUpContributor() {
-    contributor = new ImportUriContributor();
+    contributor = new UriContributor();
   }
 
   test_import() {
@@ -284,10 +284,10 @@
 }
 
 @reflectiveTest
-class ImportUriContributorWindowsTest extends AbstractCompletionTest {
+class UriContributorWindowsTest extends AbstractCompletionTest {
   @override
   void setUpContributor() {
-    contributor = new ImportUriContributor();
+    contributor = new UriContributor();
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index bd316bf..eb7bacf 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -10851,7 +10851,8 @@
             }
             if (propagatedType != null) {
               overrideVariable(loopElement, propagatedType, true);
-              _recordPropagatedType(loopVariable.identifier, propagatedType);
+              recordPropagatedTypeIfBetter(
+                  loopVariable.identifier, propagatedType);
             }
           }
         } else if (identifier != null && iterable != null) {
@@ -10859,7 +10860,7 @@
           if (identifierElement is VariableElement) {
             DartType iteratorElementType = _getIteratorElementType(iterable);
             overrideVariable(identifierElement, iteratorElementType, true);
-            _recordPropagatedType(identifier, iteratorElementType);
+            recordPropagatedTypeIfBetter(identifier, iteratorElementType);
           }
         }
         visitStatementInScope(body);
@@ -11599,18 +11600,6 @@
       _propagateTrueState(condition.expression);
     }
   }
-
-  /**
-   * Record that the propagated type of the given node is the given type.
-   *
-   * @param expression the node whose type is to be recorded
-   * @param type the propagated type of the node
-   */
-  void _recordPropagatedType(Expression expression, DartType type) {
-    if (type != null && !type.isDynamic) {
-      expression.propagatedType = type;
-    }
-  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 720f8bb..bffeaad 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -303,6 +303,14 @@
     return null;
   }
 
+  @override
+  Object visitDeclaredIdentifier(DeclaredIdentifier node) {
+    super.visitDeclaredIdentifier(node);
+    if (_resolver.definingLibrary.context.analysisOptions.strongMode) {
+      _inferForEachLoopVariableType(node);
+    }
+  }
+
   /**
    * The Dart Language Specification, 12.3: <blockquote>The static type of a literal double is
    * double.</blockquote>
@@ -1181,19 +1189,6 @@
     return null;
   }
 
-  void _inferLocalVariableType(
-      VariableDeclaration node, Expression initializer) {
-    if (initializer != null &&
-        (node.parent as VariableDeclarationList).type == null &&
-        (node.element is LocalVariableElementImpl) &&
-        (initializer.staticType != null) &&
-        (!initializer.staticType.isBottom)) {
-      LocalVariableElementImpl element = node.element;
-      element.type = initializer.staticType;
-      node.name.staticType = initializer.staticType;
-    }
-  }
-
   @override
   Object visitVariableDeclaration(VariableDeclaration node) {
     Expression initializer = node.initializer;
@@ -1400,6 +1395,43 @@
     }
   }
 
+  // TODO(vsm): Use leafp's matchType here?
+  DartType _findIteratedType(InterfaceType type, DartType targetType) {
+    // Set by _find if match is found
+    DartType result = null;
+    // Elements we've already visited on a given inheritance path.
+    HashSet<ClassElement> visitedClasses = null;
+
+    bool _find(InterfaceType type) {
+      ClassElement element = type.element;
+      if (type == _typeProvider.objectType || element == null) {
+        return false;
+      }
+      if (element == targetType.element) {
+        List<DartType> typeArguments = type.typeArguments;
+        assert(typeArguments.length == 1);
+        result = typeArguments[0];
+        return true;
+      }
+      if (visitedClasses == null) {
+        visitedClasses = new HashSet<ClassElement>();
+      }
+      // Already visited this class along this path
+      if (!visitedClasses.add(element)) {
+        return false;
+      }
+      try {
+        return _find(type.superclass) ||
+            type.interfaces.any(_find) ||
+            type.mixins.any(_find);
+      } finally {
+        visitedClasses.remove(element);
+      }
+    }
+    _find(type);
+    return result;
+  }
+
   /**
    * Return the best type of the given [expression].
    */
@@ -1621,6 +1653,42 @@
     return returnType;
   }
 
+  void _inferForEachLoopVariableType(DeclaredIdentifier loopVariable) {
+    if (loopVariable != null &&
+        loopVariable.type == null &&
+        loopVariable.parent is ForEachStatement) {
+      ForEachStatement loop = loopVariable.parent;
+      if (loop.iterable != null) {
+        Expression expr = loop.iterable;
+        LocalVariableElementImpl element = loopVariable.element;
+        DartType exprType = expr.staticType;
+        if (exprType is InterfaceType) {
+          DartType targetType = (loop.awaitKeyword == null)
+              ? _typeProvider.iterableType
+              : _typeProvider.streamType;
+          DartType iteratedType = _findIteratedType(exprType, targetType);
+          if (element != null && iteratedType != null) {
+            element.type = iteratedType;
+            loopVariable.identifier.staticType = iteratedType;
+          }
+        }
+      }
+    }
+  }
+
+  void _inferLocalVariableType(
+      VariableDeclaration node, Expression initializer) {
+    if (initializer != null &&
+        (node.parent as VariableDeclarationList).type == null &&
+        (node.element is LocalVariableElementImpl) &&
+        (initializer.staticType != null) &&
+        (!initializer.staticType.isBottom)) {
+      LocalVariableElementImpl element = node.element;
+      element.type = initializer.staticType;
+      node.name.staticType = initializer.staticType;
+    }
+  }
+
   /**
    * Return `true` if the given [Type] is the `Future` form the 'dart:async'
    * library.
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 9c30594..6463a7b 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -8054,6 +8054,17 @@
   }
 
   /**
+   * @param code the code that iterates using variable "v". We check that
+   *          "v" has expected static and propagated type.
+   */
+  void _assertPropagatedIterationType(String code, DartType expectedStaticType,
+      DartType expectedPropagatedType) {
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "v in ");
+    expect(identifier.staticType, same(expectedStaticType));
+    expect(identifier.propagatedType, same(expectedPropagatedType));
+  }
+
+  /**
    * @param code the code that assigns the value to the variable "v", no matter how. We check that
    *          "v" has expected static and propagated type.
    */
@@ -13738,6 +13749,72 @@
     _assertTypeOfMarkedExpression(
         code, typeProvider.dynamicType, typeProvider.intType);
   }
+
+  void test_foreachInference_var() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  for (var v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_foreachInference_var_iterable() {
+    String code = r'''
+main() {
+  Iterable<int> list = <int>[];
+  for (var v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_foreachInference_var_stream() {
+    String code = r'''
+import 'dart:async';
+main() async {
+  Stream<int> stream = null;
+  await for (var v in stream) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(code, typeProvider.intType, null);
+    _assertTypeOfMarkedExpression(code, typeProvider.intType, null);
+  }
+
+  void test_foreachInference_dynamic_disabled() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  for (dynamic v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
+  void test_foreachInference_reusedVar_disabled() {
+    String code = r'''
+main() {
+  var list = <int>[];
+  var v;
+  for (v in list) {
+    v; // marker
+  }
+}''';
+    _assertPropagatedIterationType(
+        code, typeProvider.dynamicType, typeProvider.intType);
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index d95c3f7..f7d74f8 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -24,7 +24,7 @@
 import 'elements/visitor.dart' show ElementVisitor;
 import 'js_backend/js_backend.dart' show JavaScriptBackend;
 import 'resolution/tree_elements.dart' show TreeElements;
-import 'scanner/scannerlib.dart' show Token;
+import 'tokens/token.dart' show Token;
 import 'tree/tree.dart';
 import 'util/util.dart';
 import 'universe/universe.dart' show
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 63b112e..e715f29 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -339,6 +339,10 @@
     return true;
   }
 
+  /// Called after the queue is closed. [onQueueEmpty] may be called multiple
+  /// times, but [onQueueClosed] is only called once.
+  void onQueueClosed() {}
+
   /// Called after [element] has been resolved.
   // TODO(johnniwinther): Change [TreeElements] to [Registry] or a dependency
   // node. [elements] is currently unused by the implementation.
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 538b06d..323822b 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -112,7 +112,6 @@
 
   void registerCompileTimeConstant(ConstantValue constant) {
     backend.registerCompileTimeConstant(constant, this);
-    backend.constants.addCompileTimeConstantForEmission(constant);
   }
 
   void registerTypeVariableBoundsSubtypeCheck(DartType subtype,
@@ -146,6 +145,7 @@
 
   void registerTypeConstant(ClassElement element) {
     backend.customElementsAnalysis.registerTypeConstant(element, world);
+    backend.lookupMapAnalysis.registerTypeConstant(element);
   }
 
   void registerStaticInvocation(Element element) {
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index fad09bc..e04c88a 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -91,6 +91,11 @@
 import 'null_compiler_output.dart' show
     NullCompilerOutput,
     NullSink;
+import 'parser/diet_parser_task.dart' show
+    DietParserTask;
+import 'parser/parser_task.dart' show
+    DietParserTask,
+    ParserTask;
 import 'patch_parser.dart' show
     PatchParserTask;
 import 'resolution/registry.dart' show
@@ -99,17 +104,8 @@
     ResolverTask;
 import 'resolution/tree_elements.dart' show
     TreeElementMapping;
-import 'scanner/token_map.dart' show
-    TokenMap;
-import 'scanner/scannerlib.dart' show
-    COMMENT_TOKEN,
-    DietParserTask,
-    EOF_TOKEN,
-    ParserTask,
-    ScannerTask,
-    StringToken,
-    Token,
-    TokenPair;
+import 'scanner/scanner_task.dart' show
+    ScannerTask;
 import 'serialization/task.dart' show
     SerializationTask;
 import 'script.dart' show
@@ -118,6 +114,15 @@
     HInstruction;
 import 'tracer.dart' show
     Tracer;
+import 'tokens/token.dart' show
+    StringToken,
+    Token,
+    TokenPair;
+import 'tokens/token_constants.dart' as Tokens show
+    COMMENT_TOKEN,
+    EOF_TOKEN;
+import 'tokens/token_map.dart' show
+    TokenMap;
 import 'tree/tree.dart' show
     Node;
 import 'typechecker.dart' show
@@ -1235,6 +1240,7 @@
     }
     emptyQueue(world);
     world.queueIsClosed = true;
+    backend.onQueueClosed();
     assert(compilationFailed || world.checkNoEnqueuedInvokedInstanceMethods());
   }
 
@@ -1520,10 +1526,10 @@
   Token processAndStripComments(Token currentToken) {
     Token firstToken = currentToken;
     Token prevToken;
-    while (currentToken.kind != EOF_TOKEN) {
-      if (identical(currentToken.kind, COMMENT_TOKEN)) {
+    while (currentToken.kind != Tokens.EOF_TOKEN) {
+      if (identical(currentToken.kind, Tokens.COMMENT_TOKEN)) {
         Token firstCommentToken = currentToken;
-        while (identical(currentToken.kind, COMMENT_TOKEN)) {
+        while (identical(currentToken.kind, Tokens.COMMENT_TOKEN)) {
           currentToken = currentToken.next;
         }
         commentMap[currentToken] = firstCommentToken;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 9bdb9ea..a9190dd 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -33,19 +33,19 @@
 ///
 /// If `condition` is true then invoke `cont1`, else `cont2`.
 ///
-///   cps.ifTrue(condition).invokeContinuation(cont1, []);
+///   cps.ifTruthy(condition).invokeContinuation(cont1, []);
 ///   cps.invokeContinuation(cont2, []);
 ///
 /// If `condition` is true then invoke `cont` with a bound primitive:
 ///
-///   CpsFragment branch = cps.ifTrue(condition);
+///   CpsFragment branch = cps.ifTruthy(condition);
 ///   branch.invokeContinuation(cont, [branch.letPrim(arg)]);
 ///
 /// Loop and call a method until it returns false:
 ///
 ///   Continuation loop = cps.beginLoop();
 ///   var result = cps.invokeMethod(receiver, selector, ...);
-///   cps.ifFalse(result).invokeContinuation(exit, []);
+///   cps.ifFalsy(result).invokeContinuation(exit, []);
 ///   cps.continueLoop(loop);
 ///
 class CpsFragment {
@@ -198,11 +198,11 @@
   /// Returns a new fragment for the 'then' branch.
   ///
   /// The 'else' branch becomes the new hole.
-  CpsFragment ifTrue(Primitive condition) {
+  CpsFragment ifTruthy(Primitive condition) {
     Continuation trueCont = new Continuation(<Parameter>[]);
     Continuation falseCont = new Continuation(<Parameter>[]);
     put(new LetCont.two(trueCont, falseCont,
-            new Branch(new IsTrue(condition), trueCont, falseCont)));
+            new Branch.loose(condition, trueCont, falseCont)));
     context = falseCont;
     return new CpsFragment(sourceInformation, trueCont);
   }
@@ -212,11 +212,11 @@
   /// Returns a new fragment for the 'else' branch.
   ///
   /// The 'then' branch becomes the new hole.
-  CpsFragment ifFalse(Primitive condition) {
+  CpsFragment ifFalsy(Primitive condition) {
     Continuation trueCont = new Continuation(<Parameter>[]);
     Continuation falseCont = new Continuation(<Parameter>[]);
     put(new LetCont.two(trueCont, falseCont,
-            new Branch(new IsTrue(condition), trueCont, falseCont)));
+            new Branch.loose(condition, trueCont, falseCont)));
     context = trueCont;
     return new CpsFragment(sourceInformation, falseCont);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index f97d15e..e4cb699 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -773,9 +773,9 @@
     elseContinuation.body = elseBuilder._root;
     add(new ir.LetCont(join.continuation,
             new ir.LetCont.two(thenContinuation, elseContinuation,
-                new ir.Branch(new ir.IsTrue(condition),
-                              thenContinuation,
-                              elseContinuation))));
+                new ir.Branch.strict(condition,
+                                     thenContinuation,
+                                     elseContinuation))));
     environment = join.environment;
     return environment.discard(1);
   }
@@ -1117,9 +1117,9 @@
 
     ir.Expression result =
         new ir.LetCont.many(arms,
-            new ir.Branch(new ir.IsTrue(condition),
-                          thenContinuation,
-                          elseContinuation));
+            new ir.Branch.strict(condition,
+                                 thenContinuation,
+                                 elseContinuation));
 
     JumpCollector join;  // Null if there is no join.
     if (thenBuilder.isOpen && elseBuilder.isOpen) {
@@ -1288,9 +1288,9 @@
     // be filled by LetCont.plug.
     ir.LetCont branch =
         new ir.LetCont.two(exitContinuation, bodyContinuation,
-            new ir.Branch(new ir.IsTrue(condition),
-                          bodyContinuation,
-                          exitContinuation));
+            new ir.Branch.strict(condition,
+                                 bodyContinuation,
+                                 exitContinuation));
     // If there are breaks in the body, then there must be a join-point
     // continuation for the normal exit and the breaks.  Otherwise, the
     // successor is translated in the hole in the exit continuation.
@@ -1449,9 +1449,9 @@
     // be filled by LetCont.plug.
     ir.LetCont branch =
         new ir.LetCont.two(exitContinuation, bodyContinuation,
-            new ir.Branch(new ir.IsTrue(condition),
-                          bodyContinuation,
-                          exitContinuation));
+            new ir.Branch.strict(condition,
+                                 bodyContinuation,
+                                 exitContinuation));
     // If there are breaks in the body, then there must be a join-point
     // continuation for the normal exit and the breaks.  Otherwise, the
     // successor is translated in the hole in the exit continuation.
@@ -1524,9 +1524,9 @@
     // be filled by LetCont.plug.
     ir.LetCont branch =
         new ir.LetCont.two(exitContinuation, bodyContinuation,
-            new ir.Branch(new ir.IsTrue(condition),
-                          bodyContinuation,
-                          exitContinuation));
+            new ir.Branch.strict(condition,
+                                 bodyContinuation,
+                                 exitContinuation));
     // If there are breaks in the body, then there must be a join-point
     // continuation for the normal exit and the breaks.  Otherwise, the
     // successor is translated in the hole in the exit continuation.
@@ -1610,9 +1610,9 @@
 
     continueBuilder.add(
         new ir.LetCont.two(exitContinuation, repeatContinuation,
-            new ir.Branch(new ir.IsTrue(condition),
-                          repeatContinuation,
-                          exitContinuation)));
+            new ir.Branch.strict(condition,
+                                 repeatContinuation,
+                                 exitContinuation)));
     continueCollector.continuation.body = continueBuilder._root;
 
     // Construct the loop continuation (i.e., the body and condition).
@@ -1676,9 +1676,9 @@
       // else continuation first.
       casesBuilder.add(
           new ir.LetCont.two(elseContinuation, thenContinuation,
-              new ir.Branch(new ir.IsTrue(condition),
-                            thenContinuation,
-                            elseContinuation)));
+              new ir.Branch.strict(condition,
+                                   thenContinuation,
+                                   elseContinuation)));
     }
 
     if (defaultCase != null) {
@@ -1883,9 +1883,9 @@
                 clause.type,
                 isTypeTest: true);
         checkBuilder.add(new ir.LetCont.two(thenContinuation, elseContinuation,
-                new ir.Branch(new ir.IsTrue(typeMatches),
-                    thenContinuation,
-                    elseContinuation)));
+            new ir.Branch.strict(typeMatches,
+                                 thenContinuation,
+                                 elseContinuation)));
         catchBody = checkBuilder._root;
       }
       builder.add(catchBody);
@@ -2232,9 +2232,9 @@
 
     add(new ir.LetCont(joinContinuation,
           new ir.LetCont.two(thenContinuation, elseContinuation,
-              new ir.Branch(new ir.IsTrue(condition),
-                            thenContinuation,
-                            elseContinuation))));
+              new ir.Branch.strict(condition,
+                                   thenContinuation,
+                                   elseContinuation))));
     return resultParameter;
   }
 
@@ -2292,9 +2292,9 @@
     // The right subexpression has two continuations.
     rightBuilder.add(
         new ir.LetCont.two(rightTrueContinuation, rightFalseContinuation,
-            new ir.Branch(new ir.IsTrue(rightValue),
-                          rightTrueContinuation,
-                          rightFalseContinuation)));
+            new ir.Branch.strict(rightValue,
+                                 rightTrueContinuation,
+                                 rightFalseContinuation)));
     // Depending on the operator, the left subexpression's continuations are
     // either the right subexpression or an invocation of the join-point
     // continuation.
@@ -2308,9 +2308,9 @@
 
     add(new ir.LetCont(join.continuation,
             new ir.LetCont.two(leftTrueContinuation, leftFalseContinuation,
-                new ir.Branch(new ir.IsTrue(leftValue),
-                              leftTrueContinuation,
-                              leftFalseContinuation))));
+                new ir.Branch.strict(leftValue,
+                                     leftTrueContinuation,
+                                     leftFalseContinuation))));
     environment = join.environment;
     return environment.discard(1);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 24938d4..b685c45 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -654,29 +654,36 @@
   accept(Visitor visitor) => visitor.visitInvokeContinuation(this);
 }
 
-/// The base class of things which can be tested and branched on.
-abstract class Condition extends Node {
-}
-
-class IsTrue extends Condition {
-  final Reference<Primitive> value;
-
-  IsTrue(Primitive val) : value = new Reference<Primitive>(val);
-
-  accept(Visitor visitor) => visitor.visitIsTrue(this);
-}
-
 /// Choose between a pair of continuations based on a condition value.
 ///
 /// The two continuations must not declare any parameters.
 class Branch extends TailExpression {
-  final Condition condition;
+  final Reference<Primitive> condition;
   final Reference<Continuation> trueContinuation;
   final Reference<Continuation> falseContinuation;
 
-  Branch(this.condition, Continuation trueCont, Continuation falseCont)
-      : trueContinuation = new Reference<Continuation>(trueCont),
-        falseContinuation = new Reference<Continuation>(falseCont);
+  /// If true, only the value `true` satisfies the condition. Otherwise, any
+  /// truthy value satisfies the check.
+  ///
+  /// Non-strict checks are preferable when the condition is known to be a
+  /// boolean.
+  bool isStrictCheck;
+
+  Branch.strict(Primitive condition,
+                Continuation trueCont,
+                Continuation falseCont)
+      : this.condition = new Reference<Primitive>(condition),
+        trueContinuation = new Reference<Continuation>(trueCont),
+        falseContinuation = new Reference<Continuation>(falseCont),
+        isStrictCheck = true;
+
+  Branch.loose(Primitive condition,
+               Continuation trueCont,
+               Continuation falseCont)
+      : this.condition = new Reference<Primitive>(condition),
+        trueContinuation = new Reference<Continuation>(trueCont),
+        falseContinuation = new Reference<Continuation>(falseCont),
+        this.isStrictCheck = false;
 
   accept(Visitor visitor) => visitor.visitBranch(this);
 }
@@ -716,6 +723,8 @@
 
   bool get isSafeForElimination => objectIsNotNull;
   bool get isSafeForReordering => false;
+
+  toString() => 'GetField($field)';
 }
 
 /// Get the length of a string or native list.
@@ -865,6 +874,8 @@
 
   bool get isSafeForElimination => true;
   bool get isSafeForReordering => true;
+
+  toString() => 'CreateInstance($classElement)';
 }
 
 class Interceptor extends Primitive {
@@ -1191,9 +1202,6 @@
   T visitGetIndex(GetIndex node);
   T visitSetIndex(SetIndex node);
 
-  // Conditions.
-  T visitIsTrue(IsTrue node);
-
   // Support for literal foreign code.
   T visitForeignCode(ForeignCode node);
 }
@@ -1201,9 +1209,6 @@
 /// Visits all non-recursive children of a CPS term, i.e. anything
 /// not of type [Expression] or [Continuation].
 ///
-/// Note that the non-recursive nodes can contain other nodes inside of them,
-/// e.g. [Branch] contains an [IsTrue] which contains a [Reference].
-///
 /// The `process*` methods are called in pre-order for every node visited.
 /// These can be overridden without disrupting the visitor traversal.
 class LeafVisitor implements Visitor {
@@ -1300,7 +1305,7 @@
     processBranch(node);
     processReference(node.trueContinuation);
     processReference(node.falseContinuation);
-    visit(node.condition);
+    processReference(node.condition);
   }
 
   processTypeCast(TypeCast node) {}
@@ -1379,12 +1384,6 @@
     node.parameters.forEach(visitParameter);
   }
 
-  processIsTrue(IsTrue node) {}
-  visitIsTrue(IsTrue node) {
-    processIsTrue(node);
-    processReference(node.value);
-  }
-
   processInterceptor(Interceptor node) {}
   visitInterceptor(Interceptor node) {
     processInterceptor(node);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index a04fb4e..988ee69 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -192,10 +192,11 @@
   }
 
   String visitBranch(Branch node) {
-    String condition = visit(node.condition);
+    String condition = access(node.condition);
     String trueCont = access(node.trueContinuation);
     String falseCont = access(node.falseContinuation);
-    return '$indentation(Branch $condition $trueCont $falseCont)';
+    String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
+    return '$indentation(Branch $condition $trueCont $falseCont $strict)';
   }
 
   String visitUnreachable(Unreachable node) {
@@ -251,11 +252,6 @@
     return '(LiteralMap ($keys) ($values))';
   }
 
-  String visitIsTrue(IsTrue node) {
-    String value = access(node.value);
-    return '(IsTrue $value)';
-  }
-
   String visitSetField(SetField node) {
     String object = access(node.object);
     String field = node.field.name;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index c802aa6..ecbe343 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -227,10 +227,11 @@
 
   visitBranch(cps_ir.Branch node) {
     String dummy = names.name(node);
-    String condition = visit(node.condition);
+    String condition = formatReference(node.condition);
     String trueCont = formatReference(node.trueContinuation);
     String falseCont = formatReference(node.falseContinuation);
-    printStmt(dummy, "Branch $condition ($trueCont, $falseCont)");
+    String strict = node.isStrictCheck ? "Strict" : "NonStrict";
+    printStmt(dummy, "Branch $condition ($trueCont, $falseCont) $strict");
   }
 
   visitSetMutable(cps_ir.SetMutable node) {
@@ -266,10 +267,6 @@
     return "Continuation ${names.name(node)}";
   }
 
-  visitIsTrue(cps_ir.IsTrue node) {
-    return "IsTrue(${names.name(node.value.definition)})";
-  }
-
   visitSetField(cps_ir.SetField node) {
     String object = formatReference(node.object);
     String field = node.field.name;
@@ -607,10 +604,6 @@
     unexpectedNode(node);
   }
 
-  visitIsTrue(cps_ir.IsTrue node) {
-    unexpectedNode(node);
-  }
-
   visitInterceptor(cps_ir.Interceptor node) {
     unexpectedNode(node);
   }
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 9a6d2a7..11c9fae 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -8,6 +8,7 @@
 import '../constants/values.dart';
 
 export 'type_propagation.dart' show TypePropagator;
+export 'scalar_replacement.dart' show ScalarReplacer;
 export 'redundant_phi.dart' show RedundantPhiEliminator;
 export 'redundant_join.dart' show RedundantJoinEliminator;
 export 'shrinking_reductions.dart' show ShrinkingReducer, ParentVisitor;
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_join.dart b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
index 2a1a584..4acb2ef 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -94,8 +94,7 @@
     // enclosing continuation.
     // Note: Do not use the parent pointer for this check, because parameters
     // are temporarily shared between different continuations during this pass.
-    IsTrue isTrue = branch.condition;
-    Primitive condition = isTrue.value.definition;
+    Primitive condition = branch.condition.definition;
     int parameterIndex = branchCont.parameters.indexOf(condition);
     if (parameterIndex == -1) return;
 
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
new file mode 100644
index 0000000..114d8a0
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -0,0 +1,251 @@
+// 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 'optimizers.dart';
+
+import 'dart:collection' show Queue;
+
+import '../closure.dart' show
+    ClosureClassElement, Identifiers;
+import '../common/names.dart' show
+    Selectors, Identifiers;
+import '../compiler.dart' as dart2js show
+    Compiler;
+import '../constants/constant_system.dart';
+import '../constants/values.dart';
+import '../dart_types.dart' as types;
+import '../diagnostics/invariant.dart' as dart2js show
+    InternalErrorFunction;
+import '../elements/elements.dart';
+import '../io/source_information.dart' show SourceInformation;
+import '../resolution/access_semantics.dart';
+import '../resolution/operators.dart';
+import '../resolution/send_structure.dart';
+import '../tree/tree.dart' as ast;
+import '../types/types.dart';
+import '../types/constants.dart' show computeTypeMask;
+import '../universe/universe.dart';
+import '../world.dart' show World;
+import 'cps_fragment.dart';
+import 'cps_ir_nodes.dart';
+import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier;
+
+/**
+ * Replaces aggregates with a set of local values.  Performs inlining of
+ * single-use closures to generate more replacable aggregates.
+ */
+class ScalarReplacer extends Pass {
+  String get passName => 'Scalar replacement';
+
+  final dart2js.InternalErrorFunction _internalError;
+
+  ScalarReplacer(dart2js.Compiler compiler)
+      : _internalError = compiler.internalError;
+
+  @override
+  void rewrite(FunctionDefinition root) {
+    // Set all parent pointers.
+    new ParentVisitor().visit(root);
+    ScalarReplacementVisitor analyzer =
+        new ScalarReplacementVisitor(_internalError);
+    analyzer.analyze(root);
+    analyzer.process();
+  }
+}
+
+/**
+ * Do scalar replacement of aggregates on instances. Since scalar replacement
+ * can create new candidiates, iterate until all scalar replacements are done.
+ */
+class ScalarReplacementVisitor extends RecursiveVisitor {
+
+  final dart2js.InternalErrorFunction internalError;
+  ScalarReplacementRemovalVisitor removalVisitor;
+
+  Primitive _current = null;
+  Set<Primitive> _allocations = new Set<Primitive>();
+  Queue<Primitive> _queue = new Queue<Primitive>();
+
+  ScalarReplacementVisitor(this.internalError) {
+    removalVisitor = new ScalarReplacementRemovalVisitor(this);
+  }
+
+  void analyze(FunctionDefinition root) {
+    visit(root);
+  }
+
+  void process() {
+    while (_queue.isNotEmpty) {
+      Primitive allocation = _queue.removeFirst();
+      _allocations.remove(allocation);
+      _current = allocation;
+      tryScalarReplacement(allocation);
+    }
+  }
+
+  void tryScalarReplacement(Primitive allocation) {
+
+    // We can do scalar replacement of an aggregate if all uses of an allocation
+    // are reads or writes.
+    for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+      Node use = ref.parent;
+      if (use is GetField) continue;
+      if (use is SetField && use.object == ref) continue;
+      return;
+    }
+
+    Set<FieldElement> reads = new Set<FieldElement>();
+    Set<FieldElement> writes = new Set<FieldElement>();
+    for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+      Node use = ref.parent;
+      if (use is GetField) {
+        reads.add(use.field);
+      } else if (use is SetField) {
+        writes.add(use.field);
+      } else {
+        assert(false);
+      }
+    }
+
+    // Find the initial values of the fields. A CreateBox has no initial
+    // values. CreateInstance has initial values in the order of the fields.
+    Map<FieldElement, Primitive> fieldInitialValues =
+        <FieldElement, Primitive>{};
+    if (allocation is CreateInstance) {
+      int i = 0;
+      allocation.classElement.forEachInstanceField(
+        (ClassElement enclosingClass, FieldElement field) {
+          Primitive argument = allocation.arguments[i++].definition;
+          fieldInitialValues[field] = argument;
+        });
+    }
+
+    // Create [MutableVariable]s for each written field. Initialize the
+    // MutableVariable with the value from the allocator, or initialize with a
+    // `null` constant if there is not initial value.
+    Map<FieldElement, MutableVariable> cells =
+        <FieldElement, MutableVariable>{};
+    InteriorNode insertionPoint = allocation.parent;  // LetPrim
+    for (FieldElement field in writes) {
+      MutableVariable variable = new MutableVariable(field);
+      cells[field] = variable;
+      Primitive initialValue = fieldInitialValues[field];
+      if (initialValue == null) {
+        assert(allocation is CreateBox);
+        initialValue = new Constant(new NullConstantValue());
+        LetPrim let = new LetPrim(initialValue);
+        let.primitive.parent = let;
+        insertionPoint = insertAtBody(insertionPoint, let);
+      }
+      LetMutable let = new LetMutable(variable, initialValue);
+      let.value.parent = let;
+      insertionPoint = insertAtBody(insertionPoint, let);
+    }
+
+    // Replace references with MutableVariable operations or references to the
+    // field's value.
+    for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) {
+      Node use = ref.parent;
+      if (use is GetField) {
+        GetField getField = use;
+        MutableVariable variable = cells[getField.field];
+        if (variable != null) {
+          GetMutable getter = new GetMutable(variable);
+          getter.variable.parent = getter;
+          getter.substituteFor(getField);
+          replacePrimitive(getField, getter);
+          deletePrimitive(getField);
+        } else {
+          Primitive value = fieldInitialValues[getField.field];
+          value.substituteFor(getField);
+          deleteLetPrimOf(getField);
+        }
+      } else if (use is SetField && use.object == ref) {
+        SetField setField = use;
+        MutableVariable variable = cells[setField.field];
+        Primitive value = setField.value.definition;
+        SetMutable setter = new SetMutable(variable, value);
+        setter.variable.parent = setter;
+        setter.value.parent = setter;
+        setter.substituteFor(setField);
+        replacePrimitive(setField, setter);
+        deletePrimitive(setField);
+      } else {
+        assert(false);
+      }
+    }
+
+    // Delete [allocation] since that might 'free' another scalar replacement
+    // candidate by deleting the last non-field-access.
+    deleteLetPrimOf(allocation);
+  }
+
+  InteriorNode insertAtBody(
+      InteriorNode insertionPoint, InteriorExpression let) {
+    let.parent = insertionPoint;
+    let.body = insertionPoint.body;
+    let.body.parent = let;
+    insertionPoint.body = let;
+    return let;
+  }
+
+  /// Replaces [old] with [primitive] in [old]'s parent [LetPrim].
+  void replacePrimitive(Primitive old, Primitive primitive) {
+    LetPrim letPrim = old.parent;
+    letPrim.primitive = primitive;
+  }
+
+  void deleteLetPrimOf(Primitive primitive) {
+    assert(primitive.hasNoUses);
+    LetPrim letPrim = primitive.parent;
+    Node child = letPrim.body;
+    InteriorNode parent = letPrim.parent;
+    child.parent = parent;
+    parent.body  = child;
+
+    deletePrimitive(primitive);
+  }
+
+  void deletePrimitive(Primitive primitive) {
+    assert(primitive.hasNoUses);
+    removalVisitor.visit(primitive);
+  }
+
+  void reconsider(Definition node) {
+    if (node is CreateInstance || node is CreateBox) {
+      if (node == _current) return;
+      enqueue(node);
+    }
+  }
+
+  void enqueue(Primitive node) {
+    assert(node is CreateInstance || node is CreateBox);
+    if (_allocations.contains(node)) return;
+    _allocations.add(node);
+    _queue.add(node);
+  }
+
+  // -------------------------- Visitor overrides ------------------------------
+  void visitCreateInstance(CreateInstance node) {
+    enqueue(node);
+  }
+
+  void visitCreateBox(CreateBox node) {
+    enqueue(node);
+  }
+}
+
+
+/// Visit a just-deleted subterm and unlink all [Reference]s in it.  Reconsider
+/// allocations for scalar replacement.
+class ScalarReplacementRemovalVisitor extends RecursiveVisitor {
+  ScalarReplacementVisitor process;
+
+  ScalarReplacementRemovalVisitor(this.process);
+
+  processReference(Reference reference) {
+    process.reconsider(reference.definition);
+    reference.unlink();
+  }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index 1c85d15..011af0f 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -610,10 +610,6 @@
     });
   }
 
-  processIsTrue(IsTrue node) {
-    node.value.parent = node;
-  }
-
   processInterceptor(Interceptor node) {
     node.input.parent = node;
   }
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 1cc1b97..3212f94 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -4,8 +4,10 @@
 
 import 'optimizers.dart';
 
+import '../closure.dart' show
+    ClosureClassElement, Identifiers;
 import '../common/names.dart' show
-    Selectors;
+    Selectors, Identifiers;
 import '../compiler.dart' as dart2js show
     Compiler;
 import '../constants/constant_system.dart';
@@ -27,6 +29,7 @@
 import '../world.dart' show World;
 import 'cps_fragment.dart';
 import 'cps_ir_nodes.dart';
+import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier;
 
 enum AbstractBool {
   True, False, Maybe, Nothing
@@ -262,6 +265,11 @@
     }
     return AbstractBool.Maybe;
   }
+
+  AbstractBool strictBoolify(TypeMask type) {
+    if (areDisjoint(type, boolType)) return AbstractBool.False;
+    return AbstractBool.Maybe;
+  }
 }
 
 class ConstantPropagationLattice {
@@ -534,6 +542,15 @@
     return typeSystem.boolify(value.type);
   }
 
+  /// Returns whether [value] is the value `true`.
+  AbstractBool strictBoolify(AbstractValue value) {
+    if (value.isNothing) return AbstractBool.Nothing;
+    if (value.isConstant) {
+      return value.constant.isTrue ? AbstractBool.True : AbstractBool.False;
+    }
+    return typeSystem.strictBoolify(value.type);
+  }
+
   /// The possible return types of a method that may be targeted by
   /// [typedSelector]. If the given selector is not a [TypedSelector], any
   /// reachable method matching the selector may be targeted.
@@ -822,11 +839,17 @@
   void visitBranch(Branch node) {
     Continuation trueCont = node.trueContinuation.definition;
     Continuation falseCont = node.falseContinuation.definition;
-    IsTrue conditionNode = node.condition;
-    Primitive condition = conditionNode.value.definition;
-
+    Primitive condition = node.condition.definition;
     AbstractValue conditionValue = getValue(condition);
-    AbstractBool boolifiedValue = lattice.boolify(conditionValue);
+
+    // Change to non-strict check if the condition is a boolean or null.
+    if (lattice.isDefinitelyBool(conditionValue, allowNull: true)) {
+      node.isStrictCheck = false;
+    }
+
+    AbstractBool boolifiedValue = node.isStrictCheck
+        ? lattice.strictBoolify(conditionValue)
+        : lattice.boolify(conditionValue);
 
     if (boolifiedValue == AbstractBool.True) {
       replaceSubtree(falseCont.body, new Unreachable());
@@ -856,12 +879,12 @@
         //   if (x == null) S1 else S2
         //     =>
         //   if (x) S2 else S1   (note the swapped branches)
-        Branch branch = new Branch(new IsTrue(leftArg), falseCont, trueCont);
+        Branch branch = new Branch.loose(leftArg, falseCont, trueCont);
         replaceSubtree(node, branch);
         return;
       } else if (left.isNullConstant &&
                  lattice.isDefinitelyNotNumStringBool(right)) {
-        Branch branch = new Branch(new IsTrue(rightArg), falseCont, trueCont);
+        Branch branch = new Branch.loose(rightArg, falseCont, trueCont);
         replaceSubtree(node, branch);
         return;
       } else if (right.isTrueConstant &&
@@ -870,12 +893,12 @@
         //   if (x == true) S1 else S2
         //     =>
         //   if (x) S1 else S2
-        Branch branch = new Branch(new IsTrue(leftArg), trueCont, falseCont);
+        Branch branch = new Branch.loose(leftArg, trueCont, falseCont);
         replaceSubtree(node, branch);
         return;
       } else if (left.isTrueConstant &&
                  lattice.isDefinitelyBool(right, allowNull: true)) {
-        Branch branch = new Branch(new IsTrue(rightArg), trueCont, falseCont);
+        Branch branch = new Branch.loose(rightArg, trueCont, falseCont);
         replaceSubtree(node, branch);
         return;
       }
@@ -1074,11 +1097,11 @@
     Primitive isTooSmall = cps.applyBuiltin(
         BuiltinOperator.NumLt,
         <Primitive>[index, cps.makeZero()]);
-    cps.ifTrue(isTooSmall).invokeContinuation(fail);
+    cps.ifTruthy(isTooSmall).invokeContinuation(fail);
     Primitive isTooLarge = cps.applyBuiltin(
         BuiltinOperator.NumGe,
         <Primitive>[index, cps.letPrim(new GetLength(list))]);
-    cps.ifTrue(isTooLarge).invokeContinuation(fail);
+    cps.ifTruthy(isTooLarge).invokeContinuation(fail);
     cps.insideContinuation(fail).invokeStaticThrower(
         backend.getThrowIndexOutOfBoundsError(),
         <Primitive>[list, index]);
@@ -1097,7 +1120,7 @@
     Primitive lengthChanged = cps.applyBuiltin(
         BuiltinOperator.StrictNeq,
         <Primitive>[originalLength, cps.letPrim(new GetLength(list))]);
-    cps.ifTrue(lengthChanged).invokeStaticThrower(
+    cps.ifTruthy(lengthChanged).invokeStaticThrower(
         backend.getThrowConcurrentModificationError(),
         <Primitive>[list]);
     return cps;
@@ -1405,7 +1428,7 @@
                 [cps.getMutable(index), cps.letPrim(new GetLength(list))]);
 
             // Return false if there are no more.
-            CpsFragment falseBranch = cps.ifFalse(hasMore);
+            CpsFragment falseBranch = cps.ifFalsy(hasMore);
             falseBranch
               ..setMutable(current, falseBranch.makeNull())
               ..invokeContinuation(useCont, [falseBranch.makeFalse()]);
@@ -1574,6 +1597,70 @@
     return false;
   }
 
+  /// Inlines a single-use closure if it leaves the closure object with only
+  /// field accesses.  This is optimized later by [ScalarReplacer].
+  bool specializeSingleUseClosureCall(InvokeMethod node) {
+    Selector call = node.selector;
+    if (!call.isClosureCall) return false;
+
+    assert(!isInterceptedSelector(call));
+    assert(call.argumentCount == node.arguments.length);
+
+    Primitive receiver = node.receiver.definition;
+    if (receiver is !CreateInstance) return false;
+    CreateInstance createInstance = receiver;
+    if (!createInstance.hasExactlyOneUse) return false;
+
+    // Inline only closures. This avoids inlining the 'call' method of a class
+    // that has many allocation sites.
+    if (createInstance.classElement is !ClosureClassElement) return false;
+
+    ClosureClassElement closureClassElement = createInstance.classElement;
+    Element element = closureClassElement.localLookup(Identifiers.call);
+
+    if (element == null || !element.isFunction) return false;
+    FunctionElement functionElement = element;
+    if (functionElement.asyncMarker != AsyncMarker.SYNC) return false;
+
+    if (!call.signatureApplies(functionElement)) return false;
+    // Inline only for exact match.
+    // TODO(sra): Handle call with defaulted arguments.
+    Selector targetSelector = new Selector.fromElement(functionElement);
+    if (call.callStructure != targetSelector.callStructure) return false;
+
+    FunctionDefinition target =
+        functionCompiler.compileToCpsIR(functionElement);
+
+    // Accesses to closed-over values are field access primitives.  We we don't
+    // inline if there are other uses of 'this' since that could be an escape or
+    // a recursive call.
+    for (Reference ref = target.thisParameter.firstRef;
+         ref != null;
+         ref = ref.next) {
+      Node use = ref.parent;
+      if (use is GetField) continue;
+      // Closures do not currently have writable fields, but closure conversion
+      // could esily be changed to allocate some cells in a closure object.
+      if (use is SetField && ref == use.object) continue;
+      return false;
+    }
+
+    // Don't inline if [target] contains try-catch or try-finally. JavaScript
+    // engines typically do poor optimization of the entire function containing
+    // the 'try'.
+    if (ContainsTry.analyze(target)) return false;
+
+    node.receiver.definition.substituteFor(target.thisParameter);
+    for (int i = 0; i < node.arguments.length; ++i) {
+      node.arguments[i].definition.substituteFor(target.parameters[i]);
+    }
+    node.continuation.definition.substituteFor(target.returnContinuation);
+
+    replaceSubtree(node, target.body);
+    push(target.body);
+    return true;
+  }
+
   /// Side-effect free expressions with constant results are be replaced by:
   ///
   ///    (LetPrim p = constant (InvokeContinuation k p)).
@@ -1598,6 +1685,7 @@
     if (specializeFieldAccess(node)) return;
     if (specializeIndexableAccess(node)) return;
     if (specializeArrayAccess(node)) return;
+    if (specializeSingleUseClosureCall(node)) return;
     if (specializeClosureCall(node)) return;
 
     AbstractValue receiver = getValue(node.receiver.definition);
@@ -2415,9 +2503,10 @@
   }
 
   void visitBranch(Branch node) {
-    IsTrue isTrue = node.condition;
-    AbstractValue conditionCell = getValue(isTrue.value.definition);
-    AbstractBool boolifiedValue = lattice.boolify(conditionCell);
+    AbstractValue conditionCell = getValue(node.condition.definition);
+    AbstractBool boolifiedValue = node.isStrictCheck
+        ? lattice.strictBoolify(conditionCell)
+        : lattice.boolify(conditionCell);
     switch (boolifiedValue) {
       case AbstractBool.Nothing:
         break;
@@ -2545,11 +2634,6 @@
     setValue(returnValue, nonConstant(typeSystem.getFieldType(node.element)));
   }
 
-  void visitIsTrue(IsTrue node) {
-    Branch branch = node.parent;
-    visitBranch(branch);
-  }
-
   void visitInterceptor(Interceptor node) {
     push(node.input.definition);
     AbstractValue value = getValue(node.input.definition);
@@ -2753,3 +2837,25 @@
     values.remove(node.variable);
   }
 }
+
+
+class ContainsTry extends RecursiveVisitor {
+  bool _found = false;
+  ContainsTry._();
+
+  /// Scans [root] for evidence of try-catch and try-finally.
+  static bool analyze(Node root) {
+    ContainsTry visitor = new ContainsTry._();
+    visitor.visit(root);
+    return visitor._found;
+  }
+
+  visit(Node node) {
+    if (_found) return;  // Early exit if we know the answer.
+    super.visit(node);
+  }
+
+  processLetHandler(LetHandler node) {
+    _found = true;
+  }
+}
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
index a004418..d215de3 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
@@ -11,8 +11,11 @@
 import '../elements/elements.dart' as elements;
 import '../resolution/tree_elements.dart' show
     TreeElementMapping;
+import '../tokens/token.dart';
+import '../tokens/token_constants.dart';
+import '../tokens/precedence.dart';
+import '../tokens/precedence_constants.dart';
 import '../tree/tree.dart' as tree;
-import '../scanner/scannerlib.dart';
 import '../util/util.dart';
 import 'backend_ast_nodes.dart';
 import 'backend_ast_emitter.dart' show TypeGenerator;
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 6757353..2e754f8 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -49,13 +49,8 @@
 import '../resolution/tree_elements.dart' show
     TreeElements,
     TreeElementMapping;
-import '../scanner/scannerlib.dart' show
-    StringToken,
-    Keyword,
-    OPEN_PAREN_INFO,
-    CLOSE_PAREN_INFO,
-    SEMICOLON_INFO,
-    IDENTIFIER_INFO;
+import '../tokens/keyword.dart' show
+    Keyword;
 import '../tree/tree.dart';
 import '../universe/universe.dart' show
     Selector,
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index b8f6d3c..99aa824 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -63,11 +63,14 @@
 
 library dart2js.messages;
 
+import '../tokens/token.dart' show
+    ErrorToken,
+    Token;
+
 import 'invariant.dart' show
     invariant;
 import 'spannable.dart' show
     CURRENT_ELEMENT_SPANNABLE;
-import '../scanner/scannerlib.dart';
 
 const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
 
diff --git a/pkg/compiler/lib/src/diagnostics/source_span.dart b/pkg/compiler/lib/src/diagnostics/source_span.dart
index 9fe080c..95c3c75 100644
--- a/pkg/compiler/lib/src/diagnostics/source_span.dart
+++ b/pkg/compiler/lib/src/diagnostics/source_span.dart
@@ -4,7 +4,7 @@
 
 library dart2js.diagnostics.source_span;
 
-import '../scanner/scannerlib.dart' show
+import '../tokens/token.dart' show
     Token;
 import '../tree/tree.dart' show
     Node;
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 78c8b45..219349b 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -21,11 +21,11 @@
 import '../resolution/tree_elements.dart' show
     TreeElements;
 import '../ordered_typeset.dart' show OrderedTypeSet;
-import '../scanner/scannerlib.dart' show
+import '../script.dart';
+import '../tokens/token.dart' show
     Token,
     isUserDefinableOperator,
     isMinusOperator;
-import '../script.dart';
 import '../tree/tree.dart';
 import '../util/characters.dart' show $_;
 import '../util/util.dart';
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 33410f7..6574231 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -35,11 +35,12 @@
     TreeElements;
 import '../resolution/typedefs.dart' show
     TypedefCyclicVisitor;
-import '../scanner/scannerlib.dart' show
-    EOF_TOKEN,
+import '../script.dart';
+import '../tokens/token.dart' show
     ErrorToken,
     Token;
-import '../script.dart';
+import '../tokens/token_constants.dart' as Tokens show
+    EOF_TOKEN;
 import '../tree/tree.dart';
 import '../util/util.dart';
 
@@ -138,7 +139,7 @@
     String needle = isConstructor ? enclosingClassName : name;
     // The unary '-' operator has a special element name (specified).
     if (needle == 'unary-') needle = '-';
-    for (Token t = token; EOF_TOKEN != t.kind; t = t.next) {
+    for (Token t = token; Tokens.EOF_TOKEN != t.kind; t = t.next) {
       if (t is !ErrorToken && needle == t.value) return t;
     }
     return token;
@@ -2325,7 +2326,11 @@
   bool get isEnumClass => false;
 
   InterfaceType computeType(Compiler compiler) {
-    if (thisTypeCache == null) {
+    if (isPatch) {
+      origin.computeType(compiler);
+      thisTypeCache = origin.thisType;
+      rawTypeCache = origin.rawType;
+    } else if (thisTypeCache == null) {
       computeThisAndRawType(compiler, computeTypeParameters(compiler));
     }
     return thisTypeCache;
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 2656ee9..6ad5177 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -53,6 +53,8 @@
     ResolverVisitor;
 import 'tree/tree.dart' show
     Send;
+import 'types/types.dart' show
+    TypeMaskStrategy;
 import 'universe/universe.dart';
 import 'util/util.dart' show
     Link,
@@ -122,7 +124,7 @@
       = new Map<String, Set<Element>>();
   final Set<ClassElement> _processedClasses = new Set<ClassElement>();
   Set<ClassElement> recentClasses = new Setlet<ClassElement>();
-  final Universe universe = new Universe();
+  final Universe universe = new Universe(const TypeMaskStrategy());
 
   static final TRACE_MIRROR_ENQUEUING =
       const bool.fromEnvironment("TRACE_MIRROR_ENQUEUING");
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index 6e0d558..794aa7a 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -17,7 +17,7 @@
     LocalElement;
 import '../js/js.dart' as js;
 import '../js/js_source_mapping.dart';
-import '../scanner/scannerlib.dart' show Token;
+import '../tokens/token.dart' show Token;
 import '../tree/tree.dart' show Node, Send;
 
 import 'source_file.dart';
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index ce801a9..f8ba241 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -233,6 +233,8 @@
       new Uri(scheme: 'dart', path: '_js_embedded_names');
   static final Uri DART_ISOLATE_HELPER =
       new Uri(scheme: 'dart', path: '_isolate_helper');
+  static final Uri PACKAGE_LOOKUP_MAP =
+      new Uri(scheme: 'package', path: 'lookup_map/lookup_map.dart');
 
   static const String INVOKE_ON = '_getCachedInvocation';
   static const String START_ROOT_ISOLATE = 'startRootIsolate';
@@ -608,6 +610,9 @@
   /// constructors for custom elements.
   CustomElementsAnalysis customElementsAnalysis;
 
+  /// Codegen support for tree-shaking entries of `LookupMap`.
+  LookupMapAnalysis lookupMapAnalysis;
+
   /// Support for classifying `noSuchMethod` implementations.
   NoSuchMethodRegistry noSuchMethodRegistry;
 
@@ -641,6 +646,7 @@
         compiler, namer, generateSourceMap, useStartupEmitter);
     typeVariableHandler = new TypeVariableHandler(compiler);
     customElementsAnalysis = new CustomElementsAnalysis(this);
+    lookupMapAnalysis = new LookupMapAnalysis(this);
     noSuchMethodRegistry = new NoSuchMethodRegistry(this);
     constantCompilerTask = new JavaScriptConstantTask(compiler);
     resolutionCallbacks = new JavaScriptResolutionCallbacks(this);
@@ -949,11 +955,23 @@
     }
   }
 
-  void registerCompileTimeConstant(ConstantValue constant, Registry registry) {
+  void registerCompileTimeConstant(ConstantValue constant, Registry registry,
+      {bool addForEmission: true}) {
     registerCompileTimeConstantInternal(constant, registry);
-    for (ConstantValue dependency in constant.getDependencies()) {
-      registerCompileTimeConstant(dependency, registry);
+
+    if (!registry.isForResolution &&
+        lookupMapAnalysis.isLookupMap(constant)) {
+      // Note: internally, this registration will temporarily remove the
+      // constant dependencies and add them later on-demand.
+      lookupMapAnalysis.registerLookupMapReference(constant);
     }
+
+    for (ConstantValue dependency in constant.getDependencies()) {
+      registerCompileTimeConstant(dependency, registry,
+          addForEmission: false);
+    }
+
+    if (addForEmission) constants.addCompileTimeConstantForEmission(constant);
   }
 
   void registerCompileTimeConstantInternal(ConstantValue constant,
@@ -971,6 +989,11 @@
     } else if (constant.isType) {
       enqueueInResolution(getCreateRuntimeType(), registry);
       registry.registerInstantiation(typeImplementation.rawType);
+      TypeConstantValue typeConstant = constant;
+      DartType representedType = typeConstant.representedType;
+      if (representedType != const DynamicType()) {
+        lookupMapAnalysis.registerTypeConstant(representedType.element);
+      }
     }
   }
 
@@ -996,7 +1019,7 @@
                                 Registry registry) {
     assert(registry.isForResolution);
     ConstantValue constant = constants.getConstantValueForMetadata(metadata);
-    registerCompileTimeConstant(constant, registry);
+    registerCompileTimeConstant(constant, registry, addForEmission: false);
     metadataConstants.add(new Dependency(constant, annotatedElement));
   }
 
@@ -1129,6 +1152,13 @@
     }
 
     customElementsAnalysis.registerInstantiatedClass(cls, enqueuer);
+    if (!enqueuer.isResolutionQueue) {
+      lookupMapAnalysis.registerInstantiatedClass(cls);
+    }
+  }
+
+  void registerInstantiatedType(InterfaceType type, Registry registry) {
+    lookupMapAnalysis.registerInstantiatedType(type, registry);
   }
 
   void registerUseInterceptor(Enqueuer enqueuer) {
@@ -1438,7 +1468,6 @@
           constants.getConstantValueForVariable(element);
       if (initialValue != null) {
         registerCompileTimeConstant(initialValue, work.registry);
-        constants.addCompileTimeConstantForEmission(initialValue);
         // We don't need to generate code for static or top-level
         // variables. For instance variables, we may need to generate
         // the checked setter.
@@ -2133,6 +2162,8 @@
         jsBuiltinEnum = find(library, 'JsBuiltin');
       } else if (uri == Uris.dart_html) {
         htmlLibraryIsLoaded = true;
+      } else if (uri == PACKAGE_LOOKUP_MAP) {
+        lookupMapAnalysis.initRuntimeClass(find(library, 'LookupMap'));
       }
       annotations.onLibraryScanned(library);
     });
@@ -2569,7 +2600,8 @@
           registerCompileTimeConstant(
               dependency.constant,
               new CodegenRegistry(compiler,
-                  dependency.annotatedElement.analyzableElement.treeElements));
+                  dependency.annotatedElement.analyzableElement.treeElements),
+              addForEmission: false);
         }
         metadataConstants.clear();
       }
@@ -2577,6 +2609,8 @@
     return true;
   }
 
+  void onQueueClosed() => lookupMapAnalysis.onQueueClosed();
+
   void onElementResolved(Element element, TreeElements elements) {
     if ((element.isFunction || element.isGenerativeConstructor) &&
         annotations.noInline(element)) {
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 00cd5b9..16c882a 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -175,6 +175,7 @@
     dumpTypedIR(cpsNode, typePropagator);
     applyCpsPass(new LoopInvariantCodeMotion());
     applyCpsPass(new ShareInterceptors());
+    applyCpsPass(new ScalarReplacer(compiler));
     applyCpsPass(new ShrinkingReducer());
     applyCpsPass(new MutableVariableEliminator());
     applyCpsPass(new RedundantJoinEliminator());
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 9913065..4fa59bb 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -31,7 +31,6 @@
 /// special nodes that respect JavaScript behavior.
 ///
 /// Performs the following rewrites:
-///  - Rewrite [IsTrue] in a [Branch] to do boolean conversion.
 ///  - Add interceptors at call sites that use interceptor calling convention.
 ///  - Add explicit receiver argument for methods that are called in interceptor
 ///    calling convention.
@@ -140,10 +139,7 @@
         new LetCont.many(<Continuation>[returnFalse, originalBody],
             new LetPrim(nullPrimitive,
                 new LetPrim(test,
-                    new Branch(
-                        new IsTrue(test),
-                        returnFalse,
-                        originalBody))));
+                    new Branch.loose(test, returnFalse, originalBody))));
     function.body = newBody;
   }
 
@@ -281,41 +277,6 @@
     node.receiver = new Reference<Primitive>(newReceiver);
   }
 
-  processBranch(Branch node) {
-    // TODO(karlklose): implement the checked mode part of boolean conversion.
-    InteriorNode parent = node.parent;
-    IsTrue condition = node.condition;
-
-    // Do not rewrite conditions that are foreign code.
-    // It is redundant, and causes infinite recursion (if not optimized)
-    // in the implementation of identical, which itself contains a condition.
-    Primitive value = condition.value.definition;
-    if (value is Parameter && value.parent is Continuation) {
-      Continuation cont = value.parent;
-      if (cont.hasExactlyOneUse && cont.firstRef.parent is ForeignCode) {
-        ForeignCode foreign = cont.firstRef.parent;
-        if (foreign.type.containsOnlyBool(_glue.classWorld)) {
-          return;
-        }
-      }
-    }
-
-    Primitive t = trueConstant;
-    Primitive i = new ApplyBuiltinOperator(
-        BuiltinOperator.Identical,
-        <Primitive>[condition.value.definition, t],
-        condition.value.definition.sourceInformation);
-    LetPrim newNode = new LetPrim(t,
-        new LetPrim(i,
-            new Branch(new IsTrue(i),
-                node.trueContinuation.definition,
-                node.falseContinuation.definition)));
-    condition.value.unlink();
-    node.trueContinuation.unlink();
-    node.falseContinuation.unlink();
-    parent.body = newNode;
-  }
-
   processInterceptor(Interceptor node) {
     _glue.registerSpecializedGetInterceptor(node.interceptedClasses);
   }
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index a13db64..1cd0c43 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -169,7 +169,6 @@
         ConstantValue constant = makeTypeConstant(classElement);
         backend.registerCompileTimeConstant(
             constant, compiler.globalDependencies);
-        backend.constants.addCompileTimeConstantForEmission(constant);
       }
     }
     activeClasses.addAll(newActiveClasses);
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 9f2e82e..af8df51 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -88,6 +88,7 @@
 import 'codegen/task.dart';
 import 'constant_system_javascript.dart';
 import 'patch_resolver.dart';
+import 'lookup_map_analysis.dart' show LookupMapAnalysis;
 
 part 'backend.dart';
 part 'checked_mode_helpers.dart';
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
new file mode 100644
index 0000000..9d44af1
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart
@@ -0,0 +1,335 @@
+// 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.
+
+/// Analysis to determine how to generate code for `LookupMap`s.
+library compiler.src.js_backend.lookup_map_analysis;
+
+import '../common/registry.dart' show Registry;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart' show
+     ConstantValue,
+     ConstructedConstantValue,
+     ListConstantValue,
+     NullConstantValue,
+     TypeConstantValue;
+import '../dart_types.dart' show DartType;
+import '../elements/elements.dart' show Elements, Element, ClassElement,
+     FieldElement, FunctionElement, FunctionSignature;
+import '../enqueue.dart' show Enqueuer;
+import 'js_backend.dart' show JavaScriptBackend;
+import '../dart_types.dart' show DynamicType, InterfaceType;
+
+/// An analysis and optimization to remove unused entries from a `LookupMap`.
+///
+/// `LookupMaps` are defined in `package:lookup_map/lookup_map.dart`. They are
+/// simple maps that contain constant expressions as keys, and that only support
+/// the lookup operation.
+///
+/// This analysis and optimization will tree-shake the contents of the maps by
+/// looking at the program and finding which keys are clearly unused. Not all
+/// constants can be approximated statically, so this optimization is limited to
+/// the following keys:
+///
+///   * Const expressions that can only be created via const constructors. This
+///   excludes primitives, strings, and any const type that overrides the ==
+///   operator.
+///
+///   * Type literals.
+///
+/// Type literals are more complex than const expressions because they can be
+/// created in multiple ways. We can approximate the possible set of keys if we
+/// follow these rules:
+///
+///   * Include all type-literals used explicitly in the code (excluding
+///   obviously the uses that can be removed from LookupMaps)
+///
+///   * Include every reflectable type-literal if a mirror API is used to create
+///   types (e.g.  ClassMirror.reflectedType).
+///
+///   * Include all allocated types if the program contains `e.runtimeType`
+///   expressions.
+///
+///   * Include all generic-type arguments, if the program uses type
+///   variables in expressions such as `class A<T> { Type get extract => T }`.
+///
+// TODO(sigmund): add support for const expressions, currently this
+// implementation only supports Type literals. To support const expressions we
+// need to change some of the invariants below (e.g. we can no longer use the
+// ClassElement of a type to refer to keys we need to discover).
+// TODO(sigmund): detect uses of mirrors
+class LookupMapAnalysis {
+  /// Reference to [JavaScriptBackend] to be able to enqueue work when we
+  /// discover that a key in a map is potentially used.
+  final JavaScriptBackend backend;
+
+  /// The resolved [ClassElement] associated with `LookupMap`.
+  ClassElement typeLookupMapClass;
+
+  /// The resolved [FieldElement] for `LookupMap._entries`.
+  FieldElement entriesField;
+
+  /// The resolved [FieldElement] for `LookupMap._key`.
+  FieldElement keyField;
+
+  /// The resolved [FieldElement] for `LookupMap._value`.
+  FieldElement valueField;
+
+  /// Constant instances of `LookupMap` and information about them tracked by
+  /// this analysis.
+  final Map<ConstantValue, _LookupMapInfo> _lookupMaps = {};
+
+  /// Types that we have discovered to be in use in the program.
+  final _inUse = new Set<ClassElement>();
+
+  /// Pending work to do if we discover that a new type is in use. For each type
+  /// that we haven't seen, we record the list of lookup-maps that use such type
+  /// as a key.
+  final _pending = <ClassElement, List<_LookupMapInfo>>{};
+
+  /// Whether the backend is currently processing the codegen queue.
+  // TODO(sigmund): is there a better way to do this. Do we need to plumb the
+  // enqueuer on each callback?
+  bool get _inCodegen => backend.compiler.phase == Compiler.PHASE_COMPILING;
+
+  LookupMapAnalysis(this.backend);
+
+  /// Whether this analysis and optimization is enabled.
+  bool get _isEnabled {
+    // `lookupMap==off` kept here to make it easy to test disabling this feature
+    if (const String.fromEnvironment('lookupMap') == 'off') return false;
+    return typeLookupMapClass != null;
+  }
+
+  /// Initializes this analysis by providing the resolver information of
+  /// `LookupMap`.
+  void initRuntimeClass(ClassElement cls) {
+    cls.computeType(backend.compiler);
+    entriesField = cls.lookupMember('_entries');
+    keyField = cls.lookupMember('_key');
+    valueField = cls.lookupMember('_value');
+    // TODO(sigmund): Maybe inline nested maps make the output code smaller?
+    typeLookupMapClass = cls;
+  }
+
+  /// Whether [constant] is an instance of a `LookupMap`.
+  bool isLookupMap(ConstantValue constant) =>
+      _isEnabled &&
+      constant is ConstructedConstantValue &&
+      constant.type.asRaw().element.isSubclassOf(typeLookupMapClass);
+
+  /// Registers an instance of a lookup-map with the analysis.
+  void registerLookupMapReference(ConstantValue lookupMap) {
+    if (!_isEnabled || !_inCodegen) return;
+    assert(isLookupMap(lookupMap));
+    _lookupMaps.putIfAbsent(lookupMap,
+        () => new _LookupMapInfo(lookupMap, this).._updateUsed());
+  }
+
+  /// Records that [type] is used in the program, and updates every map that
+  /// has it as a key.
+  void _addUse(ClassElement type) {
+    if (_inUse.add(type)) {
+      _pending[type]?.forEach((info) => info._markUsed(type));
+      _pending.remove(type);
+    }
+  }
+
+  /// Callback from the enqueuer, invoked when [element] is instantiated.
+  void registerInstantiatedClass(ClassElement element) {
+    if (!_isEnabled || !_inCodegen) return;
+    // TODO(sigmund): only add if .runtimeType is ever used
+    _addUse(element);
+  }
+
+  /// Callback from the enqueuer, invoked when [type] is instantiated.
+  void registerInstantiatedType(InterfaceType type, Registry registry) {
+    if (!_isEnabled || !_inCodegen) return;
+    // TODO(sigmund): only add if .runtimeType is ever used
+    _addUse(type.element);
+    // TODO(sigmund): only do this when type-argument expressions are used?
+    _addGenerics(type, registry);
+  }
+
+  /// Records generic type arguments in [type], in case they are retrieved and
+  /// returned using a type-argument expression.
+  void _addGenerics(InterfaceType type, Registry registry) {
+    if (!type.isGeneric) return;
+    for (var arg in type.typeArguments) {
+      if (arg is InterfaceType) {
+        _addUse(arg.element);
+        // Note: this call was needed to generate correct code for
+        // type_lookup_map/generic_type_test
+        // TODO(sigmund): can we get rid of this?
+        backend.registerInstantiatedConstantType(
+            backend.typeImplementation.rawType, registry);
+        _addGenerics(arg, registry);
+      }
+    }
+  }
+
+  /// Callback from the codegen enqueuer, invoked when a type constant
+  /// corresponding to the [element] is used in the program.
+  void registerTypeConstant(Element element) {
+    if (!_isEnabled || !_inCodegen) return;
+    assert(element.isClass);
+    _addUse(element);
+  }
+
+  /// Callback from the backend, invoked when reaching the end of the enqueuing
+  /// process, but before emitting the code. At this moment we have discovered
+  /// all types used in the program and we can tree-shake anything that is
+  /// unused.
+  void onQueueClosed() {
+    if (!_isEnabled || !_inCodegen) return;
+
+    _lookupMaps.values.forEach((info) {
+      assert (!info.emitted);
+      info.emitted = true;
+      info._prepareForEmission();
+    });
+
+    // When --verbose is passed, we show the total number and set of keys that
+    // were tree-shaken from lookup maps.
+    Compiler compiler = backend.compiler;
+    if (compiler.verbose) {
+      var sb = new StringBuffer();
+      int count = 0;
+      for (var info in _lookupMaps.values) {
+        for (var key in info.unusedEntries.keys) {
+          if (count != 0) sb.write(',');
+          sb.write(key.unparse());
+          count++;
+        }
+      }
+      compiler.log(count == 0
+          ? 'lookup-map: nothing was tree-shaken'
+          : 'lookup-map: found $count unused keys ($sb)');
+    }
+  }
+}
+
+/// Internal information about the entries on a lookup-map.
+class _LookupMapInfo {
+  /// The original reference to the constant value.
+  ///
+  /// This reference will be mutated in place to remove it's entries when the
+  /// map is first seen during codegen, and to restore them (or a subset of
+  /// them) when we have finished discovering which entries are used. This has
+  /// the side-effect that `orignal.getDependencies()` will be empty during
+  /// most of codegen until we are ready to emit the constants. However,
+  /// restoring the entries before emitting code lets us keep the emitter logic
+  /// agnostic of this optimization.
+  final ConstructedConstantValue original;
+
+  /// Reference to the lookup map analysis to be able to refer to data shared
+  /// accross infos.
+  final LookupMapAnalysis analysis;
+
+  /// Whether we have already emitted this constant.
+  bool emitted = false;
+
+  /// Whether the `LookupMap` constant was built using the `LookupMap.pair`
+  /// constructor.
+  bool singlePair;
+
+  /// Entries in the lookup map whose keys have not been seen in the rest of the
+  /// program.
+  Map<ClassElement, ConstantValue> unusedEntries =
+      <ClassElement, ConstantValue>{};
+
+  /// Entries that have been used, and thus will be part of the generated code.
+  Map<ClassElement, ConstantValue> usedEntries =
+      <ClassElement, ConstantValue>{};
+
+  /// Internal helper to memoize the mapping between map class elements and
+  /// their corresponding type constants.
+  Map<ClassElement, TypeConstantValue> _typeConstants =
+      <ClassElement, TypeConstantValue>{};
+
+  /// Creates and initializes the information containing all keys of the
+  /// original map marked as unused.
+  _LookupMapInfo(this.original, this.analysis) {
+    ConstantValue key = original.fields[analysis.keyField];
+    singlePair = !key.isNull;
+
+    if (singlePair) {
+      TypeConstantValue typeKey = key;
+      ClassElement cls = typeKey.representedType.element;
+      _typeConstants[cls] = typeKey;
+      unusedEntries[cls] = original.fields[analysis.valueField];
+
+      // Note: we modify the constant in-place, see comment in [original].
+      original.fields[analysis.keyField] = new NullConstantValue();
+      original.fields[analysis.valueField] = new NullConstantValue();
+    } else {
+      ListConstantValue list = original.fields[analysis.entriesField];
+      List<ConstantValue> keyValuePairs = list.entries;
+      for (int i = 0; i < keyValuePairs.length; i += 2) {
+        TypeConstantValue type = keyValuePairs[i];
+        ClassElement cls = type.representedType.element;
+        if (cls == null || !cls.isClass) {
+          // TODO(sigmund): report an error
+          continue;
+        }
+        _typeConstants[cls] = type;
+        unusedEntries[cls] = keyValuePairs[i + 1];
+      }
+
+      // Note: we modify the constant in-place, see comment in [original].
+      original.fields[analysis.entriesField] =
+          new ListConstantValue(list.type, []);
+    }
+  }
+
+  /// Check every key in unusedEntries and mark it as used if the analysis has
+  /// already discovered them. This is meant to be called once to finalize
+  /// initialization after constructing an instance of this class. Afterwards,
+  /// we call [_markUsed] on each individual key as it gets discovered.
+  void _updateUsed() {
+    // Note: we call toList because `_markUsed` modifies the map.
+    for (ClassElement type in unusedEntries.keys.toList()) {
+      if (analysis._inUse.contains(type)) {
+        _markUsed(type);
+      } else {
+        analysis._pending.putIfAbsent(type, () => []).add(this);
+      }
+    }
+  }
+
+  /// Marks that [type] is a key that has been seen, and thus, the corresponding
+  /// entry in this map should be considered reachable.
+  void _markUsed(ClassElement type) {
+    assert(!emitted);
+    assert(unusedEntries.containsKey(type));
+    assert(!usedEntries.containsKey(type));
+    ConstantValue constant = unusedEntries.remove(type);
+    usedEntries[type] = constant;
+    analysis.backend.registerCompileTimeConstant(constant,
+        analysis.backend.compiler.globalDependencies,
+        addForEmission: false);
+  }
+
+  /// Restores [original] to contain all of the entries marked as possibly used.
+  void _prepareForEmission() {
+    ListConstantValue originalEntries = original.fields[analysis.entriesField];
+    DartType listType = originalEntries.type;
+    List<ConstantValue> keyValuePairs = <ConstantValue>[];
+    usedEntries.forEach((key, value) {
+      keyValuePairs.add(_typeConstants[key]);
+      keyValuePairs.add(value);
+    });
+
+    // Note: we are restoring the entries here, see comment in [original].
+    if (singlePair) {
+      assert (keyValuePairs.length == 0 || keyValuePairs.length == 2);
+      if (keyValuePairs.length == 2) {
+        original.fields[analysis.keyField] = keyValuePairs[0];
+        original.fields[analysis.valueField] = keyValuePairs[1];
+      }
+    } else {
+      original.fields[analysis.entriesField] =
+          new ListConstantValue(listType, keyValuePairs);
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
index f293870..c8d478b 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -48,7 +48,7 @@
    * Invariant: [member] must be a declaration element.
    */
   Map<jsAst.Name, jsAst.Expression> generateCallStubsForGetter(
-      Element member, Map<Selector, TypeMaskSet> selectors) {
+      Element member, Map<Selector, ReceiverMaskSet> selectors) {
     assert(invariant(member, member.isDeclaration));
 
     // If the method is intercepted, the stub gets the
@@ -84,12 +84,7 @@
     for (Selector selector in selectors.keys) {
       if (generatedSelectors.contains(selector)) continue;
       if (!selector.appliesUnnamed(member, compiler.world)) continue;
-      for (TypeMask mask in selectors[selector].masks) {
-        if (mask != null &&
-            !mask.canHit(member, selector, compiler.world)) {
-          continue;
-        }
-
+      if (selectors[selector].applies(member, selector, compiler.world)) {
         generatedSelectors.add(selector);
 
         jsAst.Name invocationName = namer.invocationName(selector);
@@ -129,20 +124,12 @@
     }
 
     void addNoSuchMethodHandlers(String ignore,
-                                 Map<Selector, TypeMaskSet> selectors) {
-      TypeMask objectSubclassTypeMask =
-          new TypeMask.subclass(compiler.objectClass, compiler.world);
-
+                                 Map<Selector, ReceiverMaskSet> selectors) {
       for (Selector selector in selectors.keys) {
-        TypeMaskSet maskSet = selectors[selector];
-        for (TypeMask mask in maskSet.masks) {
-          if (mask == null) mask = objectSubclassTypeMask;
-
-          if (mask.needsNoSuchMethodHandling(selector, compiler.world)) {
-            jsAst.Name jsName = namer.invocationMirrorInternalName(selector);
-            jsNames[jsName] = selector;
-            break;
-          }
+        ReceiverMaskSet maskSet = selectors[selector];
+        if (maskSet.needsNoSuchMethodHandling(selector, compiler.world)) {
+          jsAst.Name jsName = namer.invocationMirrorInternalName(selector);
+          jsNames[jsName] = selector;
         }
       }
     }
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index b46e60d..2f2dffd 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -61,7 +61,7 @@
 import 'startup_emitter/emitter.dart' as startup_js_emitter;
 
 import '../universe/universe.dart' show
-    TypeMaskSet,
+    ReceiverMaskSet,
     TypedSelector;
 
 import '../util/util.dart' show
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index 44350b5..07398b3 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -200,14 +200,14 @@
     // The set of selectors that apply to `member`. For example, for
     // a member `foo(x, [y])` the following selectors may apply:
     // `foo(x)`, and `foo(x, y)`.
-    Map<Selector, TypeMaskSet> selectors;
+    Map<Selector, ReceiverMaskSet> selectors;
     // The set of selectors that apply to `member` if it's name was `call`.
     // This happens when a member is torn off. In that case calls to the
     // function use the name `call`, and we must be able to handle every
     // `call` invocation that matches the signature. For example, for
     // a member `foo(x, [y])` the following selectors would be possible
     // call-selectors: `call(x)`, and `call(x, y)`.
-    Map<Selector, TypeMaskSet> callSelectors;
+    Map<Selector, ReceiverMaskSet> callSelectors;
 
     // Only instance members (not static methods) need stubs.
     if (member.isInstanceMember) {
@@ -220,8 +220,9 @@
     }
 
     assert(emptySelectorSet.isEmpty);
-    if (selectors == null) selectors = const <Selector, TypeMaskSet>{};
-    if (callSelectors == null) callSelectors = const <Selector, TypeMaskSet>{};
+    if (selectors == null) selectors = const <Selector, ReceiverMaskSet>{};
+    if (callSelectors == null) callSelectors =
+        const <Selector, ReceiverMaskSet>{};
 
     List<ParameterStubMethod> stubs = <ParameterStubMethod>[];
 
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 1b9b6ef..b10abf2a 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -30,7 +30,7 @@
     MethodElement,
     ParameterElement;
 
-import '../../universe/universe.dart' show Universe, TypeMaskSet;
+import '../../universe/universe.dart' show Universe, ReceiverMaskSet;
 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
 
 part 'collector.dart';
@@ -385,7 +385,7 @@
         if (method != null) methods.add(method);
       }
       if (member.isGetter || member.isField) {
-        Map<Selector, TypeMaskSet> selectors =
+        Map<Selector, ReceiverMaskSet> selectors =
             _compiler.codegenWorld.invocationsByName(member.name);
         if (selectors != null && !selectors.isEmpty) {
 
diff --git a/pkg/compiler/lib/src/mirror_renamer/mirror_renamer.dart b/pkg/compiler/lib/src/mirror_renamer/mirror_renamer.dart
index 9be4b75..d157b74 100644
--- a/pkg/compiler/lib/src/mirror_renamer/mirror_renamer.dart
+++ b/pkg/compiler/lib/src/mirror_renamer/mirror_renamer.dart
@@ -4,12 +4,15 @@
 
 library mirror_renamer;
 
-import '../compiler.dart' show Compiler;
-import '../tree/tree.dart';
-import '../scanner/scannerlib.dart' show Token;
+import '../compiler.dart' show
+    Compiler;
+import '../dart_backend/dart_backend.dart' show
+    DartBackend,
+    PlaceholderCollector;
 import '../elements/elements.dart';
-import '../dart_backend/dart_backend.dart' show DartBackend,
-                                                PlaceholderCollector;
+import '../tokens/token.dart' show
+    Token;
+import '../tree/tree.dart';
 
 part 'renamer.dart';
 
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
index df44e28..c35fd8b 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_mirrors.dart
@@ -20,8 +20,9 @@
 import '../elements/elements.dart';
 import '../resolution/scope.dart' show
     Scope;
-import '../scanner/scannerlib.dart';
 import '../script.dart';
+import '../tokens/token.dart';
+import '../tokens/token_constants.dart' as Tokens;
 import '../tree/tree.dart';
 import '../util/util.dart'
     show Link,
@@ -214,7 +215,7 @@
   String toString() => _element.toString();
 
   void _appendCommentTokens(Token commentToken) {
-    while (commentToken != null && commentToken.kind == COMMENT_TOKEN) {
+    while (commentToken != null && commentToken.kind == Tokens.COMMENT_TOKEN) {
       _metadata.add(new Dart2JsCommentInstanceMirror(
           mirrorSystem, commentToken.value));
       commentToken = commentToken.next;
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index d936d58..1f9b47b 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -263,7 +263,7 @@
       if (token.stringValue != 'extends') return null;
       token = token.next;
       Token id = token;
-      while (token.kind != EOF_TOKEN) {
+      while (token.kind != Tokens.EOF_TOKEN) {
         token = token.next;
         if (token.stringValue != '.') break;
         token = token.next;
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index 281009d..ebe88a9 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -13,7 +13,8 @@
 import '../constants/values.dart';
 import '../dart_types.dart';
 import '../diagnostics/diagnostic_listener.dart';
-import '../diagnostics/messages.dart' show MessageKind;
+import '../diagnostics/messages.dart' show
+    MessageKind;
 import '../diagnostics/spannable.dart' show
     NO_LOCATION_SPANNABLE,
     Spannable;
@@ -28,10 +29,24 @@
     LibraryElementX;
 import '../js/js.dart' as js;
 import '../js_backend/js_backend.dart';
-import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
-import '../resolution/members.dart' show ResolverVisitor;
-import '../scanner/scannerlib.dart';
+import '../js_emitter/js_emitter.dart' show
+    CodeEmitterTask,
+    NativeEmitter;
+import '../parser/listener.dart' show
+    Listener;
+import '../parser/element_listener.dart' show
+    ElementListener;
+import '../parser/partial_elements.dart' show
+    PartialMetadataAnnotation;
+import '../resolution/members.dart' show
+    ResolverVisitor;
 import '../ssa/ssa.dart';
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    Token;
+import '../tokens/token_constants.dart' as Tokens show
+    EOF_TOKEN,
+    STRING_TOKEN;
 import '../tree/tree.dart';
 import '../universe/universe.dart' show SideEffects;
 import '../util/util.dart';
diff --git a/pkg/compiler/lib/src/native/scanner.dart b/pkg/compiler/lib/src/native/scanner.dart
index bbbbb2e..cfdb703 100644
--- a/pkg/compiler/lib/src/native/scanner.dart
+++ b/pkg/compiler/lib/src/native/scanner.dart
@@ -13,7 +13,7 @@
 Token handleNativeBlockToSkip(Listener listener, Token token) {
   checkAllowedLibrary(listener, token);
   token = token.next;
-  if (identical(token.kind, STRING_TOKEN)) {
+  if (identical(token.kind, Tokens.STRING_TOKEN)) {
     token = token.next;
   }
   if (identical(token.stringValue, '{')) {
@@ -29,7 +29,7 @@
   listener.beginReturnStatement(token);
   token = token.next;
   bool hasExpression = false;
-  if (identical(token.kind, STRING_TOKEN)) {
+  if (identical(token.kind, Tokens.STRING_TOKEN)) {
     hasExpression = true;
     listener.beginLiteralString(token);
     listener.endLiteralString(0);
diff --git a/pkg/compiler/lib/src/parser/class_element_parser.dart b/pkg/compiler/lib/src/parser/class_element_parser.dart
new file mode 100644
index 0000000..745665d
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/class_element_parser.dart
@@ -0,0 +1,19 @@
+// 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.
+
+library dart2js.parser.classes;
+
+import '../tokens/token.dart' show
+    Token;
+
+import 'listener.dart' show
+    Listener;
+import 'partial_parser.dart' show
+    PartialParser;
+
+class ClassElementParser extends PartialParser {
+  ClassElementParser(Listener listener) : super(listener);
+
+  Token parseClassBody(Token token) => fullParseClassBody(token);
+}
diff --git a/pkg/compiler/lib/src/parser/diet_parser_task.dart b/pkg/compiler/lib/src/parser/diet_parser_task.dart
new file mode 100644
index 0000000..ee22ae9
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/diet_parser_task.dart
@@ -0,0 +1,42 @@
+// 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 dart2js.parser.diet.task;
+
+import '../common/tasks.dart' show
+    CompilerTask;
+import '../compiler.dart' show
+    Compiler;
+import '../elements/elements.dart' show
+    CompilationUnitElement;
+import '../diagnostics/invariant.dart' show
+    invariant;
+import '../tokens/token.dart' show
+    Token;
+
+import 'listener.dart' show
+    ParserError;
+import 'element_listener.dart' show
+    ElementListener;
+import 'partial_parser.dart' show
+    PartialParser;
+
+class DietParserTask extends CompilerTask {
+  DietParserTask(Compiler compiler) : super(compiler);
+  final String name = 'Diet Parser';
+
+  dietParse(CompilationUnitElement compilationUnit, Token tokens) {
+    measure(() {
+      Function idGenerator = compiler.getNextFreeClassId;
+      ElementListener listener =
+          new ElementListener(compiler, compilationUnit, idGenerator);
+      PartialParser parser = new PartialParser(listener);
+      try {
+        parser.parseUnit(tokens);
+      } on ParserError catch(_) {
+        assert(invariant(compilationUnit, compiler.compilationFailed));
+      }
+    });
+  }
+}
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
new file mode 100644
index 0000000..00ec535
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -0,0 +1,755 @@
+// 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 dart2js.parser.element_listener;
+
+import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/messages.dart';
+import '../diagnostics/spannable.dart' show
+    Spannable;
+import '../elements/elements.dart' show
+    Element,
+    LibraryElement,
+    MetadataAnnotation;
+import '../elements/modelx.dart' show
+    CompilationUnitElementX,
+    DeclarationSite,
+    ElementX,
+    EnumClassElementX,
+    FieldElementX,
+    LibraryElementX,
+    MixinApplicationElementX,
+    VariableList;
+import '../native/native.dart' as native;
+import '../string_validator.dart' show
+    StringValidator;
+import '../tokens/keyword.dart' show
+    Keyword;
+import '../tokens/precedence_constants.dart' as Precedence show
+    BAD_INPUT_INFO;
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    ErrorToken,
+    KeywordToken,
+    Token;
+import '../tokens/token_constants.dart' as Tokens show
+    EOF_TOKEN;
+import '../tree/tree.dart';
+import '../util/util.dart' show
+    Link;
+
+import 'partial_elements.dart' show
+    PartialClassElement,
+    PartialElement,
+    PartialFieldList,
+    PartialFunctionElement,
+    PartialMetadataAnnotation,
+    PartialTypedefElement;
+import 'listener.dart' show
+    closeBraceFor,
+    Listener,
+    ParserError,
+    VERBOSE;
+
+typedef int IdGenerator();
+
+/**
+ * A parser event listener designed to work with [PartialParser]. It
+ * builds elements representing the top-level declarations found in
+ * the parsed compilation unit and records them in
+ * [compilationUnitElement].
+ */
+class ElementListener extends Listener {
+  final IdGenerator idGenerator;
+  final DiagnosticListener listener;
+  final CompilationUnitElementX compilationUnitElement;
+  final StringValidator stringValidator;
+  Link<StringQuoting> interpolationScope;
+
+  Link<Node> nodes = const Link<Node>();
+
+  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
+
+  /// Records a stack of booleans for each member parsed (a stack is used to
+  /// support nested members which isn't currently possible, but it also serves
+  /// as a simple way to tell we're currently parsing a member). In this case,
+  /// member refers to members of a library or a class (but currently, classes
+  /// themselves are not considered members).  If the top of the stack
+  /// (memberErrors.head) is true, the current member has already reported at
+  /// least one parse error.
+  Link<bool> memberErrors = const Link<bool>();
+
+  bool suppressParseErrors = false;
+
+  ElementListener(
+      DiagnosticListener listener,
+      this.compilationUnitElement,
+      this.idGenerator)
+      : this.listener = listener,
+        stringValidator = new StringValidator(listener),
+        interpolationScope = const Link<StringQuoting>();
+
+  bool get currentMemberHasParseError {
+    return !memberErrors.isEmpty && memberErrors.head;
+  }
+
+  void pushQuoting(StringQuoting quoting) {
+    interpolationScope = interpolationScope.prepend(quoting);
+  }
+
+  StringQuoting popQuoting() {
+    StringQuoting result = interpolationScope.head;
+    interpolationScope = interpolationScope.tail;
+    return result;
+  }
+
+  StringNode popLiteralString() {
+    StringNode node = popNode();
+    // TODO(lrn): Handle interpolations in script tags.
+    if (node.isInterpolation) {
+      listener.internalError(node,
+          "String interpolation not supported in library tags.");
+      return null;
+    }
+    return node;
+  }
+
+  bool allowLibraryTags() {
+    // Library tags are only allowed in the library file itself, not
+    // in sourced files.
+    LibraryElement library = compilationUnitElement.implementationLibrary;
+    return !compilationUnitElement.hasMembers &&
+           library.entryCompilationUnit == compilationUnitElement;
+  }
+
+  void endLibraryName(Token libraryKeyword, Token semicolon) {
+    Expression name = popNode();
+    addLibraryTag(new LibraryName(libraryKeyword, name,
+                                  popMetadata(compilationUnitElement)));
+  }
+
+  void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+                 Token semicolon) {
+    NodeList combinators = popNode();
+    bool isDeferred = deferredKeyword != null;
+    Identifier prefix;
+    if (asKeyword != null) {
+      prefix = popNode();
+    }
+    StringNode uri = popLiteralString();
+    addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
+                             popMetadata(compilationUnitElement),
+                             isDeferred: isDeferred));
+  }
+
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+    NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
+    Identifier name = popNode();
+
+    int id = idGenerator();
+    Element enclosing = compilationUnitElement;
+    pushElement(new EnumClassElementX(name.source, enclosing, id,
+        new Enum(enumKeyword, name, names)));
+    rejectBuiltInIdentifier(name);
+  }
+
+  void endExport(Token exportKeyword, Token semicolon) {
+    NodeList combinators = popNode();
+    StringNode uri = popNode();
+    addLibraryTag(new Export(exportKeyword, uri, combinators,
+                             popMetadata(compilationUnitElement)));
+  }
+
+  void endCombinators(int count) {
+    if (0 == count) {
+      pushNode(null);
+    } else {
+      pushNode(makeNodeList(count, null, null, " "));
+    }
+  }
+
+  void endHide(Token hideKeyword) => pushCombinator(hideKeyword);
+
+  void endShow(Token showKeyword) => pushCombinator(showKeyword);
+
+  void pushCombinator(Token keywordToken) {
+    NodeList identifiers = popNode();
+    pushNode(new Combinator(identifiers, keywordToken));
+  }
+
+  void endIdentifierList(int count) {
+    pushNode(makeNodeList(count, null, null, ","));
+  }
+
+  void endTypeList(int count) {
+    pushNode(makeNodeList(count, null, null, ","));
+  }
+
+  void endPart(Token partKeyword, Token semicolon) {
+    StringNode uri = popLiteralString();
+    addLibraryTag(new Part(partKeyword, uri,
+                           popMetadata(compilationUnitElement)));
+  }
+
+  void endPartOf(Token partKeyword, Token semicolon) {
+    Expression name = popNode();
+    addPartOfTag(new PartOf(partKeyword, name,
+                            popMetadata(compilationUnitElement)));
+  }
+
+  void addPartOfTag(PartOf tag) {
+    compilationUnitElement.setPartOf(tag, listener);
+  }
+
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    if (periodBeforeName != null) {
+      popNode(); // Discard name.
+    }
+    popNode(); // Discard node (Send or Identifier).
+    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
+  }
+
+  void endTopLevelDeclaration(Token token) {
+    if (!metadata.isEmpty) {
+      recoverableError(metadata.head.beginToken,
+                       'Metadata not supported here.');
+      metadata = const Link<MetadataAnnotation>();
+    }
+  }
+
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+                           Token extendsKeyword, Token implementsKeyword,
+                           Token endToken) {
+    makeNodeList(interfacesCount, implementsKeyword, null, ","); // interfaces
+    popNode(); // superType
+    popNode(); // typeParameters
+    Identifier name = popNode();
+    int id = idGenerator();
+    PartialClassElement element = new PartialClassElement(
+        name.source, beginToken, endToken, compilationUnitElement, id);
+    pushElement(element);
+    rejectBuiltInIdentifier(name);
+  }
+
+  void rejectBuiltInIdentifier(Identifier name) {
+    if (name.token is KeywordToken) {
+      Keyword keyword = (name.token as KeywordToken).keyword;
+      if (!keyword.isPseudo) {
+        recoverableError(name, "Illegal name '${keyword.syntax}'.");
+      }
+    }
+  }
+
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+    popNode(); // TODO(karlklose): do not throw away typeVariables.
+    Identifier name = popNode();
+    popNode(); // returnType
+    pushElement(
+        new PartialTypedefElement(
+            name.source, compilationUnitElement, typedefKeyword, endToken));
+    rejectBuiltInIdentifier(name);
+  }
+
+  void endNamedMixinApplication(Token classKeyword,
+                                Token implementsKeyword,
+                                Token endToken) {
+    NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
+    MixinApplication mixinApplication = popNode();
+    Modifiers modifiers = popNode();
+    NodeList typeParameters = popNode();
+    Identifier name = popNode();
+    NamedMixinApplication namedMixinApplication = new NamedMixinApplication(
+        name, typeParameters, modifiers, mixinApplication, interfaces,
+        classKeyword, endToken);
+
+    int id = idGenerator();
+    Element enclosing = compilationUnitElement;
+    pushElement(new MixinApplicationElementX(name.source, enclosing, id,
+                                             namedMixinApplication,
+                                             modifiers));
+    rejectBuiltInIdentifier(name);
+  }
+
+  void endMixinApplication() {
+    NodeList mixins = popNode();
+    TypeAnnotation superclass = popNode();
+    pushNode(new MixinApplication(superclass, mixins));
+  }
+
+  void handleVoidKeyword(Token token) {
+    pushNode(new TypeAnnotation(new Identifier(token), null));
+  }
+
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+    bool hasParseError = currentMemberHasParseError;
+    memberErrors = memberErrors.tail;
+    Identifier name = popNode();
+    popNode(); // type
+    Modifiers modifiers = popNode();
+    PartialFunctionElement element = new PartialFunctionElement(
+        name.source, beginToken, getOrSet, endToken,
+        modifiers, compilationUnitElement);
+    element.hasParseError = hasParseError;
+    pushElement(element);
+  }
+
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    bool hasParseError = currentMemberHasParseError;
+    memberErrors = memberErrors.tail;
+    void buildFieldElement(Identifier name, VariableList fields) {
+      pushElement(
+          new FieldElementX(name, compilationUnitElement, fields));
+    }
+    NodeList variables = makeNodeList(count, null, null, ",");
+    popNode(); // type
+    Modifiers modifiers = popNode();
+    buildFieldElements(modifiers, variables, compilationUnitElement,
+                       buildFieldElement,
+                       beginToken, endToken, hasParseError);
+  }
+
+  void buildFieldElements(Modifiers modifiers,
+                          NodeList variables,
+                          Element enclosingElement,
+                          void buildFieldElement(Identifier name,
+                                                 VariableList fields),
+                          Token beginToken, Token endToken,
+                          bool hasParseError) {
+    VariableList fields =
+        new PartialFieldList(beginToken, endToken, modifiers, hasParseError);
+    for (Link<Node> variableNodes = variables.nodes;
+         !variableNodes.isEmpty;
+         variableNodes = variableNodes.tail) {
+      Expression initializedIdentifier = variableNodes.head;
+      Identifier identifier = initializedIdentifier.asIdentifier();
+      if (identifier == null) {
+        identifier = initializedIdentifier.asSendSet().selector.asIdentifier();
+      }
+      buildFieldElement(identifier, fields);
+    }
+  }
+
+  void handleIdentifier(Token token) {
+    pushNode(new Identifier(token));
+  }
+
+  void handleQualified(Token period) {
+    Identifier last = popNode();
+    Expression first = popNode();
+    pushNode(new Send(first, last));
+  }
+
+  void handleNoType(Token token) {
+    pushNode(null);
+  }
+
+  void endTypeVariable(Token token) {
+    TypeAnnotation bound = popNode();
+    Identifier name = popNode();
+    pushNode(new TypeVariable(name, bound));
+    rejectBuiltInIdentifier(name);
+  }
+
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, endToken, ','));
+  }
+
+  void handleNoTypeVariables(token) {
+    pushNode(null);
+  }
+
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, endToken, ','));
+  }
+
+  void handleNoTypeArguments(Token token) {
+    pushNode(null);
+  }
+
+  void endType(Token beginToken, Token endToken) {
+    NodeList typeArguments = popNode();
+    Expression typeName = popNode();
+    pushNode(new TypeAnnotation(typeName, typeArguments));
+  }
+
+  void handleParenthesizedExpression(BeginGroupToken token) {
+    Expression expression = popNode();
+    pushNode(new ParenthesizedExpression(expression, token));
+  }
+
+  void handleModifier(Token token) {
+    pushNode(new Identifier(token));
+  }
+
+  void handleModifiers(int count) {
+    if (count == 0) {
+      pushNode(Modifiers.EMPTY);
+    } else {
+      NodeList modifierNodes = makeNodeList(count, null, null, ' ');
+      pushNode(new Modifiers(modifierNodes));
+    }
+  }
+
+  Token expected(String string, Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else if (identical(';', string)) {
+      // When a semicolon is missing, it often leads to an error on the
+      // following line. So we try to find the token preceding the semicolon
+      // and report that something is missing *after* it.
+      Token preceding = findPrecedingToken(token);
+      if (preceding == token) {
+        reportError(
+            token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
+      } else {
+        reportError(
+            preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
+      }
+      return token;
+    } else {
+      reportFatalError(
+          token,
+          MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
+              .message({'token': string}, true).toString());
+    }
+    return skipToEof(token);
+  }
+
+  /// Finds the preceding token via the begin token of the last AST node pushed
+  /// on the [nodes] stack.
+  Token findPrecedingToken(Token token) {
+    Token result;
+    Link<Node> nodes = this.nodes;
+    while (!nodes.isEmpty) {
+      result = findPrecedingTokenFromNode(nodes.head, token);
+      if (result != null) {
+        return result;
+      }
+      nodes = nodes.tail;
+    }
+    if (compilationUnitElement != null) {
+      if (compilationUnitElement is CompilationUnitElementX) {
+        CompilationUnitElementX unit = compilationUnitElement;
+        Link<Element> members = unit.localMembers;
+        while (!members.isEmpty) {
+          ElementX member = members.head;
+          DeclarationSite site = member.declarationSite;
+          if (site is PartialElement) {
+            result = findPrecedingTokenFromToken(site.endToken, token);
+            if (result != null) {
+              return result;
+            }
+          }
+          members = members.tail;
+        }
+        result =
+            findPrecedingTokenFromNode(compilationUnitElement.partTag, token);
+        if (result != null) {
+          return result;
+        }
+      }
+    }
+    return token;
+  }
+
+  Token findPrecedingTokenFromNode(Node node, Token token) {
+    if (node != null) {
+      return findPrecedingTokenFromToken(node.getBeginToken(), token);
+    }
+    return null;
+  }
+
+  Token findPrecedingTokenFromToken(Token start, Token token) {
+    if (start != null) {
+      Token current = start;
+      while (current.kind != Tokens.EOF_TOKEN && current.next != token) {
+        current = current.next;
+      }
+      if (current.kind != Tokens.EOF_TOKEN) {
+        return current;
+      }
+    }
+    return null;
+  }
+
+  Token expectedIdentifier(Token token) {
+    if (token is KeywordToken) {
+      reportError(
+          token, MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+          {'keyword': token.value});
+    } else if (token is ErrorToken) {
+      reportErrorToken(token);
+      return synthesizeIdentifier(token);
+    } else {
+      reportFatalError(token,
+          "Expected identifier, but got '${token.value}'.");
+    }
+    return token;
+  }
+
+  Token expectedType(Token token) {
+    pushNode(null);
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+      return synthesizeIdentifier(token);
+    } else {
+      reportFatalError(
+          token, "Expected a type, but got '${token.value}'.");
+      return skipToEof(token);
+    }
+  }
+
+  Token expectedExpression(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+      pushNode(new ErrorExpression(token));
+      return token.next;
+    } else {
+      reportFatalError(token,
+                       "Expected an expression, but got '${token.value}'.");
+      pushNode(null);
+      return skipToEof(token);
+    }
+  }
+
+  Token unexpected(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      String message = "Unexpected token '${token.value}'.";
+      if (token.info == Precedence.BAD_INPUT_INFO) {
+        message = token.value;
+      }
+      reportFatalError(token, message);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedBlockToSkip(Token token) {
+    if (identical(token.stringValue, 'native')) {
+      return native.handleNativeBlockToSkip(this, token);
+    } else {
+      return unexpected(token);
+    }
+  }
+
+  Token expectedFunctionBody(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      String printString = token.value;
+      reportFatalError(token,
+                       "Expected a function body, but got '$printString'.");
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedClassBody(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      reportFatalError(token,
+                       "Expected a class body, but got '${token.value}'.");
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedClassBodyToSkip(Token token) {
+    return unexpected(token);
+  }
+
+  Token expectedDeclaration(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      reportFatalError(token,
+                       "Expected a declaration, but got '${token.value}'.");
+    }
+    return skipToEof(token);
+  }
+
+  Token unmatched(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      String begin = token.value;
+      String end = closeBraceFor(begin);
+      reportError(
+          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
+    }
+    Token next = token.next;
+    while (next is ErrorToken) {
+      next = next.next;
+    }
+    return next;
+  }
+
+  void recoverableError(Spannable node, String message) {
+    // TODO(johnniwinther): Make recoverable errors non-fatal.
+    reportFatalError(node, message);
+  }
+
+  void pushElement(Element element) {
+    popMetadata(element);
+    compilationUnitElement.addMember(element, listener);
+  }
+
+  Link<MetadataAnnotation> popMetadata(ElementX element) {
+    var result = const Link<MetadataAnnotation>();
+    for (Link link = metadata; !link.isEmpty; link = link.tail) {
+      element.addMetadata(link.head);
+      // Reverse the list as is implicitly done by addMetadata.
+      result = result.prepend(link.head);
+    }
+    metadata = const Link<MetadataAnnotation>();
+    return result;
+  }
+
+  void pushMetadata(MetadataAnnotation annotation) {
+    metadata = metadata.prepend(annotation);
+  }
+
+  void addLibraryTag(LibraryTag tag) {
+    if (!allowLibraryTags()) {
+      recoverableError(tag, 'Library tags not allowed here.');
+    }
+    LibraryElementX implementationLibrary =
+        compilationUnitElement.implementationLibrary;
+    implementationLibrary.addTag(tag, listener);
+  }
+
+  void pushNode(Node node) {
+    nodes = nodes.prepend(node);
+    if (VERBOSE) log("push $nodes");
+  }
+
+  Node popNode() {
+    assert(!nodes.isEmpty);
+    Node node = nodes.head;
+    nodes = nodes.tail;
+    if (VERBOSE) log("pop $nodes");
+    return node;
+  }
+
+  void log(message) {
+    print(message);
+  }
+
+  NodeList makeNodeList(int count, Token beginToken, Token endToken,
+                        String delimiter) {
+    Link<Node> poppedNodes = const Link<Node>();
+    for (; count > 0; --count) {
+      // This effectively reverses the order of nodes so they end up
+      // in correct (source) order.
+      poppedNodes = poppedNodes.prepend(popNode());
+    }
+    return new NodeList(beginToken, poppedNodes, endToken, delimiter);
+  }
+
+  void beginLiteralString(Token token) {
+    String source = token.value;
+    StringQuoting quoting = StringValidator.quotingFromString(source);
+    pushQuoting(quoting);
+    // Just wrap the token for now. At the end of the interpolation,
+    // when we know how many there are, go back and validate the tokens.
+    pushNode(new LiteralString(token, null));
+  }
+
+  void handleStringPart(Token token) {
+    // Just push an unvalidated token now, and replace it when we know the
+    // end of the interpolation.
+    pushNode(new LiteralString(token, null));
+  }
+
+  void endLiteralString(int count) {
+    StringQuoting quoting = popQuoting();
+
+    Link<StringInterpolationPart> parts =
+        const Link<StringInterpolationPart>();
+    // Parts of the string interpolation are popped in reverse order,
+    // starting with the last literal string part.
+    bool isLast = true;
+    for (int i = 0; i < count; i++) {
+      LiteralString string = popNode();
+      DartString validation =
+          stringValidator.validateInterpolationPart(string.token, quoting,
+                                                    isFirst: false,
+                                                    isLast: isLast);
+      // Replace the unvalidated LiteralString with a new LiteralString
+      // object that has the validation result included.
+      string = new LiteralString(string.token, validation);
+      Expression expression = popNode();
+      parts = parts.prepend(new StringInterpolationPart(expression, string));
+      isLast = false;
+    }
+
+    LiteralString string = popNode();
+    DartString validation =
+        stringValidator.validateInterpolationPart(string.token, quoting,
+                                                  isFirst: true,
+                                                  isLast: isLast);
+    string = new LiteralString(string.token, validation);
+    if (isLast) {
+      pushNode(string);
+    } else {
+      NodeList partNodes = new NodeList(null, parts, null, "");
+      pushNode(new StringInterpolation(string, partNodes));
+    }
+  }
+
+  void handleStringJuxtaposition(int stringCount) {
+    assert(stringCount != 0);
+    Expression accumulator = popNode();
+    stringCount--;
+    while (stringCount > 0) {
+      Expression expression = popNode();
+      accumulator = new StringJuxtaposition(expression, accumulator);
+      stringCount--;
+    }
+    pushNode(accumulator);
+  }
+
+  void beginMember(Token token) {
+    memberErrors = memberErrors.prepend(false);
+  }
+
+  void beginTopLevelMember(Token token) {
+    beginMember(token);
+  }
+
+  void endFields(fieldCount, start, token) {
+    memberErrors = memberErrors.tail;
+  }
+
+  void endMethod(getOrSet, start, token) {
+    memberErrors = memberErrors.tail;
+  }
+
+  void beginFactoryMethod(Token token) {
+    memberErrors = memberErrors.prepend(false);
+  }
+
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    memberErrors = memberErrors.tail;
+  }
+
+  /// Don't call this method. Should only be used as a last resort when there
+  /// is no feasible way to recover from a parser error.
+  void reportFatalError(Spannable spannable, String message) {
+    reportError(spannable, MessageKind.GENERIC, {'text': message});
+    // Some parse errors are infeasible to recover from, so we throw an error.
+    throw new ParserError(message);
+  }
+
+  void reportError(Spannable spannable,
+                   MessageKind errorCode,
+                   [Map arguments = const {}]) {
+    if (currentMemberHasParseError) return; // Error already reported.
+    if (suppressParseErrors) return;
+    if (!memberErrors.isEmpty) {
+      memberErrors = memberErrors.tail.prepend(true);
+    }
+    listener.reportError(spannable, errorCode, arguments);
+  }
+}
diff --git a/pkg/compiler/lib/src/parser/listener.dart b/pkg/compiler/lib/src/parser/listener.dart
new file mode 100644
index 0000000..5252d46
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/listener.dart
@@ -0,0 +1,793 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.parser.listener;
+
+import '../diagnostics/messages.dart';
+import '../diagnostics/spannable.dart' show
+    Spannable,
+    SpannableAssertionFailure;
+import '../tokens/precedence_constants.dart' as Precedence show
+    EOF_INFO,
+    IDENTIFIER_INFO;
+import '../tokens/token.dart' show
+    BadInputToken,
+    BeginGroupToken,
+    ErrorToken,
+    StringToken,
+    Token,
+    UnmatchedToken,
+    UnterminatedToken;
+import '../tree/tree.dart';
+
+const bool VERBOSE = false;
+
+/**
+ * A parser event listener that does nothing except throw exceptions
+ * on parser errors.
+ */
+class Listener {
+  set suppressParseErrors(bool value) {
+  }
+
+  void beginArguments(Token token) {
+  }
+
+  void endArguments(int count, Token beginToken, Token endToken) {
+  }
+
+  /// Handle async modifiers `async`, `async*`, `sync`.
+  void handleAsyncModifier(Token asyncToken, Token startToken) {
+  }
+
+  void beginAwaitExpression(Token token) {
+  }
+
+  void endAwaitExpression(Token beginToken, Token endToken) {
+  }
+
+  void beginBlock(Token token) {
+  }
+
+  void endBlock(int count, Token beginToken, Token endToken) {
+  }
+
+  void beginCascade(Token token) {
+  }
+
+  void endCascade() {
+  }
+
+  void beginClassBody(Token token) {
+  }
+
+  void endClassBody(int memberCount, Token beginToken, Token endToken) {
+  }
+
+  void beginClassDeclaration(Token token) {
+  }
+
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+                           Token extendsKeyword, Token implementsKeyword,
+                           Token endToken) {
+  }
+
+  void beginCombinators(Token token) {
+  }
+
+  void endCombinators(int count) {
+  }
+
+  void beginCompilationUnit(Token token) {
+  }
+
+  void endCompilationUnit(int count, Token token) {
+  }
+
+  void beginConstructorReference(Token start) {
+  }
+
+  void endConstructorReference(Token start, Token periodBeforeName,
+                               Token endToken) {
+  }
+
+  void beginDoWhileStatement(Token token) {
+  }
+
+  void endDoWhileStatement(Token doKeyword, Token whileKeyword,
+                           Token endToken) {
+  }
+
+  void beginEnum(Token enumKeyword) {
+  }
+
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+  }
+
+  void beginExport(Token token) {
+  }
+
+  void endExport(Token exportKeyword, Token semicolon) {
+  }
+
+  void beginExpressionStatement(Token token) {
+  }
+
+  void endExpressionStatement(Token token) {
+  }
+
+  void beginFactoryMethod(Token token) {
+  }
+
+  void endFactoryMethod(Token beginToken, Token endToken) {
+  }
+
+  void beginFormalParameter(Token token) {
+  }
+
+  void endFormalParameter(Token thisKeyword) {
+  }
+
+  void handleNoFormalParameters(Token token) {
+  }
+
+  void beginFormalParameters(Token token) {
+  }
+
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+  }
+
+  void endFields(int count, Token beginToken, Token endToken) {
+  }
+
+  void beginForStatement(Token token) {
+  }
+
+  void endForStatement(int updateExpressionCount,
+                       Token beginToken, Token endToken) {
+  }
+
+  void endForIn(Token awaitToken, Token forToken,
+                Token inKeyword, Token endToken) {
+  }
+
+  void beginFunction(Token token) {
+  }
+
+  void endFunction(Token getOrSet, Token endToken) {
+  }
+
+  void beginFunctionDeclaration(Token token) {
+  }
+
+  void endFunctionDeclaration(Token token) {
+  }
+
+  void beginFunctionBody(Token token) {
+  }
+
+  void endFunctionBody(int count, Token beginToken, Token endToken) {
+  }
+
+  void handleNoFunctionBody(Token token) {
+  }
+
+  void skippedFunctionBody(Token token) {
+  }
+
+  void beginFunctionName(Token token) {
+  }
+
+  void endFunctionName(Token token) {
+  }
+
+  void beginFunctionTypeAlias(Token token) {
+  }
+
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+  }
+
+  void beginMixinApplication(Token token) {
+  }
+
+  void endMixinApplication() {
+  }
+
+  void beginNamedMixinApplication(Token token) {
+  }
+
+  void endNamedMixinApplication(Token classKeyword,
+                                Token implementsKeyword,
+                                Token endToken) {
+  }
+
+  void beginHide(Token hideKeyword) {
+  }
+
+  void endHide(Token hideKeyword) {
+  }
+
+  void beginIdentifierList(Token token) {
+  }
+
+  void endIdentifierList(int count) {
+  }
+
+  void beginTypeList(Token token) {
+  }
+
+  void endTypeList(int count) {
+  }
+
+  void beginIfStatement(Token token) {
+  }
+
+  void endIfStatement(Token ifToken, Token elseToken) {
+  }
+
+  void beginImport(Token importKeyword) {
+  }
+
+  void endImport(Token importKeyword, Token DeferredKeyword,
+                 Token asKeyword, Token semicolon) {
+  }
+
+  void beginInitializedIdentifier(Token token) {
+  }
+
+  void endInitializedIdentifier() {
+  }
+
+  void beginInitializer(Token token) {
+  }
+
+  void endInitializer(Token assignmentOperator) {
+  }
+
+  void beginInitializers(Token token) {
+  }
+
+  void endInitializers(int count, Token beginToken, Token endToken) {
+  }
+
+  void handleNoInitializers() {
+  }
+
+  void handleLabel(Token token) {
+  }
+
+  void beginLabeledStatement(Token token, int labelCount) {
+  }
+
+  void endLabeledStatement(int labelCount) {
+  }
+
+  void beginLibraryName(Token token) {
+  }
+
+  void endLibraryName(Token libraryKeyword, Token semicolon) {
+  }
+
+  void beginLiteralMapEntry(Token token) {
+  }
+
+  void endLiteralMapEntry(Token colon, Token endToken) {
+  }
+
+  void beginLiteralString(Token token) {
+  }
+
+  void endLiteralString(int interpolationCount) {
+  }
+
+  void handleStringJuxtaposition(int literalCount) {
+  }
+
+  void beginMember(Token token) {
+  }
+
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+  }
+
+  void beginMetadataStar(Token token) {
+  }
+
+  void endMetadataStar(int count, bool forParameter) {
+  }
+
+  void beginMetadata(Token token) {
+  }
+
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+  }
+
+  void beginOptionalFormalParameters(Token token) {
+  }
+
+  void endOptionalFormalParameters(int count,
+                                   Token beginToken, Token endToken) {
+  }
+
+  void beginPart(Token token) {
+  }
+
+  void endPart(Token partKeyword, Token semicolon) {
+  }
+
+  void beginPartOf(Token token) {
+  }
+
+  void endPartOf(Token partKeyword, Token semicolon) {
+  }
+
+  void beginRedirectingFactoryBody(Token token) {
+  }
+
+  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
+  }
+
+  void beginReturnStatement(Token token) {
+  }
+
+  void endReturnStatement(bool hasExpression,
+                          Token beginToken, Token endToken) {
+  }
+
+  void beginSend(Token token) {
+  }
+
+  void endSend(Token token) {
+  }
+
+  void beginShow(Token showKeyword) {
+  }
+
+  void endShow(Token showKeyword) {
+  }
+
+  void beginSwitchStatement(Token token) {
+  }
+
+  void endSwitchStatement(Token switchKeyword, Token endToken) {
+  }
+
+  void beginSwitchBlock(Token token) {
+  }
+
+  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
+  }
+
+  void beginLiteralSymbol(Token token) {
+  }
+
+  void endLiteralSymbol(Token hashToken, int identifierCount) {
+  }
+
+  void beginThrowExpression(Token token) {
+  }
+
+  void endThrowExpression(Token throwToken, Token endToken) {
+  }
+
+  void beginRethrowStatement(Token token) {
+  }
+
+  void endRethrowStatement(Token throwToken, Token endToken) {
+  }
+
+  void endTopLevelDeclaration(Token token) {
+  }
+
+  void beginTopLevelMember(Token token) {
+  }
+
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+  }
+
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+  }
+
+  void beginTryStatement(Token token) {
+  }
+
+  void handleCaseMatch(Token caseKeyword, Token colon) {
+  }
+
+  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+  }
+
+  void handleFinallyBlock(Token finallyKeyword) {
+  }
+
+  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
+  }
+
+  void endType(Token beginToken, Token endToken) {
+  }
+
+  void beginTypeArguments(Token token) {
+  }
+
+  void endTypeArguments(int count, Token beginToken, Token endToken) {
+  }
+
+  void handleNoTypeArguments(Token token) {
+  }
+
+  void beginTypeVariable(Token token) {
+  }
+
+  void endTypeVariable(Token token) {
+  }
+
+  void beginTypeVariables(Token token) {
+  }
+
+  void endTypeVariables(int count, Token beginToken, Token endToken) {
+  }
+
+  void beginUnnamedFunction(Token token) {
+  }
+
+  void endUnnamedFunction(Token token) {
+  }
+
+  void beginVariablesDeclaration(Token token) {
+  }
+
+  void endVariablesDeclaration(int count, Token endToken) {
+  }
+
+  void beginWhileStatement(Token token) {
+  }
+
+  void endWhileStatement(Token whileKeyword, Token endToken) {
+  }
+
+  void handleAsOperator(Token operathor, Token endToken) {
+    // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
+  }
+
+  void handleAssignmentExpression(Token token) {
+  }
+
+  void handleBinaryExpression(Token token) {
+  }
+
+  void handleConditionalExpression(Token question, Token colon) {
+  }
+
+  void handleConstExpression(Token token) {
+  }
+
+  void handleFunctionTypedFormalParameter(Token token) {
+  }
+
+  void handleIdentifier(Token token) {
+  }
+
+  void handleIndexedExpression(Token openCurlyBracket,
+                               Token closeCurlyBracket) {
+  }
+
+  void handleIsOperator(Token operathor, Token not, Token endToken) {
+    // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
+  }
+
+  void handleLiteralBool(Token token) {
+  }
+
+  void handleBreakStatement(bool hasTarget,
+                            Token breakKeyword, Token endToken) {
+  }
+
+  void handleContinueStatement(bool hasTarget,
+                               Token continueKeyword, Token endToken) {
+  }
+
+  void handleEmptyStatement(Token token) {
+  }
+
+  void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
+  }
+
+  /** Called with either the token containing a double literal, or
+    * an immediately preceding "unary plus" token.
+    */
+  void handleLiteralDouble(Token token) {
+  }
+
+  /** Called with either the token containing an integer literal,
+    * or an immediately preceding "unary plus" token.
+    */
+  void handleLiteralInt(Token token) {
+  }
+
+  void handleLiteralList(int count, Token beginToken, Token constKeyword,
+                         Token endToken) {
+  }
+
+  void handleLiteralMap(int count, Token beginToken, Token constKeyword,
+                        Token endToken) {
+  }
+
+  void handleLiteralNull(Token token) {
+  }
+
+  void handleModifier(Token token) {
+  }
+
+  void handleModifiers(int count) {
+  }
+
+  void handleNamedArgument(Token colon) {
+  }
+
+  void handleNewExpression(Token token) {
+  }
+
+  void handleNoArguments(Token token) {
+  }
+
+  void handleNoExpression(Token token) {
+  }
+
+  void handleNoType(Token token) {
+  }
+
+  void handleNoTypeVariables(Token token) {
+  }
+
+  void handleOperator(Token token) {
+  }
+
+  void handleOperatorName(Token operatorKeyword, Token token) {
+  }
+
+  void handleParenthesizedExpression(BeginGroupToken token) {
+  }
+
+  void handleQualified(Token period) {
+  }
+
+  void handleStringPart(Token token) {
+  }
+
+  void handleSuperExpression(Token token) {
+  }
+
+  void handleSwitchCase(int labelCount, int expressionCount,
+                        Token defaultKeyword, int statementCount,
+                        Token firstToken, Token endToken) {
+  }
+
+  void handleThisExpression(Token token) {
+  }
+
+  void handleUnaryPostfixAssignmentExpression(Token token) {
+  }
+
+  void handleUnaryPrefixExpression(Token token) {
+  }
+
+  void handleUnaryPrefixAssignmentExpression(Token token) {
+  }
+
+  void handleValuedFormalParameter(Token equals, Token token) {
+  }
+
+  void handleVoidKeyword(Token token) {
+  }
+
+  void beginYieldStatement(Token token) {
+  }
+
+  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+  }
+
+  Token expected(String string, Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected '$string', but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token synthesizeIdentifier(Token token) {
+    Token synthesizedToken =
+        new StringToken.fromString(
+            Precedence.IDENTIFIER_INFO, '?', token.charOffset);
+    synthesizedToken.next = token.next;
+    return synthesizedToken;
+  }
+
+  Token expectedIdentifier(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected identifier, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedType(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a type, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedExpression(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected an expression, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token unexpected(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("unexpected token '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedBlockToSkip(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a block, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedFunctionBody(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a function body, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedClassBody(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a class body, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedClassBodyToSkip(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a class body, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedDeclaration(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("expected a declaration, but got '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  Token unmatched(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+    } else {
+      error("unmatched '${token.value}'", token);
+    }
+    return skipToEof(token);
+  }
+
+  skipToEof(Token token) {
+    while (!identical(token.info, Precedence.EOF_INFO)) {
+      token = token.next;
+    }
+    return token;
+  }
+
+  void recoverableError(Token token, String message) {
+    error(message, token);
+  }
+
+  void error(String message, Token token) {
+    throw new ParserError("$message @ ${token.charOffset}");
+  }
+
+  void reportError(Spannable spannable,
+                   MessageKind messageKind,
+                   [Map arguments = const {}]) {
+    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+    String message = template.message(arguments, true).toString();
+    Token token;
+    if (spannable is Token) {
+      token = spannable;
+    } else if (spannable is Node) {
+      token = spannable.getBeginToken();
+    } else {
+      throw new ParserError(message);
+    }
+    recoverableError(token, message);
+  }
+
+  void reportErrorToken(ErrorToken token) {
+    if (token is BadInputToken) {
+      String hex = token.character.toRadixString(16);
+      if (hex.length < 4) {
+        String padding = "0000".substring(hex.length);
+        hex = "$padding$hex";
+      }
+      reportError(
+          token, MessageKind.BAD_INPUT_CHARACTER, {'characterHex': hex});
+    } else if (token is UnterminatedToken) {
+      MessageKind kind;
+      var arguments = const {};
+      switch (token.start) {
+        case '1e':
+          kind = MessageKind.EXPONENT_MISSING;
+          break;
+        case '"':
+        case "'":
+        case '"""':
+        case "'''":
+        case 'r"':
+        case "r'":
+        case 'r"""':
+        case "r'''":
+          kind = MessageKind.UNTERMINATED_STRING;
+          arguments = {'quote': token.start};
+          break;
+        case '0x':
+          kind = MessageKind.HEX_DIGIT_EXPECTED;
+          break;
+        case r'$':
+          kind = MessageKind.MALFORMED_STRING_LITERAL;
+          break;
+        case '/*':
+          kind = MessageKind.UNTERMINATED_COMMENT;
+          break;
+        default:
+          kind = MessageKind.UNTERMINATED_TOKEN;
+          break;
+      }
+      reportError(token, kind, arguments);
+    } else if (token is UnmatchedToken) {
+      String begin = token.begin.value;
+      String end = closeBraceFor(begin);
+      reportError(
+          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
+    } else {
+      throw new SpannableAssertionFailure(token, token.assertionMessage);
+    }
+  }
+}
+
+String closeBraceFor(String openBrace) {
+  return const {
+    '(': ')',
+    '[': ']',
+    '{': '}',
+    '<': '>',
+    r'${': '}',
+  }[openBrace];
+}
+
+class ParserError {
+  final String reason;
+  ParserError(this.reason);
+  toString() => reason;
+}
diff --git a/pkg/compiler/lib/src/parser/member_listener.dart b/pkg/compiler/lib/src/parser/member_listener.dart
new file mode 100644
index 0000000..08656d3
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/member_listener.dart
@@ -0,0 +1,175 @@
+// 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 dart2js.parser.member_listener;
+
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticListener;
+import '../diagnostics/messages.dart' show
+    MessageKind;
+import '../elements/elements.dart' show
+    Element,
+    ElementKind,
+    Elements,
+    MetadataAnnotation;
+import '../elements/modelx.dart' show
+    ClassElementX,
+    ElementX,
+    FieldElementX,
+    VariableList;
+import '../tokens/token.dart' show
+    Token;
+import '../tree/tree.dart';
+import '../util/util.dart' show
+    Link;
+
+import 'partial_elements.dart' show
+    PartialConstructorElement,
+    PartialFunctionElement,
+    PartialMetadataAnnotation;
+import 'node_listener.dart' show
+    NodeListener;
+
+class MemberListener extends NodeListener {
+  final ClassElementX enclosingClass;
+
+  MemberListener(DiagnosticListener listener,
+                 ClassElementX enclosingElement)
+      : this.enclosingClass = enclosingElement,
+        super(listener, enclosingElement.compilationUnit);
+
+  bool isConstructorName(Node nameNode) {
+    if (enclosingClass == null ||
+        enclosingClass.kind != ElementKind.CLASS) {
+      return false;
+    }
+    String name;
+    if (nameNode.asIdentifier() != null) {
+      name = nameNode.asIdentifier().source;
+    } else {
+      Send send = nameNode.asSend();
+      name = send.receiver.asIdentifier().source;
+    }
+    return enclosingClass.name == name;
+  }
+
+  // TODO(johnniwinther): Remove this method.
+  String getMethodNameHack(Node methodName) {
+    Send send = methodName.asSend();
+    if (send == null) {
+      if (isConstructorName(methodName)) return '';
+      return methodName.asIdentifier().source;
+    }
+    Identifier receiver = send.receiver.asIdentifier();
+    Identifier selector = send.selector.asIdentifier();
+    Operator operator = selector.asOperator();
+    if (operator != null) {
+      assert(identical(receiver.source, 'operator'));
+      // TODO(ahe): It is a hack to compare to ')', but it beats
+      // parsing the node.
+      bool isUnary = identical(operator.token.next.next.stringValue, ')');
+      return Elements.constructOperatorName(operator.source, isUnary);
+    } else {
+      if (receiver == null || receiver.source != enclosingClass.name) {
+        listener.reportError(send.receiver,
+                                 MessageKind.INVALID_CONSTRUCTOR_NAME,
+                                 {'name': enclosingClass.name});
+      }
+      return selector.source;
+    }
+  }
+
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+    super.endMethod(getOrSet, beginToken, endToken);
+    FunctionExpression method = popNode();
+    pushNode(null);
+    bool isConstructor = isConstructorName(method.name);
+    String name = getMethodNameHack(method.name);
+    Element memberElement;
+    if (isConstructor) {
+      if (getOrSet != null) {
+        recoverableError(getOrSet, 'illegal modifier');
+      }
+      memberElement = new PartialConstructorElement(
+          name, beginToken, endToken,
+          ElementKind.GENERATIVE_CONSTRUCTOR,
+          method.modifiers,
+          enclosingClass);
+    } else {
+      memberElement = new PartialFunctionElement(
+          name, beginToken, getOrSet, endToken,
+          method.modifiers, enclosingClass, hasBody: method.hasBody());
+    }
+    addMember(memberElement);
+  }
+
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    super.endFactoryMethod(beginToken, endToken);
+    FunctionExpression method = popNode();
+    pushNode(null);
+    String name = getMethodNameHack(method.name);
+    Identifier singleIdentifierName = method.name.asIdentifier();
+    if (singleIdentifierName != null && singleIdentifierName.source == name) {
+      if (name != enclosingClass.name) {
+        listener.reportError(singleIdentifierName,
+                                 MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
+                                 {'name': enclosingClass.name});
+      }
+    }
+    Element memberElement = new PartialConstructorElement(
+        name, beginToken, endToken,
+        ElementKind.FUNCTION,
+        method.modifiers,
+        enclosingClass);
+    addMember(memberElement);
+  }
+
+  void endFields(int count, Token beginToken, Token endToken) {
+    bool hasParseError = memberErrors.head;
+    super.endFields(count, beginToken, endToken);
+    VariableDefinitions variableDefinitions = popNode();
+    Modifiers modifiers = variableDefinitions.modifiers;
+    pushNode(null);
+    void buildFieldElement(Identifier name, VariableList fields) {
+      Element element =
+          new FieldElementX(name, enclosingClass, fields);
+      addMember(element);
+    }
+    buildFieldElements(modifiers, variableDefinitions.definitions,
+                       enclosingClass,
+                       buildFieldElement, beginToken, endToken,
+                       hasParseError);
+  }
+
+  void endInitializer(Token assignmentOperator) {
+    pushNode(null); // Super expects an expression, but
+                    // ClassElementParser just skips expressions.
+    super.endInitializer(assignmentOperator);
+  }
+
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    pushNode(null);
+  }
+
+  void addMetadata(ElementX memberElement) {
+    for (Link link = metadata; !link.isEmpty; link = link.tail) {
+      memberElement.addMetadata(link.head);
+    }
+    metadata = const Link<MetadataAnnotation>();
+  }
+
+  void addMember(ElementX memberElement) {
+    addMetadata(memberElement);
+    enclosingClass.addMember(memberElement, listener);
+  }
+
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    popNode(); // Discard arguments.
+    if (periodBeforeName != null) {
+      popNode(); // Discard name.
+    }
+    popNode(); // Discard node (Send or Identifier).
+    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
+  }
+}
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
new file mode 100644
index 0000000..455f53e
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -0,0 +1,816 @@
+// 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 dart2js.parser.node_listener;
+
+import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/messages.dart';
+import '../diagnostics/spannable.dart' show
+    Spannable,
+    SpannableAssertionFailure;
+import '../elements/elements.dart' show
+    CompilationUnitElement;
+import '../native/native.dart' as native;
+import '../tokens/precedence_constants.dart' as Precedence show
+    BAD_INPUT_INFO,
+    EOF_INFO,
+    INDEX_INFO;
+import '../tokens/token.dart' show
+    ErrorToken,
+    StringToken,
+    Token;
+import '../tree/tree.dart';
+import '../util/util.dart' show
+    Link;
+
+import 'element_listener.dart' show
+    ElementListener;
+import 'partial_elements.dart' show
+    PartialFunctionElement;
+
+class NodeListener extends ElementListener {
+  NodeListener(
+      DiagnosticListener listener,
+      CompilationUnitElement element)
+    : super(listener, element, null);
+
+  void addLibraryTag(LibraryTag tag) {
+    pushNode(tag);
+  }
+
+  void addPartOfTag(PartOf tag) {
+    pushNode(tag);
+  }
+
+  void endClassDeclaration(int interfacesCount, Token beginToken,
+                           Token extendsKeyword, Token implementsKeyword,
+                           Token endToken) {
+    NodeList body = popNode();
+    NodeList interfaces =
+        makeNodeList(interfacesCount, implementsKeyword, null, ",");
+    Node supertype = popNode();
+    NodeList typeParameters = popNode();
+    Identifier name = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new ClassNode(modifiers, name, typeParameters, supertype,
+                           interfaces, beginToken, extendsKeyword, body,
+                           endToken));
+  }
+
+  void endCompilationUnit(int count, Token token) {
+    pushNode(makeNodeList(count, null, null, '\n'));
+  }
+
+  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+    NodeList formals = popNode();
+    NodeList typeParameters = popNode();
+    Identifier name = popNode();
+    TypeAnnotation returnType = popNode();
+    pushNode(new Typedef(returnType, name, typeParameters, formals,
+                         typedefKeyword, endToken));
+  }
+
+  void endNamedMixinApplication(Token classKeyword,
+                                Token implementsKeyword,
+                                Token endToken) {
+    NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
+    Node mixinApplication = popNode();
+    Modifiers modifiers = popNode();
+    NodeList typeParameters = popNode();
+    Identifier name = popNode();
+    pushNode(new NamedMixinApplication(name, typeParameters,
+                                       modifiers, mixinApplication,
+                                       interfaces,
+                                       classKeyword, endToken));
+  }
+
+  void endEnum(Token enumKeyword, Token endBrace, int count) {
+    NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
+    Identifier name = popNode();
+    pushNode(new Enum(enumKeyword, name, names));
+  }
+
+  void endClassBody(int memberCount, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(memberCount, beginToken, endToken, null));
+  }
+
+  void endTopLevelFields(int count, Token beginToken, Token endToken) {
+    NodeList variables = makeNodeList(count, null, endToken, ",");
+    TypeAnnotation type = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new VariableDefinitions(type, modifiers, variables));
+  }
+
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+    popNode(); // body
+    popNode(); // formalParameters
+    Identifier name = popNode();
+    popNode(); // type
+    Modifiers modifiers = popNode();
+    PartialFunctionElement element = new PartialFunctionElement(
+        name.source, beginToken, getOrSet, endToken,
+        modifiers, compilationUnitElement);
+    pushElement(element);
+  }
+
+  void endFormalParameter(Token thisKeyword) {
+    Expression name = popNode();
+    if (thisKeyword != null) {
+      Identifier thisIdentifier = new Identifier(thisKeyword);
+      if (name.asSend() == null) {
+        name = new Send(thisIdentifier, name);
+      } else {
+        name = name.asSend().copyWithReceiver(thisIdentifier, false);
+      }
+    }
+    TypeAnnotation type = popNode();
+    Modifiers modifiers = popNode();
+    NodeList metadata = popNode();
+    pushNode(new VariableDefinitions.forParameter(
+        metadata, type, modifiers, new NodeList.singleton(name)));
+  }
+
+  void endFormalParameters(int count, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, endToken, ","));
+  }
+
+  void handleNoFormalParameters(Token token) {
+    pushNode(null);
+  }
+
+  void endArguments(int count, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, endToken, ","));
+  }
+
+  void handleNoArguments(Token token) {
+    pushNode(null);
+  }
+
+  void endConstructorReference(Token start, Token periodBeforeName,
+                               Token endToken) {
+    Identifier name = null;
+    if (periodBeforeName != null) {
+      name = popNode();
+    }
+    NodeList typeArguments = popNode();
+    Node classReference = popNode();
+    if (typeArguments != null) {
+      classReference = new TypeAnnotation(classReference, typeArguments);
+    } else {
+      Identifier identifier = classReference.asIdentifier();
+      Send send = classReference.asSend();
+      if (identifier != null) {
+        // TODO(ahe): Should be:
+        // classReference = new Send(null, identifier);
+        classReference = identifier;
+      } else if (send != null) {
+        classReference = send;
+      } else {
+        internalError(node: classReference);
+      }
+    }
+    Node constructor = classReference;
+    if (name != null) {
+      // Either typeName<args>.name or x.y.name.
+      constructor = new Send(classReference, name);
+    }
+    pushNode(constructor);
+  }
+
+  void endRedirectingFactoryBody(Token beginToken,
+                                 Token endToken) {
+    pushNode(new RedirectingFactoryBody(beginToken, endToken, popNode()));
+  }
+
+  void endReturnStatement(bool hasExpression,
+                          Token beginToken, Token endToken) {
+    Expression expression = hasExpression ? popNode() : null;
+    pushNode(new Return(beginToken, endToken, expression));
+  }
+
+  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
+    Expression expression = popNode();
+    pushNode(new Yield(yieldToken, starToken, expression, endToken));
+  }
+
+  void endExpressionStatement(Token token) {
+    pushNode(new ExpressionStatement(popNode(), token));
+  }
+
+  void handleOnError(Token token, var errorInformation) {
+    listener.internalError(token, "'${token.value}': ${errorInformation}");
+  }
+
+  Token expectedFunctionBody(Token token) {
+    if (identical(token.stringValue, 'native')) {
+      return native.handleNativeFunctionBody(this, token);
+    } else if (token is ErrorToken) {
+      pushNode(null);
+      reportErrorToken(token);
+    } else {
+      reportFatalError(token,
+                       "Expected a function body, but got '${token.value}'.");
+    }
+    return skipToEof(token);
+  }
+
+  Token expectedClassBody(Token token) {
+    if (token is ErrorToken) {
+      reportErrorToken(token);
+      return skipToEof(token);
+    } else {
+      reportFatalError(token,
+                       "Expected a class body, but got '${token.value}'.");
+      return skipToEof(token);
+    }
+  }
+
+  void handleLiteralInt(Token token) {
+    pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e)));
+  }
+
+  void handleLiteralDouble(Token token) {
+    pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e)));
+  }
+
+  void handleLiteralBool(Token token) {
+    pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e)));
+  }
+
+  void handleLiteralNull(Token token) {
+    pushNode(new LiteralNull(token));
+  }
+
+  void endLiteralSymbol(Token hashToken, int identifierCount) {
+    NodeList identifiers = makeNodeList(identifierCount, null, null, '.');
+    pushNode(new LiteralSymbol(hashToken, identifiers));
+  }
+
+  void handleBinaryExpression(Token token) {
+    Node argument = popNode();
+    Node receiver = popNode();
+    String tokenString = token.stringValue;
+    if (identical(tokenString, '.') ||
+        identical(tokenString, '..') ||
+        identical(tokenString, '?.')) {
+      Send argumentSend = argument.asSend();
+      if (argumentSend == null) {
+        // TODO(ahe): The parser should diagnose this problem, not
+        // this listener.
+        reportFatalError(argument,
+                         'Expected an identifier.');
+      }
+      if (argumentSend.receiver != null) internalError(node: argument);
+      if (argument is SendSet) internalError(node: argument);
+      pushNode(argument.asSend().copyWithReceiver(receiver,
+            identical(tokenString, '?.')));
+    } else {
+      NodeList arguments = new NodeList.singleton(argument);
+      pushNode(new Send(receiver, new Operator(token), arguments));
+    }
+    if (identical(tokenString, '===')) {
+      listener.reportError(token, MessageKind.UNSUPPORTED_EQ_EQ_EQ,
+                           {'lhs': receiver, 'rhs': argument});
+    }
+    if (identical(tokenString, '!==')) {
+      listener.reportError(token, MessageKind.UNSUPPORTED_BANG_EQ_EQ,
+                           {'lhs': receiver, 'rhs': argument});
+    }
+  }
+
+  void beginCascade(Token token) {
+    pushNode(new CascadeReceiver(popNode(), token));
+  }
+
+  void endCascade() {
+    pushNode(new Cascade(popNode()));
+  }
+
+  void handleAsOperator(Token operathor, Token endToken) {
+    TypeAnnotation type = popNode();
+    Expression expression = popNode();
+    NodeList arguments = new NodeList.singleton(type);
+    pushNode(new Send(expression, new Operator(operathor), arguments));
+  }
+
+  void handleAssignmentExpression(Token token) {
+    Node arg = popNode();
+    Node node = popNode();
+    Send send = node.asSend();
+    if (send == null || !(send.isPropertyAccess || send.isIndex)) {
+      reportNotAssignable(node);
+    }
+    if (send.asSendSet() != null) internalError(node: send);
+    NodeList arguments;
+    if (send.isIndex) {
+      Link<Node> link = const Link<Node>().prepend(arg);
+      link = link.prepend(send.arguments.head);
+      arguments = new NodeList(null, link);
+    } else {
+      arguments = new NodeList.singleton(arg);
+    }
+    Operator op = new Operator(token);
+    pushNode(new SendSet(send.receiver, send.selector, op, arguments,
+        send.isConditional));
+  }
+
+  void reportNotAssignable(Node node) {
+    // TODO(ahe): The parser should diagnose this problem, not this
+    // listener.
+    reportFatalError(node,
+                     'Not assignable.');
+  }
+
+  void handleConditionalExpression(Token question, Token colon) {
+    Node elseExpression = popNode();
+    Node thenExpression = popNode();
+    Node condition = popNode();
+    pushNode(new Conditional(
+        condition, thenExpression, elseExpression, question, colon));
+  }
+
+  void endSend(Token token) {
+    NodeList arguments = popNode();
+    Node selector = popNode();
+    // TODO(ahe): Handle receiver.
+    pushNode(new Send(null, selector, arguments));
+  }
+
+  void endFunctionBody(int count, Token beginToken, Token endToken) {
+    if (count == 0 && beginToken == null) {
+      pushNode(new EmptyStatement(endToken));
+    } else {
+      pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
+    }
+  }
+
+  void handleAsyncModifier(Token asyncToken, Token starToken) {
+    if (asyncToken != null) {
+      pushNode(new AsyncModifier(asyncToken, starToken));
+    } else {
+      pushNode(null);
+    }
+  }
+
+  void skippedFunctionBody(Token token) {
+    pushNode(new Block(new NodeList.empty()));
+  }
+
+  void handleNoFunctionBody(Token token) {
+    pushNode(new EmptyStatement(token));
+  }
+
+  void endFunction(Token getOrSet, Token endToken) {
+    Statement body = popNode();
+    AsyncModifier asyncModifier = popNode();
+    NodeList initializers = popNode();
+    NodeList formals = popNode();
+    // The name can be an identifier or a send in case of named constructors.
+    Expression name = popNode();
+    TypeAnnotation type = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new FunctionExpression(name, formals, body, type,
+                                    modifiers, initializers, getOrSet,
+                                    asyncModifier));
+  }
+
+  void endFunctionDeclaration(Token endToken) {
+    pushNode(new FunctionDeclaration(popNode()));
+  }
+
+  void endVariablesDeclaration(int count, Token endToken) {
+    // TODO(ahe): Pick one name for this concept, either
+    // VariablesDeclaration or VariableDefinitions.
+    NodeList variables = makeNodeList(count, null, endToken, ",");
+    TypeAnnotation type = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new VariableDefinitions(type, modifiers, variables));
+  }
+
+  void endInitializer(Token assignmentOperator) {
+    Expression initializer = popNode();
+    NodeList arguments =
+        initializer == null ? null : new NodeList.singleton(initializer);
+    Expression name = popNode();
+    Operator op = new Operator(assignmentOperator);
+    pushNode(new SendSet(null, name, op, arguments));
+  }
+
+  void endIfStatement(Token ifToken, Token elseToken) {
+    Statement elsePart = (elseToken == null) ? null : popNode();
+    Statement thenPart = popNode();
+    ParenthesizedExpression condition = popNode();
+    pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken));
+  }
+
+  void endForStatement(int updateExpressionCount,
+                       Token beginToken, Token endToken) {
+    Statement body = popNode();
+    NodeList updates = makeNodeList(updateExpressionCount, null, null, ',');
+    Statement condition = popNode();
+    Node initializer = popNode();
+    pushNode(new For(initializer, condition, updates, body, beginToken));
+  }
+
+  void handleNoExpression(Token token) {
+    pushNode(null);
+  }
+
+  void endDoWhileStatement(Token doKeyword, Token whileKeyword,
+                           Token endToken) {
+    Expression condition = popNode();
+    Statement body = popNode();
+    pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken));
+  }
+
+  void endWhileStatement(Token whileKeyword, Token endToken) {
+    Statement body = popNode();
+    Expression condition = popNode();
+    pushNode(new While(condition, body, whileKeyword));
+  }
+
+  void endBlock(int count, Token beginToken, Token endToken) {
+    pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
+  }
+
+  void endThrowExpression(Token throwToken, Token endToken) {
+    Expression expression = popNode();
+    pushNode(new Throw(expression, throwToken, endToken));
+  }
+
+  void endAwaitExpression(Token awaitToken, Token endToken) {
+    Expression expression = popNode();
+    pushNode(new Await(awaitToken, expression));
+  }
+
+  void endRethrowStatement(Token throwToken, Token endToken) {
+    pushNode(new Rethrow(throwToken, endToken));
+    if (identical(throwToken.stringValue, 'throw')) {
+      listener.reportError(throwToken,
+                           MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
+    }
+  }
+
+  void handleUnaryPrefixExpression(Token token) {
+    pushNode(new Send.prefix(popNode(), new Operator(token)));
+  }
+
+  void handleSuperExpression(Token token) {
+    pushNode(new Identifier(token));
+  }
+
+  void handleThisExpression(Token token) {
+    pushNode(new Identifier(token));
+  }
+
+  void handleUnaryAssignmentExpression(Token token, bool isPrefix) {
+    Node node = popNode();
+    Send send = node.asSend();
+    if (send == null) {
+      reportNotAssignable(node);
+    }
+    if (!(send.isPropertyAccess || send.isIndex)) {
+      reportNotAssignable(node);
+    }
+    if (send.asSendSet() != null) internalError(node: send);
+    Node argument = null;
+    if (send.isIndex) argument = send.arguments.head;
+    Operator op = new Operator(token);
+
+    if (isPrefix) {
+      pushNode(new SendSet.prefix(send.receiver, send.selector, op, argument,
+          send.isConditional));
+    } else {
+      pushNode(new SendSet.postfix(send.receiver, send.selector, op, argument,
+          send.isConditional));
+    }
+  }
+
+  void handleUnaryPostfixAssignmentExpression(Token token) {
+    handleUnaryAssignmentExpression(token, false);
+  }
+
+  void handleUnaryPrefixAssignmentExpression(Token token) {
+    handleUnaryAssignmentExpression(token, true);
+  }
+
+  void endInitializers(int count, Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, null, ','));
+  }
+
+  void handleNoInitializers() {
+    pushNode(null);
+  }
+
+  void endFields(int count, Token beginToken, Token endToken) {
+    NodeList variables = makeNodeList(count, null, endToken, ",");
+    TypeAnnotation type = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new VariableDefinitions(type, modifiers, variables));
+  }
+
+  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
+    Statement body = popNode();
+    AsyncModifier asyncModifier = popNode();
+    NodeList initializers = popNode();
+    NodeList formalParameters = popNode();
+    Expression name = popNode();
+    TypeAnnotation returnType = popNode();
+    Modifiers modifiers = popNode();
+    pushNode(new FunctionExpression(name, formalParameters, body, returnType,
+                                    modifiers, initializers, getOrSet,
+                                    asyncModifier));
+  }
+
+  void handleLiteralMap(int count, Token beginToken, Token constKeyword,
+                        Token endToken) {
+    NodeList entries = makeNodeList(count, beginToken, endToken, ',');
+    NodeList typeArguments = popNode();
+    pushNode(new LiteralMap(typeArguments, entries, constKeyword));
+  }
+
+  void endLiteralMapEntry(Token colon, Token endToken) {
+    Expression value = popNode();
+    Expression key = popNode();
+    pushNode(new LiteralMapEntry(key, colon, value));
+  }
+
+  void handleLiteralList(int count, Token beginToken, Token constKeyword,
+                         Token endToken) {
+    NodeList elements = makeNodeList(count, beginToken, endToken, ',');
+    pushNode(new LiteralList(popNode(), elements, constKeyword));
+  }
+
+  void handleIndexedExpression(Token openSquareBracket,
+                               Token closeSquareBracket) {
+    NodeList arguments =
+        makeNodeList(1, openSquareBracket, closeSquareBracket, null);
+    Node receiver = popNode();
+    Token token = new StringToken.fromString(Precedence.INDEX_INFO, '[]',
+                                  openSquareBracket.charOffset);
+    Node selector = new Operator(token);
+    pushNode(new Send(receiver, selector, arguments));
+  }
+
+  void handleNewExpression(Token token) {
+    NodeList arguments = popNode();
+    Node name = popNode();
+    pushNode(new NewExpression(token, new Send(null, name, arguments)));
+  }
+
+  void handleConstExpression(Token token) {
+    // [token] carries the 'const' information.
+    handleNewExpression(token);
+  }
+
+  void handleOperator(Token token) {
+    pushNode(new Operator(token));
+  }
+
+  void handleOperatorName(Token operatorKeyword, Token token) {
+    Operator op = new Operator(token);
+    pushNode(new Send(new Identifier(operatorKeyword), op, null));
+  }
+
+  void handleNamedArgument(Token colon) {
+    Expression expression = popNode();
+    Identifier name = popNode();
+    pushNode(new NamedArgument(name, colon, expression));
+  }
+
+  void endOptionalFormalParameters(int count,
+                                   Token beginToken, Token endToken) {
+    pushNode(makeNodeList(count, beginToken, endToken, ','));
+  }
+
+  void handleFunctionTypedFormalParameter(Token endToken) {
+    NodeList formals = popNode();
+    Identifier name = popNode();
+    TypeAnnotation returnType = popNode();
+    pushNode(null); // Signal "no type" to endFormalParameter.
+    pushNode(new FunctionExpression(name, formals, null, returnType,
+                                    Modifiers.EMPTY, null, null, null));
+  }
+
+  void handleValuedFormalParameter(Token equals, Token token) {
+    Expression defaultValue = popNode();
+    Expression parameterName = popNode();
+    pushNode(new SendSet(null, parameterName, new Operator(equals),
+                         new NodeList.singleton(defaultValue)));
+  }
+
+  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
+    Block finallyBlock = null;
+    if (finallyKeyword != null) {
+      finallyBlock = popNode();
+    }
+    NodeList catchBlocks = makeNodeList(catchCount, null, null, null);
+    Block tryBlock = popNode();
+    pushNode(new TryStatement(tryBlock, catchBlocks, finallyBlock,
+                              tryKeyword, finallyKeyword));
+  }
+
+  void handleCaseMatch(Token caseKeyword, Token colon) {
+    pushNode(new CaseMatch(caseKeyword, popNode(), colon));
+  }
+
+  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
+    Block block = popNode();
+    NodeList formals = catchKeyword != null? popNode(): null;
+    TypeAnnotation type = onKeyword != null ? popNode() : null;
+    pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword));
+  }
+
+  void endSwitchStatement(Token switchKeyword, Token endToken) {
+    NodeList cases = popNode();
+    ParenthesizedExpression expression = popNode();
+    pushNode(new SwitchStatement(expression, cases, switchKeyword));
+  }
+
+  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
+    Link<Node> caseNodes = const Link<Node>();
+    while (caseCount > 0) {
+      SwitchCase switchCase = popNode();
+      caseNodes = caseNodes.prepend(switchCase);
+      caseCount--;
+    }
+    pushNode(new NodeList(beginToken, caseNodes, endToken, null));
+  }
+
+  void handleSwitchCase(int labelCount, int caseCount,
+                        Token defaultKeyword, int statementCount,
+                        Token firstToken, Token endToken) {
+    NodeList statements = makeNodeList(statementCount, null, null, null);
+    NodeList labelsAndCases =
+        makeNodeList(labelCount + caseCount, null, null, null);
+    pushNode(new SwitchCase(labelsAndCases, defaultKeyword, statements,
+                            firstToken));
+  }
+
+  void handleBreakStatement(bool hasTarget,
+                            Token breakKeyword, Token endToken) {
+    Identifier target = null;
+    if (hasTarget) {
+      target = popNode();
+    }
+    pushNode(new BreakStatement(target, breakKeyword, endToken));
+  }
+
+  void handleContinueStatement(bool hasTarget,
+                               Token continueKeyword, Token endToken) {
+    Identifier target = null;
+    if (hasTarget) {
+      target = popNode();
+    }
+    pushNode(new ContinueStatement(target, continueKeyword, endToken));
+  }
+
+  void handleEmptyStatement(Token token) {
+    pushNode(new EmptyStatement(token));
+  }
+
+  void endFactoryMethod(Token beginToken, Token endToken) {
+    super.endFactoryMethod(beginToken, endToken);
+    Statement body = popNode();
+    AsyncModifier asyncModifier = popNode();
+    NodeList formals = popNode();
+    Node name = popNode();
+
+    // TODO(ahe): Move this parsing to the parser.
+    int modifierCount = 0;
+    Token modifier = beginToken;
+    if (modifier.stringValue == "external") {
+      handleModifier(modifier);
+      modifierCount++;
+      modifier = modifier.next;
+    }
+    if (modifier.stringValue == "const") {
+      handleModifier(modifier);
+      modifierCount++;
+      modifier = modifier.next;
+    }
+    assert(modifier.stringValue == "factory");
+    handleModifier(modifier);
+    modifierCount++;
+    handleModifiers(modifierCount);
+    Modifiers modifiers = popNode();
+
+    pushNode(new FunctionExpression(name, formals, body, null,
+                                    modifiers, null, null, asyncModifier));
+  }
+
+  void endForIn(Token awaitToken, Token forToken,
+                Token inKeyword, Token endToken) {
+    Statement body = popNode();
+    Expression expression = popNode();
+    Node declaredIdentifier = popNode();
+    if (awaitToken == null) {
+      pushNode(new SyncForIn(declaredIdentifier, expression, body,
+                             forToken, inKeyword));
+    } else {
+      pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken,
+                              forToken, inKeyword));
+    }
+  }
+
+  void endMetadataStar(int count, bool forParameter) {
+    // TODO(johnniwinther): Handle metadata for all node kinds.
+    if (forParameter) {
+      if (0 == count) {
+        pushNode(null);
+      } else {
+        pushNode(makeNodeList(count, null, null, ' '));
+      }
+    }
+  }
+
+  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+    NodeList arguments = popNode();
+    if (arguments == null) {
+      // This is a constant expression.
+      Identifier name;
+      if (periodBeforeName != null) {
+        name = popNode();
+      }
+      NodeList typeArguments = popNode();
+      Node receiver = popNode();
+      if (typeArguments != null) {
+        receiver = new TypeAnnotation(receiver, typeArguments);
+        recoverableError(typeArguments,
+                         'Type arguments are not allowed here.');
+      } else {
+        Identifier identifier = receiver.asIdentifier();
+        Send send = receiver.asSend();
+        if (identifier != null) {
+          receiver = new Send(null, identifier);
+        } else if (send == null) {
+          internalError(node: receiver);
+        }
+      }
+      Send send = receiver;
+      if (name != null) {
+        send = new Send(receiver, name);
+      }
+      pushNode(new Metadata(beginToken, send));
+    } else {
+      // This is a const constructor call.
+      endConstructorReference(beginToken, periodBeforeName, endToken);
+      Node constructor = popNode();
+      pushNode(new Metadata(beginToken,
+          new NewExpression(null,
+              new Send(null, constructor, arguments))));
+    }
+  }
+
+  void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
+    NodeList arguments = popNode();
+    Node selector = new Identifier(assertKeyword);
+    Node send = new Send(null, selector, arguments);
+    pushNode(new ExpressionStatement(send, semicolonToken));
+  }
+
+  void endUnnamedFunction(Token token) {
+    Statement body = popNode();
+    AsyncModifier asyncModifier = popNode();
+    NodeList formals = popNode();
+    pushNode(new FunctionExpression(null, formals, body, null,
+                                    Modifiers.EMPTY, null, null,
+                                    asyncModifier));
+  }
+
+  void handleIsOperator(Token operathor, Token not, Token endToken) {
+    TypeAnnotation type = popNode();
+    Expression expression = popNode();
+    Node argument;
+    if (not != null) {
+      argument = new Send.prefix(type, new Operator(not));
+    } else {
+      argument = type;
+    }
+
+    NodeList arguments = new NodeList.singleton(argument);
+    pushNode(new Send(expression, new Operator(operathor), arguments));
+  }
+
+  void handleLabel(Token colon) {
+    Identifier name = popNode();
+    pushNode(new Label(name, colon));
+  }
+
+  void endLabeledStatement(int labelCount) {
+    Statement statement = popNode();
+    NodeList labels = makeNodeList(labelCount, null, null, null);
+    pushNode(new LabeledStatement(labels, statement));
+  }
+
+  void log(message) {
+    listener.log(message);
+  }
+
+  void internalError({Token token, Node node}) {
+    // TODO(ahe): This should call listener.internalError.
+    Spannable spannable = (token == null) ? node : token;
+    throw new SpannableAssertionFailure(spannable, 'Internal error in parser.');
+  }
+}
diff --git a/pkg/compiler/lib/src/scanner/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
similarity index 98%
rename from pkg/compiler/lib/src/scanner/parser.dart
rename to pkg/compiler/lib/src/parser/parser.dart
index 66d26bd..68f96bc 100644
--- a/pkg/compiler/lib/src/scanner/parser.dart
+++ b/pkg/compiler/lib/src/parser/parser.dart
@@ -2,7 +2,65 @@
 // for 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 scanner;
+library dart2js.parser;
+
+import '../diagnostics/messages.dart' show
+    MessageKind;
+import '../tokens/keyword.dart' show
+    Keyword;
+import '../tokens/precedence.dart' show
+    PrecedenceInfo;
+import '../tokens/precedence_constants.dart' show
+    AS_INFO,
+    ASSIGNMENT_PRECEDENCE,
+    CASCADE_PRECEDENCE,
+    EQUALITY_PRECEDENCE,
+    GT_INFO,
+    GT_GT_INFO,
+    IS_INFO,
+    MINUS_MINUS_INFO,
+    OPEN_PAREN_INFO,
+    OPEN_SQUARE_BRACKET_INFO,
+    PERIOD_INFO,
+    PLUS_PLUS_INFO,
+    POSTFIX_PRECEDENCE,
+    QUESTION_INFO,
+    QUESTION_PERIOD_INFO,
+    RELATIONAL_PRECEDENCE;
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    isUserDefinableOperator,
+    KeywordToken,
+    SymbolToken,
+    Token;
+import '../tokens/token_constants.dart' show
+    BAD_INPUT_TOKEN,
+    COMMA_TOKEN,
+    DOUBLE_TOKEN,
+    EOF_TOKEN,
+    EQ_TOKEN,
+    FUNCTION_TOKEN,
+    HASH_TOKEN,
+    HEXADECIMAL_TOKEN,
+    IDENTIFIER_TOKEN,
+    INT_TOKEN,
+    KEYWORD_TOKEN,
+    LT_TOKEN,
+    OPEN_CURLY_BRACKET_TOKEN,
+    OPEN_PAREN_TOKEN,
+    OPEN_SQUARE_BRACKET_TOKEN,
+    PERIOD_TOKEN,
+    SEMICOLON_TOKEN,
+    STRING_INTERPOLATION_IDENTIFIER_TOKEN,
+    STRING_INTERPOLATION_TOKEN,
+    STRING_TOKEN;
+import '../util/characters.dart' as Characters show
+    $CLOSE_CURLY_BRACKET;
+import '../util/util.dart' show
+    Link;
+
+import 'listener.dart' show
+    Listener;
 
 class FormalParameterType {
   final String type;
@@ -452,7 +510,7 @@
     Token endGroup = beginGroupToken.endGroup;
     if (endGroup == null) {
       return listener.unmatched(beginGroupToken);
-    } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
+    } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) {
       return listener.unmatched(beginGroupToken);
     }
     return beginGroupToken.endGroup;
diff --git a/pkg/compiler/lib/src/scanner/parser_task.dart b/pkg/compiler/lib/src/parser/parser_task.dart
similarity index 66%
rename from pkg/compiler/lib/src/scanner/parser_task.dart
rename to pkg/compiler/lib/src/parser/parser_task.dart
index c680a31..a0e900a4 100644
--- a/pkg/compiler/lib/src/scanner/parser_task.dart
+++ b/pkg/compiler/lib/src/parser/parser_task.dart
@@ -2,7 +2,27 @@
 // for 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 scanner;
+library dart2js.parser.task;
+
+import '../common/tasks.dart' show
+    CompilerTask;
+import '../compiler.dart' show
+    Compiler;
+import '../diagnostics/invariant.dart' show
+    invariant;
+import '../elements/modelx.dart' show
+    ElementX;
+import '../tokens/token.dart' show
+    Token;
+import '../tree/tree.dart' show
+    Node;
+
+import 'listener.dart' show
+    ParserError;
+import 'node_listener.dart' show
+    NodeListener;
+import 'parser.dart' show
+    Parser;
 
 class ParserTask extends CompilerTask {
   ParserTask(Compiler compiler) : super(compiler);
diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart
new file mode 100644
index 0000000..0b489a1
--- /dev/null
+++ b/pkg/compiler/lib/src/parser/partial_elements.dart
@@ -0,0 +1,499 @@
+// 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 dart2js.parser.partial_elements;
+
+import '../compiler.dart' show
+    Compiler;
+import '../dart_types.dart' show DynamicType;
+import '../diagnostics/diagnostic_listener.dart';
+import '../diagnostics/invariant.dart' show
+    invariant;
+import '../diagnostics/messages.dart';
+import '../elements/elements.dart' show
+    CompilationUnitElement,
+    ConstructorElement,
+    Element,
+    ElementKind,
+    GetterElement,
+    LibraryElement,
+    MetadataAnnotation,
+    MethodElement,
+    SetterElement,
+    STATE_NOT_STARTED,
+    STATE_DONE;
+import '../elements/modelx.dart' show
+    BaseFunctionElementX,
+    ClassElementX,
+    ConstructorElementX,
+    DeclarationSite,
+    ElementX,
+    FieldElementX,
+    GetterElementX,
+    MetadataAnnotationX,
+    MethodElementX,
+    SetterElementX,
+    TypedefElementX,
+    VariableList;
+import '../elements/visitor.dart' show
+    ElementVisitor;
+import '../tokens/token.dart' show
+    BadInputToken,
+    BeginGroupToken,
+    ErrorToken,
+    KeywordToken,
+    StringToken,
+    Token,
+    UnmatchedToken,
+    UnterminatedToken;
+import '../tokens/token_constants.dart' as Tokens show
+    EOF_TOKEN;
+import '../tree/tree.dart';
+
+import 'class_element_parser.dart' show
+    ClassElementParser;
+import 'parser.dart' show
+    Parser;
+import 'listener.dart' show
+    ParserError;
+import 'member_listener.dart' show
+    MemberListener;
+import 'node_listener.dart' show
+    NodeListener;
+
+abstract class PartialElement implements DeclarationSite {
+  Token beginToken;
+  Token endToken;
+
+  bool hasParseError = false;
+
+  bool get isErroneous => hasParseError;
+
+  DeclarationSite get declarationSite => this;
+}
+
+abstract class PartialFunctionMixin implements BaseFunctionElementX {
+  FunctionExpression cachedNode;
+  Modifiers get modifiers;
+  Token beginToken;
+  Token getOrSet;
+  Token endToken;
+
+  /**
+   * The position is computed in the constructor using [findMyName]. Computing
+   * it on demand fails in case tokens are GC'd.
+   */
+  Token _position;
+
+  void init(Token beginToken, Token getOrSet, Token endToken) {
+    this.beginToken = beginToken;
+    this.getOrSet = getOrSet;
+    this.endToken = endToken;
+    _position = ElementX.findNameToken(
+        beginToken,
+        modifiers.isFactory || isGenerativeConstructor,
+        name, enclosingElement.name);
+  }
+
+  bool get hasNode => cachedNode != null;
+
+  FunctionExpression get node {
+    assert(invariant(this, cachedNode != null,
+        message: "Node has not been computed for $this."));
+    return cachedNode;
+  }
+
+  FunctionExpression parseNode(DiagnosticListener listener) {
+    if (cachedNode != null) return cachedNode;
+    parseFunction(Parser p) {
+      if (isClassMember && modifiers.isFactory) {
+        p.parseFactoryMethod(beginToken);
+      } else {
+        p.parseFunction(beginToken, getOrSet);
+      }
+    }
+    cachedNode = parse(listener, this, declarationSite, parseFunction);
+    return cachedNode;
+  }
+
+  Token get position => _position;
+
+  void reusePartialFunctionMixin() {
+    cachedNode = null;
+  }
+
+  DeclarationSite get declarationSite;
+}
+
+abstract class PartialFunctionElement
+    implements PartialElement, PartialFunctionMixin {
+
+  factory PartialFunctionElement(
+      String name,
+      Token beginToken,
+      Token getOrSet,
+      Token endToken,
+      Modifiers modifiers,
+      Element enclosingElement,
+      {bool hasBody: true}) {
+    if (getOrSet == null) {
+      return new PartialMethodElement(
+          name, beginToken, endToken, modifiers,
+          enclosingElement, hasBody: hasBody);
+    } else if (identical(getOrSet.stringValue, 'get')) {
+      return new PartialGetterElement(
+          name, beginToken, getOrSet, endToken, modifiers,
+          enclosingElement, hasBody: hasBody);
+    } else {
+      assert(identical(getOrSet.stringValue, 'set'));
+      return new PartialSetterElement(
+          name, beginToken, getOrSet, endToken, modifiers,
+          enclosingElement, hasBody: hasBody);
+    }
+  }
+
+  PartialFunctionElement copyWithEnclosing(Element enclosing);
+}
+
+
+class PartialMethodElement extends MethodElementX
+    with PartialElement, PartialFunctionMixin
+    implements PartialFunctionElement {
+  PartialMethodElement(String name,
+                       Token beginToken,
+                       Token endToken,
+                       Modifiers modifiers,
+                       Element enclosing,
+                       {bool hasBody: true})
+      : super(name, ElementKind.FUNCTION, modifiers, enclosing, hasBody) {
+    init(beginToken, null, endToken);
+  }
+
+  void reuseElement() {
+    super.reuseElement();
+    reusePartialFunctionMixin();
+  }
+
+  PartialMethodElement copyWithEnclosing(Element enclosing) {
+    return new PartialMethodElement(
+        name, beginToken, endToken, modifiers, enclosing, hasBody: hasBody);
+  }
+}
+
+class PartialGetterElement extends GetterElementX
+    with PartialElement, PartialFunctionMixin
+    implements GetterElement, PartialFunctionElement  {
+  PartialGetterElement(String name,
+                       Token beginToken,
+                       Token getToken,
+                       Token endToken,
+                       Modifiers modifiers,
+                       Element enclosing,
+                       {bool hasBody: true})
+      : super(name, modifiers, enclosing, hasBody) {
+    init(beginToken, getToken, endToken);
+  }
+
+  @override
+  SetterElement get setter => abstractField.setter;
+
+  void reuseElement() {
+    super.reuseElement();
+    reusePartialFunctionMixin();
+  }
+
+  PartialGetterElement copyWithEnclosing(Element enclosing) {
+    return new PartialGetterElement(
+        name, beginToken, getOrSet, endToken, modifiers, enclosing,
+        hasBody: hasBody);
+  }
+}
+
+class PartialSetterElement extends SetterElementX
+    with PartialElement, PartialFunctionMixin
+    implements SetterElement, PartialFunctionElement {
+  PartialSetterElement(String name,
+                       Token beginToken,
+                       Token setToken,
+                       Token endToken,
+                       Modifiers modifiers,
+                       Element enclosing,
+                       {bool hasBody: true})
+      : super(name, modifiers, enclosing, hasBody) {
+    init(beginToken, setToken, endToken);
+  }
+
+  @override
+  GetterElement get getter => abstractField.getter;
+
+  void reuseElement() {
+    super.reuseElement();
+    reusePartialFunctionMixin();
+  }
+
+  PartialSetterElement copyWithEnclosing(Element enclosing) {
+    return new PartialSetterElement(
+        name, beginToken, getOrSet, endToken, modifiers, enclosing,
+        hasBody: hasBody);
+  }
+}
+
+class PartialConstructorElement extends ConstructorElementX
+    with PartialElement, PartialFunctionMixin {
+  PartialConstructorElement(String name,
+                            Token beginToken,
+                            Token endToken,
+                            ElementKind kind,
+                            Modifiers modifiers,
+                            Element enclosing)
+      : super(name, kind, modifiers, enclosing) {
+    init(beginToken, null, endToken);
+  }
+
+  void reuseElement() {
+    super.reuseElement();
+    reusePartialFunctionMixin();
+  }
+}
+
+class PartialFieldList extends VariableList with PartialElement {
+  PartialFieldList(Token beginToken,
+                   Token endToken,
+                   Modifiers modifiers,
+                   bool hasParseError)
+      : super(modifiers) {
+    super.beginToken = beginToken;
+    super.endToken = endToken;
+    super.hasParseError = hasParseError;
+  }
+
+  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+    if (definitions != null) return definitions;
+    listener.withCurrentElement(element, () {
+      definitions = parse(
+          listener, element, declarationSite,
+          (Parser parser) => parser.parseMember(beginToken));
+
+      if (!hasParseError &&
+          !definitions.modifiers.isVar &&
+          !definitions.modifiers.isFinal &&
+          !definitions.modifiers.isConst &&
+          definitions.type == null &&
+          !definitions.isErroneous) {
+        listener.reportError(
+            definitions,
+            MessageKind.GENERIC,
+            { 'text': 'A field declaration must start with var, final, '
+                      'const, or a type annotation.' });
+      }
+    });
+    return definitions;
+  }
+
+  computeType(Element element, Compiler compiler) {
+    if (type != null) return type;
+    // TODO(johnniwinther): Compute this in the resolver.
+    compiler.withCurrentElement(element, () {
+      VariableDefinitions node = parseNode(element, compiler);
+      if (node.type != null) {
+        type = compiler.resolver.resolveTypeAnnotation(element, node.type);
+      } else {
+        type = const DynamicType();
+      }
+    });
+    assert(type != null);
+    return type;
+  }
+}
+
+class PartialTypedefElement extends TypedefElementX with PartialElement {
+
+  PartialTypedefElement(
+      String name,
+      Element enclosing,
+      Token beginToken,
+      Token endToken)
+      : super(name, enclosing) {
+    this.beginToken = beginToken;
+    this.endToken = endToken;
+  }
+
+  Token get token => beginToken;
+
+  Node parseNode(DiagnosticListener listener) {
+    if (cachedNode != null) return cachedNode;
+    cachedNode = parse(
+        listener, this, declarationSite,
+        (p) => p.parseTopLevelDeclaration(token));
+    return cachedNode;
+  }
+
+  Token get position => findMyName(token);
+}
+
+/// A [MetadataAnnotation] which is constructed on demand.
+class PartialMetadataAnnotation extends MetadataAnnotationX
+    implements PartialElement {
+  Token beginToken; // TODO(ahe): Make this final when issue 22065 is fixed.
+
+  final Token tokenAfterEndToken;
+
+  Expression cachedNode;
+
+  bool hasParseError = false;
+
+  PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
+
+  bool get isErroneous => hasParseError;
+
+  DeclarationSite get declarationSite => this;
+
+  Token get endToken {
+    Token token = beginToken;
+    while (token.kind != Tokens.EOF_TOKEN) {
+      if (identical(token.next, tokenAfterEndToken)) break;
+      token = token.next;
+    }
+    assert(token != null);
+    return token;
+  }
+
+  void set endToken(_) {
+    throw new UnsupportedError("endToken=");
+  }
+
+  Node parseNode(DiagnosticListener listener) {
+    if (cachedNode != null) return cachedNode;
+    var metadata = parse(listener,
+                         annotatedElement,
+                         declarationSite,
+                         (p) => p.parseMetadata(beginToken));
+    if (metadata is Metadata) {
+      cachedNode = metadata.expression;
+      return cachedNode;
+    } else {
+      assert (metadata is ErrorNode);
+      return metadata;
+    }
+  }
+
+  bool get hasNode => cachedNode != null;
+
+  Node get node {
+    assert(invariant(this, hasNode));
+    return cachedNode;
+  }
+}
+
+class PartialClassElement extends ClassElementX with PartialElement {
+  ClassNode cachedNode;
+
+  PartialClassElement(String name,
+                      Token beginToken,
+                      Token endToken,
+                      Element enclosing,
+                      int id)
+      : super(name, enclosing, id, STATE_NOT_STARTED) {
+    this.beginToken = beginToken;
+    this.endToken = endToken;
+  }
+
+  void set supertypeLoadState(int state) {
+    assert(state == STATE_NOT_STARTED || state == supertypeLoadState + 1);
+    assert(state <= STATE_DONE);
+    super.supertypeLoadState = state;
+  }
+
+  void set resolutionState(int state) {
+    assert(state == STATE_NOT_STARTED || state == resolutionState + 1);
+    assert(state <= STATE_DONE);
+    super.resolutionState = state;
+  }
+
+  bool get hasNode => cachedNode != null;
+
+  ClassNode get node {
+    assert(invariant(this, cachedNode != null,
+        message: "Node has not been computed for $this."));
+    return cachedNode;
+  }
+
+  ClassNode parseNode(Compiler compiler) {
+    if (cachedNode != null) return cachedNode;
+    compiler.withCurrentElement(this, () {
+      compiler.parser.measure(() {
+        MemberListener listener = new MemberListener(compiler, this);
+        Parser parser = new ClassElementParser(listener);
+        try {
+          Token token = parser.parseTopLevelDeclaration(beginToken);
+          assert(identical(token, endToken.next));
+          cachedNode = listener.popNode();
+          assert(
+              invariant(
+                  beginToken, listener.nodes.isEmpty,
+                  message: "Non-empty listener stack: ${listener.nodes}"));
+        } on ParserError {
+          // TODO(ahe): Often, a ParserError is thrown while parsing the class
+          // body. This means that the stack actually contains most of the
+          // information synthesized below. Consider rewriting the parser so
+          // endClassDeclaration is called before parsing the class body.
+          Identifier name = new Identifier(findMyName(beginToken));
+          NodeList typeParameters = null;
+          Node supertype = null;
+          NodeList interfaces = listener.makeNodeList(0, null, null, ",");
+          Token extendsKeyword = null;
+          NodeList body = listener.makeNodeList(0, beginToken, endToken, null);
+          cachedNode = new ClassNode(
+              Modifiers.EMPTY, name, typeParameters, supertype, interfaces,
+              beginToken, extendsKeyword, body, endToken);
+          hasParseError = true;
+        }
+      });
+      compiler.patchParser.measure(() {
+        if (isPatched) {
+          // TODO(lrn): Perhaps extract functionality so it doesn't
+          // need compiler.
+          compiler.patchParser.parsePatchClassNode(patch);
+        }
+      });
+    });
+    return cachedNode;
+  }
+
+  Token get position => beginToken;
+
+  // TODO(johnniwinther): Ensure that modifiers are always available.
+  Modifiers get modifiers =>
+      cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY;
+
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitClassElement(this, arg);
+  }
+
+  PartialClassElement copyWithEnclosing(CompilationUnitElement enclosing) {
+    return new PartialClassElement(name, beginToken, endToken, enclosing, id);
+  }
+}
+
+Node parse(
+    DiagnosticListener diagnosticListener,
+    ElementX element,
+    PartialElement partial,
+    doParse(Parser parser)) {
+  CompilationUnitElement unit = element.compilationUnit;
+  NodeListener listener = new NodeListener(diagnosticListener, unit);
+  listener.memberErrors = listener.memberErrors.prepend(false);
+  try {
+    if (partial.hasParseError) {
+      listener.suppressParseErrors = true;
+    }
+    doParse(new Parser(listener));
+  } on ParserError catch (e) {
+    partial.hasParseError = true;
+    return new ErrorNode(element.position, e.reason);
+  }
+  Node node = listener.popNode();
+  assert(listener.nodes.isEmpty);
+  return node;
+}
diff --git a/pkg/compiler/lib/src/scanner/partial_parser.dart b/pkg/compiler/lib/src/parser/partial_parser.dart
similarity index 90%
rename from pkg/compiler/lib/src/scanner/partial_parser.dart
rename to pkg/compiler/lib/src/parser/partial_parser.dart
index c6ccbf4..b0f5cd5 100644
--- a/pkg/compiler/lib/src/scanner/partial_parser.dart
+++ b/pkg/compiler/lib/src/parser/partial_parser.dart
@@ -2,7 +2,23 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of scanner;
+library dart2js.parser.partial;
+
+import '../diagnostics/messages.dart' show
+    MessageKind;
+import '../util/characters.dart' as Characters show
+    $CLOSE_CURLY_BRACKET;
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    ErrorToken,
+    Token;
+import '../tokens/token_constants.dart' as Tokens show
+    EOF_TOKEN;
+
+import 'listener.dart' show
+    Listener;
+import 'parser.dart' show
+    Parser;
 
 class PartialParser extends Parser {
   PartialParser(Listener listener) : super(listener);
@@ -29,7 +45,7 @@
     while (true) {
       final kind = token.kind;
       final value = token.stringValue;
-      if ((identical(kind, EOF_TOKEN)) ||
+      if ((identical(kind, Tokens.EOF_TOKEN)) ||
           (identical(value, ';')) ||
           (identical(value, ',')) ||
           (identical(value, '}')) ||
@@ -97,7 +113,7 @@
     Token endGroup = beginGroupToken.endGroup;
     if (endGroup == null) {
       return listener.unmatched(beginGroupToken);
-    } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
+    } else if (!identical(endGroup.kind, Characters.$CLOSE_CURLY_BRACKET)) {
       return listener.unmatched(beginGroupToken);
     }
     return endGroup;
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index 0631b16..0f30084 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -112,7 +112,7 @@
  *   element.
  */
 
-library patchparser;
+library dart2js.patchparser;
 
 import 'dart:async';
 
@@ -135,8 +135,25 @@
     SetterElementX;
 import 'library_loader.dart' show
     LibraryLoader;
-import 'scanner/scannerlib.dart';  // Scanner, Parsers, Listeners
+import 'parser/listener.dart' show
+    Listener,
+    ParserError;
+import 'parser/element_listener.dart' show
+    ElementListener;
+import 'parser/member_listener.dart' show
+    MemberListener;
+import 'parser/partial_elements.dart' show
+  PartialClassElement;
+import 'parser/partial_parser.dart' show
+    PartialParser;
+import 'parser/parser.dart' show
+    Parser;
+import 'scanner/scanner.dart' show
+    Scanner;
 import 'script.dart';
+import 'tokens/token.dart' show
+    StringToken,
+    Token;
 import 'util/util.dart';
 
 class PatchParserTask extends CompilerTask {
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index b09c4d9..e049206 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -377,7 +377,9 @@
           // superMember.declarations. Investigate why.
         } else if (cls == inherited.declarer.element) {
           // An error should already have been reported.
-          assert(invariant(declared.element, compiler.compilationFailed));
+          assert(invariant(declared.element, compiler.compilationFailed,
+              message: "Member $inherited inherited from its "
+                       "declaring class: ${cls}."));
           continue;
         }
 
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index cff366c..66af813 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -415,10 +415,9 @@
   }
 }
 
-class ConstructorResolver extends CommonResolverVisitor<Element> {
+class ConstructorResolver extends CommonResolverVisitor<ConstructorResult> {
   final ResolverVisitor resolver;
-  bool inConstContext;
-  DartType type;
+  final bool inConstContext;
 
   ConstructorResolver(Compiler compiler, this.resolver,
                       {bool this.inConstContext: false})
@@ -430,8 +429,10 @@
     throw 'not supported';
   }
 
-  ErroneousConstructorElementX failOrReturnErroneousConstructorElement(
+  ConstructorResult reportAndCreateErroneousConstructorElement(
       Spannable diagnosticNode,
+      ConstructorResultKind resultKind,
+      DartType type,
       Element enclosing,
       String name,
       MessageKind kind,
@@ -448,171 +449,281 @@
     } else {
       compiler.reportWarning(diagnosticNode, kind, arguments);
     }
-    return new ErroneousConstructorElementX(
+    ErroneousElement error = new ErroneousConstructorElementX(
         kind, arguments, name, enclosing);
+    if (type == null) {
+      type = new MalformedType(error, null);
+    }
+    return new ConstructorResult(resultKind, error, type);
   }
 
-  FunctionElement resolveConstructor(ClassElement cls,
-                                     Node diagnosticNode,
-                                     String constructorName) {
+  ConstructorResult resolveConstructor(
+      InterfaceType type,
+      Node diagnosticNode,
+      String constructorName) {
+    ClassElement cls = type.element;
     cls.ensureResolved(compiler);
-    Element result = cls.lookupConstructor(constructorName);
+    ConstructorElement constructor = cls.lookupConstructor(constructorName);
     // TODO(johnniwinther): Use [Name] for lookup.
     if (Name.isPrivateName(constructorName) &&
         resolver.enclosingElement.library != cls.library) {
-      result = null;
+      constructor = null;
     }
-    if (result == null) {
-      String fullConstructorName = Elements.constructorNameForDiagnostics(
-              cls.name,
-              constructorName);
-      return failOrReturnErroneousConstructorElement(
+    if (constructor == null) {
+      String fullConstructorName =
+          Elements.constructorNameForDiagnostics(cls.name, constructorName);
+      return reportAndCreateErroneousConstructorElement(
           diagnosticNode,
+          ConstructorResultKind.UNRESOLVED_CONSTRUCTOR, type,
           cls, constructorName,
           MessageKind.CANNOT_FIND_CONSTRUCTOR,
           {'constructorName': fullConstructorName},
           missingConstructor: true);
-    } else if (inConstContext && !result.isConst) {
-      error(diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
+    } else if (inConstContext && !constructor.isConst) {
+      compiler.reportError(
+          diagnosticNode, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
+      return new ConstructorResult(
+          ConstructorResultKind.NON_CONSTANT, constructor, type);
+    } else {
+      if (constructor.isGenerativeConstructor) {
+        if (cls.isAbstract) {
+          compiler.reportWarning(
+              diagnosticNode, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
+          registry.registerAbstractClassInstantiation();
+          return new ConstructorResult(
+              ConstructorResultKind.ABSTRACT, constructor, type);
+        } else {
+          return new ConstructorResult(
+              ConstructorResultKind.GENERATIVE, constructor, type);
+        }
+      } else {
+        assert(invariant(diagnosticNode, constructor.isFactoryConstructor,
+            message: "Unexpected constructor $constructor."));
+        return new ConstructorResult(
+            ConstructorResultKind.FACTORY, constructor, type);
+      }
     }
-    return result;
   }
 
-  Element visitNewExpression(NewExpression node) {
-    inConstContext = node.isConst;
+  ConstructorResult visitNewExpression(NewExpression node) {
     Node selector = node.send.selector;
-    Element element = visit(selector);
-    assert(invariant(selector, element != null,
-        message: 'No element return for $selector.'));
-    return finishConstructorReference(element, node.send.selector, node);
+    ConstructorResult result = visit(selector);
+    assert(invariant(selector, result != null,
+        message: 'No result returned for $selector.'));
+    return finishConstructorReference(result, node.send.selector, node);
   }
 
   /// Finishes resolution of a constructor reference and records the
   /// type of the constructed instance on [expression].
-  FunctionElement finishConstructorReference(Element element,
-                                             Node diagnosticNode,
-                                             Node expression) {
-    assert(invariant(diagnosticNode, element != null,
-        message: 'No element return for $diagnosticNode.'));
+  ConstructorResult finishConstructorReference(
+      ConstructorResult result,
+      Node diagnosticNode,
+      Node expression) {
+    assert(invariant(diagnosticNode, result != null,
+        message: 'No result returned for $diagnosticNode.'));
+
+    if (result.kind != null) {
+      resolver.registry.setType(expression, result.type);
+      return result;
+    }
+
     // Find the unnamed constructor if the reference resolved to a
     // class.
-    if (!Elements.isUnresolved(element) && !element.isConstructor) {
-      if (element.isClass) {
-        ClassElement cls = element;
-        cls.ensureResolved(compiler);
-        // The unnamed constructor may not exist, so [e] may become unresolved.
-        element = resolveConstructor(cls, diagnosticNode, '');
+    if (result.type != null) {
+      // The unnamed constructor may not exist, so [e] may become unresolved.
+      result = resolveConstructor(result.type, diagnosticNode, '');
+    } else {
+      Element element = result.element;
+      if (element.isErroneous) {
+        result = constructorResultForErroneous(diagnosticNode, element);
       } else {
-        element = failOrReturnErroneousConstructorElement(
+        result = reportAndCreateErroneousConstructorElement(
             diagnosticNode,
+            ConstructorResultKind.INVALID_TYPE, null,
             element, element.name,
             MessageKind.NOT_A_TYPE, {'node': diagnosticNode});
       }
-    } else if (element.isErroneous && element is! ErroneousElementX) {
-      // Parser error. The error has already been reported.
-      element = new ErroneousConstructorElementX(
-          MessageKind.NOT_A_TYPE, {'node': diagnosticNode},
-          element.name, element);
-      registry.registerThrowRuntimeError();
     }
-
-    if (type == null) {
-      if (Elements.isUnresolved(element)) {
-        type = const DynamicType();
-      } else {
-        type = element.enclosingClass.rawType;
-      }
-    }
-    resolver.registry.setType(expression, type);
-    return element;
+    resolver.registry.setType(expression, result.type);
+    return result;
   }
 
-  Element visitTypeAnnotation(TypeAnnotation node) {
-    assert(invariant(node, type == null));
+  ConstructorResult visitTypeAnnotation(TypeAnnotation node) {
     // This is not really resolving a type-annotation, but the name of the
     // constructor. Therefore we allow deferred types.
-    type = resolver.resolveTypeAnnotation(node,
-                                          malformedIsError: inConstContext,
-                                          deferredIsMalformed: false);
+    DartType type = resolver.resolveTypeAnnotation(
+        node,
+        malformedIsError: inConstContext,
+        deferredIsMalformed: false);
     registry.registerRequiredType(type, resolver.enclosingElement);
-    return type.element;
+    return constructorResultForType(node, type);
   }
 
-  Element visitSend(Send node) {
-    Element element = visit(node.receiver);
-    assert(invariant(node.receiver, element != null,
-        message: 'No element return for $node.receiver.'));
-    if (Elements.isUnresolved(element)) return element;
+  ConstructorResult visitSend(Send node) {
+    ConstructorResult receiver = visit(node.receiver);
+    assert(invariant(node.receiver, receiver != null,
+        message: 'No result returned for $node.receiver.'));
+    if (receiver.kind != null) {
+      assert(invariant(node, receiver.element.isErroneous,
+          message: "Unexpected prefix result: $receiver."));
+      // We have already found an error.
+      return receiver;
+    }
+
     Identifier name = node.selector.asIdentifier();
     if (name == null) internalError(node.selector, 'unexpected node');
 
-    if (element.isClass) {
-      ClassElement cls = element;
-      cls.ensureResolved(compiler);
-      return resolveConstructor(cls, name, name.source);
-    } else if (element.isPrefix) {
-      PrefixElement prefix = element;
-      element = prefix.lookupLocalMember(name.source);
-      element = Elements.unwrap(element, compiler, node);
-      if (element == null) {
-        return failOrReturnErroneousConstructorElement(
+    if (receiver.type != null) {
+      if (receiver.type.isInterfaceType) {
+        return resolveConstructor(receiver.type, name, name.source);
+      } else {
+        // TODO(johnniwinther): Update the message for the different types.
+        return reportAndCreateErroneousConstructorElement(
             name,
+            ConstructorResultKind.INVALID_TYPE, null,
             resolver.enclosingElement, name.source,
-            MessageKind.CANNOT_RESOLVE, {'name': name});
-      } else if (!element.isClass) {
-        return failOrReturnErroneousConstructorElement(
-            name,
-            resolver.enclosingElement, name.source,
-            MessageKind.NOT_A_TYPE, {'node': name},
-            isError: true);
+            MessageKind.NOT_A_TYPE, {'node': name});
       }
+    } else if (receiver.element.isPrefix) {
+      PrefixElement prefix = receiver.element;
+      Element member = prefix.lookupLocalMember(name.source);
+      return constructorResultForElement(node, name.source, member);
     } else {
-      internalError(node.receiver, 'unexpected element $element');
+      return internalError(node.receiver, 'unexpected receiver $receiver');
     }
-    return element;
   }
 
-  Element visitIdentifier(Identifier node) {
+  ConstructorResult visitIdentifier(Identifier node) {
     String name = node.source;
     Element element = resolver.reportLookupErrorIfAny(
         lookupInScope(compiler, node, resolver.scope, name), node, name);
     registry.useElement(node, element);
     // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
+    return constructorResultForElement(node, name, element);
+  }
+
+  /// Assumed to be called by [resolveRedirectingFactory].
+  ConstructorResult visitRedirectingFactoryBody(RedirectingFactoryBody node) {
+    Node constructorReference = node.constructorReference;
+    return finishConstructorReference(visit(constructorReference),
+        constructorReference, node);
+  }
+
+  ConstructorResult constructorResultForElement(
+      Node node, String name, Element element) {
+    element = Elements.unwrap(element, compiler, node);
     if (element == null) {
-      return failOrReturnErroneousConstructorElement(
+      return reportAndCreateErroneousConstructorElement(
           node,
+          ConstructorResultKind.INVALID_TYPE, null,
           resolver.enclosingElement, name,
           MessageKind.CANNOT_RESOLVE,
           {'name': name});
     } else if (element.isErroneous) {
-      return element;
+      return constructorResultForErroneous(node, element);
+    } else if (element.isClass) {
+      ClassElement cls = element;
+      cls.computeType(compiler);
+      return constructorResultForType(node, cls.rawType);
+    } else if (element.isPrefix) {
+      return new ConstructorResult.forElement(element);
     } else if (element.isTypedef) {
-      element = failOrReturnErroneousConstructorElement(
-          node,
-          resolver.enclosingElement, name,
-          MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name},
-          isError: true);
+      TypedefElement typdef = element;
+      typdef.ensureResolved(compiler);
+      return constructorResultForType(node, typdef.rawType);
     } else if (element.isTypeVariable) {
-      element = failOrReturnErroneousConstructorElement(
+      TypeVariableElement typeVariableElement = element;
+      return constructorResultForType(node, typeVariableElement.type);
+    } else {
+      return reportAndCreateErroneousConstructorElement(
           node,
+          ConstructorResultKind.INVALID_TYPE, null,
           resolver.enclosingElement, name,
-          MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
-          {'typeVariableName': name},
-          isError: true);
-    } else if (!element.isClass && !element.isPrefix) {
-      element = failOrReturnErroneousConstructorElement(
-          node,
-          resolver.enclosingElement, name,
-          MessageKind.NOT_A_TYPE, {'node': name},
-          isError: true);
+          MessageKind.NOT_A_TYPE, {'node': name});
     }
-    return element;
   }
 
-  /// Assumed to be called by [resolveRedirectingFactory].
-  Element visitRedirectingFactoryBody(RedirectingFactoryBody node) {
-    Node constructorReference = node.constructorReference;
-    return finishConstructorReference(visit(constructorReference),
-        constructorReference, node);
+  ConstructorResult constructorResultForErroneous(
+      Node node, Element error) {
+    if (error is! ErroneousElementX) {
+      // Parser error. The error has already been reported.
+      error = new ErroneousConstructorElementX(
+          MessageKind.NOT_A_TYPE, {'node': node},
+          error.name, error);
+      registry.registerThrowRuntimeError();
+    }
+    return new ConstructorResult(
+        ConstructorResultKind.INVALID_TYPE,
+        error,
+        new MalformedType(error, null));
+  }
+
+  ConstructorResult constructorResultForType(
+      Node node,
+      DartType type) {
+    String name = type.name;
+    if (type.isMalformed) {
+      return new ConstructorResult(
+          ConstructorResultKind.INVALID_TYPE, type.element, type);
+    } else if (type.isInterfaceType) {
+      return new ConstructorResult.forType(type);
+    } else if (type.isTypedef) {
+      return reportAndCreateErroneousConstructorElement(
+          node,
+          ConstructorResultKind.INVALID_TYPE, type,
+          resolver.enclosingElement, name,
+          MessageKind.CANNOT_INSTANTIATE_TYPEDEF, {'typedefName': name});
+    } else if (type.isTypeVariable) {
+      return reportAndCreateErroneousConstructorElement(
+          node,
+          ConstructorResultKind.INVALID_TYPE, type,
+          resolver.enclosingElement, name,
+          MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
+          {'typeVariableName': name});
+    }
+    internalError(node, "Unexpected constructor type $type");
+    return null;
+  }
+
+}
+
+enum ConstructorResultKind {
+  GENERATIVE,
+  FACTORY,
+  ABSTRACT,
+  INVALID_TYPE,
+  UNRESOLVED_CONSTRUCTOR,
+  NON_CONSTANT,
+}
+
+class ConstructorResult {
+  final ConstructorResultKind kind;
+  final Element element;
+  final DartType type;
+
+  ConstructorResult(this.kind, this.element, this.type);
+
+  ConstructorResult.forElement(this.element)
+      : kind = null,
+        type = null;
+
+  ConstructorResult.forType(this.type)
+      : kind = null,
+        element = null;
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('ConstructorResult(');
+    if (kind != null) {
+      sb.write('kind=$kind,');
+      sb.write('element=$element,');
+      sb.write('type=$type');
+    } else if (element != null) {
+      sb.write('element=$element');
+    } else {
+      sb.write('type=$type');
+    }
+    sb.write(')');
+    return sb.toString();
   }
 }
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index 16882dc..02c2c53 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -8,7 +8,11 @@
 import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart';
-import '../scanner/scannerlib.dart';
+import '../tokens/keyword.dart' show
+    Keyword;
+import '../tokens/precedence.dart';
+import '../tokens/precedence_constants.dart' as Precedence;
+import '../tokens/token.dart';
 import '../tree/tree.dart';
 import '../util/util.dart';
 
@@ -45,7 +49,8 @@
   }
 
   Token stringToken(String text) {
-    return new StringToken.fromString(IDENTIFIER_INFO, text, charOffset);
+    return new StringToken.fromString(
+        Precedence.IDENTIFIER_INFO, text, charOffset);
   }
 
   Token symbolToken(PrecedenceInfo info) {
@@ -70,16 +75,16 @@
   }
 
   NodeList argumentList(List<Node> nodes) {
-    return new NodeList(symbolToken(OPEN_PAREN_INFO),
+    return new NodeList(symbolToken(Precedence.OPEN_PAREN_INFO),
                         linkedList(nodes),
-                        symbolToken(CLOSE_PAREN_INFO),
+                        symbolToken(Precedence.CLOSE_PAREN_INFO),
                         ',');
   }
 
   Return returnStatement(Expression expression) {
     return new Return(
         keywordToken('return'),
-        symbolToken(SEMICOLON_INFO),
+        symbolToken(Precedence.SEMICOLON_INFO),
         expression);
   }
 
@@ -101,7 +106,7 @@
   }
 
   EmptyStatement emptyStatement() {
-    return new EmptyStatement(symbolToken(COMMA_INFO));
+    return new EmptyStatement(symbolToken(Precedence.COMMA_INFO));
   }
 
   LiteralInt literalInt(int value) {
@@ -118,17 +123,18 @@
   LiteralList listLiteral(List<Node> elements, {bool isConst: false}) {
     return new LiteralList(
         null,
-        new NodeList(symbolToken(OPEN_SQUARE_BRACKET_INFO),
+        new NodeList(symbolToken(Precedence.OPEN_SQUARE_BRACKET_INFO),
                      linkedList(elements),
-                     symbolToken(CLOSE_SQUARE_BRACKET_INFO),
+                     symbolToken(Precedence.CLOSE_SQUARE_BRACKET_INFO),
                      ','),
         isConst ? keywordToken('const') : null);
   }
 
   Node createDefinition(Identifier name, Expression initializer) {
     if (initializer == null) return name;
-    return new SendSet(null, name, new Operator(symbolToken(EQ_INFO)),
-                 new NodeList.singleton(initializer));
+    return new SendSet(null, name,
+        new Operator(symbolToken(Precedence.EQ_INFO)),
+            new NodeList.singleton(initializer));
   }
 
   VariableDefinitions initializingFormal(String fieldName) {
@@ -153,20 +159,20 @@
 
   Send indexGet(Expression receiver, Expression index) {
     return new Send(receiver,
-                    new Operator(symbolToken(INDEX_INFO)),
+                    new Operator(symbolToken(Precedence.INDEX_INFO)),
                     new NodeList.singleton(index));
   }
 
   LiteralMapEntry mapLiteralEntry(Expression key, Expression value) {
-    return new LiteralMapEntry(key, symbolToken(COLON_INFO), value);
+    return new LiteralMapEntry(key, symbolToken(Precedence.COLON_INFO), value);
   }
 
   LiteralMap mapLiteral(List<LiteralMapEntry> entries, {bool isConst: false}) {
     return new LiteralMap(
         null, // Type arguments.
-        new NodeList(symbolToken(OPEN_CURLY_BRACKET_INFO),
+        new NodeList(symbolToken(Precedence.OPEN_CURLY_BRACKET_INFO),
                      linkedList(entries),
-                     symbolToken(CLOSE_CURLY_BRACKET_INFO),
+                     symbolToken(Precedence.CLOSE_CURLY_BRACKET_INFO),
                      ','),
         isConst ? keywordToken('const') : null);
   }
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 16aa1a2..5b7558b 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -33,7 +33,7 @@
     ParameterElementX,
     VariableElementX,
     VariableList;
-import '../scanner/scannerlib.dart' show
+import '../tokens/token.dart' show
     isUserDefinableOperator;
 import '../tree/tree.dart';
 import '../util/util.dart' show
@@ -49,7 +49,8 @@
 import 'send_structure.dart';
 
 import 'constructors.dart' show
-    ConstructorResolver;
+    ConstructorResolver,
+    ConstructorResult;
 import 'label_scope.dart' show
     StatementScope;
 import 'registry.dart' show
@@ -3636,7 +3637,7 @@
     bool isConstConstructor = constructor.isConst;
     bool isValidAsConstant = isConstConstructor;
     ConstructorElement redirectionTarget = resolveRedirectingFactory(
-        node, inConstContext: isConstConstructor);
+        node, inConstContext: isConstConstructor).element;
     constructor.immediateRedirectionTarget = redirectionTarget;
 
     Node constructorReference = node.constructorReference;
@@ -3814,7 +3815,7 @@
 
   ResolutionResult visitNewExpression(NewExpression node) {
     bool isValidAsConstant = true;
-    FunctionElement constructor = resolveConstructor(node);
+    ConstructorElement constructor = resolveConstructor(node).element;
     final bool isSymbolConstructor = constructor == compiler.symbolConstructor;
     final bool isMirrorsUsedConstant =
         node.isConst && (constructor == compiler.mirrorsUsedConstructor);
@@ -3856,8 +3857,6 @@
     // factory constructors.
     registry.registerInstantiatedType(type);
     if (constructor.isGenerativeConstructor && cls.isAbstract) {
-      warning(node, MessageKind.ABSTRACT_CLASS_INSTANTIATION);
-      registry.registerAbstractClassInstantiation();
       isValidAsConstant = false;
     }
 
@@ -3993,14 +3992,15 @@
    * Note: this function may return an ErroneousFunctionElement instead of
    * [:null:], if there is no corresponding constructor, class or library.
    */
-  ConstructorElement resolveConstructor(NewExpression node) {
-    return node.accept(new ConstructorResolver(compiler, this));
+  ConstructorResult resolveConstructor(NewExpression node) {
+    return node.accept(new ConstructorResolver(
+        compiler, this, inConstContext: node.isConst));
   }
 
-  ConstructorElement resolveRedirectingFactory(RedirectingFactoryBody node,
+  ConstructorResult resolveRedirectingFactory(RedirectingFactoryBody node,
                                                {bool inConstContext: false}) {
-    return node.accept(new ConstructorResolver(compiler, this,
-                                               inConstContext: inConstContext));
+    return node.accept(new ConstructorResolver(
+        compiler, this, inConstContext: inConstContext));
   }
 
   DartType resolveTypeAnnotation(TypeAnnotation node,
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index d10e886..5874251 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -39,7 +39,7 @@
     TypedefElementX;
 import '../enqueue.dart' show
     WorldImpact;
-import '../scanner/scannerlib.dart' show
+import '../tokens/token.dart' show
     isBinaryOperator,
     isMinusOperator,
     isTernaryOperator,
diff --git a/pkg/compiler/lib/src/scanner/array_based_scanner.dart b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
index 457be84..49461fb 100644
--- a/pkg/compiler/lib/src/scanner/array_based_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/array_based_scanner.dart
@@ -2,7 +2,35 @@
 // for 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 scanner;
+library dart2js.scanner.array_based;
+
+import '../io/source_file.dart' show
+    SourceFile;
+import '../tokens/keyword.dart' show
+    Keyword;
+import '../tokens/precedence.dart' show
+    PrecedenceInfo;
+import '../tokens/precedence_constants.dart' as Precedence show
+    COMMENT_INFO,
+    EOF_INFO;
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    ErrorToken,
+    KeywordToken,
+    SymbolToken,
+    Token;
+import '../tokens/token_constants.dart' as Tokens show
+    LT_TOKEN,
+    OPEN_CURLY_BRACKET_TOKEN,
+    STRING_INTERPOLATION_TOKEN;
+import '../util/characters.dart' show
+    $LF,
+    $STX;
+import '../util/util.dart' show
+    Link;
+
+import 'scanner.dart' show
+    AbstractScanner;
 
 abstract class ArrayBasedScanner extends AbstractScanner {
   ArrayBasedScanner(SourceFile file, bool includeComments)
@@ -64,7 +92,7 @@
       unmatchedBeginGroup(groupingStack.head);
       groupingStack = groupingStack.tail;
     }
-    tail.next = new SymbolToken(EOF_INFO, tokenStart);
+    tail.next = new SymbolToken(Precedence.EOF_INFO, tokenStart);
     tail = tail.next;
     // EOF points to itself so there's always infinite look-ahead.
     tail.next = tail;
@@ -105,7 +133,7 @@
     tail = tail.next;
 
     // { (  [ ${ cannot appear inside a type parameters / arguments.
-    if (!identical(info.kind, LT_TOKEN)) discardOpenLt();
+    if (!identical(info.kind, Tokens.LT_TOKEN)) discardOpenLt();
     groupingStack = groupingStack.prepend(token);
   }
 
@@ -115,7 +143,7 @@
    * '>>' are handled separately bo [appendGt] and [appendGtGt].
    */
   int appendEndGroup(PrecedenceInfo info, int openKind) {
-    assert(!identical(openKind, LT_TOKEN)); // openKind is < for > and >>
+    assert(!identical(openKind, Tokens.LT_TOKEN)); // openKind is < for > and >>
     discardBeginGroupUntil(openKind);
     appendPrecedenceToken(info);
     Token close = tail;
@@ -124,8 +152,8 @@
     }
     BeginGroupToken begin = groupingStack.head;
     if (!identical(begin.kind, openKind)) {
-      assert(begin.kind == STRING_INTERPOLATION_TOKEN &&
-             openKind == OPEN_CURLY_BRACKET_TOKEN);
+      assert(begin.kind == Tokens.STRING_INTERPOLATION_TOKEN &&
+             openKind == Tokens.OPEN_CURLY_BRACKET_TOKEN);
       // We're ending an interpolated expression.
       begin.endGroup = close;
       groupingStack = groupingStack.tail;
@@ -149,8 +177,8 @@
       if (groupingStack.isEmpty) return;
       BeginGroupToken begin = groupingStack.head;
       if (openKind == begin.kind) return;
-      if (openKind == OPEN_CURLY_BRACKET_TOKEN &&
-          begin.kind == STRING_INTERPOLATION_TOKEN) return;
+      if (openKind == Tokens.OPEN_CURLY_BRACKET_TOKEN &&
+          begin.kind == Tokens.STRING_INTERPOLATION_TOKEN) return;
       unmatchedBeginGroup(begin);
       groupingStack = groupingStack.tail;
     }
@@ -164,7 +192,7 @@
   void appendGt(PrecedenceInfo info) {
     appendPrecedenceToken(info);
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
       groupingStack.head.endGroup = tail;
       groupingStack = groupingStack.tail;
     }
@@ -178,13 +206,13 @@
   void appendGtGt(PrecedenceInfo info) {
     appendPrecedenceToken(info);
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
       // Don't assign endGroup: in "T<U<V>>", the '>>' token closes the outer
       // '<', the inner '<' is left without endGroup.
       groupingStack = groupingStack.tail;
     }
     if (groupingStack.isEmpty) return;
-    if (identical(groupingStack.head.kind, LT_TOKEN)) {
+    if (identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
       groupingStack.head.endGroup = tail;
       groupingStack = groupingStack.tail;
     }
@@ -192,7 +220,7 @@
 
   void appendComment(start, bool asciiOnly) {
     if (!includeComments) return;
-    appendSubstringToken(COMMENT_INFO, start, asciiOnly);
+    appendSubstringToken(Precedence.COMMENT_INFO, start, asciiOnly);
   }
 
   void appendErrorToken(ErrorToken token) {
@@ -213,7 +241,7 @@
    */
   void discardOpenLt() {
     while (!groupingStack.isEmpty
-        && identical(groupingStack.head.kind, LT_TOKEN)) {
+        && identical(groupingStack.head.kind, Tokens.LT_TOKEN)) {
       groupingStack = groupingStack.tail;
     }
   }
diff --git a/pkg/compiler/lib/src/scanner/class_element_parser.dart b/pkg/compiler/lib/src/scanner/class_element_parser.dart
deleted file mode 100644
index 627b0ad..0000000
--- a/pkg/compiler/lib/src/scanner/class_element_parser.dart
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of scanner;
-
-class ClassElementParser extends PartialParser {
-  ClassElementParser(Listener listener) : super(listener);
-
-  Token parseClassBody(Token token) => fullParseClassBody(token);
-}
-
-class PartialClassElement extends ClassElementX with PartialElement {
-  ClassNode cachedNode;
-
-  PartialClassElement(String name,
-                      Token beginToken,
-                      Token endToken,
-                      Element enclosing,
-                      int id)
-      : super(name, enclosing, id, STATE_NOT_STARTED) {
-    this.beginToken = beginToken;
-    this.endToken = endToken;
-  }
-
-  void set supertypeLoadState(int state) {
-    assert(state == STATE_NOT_STARTED || state == supertypeLoadState + 1);
-    assert(state <= STATE_DONE);
-    super.supertypeLoadState = state;
-  }
-
-  void set resolutionState(int state) {
-    assert(state == STATE_NOT_STARTED || state == resolutionState + 1);
-    assert(state <= STATE_DONE);
-    super.resolutionState = state;
-  }
-
-  bool get hasNode => cachedNode != null;
-
-  ClassNode get node {
-    assert(invariant(this, cachedNode != null,
-        message: "Node has not been computed for $this."));
-    return cachedNode;
-  }
-
-  ClassNode parseNode(Compiler compiler) {
-    if (cachedNode != null) return cachedNode;
-    compiler.withCurrentElement(this, () {
-      compiler.parser.measure(() {
-        MemberListener listener = new MemberListener(compiler, this);
-        Parser parser = new ClassElementParser(listener);
-        try {
-          Token token = parser.parseTopLevelDeclaration(beginToken);
-          assert(identical(token, endToken.next));
-          cachedNode = listener.popNode();
-          assert(
-              invariant(
-                  beginToken, listener.nodes.isEmpty,
-                  message: "Non-empty listener stack: ${listener.nodes}"));
-        } on ParserError {
-          // TODO(ahe): Often, a ParserError is thrown while parsing the class
-          // body. This means that the stack actually contains most of the
-          // information synthesized below. Consider rewriting the parser so
-          // endClassDeclaration is called before parsing the class body.
-          Identifier name = new Identifier(findMyName(beginToken));
-          NodeList typeParameters = null;
-          Node supertype = null;
-          NodeList interfaces = listener.makeNodeList(0, null, null, ",");
-          Token extendsKeyword = null;
-          NodeList body = listener.makeNodeList(0, beginToken, endToken, null);
-          cachedNode = new ClassNode(
-              Modifiers.EMPTY, name, typeParameters, supertype, interfaces,
-              beginToken, extendsKeyword, body, endToken);
-          hasParseError = true;
-        }
-      });
-      compiler.patchParser.measure(() {
-        if (isPatched) {
-          // TODO(lrn): Perhaps extract functionality so it doesn't
-          // need compiler.
-          compiler.patchParser.parsePatchClassNode(patch);
-        }
-      });
-    });
-    return cachedNode;
-  }
-
-  Token get position => beginToken;
-
-  // TODO(johnniwinther): Ensure that modifiers are always available.
-  Modifiers get modifiers =>
-      cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY;
-
-  accept(ElementVisitor visitor, arg) {
-    return visitor.visitClassElement(this, arg);
-  }
-
-  PartialClassElement copyWithEnclosing(CompilationUnitElement enclosing) {
-    return new PartialClassElement(name, beginToken, endToken, enclosing, id);
-  }
-}
-
-class MemberListener extends NodeListener {
-  final ClassElementX enclosingClass;
-
-  MemberListener(DiagnosticListener listener,
-                 ClassElementX enclosingElement)
-      : this.enclosingClass = enclosingElement,
-        super(listener, enclosingElement.compilationUnit);
-
-  bool isConstructorName(Node nameNode) {
-    if (enclosingClass == null ||
-        enclosingClass.kind != ElementKind.CLASS) {
-      return false;
-    }
-    String name;
-    if (nameNode.asIdentifier() != null) {
-      name = nameNode.asIdentifier().source;
-    } else {
-      Send send = nameNode.asSend();
-      name = send.receiver.asIdentifier().source;
-    }
-    return enclosingClass.name == name;
-  }
-
-  // TODO(johnniwinther): Remove this method.
-  String getMethodNameHack(Node methodName) {
-    Send send = methodName.asSend();
-    if (send == null) {
-      if (isConstructorName(methodName)) return '';
-      return methodName.asIdentifier().source;
-    }
-    Identifier receiver = send.receiver.asIdentifier();
-    Identifier selector = send.selector.asIdentifier();
-    Operator operator = selector.asOperator();
-    if (operator != null) {
-      assert(identical(receiver.source, 'operator'));
-      // TODO(ahe): It is a hack to compare to ')', but it beats
-      // parsing the node.
-      bool isUnary = identical(operator.token.next.next.stringValue, ')');
-      return Elements.constructOperatorName(operator.source, isUnary);
-    } else {
-      if (receiver == null || receiver.source != enclosingClass.name) {
-        listener.reportError(send.receiver,
-                                 MessageKind.INVALID_CONSTRUCTOR_NAME,
-                                 {'name': enclosingClass.name});
-      }
-      return selector.source;
-    }
-  }
-
-  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
-    super.endMethod(getOrSet, beginToken, endToken);
-    FunctionExpression method = popNode();
-    pushNode(null);
-    bool isConstructor = isConstructorName(method.name);
-    String name = getMethodNameHack(method.name);
-    Element memberElement;
-    if (isConstructor) {
-      if (getOrSet != null) {
-        recoverableError(getOrSet, 'illegal modifier');
-      }
-      memberElement = new PartialConstructorElement(
-          name, beginToken, endToken,
-          ElementKind.GENERATIVE_CONSTRUCTOR,
-          method.modifiers,
-          enclosingClass);
-    } else {
-      memberElement = new PartialFunctionElement(
-          name, beginToken, getOrSet, endToken,
-          method.modifiers, enclosingClass, hasBody: method.hasBody());
-    }
-    addMember(memberElement);
-  }
-
-  void endFactoryMethod(Token beginToken, Token endToken) {
-    super.endFactoryMethod(beginToken, endToken);
-    FunctionExpression method = popNode();
-    pushNode(null);
-    String name = getMethodNameHack(method.name);
-    Identifier singleIdentifierName = method.name.asIdentifier();
-    if (singleIdentifierName != null && singleIdentifierName.source == name) {
-      if (name != enclosingClass.name) {
-        listener.reportError(singleIdentifierName,
-                                 MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
-                                 {'name': enclosingClass.name});
-      }
-    }
-    Element memberElement = new PartialConstructorElement(
-        name, beginToken, endToken,
-        ElementKind.FUNCTION,
-        method.modifiers,
-        enclosingClass);
-    addMember(memberElement);
-  }
-
-  void endFields(int count, Token beginToken, Token endToken) {
-    bool hasParseError = memberErrors.head;
-    super.endFields(count, beginToken, endToken);
-    VariableDefinitions variableDefinitions = popNode();
-    Modifiers modifiers = variableDefinitions.modifiers;
-    pushNode(null);
-    void buildFieldElement(Identifier name, VariableList fields) {
-      Element element =
-          new FieldElementX(name, enclosingClass, fields);
-      addMember(element);
-    }
-    buildFieldElements(modifiers, variableDefinitions.definitions,
-                       enclosingClass,
-                       buildFieldElement, beginToken, endToken,
-                       hasParseError);
-  }
-
-  void endInitializer(Token assignmentOperator) {
-    pushNode(null); // Super expects an expression, but
-                    // ClassElementParser just skips expressions.
-    super.endInitializer(assignmentOperator);
-  }
-
-  void endInitializers(int count, Token beginToken, Token endToken) {
-    pushNode(null);
-  }
-
-  void addMetadata(ElementX memberElement) {
-    for (Link link = metadata; !link.isEmpty; link = link.tail) {
-      memberElement.addMetadata(link.head);
-    }
-    metadata = const Link<MetadataAnnotation>();
-  }
-
-  void addMember(ElementX memberElement) {
-    addMetadata(memberElement);
-    enclosingClass.addMember(memberElement, listener);
-  }
-
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
-    popNode(); // Discard arguments.
-    if (periodBeforeName != null) {
-      popNode(); // Discard name.
-    }
-    popNode(); // Discard node (Send or Identifier).
-    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
-  }
-}
diff --git a/pkg/compiler/lib/src/scanner/listener.dart b/pkg/compiler/lib/src/scanner/listener.dart
deleted file mode 100644
index c3299a3..0000000
--- a/pkg/compiler/lib/src/scanner/listener.dart
+++ /dev/null
@@ -1,2610 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of scanner;
-
-const bool VERBOSE = false;
-
-/**
- * A parser event listener that does nothing except throw exceptions
- * on parser errors.
- */
-class Listener {
-  set suppressParseErrors(bool value) {
-  }
-
-  void beginArguments(Token token) {
-  }
-
-  void endArguments(int count, Token beginToken, Token endToken) {
-  }
-
-  /// Handle async modifiers `async`, `async*`, `sync`.
-  void handleAsyncModifier(Token asyncToken, Token startToken) {
-  }
-
-  void beginAwaitExpression(Token token) {
-  }
-
-  void endAwaitExpression(Token beginToken, Token endToken) {
-  }
-
-  void beginBlock(Token token) {
-  }
-
-  void endBlock(int count, Token beginToken, Token endToken) {
-  }
-
-  void beginCascade(Token token) {
-  }
-
-  void endCascade() {
-  }
-
-  void beginClassBody(Token token) {
-  }
-
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-  }
-
-  void beginClassDeclaration(Token token) {
-  }
-
-  void endClassDeclaration(int interfacesCount, Token beginToken,
-                           Token extendsKeyword, Token implementsKeyword,
-                           Token endToken) {
-  }
-
-  void beginCombinators(Token token) {
-  }
-
-  void endCombinators(int count) {
-  }
-
-  void beginCompilationUnit(Token token) {
-  }
-
-  void endCompilationUnit(int count, Token token) {
-  }
-
-  void beginConstructorReference(Token start) {
-  }
-
-  void endConstructorReference(Token start, Token periodBeforeName,
-                               Token endToken) {
-  }
-
-  void beginDoWhileStatement(Token token) {
-  }
-
-  void endDoWhileStatement(Token doKeyword, Token whileKeyword,
-                           Token endToken) {
-  }
-
-  void beginEnum(Token enumKeyword) {
-  }
-
-  void endEnum(Token enumKeyword, Token endBrace, int count) {
-  }
-
-  void beginExport(Token token) {
-  }
-
-  void endExport(Token exportKeyword, Token semicolon) {
-  }
-
-  void beginExpressionStatement(Token token) {
-  }
-
-  void endExpressionStatement(Token token) {
-  }
-
-  void beginFactoryMethod(Token token) {
-  }
-
-  void endFactoryMethod(Token beginToken, Token endToken) {
-  }
-
-  void beginFormalParameter(Token token) {
-  }
-
-  void endFormalParameter(Token thisKeyword) {
-  }
-
-  void handleNoFormalParameters(Token token) {
-  }
-
-  void beginFormalParameters(Token token) {
-  }
-
-  void endFormalParameters(int count, Token beginToken, Token endToken) {
-  }
-
-  void endFields(int count, Token beginToken, Token endToken) {
-  }
-
-  void beginForStatement(Token token) {
-  }
-
-  void endForStatement(int updateExpressionCount,
-                       Token beginToken, Token endToken) {
-  }
-
-  void endForIn(Token awaitToken, Token forToken,
-                Token inKeyword, Token endToken) {
-  }
-
-  void beginFunction(Token token) {
-  }
-
-  void endFunction(Token getOrSet, Token endToken) {
-  }
-
-  void beginFunctionDeclaration(Token token) {
-  }
-
-  void endFunctionDeclaration(Token token) {
-  }
-
-  void beginFunctionBody(Token token) {
-  }
-
-  void endFunctionBody(int count, Token beginToken, Token endToken) {
-  }
-
-  void handleNoFunctionBody(Token token) {
-  }
-
-  void skippedFunctionBody(Token token) {
-  }
-
-  void beginFunctionName(Token token) {
-  }
-
-  void endFunctionName(Token token) {
-  }
-
-  void beginFunctionTypeAlias(Token token) {
-  }
-
-  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
-  }
-
-  void beginMixinApplication(Token token) {
-  }
-
-  void endMixinApplication() {
-  }
-
-  void beginNamedMixinApplication(Token token) {
-  }
-
-  void endNamedMixinApplication(Token classKeyword,
-                                Token implementsKeyword,
-                                Token endToken) {
-  }
-
-  void beginHide(Token hideKeyword) {
-  }
-
-  void endHide(Token hideKeyword) {
-  }
-
-  void beginIdentifierList(Token token) {
-  }
-
-  void endIdentifierList(int count) {
-  }
-
-  void beginTypeList(Token token) {
-  }
-
-  void endTypeList(int count) {
-  }
-
-  void beginIfStatement(Token token) {
-  }
-
-  void endIfStatement(Token ifToken, Token elseToken) {
-  }
-
-  void beginImport(Token importKeyword) {
-  }
-
-  void endImport(Token importKeyword, Token DeferredKeyword,
-                 Token asKeyword, Token semicolon) {
-  }
-
-  void beginInitializedIdentifier(Token token) {
-  }
-
-  void endInitializedIdentifier() {
-  }
-
-  void beginInitializer(Token token) {
-  }
-
-  void endInitializer(Token assignmentOperator) {
-  }
-
-  void beginInitializers(Token token) {
-  }
-
-  void endInitializers(int count, Token beginToken, Token endToken) {
-  }
-
-  void handleNoInitializers() {
-  }
-
-  void handleLabel(Token token) {
-  }
-
-  void beginLabeledStatement(Token token, int labelCount) {
-  }
-
-  void endLabeledStatement(int labelCount) {
-  }
-
-  void beginLibraryName(Token token) {
-  }
-
-  void endLibraryName(Token libraryKeyword, Token semicolon) {
-  }
-
-  void beginLiteralMapEntry(Token token) {
-  }
-
-  void endLiteralMapEntry(Token colon, Token endToken) {
-  }
-
-  void beginLiteralString(Token token) {
-  }
-
-  void endLiteralString(int interpolationCount) {
-  }
-
-  void handleStringJuxtaposition(int literalCount) {
-  }
-
-  void beginMember(Token token) {
-  }
-
-  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
-  }
-
-  void beginMetadataStar(Token token) {
-  }
-
-  void endMetadataStar(int count, bool forParameter) {
-  }
-
-  void beginMetadata(Token token) {
-  }
-
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
-  }
-
-  void beginOptionalFormalParameters(Token token) {
-  }
-
-  void endOptionalFormalParameters(int count,
-                                   Token beginToken, Token endToken) {
-  }
-
-  void beginPart(Token token) {
-  }
-
-  void endPart(Token partKeyword, Token semicolon) {
-  }
-
-  void beginPartOf(Token token) {
-  }
-
-  void endPartOf(Token partKeyword, Token semicolon) {
-  }
-
-  void beginRedirectingFactoryBody(Token token) {
-  }
-
-  void endRedirectingFactoryBody(Token beginToken, Token endToken) {
-  }
-
-  void beginReturnStatement(Token token) {
-  }
-
-  void endReturnStatement(bool hasExpression,
-                          Token beginToken, Token endToken) {
-  }
-
-  void beginSend(Token token) {
-  }
-
-  void endSend(Token token) {
-  }
-
-  void beginShow(Token showKeyword) {
-  }
-
-  void endShow(Token showKeyword) {
-  }
-
-  void beginSwitchStatement(Token token) {
-  }
-
-  void endSwitchStatement(Token switchKeyword, Token endToken) {
-  }
-
-  void beginSwitchBlock(Token token) {
-  }
-
-  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
-  }
-
-  void beginLiteralSymbol(Token token) {
-  }
-
-  void endLiteralSymbol(Token hashToken, int identifierCount) {
-  }
-
-  void beginThrowExpression(Token token) {
-  }
-
-  void endThrowExpression(Token throwToken, Token endToken) {
-  }
-
-  void beginRethrowStatement(Token token) {
-  }
-
-  void endRethrowStatement(Token throwToken, Token endToken) {
-  }
-
-  void endTopLevelDeclaration(Token token) {
-  }
-
-  void beginTopLevelMember(Token token) {
-  }
-
-  void endTopLevelFields(int count, Token beginToken, Token endToken) {
-  }
-
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
-  }
-
-  void beginTryStatement(Token token) {
-  }
-
-  void handleCaseMatch(Token caseKeyword, Token colon) {
-  }
-
-  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
-  }
-
-  void handleFinallyBlock(Token finallyKeyword) {
-  }
-
-  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
-  }
-
-  void endType(Token beginToken, Token endToken) {
-  }
-
-  void beginTypeArguments(Token token) {
-  }
-
-  void endTypeArguments(int count, Token beginToken, Token endToken) {
-  }
-
-  void handleNoTypeArguments(Token token) {
-  }
-
-  void beginTypeVariable(Token token) {
-  }
-
-  void endTypeVariable(Token token) {
-  }
-
-  void beginTypeVariables(Token token) {
-  }
-
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
-  }
-
-  void beginUnnamedFunction(Token token) {
-  }
-
-  void endUnnamedFunction(Token token) {
-  }
-
-  void beginVariablesDeclaration(Token token) {
-  }
-
-  void endVariablesDeclaration(int count, Token endToken) {
-  }
-
-  void beginWhileStatement(Token token) {
-  }
-
-  void endWhileStatement(Token whileKeyword, Token endToken) {
-  }
-
-  void handleAsOperator(Token operathor, Token endToken) {
-    // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
-  }
-
-  void handleAssignmentExpression(Token token) {
-  }
-
-  void handleBinaryExpression(Token token) {
-  }
-
-  void handleConditionalExpression(Token question, Token colon) {
-  }
-
-  void handleConstExpression(Token token) {
-  }
-
-  void handleFunctionTypedFormalParameter(Token token) {
-  }
-
-  void handleIdentifier(Token token) {
-  }
-
-  void handleIndexedExpression(Token openCurlyBracket,
-                               Token closeCurlyBracket) {
-  }
-
-  void handleIsOperator(Token operathor, Token not, Token endToken) {
-    // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
-  }
-
-  void handleLiteralBool(Token token) {
-  }
-
-  void handleBreakStatement(bool hasTarget,
-                            Token breakKeyword, Token endToken) {
-  }
-
-  void handleContinueStatement(bool hasTarget,
-                               Token continueKeyword, Token endToken) {
-  }
-
-  void handleEmptyStatement(Token token) {
-  }
-
-  void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
-  }
-
-  /** Called with either the token containing a double literal, or
-    * an immediately preceding "unary plus" token.
-    */
-  void handleLiteralDouble(Token token) {
-  }
-
-  /** Called with either the token containing an integer literal,
-    * or an immediately preceding "unary plus" token.
-    */
-  void handleLiteralInt(Token token) {
-  }
-
-  void handleLiteralList(int count, Token beginToken, Token constKeyword,
-                         Token endToken) {
-  }
-
-  void handleLiteralMap(int count, Token beginToken, Token constKeyword,
-                        Token endToken) {
-  }
-
-  void handleLiteralNull(Token token) {
-  }
-
-  void handleModifier(Token token) {
-  }
-
-  void handleModifiers(int count) {
-  }
-
-  void handleNamedArgument(Token colon) {
-  }
-
-  void handleNewExpression(Token token) {
-  }
-
-  void handleNoArguments(Token token) {
-  }
-
-  void handleNoExpression(Token token) {
-  }
-
-  void handleNoType(Token token) {
-  }
-
-  void handleNoTypeVariables(Token token) {
-  }
-
-  void handleOperator(Token token) {
-  }
-
-  void handleOperatorName(Token operatorKeyword, Token token) {
-  }
-
-  void handleParenthesizedExpression(BeginGroupToken token) {
-  }
-
-  void handleQualified(Token period) {
-  }
-
-  void handleStringPart(Token token) {
-  }
-
-  void handleSuperExpression(Token token) {
-  }
-
-  void handleSwitchCase(int labelCount, int expressionCount,
-                        Token defaultKeyword, int statementCount,
-                        Token firstToken, Token endToken) {
-  }
-
-  void handleThisExpression(Token token) {
-  }
-
-  void handleUnaryPostfixAssignmentExpression(Token token) {
-  }
-
-  void handleUnaryPrefixExpression(Token token) {
-  }
-
-  void handleUnaryPrefixAssignmentExpression(Token token) {
-  }
-
-  void handleValuedFormalParameter(Token equals, Token token) {
-  }
-
-  void handleVoidKeyword(Token token) {
-  }
-
-  void beginYieldStatement(Token token) {
-  }
-
-  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
-  }
-
-  Token expected(String string, Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected '$string', but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token synthesizeIdentifier(Token token) {
-    Token synthesizedToken =
-        new StringToken.fromString(IDENTIFIER_INFO, '?', token.charOffset);
-    synthesizedToken.next = token.next;
-    return synthesizedToken;
-  }
-
-  Token expectedIdentifier(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected identifier, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedType(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a type, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedExpression(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected an expression, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token unexpected(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("unexpected token '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedBlockToSkip(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a block, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedFunctionBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a function body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a class body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBodyToSkip(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a class body, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedDeclaration(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("expected a declaration, but got '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  Token unmatched(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      error("unmatched '${token.value}'", token);
-    }
-    return skipToEof(token);
-  }
-
-  skipToEof(Token token) {
-    while (!identical(token.info, EOF_INFO)) {
-      token = token.next;
-    }
-    return token;
-  }
-
-  void recoverableError(Token token, String message) {
-    error(message, token);
-  }
-
-  void error(String message, Token token) {
-    throw new ParserError("$message @ ${token.charOffset}");
-  }
-
-  void reportError(Spannable spannable,
-                   MessageKind messageKind,
-                   [Map arguments = const {}]) {
-    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
-    String message = template.message(arguments, true).toString();
-    Token token;
-    if (spannable is Token) {
-      token = spannable;
-    } else if (spannable is Node) {
-      token = spannable.getBeginToken();
-    } else {
-      throw new ParserError(message);
-    }
-    recoverableError(token, message);
-  }
-
-  void reportErrorToken(ErrorToken token) {
-    if (token is BadInputToken) {
-      String hex = token.character.toRadixString(16);
-      if (hex.length < 4) {
-        String padding = "0000".substring(hex.length);
-        hex = "$padding$hex";
-      }
-      reportError(
-          token, MessageKind.BAD_INPUT_CHARACTER, {'characterHex': hex});
-    } else if (token is UnterminatedToken) {
-      MessageKind kind;
-      var arguments = const {};
-      switch (token.start) {
-        case '1e':
-          kind = MessageKind.EXPONENT_MISSING;
-          break;
-        case '"':
-        case "'":
-        case '"""':
-        case "'''":
-        case 'r"':
-        case "r'":
-        case 'r"""':
-        case "r'''":
-          kind = MessageKind.UNTERMINATED_STRING;
-          arguments = {'quote': token.start};
-          break;
-        case '0x':
-          kind = MessageKind.HEX_DIGIT_EXPECTED;
-          break;
-        case r'$':
-          kind = MessageKind.MALFORMED_STRING_LITERAL;
-          break;
-        case '/*':
-          kind = MessageKind.UNTERMINATED_COMMENT;
-          break;
-        default:
-          kind = MessageKind.UNTERMINATED_TOKEN;
-          break;
-      }
-      reportError(token, kind, arguments);
-    } else if (token is UnmatchedToken) {
-      String begin = token.begin.value;
-      String end = closeBraceFor(begin);
-      reportError(
-          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
-    } else {
-      throw new SpannableAssertionFailure(token, token.assertionMessage);
-    }
-  }
-}
-
-String closeBraceFor(String openBrace) {
-  return const {
-    '(': ')',
-    '[': ']',
-    '{': '}',
-    '<': '>',
-    r'${': '}',
-  }[openBrace];
-}
-
-class ParserError {
-  final String reason;
-  ParserError(this.reason);
-  toString() => reason;
-}
-
-typedef int IdGenerator();
-
-/**
- * A parser event listener designed to work with [PartialParser]. It
- * builds elements representing the top-level declarations found in
- * the parsed compilation unit and records them in
- * [compilationUnitElement].
- */
-class ElementListener extends Listener {
-  final IdGenerator idGenerator;
-  final DiagnosticListener listener;
-  final CompilationUnitElementX compilationUnitElement;
-  final StringValidator stringValidator;
-  Link<StringQuoting> interpolationScope;
-
-  Link<Node> nodes = const Link<Node>();
-
-  Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
-
-  /// Records a stack of booleans for each member parsed (a stack is used to
-  /// support nested members which isn't currently possible, but it also serves
-  /// as a simple way to tell we're currently parsing a member). In this case,
-  /// member refers to members of a library or a class (but currently, classes
-  /// themselves are not considered members).  If the top of the stack
-  /// (memberErrors.head) is true, the current member has already reported at
-  /// least one parse error.
-  Link<bool> memberErrors = const Link<bool>();
-
-  bool suppressParseErrors = false;
-
-  ElementListener(
-      DiagnosticListener listener,
-      this.compilationUnitElement,
-      this.idGenerator)
-      : this.listener = listener,
-        stringValidator = new StringValidator(listener),
-        interpolationScope = const Link<StringQuoting>();
-
-  bool get currentMemberHasParseError {
-    return !memberErrors.isEmpty && memberErrors.head;
-  }
-
-  void pushQuoting(StringQuoting quoting) {
-    interpolationScope = interpolationScope.prepend(quoting);
-  }
-
-  StringQuoting popQuoting() {
-    StringQuoting result = interpolationScope.head;
-    interpolationScope = interpolationScope.tail;
-    return result;
-  }
-
-  StringNode popLiteralString() {
-    StringNode node = popNode();
-    // TODO(lrn): Handle interpolations in script tags.
-    if (node.isInterpolation) {
-      listener.internalError(node,
-          "String interpolation not supported in library tags.");
-      return null;
-    }
-    return node;
-  }
-
-  bool allowLibraryTags() {
-    // Library tags are only allowed in the library file itself, not
-    // in sourced files.
-    LibraryElement library = compilationUnitElement.implementationLibrary;
-    return !compilationUnitElement.hasMembers &&
-           library.entryCompilationUnit == compilationUnitElement;
-  }
-
-  void endLibraryName(Token libraryKeyword, Token semicolon) {
-    Expression name = popNode();
-    addLibraryTag(new LibraryName(libraryKeyword, name,
-                                  popMetadata(compilationUnitElement)));
-  }
-
-  void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
-                 Token semicolon) {
-    NodeList combinators = popNode();
-    bool isDeferred = deferredKeyword != null;
-    Identifier prefix;
-    if (asKeyword != null) {
-      prefix = popNode();
-    }
-    StringNode uri = popLiteralString();
-    addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
-                             popMetadata(compilationUnitElement),
-                             isDeferred: isDeferred));
-  }
-
-  void endEnum(Token enumKeyword, Token endBrace, int count) {
-    NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
-    Identifier name = popNode();
-
-    int id = idGenerator();
-    Element enclosing = compilationUnitElement;
-    pushElement(new EnumClassElementX(name.source, enclosing, id,
-        new Enum(enumKeyword, name, names)));
-    rejectBuiltInIdentifier(name);
-  }
-
-  void endExport(Token exportKeyword, Token semicolon) {
-    NodeList combinators = popNode();
-    StringNode uri = popNode();
-    addLibraryTag(new Export(exportKeyword, uri, combinators,
-                             popMetadata(compilationUnitElement)));
-  }
-
-  void endCombinators(int count) {
-    if (0 == count) {
-      pushNode(null);
-    } else {
-      pushNode(makeNodeList(count, null, null, " "));
-    }
-  }
-
-  void endHide(Token hideKeyword) => pushCombinator(hideKeyword);
-
-  void endShow(Token showKeyword) => pushCombinator(showKeyword);
-
-  void pushCombinator(Token keywordToken) {
-    NodeList identifiers = popNode();
-    pushNode(new Combinator(identifiers, keywordToken));
-  }
-
-  void endIdentifierList(int count) {
-    pushNode(makeNodeList(count, null, null, ","));
-  }
-
-  void endTypeList(int count) {
-    pushNode(makeNodeList(count, null, null, ","));
-  }
-
-  void endPart(Token partKeyword, Token semicolon) {
-    StringNode uri = popLiteralString();
-    addLibraryTag(new Part(partKeyword, uri,
-                           popMetadata(compilationUnitElement)));
-  }
-
-  void endPartOf(Token partKeyword, Token semicolon) {
-    Expression name = popNode();
-    addPartOfTag(new PartOf(partKeyword, name,
-                            popMetadata(compilationUnitElement)));
-  }
-
-  void addPartOfTag(PartOf tag) {
-    compilationUnitElement.setPartOf(tag, listener);
-  }
-
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
-    if (periodBeforeName != null) {
-      popNode(); // Discard name.
-    }
-    popNode(); // Discard node (Send or Identifier).
-    pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
-  }
-
-  void endTopLevelDeclaration(Token token) {
-    if (!metadata.isEmpty) {
-      recoverableError(metadata.head.beginToken,
-                       'Metadata not supported here.');
-      metadata = const Link<MetadataAnnotation>();
-    }
-  }
-
-  void endClassDeclaration(int interfacesCount, Token beginToken,
-                           Token extendsKeyword, Token implementsKeyword,
-                           Token endToken) {
-    makeNodeList(interfacesCount, implementsKeyword, null, ","); // interfaces
-    popNode(); // superType
-    popNode(); // typeParameters
-    Identifier name = popNode();
-    int id = idGenerator();
-    PartialClassElement element = new PartialClassElement(
-        name.source, beginToken, endToken, compilationUnitElement, id);
-    pushElement(element);
-    rejectBuiltInIdentifier(name);
-  }
-
-  void rejectBuiltInIdentifier(Identifier name) {
-    if (name.token is KeywordToken) {
-      Keyword keyword = (name.token as KeywordToken).keyword;
-      if (!keyword.isPseudo) {
-        recoverableError(name, "Illegal name '${keyword.syntax}'.");
-      }
-    }
-  }
-
-  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
-    popNode(); // TODO(karlklose): do not throw away typeVariables.
-    Identifier name = popNode();
-    popNode(); // returnType
-    pushElement(
-        new PartialTypedefElement(
-            name.source, compilationUnitElement, typedefKeyword, endToken));
-    rejectBuiltInIdentifier(name);
-  }
-
-  void endNamedMixinApplication(Token classKeyword,
-                                Token implementsKeyword,
-                                Token endToken) {
-    NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
-    MixinApplication mixinApplication = popNode();
-    Modifiers modifiers = popNode();
-    NodeList typeParameters = popNode();
-    Identifier name = popNode();
-    NamedMixinApplication namedMixinApplication = new NamedMixinApplication(
-        name, typeParameters, modifiers, mixinApplication, interfaces,
-        classKeyword, endToken);
-
-    int id = idGenerator();
-    Element enclosing = compilationUnitElement;
-    pushElement(new MixinApplicationElementX(name.source, enclosing, id,
-                                             namedMixinApplication,
-                                             modifiers));
-    rejectBuiltInIdentifier(name);
-  }
-
-  void endMixinApplication() {
-    NodeList mixins = popNode();
-    TypeAnnotation superclass = popNode();
-    pushNode(new MixinApplication(superclass, mixins));
-  }
-
-  void handleVoidKeyword(Token token) {
-    pushNode(new TypeAnnotation(new Identifier(token), null));
-  }
-
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
-    bool hasParseError = currentMemberHasParseError;
-    memberErrors = memberErrors.tail;
-    Identifier name = popNode();
-    popNode(); // type
-    Modifiers modifiers = popNode();
-    PartialFunctionElement element = new PartialFunctionElement(
-        name.source, beginToken, getOrSet, endToken,
-        modifiers, compilationUnitElement);
-    element.hasParseError = hasParseError;
-    pushElement(element);
-  }
-
-  void endTopLevelFields(int count, Token beginToken, Token endToken) {
-    bool hasParseError = currentMemberHasParseError;
-    memberErrors = memberErrors.tail;
-    void buildFieldElement(Identifier name, VariableList fields) {
-      pushElement(
-          new FieldElementX(name, compilationUnitElement, fields));
-    }
-    NodeList variables = makeNodeList(count, null, null, ",");
-    popNode(); // type
-    Modifiers modifiers = popNode();
-    buildFieldElements(modifiers, variables, compilationUnitElement,
-                       buildFieldElement,
-                       beginToken, endToken, hasParseError);
-  }
-
-  void buildFieldElements(Modifiers modifiers,
-                          NodeList variables,
-                          Element enclosingElement,
-                          void buildFieldElement(Identifier name,
-                                                 VariableList fields),
-                          Token beginToken, Token endToken,
-                          bool hasParseError) {
-    VariableList fields =
-        new PartialFieldList(beginToken, endToken, modifiers, hasParseError);
-    for (Link<Node> variableNodes = variables.nodes;
-         !variableNodes.isEmpty;
-         variableNodes = variableNodes.tail) {
-      Expression initializedIdentifier = variableNodes.head;
-      Identifier identifier = initializedIdentifier.asIdentifier();
-      if (identifier == null) {
-        identifier = initializedIdentifier.asSendSet().selector.asIdentifier();
-      }
-      buildFieldElement(identifier, fields);
-    }
-  }
-
-  void handleIdentifier(Token token) {
-    pushNode(new Identifier(token));
-  }
-
-  void handleQualified(Token period) {
-    Identifier last = popNode();
-    Expression first = popNode();
-    pushNode(new Send(first, last));
-  }
-
-  void handleNoType(Token token) {
-    pushNode(null);
-  }
-
-  void endTypeVariable(Token token) {
-    TypeAnnotation bound = popNode();
-    Identifier name = popNode();
-    pushNode(new TypeVariable(name, bound));
-    rejectBuiltInIdentifier(name);
-  }
-
-  void endTypeVariables(int count, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, endToken, ','));
-  }
-
-  void handleNoTypeVariables(token) {
-    pushNode(null);
-  }
-
-  void endTypeArguments(int count, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, endToken, ','));
-  }
-
-  void handleNoTypeArguments(Token token) {
-    pushNode(null);
-  }
-
-  void endType(Token beginToken, Token endToken) {
-    NodeList typeArguments = popNode();
-    Expression typeName = popNode();
-    pushNode(new TypeAnnotation(typeName, typeArguments));
-  }
-
-  void handleParenthesizedExpression(BeginGroupToken token) {
-    Expression expression = popNode();
-    pushNode(new ParenthesizedExpression(expression, token));
-  }
-
-  void handleModifier(Token token) {
-    pushNode(new Identifier(token));
-  }
-
-  void handleModifiers(int count) {
-    if (count == 0) {
-      pushNode(Modifiers.EMPTY);
-    } else {
-      NodeList modifierNodes = makeNodeList(count, null, null, ' ');
-      pushNode(new Modifiers(modifierNodes));
-    }
-  }
-
-  Token expected(String string, Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else if (identical(';', string)) {
-      // When a semicolon is missing, it often leads to an error on the
-      // following line. So we try to find the token preceding the semicolon
-      // and report that something is missing *after* it.
-      Token preceding = findPrecedingToken(token);
-      if (preceding == token) {
-        reportError(
-            token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
-      } else {
-        reportError(
-            preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
-      }
-      return token;
-    } else {
-      reportFatalError(
-          token,
-          MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
-              .message({'token': string}, true).toString());
-    }
-    return skipToEof(token);
-  }
-
-  /// Finds the preceding token via the begin token of the last AST node pushed
-  /// on the [nodes] stack.
-  Token findPrecedingToken(Token token) {
-    Token result;
-    Link<Node> nodes = this.nodes;
-    while (!nodes.isEmpty) {
-      result = findPrecedingTokenFromNode(nodes.head, token);
-      if (result != null) {
-        return result;
-      }
-      nodes = nodes.tail;
-    }
-    if (compilationUnitElement != null) {
-      if (compilationUnitElement is CompilationUnitElementX) {
-        CompilationUnitElementX unit = compilationUnitElement;
-        Link<Element> members = unit.localMembers;
-        while (!members.isEmpty) {
-          ElementX member = members.head;
-          DeclarationSite site = member.declarationSite;
-          if (site is PartialElement) {
-            result = findPrecedingTokenFromToken(site.endToken, token);
-            if (result != null) {
-              return result;
-            }
-          }
-          members = members.tail;
-        }
-        result =
-            findPrecedingTokenFromNode(compilationUnitElement.partTag, token);
-        if (result != null) {
-          return result;
-        }
-      }
-    }
-    return token;
-  }
-
-  Token findPrecedingTokenFromNode(Node node, Token token) {
-    if (node != null) {
-      return findPrecedingTokenFromToken(node.getBeginToken(), token);
-    }
-    return null;
-  }
-
-  Token findPrecedingTokenFromToken(Token start, Token token) {
-    if (start != null) {
-      Token current = start;
-      while (current.kind != EOF_TOKEN && current.next != token) {
-        current = current.next;
-      }
-      if (current.kind != EOF_TOKEN) {
-        return current;
-      }
-    }
-    return null;
-  }
-
-  Token expectedIdentifier(Token token) {
-    if (token is KeywordToken) {
-      reportError(
-          token, MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
-          {'keyword': token.value});
-    } else if (token is ErrorToken) {
-      reportErrorToken(token);
-      return synthesizeIdentifier(token);
-    } else {
-      reportFatalError(token,
-          "Expected identifier, but got '${token.value}'.");
-    }
-    return token;
-  }
-
-  Token expectedType(Token token) {
-    pushNode(null);
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      return synthesizeIdentifier(token);
-    } else {
-      reportFatalError(
-          token, "Expected a type, but got '${token.value}'.");
-      return skipToEof(token);
-    }
-  }
-
-  Token expectedExpression(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      pushNode(new ErrorExpression(token));
-      return token.next;
-    } else {
-      reportFatalError(token,
-                       "Expected an expression, but got '${token.value}'.");
-      pushNode(null);
-      return skipToEof(token);
-    }
-  }
-
-  Token unexpected(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String message = "Unexpected token '${token.value}'.";
-      if (token.info == BAD_INPUT_INFO) {
-        message = token.value;
-      }
-      reportFatalError(token, message);
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedBlockToSkip(Token token) {
-    if (identical(token.stringValue, 'native')) {
-      return native.handleNativeBlockToSkip(this, token);
-    } else {
-      return unexpected(token);
-    }
-  }
-
-  Token expectedFunctionBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String printString = token.value;
-      reportFatalError(token,
-                       "Expected a function body, but got '$printString'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      reportFatalError(token,
-                       "Expected a class body, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBodyToSkip(Token token) {
-    return unexpected(token);
-  }
-
-  Token expectedDeclaration(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      reportFatalError(token,
-                       "Expected a declaration, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token unmatched(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-    } else {
-      String begin = token.value;
-      String end = closeBraceFor(begin);
-      reportError(
-          token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
-    }
-    Token next = token.next;
-    while (next is ErrorToken) {
-      next = next.next;
-    }
-    return next;
-  }
-
-  void recoverableError(Spannable node, String message) {
-    // TODO(johnniwinther): Make recoverable errors non-fatal.
-    reportFatalError(node, message);
-  }
-
-  void pushElement(Element element) {
-    popMetadata(element);
-    compilationUnitElement.addMember(element, listener);
-  }
-
-  Link<MetadataAnnotation> popMetadata(ElementX element) {
-    var result = const Link<MetadataAnnotation>();
-    for (Link link = metadata; !link.isEmpty; link = link.tail) {
-      element.addMetadata(link.head);
-      // Reverse the list as is implicitly done by addMetadata.
-      result = result.prepend(link.head);
-    }
-    metadata = const Link<MetadataAnnotation>();
-    return result;
-  }
-
-  void pushMetadata(MetadataAnnotation annotation) {
-    metadata = metadata.prepend(annotation);
-  }
-
-  void addLibraryTag(LibraryTag tag) {
-    if (!allowLibraryTags()) {
-      recoverableError(tag, 'Library tags not allowed here.');
-    }
-    LibraryElementX implementationLibrary =
-        compilationUnitElement.implementationLibrary;
-    implementationLibrary.addTag(tag, listener);
-  }
-
-  void pushNode(Node node) {
-    nodes = nodes.prepend(node);
-    if (VERBOSE) log("push $nodes");
-  }
-
-  Node popNode() {
-    assert(!nodes.isEmpty);
-    Node node = nodes.head;
-    nodes = nodes.tail;
-    if (VERBOSE) log("pop $nodes");
-    return node;
-  }
-
-  void log(message) {
-    print(message);
-  }
-
-  NodeList makeNodeList(int count, Token beginToken, Token endToken,
-                        String delimiter) {
-    Link<Node> poppedNodes = const Link<Node>();
-    for (; count > 0; --count) {
-      // This effectively reverses the order of nodes so they end up
-      // in correct (source) order.
-      poppedNodes = poppedNodes.prepend(popNode());
-    }
-    return new NodeList(beginToken, poppedNodes, endToken, delimiter);
-  }
-
-  void beginLiteralString(Token token) {
-    String source = token.value;
-    StringQuoting quoting = StringValidator.quotingFromString(source);
-    pushQuoting(quoting);
-    // Just wrap the token for now. At the end of the interpolation,
-    // when we know how many there are, go back and validate the tokens.
-    pushNode(new LiteralString(token, null));
-  }
-
-  void handleStringPart(Token token) {
-    // Just push an unvalidated token now, and replace it when we know the
-    // end of the interpolation.
-    pushNode(new LiteralString(token, null));
-  }
-
-  void endLiteralString(int count) {
-    StringQuoting quoting = popQuoting();
-
-    Link<StringInterpolationPart> parts =
-        const Link<StringInterpolationPart>();
-    // Parts of the string interpolation are popped in reverse order,
-    // starting with the last literal string part.
-    bool isLast = true;
-    for (int i = 0; i < count; i++) {
-      LiteralString string = popNode();
-      DartString validation =
-          stringValidator.validateInterpolationPart(string.token, quoting,
-                                                    isFirst: false,
-                                                    isLast: isLast);
-      // Replace the unvalidated LiteralString with a new LiteralString
-      // object that has the validation result included.
-      string = new LiteralString(string.token, validation);
-      Expression expression = popNode();
-      parts = parts.prepend(new StringInterpolationPart(expression, string));
-      isLast = false;
-    }
-
-    LiteralString string = popNode();
-    DartString validation =
-        stringValidator.validateInterpolationPart(string.token, quoting,
-                                                  isFirst: true,
-                                                  isLast: isLast);
-    string = new LiteralString(string.token, validation);
-    if (isLast) {
-      pushNode(string);
-    } else {
-      NodeList partNodes = new NodeList(null, parts, null, "");
-      pushNode(new StringInterpolation(string, partNodes));
-    }
-  }
-
-  void handleStringJuxtaposition(int stringCount) {
-    assert(stringCount != 0);
-    Expression accumulator = popNode();
-    stringCount--;
-    while (stringCount > 0) {
-      Expression expression = popNode();
-      accumulator = new StringJuxtaposition(expression, accumulator);
-      stringCount--;
-    }
-    pushNode(accumulator);
-  }
-
-  void beginMember(Token token) {
-    memberErrors = memberErrors.prepend(false);
-  }
-
-  void beginTopLevelMember(Token token) {
-    beginMember(token);
-  }
-
-  void endFields(fieldCount, start, token) {
-    memberErrors = memberErrors.tail;
-  }
-
-  void endMethod(getOrSet, start, token) {
-    memberErrors = memberErrors.tail;
-  }
-
-  void beginFactoryMethod(Token token) {
-    memberErrors = memberErrors.prepend(false);
-  }
-
-  void endFactoryMethod(Token beginToken, Token endToken) {
-    memberErrors = memberErrors.tail;
-  }
-
-  /// Don't call this method. Should only be used as a last resort when there
-  /// is no feasible way to recover from a parser error.
-  void reportFatalError(Spannable spannable, String message) {
-    reportError(spannable, MessageKind.GENERIC, {'text': message});
-    // Some parse errors are infeasible to recover from, so we throw an error.
-    throw new ParserError(message);
-  }
-
-  void reportError(Spannable spannable,
-                   MessageKind errorCode,
-                   [Map arguments = const {}]) {
-    if (currentMemberHasParseError) return; // Error already reported.
-    if (suppressParseErrors) return;
-    if (!memberErrors.isEmpty) {
-      memberErrors = memberErrors.tail.prepend(true);
-    }
-    listener.reportError(spannable, errorCode, arguments);
-  }
-}
-
-class NodeListener extends ElementListener {
-  NodeListener(
-      DiagnosticListener listener,
-      CompilationUnitElement element)
-    : super(listener, element, null);
-
-  void addLibraryTag(LibraryTag tag) {
-    pushNode(tag);
-  }
-
-  void addPartOfTag(PartOf tag) {
-    pushNode(tag);
-  }
-
-  void endClassDeclaration(int interfacesCount, Token beginToken,
-                           Token extendsKeyword, Token implementsKeyword,
-                           Token endToken) {
-    NodeList body = popNode();
-    NodeList interfaces =
-        makeNodeList(interfacesCount, implementsKeyword, null, ",");
-    Node supertype = popNode();
-    NodeList typeParameters = popNode();
-    Identifier name = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new ClassNode(modifiers, name, typeParameters, supertype,
-                           interfaces, beginToken, extendsKeyword, body,
-                           endToken));
-  }
-
-  void endCompilationUnit(int count, Token token) {
-    pushNode(makeNodeList(count, null, null, '\n'));
-  }
-
-  void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
-    NodeList formals = popNode();
-    NodeList typeParameters = popNode();
-    Identifier name = popNode();
-    TypeAnnotation returnType = popNode();
-    pushNode(new Typedef(returnType, name, typeParameters, formals,
-                         typedefKeyword, endToken));
-  }
-
-  void endNamedMixinApplication(Token classKeyword,
-                                Token implementsKeyword,
-                                Token endToken) {
-    NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
-    Node mixinApplication = popNode();
-    Modifiers modifiers = popNode();
-    NodeList typeParameters = popNode();
-    Identifier name = popNode();
-    pushNode(new NamedMixinApplication(name, typeParameters,
-                                       modifiers, mixinApplication,
-                                       interfaces,
-                                       classKeyword, endToken));
-  }
-
-  void endEnum(Token enumKeyword, Token endBrace, int count) {
-    NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
-    Identifier name = popNode();
-    pushNode(new Enum(enumKeyword, name, names));
-  }
-
-  void endClassBody(int memberCount, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(memberCount, beginToken, endToken, null));
-  }
-
-  void endTopLevelFields(int count, Token beginToken, Token endToken) {
-    NodeList variables = makeNodeList(count, null, endToken, ",");
-    TypeAnnotation type = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers, variables));
-  }
-
-  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
-    popNode(); // body
-    popNode(); // formalParameters
-    Identifier name = popNode();
-    popNode(); // type
-    Modifiers modifiers = popNode();
-    PartialFunctionElement element = new PartialFunctionElement(
-        name.source, beginToken, getOrSet, endToken,
-        modifiers, compilationUnitElement);
-    pushElement(element);
-  }
-
-  void endFormalParameter(Token thisKeyword) {
-    Expression name = popNode();
-    if (thisKeyword != null) {
-      Identifier thisIdentifier = new Identifier(thisKeyword);
-      if (name.asSend() == null) {
-        name = new Send(thisIdentifier, name);
-      } else {
-        name = name.asSend().copyWithReceiver(thisIdentifier, false);
-      }
-    }
-    TypeAnnotation type = popNode();
-    Modifiers modifiers = popNode();
-    NodeList metadata = popNode();
-    pushNode(new VariableDefinitions.forParameter(
-        metadata, type, modifiers, new NodeList.singleton(name)));
-  }
-
-  void endFormalParameters(int count, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, endToken, ","));
-  }
-
-  void handleNoFormalParameters(Token token) {
-    pushNode(null);
-  }
-
-  void endArguments(int count, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, endToken, ","));
-  }
-
-  void handleNoArguments(Token token) {
-    pushNode(null);
-  }
-
-  void endConstructorReference(Token start, Token periodBeforeName,
-                               Token endToken) {
-    Identifier name = null;
-    if (periodBeforeName != null) {
-      name = popNode();
-    }
-    NodeList typeArguments = popNode();
-    Node classReference = popNode();
-    if (typeArguments != null) {
-      classReference = new TypeAnnotation(classReference, typeArguments);
-    } else {
-      Identifier identifier = classReference.asIdentifier();
-      Send send = classReference.asSend();
-      if (identifier != null) {
-        // TODO(ahe): Should be:
-        // classReference = new Send(null, identifier);
-        classReference = identifier;
-      } else if (send != null) {
-        classReference = send;
-      } else {
-        internalError(node: classReference);
-      }
-    }
-    Node constructor = classReference;
-    if (name != null) {
-      // Either typeName<args>.name or x.y.name.
-      constructor = new Send(classReference, name);
-    }
-    pushNode(constructor);
-  }
-
-  void endRedirectingFactoryBody(Token beginToken,
-                                 Token endToken) {
-    pushNode(new RedirectingFactoryBody(beginToken, endToken, popNode()));
-  }
-
-  void endReturnStatement(bool hasExpression,
-                          Token beginToken, Token endToken) {
-    Expression expression = hasExpression ? popNode() : null;
-    pushNode(new Return(beginToken, endToken, expression));
-  }
-
-  void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
-    Expression expression = popNode();
-    pushNode(new Yield(yieldToken, starToken, expression, endToken));
-  }
-
-  void endExpressionStatement(Token token) {
-    pushNode(new ExpressionStatement(popNode(), token));
-  }
-
-  void handleOnError(Token token, var errorInformation) {
-    listener.internalError(token, "'${token.value}': ${errorInformation}");
-  }
-
-  Token expectedFunctionBody(Token token) {
-    if (identical(token.stringValue, 'native')) {
-      return native.handleNativeFunctionBody(this, token);
-    } else if (token is ErrorToken) {
-      pushNode(null);
-      reportErrorToken(token);
-    } else {
-      reportFatalError(token,
-                       "Expected a function body, but got '${token.value}'.");
-    }
-    return skipToEof(token);
-  }
-
-  Token expectedClassBody(Token token) {
-    if (token is ErrorToken) {
-      reportErrorToken(token);
-      return skipToEof(token);
-    } else {
-      reportFatalError(token,
-                       "Expected a class body, but got '${token.value}'.");
-      return skipToEof(token);
-    }
-  }
-
-  void handleLiteralInt(Token token) {
-    pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e)));
-  }
-
-  void handleLiteralDouble(Token token) {
-    pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e)));
-  }
-
-  void handleLiteralBool(Token token) {
-    pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e)));
-  }
-
-  void handleLiteralNull(Token token) {
-    pushNode(new LiteralNull(token));
-  }
-
-  void endLiteralSymbol(Token hashToken, int identifierCount) {
-    NodeList identifiers = makeNodeList(identifierCount, null, null, '.');
-    pushNode(new LiteralSymbol(hashToken, identifiers));
-  }
-
-  void handleBinaryExpression(Token token) {
-    Node argument = popNode();
-    Node receiver = popNode();
-    String tokenString = token.stringValue;
-    if (identical(tokenString, '.') ||
-        identical(tokenString, '..') ||
-        identical(tokenString, '?.')) {
-      Send argumentSend = argument.asSend();
-      if (argumentSend == null) {
-        // TODO(ahe): The parser should diagnose this problem, not
-        // this listener.
-        reportFatalError(argument,
-                         'Expected an identifier.');
-      }
-      if (argumentSend.receiver != null) internalError(node: argument);
-      if (argument is SendSet) internalError(node: argument);
-      pushNode(argument.asSend().copyWithReceiver(receiver,
-            identical(tokenString, '?.')));
-    } else {
-      NodeList arguments = new NodeList.singleton(argument);
-      pushNode(new Send(receiver, new Operator(token), arguments));
-    }
-    if (identical(tokenString, '===')) {
-      listener.reportError(token, MessageKind.UNSUPPORTED_EQ_EQ_EQ,
-                           {'lhs': receiver, 'rhs': argument});
-    }
-    if (identical(tokenString, '!==')) {
-      listener.reportError(token, MessageKind.UNSUPPORTED_BANG_EQ_EQ,
-                           {'lhs': receiver, 'rhs': argument});
-    }
-  }
-
-  void beginCascade(Token token) {
-    pushNode(new CascadeReceiver(popNode(), token));
-  }
-
-  void endCascade() {
-    pushNode(new Cascade(popNode()));
-  }
-
-  void handleAsOperator(Token operathor, Token endToken) {
-    TypeAnnotation type = popNode();
-    Expression expression = popNode();
-    NodeList arguments = new NodeList.singleton(type);
-    pushNode(new Send(expression, new Operator(operathor), arguments));
-  }
-
-  void handleAssignmentExpression(Token token) {
-    Node arg = popNode();
-    Node node = popNode();
-    Send send = node.asSend();
-    if (send == null || !(send.isPropertyAccess || send.isIndex)) {
-      reportNotAssignable(node);
-    }
-    if (send.asSendSet() != null) internalError(node: send);
-    NodeList arguments;
-    if (send.isIndex) {
-      Link<Node> link = const Link<Node>().prepend(arg);
-      link = link.prepend(send.arguments.head);
-      arguments = new NodeList(null, link);
-    } else {
-      arguments = new NodeList.singleton(arg);
-    }
-    Operator op = new Operator(token);
-    pushNode(new SendSet(send.receiver, send.selector, op, arguments,
-        send.isConditional));
-  }
-
-  void reportNotAssignable(Node node) {
-    // TODO(ahe): The parser should diagnose this problem, not this
-    // listener.
-    reportFatalError(node,
-                     'Not assignable.');
-  }
-
-  void handleConditionalExpression(Token question, Token colon) {
-    Node elseExpression = popNode();
-    Node thenExpression = popNode();
-    Node condition = popNode();
-    pushNode(new Conditional(
-        condition, thenExpression, elseExpression, question, colon));
-  }
-
-  void endSend(Token token) {
-    NodeList arguments = popNode();
-    Node selector = popNode();
-    // TODO(ahe): Handle receiver.
-    pushNode(new Send(null, selector, arguments));
-  }
-
-  void endFunctionBody(int count, Token beginToken, Token endToken) {
-    if (count == 0 && beginToken == null) {
-      pushNode(new EmptyStatement(endToken));
-    } else {
-      pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
-    }
-  }
-
-  void handleAsyncModifier(Token asyncToken, Token starToken) {
-    if (asyncToken != null) {
-      pushNode(new AsyncModifier(asyncToken, starToken));
-    } else {
-      pushNode(null);
-    }
-  }
-
-  void skippedFunctionBody(Token token) {
-    pushNode(new Block(new NodeList.empty()));
-  }
-
-  void handleNoFunctionBody(Token token) {
-    pushNode(new EmptyStatement(token));
-  }
-
-  void endFunction(Token getOrSet, Token endToken) {
-    Statement body = popNode();
-    AsyncModifier asyncModifier = popNode();
-    NodeList initializers = popNode();
-    NodeList formals = popNode();
-    // The name can be an identifier or a send in case of named constructors.
-    Expression name = popNode();
-    TypeAnnotation type = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new FunctionExpression(name, formals, body, type,
-                                    modifiers, initializers, getOrSet,
-                                    asyncModifier));
-  }
-
-  void endFunctionDeclaration(Token endToken) {
-    pushNode(new FunctionDeclaration(popNode()));
-  }
-
-  void endVariablesDeclaration(int count, Token endToken) {
-    // TODO(ahe): Pick one name for this concept, either
-    // VariablesDeclaration or VariableDefinitions.
-    NodeList variables = makeNodeList(count, null, endToken, ",");
-    TypeAnnotation type = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers, variables));
-  }
-
-  void endInitializer(Token assignmentOperator) {
-    Expression initializer = popNode();
-    NodeList arguments =
-        initializer == null ? null : new NodeList.singleton(initializer);
-    Expression name = popNode();
-    Operator op = new Operator(assignmentOperator);
-    pushNode(new SendSet(null, name, op, arguments));
-  }
-
-  void endIfStatement(Token ifToken, Token elseToken) {
-    Statement elsePart = (elseToken == null) ? null : popNode();
-    Statement thenPart = popNode();
-    ParenthesizedExpression condition = popNode();
-    pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken));
-  }
-
-  void endForStatement(int updateExpressionCount,
-                       Token beginToken, Token endToken) {
-    Statement body = popNode();
-    NodeList updates = makeNodeList(updateExpressionCount, null, null, ',');
-    Statement condition = popNode();
-    Node initializer = popNode();
-    pushNode(new For(initializer, condition, updates, body, beginToken));
-  }
-
-  void handleNoExpression(Token token) {
-    pushNode(null);
-  }
-
-  void endDoWhileStatement(Token doKeyword, Token whileKeyword,
-                           Token endToken) {
-    Expression condition = popNode();
-    Statement body = popNode();
-    pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken));
-  }
-
-  void endWhileStatement(Token whileKeyword, Token endToken) {
-    Statement body = popNode();
-    Expression condition = popNode();
-    pushNode(new While(condition, body, whileKeyword));
-  }
-
-  void endBlock(int count, Token beginToken, Token endToken) {
-    pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
-  }
-
-  void endThrowExpression(Token throwToken, Token endToken) {
-    Expression expression = popNode();
-    pushNode(new Throw(expression, throwToken, endToken));
-  }
-
-  void endAwaitExpression(Token awaitToken, Token endToken) {
-    Expression expression = popNode();
-    pushNode(new Await(awaitToken, expression));
-  }
-
-  void endRethrowStatement(Token throwToken, Token endToken) {
-    pushNode(new Rethrow(throwToken, endToken));
-    if (identical(throwToken.stringValue, 'throw')) {
-      listener.reportError(throwToken,
-                           MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
-    }
-  }
-
-  void handleUnaryPrefixExpression(Token token) {
-    pushNode(new Send.prefix(popNode(), new Operator(token)));
-  }
-
-  void handleSuperExpression(Token token) {
-    pushNode(new Identifier(token));
-  }
-
-  void handleThisExpression(Token token) {
-    pushNode(new Identifier(token));
-  }
-
-  void handleUnaryAssignmentExpression(Token token, bool isPrefix) {
-    Node node = popNode();
-    Send send = node.asSend();
-    if (send == null) {
-      reportNotAssignable(node);
-    }
-    if (!(send.isPropertyAccess || send.isIndex)) {
-      reportNotAssignable(node);
-    }
-    if (send.asSendSet() != null) internalError(node: send);
-    Node argument = null;
-    if (send.isIndex) argument = send.arguments.head;
-    Operator op = new Operator(token);
-
-    if (isPrefix) {
-      pushNode(new SendSet.prefix(send.receiver, send.selector, op, argument,
-          send.isConditional));
-    } else {
-      pushNode(new SendSet.postfix(send.receiver, send.selector, op, argument,
-          send.isConditional));
-    }
-  }
-
-  void handleUnaryPostfixAssignmentExpression(Token token) {
-    handleUnaryAssignmentExpression(token, false);
-  }
-
-  void handleUnaryPrefixAssignmentExpression(Token token) {
-    handleUnaryAssignmentExpression(token, true);
-  }
-
-  void endInitializers(int count, Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, null, ','));
-  }
-
-  void handleNoInitializers() {
-    pushNode(null);
-  }
-
-  void endFields(int count, Token beginToken, Token endToken) {
-    NodeList variables = makeNodeList(count, null, endToken, ",");
-    TypeAnnotation type = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new VariableDefinitions(type, modifiers, variables));
-  }
-
-  void endMethod(Token getOrSet, Token beginToken, Token endToken) {
-    Statement body = popNode();
-    AsyncModifier asyncModifier = popNode();
-    NodeList initializers = popNode();
-    NodeList formalParameters = popNode();
-    Expression name = popNode();
-    TypeAnnotation returnType = popNode();
-    Modifiers modifiers = popNode();
-    pushNode(new FunctionExpression(name, formalParameters, body, returnType,
-                                    modifiers, initializers, getOrSet,
-                                    asyncModifier));
-  }
-
-  void handleLiteralMap(int count, Token beginToken, Token constKeyword,
-                        Token endToken) {
-    NodeList entries = makeNodeList(count, beginToken, endToken, ',');
-    NodeList typeArguments = popNode();
-    pushNode(new LiteralMap(typeArguments, entries, constKeyword));
-  }
-
-  void endLiteralMapEntry(Token colon, Token endToken) {
-    Expression value = popNode();
-    Expression key = popNode();
-    pushNode(new LiteralMapEntry(key, colon, value));
-  }
-
-  void handleLiteralList(int count, Token beginToken, Token constKeyword,
-                         Token endToken) {
-    NodeList elements = makeNodeList(count, beginToken, endToken, ',');
-    pushNode(new LiteralList(popNode(), elements, constKeyword));
-  }
-
-  void handleIndexedExpression(Token openSquareBracket,
-                               Token closeSquareBracket) {
-    NodeList arguments =
-        makeNodeList(1, openSquareBracket, closeSquareBracket, null);
-    Node receiver = popNode();
-    Token token = new StringToken.fromString(INDEX_INFO, '[]',
-                                  openSquareBracket.charOffset);
-    Node selector = new Operator(token);
-    pushNode(new Send(receiver, selector, arguments));
-  }
-
-  void handleNewExpression(Token token) {
-    NodeList arguments = popNode();
-    Node name = popNode();
-    pushNode(new NewExpression(token, new Send(null, name, arguments)));
-  }
-
-  void handleConstExpression(Token token) {
-    // [token] carries the 'const' information.
-    handleNewExpression(token);
-  }
-
-  void handleOperator(Token token) {
-    pushNode(new Operator(token));
-  }
-
-  void handleOperatorName(Token operatorKeyword, Token token) {
-    Operator op = new Operator(token);
-    pushNode(new Send(new Identifier(operatorKeyword), op, null));
-  }
-
-  void handleNamedArgument(Token colon) {
-    Expression expression = popNode();
-    Identifier name = popNode();
-    pushNode(new NamedArgument(name, colon, expression));
-  }
-
-  void endOptionalFormalParameters(int count,
-                                   Token beginToken, Token endToken) {
-    pushNode(makeNodeList(count, beginToken, endToken, ','));
-  }
-
-  void handleFunctionTypedFormalParameter(Token endToken) {
-    NodeList formals = popNode();
-    Identifier name = popNode();
-    TypeAnnotation returnType = popNode();
-    pushNode(null); // Signal "no type" to endFormalParameter.
-    pushNode(new FunctionExpression(name, formals, null, returnType,
-                                    Modifiers.EMPTY, null, null, null));
-  }
-
-  void handleValuedFormalParameter(Token equals, Token token) {
-    Expression defaultValue = popNode();
-    Expression parameterName = popNode();
-    pushNode(new SendSet(null, parameterName, new Operator(equals),
-                         new NodeList.singleton(defaultValue)));
-  }
-
-  void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
-    Block finallyBlock = null;
-    if (finallyKeyword != null) {
-      finallyBlock = popNode();
-    }
-    NodeList catchBlocks = makeNodeList(catchCount, null, null, null);
-    Block tryBlock = popNode();
-    pushNode(new TryStatement(tryBlock, catchBlocks, finallyBlock,
-                              tryKeyword, finallyKeyword));
-  }
-
-  void handleCaseMatch(Token caseKeyword, Token colon) {
-    pushNode(new CaseMatch(caseKeyword, popNode(), colon));
-  }
-
-  void handleCatchBlock(Token onKeyword, Token catchKeyword) {
-    Block block = popNode();
-    NodeList formals = catchKeyword != null? popNode(): null;
-    TypeAnnotation type = onKeyword != null ? popNode() : null;
-    pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword));
-  }
-
-  void endSwitchStatement(Token switchKeyword, Token endToken) {
-    NodeList cases = popNode();
-    ParenthesizedExpression expression = popNode();
-    pushNode(new SwitchStatement(expression, cases, switchKeyword));
-  }
-
-  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
-    Link<Node> caseNodes = const Link<Node>();
-    while (caseCount > 0) {
-      SwitchCase switchCase = popNode();
-      caseNodes = caseNodes.prepend(switchCase);
-      caseCount--;
-    }
-    pushNode(new NodeList(beginToken, caseNodes, endToken, null));
-  }
-
-  void handleSwitchCase(int labelCount, int caseCount,
-                        Token defaultKeyword, int statementCount,
-                        Token firstToken, Token endToken) {
-    NodeList statements = makeNodeList(statementCount, null, null, null);
-    NodeList labelsAndCases =
-        makeNodeList(labelCount + caseCount, null, null, null);
-    pushNode(new SwitchCase(labelsAndCases, defaultKeyword, statements,
-                            firstToken));
-  }
-
-  void handleBreakStatement(bool hasTarget,
-                            Token breakKeyword, Token endToken) {
-    Identifier target = null;
-    if (hasTarget) {
-      target = popNode();
-    }
-    pushNode(new BreakStatement(target, breakKeyword, endToken));
-  }
-
-  void handleContinueStatement(bool hasTarget,
-                               Token continueKeyword, Token endToken) {
-    Identifier target = null;
-    if (hasTarget) {
-      target = popNode();
-    }
-    pushNode(new ContinueStatement(target, continueKeyword, endToken));
-  }
-
-  void handleEmptyStatement(Token token) {
-    pushNode(new EmptyStatement(token));
-  }
-
-  void endFactoryMethod(Token beginToken, Token endToken) {
-    super.endFactoryMethod(beginToken, endToken);
-    Statement body = popNode();
-    AsyncModifier asyncModifier = popNode();
-    NodeList formals = popNode();
-    Node name = popNode();
-
-    // TODO(ahe): Move this parsing to the parser.
-    int modifierCount = 0;
-    Token modifier = beginToken;
-    if (modifier.stringValue == "external") {
-      handleModifier(modifier);
-      modifierCount++;
-      modifier = modifier.next;
-    }
-    if (modifier.stringValue == "const") {
-      handleModifier(modifier);
-      modifierCount++;
-      modifier = modifier.next;
-    }
-    assert(modifier.stringValue == "factory");
-    handleModifier(modifier);
-    modifierCount++;
-    handleModifiers(modifierCount);
-    Modifiers modifiers = popNode();
-
-    pushNode(new FunctionExpression(name, formals, body, null,
-                                    modifiers, null, null, asyncModifier));
-  }
-
-  void endForIn(Token awaitToken, Token forToken,
-                Token inKeyword, Token endToken) {
-    Statement body = popNode();
-    Expression expression = popNode();
-    Node declaredIdentifier = popNode();
-    if (awaitToken == null) {
-      pushNode(new SyncForIn(declaredIdentifier, expression, body,
-                             forToken, inKeyword));
-    } else {
-      pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken,
-                              forToken, inKeyword));
-    }
-  }
-
-  void endMetadataStar(int count, bool forParameter) {
-    // TODO(johnniwinther): Handle metadata for all node kinds.
-    if (forParameter) {
-      if (0 == count) {
-        pushNode(null);
-      } else {
-        pushNode(makeNodeList(count, null, null, ' '));
-      }
-    }
-  }
-
-  void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
-    NodeList arguments = popNode();
-    if (arguments == null) {
-      // This is a constant expression.
-      Identifier name;
-      if (periodBeforeName != null) {
-        name = popNode();
-      }
-      NodeList typeArguments = popNode();
-      Node receiver = popNode();
-      if (typeArguments != null) {
-        receiver = new TypeAnnotation(receiver, typeArguments);
-        recoverableError(typeArguments,
-                         'Type arguments are not allowed here.');
-      } else {
-        Identifier identifier = receiver.asIdentifier();
-        Send send = receiver.asSend();
-        if (identifier != null) {
-          receiver = new Send(null, identifier);
-        } else if (send == null) {
-          internalError(node: receiver);
-        }
-      }
-      Send send = receiver;
-      if (name != null) {
-        send = new Send(receiver, name);
-      }
-      pushNode(new Metadata(beginToken, send));
-    } else {
-      // This is a const constructor call.
-      endConstructorReference(beginToken, periodBeforeName, endToken);
-      Node constructor = popNode();
-      pushNode(new Metadata(beginToken,
-          new NewExpression(null,
-              new Send(null, constructor, arguments))));
-    }
-  }
-
-  void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
-    NodeList arguments = popNode();
-    Node selector = new Identifier(assertKeyword);
-    Node send = new Send(null, selector, arguments);
-    pushNode(new ExpressionStatement(send, semicolonToken));
-  }
-
-  void endUnnamedFunction(Token token) {
-    Statement body = popNode();
-    AsyncModifier asyncModifier = popNode();
-    NodeList formals = popNode();
-    pushNode(new FunctionExpression(null, formals, body, null,
-                                    Modifiers.EMPTY, null, null,
-                                    asyncModifier));
-  }
-
-  void handleIsOperator(Token operathor, Token not, Token endToken) {
-    TypeAnnotation type = popNode();
-    Expression expression = popNode();
-    Node argument;
-    if (not != null) {
-      argument = new Send.prefix(type, new Operator(not));
-    } else {
-      argument = type;
-    }
-
-    NodeList arguments = new NodeList.singleton(argument);
-    pushNode(new Send(expression, new Operator(operathor), arguments));
-  }
-
-  void handleLabel(Token colon) {
-    Identifier name = popNode();
-    pushNode(new Label(name, colon));
-  }
-
-  void endLabeledStatement(int labelCount) {
-    Statement statement = popNode();
-    NodeList labels = makeNodeList(labelCount, null, null, null);
-    pushNode(new LabeledStatement(labels, statement));
-  }
-
-  void log(message) {
-    listener.log(message);
-  }
-
-  void internalError({Token token, Node node}) {
-    // TODO(ahe): This should call listener.internalError.
-    Spannable spannable = (token == null) ? node : token;
-    throw new SpannableAssertionFailure(spannable, 'Internal error in parser.');
-  }
-}
-
-abstract class PartialElement implements DeclarationSite {
-  Token beginToken;
-  Token endToken;
-
-  bool hasParseError = false;
-
-  bool get isErroneous => hasParseError;
-
-  DeclarationSite get declarationSite => this;
-}
-
-abstract class PartialFunctionMixin implements BaseFunctionElementX {
-  FunctionExpression cachedNode;
-  Modifiers get modifiers;
-  Token beginToken;
-  Token getOrSet;
-  Token endToken;
-
-  /**
-   * The position is computed in the constructor using [findMyName]. Computing
-   * it on demand fails in case tokens are GC'd.
-   */
-  Token _position;
-
-  void init(Token beginToken, Token getOrSet, Token endToken) {
-    this.beginToken = beginToken;
-    this.getOrSet = getOrSet;
-    this.endToken = endToken;
-    _position = ElementX.findNameToken(
-        beginToken,
-        modifiers.isFactory ||
-          identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR),
-        name, enclosingElement.name);
-  }
-
-  bool get hasNode => cachedNode != null;
-
-  FunctionExpression get node {
-    assert(invariant(this, cachedNode != null,
-        message: "Node has not been computed for $this."));
-    return cachedNode;
-  }
-
-  FunctionExpression parseNode(DiagnosticListener listener) {
-    if (cachedNode != null) return cachedNode;
-    parseFunction(Parser p) {
-      if (isClassMember && modifiers.isFactory) {
-        p.parseFactoryMethod(beginToken);
-      } else {
-        p.parseFunction(beginToken, getOrSet);
-      }
-    }
-    cachedNode = parse(listener, this, declarationSite, parseFunction);
-    return cachedNode;
-  }
-
-  Token get position => _position;
-
-  void reusePartialFunctionMixin() {
-    cachedNode = null;
-  }
-
-  DeclarationSite get declarationSite;
-}
-
-abstract class PartialFunctionElement
-    implements PartialElement, PartialFunctionMixin {
-
-  factory PartialFunctionElement(
-      String name,
-      Token beginToken,
-      Token getOrSet,
-      Token endToken,
-      Modifiers modifiers,
-      Element enclosingElement,
-      {bool hasBody: true}) {
-    if (getOrSet == null) {
-      return new PartialMethodElement(
-          name, beginToken, endToken, modifiers,
-          enclosingElement, hasBody: hasBody);
-    } else if (identical(getOrSet.stringValue, 'get')) {
-      return new PartialGetterElement(
-          name, beginToken, getOrSet, endToken, modifiers,
-          enclosingElement, hasBody: hasBody);
-    } else {
-      assert(identical(getOrSet.stringValue, 'set'));
-      return new PartialSetterElement(
-          name, beginToken, getOrSet, endToken, modifiers,
-          enclosingElement, hasBody: hasBody);
-    }
-  }
-
-  PartialFunctionElement copyWithEnclosing(Element enclosing);
-}
-
-
-class PartialMethodElement extends MethodElementX
-    with PartialElement, PartialFunctionMixin
-    implements PartialFunctionElement {
-  PartialMethodElement(String name,
-                       Token beginToken,
-                       Token endToken,
-                       Modifiers modifiers,
-                       Element enclosing,
-                       {bool hasBody: true})
-      : super(name, ElementKind.FUNCTION, modifiers, enclosing, hasBody) {
-    init(beginToken, null, endToken);
-  }
-
-  void reuseElement() {
-    super.reuseElement();
-    reusePartialFunctionMixin();
-  }
-
-  PartialMethodElement copyWithEnclosing(Element enclosing) {
-    return new PartialMethodElement(
-        name, beginToken, endToken, modifiers, enclosing, hasBody: hasBody);
-  }
-}
-
-class PartialGetterElement extends GetterElementX
-    with PartialElement, PartialFunctionMixin
-    implements GetterElement, PartialFunctionElement  {
-  PartialGetterElement(String name,
-                       Token beginToken,
-                       Token getToken,
-                       Token endToken,
-                       Modifiers modifiers,
-                       Element enclosing,
-                       {bool hasBody: true})
-      : super(name, modifiers, enclosing, hasBody) {
-    init(beginToken, getToken, endToken);
-  }
-
-  @override
-  SetterElement get setter => abstractField.setter;
-
-  void reuseElement() {
-    super.reuseElement();
-    reusePartialFunctionMixin();
-  }
-
-  PartialGetterElement copyWithEnclosing(Element enclosing) {
-    return new PartialGetterElement(
-        name, beginToken, getOrSet, endToken, modifiers, enclosing,
-        hasBody: hasBody);
-  }
-}
-
-class PartialSetterElement extends SetterElementX
-    with PartialElement, PartialFunctionMixin
-    implements SetterElement, PartialFunctionElement {
-  PartialSetterElement(String name,
-                       Token beginToken,
-                       Token setToken,
-                       Token endToken,
-                       Modifiers modifiers,
-                       Element enclosing,
-                       {bool hasBody: true})
-      : super(name, modifiers, enclosing, hasBody) {
-    init(beginToken, setToken, endToken);
-  }
-
-  @override
-  GetterElement get getter => abstractField.getter;
-
-  void reuseElement() {
-    super.reuseElement();
-    reusePartialFunctionMixin();
-  }
-
-  PartialSetterElement copyWithEnclosing(Element enclosing) {
-    return new PartialSetterElement(
-        name, beginToken, getOrSet, endToken, modifiers, enclosing,
-        hasBody: hasBody);
-  }
-}
-
-class PartialConstructorElement extends ConstructorElementX
-    with PartialElement, PartialFunctionMixin {
-  PartialConstructorElement(String name,
-                            Token beginToken,
-                            Token endToken,
-                            ElementKind kind,
-                            Modifiers modifiers,
-                            Element enclosing)
-      : super(name, kind, modifiers, enclosing) {
-    init(beginToken, null, endToken);
-  }
-
-  void reuseElement() {
-    super.reuseElement();
-    reusePartialFunctionMixin();
-  }
-}
-
-class PartialFieldList extends VariableList with PartialElement {
-  PartialFieldList(Token beginToken,
-                   Token endToken,
-                   Modifiers modifiers,
-                   bool hasParseError)
-      : super(modifiers) {
-    super.beginToken = beginToken;
-    super.endToken = endToken;
-    super.hasParseError = hasParseError;
-  }
-
-  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
-    if (definitions != null) return definitions;
-    listener.withCurrentElement(element, () {
-      definitions = parse(
-          listener, element, declarationSite,
-          (Parser parser) => parser.parseMember(beginToken));
-
-      if (!hasParseError &&
-          !definitions.modifiers.isVar &&
-          !definitions.modifiers.isFinal &&
-          !definitions.modifiers.isConst &&
-          definitions.type == null &&
-          !definitions.isErroneous) {
-        listener.reportError(
-            definitions,
-            MessageKind.GENERIC,
-            { 'text': 'A field declaration must start with var, final, '
-                      'const, or a type annotation.' });
-      }
-    });
-    return definitions;
-  }
-
-  computeType(Element element, Compiler compiler) {
-    if (type != null) return type;
-    // TODO(johnniwinther): Compute this in the resolver.
-    compiler.withCurrentElement(element, () {
-      VariableDefinitions node = parseNode(element, compiler);
-      if (node.type != null) {
-        type = compiler.resolver.resolveTypeAnnotation(element, node.type);
-      } else {
-        type = const DynamicType();
-      }
-    });
-    assert(type != null);
-    return type;
-  }
-}
-
-class PartialTypedefElement extends TypedefElementX with PartialElement {
-
-  PartialTypedefElement(
-      String name,
-      Element enclosing,
-      Token beginToken,
-      Token endToken)
-      : super(name, enclosing) {
-    this.beginToken = beginToken;
-    this.endToken = endToken;
-  }
-
-  Token get token => beginToken;
-
-  Node parseNode(DiagnosticListener listener) {
-    if (cachedNode != null) return cachedNode;
-    cachedNode = parse(
-        listener, this, declarationSite,
-        (p) => p.parseTopLevelDeclaration(token));
-    return cachedNode;
-  }
-
-  Token get position => findMyName(token);
-}
-
-/// A [MetadataAnnotation] which is constructed on demand.
-class PartialMetadataAnnotation extends MetadataAnnotationX
-    implements PartialElement {
-  Token beginToken; // TODO(ahe): Make this final when issue 22065 is fixed.
-
-  final Token tokenAfterEndToken;
-
-  Expression cachedNode;
-
-  bool hasParseError = false;
-
-  PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
-
-  bool get isErroneous => hasParseError;
-
-  DeclarationSite get declarationSite => this;
-
-  Token get endToken {
-    Token token = beginToken;
-    while (token.kind != EOF_TOKEN) {
-      if (identical(token.next, tokenAfterEndToken)) break;
-      token = token.next;
-    }
-    assert(token != null);
-    return token;
-  }
-
-  void set endToken(_) {
-    throw new UnsupportedError("endToken=");
-  }
-
-  Node parseNode(DiagnosticListener listener) {
-    if (cachedNode != null) return cachedNode;
-    var metadata = parse(listener,
-                         annotatedElement,
-                         declarationSite,
-                         (p) => p.parseMetadata(beginToken));
-    if (metadata is Metadata) {
-      cachedNode = metadata.expression;
-      return cachedNode;
-    } else {
-      assert (metadata is ErrorNode);
-      return metadata;
-    }
-  }
-
-  bool get hasNode => cachedNode != null;
-
-  Node get node {
-    assert(invariant(this, hasNode));
-    return cachedNode;
-  }
-}
-
-Node parse(
-    DiagnosticListener diagnosticListener,
-    ElementX element,
-    PartialElement partial,
-    doParse(Parser parser)) {
-  CompilationUnitElement unit = element.compilationUnit;
-  NodeListener listener = new NodeListener(diagnosticListener, unit);
-  listener.memberErrors = listener.memberErrors.prepend(false);
-  try {
-    if (partial.hasParseError) {
-      listener.suppressParseErrors = true;
-    }
-    doParse(new Parser(listener));
-  } on ParserError catch (e) {
-    partial.hasParseError = true;
-    return new ErrorNode(element.position, e.reason);
-  }
-  Node node = listener.popNode();
-  assert(listener.nodes.isEmpty);
-  return node;
-}
diff --git a/pkg/compiler/lib/src/scanner/scanner.dart b/pkg/compiler/lib/src/scanner/scanner.dart
index d9ab312..1a52a64 100644
--- a/pkg/compiler/lib/src/scanner/scanner.dart
+++ b/pkg/compiler/lib/src/scanner/scanner.dart
@@ -2,7 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of scanner;
+library dart2js.scanner;
+
+import '../io/source_file.dart' show
+    SourceFile,
+    Utf8BytesSourceFile;
+import '../tokens/keyword.dart' show
+    Keyword,
+    KeywordState;
+import '../tokens/precedence.dart';
+import '../tokens/precedence_constants.dart';
+import '../tokens/token.dart';
+import '../tokens/token_constants.dart';
+import '../util/characters.dart';
+
+import 'string_scanner.dart' show
+    StringScanner;
+import 'utf8_bytes_scanner.dart' show
+    Utf8BytesScanner;
+
 
 abstract class Scanner {
   Token tokenize();
diff --git a/pkg/compiler/lib/src/scanner/scanner_task.dart b/pkg/compiler/lib/src/scanner/scanner_task.dart
index 636ee34..cc13bb5 100644
--- a/pkg/compiler/lib/src/scanner/scanner_task.dart
+++ b/pkg/compiler/lib/src/scanner/scanner_task.dart
@@ -2,7 +2,24 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of scanner;
+library dart2js.scanner.task;
+
+import '../common/tasks.dart' show
+    CompilerTask;
+import '../compiler.dart' show
+    Compiler;
+import '../elements/elements.dart' show
+    CompilationUnitElement,
+    LibraryElement;
+import '../script.dart' show
+    Script;
+import '../tokens/token.dart' show
+    Token;
+
+import 'scanner.dart' show
+    Scanner;
+import 'string_scanner.dart' show
+    StringScanner;
 
 class ScannerTask extends CompilerTask {
   ScannerTask(Compiler compiler) : super(compiler);
@@ -50,22 +67,3 @@
     });
   }
 }
-
-class DietParserTask extends CompilerTask {
-  DietParserTask(Compiler compiler) : super(compiler);
-  final String name = 'Diet Parser';
-
-  dietParse(CompilationUnitElement compilationUnit, Token tokens) {
-    measure(() {
-      Function idGenerator = compiler.getNextFreeClassId;
-      ElementListener listener =
-          new ElementListener(compiler, compilationUnit, idGenerator);
-      PartialParser parser = new PartialParser(listener);
-      try {
-        parser.parseUnit(tokens);
-      } on ParserError catch(_) {
-        assert(invariant(compilationUnit, compiler.compilationFailed));
-      }
-    });
-  }
-}
diff --git a/pkg/compiler/lib/src/scanner/scannerlib.dart b/pkg/compiler/lib/src/scanner/scannerlib.dart
deleted file mode 100644
index e4058c8..0000000
--- a/pkg/compiler/lib/src/scanner/scannerlib.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library scanner;
-
-import 'dart:collection' show IterableBase, HashSet;
-
-import '../common/tasks.dart' show
-    CompilerTask;
-import '../compiler.dart' show
-    Compiler;
-import '../dart_types.dart' show DynamicType;
-import '../diagnostics/diagnostic_listener.dart';
-import '../diagnostics/invariant.dart' show
-    invariant;
-import '../diagnostics/messages.dart';
-import '../diagnostics/spannable.dart' show
-    Spannable,
-    SpannableAssertionFailure;
-import '../elements/elements.dart';
-
-import '../elements/modelx.dart' show
-    BaseFunctionElementX,
-    ClassElementX,
-    CompilationUnitElementX,
-    ConstructorElementX,
-    DeclarationSite,
-    ElementX,
-    EnumClassElementX,
-    FieldElementX,
-    GetterElementX,
-    MethodElementX,
-    LibraryElementX,
-    MetadataAnnotationX,
-    MixinApplicationElementX,
-    SetterElementX,
-    TypedefElementX,
-    VariableElementX,
-    VariableList;
-
-import '../elements/visitor.dart'
-    show ElementVisitor;
-import '../native/native.dart' as native;
-import '../string_validator.dart';
-import '../script.dart';
-import '../tree/tree.dart';
-import '../util/characters.dart';
-import '../util/util.dart';
-import '../io/source_file.dart' show SourceFile, Utf8BytesSourceFile;
-import 'dart:convert' show UTF8, UNICODE_BOM_CHARACTER_RUNE;
-
-part 'class_element_parser.dart';
-part 'keyword.dart';
-part 'listener.dart';
-part 'parser.dart';
-part 'parser_task.dart';
-part 'partial_parser.dart';
-part 'scanner.dart';
-part 'scanner_task.dart';
-part 'array_based_scanner.dart';
-part 'utf8_bytes_scanner.dart';
-part 'string_scanner.dart';
-part 'token.dart';
diff --git a/pkg/compiler/lib/src/scanner/string_scanner.dart b/pkg/compiler/lib/src/scanner/string_scanner.dart
index 5a30e43..aec14a0 100644
--- a/pkg/compiler/lib/src/scanner/string_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/string_scanner.dart
@@ -2,7 +2,20 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of scanner;
+library dart2js.scanner.string;
+
+import '../io/source_file.dart' show
+    SourceFile;
+import '../tokens/precedence.dart' show
+    PrecedenceInfo;
+import '../tokens/token.dart' show
+    PrecedenceInfo,
+    StringToken,
+    Token;
+
+import 'array_based_scanner.dart' show
+    ArrayBasedScanner;
+
 
 /**
  * Scanner that reads from a String and creates tokens that points to
diff --git a/pkg/compiler/lib/src/scanner/token.dart b/pkg/compiler/lib/src/scanner/token.dart
deleted file mode 100644
index 2dff11e..0000000
--- a/pkg/compiler/lib/src/scanner/token.dart
+++ /dev/null
@@ -1,741 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of scanner;
-
-const int EOF_TOKEN = 0;
-
-const int KEYWORD_TOKEN = $k;
-const int IDENTIFIER_TOKEN = $a;
-const int BAD_INPUT_TOKEN = $X;
-const int DOUBLE_TOKEN = $d;
-const int INT_TOKEN = $i;
-const int HEXADECIMAL_TOKEN = $x;
-const int STRING_TOKEN = $SQ;
-
-const int AMPERSAND_TOKEN = $AMPERSAND;
-const int BACKPING_TOKEN = $BACKPING;
-const int BACKSLASH_TOKEN = $BACKSLASH;
-const int BANG_TOKEN = $BANG;
-const int BAR_TOKEN = $BAR;
-const int COLON_TOKEN = $COLON;
-const int COMMA_TOKEN = $COMMA;
-const int EQ_TOKEN = $EQ;
-const int GT_TOKEN = $GT;
-const int HASH_TOKEN = $HASH;
-const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET;
-const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET;
-const int OPEN_PAREN_TOKEN = $OPEN_PAREN;
-const int LT_TOKEN = $LT;
-const int MINUS_TOKEN = $MINUS;
-const int PERIOD_TOKEN = $PERIOD;
-const int PLUS_TOKEN = $PLUS;
-const int QUESTION_TOKEN = $QUESTION;
-const int AT_TOKEN = $AT;
-const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET;
-const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET;
-const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN;
-const int SEMICOLON_TOKEN = $SEMICOLON;
-const int SLASH_TOKEN = $SLASH;
-const int TILDE_TOKEN = $TILDE;
-const int STAR_TOKEN = $STAR;
-const int PERCENT_TOKEN = $PERCENT;
-const int CARET_TOKEN = $CARET;
-
-const int STRING_INTERPOLATION_TOKEN = 128;
-const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1;
-const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1;
-const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1;
-const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1;
-const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1;
-const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1;
-const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1;
-const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1;
-const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1;
-const int GT_EQ_TOKEN = LT_LT_TOKEN + 1;
-const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1;
-const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1;
-const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1;
-const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1;
-const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1;
-const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1;
-const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1;
-const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1;
-const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1;
-const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1;
-const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1;
-const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1;
-const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1;
-const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1;
-const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1;
-const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1;
-const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1;
-const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1;
-const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1;
-const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1;
-const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1;
-const int QUESTION_PERIOD_TOKEN = STRING_INTERPOLATION_IDENTIFIER_TOKEN + 1;
-const int QUESTION_QUESTION_TOKEN = QUESTION_PERIOD_TOKEN + 1;
-const int QUESTION_QUESTION_EQ_TOKEN = QUESTION_QUESTION_TOKEN + 1;
-
-/**
- * A token that doubles as a linked list.
- */
-abstract class Token implements Spannable {
-  /**
-   * The character offset of the start of this token within the source text.
-   */
-  final int charOffset;
-
-  Token(this.charOffset);
-
-  /**
-   * The next token in the token stream.
-   */
-  Token next;
-
-  /**
-   * The precedence info for this token. [info] determines the kind and the
-   * precedence level of this token.
-   *
-   * Defined as getter to save a field in the [KeywordToken] subclass.
-   */
-  PrecedenceInfo get info;
-
-  /**
-   * The string represented by this token, a substring of the source code.
-   *
-   * For [StringToken]s the [value] includes the quotes, explicit escapes, etc.
-   */
-  String get value;
-
-  /**
-   * For symbol and keyword tokens, returns the string value represented by this
-   * token. For [StringToken]s this method returns [:null:].
-   *
-   * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time
-   * constant originating in the [PrecedenceInfo] or in the [Keyword] instance.
-   * This allows testing for keywords and symbols using [:identical:], e.g.,
-   * [:identical('class', token.value):].
-   *
-   * Note that returning [:null:] for string tokens is important to identify
-   * symbols and keywords, we cannot use [value] instead. The string literal
-   *   "$a($b"
-   * produces ..., SymbolToken($), StringToken(a), StringToken((), ...
-   *
-   * After parsing the identifier 'a', the parser tests for a function
-   * declaration using [:identical(next.stringValue, '('):], which (rightfully)
-   * returns false because stringValue returns [:null:].
-   */
-  String get stringValue;
-
-  /**
-   * The kind enum of this token as determined by its [info].
-   */
-  int get kind => info.kind;
-
-  /**
-   * The precedence level for this token.
-   */
-  int get precedence => info.precedence;
-
-  /**
-   * True if this token is an identifier. Some keywords allowed as identifiers,
-   * see implementation in [KeywordToken].
-   */
-  bool isIdentifier();
-
-  /**
-   * Returns a textual representation of this token to be used for debugging
-   * purposes. The resulting string might contain information about the
-   * structure of the token, for example 'StringToken(foo)' for the identifier
-   * token 'foo'.
-   *
-   * Use [value] for the text actually parsed by the token.
-   */
-  String toString();
-
-  /**
-   * The number of characters parsed by this token.
-   */
-  int get charCount {
-    if (info == BAD_INPUT_INFO) {
-      // This is a token that wraps around an error message. Return 1
-      // instead of the size of the length of the error message.
-      return 1;
-    } else {
-      return value.length;
-    }
-  }
-
-  int get hashCode => computeHashCode(charOffset, info, value);
-}
-
-/// A pair of tokens marking the beginning and the end of a span. Use for error
-/// reporting.
-class TokenPair implements Spannable {
-  final Token begin;
-  final Token end;
-
-  TokenPair(this.begin, this.end);
-}
-
-/**
- * A [SymbolToken] represents the symbol in its precendence info.
- * Also used for end of file with EOF_INFO.
- */
-class SymbolToken extends Token {
-
-  final PrecedenceInfo info;
-
-  SymbolToken(this.info, int charOffset) : super(charOffset);
-
-  String get value => info.value;
-
-  String get stringValue => info.value;
-
-  bool isIdentifier() => false;
-
-  String toString() => "SymbolToken($value)";
-}
-
-/**
- * A [BeginGroupToken] represents a symbol that may be the beginning of
- * a pair of brackets, i.e., ( { [ < or ${
- * The [endGroup] token points to the matching closing bracked in case
- * it can be identified during scanning.
- */
-class BeginGroupToken extends SymbolToken {
-  Token endGroup;
-
-  BeginGroupToken(PrecedenceInfo info, int charOffset)
-      : super(info, charOffset);
-}
-
-/**
- * A keyword token.
- */
-class KeywordToken extends Token {
-  final Keyword keyword;
-
-  KeywordToken(this.keyword, int charOffset) : super(charOffset);
-
-  PrecedenceInfo get info => keyword.info;
-
-  String get value => keyword.syntax;
-
-  String get stringValue => keyword.syntax;
-
-  bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn;
-
-  String toString() => "KeywordToken($value)";
-}
-
-abstract class ErrorToken extends Token {
-  ErrorToken(int charOffset)
-      : super(charOffset);
-
-  PrecedenceInfo get info => BAD_INPUT_INFO;
-
-  String get value {
-    throw new SpannableAssertionFailure(this, assertionMessage);
-  }
-
-  String get stringValue => null;
-
-  bool isIdentifier() => false;
-
-  String get assertionMessage;
-}
-
-class BadInputToken extends ErrorToken {
-  final int character;
-
-  BadInputToken(this.character, int charOffset)
-      : super(charOffset);
-
-  String toString() => "BadInputToken($character)";
-
-  String get assertionMessage {
-    return 'Character U+${character.toRadixString(16)} not allowed here.';
-  }
-}
-
-class UnterminatedToken extends ErrorToken {
-  final String start;
-  final int endOffset;
-
-  UnterminatedToken(this.start, int charOffset, this.endOffset)
-      : super(charOffset);
-
-  String toString() => "UnterminatedToken($start)";
-
-  String get assertionMessage => "'$start' isn't terminated.";
-
-  int get charCount => endOffset - charOffset;
-}
-
-class UnmatchedToken extends ErrorToken {
-  final BeginGroupToken begin;
-
-  UnmatchedToken(BeginGroupToken begin)
-      : this.begin = begin,
-        super(begin.charOffset);
-
-  String toString() => "UnmatchedToken(${begin.value})";
-
-  String get assertionMessage => "'$begin' isn't closed.";
-}
-
-/**
- * A String-valued token. Represents identifiers, string literals,
- * number literals, comments, and error tokens, using the corresponding
- * precedence info.
- */
-class StringToken extends Token {
-  /**
-   * The length threshold above which substring tokens are computed lazily.
-   *
-   * For string tokens that are substrings of the program source, the actual
-   * substring extraction is performed lazily. This is beneficial because
-   * not all scanned code is actually used. For unused parts, the substrings
-   * are never computed and allocated.
-   */
-  static const int LAZY_THRESHOLD = 4;
-
-  var /* String | LazySubtring */ valueOrLazySubstring;
-
-  final PrecedenceInfo info;
-
-  /**
-   * Creates a non-lazy string token. If [canonicalize] is true, the string
-   * is canonicalized before the token is created.
-   */
-  StringToken.fromString(this.info, String value, int charOffset,
-                         {bool canonicalize : false})
-      : valueOrLazySubstring = canonicalizedString(value, canonicalize),
-        super(charOffset);
-
-  /**
-   * Creates a lazy string token. If [canonicalize] is true, the string
-   * is canonicalized before the token is created.
-   */
-  StringToken.fromSubstring(this.info, String data, int start, int end,
-                            int charOffset, {bool canonicalize : false})
-      : super(charOffset) {
-    int length = end - start;
-    if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring = canonicalizedString(data.substring(start, end),
-                                                 canonicalize);
-    } else {
-      valueOrLazySubstring =
-          new LazySubstring(data, start, length, canonicalize);
-    }
-  }
-
-  /**
-   * Creates a lazy string token. If [asciiOnly] is false, the byte array
-   * is passed through a UTF-8 decoder.
-   */
-  StringToken.fromUtf8Bytes(this.info, List<int> data, int start, int end,
-                            bool asciiOnly, int charOffset)
-      : super(charOffset) {
-    int length = end - start;
-    if (length <= LAZY_THRESHOLD) {
-      valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly);
-    } else {
-      valueOrLazySubstring = new LazySubstring(data, start, length, asciiOnly);
-    }
-  }
-
-  String get value {
-    if (valueOrLazySubstring is String) {
-      return valueOrLazySubstring;
-    } else {
-      assert(valueOrLazySubstring is LazySubstring);
-      var data = valueOrLazySubstring.data;
-      int start = valueOrLazySubstring.start;
-      int end = start + valueOrLazySubstring.length;
-      if (data is String) {
-        valueOrLazySubstring = canonicalizedString(
-            data.substring(start, end), valueOrLazySubstring.boolValue);
-      } else {
-        valueOrLazySubstring = decodeUtf8(
-            data, start, end, valueOrLazySubstring.boolValue);
-      }
-      return valueOrLazySubstring;
-    }
-  }
-
-  /// See [Token.stringValue] for an explanation.
-  String get stringValue => null;
-
-  bool isIdentifier() => identical(kind, IDENTIFIER_TOKEN);
-
-  String toString() => "StringToken($value)";
-
-  static final HashSet<String> canonicalizedSubstrings =
-      new HashSet<String>();
-
-  static String canonicalizedString(String s, bool canonicalize) {
-    if (!canonicalize) return s;
-    var result = canonicalizedSubstrings.lookup(s);
-    if (result != null) return result;
-    canonicalizedSubstrings.add(s);
-    return s;
-  }
-
-  static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
-    var s;
-    if (asciiOnly) {
-      s = new String.fromCharCodes(data, start, end);
-    } else {
-      s = UTF8.decoder.convert(data, start, end);
-    }
-    return canonicalizedString(s, true);
-  }
-}
-
-/**
- * This class represents the necessary information to compute a substring
- * lazily. The substring can either originate from a string or from
- * a [:List<int>:] of UTF-8 bytes.
- */
-abstract class LazySubstring {
-  /** The original data, either a string or a List<int> */
-  get data;
-
-  int get start;
-  int get length;
-
-  /**
-   * If this substring is based on a String, the [boolValue] indicates wheter
-   * the resulting substring should be canonicalized.
-   *
-   * For substrings based on a byte array, the [boolValue] is true if the
-   * array only holds ASCII characters. The resulting substring will be
-   * canonicalized after decoding.
-   */
-  bool get boolValue;
-
-  LazySubstring.internal();
-
-  factory LazySubstring(data, int start, int length, bool b) {
-    // See comment on [CompactLazySubstring].
-    if (start < 0x100000 && length < 0x200) {
-      int fields = (start << 9);
-      fields = fields | length;
-      fields = fields << 1;
-      if (b) fields |= 1;
-      return new CompactLazySubstring(data, fields);
-    } else {
-      return new FullLazySubstring(data, start, length, b);
-    }
-  }
-}
-
-/**
- * This class encodes [start], [length] and [boolValue] in a single
- * 30 bit integer. It uses 20 bits for [start], which covers source files
- * of 1MB. [length] has 9 bits, which covers 512 characters.
- *
- * The file html_dart2js.dart is currently around 1MB.
- */
-class CompactLazySubstring extends LazySubstring {
-  final data;
-  final int fields;
-
-  CompactLazySubstring(this.data, this.fields) : super.internal();
-
-  int get start => fields >> 10;
-  int get length => (fields >> 1) & 0x1ff;
-  bool get boolValue => (fields & 1) == 1;
-}
-
-class FullLazySubstring extends LazySubstring {
-  final data;
-  final int start;
-  final int length;
-  final bool boolValue;
-  FullLazySubstring(this.data, this.start, this.length, this.boolValue)
-      : super.internal();
-}
-
-bool isUserDefinableOperator(String value) {
-  return
-      isBinaryOperator(value) ||
-      isMinusOperator(value) ||
-      isTernaryOperator(value) ||
-      isUnaryOperator(value);
-}
-
-bool isUnaryOperator(String value) => identical(value, '~');
-
-bool isBinaryOperator(String value) {
-  return
-      (identical(value, '==')) ||
-      (identical(value, '[]')) ||
-      (identical(value, '*')) ||
-      (identical(value, '/')) ||
-      (identical(value, '%')) ||
-      (identical(value, '~/')) ||
-      (identical(value, '+')) ||
-      (identical(value, '<<')) ||
-      (identical(value, '>>')) ||
-      (identical(value, '>=')) ||
-      (identical(value, '>')) ||
-      (identical(value, '<=')) ||
-      (identical(value, '<')) ||
-      (identical(value, '&')) ||
-      (identical(value, '^')) ||
-      (identical(value, '|'));
-}
-
-bool isTernaryOperator(String value) => identical(value, '[]=');
-
-bool isMinusOperator(String value) => identical(value, '-');
-
-class PrecedenceInfo {
-  final String value;
-  final int precedence;
-  final int kind;
-
-  const PrecedenceInfo(this.value, this.precedence, this.kind);
-
-  toString() => 'PrecedenceInfo($value, $precedence, $kind)';
-
-  int get hashCode => computeHashCode(value, precedence, kind);
-}
-
-// TODO(ahe): The following are not tokens in Dart.
-const PrecedenceInfo BACKPING_INFO =
-  const PrecedenceInfo('`', 0, BACKPING_TOKEN);
-const PrecedenceInfo BACKSLASH_INFO =
-  const PrecedenceInfo('\\', 0, BACKSLASH_TOKEN);
-const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO =
-  const PrecedenceInfo('...', 0,
-                       PERIOD_PERIOD_PERIOD_TOKEN);
-
-/**
- * The cascade operator has the lowest precedence of any operator
- * except assignment.
- */
-const int CASCADE_PRECEDENCE = 2;
-const PrecedenceInfo PERIOD_PERIOD_INFO =
-  const PrecedenceInfo('..', CASCADE_PRECEDENCE,
-                       PERIOD_PERIOD_TOKEN);
-
-const PrecedenceInfo BANG_INFO =
-  const PrecedenceInfo('!', 0, BANG_TOKEN);
-const PrecedenceInfo COLON_INFO =
-  const PrecedenceInfo(':', 0, COLON_TOKEN);
-const PrecedenceInfo INDEX_INFO =
-  const PrecedenceInfo('[]', 0, INDEX_TOKEN);
-const PrecedenceInfo MINUS_MINUS_INFO =
-  const PrecedenceInfo('--', POSTFIX_PRECEDENCE,
-                       MINUS_MINUS_TOKEN);
-const PrecedenceInfo PLUS_PLUS_INFO =
-  const PrecedenceInfo('++', POSTFIX_PRECEDENCE,
-                       PLUS_PLUS_TOKEN);
-const PrecedenceInfo TILDE_INFO =
-  const PrecedenceInfo('~', 0, TILDE_TOKEN);
-
-const PrecedenceInfo FUNCTION_INFO =
-  const PrecedenceInfo('=>', 0, FUNCTION_TOKEN);
-const PrecedenceInfo HASH_INFO =
-  const PrecedenceInfo('#', 0, HASH_TOKEN);
-const PrecedenceInfo INDEX_EQ_INFO =
-  const PrecedenceInfo('[]=', 0, INDEX_EQ_TOKEN);
-const PrecedenceInfo SEMICOLON_INFO =
-  const PrecedenceInfo(';', 0, SEMICOLON_TOKEN);
-const PrecedenceInfo COMMA_INFO =
-  const PrecedenceInfo(',', 0, COMMA_TOKEN);
-
-const PrecedenceInfo AT_INFO =
-  const PrecedenceInfo('@', 0, AT_TOKEN);
-
-// Assignment operators.
-const int ASSIGNMENT_PRECEDENCE = 1;
-const PrecedenceInfo AMPERSAND_EQ_INFO =
-  const PrecedenceInfo('&=',
-                       ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN);
-const PrecedenceInfo BAR_EQ_INFO =
-  const PrecedenceInfo('|=',
-                       ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN);
-const PrecedenceInfo CARET_EQ_INFO =
-  const PrecedenceInfo('^=',
-                       ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN);
-const PrecedenceInfo EQ_INFO =
-  const PrecedenceInfo('=',
-                       ASSIGNMENT_PRECEDENCE, EQ_TOKEN);
-const PrecedenceInfo GT_GT_EQ_INFO =
-  const PrecedenceInfo('>>=',
-                       ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN);
-const PrecedenceInfo LT_LT_EQ_INFO =
-  const PrecedenceInfo('<<=',
-                       ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN);
-const PrecedenceInfo MINUS_EQ_INFO =
-  const PrecedenceInfo('-=',
-                       ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN);
-const PrecedenceInfo PERCENT_EQ_INFO =
-  const PrecedenceInfo('%=',
-                       ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN);
-const PrecedenceInfo PLUS_EQ_INFO =
-  const PrecedenceInfo('+=',
-                       ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN);
-const PrecedenceInfo SLASH_EQ_INFO =
-  const PrecedenceInfo('/=',
-                       ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN);
-const PrecedenceInfo STAR_EQ_INFO =
-  const PrecedenceInfo('*=',
-                       ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN);
-const PrecedenceInfo TILDE_SLASH_EQ_INFO =
-  const PrecedenceInfo('~/=',
-                       ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN);
-const PrecedenceInfo QUESTION_QUESTION_EQ_INFO =
-  const PrecedenceInfo('??=',
-                       ASSIGNMENT_PRECEDENCE, QUESTION_QUESTION_EQ_TOKEN);
-
-const PrecedenceInfo QUESTION_INFO =
-  const PrecedenceInfo('?', 3, QUESTION_TOKEN);
-
-const PrecedenceInfo QUESTION_QUESTION_INFO =
-  const PrecedenceInfo('??', 4, QUESTION_QUESTION_TOKEN);
-
-const PrecedenceInfo BAR_BAR_INFO =
-  const PrecedenceInfo('||', 5, BAR_BAR_TOKEN);
-
-const PrecedenceInfo AMPERSAND_AMPERSAND_INFO =
-  const PrecedenceInfo('&&', 6, AMPERSAND_AMPERSAND_TOKEN);
-
-const PrecedenceInfo BAR_INFO =
-  const PrecedenceInfo('|', 9, BAR_TOKEN);
-
-const PrecedenceInfo CARET_INFO =
-  const PrecedenceInfo('^', 10, CARET_TOKEN);
-
-const PrecedenceInfo AMPERSAND_INFO =
-  const PrecedenceInfo('&', 11, AMPERSAND_TOKEN);
-
-// Equality operators.
-const int EQUALITY_PRECEDENCE = 7;
-const PrecedenceInfo BANG_EQ_EQ_INFO =
-  const PrecedenceInfo('!==',
-                       EQUALITY_PRECEDENCE, BANG_EQ_EQ_TOKEN);
-const PrecedenceInfo BANG_EQ_INFO =
-  const PrecedenceInfo('!=',
-                       EQUALITY_PRECEDENCE, BANG_EQ_TOKEN);
-const PrecedenceInfo EQ_EQ_EQ_INFO =
-  const PrecedenceInfo('===',
-                       EQUALITY_PRECEDENCE, EQ_EQ_EQ_TOKEN);
-const PrecedenceInfo EQ_EQ_INFO =
-  const PrecedenceInfo('==',
-                       EQUALITY_PRECEDENCE, EQ_EQ_TOKEN);
-
-// Relational operators.
-const int RELATIONAL_PRECEDENCE = 8;
-const PrecedenceInfo GT_EQ_INFO =
-  const PrecedenceInfo('>=',
-                       RELATIONAL_PRECEDENCE, GT_EQ_TOKEN);
-const PrecedenceInfo GT_INFO =
-  const PrecedenceInfo('>',
-                       RELATIONAL_PRECEDENCE, GT_TOKEN);
-const PrecedenceInfo IS_INFO =
-  const PrecedenceInfo('is',
-                       RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
-const PrecedenceInfo AS_INFO =
-  const PrecedenceInfo('as',
-                       RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
-const PrecedenceInfo LT_EQ_INFO =
-  const PrecedenceInfo('<=',
-                       RELATIONAL_PRECEDENCE, LT_EQ_TOKEN);
-const PrecedenceInfo LT_INFO =
-  const PrecedenceInfo('<',
-                       RELATIONAL_PRECEDENCE, LT_TOKEN);
-
-// Shift operators.
-const PrecedenceInfo GT_GT_INFO =
-  const PrecedenceInfo('>>', 12, GT_GT_TOKEN);
-const PrecedenceInfo LT_LT_INFO =
-  const PrecedenceInfo('<<', 12, LT_LT_TOKEN);
-
-// Additive operators.
-const PrecedenceInfo MINUS_INFO =
-  const PrecedenceInfo('-', 13, MINUS_TOKEN);
-const PrecedenceInfo PLUS_INFO =
-  const PrecedenceInfo('+', 13, PLUS_TOKEN);
-
-// Multiplicative operators.
-const PrecedenceInfo PERCENT_INFO =
-  const PrecedenceInfo('%', 14, PERCENT_TOKEN);
-const PrecedenceInfo SLASH_INFO =
-  const PrecedenceInfo('/', 14, SLASH_TOKEN);
-const PrecedenceInfo STAR_INFO =
-  const PrecedenceInfo('*', 14, STAR_TOKEN);
-const PrecedenceInfo TILDE_SLASH_INFO =
-  const PrecedenceInfo('~/', 14, TILDE_SLASH_TOKEN);
-
-const int POSTFIX_PRECEDENCE = 15;
-const PrecedenceInfo PERIOD_INFO =
-  const PrecedenceInfo('.', POSTFIX_PRECEDENCE,
-                       PERIOD_TOKEN);
-const PrecedenceInfo QUESTION_PERIOD_INFO =
-  const PrecedenceInfo('?.', POSTFIX_PRECEDENCE,
-                       QUESTION_PERIOD_TOKEN);
-
-const PrecedenceInfo KEYWORD_INFO =
-  const PrecedenceInfo('keyword', 0, KEYWORD_TOKEN);
-
-const PrecedenceInfo EOF_INFO =
-  const PrecedenceInfo('EOF', 0, EOF_TOKEN);
-
-const PrecedenceInfo IDENTIFIER_INFO =
-  const PrecedenceInfo('identifier', 0, IDENTIFIER_TOKEN);
-
-const PrecedenceInfo BAD_INPUT_INFO =
-  const PrecedenceInfo('malformed input', 0,
-                       BAD_INPUT_TOKEN);
-
-const PrecedenceInfo OPEN_PAREN_INFO =
-  const PrecedenceInfo('(', POSTFIX_PRECEDENCE,
-                       OPEN_PAREN_TOKEN);
-
-const PrecedenceInfo CLOSE_PAREN_INFO =
-  const PrecedenceInfo(')', 0, CLOSE_PAREN_TOKEN);
-
-const PrecedenceInfo OPEN_CURLY_BRACKET_INFO =
-  const PrecedenceInfo('{', 0, OPEN_CURLY_BRACKET_TOKEN);
-
-const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO =
-  const PrecedenceInfo('}', 0, CLOSE_CURLY_BRACKET_TOKEN);
-
-const PrecedenceInfo INT_INFO =
-  const PrecedenceInfo('int', 0, INT_TOKEN);
-
-const PrecedenceInfo STRING_INFO =
-  const PrecedenceInfo('string', 0, STRING_TOKEN);
-
-const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO =
-  const PrecedenceInfo('[', POSTFIX_PRECEDENCE,
-                       OPEN_SQUARE_BRACKET_TOKEN);
-
-const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO =
-  const PrecedenceInfo(']', 0, CLOSE_SQUARE_BRACKET_TOKEN);
-
-const PrecedenceInfo DOUBLE_INFO =
-  const PrecedenceInfo('double', 0, DOUBLE_TOKEN);
-
-const PrecedenceInfo STRING_INTERPOLATION_INFO =
-  const PrecedenceInfo('\${', 0,
-                       STRING_INTERPOLATION_TOKEN);
-
-const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO =
-  const PrecedenceInfo('\$', 0,
-                       STRING_INTERPOLATION_IDENTIFIER_TOKEN);
-
-const PrecedenceInfo HEXADECIMAL_INFO =
-  const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN);
-
-const PrecedenceInfo COMMENT_INFO =
-  const PrecedenceInfo('comment', 0, COMMENT_TOKEN);
diff --git a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
index d919596..4c42bf7 100644
--- a/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/pkg/compiler/lib/src/scanner/utf8_bytes_scanner.dart
@@ -2,7 +2,22 @@
 // for 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 scanner;
+library dart2js.scanner.utf8;
+
+import 'dart:convert' show
+    UNICODE_BOM_CHARACTER_RUNE,
+    UTF8;
+
+import '../io/source_file.dart' show
+    SourceFile;
+import '../tokens/precedence.dart' show
+    PrecedenceInfo;
+import '../tokens/token.dart' show
+    StringToken,
+    Token;
+
+import 'array_based_scanner.dart' show
+    ArrayBasedScanner;
 
 /**
  * Scanner that reads from a UTF-8 encoded list of bytes and creates tokens
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index bd28c0e..a0ba0a8 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -33,11 +33,12 @@
     TreeElements;
 import '../resolution/scope.dart' show
     Scope;
-import '../scanner/scannerlib.dart' show
-    Token,
-    SEMICOLON_INFO;
 import '../script.dart';
 import '../serialization/constant_serialization.dart';
+import '../tokens/precedence_constants.dart' as Precedence show
+    SEMICOLON_INFO;
+import '../tokens/token.dart' show
+    Token;
 import '../tree/tree.dart';
 import '../util/util.dart' show
     Link,
@@ -484,7 +485,8 @@
           Import tag = new Import(
               builder.keywordToken('import'),
               builder.literalString(library.canonicalUri.toString())
-                  ..getEndToken().next = builder.symbolToken(SEMICOLON_INFO),
+                  ..getEndToken().next =
+                      builder.symbolToken(Precedence.SEMICOLON_INFO),
               null, // prefix
               null, // combinators
               null, // metadata
@@ -494,7 +496,8 @@
           Export tag = new Export(
               builder.keywordToken('export'),
               builder.literalString(library.canonicalUri.toString())
-                  ..getEndToken().next = builder.symbolToken(SEMICOLON_INFO),
+                  ..getEndToken().next =
+                      builder.symbolToken(Precedence.SEMICOLON_INFO),
               null,  // combinators
               null); // metadata
           _libraryDependencies[tag] = library;
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 998ed36..6a2002c 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1924,7 +1924,6 @@
     generateConstant(node.constant, node.sourceInformation);
 
     registry.registerCompileTimeConstant(node.constant);
-    backend.constants.addCompileTimeConstantForEmission(node.constant);
   }
 
   visitNot(HNot node) {
diff --git a/pkg/compiler/lib/src/string_validator.dart b/pkg/compiler/lib/src/string_validator.dart
index 2968528..7171368 100644
--- a/pkg/compiler/lib/src/string_validator.dart
+++ b/pkg/compiler/lib/src/string_validator.dart
@@ -10,7 +10,7 @@
 
 import 'diagnostics/diagnostic_listener.dart';
 import 'diagnostics/messages.dart' show MessageKind;
-import 'scanner/scannerlib.dart' show Token;
+import 'tokens/token.dart' show Token;
 import 'tree/tree.dart';
 import 'util/characters.dart';
 
diff --git a/pkg/compiler/lib/src/scanner/keyword.dart b/pkg/compiler/lib/src/tokens/keyword.dart
similarity index 86%
rename from pkg/compiler/lib/src/scanner/keyword.dart
rename to pkg/compiler/lib/src/tokens/keyword.dart
index 804a0ee..ce1bc87 100644
--- a/pkg/compiler/lib/src/scanner/keyword.dart
+++ b/pkg/compiler/lib/src/tokens/keyword.dart
@@ -2,7 +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.
 
-part of scanner;
+library dart2js.tokens.keywords;
+
+import '../util/characters.dart' as Characters show
+    $a;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+import 'precedence_constants.dart' as Precedence show
+    AS_INFO,
+    IS_INFO,
+    KEYWORD_INFO;
 
 /**
  * A keyword in the Dart programming language.
@@ -44,10 +54,10 @@
 
       // TODO(ahe): Don't think this is a reserved word.
       // See: http://dartbug.com/5579
-      const Keyword("is", info: IS_INFO),
+      const Keyword("is", info: Precedence.IS_INFO),
 
       const Keyword("abstract", isBuiltIn: true),
-      const Keyword("as", info: AS_INFO, isBuiltIn: true),
+      const Keyword("as", info: Precedence.AS_INFO, isBuiltIn: true),
       const Keyword("dynamic", isBuiltIn: true),
       const Keyword("export", isBuiltIn: true),
       const Keyword("external", isBuiltIn: true),
@@ -90,7 +100,7 @@
   const Keyword(this.syntax,
                 {this.isPseudo: false,
                  this.isBuiltIn: false,
-                 this.info: KEYWORD_INFO});
+                 this.info: Precedence.KEYWORD_INFO});
 
   static Map<String, Keyword> computeKeywordMap() {
     Map<String, Keyword> result = new Map<String, Keyword>();
@@ -141,10 +151,10 @@
         int c = strings[i].codeUnitAt(start);
         if (chunk != c) {
           if (chunkStart != -1) {
-            assert(result[chunk - $a] == null);
-            result[chunk - $a] = computeKeywordStateTable(start + 1, strings,
-                                                          chunkStart,
-                                                          i - chunkStart);
+            assert(result[chunk - Characters.$a] == null);
+            result[chunk - Characters.$a] =
+                computeKeywordStateTable(
+                    start + 1, strings, chunkStart, i - chunkStart);
           }
           chunkStart = i;
           chunk = c;
@@ -152,8 +162,8 @@
       }
     }
     if (chunkStart != -1) {
-      assert(result[chunk - $a] == null);
-      result[chunk - $a] =
+      assert(result[chunk - Characters.$a] == null);
+      result[chunk - Characters.$a] =
         computeKeywordStateTable(start + 1, strings, chunkStart,
                                  offset + length - chunkStart);
     } else {
@@ -177,7 +187,7 @@
   ArrayKeywordState(List<KeywordState> this.table, String syntax)
     : super((syntax == null) ? null : Keyword.keywords[syntax]);
 
-  KeywordState next(int c) => table[c - $a];
+  KeywordState next(int c) => table[c - Characters.$a];
 
   String toString() {
     StringBuffer sb = new StringBuffer();
@@ -190,7 +200,8 @@
     List<KeywordState> foo = table;
     for (int i = 0; i < foo.length; i++) {
       if (foo[i] != null) {
-        sb.write("${new String.fromCharCodes([i + $a])}: ${foo[i]}; ");
+        sb.write("${new String.fromCharCodes([i + Characters.$a])}: "
+                 "${foo[i]}; ");
       }
     }
     sb.write("]");
diff --git a/pkg/compiler/lib/src/tokens/precedence.dart b/pkg/compiler/lib/src/tokens/precedence.dart
new file mode 100644
index 0000000..1183a0b
--- /dev/null
+++ b/pkg/compiler/lib/src/tokens/precedence.dart
@@ -0,0 +1,20 @@
+// 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 dart2js.tokens.precedence;
+
+import '../util/util.dart' show
+    computeHashCode;
+
+class PrecedenceInfo {
+  final String value;
+  final int precedence;
+  final int kind;
+
+  const PrecedenceInfo(this.value, this.precedence, this.kind);
+
+  toString() => 'PrecedenceInfo($value, $precedence, $kind)';
+
+  int get hashCode => computeHashCode(value, precedence, kind);
+}
diff --git a/pkg/compiler/lib/src/tokens/precedence_constants.dart b/pkg/compiler/lib/src/tokens/precedence_constants.dart
new file mode 100644
index 0000000..f2e44f2
--- /dev/null
+++ b/pkg/compiler/lib/src/tokens/precedence_constants.dart
@@ -0,0 +1,241 @@
+// 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 dart2js.tokens.precedence.constants;
+
+import 'precedence.dart' show
+    PrecedenceInfo;
+import 'token_constants.dart';
+
+// TODO(ahe): The following are not tokens in Dart.
+const PrecedenceInfo BACKPING_INFO =
+  const PrecedenceInfo('`', 0, BACKPING_TOKEN);
+const PrecedenceInfo BACKSLASH_INFO =
+  const PrecedenceInfo('\\', 0, BACKSLASH_TOKEN);
+const PrecedenceInfo PERIOD_PERIOD_PERIOD_INFO =
+  const PrecedenceInfo('...', 0,
+                       PERIOD_PERIOD_PERIOD_TOKEN);
+
+/**
+ * The cascade operator has the lowest precedence of any operator
+ * except assignment.
+ */
+const int CASCADE_PRECEDENCE = 2;
+const PrecedenceInfo PERIOD_PERIOD_INFO =
+  const PrecedenceInfo('..', CASCADE_PRECEDENCE,
+                       PERIOD_PERIOD_TOKEN);
+
+const PrecedenceInfo BANG_INFO =
+  const PrecedenceInfo('!', 0, BANG_TOKEN);
+const PrecedenceInfo COLON_INFO =
+  const PrecedenceInfo(':', 0, COLON_TOKEN);
+const PrecedenceInfo INDEX_INFO =
+  const PrecedenceInfo('[]', 0, INDEX_TOKEN);
+const PrecedenceInfo MINUS_MINUS_INFO =
+  const PrecedenceInfo('--', POSTFIX_PRECEDENCE,
+                       MINUS_MINUS_TOKEN);
+const PrecedenceInfo PLUS_PLUS_INFO =
+  const PrecedenceInfo('++', POSTFIX_PRECEDENCE,
+                       PLUS_PLUS_TOKEN);
+const PrecedenceInfo TILDE_INFO =
+  const PrecedenceInfo('~', 0, TILDE_TOKEN);
+
+const PrecedenceInfo FUNCTION_INFO =
+  const PrecedenceInfo('=>', 0, FUNCTION_TOKEN);
+const PrecedenceInfo HASH_INFO =
+  const PrecedenceInfo('#', 0, HASH_TOKEN);
+const PrecedenceInfo INDEX_EQ_INFO =
+  const PrecedenceInfo('[]=', 0, INDEX_EQ_TOKEN);
+const PrecedenceInfo SEMICOLON_INFO =
+  const PrecedenceInfo(';', 0, SEMICOLON_TOKEN);
+const PrecedenceInfo COMMA_INFO =
+  const PrecedenceInfo(',', 0, COMMA_TOKEN);
+
+const PrecedenceInfo AT_INFO =
+  const PrecedenceInfo('@', 0, AT_TOKEN);
+
+// Assignment operators.
+const int ASSIGNMENT_PRECEDENCE = 1;
+const PrecedenceInfo AMPERSAND_EQ_INFO =
+  const PrecedenceInfo('&=',
+                       ASSIGNMENT_PRECEDENCE, AMPERSAND_EQ_TOKEN);
+const PrecedenceInfo BAR_EQ_INFO =
+  const PrecedenceInfo('|=',
+                       ASSIGNMENT_PRECEDENCE, BAR_EQ_TOKEN);
+const PrecedenceInfo CARET_EQ_INFO =
+  const PrecedenceInfo('^=',
+                       ASSIGNMENT_PRECEDENCE, CARET_EQ_TOKEN);
+const PrecedenceInfo EQ_INFO =
+  const PrecedenceInfo('=',
+                       ASSIGNMENT_PRECEDENCE, EQ_TOKEN);
+const PrecedenceInfo GT_GT_EQ_INFO =
+  const PrecedenceInfo('>>=',
+                       ASSIGNMENT_PRECEDENCE, GT_GT_EQ_TOKEN);
+const PrecedenceInfo LT_LT_EQ_INFO =
+  const PrecedenceInfo('<<=',
+                       ASSIGNMENT_PRECEDENCE, LT_LT_EQ_TOKEN);
+const PrecedenceInfo MINUS_EQ_INFO =
+  const PrecedenceInfo('-=',
+                       ASSIGNMENT_PRECEDENCE, MINUS_EQ_TOKEN);
+const PrecedenceInfo PERCENT_EQ_INFO =
+  const PrecedenceInfo('%=',
+                       ASSIGNMENT_PRECEDENCE, PERCENT_EQ_TOKEN);
+const PrecedenceInfo PLUS_EQ_INFO =
+  const PrecedenceInfo('+=',
+                       ASSIGNMENT_PRECEDENCE, PLUS_EQ_TOKEN);
+const PrecedenceInfo SLASH_EQ_INFO =
+  const PrecedenceInfo('/=',
+                       ASSIGNMENT_PRECEDENCE, SLASH_EQ_TOKEN);
+const PrecedenceInfo STAR_EQ_INFO =
+  const PrecedenceInfo('*=',
+                       ASSIGNMENT_PRECEDENCE, STAR_EQ_TOKEN);
+const PrecedenceInfo TILDE_SLASH_EQ_INFO =
+  const PrecedenceInfo('~/=',
+                       ASSIGNMENT_PRECEDENCE, TILDE_SLASH_EQ_TOKEN);
+const PrecedenceInfo QUESTION_QUESTION_EQ_INFO =
+  const PrecedenceInfo('??=',
+                       ASSIGNMENT_PRECEDENCE, QUESTION_QUESTION_EQ_TOKEN);
+
+const PrecedenceInfo QUESTION_INFO =
+  const PrecedenceInfo('?', 3, QUESTION_TOKEN);
+
+const PrecedenceInfo QUESTION_QUESTION_INFO =
+  const PrecedenceInfo('??', 4, QUESTION_QUESTION_TOKEN);
+
+const PrecedenceInfo BAR_BAR_INFO =
+  const PrecedenceInfo('||', 5, BAR_BAR_TOKEN);
+
+const PrecedenceInfo AMPERSAND_AMPERSAND_INFO =
+  const PrecedenceInfo('&&', 6, AMPERSAND_AMPERSAND_TOKEN);
+
+const PrecedenceInfo BAR_INFO =
+  const PrecedenceInfo('|', 9, BAR_TOKEN);
+
+const PrecedenceInfo CARET_INFO =
+  const PrecedenceInfo('^', 10, CARET_TOKEN);
+
+const PrecedenceInfo AMPERSAND_INFO =
+  const PrecedenceInfo('&', 11, AMPERSAND_TOKEN);
+
+// Equality operators.
+const int EQUALITY_PRECEDENCE = 7;
+const PrecedenceInfo BANG_EQ_EQ_INFO =
+  const PrecedenceInfo('!==',
+                       EQUALITY_PRECEDENCE, BANG_EQ_EQ_TOKEN);
+const PrecedenceInfo BANG_EQ_INFO =
+  const PrecedenceInfo('!=',
+                       EQUALITY_PRECEDENCE, BANG_EQ_TOKEN);
+const PrecedenceInfo EQ_EQ_EQ_INFO =
+  const PrecedenceInfo('===',
+                       EQUALITY_PRECEDENCE, EQ_EQ_EQ_TOKEN);
+const PrecedenceInfo EQ_EQ_INFO =
+  const PrecedenceInfo('==',
+                       EQUALITY_PRECEDENCE, EQ_EQ_TOKEN);
+
+// Relational operators.
+const int RELATIONAL_PRECEDENCE = 8;
+const PrecedenceInfo GT_EQ_INFO =
+  const PrecedenceInfo('>=',
+                       RELATIONAL_PRECEDENCE, GT_EQ_TOKEN);
+const PrecedenceInfo GT_INFO =
+  const PrecedenceInfo('>',
+                       RELATIONAL_PRECEDENCE, GT_TOKEN);
+const PrecedenceInfo IS_INFO =
+  const PrecedenceInfo('is',
+                       RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
+const PrecedenceInfo AS_INFO =
+  const PrecedenceInfo('as',
+                       RELATIONAL_PRECEDENCE, KEYWORD_TOKEN);
+const PrecedenceInfo LT_EQ_INFO =
+  const PrecedenceInfo('<=',
+                       RELATIONAL_PRECEDENCE, LT_EQ_TOKEN);
+const PrecedenceInfo LT_INFO =
+  const PrecedenceInfo('<',
+                       RELATIONAL_PRECEDENCE, LT_TOKEN);
+
+// Shift operators.
+const PrecedenceInfo GT_GT_INFO =
+  const PrecedenceInfo('>>', 12, GT_GT_TOKEN);
+const PrecedenceInfo LT_LT_INFO =
+  const PrecedenceInfo('<<', 12, LT_LT_TOKEN);
+
+// Additive operators.
+const PrecedenceInfo MINUS_INFO =
+  const PrecedenceInfo('-', 13, MINUS_TOKEN);
+const PrecedenceInfo PLUS_INFO =
+  const PrecedenceInfo('+', 13, PLUS_TOKEN);
+
+// Multiplicative operators.
+const PrecedenceInfo PERCENT_INFO =
+  const PrecedenceInfo('%', 14, PERCENT_TOKEN);
+const PrecedenceInfo SLASH_INFO =
+  const PrecedenceInfo('/', 14, SLASH_TOKEN);
+const PrecedenceInfo STAR_INFO =
+  const PrecedenceInfo('*', 14, STAR_TOKEN);
+const PrecedenceInfo TILDE_SLASH_INFO =
+  const PrecedenceInfo('~/', 14, TILDE_SLASH_TOKEN);
+
+const int POSTFIX_PRECEDENCE = 15;
+const PrecedenceInfo PERIOD_INFO =
+  const PrecedenceInfo('.', POSTFIX_PRECEDENCE,
+                       PERIOD_TOKEN);
+const PrecedenceInfo QUESTION_PERIOD_INFO =
+  const PrecedenceInfo('?.', POSTFIX_PRECEDENCE,
+                       QUESTION_PERIOD_TOKEN);
+
+const PrecedenceInfo KEYWORD_INFO =
+  const PrecedenceInfo('keyword', 0, KEYWORD_TOKEN);
+
+const PrecedenceInfo EOF_INFO =
+  const PrecedenceInfo('EOF', 0, EOF_TOKEN);
+
+const PrecedenceInfo IDENTIFIER_INFO =
+  const PrecedenceInfo('identifier', 0, IDENTIFIER_TOKEN);
+
+const PrecedenceInfo BAD_INPUT_INFO =
+  const PrecedenceInfo('malformed input', 0,
+                       BAD_INPUT_TOKEN);
+
+const PrecedenceInfo OPEN_PAREN_INFO =
+  const PrecedenceInfo('(', POSTFIX_PRECEDENCE,
+                       OPEN_PAREN_TOKEN);
+
+const PrecedenceInfo CLOSE_PAREN_INFO =
+  const PrecedenceInfo(')', 0, CLOSE_PAREN_TOKEN);
+
+const PrecedenceInfo OPEN_CURLY_BRACKET_INFO =
+  const PrecedenceInfo('{', 0, OPEN_CURLY_BRACKET_TOKEN);
+
+const PrecedenceInfo CLOSE_CURLY_BRACKET_INFO =
+  const PrecedenceInfo('}', 0, CLOSE_CURLY_BRACKET_TOKEN);
+
+const PrecedenceInfo INT_INFO =
+  const PrecedenceInfo('int', 0, INT_TOKEN);
+
+const PrecedenceInfo STRING_INFO =
+  const PrecedenceInfo('string', 0, STRING_TOKEN);
+
+const PrecedenceInfo OPEN_SQUARE_BRACKET_INFO =
+  const PrecedenceInfo('[', POSTFIX_PRECEDENCE,
+                       OPEN_SQUARE_BRACKET_TOKEN);
+
+const PrecedenceInfo CLOSE_SQUARE_BRACKET_INFO =
+  const PrecedenceInfo(']', 0, CLOSE_SQUARE_BRACKET_TOKEN);
+
+const PrecedenceInfo DOUBLE_INFO =
+  const PrecedenceInfo('double', 0, DOUBLE_TOKEN);
+
+const PrecedenceInfo STRING_INTERPOLATION_INFO =
+  const PrecedenceInfo('\${', 0,
+                       STRING_INTERPOLATION_TOKEN);
+
+const PrecedenceInfo STRING_INTERPOLATION_IDENTIFIER_INFO =
+  const PrecedenceInfo('\$', 0,
+                       STRING_INTERPOLATION_IDENTIFIER_TOKEN);
+
+const PrecedenceInfo HEXADECIMAL_INFO =
+  const PrecedenceInfo('hexadecimal', 0, HEXADECIMAL_TOKEN);
+
+const PrecedenceInfo COMMENT_INFO =
+  const PrecedenceInfo('comment', 0, COMMENT_TOKEN);
diff --git a/pkg/compiler/lib/src/tokens/token.dart b/pkg/compiler/lib/src/tokens/token.dart
new file mode 100644
index 0000000..e656f9e
--- /dev/null
+++ b/pkg/compiler/lib/src/tokens/token.dart
@@ -0,0 +1,442 @@
+// 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.
+
+library dart2js.tokens;
+
+import 'dart:convert' show
+    UTF8;
+import 'dart:collection' show
+    HashSet;
+
+import '../diagnostics/spannable.dart' show
+    Spannable,
+    SpannableAssertionFailure;
+import '../util/util.dart' show
+    computeHashCode;
+
+import 'keyword.dart' show
+    Keyword;
+import 'precedence.dart' show
+    PrecedenceInfo;
+import 'precedence_constants.dart' as Precedence show
+    BAD_INPUT_INFO;
+import 'token_constants.dart' as Tokens show
+    IDENTIFIER_TOKEN;
+
+/**
+ * A token that doubles as a linked list.
+ */
+abstract class Token implements Spannable {
+  /**
+   * The character offset of the start of this token within the source text.
+   */
+  final int charOffset;
+
+  Token(this.charOffset);
+
+  /**
+   * The next token in the token stream.
+   */
+  Token next;
+
+  /**
+   * The precedence info for this token. [info] determines the kind and the
+   * precedence level of this token.
+   *
+   * Defined as getter to save a field in the [KeywordToken] subclass.
+   */
+  PrecedenceInfo get info;
+
+  /**
+   * The string represented by this token, a substring of the source code.
+   *
+   * For [StringToken]s the [value] includes the quotes, explicit escapes, etc.
+   */
+  String get value;
+
+  /**
+   * For symbol and keyword tokens, returns the string value represented by this
+   * token. For [StringToken]s this method returns [:null:].
+   *
+   * For [SymbolToken]s and [KeywordToken]s, the string value is a compile-time
+   * constant originating in the [PrecedenceInfo] or in the [Keyword] instance.
+   * This allows testing for keywords and symbols using [:identical:], e.g.,
+   * [:identical('class', token.value):].
+   *
+   * Note that returning [:null:] for string tokens is important to identify
+   * symbols and keywords, we cannot use [value] instead. The string literal
+   *   "$a($b"
+   * produces ..., SymbolToken($), StringToken(a), StringToken((), ...
+   *
+   * After parsing the identifier 'a', the parser tests for a function
+   * declaration using [:identical(next.stringValue, '('):], which (rightfully)
+   * returns false because stringValue returns [:null:].
+   */
+  String get stringValue;
+
+  /**
+   * The kind enum of this token as determined by its [info].
+   */
+  int get kind => info.kind;
+
+  /**
+   * The precedence level for this token.
+   */
+  int get precedence => info.precedence;
+
+  /**
+   * True if this token is an identifier. Some keywords allowed as identifiers,
+   * see implementation in [KeywordToken].
+   */
+  bool isIdentifier();
+
+  /**
+   * Returns a textual representation of this token to be used for debugging
+   * purposes. The resulting string might contain information about the
+   * structure of the token, for example 'StringToken(foo)' for the identifier
+   * token 'foo'.
+   *
+   * Use [value] for the text actually parsed by the token.
+   */
+  String toString();
+
+  /**
+   * The number of characters parsed by this token.
+   */
+  int get charCount {
+    if (info == Precedence.BAD_INPUT_INFO) {
+      // This is a token that wraps around an error message. Return 1
+      // instead of the size of the length of the error message.
+      return 1;
+    } else {
+      return value.length;
+    }
+  }
+
+  int get hashCode => computeHashCode(charOffset, info, value);
+}
+
+/// A pair of tokens marking the beginning and the end of a span. Use for error
+/// reporting.
+class TokenPair implements Spannable {
+  final Token begin;
+  final Token end;
+
+  TokenPair(this.begin, this.end);
+}
+
+/**
+ * A [SymbolToken] represents the symbol in its precendence info.
+ * Also used for end of file with EOF_INFO.
+ */
+class SymbolToken extends Token {
+
+  final PrecedenceInfo info;
+
+  SymbolToken(this.info, int charOffset) : super(charOffset);
+
+  String get value => info.value;
+
+  String get stringValue => info.value;
+
+  bool isIdentifier() => false;
+
+  String toString() => "SymbolToken($value)";
+}
+
+/**
+ * A [BeginGroupToken] represents a symbol that may be the beginning of
+ * a pair of brackets, i.e., ( { [ < or ${
+ * The [endGroup] token points to the matching closing bracked in case
+ * it can be identified during scanning.
+ */
+class BeginGroupToken extends SymbolToken {
+  Token endGroup;
+
+  BeginGroupToken(PrecedenceInfo info, int charOffset)
+      : super(info, charOffset);
+}
+
+/**
+ * A keyword token.
+ */
+class KeywordToken extends Token {
+  final Keyword keyword;
+
+  KeywordToken(this.keyword, int charOffset) : super(charOffset);
+
+  PrecedenceInfo get info => keyword.info;
+
+  String get value => keyword.syntax;
+
+  String get stringValue => keyword.syntax;
+
+  bool isIdentifier() => keyword.isPseudo || keyword.isBuiltIn;
+
+  String toString() => "KeywordToken($value)";
+}
+
+abstract class ErrorToken extends Token {
+  ErrorToken(int charOffset)
+      : super(charOffset);
+
+  PrecedenceInfo get info => Precedence.BAD_INPUT_INFO;
+
+  String get value {
+    throw new SpannableAssertionFailure(this, assertionMessage);
+  }
+
+  String get stringValue => null;
+
+  bool isIdentifier() => false;
+
+  String get assertionMessage;
+}
+
+class BadInputToken extends ErrorToken {
+  final int character;
+
+  BadInputToken(this.character, int charOffset)
+      : super(charOffset);
+
+  String toString() => "BadInputToken($character)";
+
+  String get assertionMessage {
+    return 'Character U+${character.toRadixString(16)} not allowed here.';
+  }
+}
+
+class UnterminatedToken extends ErrorToken {
+  final String start;
+  final int endOffset;
+
+  UnterminatedToken(this.start, int charOffset, this.endOffset)
+      : super(charOffset);
+
+  String toString() => "UnterminatedToken($start)";
+
+  String get assertionMessage => "'$start' isn't terminated.";
+
+  int get charCount => endOffset - charOffset;
+}
+
+class UnmatchedToken extends ErrorToken {
+  final BeginGroupToken begin;
+
+  UnmatchedToken(BeginGroupToken begin)
+      : this.begin = begin,
+        super(begin.charOffset);
+
+  String toString() => "UnmatchedToken(${begin.value})";
+
+  String get assertionMessage => "'$begin' isn't closed.";
+}
+
+/**
+ * A String-valued token. Represents identifiers, string literals,
+ * number literals, comments, and error tokens, using the corresponding
+ * precedence info.
+ */
+class StringToken extends Token {
+  /**
+   * The length threshold above which substring tokens are computed lazily.
+   *
+   * For string tokens that are substrings of the program source, the actual
+   * substring extraction is performed lazily. This is beneficial because
+   * not all scanned code is actually used. For unused parts, the substrings
+   * are never computed and allocated.
+   */
+  static const int LAZY_THRESHOLD = 4;
+
+  var /* String | LazySubtring */ valueOrLazySubstring;
+
+  final PrecedenceInfo info;
+
+  /**
+   * Creates a non-lazy string token. If [canonicalize] is true, the string
+   * is canonicalized before the token is created.
+   */
+  StringToken.fromString(this.info, String value, int charOffset,
+                         {bool canonicalize : false})
+      : valueOrLazySubstring = canonicalizedString(value, canonicalize),
+        super(charOffset);
+
+  /**
+   * Creates a lazy string token. If [canonicalize] is true, the string
+   * is canonicalized before the token is created.
+   */
+  StringToken.fromSubstring(this.info, String data, int start, int end,
+                            int charOffset, {bool canonicalize : false})
+      : super(charOffset) {
+    int length = end - start;
+    if (length <= LAZY_THRESHOLD) {
+      valueOrLazySubstring = canonicalizedString(data.substring(start, end),
+                                                 canonicalize);
+    } else {
+      valueOrLazySubstring =
+          new LazySubstring(data, start, length, canonicalize);
+    }
+  }
+
+  /**
+   * Creates a lazy string token. If [asciiOnly] is false, the byte array
+   * is passed through a UTF-8 decoder.
+   */
+  StringToken.fromUtf8Bytes(this.info, List<int> data, int start, int end,
+                            bool asciiOnly, int charOffset)
+      : super(charOffset) {
+    int length = end - start;
+    if (length <= LAZY_THRESHOLD) {
+      valueOrLazySubstring = decodeUtf8(data, start, end, asciiOnly);
+    } else {
+      valueOrLazySubstring = new LazySubstring(data, start, length, asciiOnly);
+    }
+  }
+
+  String get value {
+    if (valueOrLazySubstring is String) {
+      return valueOrLazySubstring;
+    } else {
+      assert(valueOrLazySubstring is LazySubstring);
+      var data = valueOrLazySubstring.data;
+      int start = valueOrLazySubstring.start;
+      int end = start + valueOrLazySubstring.length;
+      if (data is String) {
+        valueOrLazySubstring = canonicalizedString(
+            data.substring(start, end), valueOrLazySubstring.boolValue);
+      } else {
+        valueOrLazySubstring = decodeUtf8(
+            data, start, end, valueOrLazySubstring.boolValue);
+      }
+      return valueOrLazySubstring;
+    }
+  }
+
+  /// See [Token.stringValue] for an explanation.
+  String get stringValue => null;
+
+  bool isIdentifier() => identical(kind, Tokens.IDENTIFIER_TOKEN);
+
+  String toString() => "StringToken($value)";
+
+  static final HashSet<String> canonicalizedSubstrings =
+      new HashSet<String>();
+
+  static String canonicalizedString(String s, bool canonicalize) {
+    if (!canonicalize) return s;
+    var result = canonicalizedSubstrings.lookup(s);
+    if (result != null) return result;
+    canonicalizedSubstrings.add(s);
+    return s;
+  }
+
+  static String decodeUtf8(List<int> data, int start, int end, bool asciiOnly) {
+    var s;
+    if (asciiOnly) {
+      s = new String.fromCharCodes(data, start, end);
+    } else {
+      s = UTF8.decoder.convert(data, start, end);
+    }
+    return canonicalizedString(s, true);
+  }
+}
+
+/**
+ * This class represents the necessary information to compute a substring
+ * lazily. The substring can either originate from a string or from
+ * a [:List<int>:] of UTF-8 bytes.
+ */
+abstract class LazySubstring {
+  /** The original data, either a string or a List<int> */
+  get data;
+
+  int get start;
+  int get length;
+
+  /**
+   * If this substring is based on a String, the [boolValue] indicates wheter
+   * the resulting substring should be canonicalized.
+   *
+   * For substrings based on a byte array, the [boolValue] is true if the
+   * array only holds ASCII characters. The resulting substring will be
+   * canonicalized after decoding.
+   */
+  bool get boolValue;
+
+  LazySubstring.internal();
+
+  factory LazySubstring(data, int start, int length, bool b) {
+    // See comment on [CompactLazySubstring].
+    if (start < 0x100000 && length < 0x200) {
+      int fields = (start << 9);
+      fields = fields | length;
+      fields = fields << 1;
+      if (b) fields |= 1;
+      return new CompactLazySubstring(data, fields);
+    } else {
+      return new FullLazySubstring(data, start, length, b);
+    }
+  }
+}
+
+/**
+ * This class encodes [start], [length] and [boolValue] in a single
+ * 30 bit integer. It uses 20 bits for [start], which covers source files
+ * of 1MB. [length] has 9 bits, which covers 512 characters.
+ *
+ * The file html_dart2js.dart is currently around 1MB.
+ */
+class CompactLazySubstring extends LazySubstring {
+  final data;
+  final int fields;
+
+  CompactLazySubstring(this.data, this.fields) : super.internal();
+
+  int get start => fields >> 10;
+  int get length => (fields >> 1) & 0x1ff;
+  bool get boolValue => (fields & 1) == 1;
+}
+
+class FullLazySubstring extends LazySubstring {
+  final data;
+  final int start;
+  final int length;
+  final bool boolValue;
+  FullLazySubstring(this.data, this.start, this.length, this.boolValue)
+      : super.internal();
+}
+
+bool isUserDefinableOperator(String value) {
+  return
+      isBinaryOperator(value) ||
+      isMinusOperator(value) ||
+      isTernaryOperator(value) ||
+      isUnaryOperator(value);
+}
+
+bool isUnaryOperator(String value) => identical(value, '~');
+
+bool isBinaryOperator(String value) {
+  return
+      (identical(value, '==')) ||
+      (identical(value, '[]')) ||
+      (identical(value, '*')) ||
+      (identical(value, '/')) ||
+      (identical(value, '%')) ||
+      (identical(value, '~/')) ||
+      (identical(value, '+')) ||
+      (identical(value, '<<')) ||
+      (identical(value, '>>')) ||
+      (identical(value, '>=')) ||
+      (identical(value, '>')) ||
+      (identical(value, '<=')) ||
+      (identical(value, '<')) ||
+      (identical(value, '&')) ||
+      (identical(value, '^')) ||
+      (identical(value, '|'));
+}
+
+bool isTernaryOperator(String value) => identical(value, '[]=');
+
+bool isMinusOperator(String value) => identical(value, '-');
diff --git a/pkg/compiler/lib/src/tokens/token_constants.dart b/pkg/compiler/lib/src/tokens/token_constants.dart
new file mode 100644
index 0000000..c1078f0
--- /dev/null
+++ b/pkg/compiler/lib/src/tokens/token_constants.dart
@@ -0,0 +1,82 @@
+// 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 dart2js.tokens.constants;
+
+import '../util/characters.dart';
+
+const int EOF_TOKEN = 0;
+
+const int KEYWORD_TOKEN = $k;
+const int IDENTIFIER_TOKEN = $a;
+const int BAD_INPUT_TOKEN = $X;
+const int DOUBLE_TOKEN = $d;
+const int INT_TOKEN = $i;
+const int HEXADECIMAL_TOKEN = $x;
+const int STRING_TOKEN = $SQ;
+
+const int AMPERSAND_TOKEN = $AMPERSAND;
+const int BACKPING_TOKEN = $BACKPING;
+const int BACKSLASH_TOKEN = $BACKSLASH;
+const int BANG_TOKEN = $BANG;
+const int BAR_TOKEN = $BAR;
+const int COLON_TOKEN = $COLON;
+const int COMMA_TOKEN = $COMMA;
+const int EQ_TOKEN = $EQ;
+const int GT_TOKEN = $GT;
+const int HASH_TOKEN = $HASH;
+const int OPEN_CURLY_BRACKET_TOKEN = $OPEN_CURLY_BRACKET;
+const int OPEN_SQUARE_BRACKET_TOKEN = $OPEN_SQUARE_BRACKET;
+const int OPEN_PAREN_TOKEN = $OPEN_PAREN;
+const int LT_TOKEN = $LT;
+const int MINUS_TOKEN = $MINUS;
+const int PERIOD_TOKEN = $PERIOD;
+const int PLUS_TOKEN = $PLUS;
+const int QUESTION_TOKEN = $QUESTION;
+const int AT_TOKEN = $AT;
+const int CLOSE_CURLY_BRACKET_TOKEN = $CLOSE_CURLY_BRACKET;
+const int CLOSE_SQUARE_BRACKET_TOKEN = $CLOSE_SQUARE_BRACKET;
+const int CLOSE_PAREN_TOKEN = $CLOSE_PAREN;
+const int SEMICOLON_TOKEN = $SEMICOLON;
+const int SLASH_TOKEN = $SLASH;
+const int TILDE_TOKEN = $TILDE;
+const int STAR_TOKEN = $STAR;
+const int PERCENT_TOKEN = $PERCENT;
+const int CARET_TOKEN = $CARET;
+
+const int STRING_INTERPOLATION_TOKEN = 128;
+const int LT_EQ_TOKEN = STRING_INTERPOLATION_TOKEN + 1;
+const int FUNCTION_TOKEN = LT_EQ_TOKEN + 1;
+const int SLASH_EQ_TOKEN = FUNCTION_TOKEN + 1;
+const int PERIOD_PERIOD_PERIOD_TOKEN = SLASH_EQ_TOKEN + 1;
+const int PERIOD_PERIOD_TOKEN = PERIOD_PERIOD_PERIOD_TOKEN + 1;
+const int EQ_EQ_EQ_TOKEN = PERIOD_PERIOD_TOKEN + 1;
+const int EQ_EQ_TOKEN = EQ_EQ_EQ_TOKEN + 1;
+const int LT_LT_EQ_TOKEN = EQ_EQ_TOKEN + 1;
+const int LT_LT_TOKEN = LT_LT_EQ_TOKEN + 1;
+const int GT_EQ_TOKEN = LT_LT_TOKEN + 1;
+const int GT_GT_EQ_TOKEN = GT_EQ_TOKEN + 1;
+const int INDEX_EQ_TOKEN = GT_GT_EQ_TOKEN + 1;
+const int INDEX_TOKEN = INDEX_EQ_TOKEN + 1;
+const int BANG_EQ_EQ_TOKEN = INDEX_TOKEN + 1;
+const int BANG_EQ_TOKEN = BANG_EQ_EQ_TOKEN + 1;
+const int AMPERSAND_AMPERSAND_TOKEN = BANG_EQ_TOKEN + 1;
+const int AMPERSAND_EQ_TOKEN = AMPERSAND_AMPERSAND_TOKEN + 1;
+const int BAR_BAR_TOKEN = AMPERSAND_EQ_TOKEN + 1;
+const int BAR_EQ_TOKEN = BAR_BAR_TOKEN + 1;
+const int STAR_EQ_TOKEN = BAR_EQ_TOKEN + 1;
+const int PLUS_PLUS_TOKEN = STAR_EQ_TOKEN + 1;
+const int PLUS_EQ_TOKEN = PLUS_PLUS_TOKEN + 1;
+const int MINUS_MINUS_TOKEN = PLUS_EQ_TOKEN + 1;
+const int MINUS_EQ_TOKEN = MINUS_MINUS_TOKEN + 1;
+const int TILDE_SLASH_EQ_TOKEN = MINUS_EQ_TOKEN + 1;
+const int TILDE_SLASH_TOKEN = TILDE_SLASH_EQ_TOKEN + 1;
+const int PERCENT_EQ_TOKEN = TILDE_SLASH_TOKEN + 1;
+const int GT_GT_TOKEN = PERCENT_EQ_TOKEN + 1;
+const int CARET_EQ_TOKEN = GT_GT_TOKEN + 1;
+const int COMMENT_TOKEN = CARET_EQ_TOKEN + 1;
+const int STRING_INTERPOLATION_IDENTIFIER_TOKEN = COMMENT_TOKEN + 1;
+const int QUESTION_PERIOD_TOKEN = STRING_INTERPOLATION_IDENTIFIER_TOKEN + 1;
+const int QUESTION_QUESTION_TOKEN = QUESTION_PERIOD_TOKEN + 1;
+const int QUESTION_QUESTION_EQ_TOKEN = QUESTION_QUESTION_TOKEN + 1;
diff --git a/pkg/compiler/lib/src/scanner/token_map.dart b/pkg/compiler/lib/src/tokens/token_map.dart
similarity index 97%
rename from pkg/compiler/lib/src/scanner/token_map.dart
rename to pkg/compiler/lib/src/tokens/token_map.dart
index 8e4c53e..55b4d30 100644
--- a/pkg/compiler/lib/src/scanner/token_map.dart
+++ b/pkg/compiler/lib/src/tokens/token_map.dart
@@ -4,7 +4,7 @@
 
 library dart2js.tokens.token_map;
 
-import 'scannerlib.dart' show
+import 'token.dart' show
     Token;
 
 /**
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index e239366..56f1f26 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -852,7 +852,9 @@
   int get value {
     try {
       Token valueToken = token;
-      if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next;
+      if (identical(valueToken.kind, Tokens.PLUS_TOKEN)) {
+        valueToken = valueToken.next;
+      }
       return int.parse(valueToken.value);
     } on FormatException catch (ex) {
       (this.handler)(token, ex);
@@ -871,7 +873,9 @@
   double get value {
     try {
       Token valueToken = token;
-      if (identical(valueToken.kind, PLUS_TOKEN)) valueToken = valueToken.next;
+      if (identical(valueToken.kind, Tokens.PLUS_TOKEN)) {
+        valueToken = valueToken.next;
+      }
       return double.parse(valueToken.value);
     } on FormatException catch (ex) {
       (this.handler)(token, ex);
@@ -1087,7 +1091,7 @@
   bool get hasExpression => expression != null;
 
   /// `true` if this return is of the form `=> e;`.
-  bool get isArrowBody => beginToken.info == FUNCTION_INFO;
+  bool get isArrowBody => beginToken.info == Precedence.FUNCTION_INFO;
 
   accept(Visitor visitor) => visitor.visitReturn(this);
 
diff --git a/pkg/compiler/lib/src/tree/tree.dart b/pkg/compiler/lib/src/tree/tree.dart
index 67993f2..d4331b5 100644
--- a/pkg/compiler/lib/src/tree/tree.dart
+++ b/pkg/compiler/lib/src/tree/tree.dart
@@ -9,7 +9,15 @@
 import '../diagnostics/spannable.dart' show
     Spannable,
     SpannableAssertionFailure;
-import '../scanner/scannerlib.dart';
+import '../tokens/precedence_constants.dart' as Precedence show
+    FUNCTION_INFO;
+import '../tokens/token.dart' show
+    BeginGroupToken,
+    Token;
+import '../tokens/token_constants.dart' as Tokens show
+    IDENTIFIER_TOKEN,
+    KEYWORD_TOKEN,
+    PLUS_TOKEN;
 import '../util/util.dart';
 import '../util/characters.dart';
 
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index b7d3109..fd00ba3 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -34,8 +34,8 @@
   void addToken(Token token) {
     if (token == null) return;
     write(token.value);
-    if (identical(token.kind, KEYWORD_TOKEN)
-        || identical(token.kind, IDENTIFIER_TOKEN)) {
+    if (identical(token.kind, Tokens.KEYWORD_TOKEN)
+        || identical(token.kind, Tokens.IDENTIFIER_TOKEN)) {
       write(' ');
     }
   }
@@ -209,7 +209,7 @@
       } else {
         visit(send.receiver);
         Identifier identifier = send.selector.asIdentifier();
-        if (identical(identifier.token.kind, KEYWORD_TOKEN)) {
+        if (identical(identifier.token.kind, Tokens.KEYWORD_TOKEN)) {
           write(' ');
         } else if (identifier.source == 'negate') {
           // TODO(ahe): Remove special case for negate.
@@ -292,13 +292,13 @@
   visitLiteralDouble(LiteralDouble node) {
     write(node.token.value);
     // -Lit is represented as a send.
-    if (node.token.kind == PLUS_TOKEN) write(node.token.next.value);
+    if (node.token.kind == Tokens.PLUS_TOKEN) write(node.token.next.value);
   }
 
   visitLiteralInt(LiteralInt node) {
     write(node.token.value);
     // -Lit is represented as a send.
-    if (node.token.kind == PLUS_TOKEN) write(node.token.next.value);
+    if (node.token.kind == Tokens.PLUS_TOKEN) write(node.token.next.value);
   }
 
   visitLiteralString(LiteralString node) {
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index 5e19e04..89b8b19 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -11,6 +11,7 @@
 import '../elements/elements.dart';
 import '../cps_ir/cps_ir_nodes.dart' as cps_ir;
 import 'tree_ir_nodes.dart';
+import '../constants/values.dart';
 
 typedef Statement NodeCallback(Statement next);
 
@@ -277,12 +278,6 @@
     return prim.accept(this);
   }
 
-  /// Translates a condition to a tree expression.
-  Expression translateCondition(cps_ir.Condition condition) {
-    cps_ir.IsTrue isTrue = condition;
-    return getVariableUse(isTrue.value);
-  }
-
   /************************ INTERIOR EXPRESSIONS  ************************/
   //
   // Visit methods for interior expressions must return a function:
@@ -500,8 +495,20 @@
     }
   }
 
+  /// Translates a branch condition to a tree expression.
+  Expression translateCondition(cps_ir.Branch branch) {
+    Expression value = getVariableUse(branch.condition);
+    if (branch.isStrictCheck) {
+      return new ApplyBuiltinOperator(
+          BuiltinOperator.StrictEq,
+          <Expression>[value, new Constant(new TrueConstantValue())]);
+    } else {
+      return value;
+    }
+  }
+
   Statement visitBranch(cps_ir.Branch node) {
-    Expression condition = translateCondition(node.condition);
+    Expression condition = translateCondition(node);
     Statement thenStatement, elseStatement;
     cps_ir.Continuation cont = node.trueContinuation.definition;
     assert(cont.parameters.isEmpty);
@@ -680,6 +687,5 @@
   visitParameter(cps_ir.Parameter node) => unexpectedNode(node);
   visitContinuation(cps_ir.Continuation node) => unexpectedNode(node);
   visitMutableVariable(cps_ir.MutableVariable node) => unexpectedNode(node);
-  visitIsTrue(cps_ir.IsTrue node) => unexpectedNode(node);
 }
 
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index 9ea82ab..65cf596 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -4,12 +4,78 @@
 
 part of types;
 
+/// An implementation of a [UniverseReceiverMaskSet] that is consists if an only
+/// increasing set of [TypeMask]s, that is, once a mask is added it cannot be
+/// removed.
+class IncreasingTypeMaskSet extends UniverseReceiverMaskSet {
+  bool isAll = false;
+  Set<TypeMask> _masks;
+
+  @override
+  bool applies(Element element, Selector selector, ClassWorld world) {
+    if (isAll) return true;
+    if (_masks == null) return false;
+    for (TypeMask mask in _masks) {
+      if (mask.canHit(element, selector, world)) return true;
+    }
+    return false;
+  }
+
+  @override
+  bool needsNoSuchMethodHandling(Selector selector, ClassWorld world) {
+    if (isAll) {
+      TypeMask mask =
+          new TypeMask.subclass(world.objectClass, world);
+      return mask.needsNoSuchMethodHandling(selector, world);
+    }
+    for (TypeMask mask in _masks) {
+      if (mask.needsNoSuchMethodHandling(selector, world)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
+  bool addReceiverMask(TypeMask mask) {
+    if (isAll) return false;
+    if (mask == null) {
+      isAll = true;
+      _masks = null;
+      return true;
+    }
+    if (_masks == null) {
+      _masks = new Setlet<TypeMask>();
+    }
+    return _masks.add(mask);
+  }
+
+  String toString() {
+    if (isAll) {
+      return '<all>';
+    } else if (_masks != null) {
+      return '$_masks';
+    } else {
+      return '<none>';
+    }
+  }
+}
+
+class TypeMaskStrategy implements ReceiverMaskStrategy {
+  const TypeMaskStrategy();
+
+  @override
+  UniverseReceiverMaskSet createReceiverMaskSet(Selector selector) {
+    return new IncreasingTypeMaskSet();
+  }
+}
+
 /**
  * A type mask represents a set of contained classes, but the
  * operations on it are not guaranteed to be precise and they may
  * yield conservative answers that contain too many classes.
  */
-abstract class TypeMask {
+abstract class TypeMask implements ReceiverMask {
   factory TypeMask(ClassElement base,
                    int kind,
                    bool isNullable,
diff --git a/pkg/compiler/lib/src/universe/function_set.dart b/pkg/compiler/lib/src/universe/function_set.dart
index 0b4b0bc..5f8dedd 100644
--- a/pkg/compiler/lib/src/universe/function_set.dart
+++ b/pkg/compiler/lib/src/universe/function_set.dart
@@ -13,6 +13,8 @@
       new Map<String, FunctionSetNode>();
   FunctionSet(this.compiler);
 
+  ClassWorld get classWorld => compiler.world;
+
   FunctionSetNode newNode(String name)
       => new FunctionSetNode(name);
 
@@ -44,30 +46,50 @@
         : false;
   }
 
-  /**
-   * Returns an object that allows iterating over all the functions
-   * that may be invoked with the given [selector].
-   */
+  /// Returns an object that allows iterating over all the functions
+  /// that may be invoked with the given [selector].
   Iterable<Element> filter(Selector selector, TypeMask mask) {
     return query(selector, mask).functions;
   }
 
+  /// Returns the mask for the potential receivers of a dynamic call to
+  /// [selector] on [mask].
+  ///
+  /// This will reduce the set of classes in [mask] to a [TypeMask] of the set
+  /// of classes that actually implement the selected member or implement the
+  /// handling 'noSuchMethod' where the selected member is unimplemented.
   TypeMask receiverType(Selector selector, TypeMask mask) {
-    return query(selector, mask).computeMask(compiler.world);
+    return query(selector, mask).computeMask(classWorld);
   }
 
+  SelectorMask _createSelectorMask(
+      Selector selector, TypeMask mask, ClassWorld classWorld) {
+    return mask != null
+        ? new SelectorMask(selector, mask)
+        : new SelectorMask(selector,
+            new TypeMask.subclass(classWorld.objectClass, classWorld));
+  }
+
+  /// Returns the set of functions that can be the target of a call to
+  /// [selector] on a receiver of type [mask] including 'noSuchMethod' methods
+  /// where applicable.
   FunctionSetQuery query(Selector selector, TypeMask mask) {
     String name = selector.name;
+    SelectorMask selectorMask = _createSelectorMask(selector, mask, classWorld);
+    SelectorMask noSuchMethodMask =
+        new SelectorMask(Selectors.noSuchMethod_, selectorMask.mask);
     FunctionSetNode node = nodes[name];
     FunctionSetNode noSuchMethods = nodes[Identifiers.noSuchMethod_];
     if (node != null) {
-      return node.query(selector, mask, compiler, noSuchMethods);
+      return node.query(
+          selectorMask, classWorld, noSuchMethods, noSuchMethodMask);
     }
     // If there is no method that matches [selector] we know we can
     // only hit [:noSuchMethod:].
-    if (noSuchMethods == null) return const FunctionSetQuery(const <Element>[]);
-    return noSuchMethods.query(
-        Selectors.noSuchMethod_, mask, compiler, null);
+    if (noSuchMethods == null) {
+      return const EmptyFunctionSetQuery();
+    }
+    return noSuchMethods.query(noSuchMethodMask, classWorld);
   }
 
   void forEach(Function action) {
@@ -77,6 +99,8 @@
   }
 }
 
+/// A selector/mask pair representing the dynamic invocation of [selector] on
+/// a receiver of type [mask].
 class SelectorMask {
   final Selector selector;
   final TypeMask mask;
@@ -86,16 +110,21 @@
       : this.selector = selector,
         this.mask = mask,
         this.hashCode =
-            Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode);
+            Hashing.mixHashCodeBits(selector.hashCode, mask.hashCode) {
+    assert(mask != null);
+  }
 
   String get name => selector.name;
 
   bool applies(Element element, ClassWorld classWorld) {
     if (!selector.appliesUnnamed(element, classWorld)) return false;
-    if (mask == null) return true;
     return mask.canHit(element, selector, classWorld);
   }
 
+  bool needsNoSuchMethodHandling(ClassWorld classWorld) {
+    return mask.needsNoSuchMethodHandling(selector, classWorld);
+  }
+
   bool operator ==(other) {
     if (identical(this, other)) return true;
     return selector == other.selector && mask == other.mask;
@@ -104,6 +133,8 @@
   String toString() => '($selector,$mask)';
 }
 
+/// A node in the [FunctionSet] caching all [FunctionSetQuery] object for
+/// selectors with the same [name].
 class FunctionSetNode {
   final String name;
   final Map<SelectorMask, FunctionSetQuery> cache =
@@ -164,24 +195,13 @@
     elements.forEach(action);
   }
 
-  TypeMask getNonNullTypeMaskOfSelector(TypeMask mask, ClassWorld classWorld) {
-    // TODO(ngeoffray): We should probably change untyped selector
-    // to always be a subclass of Object.
-    return mask != null
-        ? mask
-        : new TypeMask.subclass(classWorld.objectClass, classWorld);
-    }
-
-  // TODO(johnniwinther): Use [SelectorMask] instead of [Selector] and
-  // [TypeMask].
-  FunctionSetQuery query(Selector selector,
-                         TypeMask mask,
-                         Compiler compiler,
-                         FunctionSetNode noSuchMethods) {
-    mask = getNonNullTypeMaskOfSelector(mask, compiler.world);
-    SelectorMask selectorMask = new SelectorMask(selector, mask);
-    ClassWorld classWorld = compiler.world;
-    assert(selector.name == name);
+  /// Returns the set of functions that can be the target of [selectorMask]
+  /// including no such method handling where applicable.
+  FunctionSetQuery query(SelectorMask selectorMask,
+                         ClassWorld classWorld,
+                         [FunctionSetNode noSuchMethods,
+                          SelectorMask noSuchMethodMask]) {
+    assert(selectorMask.name == name);
     FunctionSetQuery result = cache[selectorMask];
     if (result != null) return result;
 
@@ -201,13 +221,10 @@
     // If we cannot ensure a method will be found at runtime, we also
     // add [noSuchMethod] implementations that apply to [mask] as
     // potential targets.
-    if (noSuchMethods != null
-        && mask.needsNoSuchMethodHandling(selector, classWorld)) {
-      FunctionSetQuery noSuchMethodQuery = noSuchMethods.query(
-          Selectors.noSuchMethod_,
-          mask,
-          compiler,
-          null);
+    if (noSuchMethods != null &&
+        selectorMask.needsNoSuchMethodHandling(classWorld)) {
+      FunctionSetQuery noSuchMethodQuery =
+          noSuchMethods.query(noSuchMethodMask, classWorld);
       if (!noSuchMethodQuery.functions.isEmpty) {
         if (functions == null) {
           functions = new Setlet<Element>.from(noSuchMethodQuery.functions);
@@ -217,31 +234,43 @@
       }
     }
     cache[selectorMask] = result = (functions != null)
-        ? newQuery(functions, selector, mask, compiler)
-        : const FunctionSetQuery(const <Element>[]);
+        ? new FullFunctionSetQuery(functions)
+        : const EmptyFunctionSetQuery();
     return result;
   }
-
-  FunctionSetQuery newQuery(Iterable<Element> functions,
-                            Selector selector,
-                            TypeMask mask,
-                            Compiler compiler) {
-    return new FullFunctionSetQuery(functions);
-  }
 }
 
-class FunctionSetQuery {
-  final Iterable<Element> functions;
+/// A set of functions that are the potential targets of all call sites sharing
+/// the same receiver mask and selector.
+abstract class FunctionSetQuery {
+  const FunctionSetQuery();
+
+  /// Compute the type of all potential receivers of this function set.
+  TypeMask computeMask(ClassWorld classWorld);
+
+  /// Returns all potential targets of this function set.
+  Iterable<Element> get functions;
+}
+
+class EmptyFunctionSetQuery implements FunctionSetQuery {
+  const EmptyFunctionSetQuery();
+
+  @override
   TypeMask computeMask(ClassWorld classWorld) => const TypeMask.nonNullEmpty();
-  const FunctionSetQuery(this.functions);
+
+  @override
+  Iterable<Element> get functions => const <Element>[];
 }
 
-class FullFunctionSetQuery extends FunctionSetQuery {
+class FullFunctionSetQuery implements FunctionSetQuery {
+  @override
+  final Iterable<Element> functions;
+
   TypeMask _mask;
 
-  /**
-   * Compute the type of all potential receivers of this function set.
-   */
+  FullFunctionSetQuery(this.functions);
+
+  @override
   TypeMask computeMask(ClassWorld classWorld) {
     assert(classWorld.hasAnyStrictSubclass(classWorld.objectClass));
     if (_mask != null) return _mask;
@@ -259,6 +288,4 @@
         }),
         classWorld);
   }
-
-  FullFunctionSetQuery(functions) : super(functions);
 }
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index c5da864..4530400 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -18,8 +18,8 @@
     SpannableAssertionFailure;
 import '../elements/elements.dart';
 import '../dart_types.dart';
-import '../types/types.dart';
 import '../tree/tree.dart';
+import '../types/types.dart';
 import '../util/util.dart';
 import '../world.dart' show
     ClassWorld,
@@ -30,7 +30,7 @@
 
 class UniverseSelector {
   final Selector selector;
-  final TypeMask mask;
+  final ReceiverMask mask;
 
   UniverseSelector(this.selector, this.mask);
 
@@ -42,57 +42,56 @@
   String toString() => '$selector,$mask';
 }
 
-abstract class TypeMaskSet {
+/// A potential receiver for a dynamic call site.
+abstract class ReceiverMask {
+  /// Returns whether [element] is a potential target when being
+  /// invoked on this receiver mask. [selector] is used to ensure library
+  /// privacy is taken into account.
+  bool canHit(Element element, Selector selector, ClassWorld classWorld);
+}
+
+/// A set of potential receivers for the dynamic call sites of the same
+/// selector.
+///
+/// For instance for these calls
+///
+///     new A().foo(a, b);
+///     new B().foo(0, 42);
+///
+/// the receiver mask set for dynamic calls to 'foo' with to positional
+/// arguments will contain receiver masks abstracting `new A()` and `new B()`.
+abstract class ReceiverMaskSet {
+  /// Returns `true` if [selector] applies to any of the potential receivers
+  /// in this set given the closed [world].
   bool applies(Element element, Selector selector, ClassWorld world);
-  Iterable<TypeMask> get masks;
+
+  /// Returns `true` if any potential receivers in this set given the closed
+  /// [world] have no implementation matching [selector].
+  ///
+  /// For instance for this code snippet
+  ///
+  ///     class A {}
+  ///     class B { foo() {} }
+  ///     m(b) => (b ? new A() : new B()).foo();
+  ///
+  /// the potential receiver `new A()` have no implementation of `foo` and thus
+  /// needs to handle the call though its `noSuchMethod` handler.
+  bool needsNoSuchMethodHandling(Selector selector, ClassWorld world);
 }
 
-/// An implementation of a [TypeMaskSet] that is only increasing, that is, once
-/// a mask is added it cannot be removed.
-class IncreasingTypeMaskSet extends TypeMaskSet {
-  bool isAll = false;
-  Set<TypeMask> _masks;
-
-  bool applies(Element element, Selector selector, ClassWorld world) {
-    if (isAll) return true;
-    if (_masks == null) return false;
-    for (TypeMask mask in _masks) {
-      if (mask.canHit(element, selector, world)) return true;
-    }
-    return false;
-  }
-
-  bool add(TypeMask mask) {
-    if (isAll) return false;
-    if (mask == null) {
-      isAll = true;
-      _masks = null;
-      return true;
-    }
-    if (_masks == null) {
-      _masks = new Setlet<TypeMask>();
-    }
-    return _masks.add(mask);
-  }
-
-  Iterable<TypeMask> get masks {
-    if (isAll) return const [null];
-    if (_masks == null) return const [];
-    return _masks;
-  }
-
-  String toString() {
-    if (isAll) {
-      return '<all>';
-    } else if (_masks != null) {
-      return '$_masks';
-    } else {
-      return '<none>';
-    }
-  }
+/// A mutable [ReceiverMaskSet] used in [Universe].
+abstract class UniverseReceiverMaskSet extends ReceiverMaskSet {
+  /// Adds [mask] to this set of potential receivers. Return `true` if the
+  /// set expanded due to the new mask.
+  bool addReceiverMask(ReceiverMask mask);
 }
 
-
+/// Strategy for computing potential receivers of dynamic call sites.
+abstract class ReceiverMaskStrategy {
+  /// Create a [UniverseReceiverMaskSet] to represent the potential receiver for
+  /// a dynamic call site with [selector].
+  UniverseReceiverMaskSet createReceiverMaskSet(Selector selector);
+}
 
 class Universe {
   /// The set of all directly instantiated classes, that is, classes with a
@@ -131,12 +130,12 @@
       new Set<FunctionElement>();
   final Set<FunctionElement> methodsNeedingSuperGetter =
       new Set<FunctionElement>();
-  final Map<String, Map<Selector, TypeMaskSet>> _invokedNames =
-      <String, Map<Selector, TypeMaskSet>>{};
-  final Map<String, Map<Selector, TypeMaskSet>> _invokedGetters =
-      <String, Map<Selector, TypeMaskSet>>{};
-  final Map<String, Map<Selector, TypeMaskSet>> _invokedSetters =
-      <String, Map<Selector, TypeMaskSet>>{};
+  final Map<String, Map<Selector, ReceiverMaskSet>> _invokedNames =
+      <String, Map<Selector, ReceiverMaskSet>>{};
+  final Map<String, Map<Selector, ReceiverMaskSet>> _invokedGetters =
+      <String, Map<Selector, ReceiverMaskSet>>{};
+  final Map<String, Map<Selector, ReceiverMaskSet>> _invokedSetters =
+      <String, Map<Selector, ReceiverMaskSet>>{};
 
   /**
    * Fields accessed. Currently only the codegen knows this
@@ -178,6 +177,10 @@
    */
   final Set<Element> closurizedMembers = new Set<Element>();
 
+  final ReceiverMaskStrategy receiverMaskStrategy;
+
+  Universe(this.receiverMaskStrategy);
+
   /// All directly instantiated classes, that is, classes with a generative
   /// constructor that has been called directly and not only through a
   /// super-call.
@@ -239,13 +242,13 @@
     });
   }
 
-  bool _hasMatchingSelector(Map<Selector, TypeMaskSet> selectors,
+  bool _hasMatchingSelector(Map<Selector, ReceiverMaskSet> selectors,
                             Element member,
                             World world) {
     if (selectors == null) return false;
     for (Selector selector in selectors.keys) {
       if (selector.appliesUnnamed(member, world)) {
-        TypeMaskSet masks = selectors[selector];
+        ReceiverMaskSet masks = selectors[selector];
         if (masks.applies(member, selector, world)) {
           return true;
         }
@@ -280,46 +283,47 @@
 
   bool _registerNewSelector(
       UniverseSelector universeSelector,
-      Map<String, Map<Selector, TypeMaskSet>> selectorMap) {
+      Map<String, Map<Selector, ReceiverMaskSet>> selectorMap) {
     Selector selector = universeSelector.selector;
     String name = selector.name;
-    TypeMask mask = universeSelector.mask;
-    Map<Selector, TypeMaskSet> selectors = selectorMap.putIfAbsent(
-        name, () => new Maplet<Selector, TypeMaskSet>());
-    IncreasingTypeMaskSet masks = selectors.putIfAbsent(
-        selector, () => new IncreasingTypeMaskSet());
-    return masks.add(mask);
+    ReceiverMask mask = universeSelector.mask;
+    Map<Selector, ReceiverMaskSet> selectors = selectorMap.putIfAbsent(
+        name, () => new Maplet<Selector, ReceiverMaskSet>());
+    UniverseReceiverMaskSet masks = selectors.putIfAbsent(
+        selector, () => receiverMaskStrategy.createReceiverMaskSet(selector));
+    return masks.addReceiverMask(mask);
   }
 
-  Map<Selector, TypeMaskSet> _asUnmodifiable(Map<Selector, TypeMaskSet> map) {
+  Map<Selector, ReceiverMaskSet> _asUnmodifiable(
+      Map<Selector, ReceiverMaskSet> map) {
     if (map == null) return null;
     return new UnmodifiableMapView(map);
   }
 
-  Map<Selector, TypeMaskSet> invocationsByName(String name) {
+  Map<Selector, ReceiverMaskSet> invocationsByName(String name) {
     return _asUnmodifiable(_invokedNames[name]);
   }
 
-  Map<Selector, TypeMaskSet> getterInvocationsByName(String name) {
+  Map<Selector, ReceiverMaskSet> getterInvocationsByName(String name) {
     return _asUnmodifiable(_invokedGetters[name]);
   }
 
-  Map<Selector, TypeMaskSet> setterInvocationsByName(String name) {
+  Map<Selector, ReceiverMaskSet> setterInvocationsByName(String name) {
     return _asUnmodifiable(_invokedSetters[name]);
   }
 
   void forEachInvokedName(
-      f(String name, Map<Selector, TypeMaskSet> selectors)) {
+      f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
     _invokedNames.forEach(f);
   }
 
   void forEachInvokedGetter(
-      f(String name, Map<Selector, TypeMaskSet> selectors)) {
+      f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
     _invokedGetters.forEach(f);
   }
 
   void forEachInvokedSetter(
-      f(String name, Map<Selector, TypeMaskSet> selectors)) {
+      f(String name, Map<Selector, ReceiverMaskSet> selectors)) {
     _invokedSetters.forEach(f);
   }
 
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 3fbf537..bdb0acf 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -46,7 +46,7 @@
 import 'util/util.dart' as util;
 import 'world.dart';
 
-import 'scanner/scannerlib.dart' show
+import 'parser/partial_elements.dart' show
     PartialClassElement,
     PartialFunctionElement;
 
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index ad922d2..fe774b2 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -11,6 +11,8 @@
   sdk_library_metadata:
     path: ../../sdk/lib/_internal/sdk_library_metadata
   dart2js_info: ^0.0.2
+  lookup_map:
+    path: ../lookup_map
 
 
 # Uncomment if running gclient, so you can depend directly on the downloaded
diff --git a/pkg/dart2js_incremental/lib/diff.dart b/pkg/dart2js_incremental/lib/diff.dart
index a667fad..b0569d1 100644
--- a/pkg/dart2js_incremental/lib/diff.dart
+++ b/pkg/dart2js_incremental/lib/diff.dart
@@ -19,15 +19,19 @@
 import 'package:compiler/src/elements/modelx.dart' show
     DeclarationSite;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
-    EOF_TOKEN,
-    ErrorToken,
-    IDENTIFIER_TOKEN,
-    KEYWORD_TOKEN,
+import 'package:compiler/src/parser/partial_elements.dart' show
     PartialClassElement,
-    PartialElement,
+    PartialElement;
+
+import 'package:compiler/src/tokens/token.dart' show
+    ErrorToken,
     Token;
 
+import 'package:compiler/src/tokens/token_constants.dart' show
+    EOF_TOKEN,
+    IDENTIFIER_TOKEN,
+    KEYWORD_TOKEN;
+
 class Difference {
   final DeclarationSite before;
   final DeclarationSite after;
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 6120e379..faca103 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -27,18 +27,30 @@
 import 'package:compiler/src/enqueue.dart' show
     EnqueueTask;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
-    EOF_TOKEN,
-    Listener,
-    NodeListener,
-    Parser,
+import 'package:compiler/src/parser/listener.dart' show
+    Listener;
+
+import 'package:compiler/src/parser/node_listener.dart' show
+    NodeListener;
+
+import 'package:compiler/src/parser/partial_elements.dart' show
     PartialClassElement,
     PartialElement,
     PartialFieldList,
-    PartialFunctionElement,
-    Scanner,
+    PartialFunctionElement;
+
+import 'package:compiler/src/parser/parser.dart' show
+    Parser;
+
+import 'package:compiler/src/scanner/scanner.dart' show
+    Scanner;
+
+import 'package:compiler/src/tokens/token.dart' show
     Token;
 
+import 'package:compiler/src/tokens/token_constants.dart' show
+    EOF_TOKEN;
+
 import 'package:compiler/src/script.dart' show
     Script;
 
diff --git a/pkg/lookup_map/AUTHORS b/pkg/lookup_map/AUTHORS
new file mode 100644
index 0000000..e8063a8
--- /dev/null
+++ b/pkg/lookup_map/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the project. Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google Inc.
diff --git a/pkg/lookup_map/CHANGELOG.md b/pkg/lookup_map/CHANGELOG.md
new file mode 100644
index 0000000..cbe7954a
--- /dev/null
+++ b/pkg/lookup_map/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Changelog
+
+## 0.0.1
+- Initial version of `LookupMap`
diff --git a/pkg/lookup_map/LICENSE b/pkg/lookup_map/LICENSE
new file mode 100644
index 0000000..de31e1a
--- /dev/null
+++ b/pkg/lookup_map/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2015, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/lookup_map/README.md b/pkg/lookup_map/README.md
new file mode 100644
index 0000000..73f5a81
--- /dev/null
+++ b/pkg/lookup_map/README.md
@@ -0,0 +1,29 @@
+# Lookup maps
+
+This package contains the definition of `LookupMap`: a simple, but very
+restricted map. The map can only hold constant keys and the only way to use the
+map is to retrieve values with a key you already have.  Expect for lookup, any
+other operation in `Map` (like forEach, keys, values, length, etc) is not
+available.
+
+Constant `LookupMap`s are understood by dart2js and can be tree-shaken
+internally: if a key is not used elsewhere in the program, its entry can be
+deleted from the map during compilation without changing the program's behavior.
+Currently dart2js supports tree-shaking keys that are Type literals, and any
+const expression that can only be created with a const constructor. This means
+that primitives, Strings, and constant objects that override the `==` operator
+cannot be tree-shaken.
+
+
+## Examples
+
+`LookupMap` is unlikely going to be useful for individual developers writing
+code by hand. It is mainly intended as a helper utility for frameworks that need
+to autogenerate data and associate it with a type in the program. For example,
+this can be used by a dependency injection system to record how to create
+instances of a given type. A dependency injection framework can store in a
+`LookupMap` all the information it needs for every injectable type in every
+library and package.  When compiling a specific application, dart2js can
+tree-shake the data of types that are not used by the application. Similarly,
+this can also be used by serialization/deserialization packages that can store
+in a `LookupMap` the deserialization logic for a given type.
diff --git a/pkg/lookup_map/lib/lookup_map.dart b/pkg/lookup_map/lib/lookup_map.dart
new file mode 100644
index 0000000..609f854
--- /dev/null
+++ b/pkg/lookup_map/lib/lookup_map.dart
@@ -0,0 +1,93 @@
+// 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.
+
+/// Defines [LookupMap], a simple map that can be optimized by dart2js.
+library lookup_map;
+
+/// [LookupMap] is a simple, but very restricted map.  The map can only hold
+/// constant keys and the only way to use the map is to retrieve values with a
+/// key you already have.  Expect for lookup, any other operation in [Map] (like
+/// forEach, keys, values, length, etc) is not available.
+///
+/// Constant [LookupMap]s are understood by dart2js and can be tree-shaken
+/// internally: if a key is not used elsewhere in the program, its entry can be
+/// deleted from the map during compilation without changing the program's
+/// behavior. Currently dart2js supports tree-shaking keys that are `Type`
+/// literals, and any const expression that can only be created with a const
+/// constructor. This means that primitives, Strings, and constant objects that
+/// override the `==` operator cannot be tree-shaken.
+///
+/// Note: [LookupMap] is unlikely going to be useful for individual developers
+/// writing code by hand. It is mainly intended as a helper utility for
+/// frameworks that need to autogenerate data and associate it with a type in
+/// the program. For example, this can be used by a dependency injection system
+/// to record how to create instances of a given type. A dependency injection
+/// framework can store in a [LookupMap] all the information it needs for every
+/// injectable type in every library and package.  When compiling a specific
+/// application, dart2js can tree-shake the data of types that are not used by
+/// the application. Similarly, this can also be used by
+/// serialization/deserialization packages that can store in a [LookupMap] the
+/// deserialization logic for a given type.
+class LookupMap<K, V> {
+  /// The key for [LookupMap]s with a single key/value pair.
+  final K _key;
+
+  /// The value for [LookupMap]s with a single key/value pair.
+  final V _value;
+
+  /// List of alternating key-value pairs in the map.
+  final List _entries;
+
+  /// Other maps to which this map delegates lookup operations if the key is not
+  /// found on [entries]. See [LookupMap]'s constructor for details.
+  final List<LookupMap<K, V>> _nestedMaps;
+
+  /// Creates a lookup-map given a list of key-value pair [entries], and
+  /// optionally additional entries from other [LookupMap]s.
+  ///
+  /// When doing a lookup, if the key is not found on [entries]. The lookup will
+  /// be performed in reverse order of the list of [nestedMaps], so a later
+  /// entry for a key shadows previous entries.  For example, in:
+  ///
+  ///     const map = const LookupMap(const [A, 1],
+  ///         const [const LookupMap(const [A, 2, B, 4]),
+  ///                const LookupMap(const [A, 3, B, 5]));
+  ///
+  /// `map[A]` returns `1` and `map[B]` returns `5`.
+  ///
+  /// Note: in the future we expect to change [entries] to be a const map
+  /// instead of a list of key-value pairs.
+  // TODO(sigmund): make entries a map once we fix TypeImpl.== (issue #17207).
+  const LookupMap(List entries, [List<LookupMap<K, V>> nestedMaps = const []])
+    : _key = null, _value = null, _entries = entries, _nestedMaps = nestedMaps;
+
+  /// Creates a lookup map with a single key-value pair.
+  const LookupMap.pair(K key, V value)
+    : _key = key, _value = value, _entries = const [], _nestedMaps = const [];
+
+  /// Return the data corresponding to [key].
+  V operator[](K key) {
+    var map = _flatMap[this];
+    if (map == null) {
+      map = {};
+      _addEntriesTo(map);
+      _flatMap[this] = map;
+    }
+    return map[key];
+  }
+
+  /// Add to [map] entries from [nestedMaps] and from [entries] according to the
+  /// precedense order described in [nestedMaps].
+  _addEntriesTo(Map map) {
+    _nestedMaps.forEach((m) => m._addEntriesTo(map));
+    for (var i = 0; i < _entries.length; i += 2) {
+      map[_entries[i]] = _entries[i + 1];
+    }
+    if (_key != null) map[_key] = _value;
+  }
+}
+
+/// An expando that stores a flatten version of a [LookupMap], this is
+/// computed and stored the first time the map is accessed.
+final _flatMap = new Expando('_flat_map');
diff --git a/pkg/lookup_map/pubspec.yaml b/pkg/lookup_map/pubspec.yaml
new file mode 100644
index 0000000..fdc8946
--- /dev/null
+++ b/pkg/lookup_map/pubspec.yaml
@@ -0,0 +1,3 @@
+name: lookup_map
+description: a lookup-only map that can be tree-shaken by dart2js
+version: 0.0.1
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 2cc4cd8..6bd0cda 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -198,6 +198,9 @@
       msgbuf_->ReadData();
     }
     if (!msgbuf_->Alive()) {
+      if (trace_debug_protocol) {
+        Log::Print("Debugger is exiting HandleMessages loop.\n");
+      }
       return;
     }
 
@@ -344,6 +347,13 @@
 }
 
 
+void DebuggerConnectionHandler::StopHandler() {
+  if (IsConnected()) {
+    DebuggerConnectionImpl::StopHandler(singleton_handler->debug_fd());
+  }
+}
+
+
 void DebuggerConnectionHandler::WaitForConnection() {
   ASSERT(handler_lock_ != NULL);
   MonitorLocker ml(handler_lock_);
diff --git a/runtime/bin/dbg_connection.h b/runtime/bin/dbg_connection.h
index bd4f4dd..577c30a 100644
--- a/runtime/bin/dbg_connection.h
+++ b/runtime/bin/dbg_connection.h
@@ -51,6 +51,9 @@
   // from the client.
   static int StartHandler(const char* address, int port_number);
 
+  // Stops the native thread.
+  static void StopHandler();
+
   // Initializes the parts of the debugger which are needed by the vm
   // service.  This function should only be called when StartHandler
   // is not called.
diff --git a/runtime/bin/dbg_connection_android.h b/runtime/bin/dbg_connection_android.h
index 591ee9f..8975294 100644
--- a/runtime/bin/dbg_connection_android.h
+++ b/runtime/bin/dbg_connection_android.h
@@ -16,6 +16,7 @@
 class DebuggerConnectionImpl {
  public:
   static void StartHandler(int port_number);
+  static void StopHandler(intptr_t debug_fd) {}
   static intptr_t Send(intptr_t socket, const char* buf, int len);
   static intptr_t Receive(intptr_t socket, char* buf, int len);
 
diff --git a/runtime/bin/dbg_connection_linux.h b/runtime/bin/dbg_connection_linux.h
index 94a9664..fcbd16e 100644
--- a/runtime/bin/dbg_connection_linux.h
+++ b/runtime/bin/dbg_connection_linux.h
@@ -16,6 +16,7 @@
 class DebuggerConnectionImpl {
  public:
   static void StartHandler(int port_number);
+  static void StopHandler(intptr_t debug_fd) {}
   static intptr_t Send(intptr_t socket, const char* buf, int len);
   static intptr_t Receive(intptr_t socket, char* buf, int len);
 
diff --git a/runtime/bin/dbg_connection_macos.h b/runtime/bin/dbg_connection_macos.h
index 9665700..064238e 100644
--- a/runtime/bin/dbg_connection_macos.h
+++ b/runtime/bin/dbg_connection_macos.h
@@ -16,6 +16,7 @@
 class DebuggerConnectionImpl {
  public:
   static void StartHandler(int port_number);
+  static void StopHandler(intptr_t debug_fd) {}
   static intptr_t Send(intptr_t socket, const char* buf, int len);
   static intptr_t Receive(intptr_t socket, char* buf, int len);
 
diff --git a/runtime/bin/dbg_connection_win.cc b/runtime/bin/dbg_connection_win.cc
index fee02e6c..49bc4a9 100644
--- a/runtime/bin/dbg_connection_win.cc
+++ b/runtime/bin/dbg_connection_win.cc
@@ -8,12 +8,59 @@
 #include "bin/dbg_connection.h"
 
 #include "bin/eventhandler.h"
-
+#include "bin/lockers.h"
+#include "bin/log.h"
+#include "bin/thread.h"
 
 namespace dart {
 namespace bin {
 
+Monitor* DebuggerConnectionImpl::handler_monitor_ = new Monitor();
+ThreadId DebuggerConnectionImpl::handler_thread_id_ = Thread::kInvalidThreadId;
+bool DebuggerConnectionImpl::handler_thread_running_ = false;
+
+
+void DebuggerConnectionImpl::NotifyThreadStarted() {
+  MonitorLocker ml(handler_monitor_);
+  ASSERT(!handler_thread_running_);
+  ASSERT(handler_thread_id_ == Thread::kInvalidThreadId);
+  handler_thread_running_ = true;
+  handler_thread_id_ = Thread::GetCurrentThreadId();
+  ml.Notify();
+}
+
+
+void DebuggerConnectionImpl::WaitForThreadStarted() {
+  MonitorLocker ml(handler_monitor_);
+  while (!handler_thread_running_) {
+    ml.Wait();
+  }
+  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
+}
+
+
+void DebuggerConnectionImpl::NotifyThreadFinished() {
+  MonitorLocker ml(handler_monitor_);
+  ASSERT(handler_thread_running_);
+  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
+  handler_thread_running_ = false;
+  ml.Notify();
+}
+
+
+void DebuggerConnectionImpl::WaitForThreadFinished() {
+  MonitorLocker ml(handler_monitor_);
+  while (handler_thread_running_) {
+    ml.Wait();
+  }
+  ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
+  Thread::Join(handler_thread_id_);
+  handler_thread_id_ = Thread::kInvalidThreadId;
+}
+
+
 void DebuggerConnectionImpl::ThreadEntry(uword args) {
+  NotifyThreadStarted();
   ListenSocket* listen_socket =
       reinterpret_cast<ListenSocket*>(DebuggerConnectionHandler::listener_fd_);
   SOCKET client_socket = accept(listen_socket->socket(), NULL, NULL);
@@ -23,6 +70,7 @@
   ClientSocket* socket = new ClientSocket(client_socket);
   DebuggerConnectionHandler::AcceptDbgConnection(
       reinterpret_cast<intptr_t>(socket));
+  NotifyThreadFinished();
 }
 
 
@@ -32,6 +80,13 @@
   if (result != 0) {
     FATAL1("Failed to start debugger connection handler thread: %d\n", result);
   }
+  WaitForThreadStarted();
+}
+
+
+void DebuggerConnectionImpl::StopHandler(intptr_t debug_fd) {
+  Send(debug_fd, NULL, 0);
+  WaitForThreadFinished();
 }
 
 
diff --git a/runtime/bin/dbg_connection_win.h b/runtime/bin/dbg_connection_win.h
index 2a9feb2..8f5d0c6 100644
--- a/runtime/bin/dbg_connection_win.h
+++ b/runtime/bin/dbg_connection_win.h
@@ -5,17 +5,29 @@
 #ifndef BIN_DBG_CONNECTION_WIN_H_
 #define BIN_DBG_CONNECTION_WIN_H_
 
+#include "bin/lockers.h"
+#include "bin/thread.h"
+
 namespace dart {
 namespace bin {
 
 class DebuggerConnectionImpl {
  public:
   static void StartHandler(int port_number);
+  static void StopHandler(intptr_t debug_fd);
   static intptr_t Send(intptr_t socket, const char* buf, int len);
   static intptr_t Receive(intptr_t socket, char* buf, int len);
 
  private:
   static void ThreadEntry(uword args);
+  static void NotifyThreadStarted();
+  static void WaitForThreadStarted();
+  static void NotifyThreadFinished();
+  static void WaitForThreadFinished();
+
+  static Monitor* handler_monitor_;
+  static ThreadId handler_thread_id_;
+  static bool handler_thread_running_;
 };
 
 }  // namespace bin
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index db698a3..6e27f82 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -121,23 +121,16 @@
       pending_read_(NULL),
       pending_write_(NULL),
       last_error_(NOERROR),
-      flags_(0) {
-  InitializeCriticalSection(&cs_);
+      flags_(0),
+      read_thread_id_(Thread::kInvalidThreadId),
+      read_thread_starting_(false),
+      read_thread_finished_(false),
+      monitor_(new Monitor()) {
 }
 
 
 Handle::~Handle() {
-  DeleteCriticalSection(&cs_);
-}
-
-
-void Handle::Lock() {
-  EnterCriticalSection(&cs_);
-}
-
-
-void Handle::Unlock() {
-  LeaveCriticalSection(&cs_);
+  delete monitor_;
 }
 
 
@@ -154,7 +147,7 @@
 
 
 void Handle::Close() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (!IsClosing()) {
     // Close the socket and set the closing state. This close method can be
     // called again if this socket has pending IO operations in flight.
@@ -175,28 +168,60 @@
 
 
 bool Handle::HasPendingRead() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   return pending_read_ != NULL;
 }
 
 
 bool Handle::HasPendingWrite() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   return pending_write_ != NULL;
 }
 
 
-void Handle::ReadComplete(OverlappedBuffer* buffer) {
-  ScopedLock lock(this);
-  // Currently only one outstanding read at the time.
-  ASSERT(pending_read_ == buffer);
-  ASSERT(data_ready_ == NULL);
-  if (!IsClosing() && !buffer->IsEmpty()) {
-    data_ready_ = pending_read_;
-  } else {
-    OverlappedBuffer::DisposeBuffer(buffer);
+void Handle::WaitForReadThreadStarted() {
+  MonitorLocker ml(monitor_);
+  while (read_thread_starting_) {
+    ml.Wait();
   }
-  pending_read_ = NULL;
+}
+
+
+void Handle::WaitForReadThreadFinished() {
+  // Join the Reader thread if there is one.
+  ThreadId to_join = Thread::kInvalidThreadId;
+  {
+    MonitorLocker ml(monitor_);
+    if (read_thread_id_ != Thread::kInvalidThreadId) {
+      while (!read_thread_finished_) {
+        ml.Wait();
+      }
+      read_thread_finished_ = false;
+      to_join = read_thread_id_;
+      read_thread_id_ = Thread::kInvalidThreadId;
+    }
+  }
+  if (to_join != Thread::kInvalidThreadId) {
+    Thread::Join(to_join);
+  }
+}
+
+
+void Handle::ReadComplete(OverlappedBuffer* buffer) {
+  WaitForReadThreadStarted();
+  {
+    MonitorLocker ml(monitor_);
+    // Currently only one outstanding read at the time.
+    ASSERT(pending_read_ == buffer);
+    ASSERT(data_ready_ == NULL);
+    if (!IsClosing() && !buffer->IsEmpty()) {
+      data_ready_ = pending_read_;
+    } else {
+      OverlappedBuffer::DisposeBuffer(buffer);
+    }
+    pending_read_ = NULL;
+  }
+  WaitForReadThreadFinished();
 }
 
 
@@ -206,7 +231,7 @@
 
 
 void Handle::WriteComplete(OverlappedBuffer* buffer) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   // Currently only one outstanding write at the time.
   ASSERT(pending_write_ == buffer);
   OverlappedBuffer::DisposeBuffer(buffer);
@@ -220,7 +245,26 @@
 }
 
 
+void Handle::NotifyReadThreadStarted() {
+  MonitorLocker ml(monitor_);
+  ASSERT(read_thread_starting_);
+  ASSERT(read_thread_id_ == Thread::kInvalidThreadId);
+  read_thread_id_ = Thread::GetCurrentThreadId();
+  read_thread_starting_ = false;
+  ml.Notify();
+}
+
+void Handle::NotifyReadThreadFinished() {
+  MonitorLocker ml(monitor_);
+  ASSERT(!read_thread_finished_);
+  ASSERT(read_thread_id_ != Thread::kInvalidThreadId);
+  read_thread_finished_ = true;
+  ml.Notify();
+}
+
+
 void Handle::ReadSyncCompleteAsync() {
+  NotifyReadThreadStarted();
   ASSERT(pending_read_ != NULL);
   ASSERT(pending_read_->GetBufferSize() >= kStdOverlappedBufferSize);
 
@@ -228,9 +272,10 @@
   if (GetFileType(handle_) == FILE_TYPE_CHAR) {
     buffer_size = kStdOverlappedBufferSize;
   }
+  char* buffer_start = pending_read_->GetBufferStart();
   DWORD bytes_read = 0;
   BOOL ok = ReadFile(handle_,
-                     pending_read_->GetBufferStart(),
+                     buffer_start,
                      buffer_size,
                      &bytes_read,
                      NULL);
@@ -245,11 +290,11 @@
   if (!ok) {
     FATAL("PostQueuedCompletionStatus failed");
   }
+  NotifyReadThreadFinished();
 }
 
 
 bool Handle::IssueRead() {
-  ScopedLock lock(this);
   ASSERT(type_ != kListenSocket);
   ASSERT(pending_read_ == NULL);
   OverlappedBuffer* buffer = OverlappedBuffer::AllocateReadBuffer(kBufferSize);
@@ -272,6 +317,7 @@
   } else {
     // Completing asynchronously through thread.
     pending_read_ = buffer;
+    read_thread_starting_ = true;
     int result = Thread::Start(ReadFileThread,
                                reinterpret_cast<uword>(this));
     if (result != 0) {
@@ -288,7 +334,7 @@
 
 
 bool Handle::IssueWrite() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   ASSERT(type_ != kListenSocket);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_write_ != NULL);
@@ -345,7 +391,7 @@
 
 
 void FileHandle::EnsureInitialized(EventHandlerImplementation* event_handler) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   event_handler_ = event_handler;
   if (SupportsOverlappedIO() && completion_port_ == INVALID_HANDLE_VALUE) {
     CreateCompletionPort(event_handler_->completion_port());
@@ -360,7 +406,7 @@
 
 void DirectoryWatchHandle::EnsureInitialized(
     EventHandlerImplementation* event_handler) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   event_handler_ = event_handler;
   if (completion_port_ == INVALID_HANDLE_VALUE) {
     CreateCompletionPort(event_handler_->completion_port());
@@ -374,7 +420,6 @@
 
 
 bool DirectoryWatchHandle::IssueRead() {
-  ScopedLock lock(this);
   // It may have been started before, as we start the directory-handler when
   // we create it.
   if (pending_read_ != NULL || data_ready_ != NULL) return true;
@@ -399,7 +444,7 @@
 
 
 void DirectoryWatchHandle::Stop() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   // Stop the outstanding read, so we can close the handle.
 
   if (pending_read_ != NULL) {
@@ -443,7 +488,7 @@
 
 
 bool ListenSocket::IssueAccept() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
 
   // For AcceptEx there needs to be buffer storage for address
   // information for two addresses (local and remote address). The
@@ -483,7 +528,7 @@
 
 void ListenSocket::AcceptComplete(OverlappedBuffer* buffer,
                                   HANDLE completion_port) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (!IsClosing()) {
     // Update the accepted socket to support the full range of API calls.
     SOCKET s = socket();
@@ -544,13 +589,13 @@
 
 
 bool ListenSocket::CanAccept() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   return accepted_head_ != NULL;
 }
 
 
 ClientSocket* ListenSocket::Accept() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
 
   ClientSocket *result = NULL;
 
@@ -577,7 +622,7 @@
 
 void ListenSocket::EnsureInitialized(
     EventHandlerImplementation* event_handler) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (AcceptEx_ == NULL) {
     ASSERT(completion_port_ == INVALID_HANDLE_VALUE);
     ASSERT(event_handler_ == NULL);
@@ -594,7 +639,7 @@
 
 
 intptr_t Handle::Available() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (data_ready_ == NULL) return 0;
   ASSERT(!data_ready_->IsEmpty());
   return data_ready_->GetRemainingLength();
@@ -602,7 +647,7 @@
 
 
 intptr_t Handle::Read(void* buffer, intptr_t num_bytes) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (data_ready_ == NULL) return 0;
   num_bytes = data_ready_->Read(
       buffer, Utils::Minimum<intptr_t>(num_bytes, INT_MAX));
@@ -617,7 +662,7 @@
 
 intptr_t Handle::RecvFrom(
     void* buffer, intptr_t num_bytes, struct sockaddr* sa, socklen_t sa_len) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (data_ready_ == NULL) return 0;
   num_bytes = data_ready_->Read(
       buffer, Utils::Minimum<intptr_t>(num_bytes, INT_MAX));
@@ -639,7 +684,7 @@
 
 
 intptr_t Handle::Write(const void* buffer, intptr_t num_bytes) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (pending_write_ != NULL) return 0;
   if (num_bytes > kBufferSize) num_bytes = kBufferSize;
   ASSERT(SupportsOverlappedIO());
@@ -656,7 +701,7 @@
                         intptr_t num_bytes,
                         struct sockaddr* sa,
                         socklen_t sa_len) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (pending_write_ != NULL) return 0;
   if (num_bytes > kBufferSize) num_bytes = kBufferSize;
   ASSERT(SupportsOverlappedIO());
@@ -675,13 +720,14 @@
 
 
 void StdHandle::RunWriteLoop() {
-  write_monitor_->Enter();
+  MonitorLocker ml(monitor_);
   write_thread_running_ = true;
+  thread_id_ = Thread::GetCurrentThreadId();
   // Notify we have started.
-  write_monitor_->Notify();
+  ml.Notify();
 
   while (write_thread_running_) {
-    write_monitor_->Wait(Monitor::kNoTimeout);
+    ml.Wait(Monitor::kNoTimeout);
     if (pending_write_ != NULL) {
       // We woke up and had a pending write. Execute it.
       WriteSyncCompleteAsync();
@@ -689,8 +735,7 @@
   }
 
   write_thread_exists_ = false;
-  write_monitor_->Notify();
-  write_monitor_->Exit();
+  ml.Notify();
 }
 
 
@@ -718,7 +763,7 @@
 }
 
 intptr_t StdHandle::Write(const void* buffer, intptr_t num_bytes) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (pending_write_ != NULL) return 0;
   if (num_bytes > kBufferSize) num_bytes = kBufferSize;
   // In the case of stdout and stderr, OverlappedIO is not supported.
@@ -726,7 +771,6 @@
   // This code is actually never exposed to the user, as stdout and stderr is
   // not available as a RawSocket, but only wrapped in a Socket.
   // Note that we return '0', unless a thread have already completed a write.
-  MonitorLocker locker(write_monitor_);
   if (thread_wrote_ > 0) {
     if (num_bytes > thread_wrote_) num_bytes = thread_wrote_;
     thread_wrote_ -= num_bytes;
@@ -734,14 +778,14 @@
   }
   if (!write_thread_exists_) {
     write_thread_exists_ = true;
-    int result = Thread::Start(WriteFileThread,
-                                     reinterpret_cast<uword>(this));
+    int result = Thread::Start(
+        WriteFileThread, reinterpret_cast<uword>(this));
     if (result != 0) {
       FATAL1("Failed to start write file thread %d", result);
     }
     while (!write_thread_running_) {
       // Wait until we the thread is running.
-      locker.Wait(Monitor::kNoTimeout);
+      ml.Wait(Monitor::kNoTimeout);
     }
   }
   // Only queue up to INT_MAX bytes.
@@ -749,19 +793,20 @@
   // Create buffer and notify thread about the new handle.
   pending_write_ = OverlappedBuffer::AllocateWriteBuffer(truncated_bytes);
   pending_write_->Write(buffer, truncated_bytes);
-  locker.Notify();
+  ml.Notify();
   return 0;
 }
 
 
 void StdHandle::DoClose() {
-  MonitorLocker locker(write_monitor_);
+  MonitorLocker ml(monitor_);
   if (write_thread_exists_) {
     write_thread_running_ = false;
-    locker.Notify();
+    ml.Notify();
     while (write_thread_exists_) {
-      locker.Wait(Monitor::kNoTimeout);
+      ml.Wait(Monitor::kNoTimeout);
     }
+    Thread::Join(thread_id_);
   }
   Handle::DoClose();
 }
@@ -807,7 +852,7 @@
 
 
 bool ClientSocket::IssueRead() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_read_ == NULL);
 
@@ -836,7 +881,7 @@
 
 
 bool ClientSocket::IssueWrite() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_write_ != NULL);
   ASSERT(pending_write_->operation() == OverlappedBuffer::kWrite);
@@ -900,7 +945,7 @@
 
 void ClientSocket::EnsureInitialized(
     EventHandlerImplementation* event_handler) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (completion_port_ == INVALID_HANDLE_VALUE) {
     ASSERT(event_handler_ == NULL);
     event_handler_ = event_handler;
@@ -915,7 +960,7 @@
 
 
 bool DatagramSocket::IssueSendTo(struct sockaddr* sa, socklen_t sa_len) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_write_ != NULL);
   ASSERT(pending_write_->operation() == OverlappedBuffer::kSendTo);
@@ -940,7 +985,7 @@
 
 
 bool DatagramSocket::IssueRecvFrom() {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
   ASSERT(pending_read_ == NULL);
 
@@ -970,7 +1015,7 @@
 
 void DatagramSocket::EnsureInitialized(
     EventHandlerImplementation* event_handler) {
-  ScopedLock lock(this);
+  MonitorLocker ml(monitor_);
   if (completion_port_ == INVALID_HANDLE_VALUE) {
     ASSERT(event_handler_ == NULL);
     event_handler_ = event_handler;
@@ -1010,7 +1055,7 @@
           reinterpret_cast<ListenSocket*>(handle);
       listen_socket->EnsureInitialized(this);
 
-      Handle::ScopedLock lock(listen_socket);
+      MonitorLocker ml(listen_socket->monitor_);
 
       if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
         listen_socket->ReturnTokens(msg->dart_port, TOKEN_COUNT(msg->data));
@@ -1040,7 +1085,7 @@
       }
     } else {
       handle->EnsureInitialized(this);
-      Handle::ScopedLock lock(handle);
+      MonitorLocker ml(handle->monitor_);
 
       if (IS_COMMAND(msg->data, kReturnTokenCommand)) {
         handle->ReturnTokens(msg->dart_port, TOKEN_COUNT(msg->data));
@@ -1114,7 +1159,7 @@
   listen_socket->AcceptComplete(buffer, completion_port_);
 
   {
-    Handle::ScopedLock lock(listen_socket);
+    MonitorLocker ml(listen_socket->monitor_);
     TryDispatchingPendingAccepts(listen_socket);
   }
 
@@ -1278,6 +1323,8 @@
 
 
 EventHandlerImplementation::EventHandlerImplementation() {
+  startup_monitor_ = new Monitor();
+  handler_thread_id_ = Thread::kInvalidThreadId;
   completion_port_ =
       CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
   if (completion_port_ == NULL) {
@@ -1288,6 +1335,8 @@
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
+  Thread::Join(handler_thread_id_);
+  delete startup_monitor_;
   CloseHandle(completion_port_);
 }
 
@@ -1322,6 +1371,12 @@
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
 
+  {
+    MonitorLocker ml(handler_impl->startup_monitor_);
+    handler_impl->handler_thread_id_ = Thread::GetCurrentThreadId();
+    ml.Notify();
+  }
+
   while (!handler_impl->shutdown_) {
     DWORD bytes;
     ULONG_PTR key;
@@ -1382,6 +1437,13 @@
     FATAL1("Failed to start event handler thread %d", result);
   }
 
+  {
+    MonitorLocker ml(startup_monitor_);
+    while (handler_thread_id_ == Thread::kInvalidThreadId) {
+      ml.Wait();
+    }
+  }
+
   // Initialize Winsock32
   if (!Socket::Initialize()) {
     FATAL("Failed to initialized Windows sockets");
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index bfd02f9..38509dd 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -165,20 +165,6 @@
     kDatagramSocket
   };
 
-  class ScopedLock {
-   public:
-    explicit ScopedLock(Handle* handle)
-        : handle_(handle) {
-      handle_->Lock();
-    }
-    ~ScopedLock() {
-      handle_->Unlock();
-    }
-
-   private:
-    Handle* handle_;
-  };
-
   virtual ~Handle();
 
   // Socket interface exposing normal socket operations.
@@ -219,9 +205,6 @@
 
   HANDLE handle() { return handle_; }
 
-  void Lock();
-  void Unlock();
-
   bool CreateCompletionPort(HANDLE completion_port);
 
   void Close();
@@ -252,6 +235,9 @@
   void set_last_error(DWORD last_error) { last_error_ = last_error; }
 
  protected:
+  // For access to monitor_;
+  friend class EventHandlerImplementation;
+
   enum Flags {
     kClosing = 0,
     kCloseRead = 1,
@@ -264,6 +250,7 @@
 
   virtual void HandleIssueError();
 
+  Monitor* monitor_;
   Type type_;
   HANDLE handle_;
   HANDLE completion_port_;
@@ -275,9 +262,17 @@
 
   DWORD last_error_;
 
+  ThreadId read_thread_id_;
+  bool read_thread_starting_;
+  bool read_thread_finished_;
+
  private:
+  void WaitForReadThreadStarted();
+  void NotifyReadThreadStarted();
+  void WaitForReadThreadFinished();
+  void NotifyReadThreadFinished();
+
   int flags_;
-  CRITICAL_SECTION cs_;  // Critical section protecting this object.
 };
 
 
@@ -297,17 +292,13 @@
  public:
   explicit StdHandle(HANDLE handle)
       : FileHandle(handle),
+        thread_id_(Thread::kInvalidThreadId),
         thread_wrote_(0),
         write_thread_exists_(false),
-        write_thread_running_(false),
-        write_monitor_(new Monitor()) {
+        write_thread_running_(false) {
     type_ = kStd;
   }
 
-  ~StdHandle() {
-    delete write_monitor_;
-  }
-
   virtual void DoClose();
   virtual intptr_t Write(const void* buffer, intptr_t num_bytes);
 
@@ -315,10 +306,10 @@
   void RunWriteLoop();
 
  private:
+  ThreadId thread_id_;
   intptr_t thread_wrote_;
   bool write_thread_exists_;
   bool write_thread_running_;
-  Monitor* write_monitor_;
 };
 
 
@@ -526,6 +517,9 @@
  private:
   ClientSocket* client_sockets_head_;
 
+  Monitor* startup_monitor_;
+  ThreadId handler_thread_id_;
+
   TimeoutQueue timeout_queue_;  // Time for next timeout.
   bool shutdown_;
   HANDLE completion_port_;
diff --git a/runtime/bin/extensions.h b/runtime/bin/extensions.h
index 2b4e19b..25dbfeb 100644
--- a/runtime/bin/extensions.h
+++ b/runtime/bin/extensions.h
@@ -21,14 +21,14 @@
                                    const char* extension_name,
                                    Dart_Handle parent_library);
 
- private:
-  // The returned string must be freed.
-  static char* Concatenate(const char** strings);
-
   // Platform-specific implementations.
   static void* LoadExtensionLibrary(const char* library_file);
   static void* ResolveSymbol(void* lib_handle, const char* symbol);
 
+ private:
+  // The returned string must be freed.
+  static char* Concatenate(const char** strings);
+
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(Extensions);
 };
diff --git a/runtime/bin/extensions_android.cc b/runtime/bin/extensions_android.cc
index 3d2688b..1b79991 100644
--- a/runtime/bin/extensions_android.cc
+++ b/runtime/bin/extensions_android.cc
@@ -12,6 +12,9 @@
 namespace dart {
 namespace bin {
 
+const char* kPrecompiledLibraryName = "libprecompiled.so";
+const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
 }
diff --git a/runtime/bin/extensions_linux.cc b/runtime/bin/extensions_linux.cc
index c42024a..23ee6ed 100644
--- a/runtime/bin/extensions_linux.cc
+++ b/runtime/bin/extensions_linux.cc
@@ -12,6 +12,9 @@
 namespace dart {
 namespace bin {
 
+const char* kPrecompiledLibraryName = "libprecompiled.so";
+const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
 }
diff --git a/runtime/bin/extensions_macos.cc b/runtime/bin/extensions_macos.cc
index 814f935..92a5e98 100644
--- a/runtime/bin/extensions_macos.cc
+++ b/runtime/bin/extensions_macos.cc
@@ -12,6 +12,9 @@
 namespace dart {
 namespace bin {
 
+const char* kPrecompiledLibraryName = "libprecompiled.dylib";
+const char* kPrecompiledSymbolName = "kInstructionsSnapshot";
+
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
 }
diff --git a/runtime/bin/extensions_win.cc b/runtime/bin/extensions_win.cc
index 63462ee..8c0a15f 100644
--- a/runtime/bin/extensions_win.cc
+++ b/runtime/bin/extensions_win.cc
@@ -13,6 +13,9 @@
 namespace dart {
 namespace bin {
 
+const char* kPrecompiledLibraryName = "precompiled.dll";
+const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return LoadLibraryW(StringUtilsWin::Utf8ToWide(library_file));
 }
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 4e2b24a..45fe8b4 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -73,7 +73,19 @@
 
 // Global flag that is used to indicate that we want to compile all the
 // dart functions before running main and not compile anything thereafter.
-static bool has_precompile = false;
+static bool has_gen_precompiled_snapshot = false;
+
+
+// Global flag that is used to indicate that we want to run from a precompiled
+// snapshot.
+static bool has_run_precompiled_snapshot = false;
+
+
+extern const char* kPrecompiledLibraryName;
+extern const char* kPrecompiledSymbolName;
+static const char* kPrecompiledVmIsolateName = "precompiled.vmisolate";
+static const char* kPrecompiledIsolateName = "precompiled.isolate";
+static const char* kPrecompiledInstructionsName = "precompiled.instructions";
 
 
 // Global flag that is used to indicate that we want to trace resolution of
@@ -110,6 +122,9 @@
 
   Dart_Cleanup();
 
+  DebuggerConnectionHandler::StopHandler();
+  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
+  // EventHandler::Stop();
   exit(exit_code);
 }
 
@@ -289,13 +304,33 @@
 }
 
 
-static bool ProcessPrecompileOption(const char* arg,
-                                    CommandLineOptions* vm_options) {
+static bool ProcessGenPrecompiledSnapshotOption(
+    const char* arg,
+    CommandLineOptions* vm_options) {
   ASSERT(arg != NULL);
   if (*arg != '\0') {
     return false;
   }
-  has_precompile = true;
+  // Ensure that we are not already running using a full snapshot.
+  if (isolate_snapshot_buffer != NULL) {
+    Log::PrintErr("Precompiled snapshots must be generated with"
+                  " dart_no_snapshot.");
+    return false;
+  }
+  has_gen_precompiled_snapshot = true;
+  vm_options->AddArgument("--precompile");
+  return true;
+}
+
+
+static bool ProcessRunPrecompiledSnapshotOption(
+    const char* arg,
+    CommandLineOptions* vm_options) {
+  ASSERT(arg != NULL);
+  if (*arg != '\0') {
+    return false;
+  }
+  has_run_precompiled_snapshot = true;
   vm_options->AddArgument("--precompile");
   return true;
 }
@@ -320,7 +355,7 @@
 static bool ProcessGenScriptSnapshotOption(const char* filename,
                                            CommandLineOptions* vm_options) {
   if (filename != NULL && strlen(filename) != 0) {
-    // Ensure that are already running using a full snapshot.
+    // Ensure that we are already running using a full snapshot.
     if (isolate_snapshot_buffer == NULL) {
       Log::PrintErr("Script snapshots cannot be generated in this version of"
                     " dart\n");
@@ -411,7 +446,8 @@
   // VM specific options to the standalone dart program.
   { "--break-at=", ProcessBreakpointOption },
   { "--compile_all", ProcessCompileAllOption },
-  { "--precompile", ProcessPrecompileOption },
+  { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
+  { "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
   { "--debug", ProcessDebugOption },
   { "--snapshot=", ProcessGenScriptSnapshotOption },
   { "--enable-vm-service", ProcessEnableVmServiceOption },
@@ -645,7 +681,7 @@
       *error = strdup(VmService::GetErrorMessage());
       return NULL;
     }
-    if (has_precompile) {
+    if (has_gen_precompiled_snapshot) {
       result = Dart_Precompile();
       CHECK_RESULT(result);
     } else if (has_compile_all) {
@@ -959,6 +995,50 @@
 }
 
 
+static void WriteSnapshotFile(const char* filename,
+                              const uint8_t* buffer,
+                              const intptr_t size) {
+  File* file = File::Open(filename, File::kWriteTruncate);
+  ASSERT(file != NULL);
+  if (!file->WriteFully(buffer, size)) {
+    Log::PrintErr("Error: Failed to write snapshot file.\n\n");
+  }
+  delete file;
+}
+
+
+static void ReadSnapshotFile(const char* filename,
+                             const uint8_t** buffer) {
+  void* file = DartUtils::OpenFile(filename, false);
+  if (file == NULL) {
+    Log::PrintErr("Error: Failed to open '%s'.\n\n", filename);
+    exit(kErrorExitCode);
+  }
+  intptr_t len = -1;
+  DartUtils::ReadFile(buffer, &len, file);
+  if (*buffer == NULL || len == -1) {
+    Log::PrintErr("Error: Failed to read '%s'.\n\n", filename);
+    exit(kErrorExitCode);
+  }
+  DartUtils::CloseFile(file);
+}
+
+
+static void* LoadLibrarySymbol(const char* libname, const char* symname) {
+  void* library = Extensions::LoadExtensionLibrary(libname);
+  if (library == NULL) {
+    Log::PrintErr("Error: Failed to load library '%s'.\n\n", libname);
+    exit(kErrorExitCode);
+  }
+  void* symbol = Extensions::ResolveSymbol(library, symname);
+  if (symbol == NULL) {
+    Log::PrintErr("Failed to load symbol '%s'\n", symname);
+    exit(kErrorExitCode);
+  }
+  return symbol;
+}
+
+
 void main(int argc, char** argv) {
   char* script_name;
   const int EXTRA_VM_ARGUMENTS = 2;
@@ -1032,8 +1112,16 @@
     DebuggerConnectionHandler::InitForVmService();
   }
 
+  const uint8_t* instructions_snapshot = NULL;
+  if (has_run_precompiled_snapshot) {
+    instructions_snapshot = reinterpret_cast<const uint8_t*>(
+        LoadLibrarySymbol(kPrecompiledLibraryName, kPrecompiledSymbolName));
+    ReadSnapshotFile(kPrecompiledVmIsolateName, &vm_isolate_snapshot_buffer);
+    ReadSnapshotFile(kPrecompiledIsolateName, &isolate_snapshot_buffer);
+  }
+
   // Initialize the Dart VM.
-  if (!Dart_Initialize(vm_isolate_snapshot_buffer, NULL,
+  if (!Dart_Initialize(vm_isolate_snapshot_buffer, instructions_snapshot,
                        CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
                        DartUtils::OpenFile,
                        DartUtils::ReadFile,
@@ -1042,6 +1130,9 @@
                        DartUtils::EntropySource)) {
     fprintf(stderr, "%s", "VM initialization failed\n");
     fflush(stderr);
+    DebuggerConnectionHandler::StopHandler();
+    // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
+    // EventHandler::Stop();
     exit(kErrorExitCode);
   }
 
@@ -1066,6 +1157,9 @@
     Log::PrintErr("%s\n", error);
     free(error);
     delete [] isolate_name;
+    DebuggerConnectionHandler::StopHandler();
+    // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
+    // EventHandler::Stop();
     exit((exit_code != 0) ? exit_code : kErrorExitCode);
   }
   delete [] isolate_name;
@@ -1111,9 +1205,32 @@
     ASSERT(!Dart_IsError(builtin_lib));
     result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
 
-    if (has_precompile) {
+    if (has_gen_precompiled_snapshot) {
       result = Dart_Precompile();
       DartExitOnError(result);
+
+      uint8_t* vm_isolate_buffer = NULL;
+      intptr_t vm_isolate_size = 0;
+      uint8_t* isolate_buffer = NULL;
+      intptr_t isolate_size = 0;
+      uint8_t* instructions_buffer = NULL;
+      intptr_t instructions_size = 0;
+      result = Dart_CreatePrecompiledSnapshot(&vm_isolate_buffer,
+                                              &vm_isolate_size,
+                                              &isolate_buffer,
+                                              &isolate_size,
+                                              &instructions_buffer,
+                                              &instructions_size);
+      DartExitOnError(result);
+      WriteSnapshotFile(kPrecompiledVmIsolateName,
+                        vm_isolate_buffer,
+                        vm_isolate_size);
+      WriteSnapshotFile(kPrecompiledIsolateName,
+                        isolate_buffer,
+                        isolate_size);
+      WriteSnapshotFile(kPrecompiledInstructionsName,
+                        instructions_buffer,
+                        instructions_size);
     } else if (has_compile_all) {
       result = Dart_CompileAll();
       DartExitOnError(result);
@@ -1171,6 +1288,10 @@
 
   Dart_Cleanup();
 
+  DebuggerConnectionHandler::StopHandler();
+  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
+  // EventHandler::Stop();
+
   // Free copied argument strings if converted.
   if (argv_converted) {
     for (int i = 0; i < argc; i++) free(argv[i]);
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 2c90c11..242ef1c 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "bin/dartutils.h"
+#include "bin/dbg_connection.h"
+#include "bin/eventhandler.h"
 #include "bin/io_buffer.h"
 #include "bin/platform.h"
 #include "bin/process.h"
@@ -218,6 +220,9 @@
   DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status);
   Dart_ExitIsolate();
   Dart_Cleanup();
+  DebuggerConnectionHandler::StopHandler();
+  // TODO(zra): Stop the EventHandler once thread shutdown is enabled.
+  // EventHandler::Stop();
   exit(static_cast<int>(status));
 }
 
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index c32301d..0670683 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -100,14 +100,28 @@
 }
 
 
+static void FreeSecurityContext(
+    void* isolate_data,
+    Dart_WeakPersistentHandle handle,
+    void* context_pointer) {
+  SSL_CTX* context = static_cast<SSL_CTX*>(context_pointer);
+  SSL_CTX_free(context);
+}
+
+
 static void SetSecurityContext(Dart_NativeArguments args,
                                SSL_CTX* context) {
+  const int approximate_size_of_context = 1500;
   Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
   ASSERT(Dart_IsInstance(dart_this));
   ThrowIfError(Dart_SetNativeInstanceField(
       dart_this,
       kSecurityContextNativeFieldIndex,
       reinterpret_cast<intptr_t>(context)));
+  Dart_NewWeakPersistentHandle(dart_this,
+                               context,
+                               approximate_size_of_context,
+                               FreeSecurityContext);
 }
 
 
@@ -313,9 +327,6 @@
   SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM");
   SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM");
   SetSecurityContext(args, context);
-  // TODO(whesse): Use WeakPersistentHandle to free the SSL_CTX
-  // when the object is GC'd.  Also free the alpn_select_cb data pointer,
-  // if non-null (allocated in SetAlpnProtocolList).
 }
 
 
@@ -825,7 +836,9 @@
       // TODO(whesse): If this function is called again, free the previous
       // protocol_string_copy.  It may be better to keep this as a native
       // field on the Dart object, since fetching it from the structure is
-      // not in the public api.  Also free this when the context is destroyed.
+      // not in the public api.
+      // Also free protocol_string_copy when the context is destroyed,
+      // in FreeSecurityContext()
     } else {
       // The function makes a local copy of protocol_string, which it owns.
       if (ssl != NULL) {
@@ -1022,6 +1035,10 @@
     SSL_free(ssl_);
     ssl_ = NULL;
   }
+  if (socket_side_ != NULL) {
+    BIO_free(socket_side_);
+    socket_side_ = NULL;
+  }
   for (int i = 0; i < kNumBuffers; ++i) {
     Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
     delete[] buffers_[i];
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index cd3611a..2af0055 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -54,6 +54,7 @@
   SSLFilter()
       : callback_error(NULL),
         ssl_(NULL),
+        socket_side_(NULL),
         string_start_(NULL),
         string_length_(NULL),
         handshake_complete_(NULL),
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 8b9070c..15114a6 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -852,6 +852,8 @@
  *
  * \param vm_isolate_snapshot A buffer containing a snapshot of the VM isolate
  *   or NULL if no snapshot is provided.
+ * \param instructions_snapshot A buffer containing a snapshot of precompiled
+ *   instructions, or NULL if no snapshot is provided.
  * \param create A function to be called during isolate creation.
  *   See Dart_IsolateCreateCallback.
  * \param interrupt A function to be called when an isolate is interrupted.
@@ -2859,4 +2861,21 @@
  */
 DART_EXPORT Dart_Port Dart_ServiceWaitForLoadPort();
 
+
+/*
+ * ==============
+ * Precompilation
+ * ==============
+ */
+
+
+DART_EXPORT Dart_Handle Dart_Precompile();
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
+    uint8_t** vm_isolate_snapshot_buffer,
+    intptr_t* vm_isolate_snapshot_size,
+    uint8_t** isolate_snapshot_buffer,
+    intptr_t* isolate_snapshot_size,
+    uint8_t** instructions_snapshot_buffer,
+    intptr_t* instructions_snapshot_size);
+
 #endif  /* INCLUDE_DART_API_H_ */  /* NOLINT */
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index 5a27249..ea7900d 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -159,6 +159,5 @@
  * TODO(turnidge): Document.
  */
 DART_EXPORT Dart_Handle Dart_CompileAll();
-DART_EXPORT Dart_Handle Dart_Precompile();
 
 #endif  /* INCLUDE_DART_NATIVE_API_H_ */  /* NOLINT */
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index d68e758..c1a869a 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -109,7 +109,7 @@
 
 static RawInstance* CreateParameterMirrorList(const Function& func,
                                               const Instance& owner_mirror) {
-  HANDLESCOPE(Isolate::Current());
+  HANDLESCOPE(Thread::Current());
   const intptr_t implicit_param_count = func.NumImplicitParameters();
   const intptr_t non_implicit_param_count = func.NumParameters() -
                                             implicit_param_count;
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index ae16694..f652da1 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -621,7 +621,7 @@
       'Set a debugger option.\n'
       '\n'
       'Known options:\n'
-      '  break-on-exceptions   # Should the debugger break on exceptions?\n'
+      '  break-on-exception    # Should the debugger break on exceptions?\n'
       "                        # ${_boeValues}\n"
       '  up-is-down            # Reverse meaning of up/down commands?\n'
       "                        # ${_boolValues}\n"
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 32fd18d..7b4ae79 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -165,13 +165,15 @@
             LocalVariable* saved_try_ctx,
             LocalVariable* async_saved_try_ctx,
             LocalVariable* outer_saved_try_ctx,
-            LocalVariable* outer_async_saved_try_ctx)
+            LocalVariable* outer_async_saved_try_ctx,
+            LocalScope* scope)
     : AstNode(token_pos),
       expr_(expr),
       saved_try_ctx_(saved_try_ctx),
       async_saved_try_ctx_(async_saved_try_ctx),
       outer_saved_try_ctx_(outer_saved_try_ctx),
-      outer_async_saved_try_ctx_(outer_async_saved_try_ctx) { }
+      outer_async_saved_try_ctx_(outer_async_saved_try_ctx),
+      scope_(scope) { }
 
   void VisitChildren(AstNodeVisitor* visitor) const {
     expr_->Visit(visitor);
@@ -184,6 +186,7 @@
   LocalVariable* outer_async_saved_try_ctx() const {
     return outer_async_saved_try_ctx_;
   }
+  LocalScope* scope() const { return scope_; }
 
   DECLARE_COMMON_NODE_FUNCTIONS(AwaitNode);
 
@@ -193,6 +196,7 @@
   LocalVariable* async_saved_try_ctx_;
   LocalVariable* outer_saved_try_ctx_;
   LocalVariable* outer_async_saved_try_ctx_;
+  LocalScope* scope_;
 
   DISALLOW_COPY_AND_ASSIGN(AwaitNode);
 };
@@ -209,17 +213,25 @@
 //   <AwaitMarker> -> ...
 class AwaitMarkerNode : public AstNode {
  public:
-  AwaitMarkerNode() : AstNode(Scanner::kNoSourcePos) { }
+  AwaitMarkerNode(LocalScope* async_scope, LocalScope* await_scope)
+    : AstNode(Scanner::kNoSourcePos),
+      async_scope_(async_scope),
+      await_scope_(await_scope) {
+    ASSERT(async_scope != NULL);
+    ASSERT(await_scope != NULL);
+    await_scope->CaptureLocalVariables(async_scope);
+  }
 
   void VisitChildren(AstNodeVisitor* visitor) const { }
 
-  LocalScope* scope() const { return scope_; }
-  void set_scope(LocalScope* scope) { scope_ = scope; }
+  LocalScope* async_scope() const { return async_scope_; }
+  LocalScope* await_scope() const { return await_scope_; }
 
   DECLARE_COMMON_NODE_FUNCTIONS(AwaitMarkerNode);
 
  private:
-  LocalScope* scope_;
+  LocalScope* async_scope_;
+  LocalScope* await_scope_;
 
   DISALLOW_COPY_AND_ASSIGN(AwaitMarkerNode);
 };
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 4877eac..aa5c29f 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -191,17 +191,22 @@
 
 
 void AstPrinter::VisitAwaitNode(AwaitNode* node) {
-  VisitGenericAstNode(node);
+  ISL_Print("(*****%s***** (scope \"%p\") ", node->PrettyName(), node->scope());
+  node->VisitChildren(this);
+  ISL_Print(")");
 }
 
 
 void AstPrinter::VisitAwaitMarkerNode(AwaitMarkerNode* node) {
-  VisitGenericAstNode(node);
+  ISL_Print("(%s (async_scope \"%p\" await_scope \"%p\"))",
+            node->PrettyName(),
+            node->async_scope(),
+            node->await_scope());
 }
 
 
 void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
-  ISL_Print("*****%s***** \"%s\")",
+  ISL_Print("(*****%s***** \"%s\")",
             node->PrettyName(),
             node->primary().ToCString());
 }
@@ -506,7 +511,7 @@
 
 
 void AstPrinter::PrintFunctionScope(const ParsedFunction& parsed_function) {
-  HANDLESCOPE(Isolate::Current());
+  HANDLESCOPE(parsed_function.thread());
   const Function& function = parsed_function.function();
   SequenceNode* node_sequence = parsed_function.node_sequence();
   ASSERT(node_sequence != NULL);
@@ -558,7 +563,7 @@
 
 
 void AstPrinter::PrintFunctionNodes(const ParsedFunction& parsed_function) {
-  HANDLESCOPE(Isolate::Current());
+  HANDLESCOPE(parsed_function.thread());
   SequenceNode* node_sequence = parsed_function.node_sequence();
   ASSERT(node_sequence != NULL);
   AstPrinter ast_printer;
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index 11cb61c..76faa89 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -46,12 +46,12 @@
 #undef DEFINE_UNREACHABLE
 
 AwaitTransformer::AwaitTransformer(SequenceNode* preamble,
-                                   LocalScope* function_top)
+                                   LocalScope* async_temp_scope)
     : preamble_(preamble),
       temp_cnt_(0),
-      function_top_(function_top),
+      async_temp_scope_(async_temp_scope),
       thread_(Thread::Current()) {
-  ASSERT(function_top_ != NULL);
+  ASSERT(async_temp_scope_ != NULL);
 }
 
 
@@ -62,18 +62,16 @@
 
 
 LocalVariable* AwaitTransformer::EnsureCurrentTempVar() {
-  const char* await_temp_prefix = ":await_temp_var_";
-  const String& cnt_str = String::ZoneHandle(
-      Z, String::NewFormatted("%s%d", await_temp_prefix, temp_cnt_));
-  const String& symbol = String::ZoneHandle(Z, Symbols::New(cnt_str));
+  String& symbol = String::ZoneHandle(Z, String::NewFormatted("%d", temp_cnt_));
+  symbol = Symbols::FromConcat(Symbols::AwaitTempVarPrefix(), symbol);
   ASSERT(!symbol.IsNull());
   // Look up the variable in the scope used for async temp variables.
-  LocalVariable* await_tmp = function_top_->LocalLookupVariable(symbol);
+  LocalVariable* await_tmp = async_temp_scope_->LocalLookupVariable(symbol);
   if (await_tmp == NULL) {
     // We need a new temp variable; add it to the function's top scope.
     await_tmp = new (Z) LocalVariable(
         Scanner::kNoSourcePos, symbol, Type::ZoneHandle(Type::DynamicType()));
-    function_top_->AddVariable(await_tmp);
+    async_temp_scope_->AddVariable(await_tmp);
     // After adding it to the top scope, we can look it up from the preamble.
     // The following call includes an ASSERT check.
     await_tmp = GetVariableInScope(preamble_->scope(), symbol);
@@ -136,8 +134,8 @@
   AstNode* transformed_expr = Transform(node->expr());
   LocalVariable* await_temp = AddToPreambleNewTempVar(transformed_expr);
 
-  AwaitMarkerNode* await_marker = new (Z) AwaitMarkerNode();
-  await_marker->set_scope(preamble_->scope());
+  AwaitMarkerNode* await_marker =
+      new (Z) AwaitMarkerNode(async_temp_scope_, node->scope());
   preamble_->Add(await_marker);
 
   // :result_param = _awaitHelper(
@@ -562,7 +560,7 @@
   // added to a scope, and the subsequent nodes that are added to the
   // preample can access them.
   for (intptr_t i = 0; i < node->num_temps(); i++) {
-    function_top_->AddVariable(node->TempAt(i));
+    async_temp_scope_->AddVariable(node->TempAt(i));
     AstNode* new_init_val = Transform(node->InitializerAt(i));
     preamble_->Add(new(Z) StoreLocalNode(node->token_pos(),
                    node->TempAt(i),
diff --git a/runtime/vm/ast_transformer.h b/runtime/vm/ast_transformer.h
index 807f7cf..e9f6791 100644
--- a/runtime/vm/ast_transformer.h
+++ b/runtime/vm/ast_transformer.h
@@ -39,7 +39,7 @@
 //
 class AwaitTransformer : public AstNodeVisitor {
  public:
-  AwaitTransformer(SequenceNode* preamble, LocalScope* function_top);
+  AwaitTransformer(SequenceNode* preamble, LocalScope* async_temp_scope);
 
 #define DECLARE_VISIT(BaseName)                                                \
   virtual void Visit##BaseName##Node(BaseName##Node* node);
@@ -66,7 +66,7 @@
   SequenceNode* preamble_;
   int32_t temp_cnt_;
   AstNode* result_;
-  LocalScope* function_top_;
+  LocalScope* async_temp_scope_;
 
   Thread* thread_;
 
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index b65d639..ee3ca57 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -353,8 +353,7 @@
   char* dart_root = ComputeDart2JSPath(Benchmark::Executable());
   char* script = NULL;
   if (dart_root != NULL) {
-    Isolate* isolate = Isolate::Current();
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     const char* kFormatStr =
         "import '%s/pkg/compiler/lib/compiler.dart';";
     intptr_t len = OS::SNPrint(NULL, 0, kFormatStr, dart_root) + 1;
@@ -502,8 +501,10 @@
   // Write snapshot with object content.
   FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
                             &isolate_snapshot_buffer,
+                            NULL, /* instructions_snapshot_buffer */
                             &malloc_allocator,
-                            false /* snapshot_code */);
+                            false, /* snapshot_code */
+                            true /* vm_isolate_is_symbolic */);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot = Snapshot::SetupFromBuffer(isolate_snapshot_buffer);
   ASSERT(snapshot->kind() == Snapshot::kFull);
@@ -537,8 +538,10 @@
   // Write snapshot with object content.
   FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
                             &isolate_snapshot_buffer,
+                            NULL, /* instructions_snapshot_buffer */
                             &malloc_allocator,
-                            false /* snapshot_code */);
+                            false, /* snapshot_code */
+                            true /* vm_isolate_is_symbolic */);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot = Snapshot::SetupFromBuffer(isolate_snapshot_buffer);
   ASSERT(snapshot->kind() == Snapshot::kFull);
@@ -595,12 +598,11 @@
 BENCHMARK(SerializeNull) {
   const Object& null_object = Object::Handle();
   const intptr_t kLoopCount = 1000000;
-  Isolate* isolate = Isolate::Current();
   uint8_t* buffer;
   Timer timer(true, "Serialize Null");
   timer.Start();
   for (intptr_t i = 0; i < kLoopCount; i++) {
-    StackZone zone(isolate);
+    StackZone zone(thread);
     MessageWriter writer(&buffer, &message_allocator, true);
     writer.WriteMessage(null_object);
     intptr_t buffer_len = writer.BytesWritten();
@@ -608,8 +610,7 @@
     // Read object back from the snapshot.
     MessageSnapshotReader reader(buffer,
                                  buffer_len,
-                                 isolate,
-                                 zone.GetZone());
+                                 thread);
     reader.ReadObject();
   }
   timer.Stop();
@@ -621,12 +622,11 @@
 BENCHMARK(SerializeSmi) {
   const Integer& smi_object = Integer::Handle(Smi::New(42));
   const intptr_t kLoopCount = 1000000;
-  Isolate* isolate = Isolate::Current();
   uint8_t* buffer;
   Timer timer(true, "Serialize Smi");
   timer.Start();
   for (intptr_t i = 0; i < kLoopCount; i++) {
-    StackZone zone(isolate);
+    StackZone zone(thread);
     MessageWriter writer(&buffer, &message_allocator, true);
     writer.WriteMessage(smi_object);
     intptr_t buffer_len = writer.BytesWritten();
@@ -634,8 +634,7 @@
     // Read object back from the snapshot.
     MessageSnapshotReader reader(buffer,
                                  buffer_len,
-                                 isolate,
-                                 zone.GetZone());
+                                 thread);
     reader.ReadObject();
   }
   timer.Stop();
@@ -649,12 +648,11 @@
   array_object.SetAt(0, Integer::Handle(Smi::New(42)));
   array_object.SetAt(1, Object::Handle());
   const intptr_t kLoopCount = 1000000;
-  Isolate* isolate = Isolate::Current();
   uint8_t* buffer;
   Timer timer(true, "Simple Message");
   timer.Start();
   for (intptr_t i = 0; i < kLoopCount; i++) {
-    StackZone zone(isolate);
+    StackZone zone(thread);
     MessageWriter writer(&buffer, &malloc_allocator, true);
     writer.WriteMessage(array_object);
     intptr_t buffer_len = writer.BytesWritten();
@@ -662,8 +660,7 @@
     // Read object back from the snapshot.
     MessageSnapshotReader reader(buffer,
                                  buffer_len,
-                                 isolate,
-                                 zone.GetZone());
+                                 thread);
     reader.ReadObject();
     free(buffer);
   }
@@ -687,12 +684,11 @@
   Instance& map = Instance::Handle();
   map ^= Api::UnwrapHandle(h_result);
   const intptr_t kLoopCount = 100;
-  Isolate* isolate = Isolate::Current();
   uint8_t* buffer;
   Timer timer(true, "Large Map");
   timer.Start();
   for (intptr_t i = 0; i < kLoopCount; i++) {
-    StackZone zone(isolate);
+    StackZone zone(thread);
     MessageWriter writer(&buffer, &malloc_allocator, true);
     writer.WriteMessage(map);
     intptr_t buffer_len = writer.BytesWritten();
@@ -700,8 +696,7 @@
     // Read object back from the snapshot.
     MessageSnapshotReader reader(buffer,
                                  buffer_len,
-                                 isolate,
-                                 zone.GetZone());
+                                 thread);
     reader.ReadObject();
     free(buffer);
   }
diff --git a/runtime/vm/benchmark_test.h b/runtime/vm/benchmark_test.h
index a91bc01..615965c 100644
--- a/runtime/vm/benchmark_test.h
+++ b/runtime/vm/benchmark_test.h
@@ -34,7 +34,7 @@
 #define BENCHMARK_HELPER(name, kind)                                           \
   void Dart_Benchmark##name(Benchmark* benchmark);                             \
   static Benchmark kRegister##name(Dart_Benchmark##name, #name, kind);         \
-  static void Dart_BenchmarkHelper##name(Benchmark* benchmark);                \
+  static void Dart_BenchmarkHelper##name(Benchmark* benchmark, Thread* thread);\
   void Dart_Benchmark##name(Benchmark* benchmark) {                            \
     FLAG_old_gen_growth_space_ratio = 100;                                     \
     BenchmarkIsolateScope __isolate__(benchmark);                              \
@@ -42,9 +42,9 @@
     ASSERT(__thread__->isolate() == benchmark->isolate());                     \
     StackZone __zone__(__thread__);                                            \
     HandleScope __hs__(__thread__);                                            \
-    Dart_BenchmarkHelper##name(benchmark);                                     \
+    Dart_BenchmarkHelper##name(benchmark, __thread__);                         \
   }                                                                            \
-  static void Dart_BenchmarkHelper##name(Benchmark* benchmark)
+  static void Dart_BenchmarkHelper##name(Benchmark* benchmark, Thread* thread)
 
 #define BENCHMARK(name) BENCHMARK_HELPER(name, "RunTime")
 #define BENCHMARK_SIZE(name) BENCHMARK_HELPER(name, "CodeSize")
diff --git a/runtime/vm/bit_vector_test.cc b/runtime/vm/bit_vector_test.cc
index 4c803d9..d2b7d1a 100644
--- a/runtime/vm/bit_vector_test.cc
+++ b/runtime/vm/bit_vector_test.cc
@@ -8,7 +8,7 @@
 
 namespace dart {
 
-#define Z Thread::Current()->zone()
+#define Z (thread->zone())
 
 TEST_CASE(BitVector) {
   { BitVector* v = new BitVector(Z, 15);
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index a9b9485..912aa1f 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -253,7 +253,8 @@
 
 
 RawError* Bootstrap::LoadandCompileScripts() {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   String& uri = String::Handle(isolate);
   String& patch_uri = String::Handle(isolate);
   String& source = String::Handle(isolate);
@@ -266,7 +267,7 @@
   // library tag handler so that we can load all the bootstrap libraries.
   isolate->set_library_tag_handler(BootstrapLibraryTagHandler);
 
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
 
   // Create library objects for all the bootstrap libraries.
   for (intptr_t i = 0;
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 48bbfce..fc4dfad 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -116,9 +116,10 @@
 // a) when bootstrap process completes (VerifyBootstrapClasses).
 // b) after the user classes are loaded (dart_api).
 bool ClassFinalizer::ProcessPendingClasses() {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
   ObjectStore* object_store = isolate->object_store();
   const Error& error = Error::Handle(isolate, object_store->sticky_error());
   if (!error.IsNull()) {
@@ -523,7 +524,7 @@
 
 void ClassFinalizer::FinalizeTypeParameters(
     const Class& cls,
-    GrowableObjectArray* pending_types) {
+    PendingTypes* pending_types) {
   if (FLAG_trace_type_finalization) {
     ISL_Print("Finalizing type parameters of '%s'\n",
               String::Handle(cls.Name()).ToCString());
@@ -561,7 +562,7 @@
 // pending finalization that are mutually recursive with the checked type.
 void ClassFinalizer::CheckRecursiveType(const Class& cls,
                                         const Type& type,
-                                        GrowableObjectArray* pending_types) {
+                                        PendingTypes* pending_types) {
   Isolate* isolate = Isolate::Current();
   if (FLAG_trace_type_finalization) {
     ISL_Print("Checking recursive type '%s': %s\n",
@@ -589,11 +590,10 @@
   // The type parameters are not instantiated. Verify that there is no other
   // type pending finalization with the same type class, but different
   // uninstantiated type parameters.
-  Type& pending_type = Type::Handle(isolate);
   TypeArguments& pending_arguments = TypeArguments::Handle(isolate);
-  const intptr_t num_pending_types = pending_types->Length();
+  const intptr_t num_pending_types = pending_types->length();
   for (intptr_t i = num_pending_types - 1; i >= 0; i--) {
-    pending_type ^= pending_types->At(i);
+    const Type& pending_type = Type::Cast(pending_types->At(i));
     if (FLAG_trace_type_finalization) {
       ISL_Print("  Comparing with pending type '%s': %s\n",
                 String::Handle(pending_type.Name()).ToCString(),
@@ -655,7 +655,7 @@
     const TypeArguments& arguments,
     intptr_t num_uninitialized_arguments,
     Error* bound_error,
-    GrowableObjectArray* pending_types,
+    PendingTypes* pending_types,
     TrailPtr trail) {
   ASSERT(arguments.Length() >= cls.NumTypeArguments());
   if (!cls.is_type_finalized()) {
@@ -906,7 +906,7 @@
     const Class& cls,
     const AbstractType& type,
     FinalizationKind finalization,
-    GrowableObjectArray* pending_types) {
+    PendingTypes* pending_types) {
   // Only the 'root' type of the graph can be canonicalized, after all depending
   // types have been bound checked.
   ASSERT((pending_types == NULL) || (finalization < kCanonicalize));
@@ -981,10 +981,8 @@
   // This type is the root type of the type graph if no pending types queue is
   // allocated yet.
   const bool is_root_type = (pending_types == NULL);
-  GrowableObjectArray& types = GrowableObjectArray::Handle(Z);
   if (is_root_type) {
-    types = GrowableObjectArray::New();
-    pending_types = &types;
+    pending_types = new PendingTypes(Z, 4);
   }
 
   // The type class does not need to be finalized in order to finalize the type,
@@ -1120,10 +1118,8 @@
   // If we are done finalizing a graph of mutually recursive types, check their
   // bounds.
   if (is_root_type) {
-    Type& type = Type::Handle(Z);
-    for (intptr_t i = types.Length() - 1; i >= 0; i--) {
-      type ^= types.At(i);
-      CheckTypeBounds(cls, type);
+    for (intptr_t i = pending_types->length() - 1; i >= 0; i--) {
+      CheckTypeBounds(cls, Type::Cast(pending_types->At(i)));
       if (FLAG_trace_type_finalization && type.IsRecursive()) {
         ISL_Print("Done finalizing recursive type '%s': %s\n",
                   String::Handle(Z, type.Name()).ToCString(),
@@ -2007,7 +2003,7 @@
 
 
 void ClassFinalizer::ApplyMixinType(const Class& mixin_app_class,
-                                    GrowableObjectArray* pending_types) {
+                                    PendingTypes* pending_types) {
   if (mixin_app_class.is_mixin_type_applied()) {
     return;
   }
@@ -2227,7 +2223,8 @@
 
 
 void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
-  HANDLESCOPE(Isolate::Current());
+  Thread* thread = Thread::Current();
+  HANDLESCOPE(thread);
   if (cls.is_type_finalized()) {
     return;
   }
@@ -2360,7 +2357,8 @@
 
 
 void ClassFinalizer::FinalizeClass(const Class& cls) {
-  HANDLESCOPE(Isolate::Current());
+  Thread* thread = Thread::Current();
+  HANDLESCOPE(thread);
   if (cls.is_finalized()) {
     return;
   }
@@ -2990,7 +2988,8 @@
 
 
 void ClassFinalizer::PrintClassInformation(const Class& cls) {
-  HANDLESCOPE(Isolate::Current());
+  Thread* thread = Thread::Current();
+  HANDLESCOPE(thread);
   const String& class_name = String::Handle(cls.Name());
   ISL_Print("class '%s'", class_name.ToCString());
   const Library& library = Library::Handle(cls.library());
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index a43689f..0b8d7c5 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -15,6 +15,8 @@
 // finalized.
 class ClassFinalizer : public AllStatic {
  public:
+  typedef ZoneGrowableHandlePtrArray<const AbstractType> PendingTypes;
+
   // Modes for type resolution and finalization. The ordering is relevant.
   enum FinalizationKind {
     kIgnore,                   // Type is ignored and replaced by dynamic.
@@ -32,7 +34,7 @@
       const Class& cls,
       const AbstractType& type,
       FinalizationKind finalization,
-      GrowableObjectArray* pending_types = NULL);
+      PendingTypes* pending_types = NULL);
 
   // Allocate, finalize, and return a new malformed type as if it was declared
   // in class cls at the given token position.
@@ -95,7 +97,7 @@
 
   // Apply the mixin type to the mixin application class.
   static void ApplyMixinType(const Class& mixin_app_class,
-                             GrowableObjectArray* pending_types = NULL);
+                             PendingTypes* pending_types = NULL);
 
  private:
   static void AllocateEnumValues(const Class& enum_cls);
@@ -130,16 +132,16 @@
   static void ResolveSuperTypeAndInterfaces(const Class& cls,
                                             GrowableArray<intptr_t>* visited);
   static void FinalizeTypeParameters(const Class& cls,
-                                     GrowableObjectArray* pending_types = NULL);
+                                     PendingTypes* pending_types = NULL);
   static void FinalizeTypeArguments(const Class& cls,
                                     const TypeArguments& arguments,
                                     intptr_t num_uninitialized_arguments,
                                     Error* bound_error,
-                                    GrowableObjectArray* pending_types,
+                                    PendingTypes* pending_types,
                                     TrailPtr trail);
   static void CheckRecursiveType(const Class& cls,
                                  const Type& type,
-                                 GrowableObjectArray* pending_types);
+                                 PendingTypes* pending_types);
   static void CheckTypeBounds(const Class& cls, const Type& type);
   static void CheckTypeArgumentBounds(const Class& cls,
                                       const TypeArguments& arguments,
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 4ba0378..8b96530 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -212,9 +212,10 @@
 }
 
 
-static void AddRelatedClassesToList(const Class& cls,
-                                    const GrowableObjectArray& parse_list,
-                                    const GrowableObjectArray& patch_list) {
+static void AddRelatedClassesToList(
+    const Class& cls,
+    GrowableHandlePtrArray<const Class>* parse_list,
+    GrowableHandlePtrArray<const Class>* patch_list) {
   Isolate* isolate = Isolate::Current();
   Class& parse_class = Class::Handle(isolate);
   AbstractType& interface_type = Type::Handle(isolate);
@@ -228,7 +229,7 @@
     interface_type ^= interfaces.At(i);
     parse_class ^= interface_type.type_class();
     if (!parse_class.is_finalized() && !parse_class.is_marked_for_parsing()) {
-      parse_list.Add(parse_class);
+      parse_list->Add(parse_class);
       parse_class.set_is_marked_for_parsing();
     }
   }
@@ -239,7 +240,7 @@
   parse_class ^= cls.SuperClass();
   while (!parse_class.IsNull()) {
     if (!parse_class.is_finalized() && !parse_class.is_marked_for_parsing()) {
-      parse_list.Add(parse_class);
+      parse_list->Add(parse_class);
       parse_class.set_is_marked_for_parsing();
     }
     parse_class ^= parse_class.SuperClass();
@@ -251,7 +252,7 @@
   parse_class ^= cls.patch_class();
   if (!parse_class.IsNull()) {
     if (!parse_class.is_finalized() && !parse_class.is_marked_for_parsing()) {
-      patch_list.Add(parse_class);
+      patch_list->Add(parse_class);
       parse_class.set_is_marked_for_parsing();
     }
   }
@@ -291,20 +292,17 @@
 
   Thread* const thread = Thread::Current();
   Isolate* const isolate = thread->isolate();
+  StackZone zone(thread);
   // We remember all the classes that are being compiled in these lists. This
   // also allows us to reset the marked_for_parsing state in case we see an
   // error.
   VMTagScope tagScope(thread, VMTag::kCompileClassTagId);
-  Class& parse_class = Class::Handle(isolate);
-  const GrowableObjectArray& parse_list =
-      GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New(4));
-  const GrowableObjectArray& patch_list =
-      GrowableObjectArray::Handle(thread->zone(), GrowableObjectArray::New(4));
+  GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4);
+  GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4);
 
   // Parse the class and all the interfaces it implements and super classes.
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
-    StackZone zone(thread);
     if (FLAG_trace_compiler) {
       ISL_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
     }
@@ -321,34 +319,33 @@
     // to it by AddRelatedClassesToList. It is not OK to hoist
     // parse_list.Length() into a local variable and iterate using the local
     // variable.
-    for (intptr_t i = 0; i < parse_list.Length(); i++) {
-      parse_class ^= parse_list.At(i);
-      AddRelatedClassesToList(parse_class, parse_list, patch_list);
+    for (intptr_t i = 0; i < parse_list.length(); i++) {
+      AddRelatedClassesToList(parse_list.At(i), &parse_list, &patch_list);
     }
 
     // Parse all the classes that have been added above.
-    for (intptr_t i = (parse_list.Length() - 1); i >=0 ; i--) {
-      parse_class ^= parse_list.At(i);
+    for (intptr_t i = (parse_list.length() - 1); i >=0 ; i--) {
+      const Class& parse_class = parse_list.At(i);
       ASSERT(!parse_class.IsNull());
       Parser::ParseClass(parse_class);
     }
 
     // Parse all the patch classes that have been added above.
-    for (intptr_t i = 0; i < patch_list.Length(); i++) {
-      parse_class ^= patch_list.At(i);
+    for (intptr_t i = 0; i < patch_list.length(); i++) {
+      const Class& parse_class = patch_list.At(i);
       ASSERT(!parse_class.IsNull());
       Parser::ParseClass(parse_class);
     }
 
     // Finalize these classes.
-    for (intptr_t i = (parse_list.Length() - 1); i >=0 ; i--) {
-      parse_class ^= parse_list.At(i);
+    for (intptr_t i = (parse_list.length() - 1); i >=0 ; i--) {
+      const Class& parse_class = parse_list.At(i);
       ASSERT(!parse_class.IsNull());
       ClassFinalizer::FinalizeClass(parse_class);
       parse_class.reset_is_marked_for_parsing();
     }
-    for (intptr_t i = (patch_list.Length() - 1); i >=0 ; i--) {
-      parse_class ^= patch_list.At(i);
+    for (intptr_t i = (patch_list.length() - 1); i >=0 ; i--) {
+      const Class& parse_class = patch_list.At(i);
       ASSERT(!parse_class.IsNull());
       ClassFinalizer::FinalizeClass(parse_class);
       parse_class.reset_is_marked_for_parsing();
@@ -357,21 +354,18 @@
     return Error::null();
   } else {
     // Reset the marked for parsing flags.
-    for (intptr_t i = 0; i < parse_list.Length(); i++) {
-      parse_class ^= parse_list.At(i);
+    for (intptr_t i = 0; i < parse_list.length(); i++) {
+      const Class& parse_class = parse_list.At(i);
       if (parse_class.is_marked_for_parsing()) {
         parse_class.reset_is_marked_for_parsing();
       }
     }
-    for (intptr_t i = 0; i < patch_list.Length(); i++) {
-      parse_class ^= patch_list.At(i);
+    for (intptr_t i = 0; i < patch_list.length(); i++) {
+      const Class& parse_class = patch_list.At(i);
       if (parse_class.is_marked_for_parsing()) {
         parse_class.reset_is_marked_for_parsing();
       }
     }
-    Thread* const thread = Thread::Current();
-    Isolate* const isolate = Isolate::Current();
-    StackZone zone(thread);
     Error& error = Error::Handle(isolate);
     error = isolate->object_store()->sticky_error();
     isolate->object_store()->clear_sticky_error();
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
index cef0201..7892e37 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -72,7 +72,6 @@
   }
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
   // Make sure we have the unoptimized code for this function available.
   if (Compiler::EnsureUnoptimizedCode(thread, function) != Error::null()) {
     // Ignore the error and this function entirely.
@@ -96,7 +95,7 @@
   PcDescriptors::Iterator iter(descriptors,
       RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall);
   while (iter.MoveNext()) {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
     if (!ic_data->IsNull()) {
       const intptr_t token_pos = iter.TokenPos();
@@ -141,7 +140,8 @@
                               const JSONArray& jsarr,
                               CoverageFilter* filter,
                               bool as_call_sites) {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   if (cls.EnsureIsFinalized(isolate) != Error::null()) {
     // Only classes that have been finalized do have a meaningful list of
     // functions.
@@ -156,7 +156,7 @@
   GrowableArray<intptr_t> pos_to_line;
   int i = 0;
   while (i < functions.Length()) {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     function ^= functions.At(i);
     script = function.script();
     saved_url = script.url();
@@ -201,7 +201,7 @@
     // We need to keep rechecking the length of the closures array, as handling
     // a closure potentially adds new entries to the end.
     while (i < closures.Length()) {
-      HANDLESCOPE(isolate);
+      HANDLESCOPE(thread);
       function ^= closures.At(i);
       script = function.script();
       saved_url = script.url();
@@ -248,7 +248,7 @@
   JSONStream stream;
   PrintJSON(isolate, &stream, NULL, false);
 
-  const char* format = "%s/dart-cov-%" Pd "-%" Pd ".json";
+  const char* format = "%s/dart-cov-%" Pd "-%" Pd64 ".json";
   intptr_t pid = OS::ProcessId();
   intptr_t len = OS::SNPrint(NULL, 0, format,
                              FLAG_coverage_dir, pid, isolate->main_port());
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 70b0504..e59c411 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -113,6 +113,8 @@
   ASSERT(thread_pool_ == NULL);
   thread_pool_ = new ThreadPool();
   {
+    Thread* T = Thread::Current();
+    ASSERT(T != NULL);
     ASSERT(vm_isolate_ == NULL);
     ASSERT(Flags::Initialized());
     const bool is_vm_isolate = true;
@@ -122,9 +124,12 @@
     Dart_IsolateFlags api_flags;
     vm_flags.CopyTo(&api_flags);
     vm_isolate_ = Isolate::Init("vm-isolate", api_flags, is_vm_isolate);
+    // Verify assumptions about executing in the VM isolate.
+    ASSERT(vm_isolate_ == Isolate::Current());
+    ASSERT(vm_isolate_ == Thread::Current()->isolate());
 
-    StackZone zone(vm_isolate_);
-    HandleScope handle_scope(vm_isolate_);
+    StackZone zone(T);
+    HandleScope handle_scope(T);
     Object::InitNull(vm_isolate_);
     ObjectStore::Init(vm_isolate_);
     TargetCPUFeatures::InitOnce();
@@ -142,7 +147,8 @@
       ASSERT(snapshot->kind() == Snapshot::kFull);
       VmIsolateSnapshotReader reader(snapshot->content(),
                                      snapshot->length(),
-                                     zone.GetZone());
+                                     instructions_snapshot,
+                                     T);
       const Error& error = Error::Handle(reader.ReadVmIsolateSnapshot());
       if (!error.IsNull()) {
         return error.ToCString();
@@ -240,37 +246,32 @@
 
 RawError* Dart::InitializeIsolate(const uint8_t* snapshot_buffer, void* data) {
   // Initialize the new isolate.
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  TIMERSCOPE(thread, time_isolate_initialization);
-  TimelineDurationScope tds(isolate,
-                            isolate->GetIsolateStream(),
-                            "InitializeIsolate");
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  TIMERSCOPE(T, time_isolate_initialization);
+  TimelineDurationScope tds(I, I->GetIsolateStream(), "InitializeIsolate");
   tds.SetNumArguments(1);
-  tds.CopyArgument(0, "isolateName", isolate->name());
+  tds.CopyArgument(0, "isolateName", I->name());
 
-  ASSERT(isolate != NULL);
-  StackZone zone(isolate);
-  HandleScope handle_scope(isolate);
+  ASSERT(I != NULL);
+  StackZone zone(T);
+  HandleScope handle_scope(T);
   {
-    TimelineDurationScope tds(isolate,
-                              isolate->GetIsolateStream(),
-                              "ObjectStore::Init");
-    ObjectStore::Init(isolate);
+    TimelineDurationScope tds(I, I->GetIsolateStream(), "ObjectStore::Init");
+    ObjectStore::Init(I);
   }
 
   // Setup for profiling.
-  Profiler::InitProfilingForIsolate(isolate);
+  Profiler::InitProfilingForIsolate(I);
 
-  const Error& error = Error::Handle(Object::Init(isolate));
+  const Error& error = Error::Handle(Object::Init(I));
   if (!error.IsNull()) {
     return error.raw();
   }
   if (snapshot_buffer != NULL) {
     // Read the snapshot and setup the initial state.
-    TimelineDurationScope tds(isolate,
-                              isolate->GetIsolateStream(),
-                              "IsolateSnapshotReader");
+    TimelineDurationScope tds(
+        I, I->GetIsolateStream(), "IsolateSnapshotReader");
     // TODO(turnidge): Remove once length is not part of the snapshot.
     const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_buffer);
     if (snapshot == NULL) {
@@ -284,15 +285,15 @@
     }
     IsolateSnapshotReader reader(snapshot->content(),
                                  snapshot->length(),
-                                 isolate,
-                                 zone.GetZone());
+                                 Object::instructions_snapshot_buffer(),
+                                 T);
     const Error& error = Error::Handle(reader.ReadFullSnapshot());
     if (!error.IsNull()) {
       return error.raw();
     }
     if (FLAG_trace_isolates) {
-      isolate->heap()->PrintSizes();
-      isolate->megamorphic_cache_table()->PrintSizes();
+      I->heap()->PrintSizes();
+      I->megamorphic_cache_table()->PrintSizes();
     }
   } else {
     // Populate the isolate's symbol table with all symbols from the
@@ -305,41 +306,38 @@
   Object::VerifyBuiltinVtables();
 
   {
-    TimelineDurationScope tds(isolate,
-                              isolate->GetIsolateStream(),
-                              "StubCode::Init");
-    StubCode::Init(isolate);
+    TimelineDurationScope tds(I, I->GetIsolateStream(), "StubCode::Init");
+    StubCode::Init(I);
   }
 
-  isolate->megamorphic_cache_table()->InitMissHandler();
+  I->megamorphic_cache_table()->InitMissHandler();
   if (snapshot_buffer == NULL) {
-    if (!isolate->object_store()->PreallocateObjects()) {
-      return isolate->object_store()->sticky_error();
+    if (!I->object_store()->PreallocateObjects()) {
+      return I->object_store()->sticky_error();
     }
   }
 
-  isolate->heap()->EnableGrowthControl();
-  isolate->set_init_callback_data(data);
-  Api::SetupAcquiredError(isolate);
+  I->heap()->EnableGrowthControl();
+  I->set_init_callback_data(data);
+  Api::SetupAcquiredError(I);
   if (FLAG_print_class_table) {
-    isolate->class_table()->Print();
+    I->class_table()->Print();
   }
 
-  ServiceIsolate::MaybeInjectVMServiceLibrary(isolate);
+  ServiceIsolate::MaybeInjectVMServiceLibrary(I);
 
   ServiceIsolate::SendIsolateStartupMessage();
-  isolate->debugger()->NotifyIsolateCreated();
+  I->debugger()->NotifyIsolateCreated();
 
   // Create tag table.
-  isolate->set_tag_table(
-      GrowableObjectArray::Handle(GrowableObjectArray::New()));
+  I->set_tag_table(GrowableObjectArray::Handle(GrowableObjectArray::New()));
   // Set up default UserTag.
   const UserTag& default_tag = UserTag::Handle(UserTag::DefaultTag());
-  isolate->set_current_tag(default_tag);
+  I->set_current_tag(default_tag);
 
   if (FLAG_keep_code) {
-    isolate->set_deoptimized_code_array(
-      GrowableObjectArray::Handle(GrowableObjectArray::New()));
+    I->set_deoptimized_code_array(
+        GrowableObjectArray::Handle(GrowableObjectArray::New()));
   }
   return Error::null();
 }
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 151d669..dcda02a 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -27,6 +27,7 @@
 #include "vm/object_store.h"
 #include "vm/os_thread.h"
 #include "vm/port.h"
+#include "vm/precompiler.h"
 #include "vm/profiler.h"
 #include "vm/resolver.h"
 #include "vm/reusable_handles.h"
@@ -45,6 +46,10 @@
 
 namespace dart {
 
+// Facilitate quick access to the current zone once we have the curren thread.
+#define Z (T->zone())
+
+
 DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, print_class_table);
 DECLARE_FLAG(bool, verify_handles);
@@ -116,15 +121,15 @@
 #endif  // #if defined(DEBUG).
 
 
-static RawInstance* GetListInstance(Isolate* isolate, const Object& obj) {
+static RawInstance* GetListInstance(Zone* zone, const Object& obj) {
   if (obj.IsInstance()) {
-    const Library& core_lib = Library::Handle(Library::CoreLibrary());
+    const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
     const Class& list_class =
-        Class::Handle(core_lib.LookupClass(Symbols::List()));
+        Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
     ASSERT(!list_class.IsNull());
     const Instance& instance = Instance::Cast(obj);
-    const Class& obj_class = Class::Handle(isolate, obj.clazz());
-    Error& malformed_type_error = Error::Handle(isolate);
+    const Class& obj_class = Class::Handle(zone, obj.clazz());
+    Error& malformed_type_error = Error::Handle(zone);
     if (obj_class.IsSubtypeOf(Object::null_type_arguments(),
                               list_class,
                               Object::null_type_arguments(),
@@ -136,15 +141,15 @@
   return Instance::null();
 }
 
-static RawInstance* GetMapInstance(Isolate* isolate, const Object& obj) {
+static RawInstance* GetMapInstance(Zone* zone, const Object& obj) {
   if (obj.IsInstance()) {
-    const Library& core_lib = Library::Handle(Library::CoreLibrary());
+    const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
     const Class& map_class =
         Class::Handle(core_lib.LookupClass(Symbols::Map()));
     ASSERT(!map_class.IsNull());
     const Instance& instance = Instance::Cast(obj);
-    const Class& obj_class = Class::Handle(isolate, obj.clazz());
-    Error& malformed_type_error = Error::Handle(isolate);
+    const Class& obj_class = Class::Handle(zone, obj.clazz());
+    Error& malformed_type_error = Error::Handle(zone);
     if (obj_class.IsSubtypeOf(Object::null_type_arguments(),
                               map_class,
                               Object::null_type_arguments(),
@@ -443,25 +448,22 @@
 
 
 Dart_Handle Api::NewError(const char* format, ...) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  Zone* zone = thread->zone();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
   va_list args;
   va_start(args, format);
   intptr_t len = OS::VSNPrint(NULL, 0, format, args);
   va_end(args);
 
-  char* buffer = zone->Alloc<char>(len + 1);
+  char* buffer = Z->Alloc<char>(len + 1);
   va_list args2;
   va_start(args2, format);
   OS::VSNPrint(buffer, (len + 1), format, args2);
   va_end(args2);
 
-  const String& message = String::Handle(zone, String::New(buffer));
-  return Api::NewHandle(isolate, ApiError::New(message));
+  const String& message = String::Handle(Z, String::New(buffer));
+  return Api::NewHandle(I, ApiError::New(message));
 }
 
 
@@ -745,14 +747,13 @@
 
 
 DART_EXPORT const char* Dart_GetError(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsError()) {
     const Error& error = Error::Cast(obj);
     const char* str = error.ToErrorCString();
     intptr_t len = strlen(str) + 1;
-    char* str_copy = Api::TopScope(isolate)->zone()->Alloc<char>(len);
+    char* str_copy = Api::TopScope(I)->zone()->Alloc<char>(len);
     strncpy(str_copy, str, len);
     // Strip a possible trailing '\n'.
     if ((len > 1) && (str_copy[len - 2] == '\n')) {
@@ -766,20 +767,18 @@
 
 
 DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   return obj.IsUnhandledException();
 }
 
 
 DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsUnhandledException()) {
     const UnhandledException& error = UnhandledException::Cast(obj);
-    return Api::NewHandle(isolate, error.exception());
+    return Api::NewHandle(I, error.exception());
   } else if (obj.IsError()) {
     return Api::NewError("This error is not an unhandled exception error.");
   } else {
@@ -789,12 +788,11 @@
 
 
 DART_EXPORT Dart_Handle Dart_ErrorGetStacktrace(Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsUnhandledException()) {
     const UnhandledException& error = UnhandledException::Cast(obj);
-    return Api::NewHandle(isolate, error.stacktrace());
+    return Api::NewHandle(I, error.stacktrace());
   } else if (obj.IsError()) {
     return Api::NewError("This error is not an unhandled exception error.");
   } else {
@@ -806,32 +804,30 @@
 // TODO(turnidge): This clones Api::NewError.  I need to use va_copy to
 // fix this but not sure if it available on all of our builds.
 DART_EXPORT Dart_Handle Dart_NewApiError(const char* error) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  const String& message = String::Handle(isolate, String::New(error));
-  return Api::NewHandle(isolate, ApiError::New(message));
+  const String& message = String::Handle(Z, String::New(error));
+  return Api::NewHandle(I, ApiError::New(message));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  Instance& obj = Instance::Handle(isolate);
+  Instance& obj = Instance::Handle(Z);
   intptr_t class_id = Api::ClassId(exception);
   if ((class_id == kApiErrorCid) || (class_id == kLanguageErrorCid)) {
     obj = String::New(::Dart_GetError(exception));
   } else {
-    obj = Api::UnwrapInstanceHandle(isolate, exception).raw();
+    obj = Api::UnwrapInstanceHandle(I, exception).raw();
     if (obj.IsNull()) {
-      RETURN_TYPE_ERROR(isolate, exception, Instance);
+      RETURN_TYPE_ERROR(I, exception, Instance);
     }
   }
-  const Stacktrace& stacktrace = Stacktrace::Handle(isolate);
-  return Api::NewHandle(isolate, UnhandledException::New(obj, stacktrace));
+  const Stacktrace& stacktrace = Stacktrace::Handle(Z);
+  return Api::NewHandle(I, UnhandledException::New(obj, stacktrace));
 }
 
 
@@ -883,34 +879,32 @@
 
 
 DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
   if (obj.IsString()) {
-    return Api::NewHandle(isolate, obj.raw());
+    return Api::NewHandle(I, obj.raw());
   } else if (obj.IsInstance()) {
-    CHECK_CALLBACK_STATE(isolate);
+    CHECK_CALLBACK_STATE(I);
     const Instance& receiver = Instance::Cast(obj);
-    return Api::NewHandle(isolate, DartLibraryCalls::ToString(receiver));
+    return Api::NewHandle(I, DartLibraryCalls::ToString(receiver));
   } else {
-    CHECK_CALLBACK_STATE(isolate);
+    CHECK_CALLBACK_STATE(I);
     // This is a VM internal object. Call the C++ method of printing.
-    return Api::NewHandle(isolate, String::New(obj.ToCString()));
+    return Api::NewHandle(I, String::New(obj.ToCString()));
   }
 }
 
 
 DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   {
     NoSafepointScope no_safepoint_scope;
     if (Api::UnwrapHandle(obj1) == Api::UnwrapHandle(obj2)) {
       return true;
     }
   }
-  const Object& object1 = Object::Handle(isolate, Api::UnwrapHandle(obj1));
-  const Object& object2 = Object::Handle(isolate, Api::UnwrapHandle(obj2));
+  const Object& object1 = Object::Handle(Z, Api::UnwrapHandle(obj1));
+  const Object& object2 = Object::Handle(Z, Api::UnwrapHandle(obj2));
   if (object1.IsInstance() && object2.IsInstance()) {
     return Instance::Cast(object1).IsIdenticalTo(Instance::Cast(object2));
   }
@@ -919,29 +913,27 @@
 
 
 DART_EXPORT uint64_t Dart_IdentityHash(Dart_Handle obj) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
-  const Object& object = Object::Handle(isolate, Api::UnwrapHandle(obj));
+  const Object& object = Object::Handle(Z, Api::UnwrapHandle(obj));
   if (!object.IsInstance() && !object.IsNull()) {
     return 0;
   }
 
-  const Library& libcore = Library::Handle(isolate, Library::CoreLibrary());
-  const String& function_name = String::Handle(isolate,
+  const Library& libcore = Library::Handle(Z, Library::CoreLibrary());
+  const String& function_name = String::Handle(Z,
                                                String::New("identityHashCode"));
   const Function& function =
-      Function::Handle(isolate,
-                       libcore.LookupFunctionAllowPrivate(function_name));
+      Function::Handle(Z, libcore.LookupFunctionAllowPrivate(function_name));
   if (function.IsNull()) {
     UNREACHABLE();
     return 0;
   }
 
-  const Array& arguments = Array::Handle(isolate, Array::New(1));
+  const Array& arguments = Array::Handle(Z, Array::New(1));
   arguments.SetAt(0, object);
   const Object& result =
-      Object::Handle(isolate, DartEntry::InvokeFunction(function, arguments));
+      Object::Handle(Z, DartEntry::InvokeFunction(function, arguments));
 
   if (result.IsSmi()) {
     return Smi::Cast(result).Value();
@@ -986,11 +978,10 @@
 
 
 DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  ApiState* state = isolate->api_state();
+  DARTSCOPE(Thread::Current());
+  ApiState* state = I->api_state();
   ASSERT(state != NULL);
-  const Object& old_ref = Object::Handle(isolate, Api::UnwrapHandle(object));
+  const Object& old_ref = Object::Handle(Z, Api::UnwrapHandle(object));
   PersistentHandle* new_ref = state->persistent_handles().AllocateHandle();
   new_ref->set_raw(old_ref);
   return new_ref->apiHandle();
@@ -999,12 +990,11 @@
 
 DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
                                           Dart_Handle obj2) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  ApiState* state = isolate->api_state();
+  DARTSCOPE(Thread::Current());
+  ApiState* state = I->api_state();
   ASSERT(state != NULL);
   ASSERT(state->IsValidPersistentHandle(obj1));
-  const Object& obj2_ref = Object::Handle(isolate, Api::UnwrapHandle(obj2));
+  const Object& obj2_ref = Object::Handle(Z, Api::UnwrapHandle(obj2));
   PersistentHandle* obj1_ref = PersistentHandle::Cast(obj1);
   obj1_ref->set_raw(obj2_ref);
 }
@@ -1365,18 +1355,18 @@
     vm_flags.CopyTo(&api_flags);
     flags = &api_flags;
   }
-  Isolate* isolate = Dart::CreateIsolate(isolate_name, *flags);
+  Isolate* I = Dart::CreateIsolate(isolate_name, *flags);
   free(isolate_name);
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    Thread* T = Thread::Current();
+    StackZone zone(T);
+    HANDLESCOPE(T);
     // We enter an API scope here as InitializeIsolate could compile some
     // bootstrap library files which call out to a tag handler that may create
     // Api Handles when an error is encountered.
     Dart_EnterScope();
     const Error& error_obj =
-        Error::Handle(isolate,
-                      Dart::InitializeIsolate(snapshot, callback_data));
+        Error::Handle(Z, Dart::InitializeIsolate(snapshot, callback_data));
     if (error_obj.IsNull()) {
   #if defined(DART_NO_SNAPSHOT)
       if (FLAG_check_function_fingerprints) {
@@ -1385,8 +1375,8 @@
   #endif  // defined(DART_NO_SNAPSHOT).
       // We exit the API scope entered above.
       Dart_ExitScope();
-      START_TIMER(isolate, time_total_runtime);
-      return Api::CastIsolate(isolate);
+      START_TIMER(I, time_total_runtime);
+      return Api::CastIsolate(I);
     }
     *error = strdup(error_obj.ToErrorCString());
     // We exit the API scope entered above.
@@ -1398,14 +1388,15 @@
 
 
 DART_EXPORT void Dart_ShutdownIsolate() {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE(isolate);
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  CHECK_ISOLATE(I);
   {
-    StackZone zone(isolate);
-    HandleScope handle_scope(isolate);
+    StackZone zone(T);
+    HandleScope handle_scope(T);
     Dart::RunShutdownCallback();
   }
-  STOP_TIMER(isolate, time_total_runtime);
+  STOP_TIMER(I, time_total_runtime);
   Dart::ShutdownIsolate();
 }
 
@@ -1434,9 +1425,8 @@
 
 
 DART_EXPORT Dart_Handle Dart_DebugName() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  return Api::NewHandle(isolate, String::New(isolate->name()));
+  DARTSCOPE(Thread::Current());
+  return Api::NewHandle(I, String::New(I->name()));
 }
 
 
@@ -1512,10 +1502,8 @@
     uint8_t** isolate_snapshot_buffer,
     intptr_t* isolate_snapshot_size) {
   ASSERT(FLAG_load_deferred_eagerly);
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_creating_snapshot);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_creating_snapshot);
   if (vm_isolate_snapshot_buffer != NULL &&
       vm_isolate_snapshot_size == NULL) {
     RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -1527,22 +1515,24 @@
     RETURN_NULL_ERROR(isolate_snapshot_size);
   }
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
   if (::Dart_IsError(state)) {
     return state;
   }
-  isolate->heap()->CollectAllGarbage();
+  I->heap()->CollectAllGarbage();
 #if defined(DEBUG)
-  FunctionVisitor check_canonical(isolate);
-  isolate->heap()->IterateObjects(&check_canonical);
+  FunctionVisitor check_canonical(I);
+  I->heap()->IterateObjects(&check_canonical);
 #endif  // #if defined(DEBUG).
 
   // Since this is only a snapshot the root library should not be set.
-  isolate->object_store()->set_root_library(Library::Handle(isolate));
+  I->object_store()->set_root_library(Library::Handle(Z));
   FullSnapshotWriter writer(vm_isolate_snapshot_buffer,
                             isolate_snapshot_buffer,
+                            NULL, /* instructions_snapshot_buffer */
                             ApiReallocate,
-                            false /* snapshot_code */);
+                            false, /* snapshot_code */
+                            true /* vm_isolate_is_symbolic */);
   writer.WriteFullSnapshot();
   *vm_isolate_snapshot_size = writer.VmIsolateSnapshotSize();
   *isolate_snapshot_size = writer.IsolateSnapshotSize();
@@ -1553,10 +1543,8 @@
 static Dart_Handle createLibrarySnapshot(Dart_Handle library,
                                          uint8_t** buffer,
                                          intptr_t* size) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_creating_snapshot);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_creating_snapshot);
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
   }
@@ -1564,20 +1552,20 @@
     RETURN_NULL_ERROR(size);
   }
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
   if (::Dart_IsError(state)) {
     return state;
   }
-  Library& lib = Library::Handle(isolate);
+  Library& lib = Library::Handle(Z);
   if (library == Dart_Null()) {
-    lib ^= isolate->object_store()->root_library();
+    lib ^= I->object_store()->root_library();
   } else {
     lib ^= Api::UnwrapHandle(library);
   }
-  isolate->heap()->CollectAllGarbage();
+  I->heap()->CollectAllGarbage();
 #if defined(DEBUG)
-  FunctionVisitor check_canonical(isolate);
-  isolate->heap()->IterateObjects(&check_canonical);
+  FunctionVisitor check_canonical(I);
+  I->heap()->IterateObjects(&check_canonical);
 #endif  // #if defined(DEBUG).
   ScriptSnapshotWriter writer(buffer, ApiReallocate);
   writer.WriteScriptSnapshot(lib);
@@ -1660,9 +1648,10 @@
 
 
 DART_EXPORT Dart_Handle Dart_RunLoop() {
-  Isolate* isolate = Isolate::Current();
-  CHECK_ISOLATE_SCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  CHECK_ISOLATE_SCOPE(I);
+  CHECK_CALLBACK_STATE(I);
   Monitor monitor;
   MonitorLocker ml(&monitor);
   {
@@ -1671,22 +1660,21 @@
     RunLoopData data;
     data.monitor = &monitor;
     data.done = false;
-    isolate->message_handler()->Run(
+    I->message_handler()->Run(
         Dart::thread_pool(),
         NULL, RunLoopDone, reinterpret_cast<uword>(&data));
     while (!data.done) {
       ml.Wait();
     }
   }
-  if (isolate->object_store()->sticky_error() != Object::null()) {
-    Dart_Handle error = Api::NewHandle(isolate,
-                                       isolate->object_store()->sticky_error());
-    isolate->object_store()->clear_sticky_error();
+  if (I->object_store()->sticky_error() != Object::null()) {
+    Dart_Handle error = Api::NewHandle(I, I->object_store()->sticky_error());
+    I->object_store()->clear_sticky_error();
     return error;
   }
   if (FLAG_print_class_table) {
-    HANDLESCOPE(isolate);
-    isolate->class_table()->Print();
+    HANDLESCOPE(T);
+    I->class_table()->Print();
   }
   return Api::Success();
 }
@@ -1738,12 +1726,11 @@
 
 
 DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle handle) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (port_id == ILLEGAL_PORT) {
     return false;
   }
-  const Object& object = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  const Object& object = Object::Handle(Z, Api::UnwrapHandle(handle));
   uint8_t* data = NULL;
   MessageWriter writer(&data, &allocator, false);
   writer.WriteMessage(object);
@@ -1754,26 +1741,24 @@
 
 
 DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
   if (port_id == ILLEGAL_PORT) {
     return Api::NewError("%s: illegal port_id %" Pd64 ".",
                          CURRENT_FUNC,
                          port_id);
   }
-  return Api::NewHandle(isolate, SendPort::New(port_id));
+  return Api::NewHandle(I, SendPort::New(port_id));
 }
 
 
 DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
                                            Dart_Port* port_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const SendPort& send_port = Api::UnwrapSendPortHandle(isolate, port);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  const SendPort& send_port = Api::UnwrapSendPortHandle(I, port);
   if (send_port.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, port, SendPort);
+    RETURN_TYPE_ERROR(I, port, SendPort);
   }
   if (port_id == NULL) {
     RETURN_NULL_ERROR(port_id);
@@ -1869,22 +1854,19 @@
 
 DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1, Dart_Handle obj2,
                                           bool* value) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  Zone* zone = thread->zone();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
   const Instance& expected =
-      Instance::CheckedHandle(zone, Api::UnwrapHandle(obj1));
+      Instance::CheckedHandle(Z, Api::UnwrapHandle(obj1));
   const Instance& actual =
-      Instance::CheckedHandle(zone, Api::UnwrapHandle(obj2));
+      Instance::CheckedHandle(Z, Api::UnwrapHandle(obj2));
   const Object& result =
-      Object::Handle(zone, DartLibraryCalls::Equals(expected, actual));
+      Object::Handle(Z, DartLibraryCalls::Equals(expected, actual));
   if (result.IsBool()) {
     *value = Bool::Cast(result).value();
     return Api::Success();
   } else if (result.IsError()) {
-    return Api::NewHandle(isolate, result.raw());
+    return Api::NewHandle(I, result.raw());
   } else {
     return Api::NewError("Expected boolean result from ==");
   }
@@ -1897,13 +1879,12 @@
 DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
                                           Dart_Handle type,
                                           bool* value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
-  const Type& type_obj = Api::UnwrapTypeHandle(isolate, type);
+  const Type& type_obj = Api::UnwrapTypeHandle(I, type);
   if (type_obj.IsNull()) {
     *value = false;
-    RETURN_TYPE_ERROR(isolate, type, Type);
+    RETURN_TYPE_ERROR(I, type, Type);
   }
   if (!type_obj.IsFinalized()) {
     return Api::NewError(
@@ -1914,13 +1895,13 @@
     *value = false;
     return Api::Success();
   }
-  const Instance& instance = Api::UnwrapInstanceHandle(isolate, object);
+  const Instance& instance = Api::UnwrapInstanceHandle(I, object);
   if (instance.IsNull()) {
     *value = false;
-    RETURN_TYPE_ERROR(isolate, object, Instance);
+    RETURN_TYPE_ERROR(I, object, Instance);
   }
-  CHECK_CALLBACK_STATE(isolate);
-  Error& malformed_type_error = Error::Handle(isolate);
+  CHECK_CALLBACK_STATE(I);
+  Error& malformed_type_error = Error::Handle(Z);
   *value = instance.IsInstanceOf(type_obj,
                                  Object::null_type_arguments(),
                                  &malformed_type_error);
@@ -1987,18 +1968,16 @@
     return true;
   }
 
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-  return GetListInstance(isolate, obj) != Instance::null();
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
+  return GetListInstance(Z, obj) != Instance::null();
 }
 
 
 DART_EXPORT bool Dart_IsMap(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-  return GetMapInstance(isolate, obj) != Instance::null();
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
+  return GetMapInstance(Z, obj) != Instance::null();
 }
 
 
@@ -2061,15 +2040,14 @@
 
 DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
   TRACE_API_CALL(CURRENT_FUNC);
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsInstance()) {
     const Class& future_class =
-        Class::Handle(isolate->object_store()->future_class());
+        Class::Handle(I->object_store()->future_class());
     ASSERT(!future_class.IsNull());
-    const Class& obj_class = Class::Handle(isolate, obj.clazz());
-    Error& malformed_type_error = Error::Handle(isolate);
+    const Class& obj_class = Class::Handle(Z, obj.clazz());
+    Error& malformed_type_error = Error::Handle(Z);
     bool is_future = obj_class.IsSubtypeOf(Object::null_type_arguments(),
                                            future_class,
                                            Object::null_type_arguments(),
@@ -2084,17 +2062,16 @@
 // --- Instances ----
 
 DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(instance));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(instance));
   if (obj.IsNull()) {
-    return Api::NewHandle(isolate, isolate->object_store()->null_type());
+    return Api::NewHandle(I, I->object_store()->null_type());
   }
   if (!obj.IsInstance()) {
-    RETURN_TYPE_ERROR(isolate, instance, Instance);
+    RETURN_TYPE_ERROR(I, instance, Instance);
   }
   const Type& type = Type::Handle(Instance::Cast(obj).GetType());
-  return Api::NewHandle(isolate, type.Canonicalize());
+  return Api::NewHandle(I, type.Canonicalize());
 }
 
 
@@ -2103,7 +2080,8 @@
 DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
                                                   bool* fits) {
   // Fast path for Smis and Mints.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   intptr_t class_id = Api::ClassId(integer);
   if (class_id == kSmiCid || class_id == kMintCid) {
@@ -2111,7 +2089,7 @@
     return Api::Success();
   }
   // Slow path for Mints and Bigints.
-  DARTSCOPE(isolate);
+  DARTSCOPE(thread);
   const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer);
   if (int_obj.IsNull()) {
     RETURN_TYPE_ERROR(isolate, integer, Integer);
@@ -2125,14 +2103,15 @@
 DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer,
                                                    bool* fits) {
   // Fast path for Smis.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   if (Api::IsSmi(integer)) {
     *fits = (Api::SmiValue(integer) >= 0);
     return Api::Success();
   }
   // Slow path for Mints and Bigints.
-  DARTSCOPE(isolate);
+  DARTSCOPE(thread);
   const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer);
   if (int_obj.IsNull()) {
     RETURN_TYPE_ERROR(isolate, integer, Integer);
@@ -2149,47 +2128,47 @@
 
 DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value) {
   // Fast path for Smis.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   if (Smi::IsValid(value)) {
-    NOHANDLESCOPE(isolate);
+    NOHANDLESCOPE(thread);
     return Api::NewHandle(isolate, Smi::New(static_cast<intptr_t>(value)));
   }
   // Slow path for Mints and Bigints.
-  DARTSCOPE(isolate);
+  DARTSCOPE(thread);
   CHECK_CALLBACK_STATE(isolate);
   return Api::NewHandle(isolate, Integer::New(value));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, Integer::NewFromUint64(value));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, Integer::NewFromUint64(value));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* str) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const String& str_obj = String::Handle(isolate, String::New(str));
-  return Api::NewHandle(isolate, Integer::New(str_obj));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  const String& str_obj = String::Handle(Z, String::New(str));
+  return Api::NewHandle(I, Integer::New(str_obj));
 }
 
 
 DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer,
                                             int64_t* value) {
   // Fast path for Smis.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   if (Api::IsSmi(integer)) {
     *value = Api::SmiValue(integer);
     return Api::Success();
   }
   // Slow path for Mints and Bigints.
-  DARTSCOPE(isolate);
+  DARTSCOPE(thread);
   const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer);
   if (int_obj.IsNull()) {
     RETURN_TYPE_ERROR(isolate, integer, Integer);
@@ -2213,7 +2192,8 @@
 DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
                                              uint64_t* value) {
   // Fast path for Smis.
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   if (Api::IsSmi(integer)) {
     intptr_t smi_value = Api::SmiValue(integer);
@@ -2223,7 +2203,7 @@
     }
   }
   // Slow path for Mints and Bigints.
-  DARTSCOPE(isolate);
+  DARTSCOPE(thread);
   const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer);
   if (int_obj.IsNull()) {
     RETURN_TYPE_ERROR(isolate, integer, Integer);
@@ -2252,14 +2232,13 @@
 
 DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
                                                  const char** value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer);
+  DARTSCOPE(Thread::Current());
+  const Integer& int_obj = Api::UnwrapIntegerHandle(I, integer);
   if (int_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, integer, Integer);
+    RETURN_TYPE_ERROR(I, integer, Integer);
   }
   if (int_obj.IsSmi() || int_obj.IsMint()) {
-    const Bigint& bigint = Bigint::Handle(isolate,
+    const Bigint& bigint = Bigint::Handle(Z,
         Bigint::NewFromInt64(int_obj.AsInt64Value()));
     *value = bigint.ToHexCString(BigintAllocate);
   } else {
@@ -2270,20 +2249,18 @@
 
 
 DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, Double::New(value));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, Double::New(value));
 }
 
 
 DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj,
                                          double* value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Double& obj = Api::UnwrapDoubleHandle(isolate, double_obj);
+  DARTSCOPE(Thread::Current());
+  const Double& obj = Api::UnwrapDoubleHandle(I, double_obj);
   if (obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, double_obj, Double);
+    RETURN_TYPE_ERROR(I, double_obj, Double);
   }
   *value = obj.value();
   return Api::Success();
@@ -2313,11 +2290,10 @@
 
 DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj,
                                           bool* value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Bool& obj = Api::UnwrapBoolHandle(isolate, boolean_obj);
+  DARTSCOPE(Thread::Current());
+  const Bool& obj = Api::UnwrapBoolHandle(I, boolean_obj);
   if (obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, boolean_obj, Bool);
+    RETURN_TYPE_ERROR(I, boolean_obj, Bool);
   }
   *value = obj.value();
   return Api::Success();
@@ -2341,20 +2317,18 @@
 
 
 DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (str == NULL) {
     RETURN_NULL_ERROR(str);
   }
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, String::New(str));
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, String::New(str));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array,
                                                intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (utf8_array == NULL && length != 0) {
     RETURN_NULL_ERROR(utf8_array);
   }
@@ -2363,34 +2337,32 @@
     return Api::NewError("%s expects argument 'str' to be valid UTF-8.",
                          CURRENT_FUNC);
   }
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, String::FromUTF8(utf8_array, length));
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, String::FromUTF8(utf8_array, length));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
                                                 intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (utf16_array == NULL && length != 0) {
     RETURN_NULL_ERROR(utf16_array);
   }
   CHECK_LENGTH(length, String::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, String::FromUTF16(utf16_array, length));
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, String::FromUTF16(utf16_array, length));
 }
 
 
 DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
                                                 intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (utf32_array == NULL && length != 0) {
     RETURN_NULL_ERROR(utf32_array);
   }
   CHECK_LENGTH(length, String::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, String::FromUTF32(utf32_array, length));
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, String::FromUTF32(utf32_array, length));
 }
 
 
@@ -2399,19 +2371,18 @@
     intptr_t length,
     void* peer,
     Dart_PeerFinalizer cback) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (latin1_array == NULL && length != 0) {
     RETURN_NULL_ERROR(latin1_array);
   }
   CHECK_LENGTH(length, String::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate,
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I,
                         String::NewExternal(latin1_array,
                                             length,
                                             peer,
                                             cback,
-                                            SpaceForExternal(isolate, length)));
+                                            SpaceForExternal(I, length)));
 }
 
 
@@ -2419,36 +2390,34 @@
                                                     intptr_t length,
                                                     void* peer,
                                                     Dart_PeerFinalizer cback) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (utf16_array == NULL && length != 0) {
     RETURN_NULL_ERROR(utf16_array);
   }
   CHECK_LENGTH(length, String::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
   intptr_t bytes = length * sizeof(*utf16_array);
-  return Api::NewHandle(isolate,
+  return Api::NewHandle(I,
                         String::NewExternal(utf16_array,
                                             length,
                                             peer,
                                             cback,
-                                            SpaceForExternal(isolate, bytes)));
+                                            SpaceForExternal(I, bytes)));
 }
 
 
 DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object,
                                              const char** cstr) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (cstr == NULL) {
     RETURN_NULL_ERROR(cstr);
   }
-  const String& str_obj = Api::UnwrapStringHandle(isolate, object);
+  const String& str_obj = Api::UnwrapStringHandle(I, object);
   if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, object, String);
+    RETURN_TYPE_ERROR(I, object, String);
   }
   intptr_t string_length = Utf8::Length(str_obj);
-  char* res = Api::TopScope(isolate)->zone()->Alloc<char>(string_length + 1);
+  char* res = Api::TopScope(I)->zone()->Alloc<char>(string_length + 1);
   if (res == NULL) {
     return Api::NewError("Unable to allocate memory");
   }
@@ -2463,20 +2432,19 @@
 DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str,
                                           uint8_t** utf8_array,
                                           intptr_t* length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (utf8_array == NULL) {
     RETURN_NULL_ERROR(utf8_array);
   }
   if (length == NULL) {
     RETURN_NULL_ERROR(length);
   }
-  const String& str_obj = Api::UnwrapStringHandle(isolate, str);
+  const String& str_obj = Api::UnwrapStringHandle(I, str);
   if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, str, String);
+    RETURN_TYPE_ERROR(I, str, String);
   }
   intptr_t str_len = Utf8::Length(str_obj);
-  *utf8_array = Api::TopScope(isolate)->zone()->Alloc<uint8_t>(str_len);
+  *utf8_array = Api::TopScope(I)->zone()->Alloc<uint8_t>(str_len);
   if (*utf8_array == NULL) {
     return Api::NewError("Unable to allocate memory");
   }
@@ -2489,17 +2457,16 @@
 DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str,
                                             uint8_t* latin1_array,
                                             intptr_t* length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (latin1_array == NULL) {
     RETURN_NULL_ERROR(latin1_array);
   }
   if (length == NULL) {
     RETURN_NULL_ERROR(length);
   }
-  const String& str_obj = Api::UnwrapStringHandle(isolate, str);
+  const String& str_obj = Api::UnwrapStringHandle(I, str);
   if (str_obj.IsNull() || !str_obj.IsOneByteString()) {
-    RETURN_TYPE_ERROR(isolate, str, String);
+    RETURN_TYPE_ERROR(I, str, String);
   }
   intptr_t str_len = str_obj.Length();
   intptr_t copy_len = (str_len > *length) ? *length : str_len;
@@ -2517,11 +2484,10 @@
 DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str,
                                            uint16_t* utf16_array,
                                            intptr_t* length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const String& str_obj = Api::UnwrapStringHandle(isolate, str);
+  DARTSCOPE(Thread::Current());
+  const String& str_obj = Api::UnwrapStringHandle(I, str);
   if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, str, String);
+    RETURN_TYPE_ERROR(I, str, String);
   }
   intptr_t str_len = str_obj.Length();
   intptr_t copy_len = (str_len > *length) ? *length : str_len;
@@ -2555,14 +2521,13 @@
                                                 intptr_t length,
                                                 void* peer,
                                                 Dart_PeerFinalizer cback) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const String& str_obj = Api::UnwrapStringHandle(isolate, str);
+  DARTSCOPE(Thread::Current());
+  const String& str_obj = Api::UnwrapStringHandle(I, str);
   if (str_obj.IsExternal()) {
     return str;  // String is already an external string.
   }
   if (str_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, str, String);
+    RETURN_TYPE_ERROR(I, str, String);
   }
   if (array == NULL) {
     RETURN_NULL_ERROR(array);
@@ -2599,8 +2564,7 @@
     }
     return str;
   }
-  return Api::NewHandle(isolate,
-                        str_obj.MakeExternal(array, length, peer, cback));
+  return Api::NewHandle(I, str_obj.MakeExternal(array, length, peer, cback));
 }
 
 
@@ -2631,65 +2595,60 @@
 // --- Lists ---
 
 DART_EXPORT Dart_Handle Dart_NewList(intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_LENGTH(length, Array::kMaxElements);
-  CHECK_CALLBACK_STATE(isolate);
-  return Api::NewHandle(isolate, Array::New(length));
+  CHECK_CALLBACK_STATE(I);
+  return Api::NewHandle(I, Array::New(length));
 }
 
 
-#define GET_LIST_LENGTH(isolate, type, obj, len)                               \
-  type& array = type::Handle(isolate);                                         \
+#define GET_LIST_LENGTH(zone, type, obj, len)                                  \
+  type& array = type::Handle(zone);                                            \
   array ^= obj.raw();                                                          \
   *len = array.Length();                                                       \
   return Api::Success();                                                       \
 
 
 DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* len) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsError()) {
     // Pass through errors.
     return list;
   }
   if (obj.IsTypedData()) {
-    GET_LIST_LENGTH(isolate, TypedData, obj, len);
+    GET_LIST_LENGTH(Z, TypedData, obj, len);
   }
   if (obj.IsArray()) {
-    GET_LIST_LENGTH(isolate, Array, obj, len);
+    GET_LIST_LENGTH(Z, Array, obj, len);
   }
   if (obj.IsGrowableObjectArray()) {
-    GET_LIST_LENGTH(isolate, GrowableObjectArray, obj, len);
+    GET_LIST_LENGTH(Z, GrowableObjectArray, obj, len);
   }
   if (obj.IsExternalTypedData()) {
-    GET_LIST_LENGTH(isolate, ExternalTypedData, obj, len);
+    GET_LIST_LENGTH(Z, ExternalTypedData, obj, len);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   // Now check and handle a dart object that implements the List interface.
-  const Instance& instance =
-      Instance::Handle(isolate, GetListInstance(isolate, obj));
+  const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
   if (instance.IsNull()) {
     return Api::NewError("Object does not implement the List interface");
   }
-  const String& name = String::Handle(Field::GetterName(Symbols::Length()));
+  const String& name = String::Handle(Z, Field::GetterName(Symbols::Length()));
   const int kNumArgs = 1;
   ArgumentsDescriptor args_desc(
-      Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
+      Array::Handle(Z, ArgumentsDescriptor::New(kNumArgs)));
   const Function& function =
-      Function::Handle(isolate, Resolver::ResolveDynamic(instance,
-                                                         name,
-                                                         args_desc));
+      Function::Handle(Z, Resolver::ResolveDynamic(instance, name, args_desc));
   if (function.IsNull()) {
     return Api::NewError("List object does not have a 'length' field.");
   }
 
-  const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+  const Array& args = Array::Handle(Z, Array::New(kNumArgs));
   args.SetAt(0, instance);  // Set up the receiver as the first argument.
   const Object& retval =
-    Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
+    Object::Handle(Z, DartEntry::InvokeFunction(function, args));
   if (retval.IsSmi()) {
     *len = Smi::Cast(retval).Value();
     return Api::Success();
@@ -2713,7 +2672,7 @@
     return Api::NewError("Length of List object is greater than the "
                          "maximum value that 'len' parameter can hold");
   } else if (retval.IsError()) {
-    return Api::NewHandle(isolate, retval.raw());
+    return Api::NewHandle(I, retval.raw());
   } else {
     return Api::NewError("Length of List object is not an integer");
   }
@@ -2729,25 +2688,23 @@
 
 
 DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsArray()) {
-    GET_LIST_ELEMENT(isolate, Array, obj, index);
+    GET_LIST_ELEMENT(I, Array, obj, index);
   } else if (obj.IsGrowableObjectArray()) {
-    GET_LIST_ELEMENT(isolate, GrowableObjectArray, obj, index);
+    GET_LIST_ELEMENT(I, GrowableObjectArray, obj, index);
   } else if (obj.IsError()) {
     return list;
   } else {
-    CHECK_CALLBACK_STATE(isolate);
+    CHECK_CALLBACK_STATE(I);
     // Check and handle a dart object that implements the List interface.
-    const Instance& instance =
-        Instance::Handle(isolate, GetListInstance(isolate, obj));
+    const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
     if (!instance.IsNull()) {
-      return Api::NewHandle(isolate, Send1Arg(
+      return Api::NewHandle(I, Send1Arg(
           instance,
           Symbols::IndexToken(),
-          Instance::Handle(isolate, Integer::New(index))));
+          Instance::Handle(Z, Integer::New(index))));
     }
     return Api::NewError("Object does not implement the 'List' interface");
   }
@@ -2769,40 +2726,37 @@
                                           intptr_t offset,
                                           intptr_t length,
                                           Dart_Handle* result) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (result == NULL) {
     RETURN_NULL_ERROR(result);
   }
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsArray()) {
-    GET_LIST_RANGE(isolate, Array, obj, offset, length);
+    GET_LIST_RANGE(I, Array, obj, offset, length);
   } else if (obj.IsGrowableObjectArray()) {
-    GET_LIST_RANGE(isolate, GrowableObjectArray, obj, offset, length);
+    GET_LIST_RANGE(I, GrowableObjectArray, obj, offset, length);
   } else if (obj.IsError()) {
     return list;
   } else {
-    CHECK_CALLBACK_STATE(isolate);
+    CHECK_CALLBACK_STATE(I);
     // Check and handle a dart object that implements the List interface.
-    const Instance& instance =
-        Instance::Handle(isolate, GetListInstance(isolate, obj));
+    const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
     if (!instance.IsNull()) {
       const intptr_t kNumArgs = 2;
       ArgumentsDescriptor args_desc(
           Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
-      const Function& function = Function::Handle(
-          isolate,
+      const Function& function = Function::Handle(Z,
           Resolver::ResolveDynamic(instance,
                                    Symbols::AssignIndexToken(),
                                    args_desc));
       if (!function.IsNull()) {
         const Array& args = Array::Handle(Array::New(kNumArgs));
         args.SetAt(0, instance);
-        Instance& index = Instance::Handle(isolate);
+        Instance& index = Instance::Handle(Z);
         for (intptr_t i = 0; i < length; ++i) {
           index = Integer::New(i);
           args.SetAt(1, index);
-          Dart_Handle value = Api::NewHandle(isolate,
+          Dart_Handle value = Api::NewHandle(I,
               DartEntry::InvokeFunction(function, args));
           if (::Dart_IsError(value))
             return value;
@@ -2816,11 +2770,11 @@
 }
 
 
-#define SET_LIST_ELEMENT(isolate, type, obj, index, value)                     \
+#define SET_LIST_ELEMENT(type, obj, index, value)                              \
   const type& array = type::Cast(obj);                                         \
-  const Object& value_obj = Object::Handle(isolate, Api::UnwrapHandle(value)); \
+  const Object& value_obj = Object::Handle(Z, Api::UnwrapHandle(value));       \
   if (!value_obj.IsNull() && !value_obj.IsInstance()) {                        \
-    RETURN_TYPE_ERROR(isolate, value, Instance);                               \
+    RETURN_TYPE_ERROR(I, value, Instance);                                     \
   }                                                                            \
   if ((index >= 0) && (index < array.Length())) {                              \
     array.SetAt(index, value_obj);                                             \
@@ -2832,45 +2786,40 @@
 DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list,
                                        intptr_t index,
                                        Dart_Handle value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   // If the list is immutable we call into Dart for the indexed setter to
   // get the unsupported operation exception as the result.
   if (obj.IsArray() && !Array::Cast(obj).IsImmutable()) {
-    SET_LIST_ELEMENT(isolate, Array, obj, index, value);
+    SET_LIST_ELEMENT(Array, obj, index, value);
   } else if (obj.IsGrowableObjectArray()) {
-    SET_LIST_ELEMENT(isolate, GrowableObjectArray, obj, index, value);
+    SET_LIST_ELEMENT(GrowableObjectArray, obj, index, value);
   } else if (obj.IsError()) {
     return list;
   } else {
-    CHECK_CALLBACK_STATE(isolate);
+    CHECK_CALLBACK_STATE(I);
 
     // Check and handle a dart object that implements the List interface.
-    const Instance& instance =
-        Instance::Handle(isolate, GetListInstance(isolate, obj));
+    const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
     if (!instance.IsNull()) {
       const intptr_t kNumArgs = 3;
       ArgumentsDescriptor args_desc(
           Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
-      const Function& function = Function::Handle(
-          isolate,
+      const Function& function = Function::Handle(Z,
           Resolver::ResolveDynamic(instance,
                                    Symbols::AssignIndexToken(),
                                    args_desc));
       if (!function.IsNull()) {
-        const Integer& index_obj =
-            Integer::Handle(isolate, Integer::New(index));
-        const Object& value_obj =
-            Object::Handle(isolate, Api::UnwrapHandle(value));
+        const Integer& index_obj = Integer::Handle(Z, Integer::New(index));
+        const Object& value_obj = Object::Handle(Z, Api::UnwrapHandle(value));
         if (!value_obj.IsNull() && !value_obj.IsInstance()) {
-          RETURN_TYPE_ERROR(isolate, value, Instance);
+          RETURN_TYPE_ERROR(I, value, Instance);
         }
-        const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+        const Array& args = Array::Handle(Z, Array::New(kNumArgs));
         args.SetAt(0, instance);
         args.SetAt(1, index_obj);
         args.SetAt(2, value_obj);
-        return Api::NewHandle(isolate, DartEntry::InvokeFunction(function,
+        return Api::NewHandle(I, DartEntry::InvokeFunction(function,
                                                                  args));
       }
     }
@@ -2953,16 +2902,15 @@
 }
 
 // TODO(sgjesse): value should always be smaller then 0xff. Add error handling.
-#define GET_LIST_ELEMENT_AS_BYTES(isolate, type, obj, native_array, offset,    \
-                                  length)                                      \
+#define GET_LIST_ELEMENT_AS_BYTES(type, obj, native_array, offset, length)     \
   const type& array = type::Cast(obj);                                         \
   if (Utils::RangeCheck(offset, length, array.Length())) {                     \
-    Object& element = Object::Handle(isolate);                                 \
+    Object& element = Object::Handle(Z);                                       \
     for (int i = 0; i < length; i++) {                                         \
       element = array.At(offset + i);                                          \
       if (!element.IsInteger()) {                                              \
-        return Api::NewHandle(                                                 \
-            isolate, ThrowArgumentError("List contains non-int elements"));    \
+        return Api::NewHandle(I,                                               \
+            ThrowArgumentError("List contains non-int elements"));             \
                                                                                \
       }                                                                        \
       const Integer& integer = Integer::Cast(element);                         \
@@ -2991,9 +2939,8 @@
                                             intptr_t offset,
                                             uint8_t* native_array,
                                             intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsTypedData()) {
     const TypedData& array = TypedData::Cast(obj);
     if (array.ElementSizeInBytes() == 1) {
@@ -3036,48 +2983,38 @@
     }
   }
   if (obj.IsArray()) {
-    GET_LIST_ELEMENT_AS_BYTES(isolate,
-                              Array,
-                              obj,
-                              native_array,
-                              offset,
-                              length);
+    GET_LIST_ELEMENT_AS_BYTES(Array, obj, native_array, offset, length);
   }
   if (obj.IsGrowableObjectArray()) {
-    GET_LIST_ELEMENT_AS_BYTES(isolate,
-                              GrowableObjectArray,
-                              obj,
-                              native_array,
-                              offset,
-                              length);
+    GET_LIST_ELEMENT_AS_BYTES(
+        GrowableObjectArray, obj, native_array, offset, length);
   }
   if (obj.IsError()) {
     return list;
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   // Check and handle a dart object that implements the List interface.
   const Instance& instance =
-      Instance::Handle(isolate, GetListInstance(isolate, obj));
+      Instance::Handle(Z, GetListInstance(Z, obj));
   if (!instance.IsNull()) {
     const int kNumArgs = 2;
     ArgumentsDescriptor args_desc(
         Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
-    const Function& function = Function::Handle(
-        isolate,
+    const Function& function = Function::Handle(Z,
         Resolver::ResolveDynamic(instance, Symbols::IndexToken(), args_desc));
     if (!function.IsNull()) {
-      Object& result = Object::Handle(isolate);
-      Integer& intobj = Integer::Handle(isolate);
-      const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+      Object& result = Object::Handle(Z);
+      Integer& intobj = Integer::Handle(Z);
+      const Array& args = Array::Handle(Z, Array::New(kNumArgs));
       args.SetAt(0, instance);  // Set up the receiver as the first argument.
       for (int i = 0; i < length; i++) {
-        HANDLESCOPE(isolate);
+        HANDLESCOPE(T);
         intobj = Integer::New(offset + i);
         args.SetAt(1, intobj);
         result = DartEntry::InvokeFunction(function, args);
         if (result.IsError()) {
-          return Api::NewHandle(isolate, result.raw());
+          return Api::NewHandle(I, result.raw());
         }
         if (!result.IsInteger()) {
           return Api::NewError("%s expects the argument 'list' to be "
@@ -3097,10 +3034,9 @@
 }
 
 
-#define SET_LIST_ELEMENT_AS_BYTES(isolate, type, obj, native_array, offset,    \
-                                  length)                                      \
+#define SET_LIST_ELEMENT_AS_BYTES(type, obj, native_array, offset, length)     \
   const type& array = type::Cast(obj);                                         \
-  Integer& integer = Integer::Handle(isolate);                                 \
+  Integer& integer = Integer::Handle(Z);                                       \
   if (Utils::RangeCheck(offset, length, array.Length())) {                     \
     for (int i = 0; i < length; i++) {                                         \
       integer = Integer::New(native_array[i]);                                 \
@@ -3115,9 +3051,8 @@
                                             intptr_t offset,
                                             uint8_t* native_array,
                                             intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
   if (obj.IsTypedData()) {
     const TypedData& array = TypedData::Cast(obj);
     if (array.ElementSizeInBytes() == 1) {
@@ -3134,52 +3069,41 @@
   if (obj.IsArray() && !Array::Cast(obj).IsImmutable()) {
     // If the list is immutable we call into Dart for the indexed setter to
     // get the unsupported operation exception as the result.
-    SET_LIST_ELEMENT_AS_BYTES(isolate,
-                              Array,
-                              obj,
-                              native_array,
-                              offset,
-                              length);
+    SET_LIST_ELEMENT_AS_BYTES(Array, obj, native_array, offset, length);
   }
   if (obj.IsGrowableObjectArray()) {
-    SET_LIST_ELEMENT_AS_BYTES(isolate,
-                              GrowableObjectArray,
-                              obj,
-                              native_array,
-                              offset,
-                              length);
+    SET_LIST_ELEMENT_AS_BYTES(
+        GrowableObjectArray, obj, native_array, offset, length);
   }
   if (obj.IsError()) {
     return list;
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   // Check and handle a dart object that implements the List interface.
-  const Instance& instance =
-      Instance::Handle(isolate, GetListInstance(isolate, obj));
+  const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
   if (!instance.IsNull()) {
     const int kNumArgs = 3;
     ArgumentsDescriptor args_desc(
         Array::Handle(ArgumentsDescriptor::New(kNumArgs)));
-    const Function& function = Function::Handle(
-        isolate,
+    const Function& function = Function::Handle(Z,
         Resolver::ResolveDynamic(instance,
                                  Symbols::AssignIndexToken(),
                                  args_desc));
     if (!function.IsNull()) {
-      Integer& indexobj = Integer::Handle(isolate);
-      Integer& valueobj = Integer::Handle(isolate);
-      const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+      Integer& indexobj = Integer::Handle(Z);
+      Integer& valueobj = Integer::Handle(Z);
+      const Array& args = Array::Handle(Z, Array::New(kNumArgs));
       args.SetAt(0, instance);  // Set up the receiver as the first argument.
       for (int i = 0; i < length; i++) {
         indexobj = Integer::New(offset + i);
         valueobj = Integer::New(native_array[i]);
         args.SetAt(1, indexobj);
         args.SetAt(2, valueobj);
-        const Object& result = Object::Handle(
-            isolate, DartEntry::InvokeFunction(function, args));
+        const Object& result = Object::Handle(Z,
+            DartEntry::InvokeFunction(function, args));
         if (result.IsError()) {
-          return Api::NewHandle(isolate, result.raw());
+          return Api::NewHandle(I, result.raw());
         }
       }
       return Api::Success();
@@ -3192,41 +3116,35 @@
 // --- Maps ---
 
 DART_EXPORT Dart_Handle Dart_MapGetAt(Dart_Handle map, Dart_Handle key) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(map));
-  const Instance& instance =
-      Instance::Handle(isolate, GetMapInstance(isolate, obj));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(map));
+  const Instance& instance = Instance::Handle(Z, GetMapInstance(Z, obj));
   if (!instance.IsNull()) {
     const Object& key_obj = Object::Handle(Api::UnwrapHandle(key));
     if (!(key_obj.IsInstance() || key_obj.IsNull())) {
       return Api::NewError("Key is not an instance");
     }
-    return Api::NewHandle(isolate, Send1Arg(
-       instance,
-       Symbols::IndexToken(),
-       Instance::Cast(key_obj)));
+    return Api::NewHandle(I,
+        Send1Arg(instance, Symbols::IndexToken(), Instance::Cast(key_obj)));
   }
   return Api::NewError("Object does not implement the 'Map' interface");
 }
 
 
 DART_EXPORT Dart_Handle Dart_MapContainsKey(Dart_Handle map, Dart_Handle key) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(map));
-  const Instance& instance =
-      Instance::Handle(isolate, GetMapInstance(isolate, obj));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(map));
+  const Instance& instance = Instance::Handle(Z, GetMapInstance(Z, obj));
   if (!instance.IsNull()) {
-    const Object& key_obj = Object::Handle(Api::UnwrapHandle(key));
+    const Object& key_obj = Object::Handle(Z, Api::UnwrapHandle(key));
     if (!(key_obj.IsInstance() || key_obj.IsNull())) {
       return Api::NewError("Key is not an instance");
     }
-    return Api::NewHandle(isolate, Send1Arg(
+    return Api::NewHandle(I, Send1Arg(
        instance,
-       String::Handle(isolate, String::New("containsKey")),
+       String::Handle(Z, String::New("containsKey")),
        Instance::Cast(key_obj)));
   }
   return Api::NewError("Object does not implement the 'Map' interface");
@@ -3234,19 +3152,17 @@
 
 
 DART_EXPORT Dart_Handle Dart_MapKeys(Dart_Handle map) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  Object& obj = Object::Handle(isolate, Api::UnwrapHandle(map));
-  Instance& instance =
-      Instance::Handle(isolate, GetMapInstance(isolate, obj));
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  Object& obj = Object::Handle(Z, Api::UnwrapHandle(map));
+  Instance& instance = Instance::Handle(Z, GetMapInstance(Z, obj));
   if (!instance.IsNull()) {
     const Object& iterator = Object::Handle(Send0Arg(
-        instance, String::Handle(String::New("get:keys"))));
+        instance, String::Handle(Z, String::New("get:keys"))));
     if (!iterator.IsInstance()) {
-      return Api::NewHandle(isolate, iterator.raw());
+      return Api::NewHandle(I, iterator.raw());
     }
-    return Api::NewHandle(isolate, Send0Arg(
+    return Api::NewHandle(I, Send0Arg(
         Instance::Cast(iterator),
         String::Handle(String::New("toList"))));
   }
@@ -3462,36 +3378,35 @@
 
 DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type,
                                           intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
   switch (type) {
     case Dart_TypedData_kByteData :
-      return NewByteData(isolate, length);
+      return NewByteData(I, length);
     case Dart_TypedData_kInt8 :
-      return NewTypedData(isolate, kTypedDataInt8ArrayCid, length);
+      return NewTypedData(I, kTypedDataInt8ArrayCid, length);
     case Dart_TypedData_kUint8 :
-      return NewTypedData(isolate, kTypedDataUint8ArrayCid, length);
+      return NewTypedData(I, kTypedDataUint8ArrayCid, length);
     case Dart_TypedData_kUint8Clamped :
-      return NewTypedData(isolate, kTypedDataUint8ClampedArrayCid, length);
+      return NewTypedData(I, kTypedDataUint8ClampedArrayCid, length);
     case Dart_TypedData_kInt16 :
-      return NewTypedData(isolate, kTypedDataInt16ArrayCid, length);
+      return NewTypedData(I, kTypedDataInt16ArrayCid, length);
     case Dart_TypedData_kUint16 :
-      return NewTypedData(isolate, kTypedDataUint16ArrayCid, length);
+      return NewTypedData(I, kTypedDataUint16ArrayCid, length);
     case Dart_TypedData_kInt32 :
-      return NewTypedData(isolate, kTypedDataInt32ArrayCid, length);
+      return NewTypedData(I, kTypedDataInt32ArrayCid, length);
     case Dart_TypedData_kUint32 :
-      return NewTypedData(isolate, kTypedDataUint32ArrayCid, length);
+      return NewTypedData(I, kTypedDataUint32ArrayCid, length);
     case Dart_TypedData_kInt64 :
-      return NewTypedData(isolate, kTypedDataInt64ArrayCid, length);
+      return NewTypedData(I, kTypedDataInt64ArrayCid, length);
     case Dart_TypedData_kUint64 :
-      return NewTypedData(isolate, kTypedDataUint64ArrayCid, length);
+      return NewTypedData(I, kTypedDataUint64ArrayCid, length);
     case Dart_TypedData_kFloat32 :
-      return NewTypedData(isolate, kTypedDataFloat32ArrayCid,  length);
+      return NewTypedData(I, kTypedDataFloat32ArrayCid,  length);
     case Dart_TypedData_kFloat64 :
-      return NewTypedData(isolate, kTypedDataFloat64ArrayCid, length);
+      return NewTypedData(I, kTypedDataFloat64ArrayCid, length);
     case Dart_TypedData_kFloat32x4:
-      return NewTypedData(isolate, kTypedDataFloat32x4ArrayCid, length);
+      return NewTypedData(I, kTypedDataFloat32x4ArrayCid, length);
     default:
       return Api::NewError("%s expects argument 'type' to be of 'TypedData'",
                            CURRENT_FUNC);
@@ -3505,75 +3420,50 @@
     Dart_TypedData_Type type,
     void* data,
     intptr_t length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (data == NULL && length != 0) {
     RETURN_NULL_ERROR(data);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
   switch (type) {
     case Dart_TypedData_kByteData:
-      return NewExternalByteData(isolate, data, length);
+      return NewExternalByteData(I, data, length);
     case Dart_TypedData_kInt8:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataInt8ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataInt8ArrayCid, data, length);
     case Dart_TypedData_kUint8:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataUint8ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataUint8ArrayCid, data, length);
     case Dart_TypedData_kUint8Clamped:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataUint8ClampedArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataUint8ClampedArrayCid, data, length);
     case Dart_TypedData_kInt16:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataInt16ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataInt16ArrayCid, data, length);
     case Dart_TypedData_kUint16:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataUint16ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataUint16ArrayCid, data, length);
     case Dart_TypedData_kInt32:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataInt32ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataInt32ArrayCid, data, length);
     case Dart_TypedData_kUint32:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataUint32ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataUint32ArrayCid, data, length);
     case Dart_TypedData_kInt64:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataInt64ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataInt64ArrayCid, data, length);
     case Dart_TypedData_kUint64:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataUint64ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataUint64ArrayCid, data, length);
     case Dart_TypedData_kFloat32:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataFloat32ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataFloat32ArrayCid, data, length);
     case Dart_TypedData_kFloat64:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataFloat64ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataFloat64ArrayCid, data, length);
     case Dart_TypedData_kFloat32x4:
-      return NewExternalTypedData(isolate,
-                                  kExternalTypedDataFloat32x4ArrayCid,
-                                  data,
-                                  length);
+      return NewExternalTypedData(I,
+          kExternalTypedDataFloat32x4ArrayCid, data, length);
     default:
       return Api::NewError("%s expects argument 'type' to be of"
                            " 'external TypedData'", CURRENT_FUNC);
@@ -3602,16 +3492,15 @@
 
 
 DART_EXPORT Dart_Handle Dart_NewByteBuffer(Dart_Handle typed_data) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   intptr_t class_id = Api::ClassId(typed_data);
   if (!RawObject::IsExternalTypedDataClassId(class_id) &&
       !RawObject::IsTypedDataViewClassId(class_id) &&
       !RawObject::IsTypedDataClassId(class_id)) {
-    RETURN_TYPE_ERROR(isolate, typed_data, 'TypedData');
+    RETURN_TYPE_ERROR(I, typed_data, 'TypedData');
   }
-  Object& result = Object::Handle(isolate);
-  result = GetByteBufferConstructor(isolate,
+  Object& result = Object::Handle(Z);
+  result = GetByteBufferConstructor(I,
                                     Symbols::_ByteBuffer(),
                                     Symbols::_ByteBufferDot_New(),
                                     1);
@@ -3621,16 +3510,16 @@
   ASSERT(!factory.IsGenerativeConstructor());
 
   // Create the argument list.
-  const Array& args = Array::Handle(isolate, Array::New(2));
+  const Array& args = Array::Handle(Z, Array::New(2));
   // Factories get type arguments.
   args.SetAt(0, Object::null_type_arguments());
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(typed_data));
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(typed_data));
   args.SetAt(1, obj);
 
   // Invoke the factory constructor and return the new object.
   result = DartEntry::InvokeFunction(factory, args);
   ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
-  return Api::NewHandle(isolate, result.raw());
+  return Api::NewHandle(I, result.raw());
 }
 
 
@@ -3671,14 +3560,12 @@
                                                   Dart_TypedData_Type* type,
                                                   void** data,
                                                   intptr_t* len) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsExternalTypedDataClassId(class_id) &&
       !RawObject::IsTypedDataViewClassId(class_id) &&
       !RawObject::IsTypedDataClassId(class_id)) {
-    RETURN_TYPE_ERROR(isolate, object, 'TypedData');
+    RETURN_TYPE_ERROR(I, object, 'TypedData');
   }
   if (type == NULL) {
     RETURN_NULL_ERROR(type);
@@ -3698,7 +3585,7 @@
   // If it is an external typed data object just return the data field.
   if (RawObject::IsExternalTypedDataClassId(class_id)) {
     const ExternalTypedData& obj =
-        Api::UnwrapExternalTypedDataHandle(isolate, object);
+        Api::UnwrapExternalTypedDataHandle(I, object);
     ASSERT(!obj.IsNull());
     length = obj.Length();
     size_in_bytes = length * ExternalTypedData::ElementSizeInBytes(class_id);
@@ -3706,16 +3593,16 @@
     external = true;
   } else if (RawObject::IsTypedDataClassId(class_id)) {
     // Regular typed data object, set up some GC and API callback guards.
-    const TypedData& obj = Api::UnwrapTypedDataHandle(isolate, object);
+    const TypedData& obj = Api::UnwrapTypedDataHandle(I, object);
     ASSERT(!obj.IsNull());
     length = obj.Length();
     size_in_bytes = length * TypedData::ElementSizeInBytes(class_id);
-    thread->IncrementNoSafepointScopeDepth();
-    START_NO_CALLBACK_SCOPE(isolate);
+    T->IncrementNoSafepointScopeDepth();
+    START_NO_CALLBACK_SCOPE(I);
     data_tmp = obj.DataAddr(0);
   } else {
     ASSERT(RawObject::IsTypedDataViewClassId(class_id));
-    const Instance& view_obj = Api::UnwrapInstanceHandle(isolate, object);
+    const Instance& view_obj = Api::UnwrapInstanceHandle(I, object);
     ASSERT(!view_obj.IsNull());
     Smi& val = Smi::Handle();
     val ^= TypedDataView::Length(view_obj);
@@ -3724,8 +3611,8 @@
     val ^= TypedDataView::OffsetInBytes(view_obj);
     intptr_t offset_in_bytes = val.Value();
     const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj));
-    thread->IncrementNoSafepointScopeDepth();
-    START_NO_CALLBACK_SCOPE(isolate);
+    T->IncrementNoSafepointScopeDepth();
+    START_NO_CALLBACK_SCOPE(I);
     if (TypedData::IsTypedData(obj)) {
       const TypedData& data_obj = TypedData::Cast(obj);
       data_tmp = data_obj.DataAddr(offset_in_bytes);
@@ -3738,12 +3625,12 @@
   }
   if (FLAG_verify_acquired_data) {
     if (external) {
-      ASSERT(!isolate->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
+      ASSERT(!I->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
     } else {
-      ASSERT(isolate->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
+      ASSERT(I->heap()->Contains(reinterpret_cast<uword>(data_tmp)));
     }
-    const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-    WeakTable* table = isolate->api_state()->acquired_table();
+    const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
+    WeakTable* table = I->api_state()->acquired_table();
     intptr_t current = table->GetValue(obj.raw());
     if (current != 0) {
       return Api::NewError("Data was already acquired for this object.");
@@ -3762,22 +3649,20 @@
 
 
 DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   intptr_t class_id = Api::ClassId(object);
   if (!RawObject::IsExternalTypedDataClassId(class_id) &&
       !RawObject::IsTypedDataViewClassId(class_id) &&
       !RawObject::IsTypedDataClassId(class_id)) {
-    RETURN_TYPE_ERROR(isolate, object, 'TypedData');
+    RETURN_TYPE_ERROR(I, object, 'TypedData');
   }
   if (!RawObject::IsExternalTypedDataClassId(class_id)) {
-    thread->DecrementNoSafepointScopeDepth();
-    END_NO_CALLBACK_SCOPE(isolate);
+    T->DecrementNoSafepointScopeDepth();
+    END_NO_CALLBACK_SCOPE(I);
   }
   if (FLAG_verify_acquired_data) {
-    const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
-    WeakTable* table = isolate->api_state()->acquired_table();
+    const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
+    WeakTable* table = I->api_state()->acquired_table();
     intptr_t current = table->GetValue(obj.raw());
     if (current == 0) {
       return Api::NewError("Data was not acquired for this object.");
@@ -3857,10 +3742,9 @@
                                  Dart_Handle constructor_name,
                                  int number_of_arguments,
                                  Dart_Handle* arguments) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  Object& result = Object::Handle(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  Object& result = Object::Handle(Z);
 
   if (number_of_arguments < 0) {
     return Api::NewError(
@@ -3871,7 +3755,7 @@
   // Get the class to instantiate.
   Object& unchecked_type = Object::Handle(Api::UnwrapHandle(type));
   if (unchecked_type.IsNull() || !unchecked_type.IsType()) {
-    RETURN_TYPE_ERROR(isolate, type, Type);
+    RETURN_TYPE_ERROR(I, type, Type);
   }
   Type& type_obj = Type::Handle();
   type_obj ^= unchecked_type.raw();
@@ -3880,21 +3764,21 @@
         "%s expects argument 'type' to be a fully resolved type.",
         CURRENT_FUNC);
   }
-  Class& cls = Class::Handle(isolate, type_obj.type_class());
+  Class& cls = Class::Handle(Z, type_obj.type_class());
   TypeArguments& type_arguments =
-      TypeArguments::Handle(isolate, type_obj.arguments());
+      TypeArguments::Handle(Z, type_obj.arguments());
 
-  const String& base_constructor_name = String::Handle(isolate, cls.Name());
+  const String& base_constructor_name = String::Handle(Z, cls.Name());
 
   // And get the name of the constructor to invoke.
-  String& dot_name = String::Handle(isolate);
+  String& dot_name = String::Handle(Z);
   result = Api::UnwrapHandle(constructor_name);
   if (result.IsNull()) {
     dot_name = Symbols::Dot().raw();
   } else if (result.IsString()) {
     dot_name = String::Concat(Symbols::Dot(), String::Cast(result));
   } else {
-    RETURN_TYPE_ERROR(isolate, constructor_name, String);
+    RETURN_TYPE_ERROR(I, constructor_name, String);
   }
 
   // Resolve the constructor.
@@ -3906,20 +3790,20 @@
                               constr_name,
                               number_of_arguments);
   if (result.IsError()) {
-    return Api::NewHandle(isolate, result.raw());
+    return Api::NewHandle(I, result.raw());
   }
   ASSERT(result.IsFunction());
-  Function& constructor = Function::Handle(isolate);
+  Function& constructor = Function::Handle(Z);
   constructor ^= result.raw();
 
-  Instance& new_object = Instance::Handle(isolate);
+  Instance& new_object = Instance::Handle(Z);
   if (constructor.IsRedirectingFactory()) {
     ClassFinalizer::ResolveRedirectingFactory(cls, constructor);
     Type& redirect_type = Type::Handle(constructor.RedirectionType());
     constructor = constructor.RedirectionTarget();
     if (constructor.IsNull()) {
       ASSERT(redirect_type.IsMalformed());
-      return Api::NewHandle(isolate, redirect_type.error());
+      return Api::NewHandle(I, redirect_type.error());
     }
 
     if (!redirect_type.IsInstantiated()) {
@@ -3929,7 +3813,7 @@
       redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
                                                      &bound_error);
       if (!bound_error.IsNull()) {
-        return Api::NewHandle(isolate, bound_error.raw());
+        return Api::NewHandle(I, bound_error.raw());
       }
       redirect_type ^= redirect_type.Canonicalize();
     }
@@ -3948,7 +3832,7 @@
   intptr_t arg_index = 0;
   int extra_args = (constructor.IsGenerativeConstructor() ? 2 : 1);
   const Array& args =
-      Array::Handle(isolate, Array::New(number_of_arguments + extra_args));
+      Array::Handle(Z, Array::New(number_of_arguments + extra_args));
   if (constructor.IsGenerativeConstructor()) {
     // Constructors get the uninitialized object and a constructor phase.
     if (!type_arguments.IsNull()) {
@@ -3958,18 +3842,17 @@
       new_object.SetTypeArguments(type_arguments);
     }
     args.SetAt(arg_index++, new_object);
-    args.SetAt(arg_index++,
-               Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll)));
+    args.SetAt(arg_index++, Smi::Handle(Z, Smi::New(Function::kCtorPhaseAll)));
   } else {
     // Factories get type arguments.
     args.SetAt(arg_index++, type_arguments);
   }
-  Object& argument = Object::Handle(isolate);
+  Object& argument = Object::Handle(Z);
   for (int i = 0; i < number_of_arguments; i++) {
     argument = Api::UnwrapHandle(arguments[i]);
     if (!argument.IsNull() && !argument.IsInstance()) {
       if (argument.IsError()) {
-        return Api::NewHandle(isolate, argument.raw());
+        return Api::NewHandle(I, argument.raw());
       } else {
         return Api::NewError(
             "%s expects arguments[%d] to be an Instance handle.",
@@ -3982,7 +3865,7 @@
   // Invoke the constructor and return the new object.
   result = DartEntry::InvokeFunction(constructor, args);
   if (result.IsError()) {
-    return Api::NewHandle(isolate, result.raw());
+    return Api::NewHandle(I, result.raw());
   }
 
   if (constructor.IsGenerativeConstructor()) {
@@ -3991,7 +3874,7 @@
     ASSERT(result.IsNull() || result.IsInstance());
     new_object ^= result.raw();
   }
-  return Api::NewHandle(isolate, new_object.raw());
+  return Api::NewHandle(I, new_object.raw());
 }
 
 
@@ -4022,22 +3905,21 @@
 
 
 DART_EXPORT Dart_Handle Dart_Allocate(Dart_Handle type) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  const Type& type_obj = Api::UnwrapTypeHandle(isolate, type);
+  const Type& type_obj = Api::UnwrapTypeHandle(I, type);
   // Get the class to instantiate.
   if (type_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type, Type);
+    RETURN_TYPE_ERROR(I, type, Type);
   }
-  const Class& cls = Class::Handle(isolate, type_obj.type_class());
-  const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+  const Class& cls = Class::Handle(Z, type_obj.type_class());
+  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
   if (!error.IsNull()) {
     // An error occurred, return error object.
-    return Api::NewHandle(isolate, error.raw());
+    return Api::NewHandle(I, error.raw());
   }
-  return Api::NewHandle(isolate, AllocateObject(isolate, cls));
+  return Api::NewHandle(I, AllocateObject(I, cls));
 }
 
 
@@ -4045,33 +3927,31 @@
     Dart_Handle type,
     intptr_t num_native_fields,
     const intptr_t* native_fields) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  const Type& type_obj = Api::UnwrapTypeHandle(isolate, type);
+  const Type& type_obj = Api::UnwrapTypeHandle(I, type);
   // Get the class to instantiate.
   if (type_obj.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, type, Type);
+    RETURN_TYPE_ERROR(I, type, Type);
   }
   if (native_fields == NULL) {
     RETURN_NULL_ERROR(native_fields);
   }
-  const Class& cls = Class::Handle(isolate, type_obj.type_class());
-  const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+  const Class& cls = Class::Handle(Z, type_obj.type_class());
+  const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
   if (!error.IsNull()) {
     // An error occurred, return error object.
-    return Api::NewHandle(isolate, error.raw());
+    return Api::NewHandle(I, error.raw());
   }
   if (num_native_fields != cls.num_native_fields()) {
     return Api::NewError(
         "%s: invalid number of native fields %" Pd " passed in, expected %d",
         CURRENT_FUNC, num_native_fields, cls.num_native_fields());
   }
-  const Instance& instance = Instance::Handle(isolate,
-                                              AllocateObject(isolate, cls));
+  const Instance& instance = Instance::Handle(Z, AllocateObject(I, cls));
   instance.SetNativeFields(num_native_fields, native_fields);
-  return Api::NewHandle(isolate, instance.raw());
+  return Api::NewHandle(I, instance.raw());
 }
 
 
@@ -4105,22 +3985,21 @@
                                                Dart_Handle name,
                                                int number_of_arguments,
                                                Dart_Handle* arguments) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
   if (number_of_arguments < 0) {
     return Api::NewError(
         "%s expects argument 'number_of_arguments' to be non-negative.",
         CURRENT_FUNC);
   }
-  const String& constructor_name = Api::UnwrapStringHandle(isolate, name);
+  const String& constructor_name = Api::UnwrapStringHandle(I, name);
   if (constructor_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, name, String);
+    RETURN_TYPE_ERROR(I, name, String);
   }
-  const Instance& instance = Api::UnwrapInstanceHandle(isolate, object);
+  const Instance& instance = Api::UnwrapInstanceHandle(I, object);
   if (instance.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, object, Instance);
+    RETURN_TYPE_ERROR(I, object, Instance);
   }
 
   // Since we have allocated an object it would mean that the type
@@ -4129,18 +4008,18 @@
   // once for the same object.
 
   // Construct name of the constructor to invoke.
-  const Type& type_obj = Type::Handle(isolate, instance.GetType());
-  const Class& cls = Class::Handle(isolate, type_obj.type_class());
-  const String& class_name = String::Handle(isolate, cls.Name());
-  const Array& strings = Array::Handle(Array::New(3));
+  const Type& type_obj = Type::Handle(Z, instance.GetType());
+  const Class& cls = Class::Handle(Z, type_obj.type_class());
+  const String& class_name = String::Handle(Z, cls.Name());
+  const Array& strings = Array::Handle(Z, Array::New(3));
   strings.SetAt(0, class_name);
   strings.SetAt(1, Symbols::Dot());
   strings.SetAt(2, constructor_name);
-  const String& dot_name = String::Handle(isolate, String::ConcatAll(strings));
+  const String& dot_name = String::Handle(Z, String::ConcatAll(strings));
   const TypeArguments& type_arguments =
-    TypeArguments::Handle(isolate, type_obj.arguments());
+      TypeArguments::Handle(Z, type_obj.arguments());
   const Function& constructor =
-    Function::Handle(isolate, cls.LookupFunctionAllowPrivate(dot_name));
+      Function::Handle(Z, cls.LookupFunctionAllowPrivate(dot_name));
   const int extra_args = 2;
   if (!constructor.IsNull() &&
       constructor.IsGenerativeConstructor() &&
@@ -4157,22 +4036,18 @@
       instance.SetTypeArguments(type_arguments);
     }
     Dart_Handle result;
-    Array& args = Array::Handle(isolate);
-    result = SetupArguments(isolate,
-                            number_of_arguments,
-                            arguments,
-                            extra_args,
-                            &args);
+    Array& args = Array::Handle(Z);
+    result = SetupArguments(I,
+        number_of_arguments, arguments, extra_args, &args);
     if (!::Dart_IsError(result)) {
       args.SetAt(0, instance);
-      args.SetAt(1, Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll)));
-      const Object& retval = Object::Handle(
-          isolate,
+      args.SetAt(1, Smi::Handle(Z, Smi::New(Function::kCtorPhaseAll)));
+      const Object& retval = Object::Handle(Z,
           DartEntry::InvokeFunction(constructor, args));
       if (retval.IsError()) {
-        result = Api::NewHandle(isolate, retval.raw());
+        result = Api::NewHandle(I, retval.raw());
       } else {
-        result = Api::NewHandle(isolate, instance.raw());
+        result = Api::NewHandle(I, instance.raw());
       }
     }
     return result;
@@ -4187,29 +4062,27 @@
                                     Dart_Handle name,
                                     int number_of_arguments,
                                     Dart_Handle* arguments) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
   // TODO(turnidge): This is a bit simplistic.  It overcounts when
   // other operations (gc, compilation) are active.
-  TIMERSCOPE(thread, time_dart_execution);
+  TIMERSCOPE(T, time_dart_execution);
 
-  const String& function_name = Api::UnwrapStringHandle(isolate, name);
+  const String& function_name = Api::UnwrapStringHandle(I, name);
   if (function_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, name, String);
+    RETURN_TYPE_ERROR(I, name, String);
   }
   if (number_of_arguments < 0) {
     return Api::NewError(
         "%s expects argument 'number_of_arguments' to be non-negative.",
         CURRENT_FUNC);
   }
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(target));
   if (obj.IsError()) {
     return target;
   }
   Dart_Handle result;
-  Array& args = Array::Handle(isolate);
+  Array& args = Array::Handle(Z);
   if (obj.IsType()) {
     if (!Type::Cast(obj).IsFinalized()) {
       return Api::NewError(
@@ -4217,41 +4090,38 @@
           CURRENT_FUNC);
     }
 
-    const Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
-    const Function& function = Function::Handle(
-        isolate,
+    const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
+    const Function& function = Function::Handle(Z,
         Resolver::ResolveStaticAllowPrivate(cls,
                                             function_name,
                                             number_of_arguments,
                                             Object::empty_array()));
     if (function.IsNull()) {
-      const String& cls_name = String::Handle(isolate, cls.Name());
+      const String& cls_name = String::Handle(Z, cls.Name());
       return Api::NewError("%s: did not find static method '%s.%s'.",
                            CURRENT_FUNC,
                            cls_name.ToCString(),
                            function_name.ToCString());
     }
     // Setup args and check for malformed arguments in the arguments list.
-    result = SetupArguments(isolate, number_of_arguments, arguments, 0, &args);
+    result = SetupArguments(I, number_of_arguments, arguments, 0, &args);
     if (!::Dart_IsError(result)) {
-      result = Api::NewHandle(isolate,
-                              DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else if (obj.IsNull() || obj.IsInstance()) {
     // Since we have allocated an object it would mean that the type of the
     // receiver is already resolved and finalized, hence it is not necessary
     // to check here.
-    Instance& instance = Instance::Handle(isolate);
+    Instance& instance = Instance::Handle(Z);
     instance ^= obj.raw();
     ArgumentsDescriptor args_desc(
-        Array::Handle(ArgumentsDescriptor::New(number_of_arguments + 1)));
-    const Function& function = Function::Handle(
-        isolate,
+        Array::Handle(Z, ArgumentsDescriptor::New(number_of_arguments + 1)));
+    const Function& function = Function::Handle(Z,
         Resolver::ResolveDynamic(instance, function_name, args_desc));
     if (function.IsNull()) {
       // Setup args and check for malformed arguments in the arguments list.
-      result = SetupArguments(isolate,
+      result = SetupArguments(I,
                               number_of_arguments,
                               arguments,
                               1,
@@ -4259,8 +4129,8 @@
       if (!::Dart_IsError(result)) {
         args.SetAt(0, instance);
         const Array& args_descriptor =
-          Array::Handle(ArgumentsDescriptor::New(args.Length()));
-        result = Api::NewHandle(isolate,
+          Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
+        result = Api::NewHandle(I,
                                 DartEntry::InvokeNoSuchMethod(instance,
                                                               function_name,
                                                               args,
@@ -4269,11 +4139,10 @@
       return result;
     }
     // Setup args and check for malformed arguments in the arguments list.
-    result = SetupArguments(isolate, number_of_arguments, arguments, 1, &args);
+    result = SetupArguments(I, number_of_arguments, arguments, 1, &args);
     if (!::Dart_IsError(result)) {
       args.SetAt(0, instance);
-      result = Api::NewHandle(isolate,
-                              DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else if (obj.IsLibrary()) {
@@ -4288,8 +4157,7 @@
     }
 
     const Function& function =
-        Function::Handle(isolate,
-                         lib.LookupFunctionAllowPrivate(function_name));
+        Function::Handle(Z, lib.LookupFunctionAllowPrivate(function_name));
     if (function.IsNull()) {
       return Api::NewError("%s: did not find top-level function '%s'.",
                            CURRENT_FUNC,
@@ -4297,7 +4165,7 @@
     }
     // LookupFunctionAllowPrivate does not check argument arity, so we
     // do it here.
-    String& error_message = String::Handle();
+    String& error_message = String::Handle(Z);
     if (!function.AreValidArgumentCounts(number_of_arguments,
                                          0,
                                          &error_message)) {
@@ -4307,10 +4175,9 @@
                            error_message.ToCString());
     }
     // Setup args and check for malformed arguments in the arguments list.
-    result = SetupArguments(isolate, number_of_arguments, arguments, 0, &args);
+    result = SetupArguments(I, number_of_arguments, arguments, 0, &args);
     if (!::Dart_IsError(result)) {
-      result = Api::NewHandle(isolate,
-                              DartEntry::InvokeFunction(function, args));
+      result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
     }
     return result;
   } else {
@@ -4324,12 +4191,11 @@
 DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure,
                                            int number_of_arguments,
                                            Dart_Handle* arguments) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
-  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
+  const Instance& closure_obj = Api::UnwrapInstanceHandle(I, closure);
   if (closure_obj.IsNull() || !closure_obj.IsCallable(NULL)) {
-    RETURN_TYPE_ERROR(isolate, closure, Instance);
+    RETURN_TYPE_ERROR(I, closure, Instance);
   }
   if (number_of_arguments < 0) {
     return Api::NewError(
@@ -4338,35 +4204,33 @@
   }
 
   // Set up arguments to include the closure as the first argument.
-  const Array& args = Array::Handle(isolate,
-                                    Array::New(number_of_arguments + 1));
-  Object& obj = Object::Handle(isolate);
+  const Array& args = Array::Handle(Z, Array::New(number_of_arguments + 1));
+  Object& obj = Object::Handle(Z);
   args.SetAt(0, closure_obj);
   for (int i = 0; i < number_of_arguments; i++) {
     obj = Api::UnwrapHandle(arguments[i]);
     if (!obj.IsNull() && !obj.IsInstance()) {
-      RETURN_TYPE_ERROR(isolate, arguments[i], Instance);
+      RETURN_TYPE_ERROR(I, arguments[i], Instance);
     }
     args.SetAt(i + 1, obj);
   }
   // Now try to invoke the closure.
-  return Api::NewHandle(isolate, DartEntry::InvokeClosure(args));
+  return Api::NewHandle(I, DartEntry::InvokeClosure(args));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetField(Dart_Handle container, Dart_Handle name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  const String& field_name = Api::UnwrapStringHandle(isolate, name);
+  const String& field_name = Api::UnwrapStringHandle(I, name);
   if (field_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, name, String);
+    RETURN_TYPE_ERROR(I, name, String);
   }
 
-  Field& field = Field::Handle(isolate);
-  Function& getter = Function::Handle(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
+  Field& field = Field::Handle(Z);
+  Function& getter = Function::Handle(Z);
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(container));
   if (obj.IsNull()) {
     return Api::NewError("%s expects argument 'container' to be non-null.",
                          CURRENT_FUNC);
@@ -4378,21 +4242,21 @@
     }
     // To access a static field we may need to use the Field or the
     // getter Function.
-    Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
+    Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
 
     field = cls.LookupStaticField(field_name);
     if (field.IsNull() || field.IsUninitialized()) {
       const String& getter_name =
-          String::Handle(isolate, Field::GetterName(field_name));
+          String::Handle(Z, Field::GetterName(field_name));
       getter = cls.LookupStaticFunctionAllowPrivate(getter_name);
     }
 
     if (!getter.IsNull()) {
       // Invoke the getter and return the result.
-      return Api::NewHandle(
-          isolate, DartEntry::InvokeFunction(getter, Object::empty_array()));
+      return Api::NewHandle(I,
+          DartEntry::InvokeFunction(getter, Object::empty_array()));
     } else if (!field.IsNull()) {
-      return Api::NewHandle(isolate, field.value());
+      return Api::NewHandle(I, field.value());
     } else {
       return Api::NewError("%s: did not find static field '%s'.",
                            CURRENT_FUNC, field_name.ToCString());
@@ -4403,9 +4267,8 @@
     // getter in any superclass and use that function to access the
     // field.
     const Instance& instance = Instance::Cast(obj);
-    Class& cls = Class::Handle(isolate, instance.clazz());
-    String& getter_name =
-        String::Handle(isolate, Field::GetterName(field_name));
+    Class& cls = Class::Handle(Z, instance.clazz());
+    String& getter_name = String::Handle(Z, Field::GetterName(field_name));
     while (!cls.IsNull()) {
       getter = cls.LookupDynamicFunctionAllowPrivate(getter_name);
       if (!getter.IsNull()) {
@@ -4416,18 +4279,18 @@
 
     // Invoke the getter and return the result.
     const int kNumArgs = 1;
-    const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+    const Array& args = Array::Handle(Z, Array::New(kNumArgs));
     args.SetAt(0, instance);
     if (getter.IsNull()) {
       const Array& args_descriptor =
-          Array::Handle(ArgumentsDescriptor::New(args.Length()));
-      return Api::NewHandle(isolate,
+          Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
+      return Api::NewHandle(I,
                             DartEntry::InvokeNoSuchMethod(instance,
                                                           getter_name,
                                                           args,
                                                           args_descriptor));
     }
-    return Api::NewHandle(isolate, DartEntry::InvokeFunction(getter, args));
+    return Api::NewHandle(I, DartEntry::InvokeFunction(getter, args));
 
   } else if (obj.IsLibrary()) {
     // To access a top-level we may need to use the Field or the
@@ -4444,23 +4307,23 @@
     if (field.IsNull()) {
       // No field found and no ambiguity error.  Check for a getter in the lib.
       const String& getter_name =
-          String::Handle(isolate, Field::GetterName(field_name));
+          String::Handle(Z, Field::GetterName(field_name));
       getter = lib.LookupFunctionAllowPrivate(getter_name);
     } else if (!field.IsNull() && field.IsUninitialized()) {
       // A field was found.  Check for a getter in the field's owner classs.
-      const Class& cls = Class::Handle(isolate, field.owner());
-      const String& getter_name =
-          String::Handle(isolate, Field::GetterName(field_name));
+      const Class& cls = Class::Handle(Z, field.owner());
+      const String& getter_name = String::Handle(Z,
+          Field::GetterName(field_name));
       getter = cls.LookupStaticFunctionAllowPrivate(getter_name);
     }
 
     if (!getter.IsNull()) {
       // Invoke the getter and return the result.
-      return Api::NewHandle(
-          isolate, DartEntry::InvokeFunction(getter, Object::empty_array()));
+      return Api::NewHandle(I,
+          DartEntry::InvokeFunction(getter, Object::empty_array()));
     }
     if (!field.IsNull()) {
-      return Api::NewHandle(isolate, field.value());
+      return Api::NewHandle(I, field.value());
     }
     return Api::NewError("%s: did not find top-level variable '%s'.",
                          CURRENT_FUNC, field_name.ToCString());
@@ -4478,26 +4341,25 @@
 DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container,
                                       Dart_Handle name,
                                       Dart_Handle value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  const String& field_name = Api::UnwrapStringHandle(isolate, name);
+  const String& field_name = Api::UnwrapStringHandle(I, name);
   if (field_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, name, String);
+    RETURN_TYPE_ERROR(I, name, String);
   }
 
   // Since null is allowed for value, we don't use UnwrapInstanceHandle.
-  const Object& value_obj = Object::Handle(isolate, Api::UnwrapHandle(value));
+  const Object& value_obj = Object::Handle(Z, Api::UnwrapHandle(value));
   if (!value_obj.IsNull() && !value_obj.IsInstance()) {
-    RETURN_TYPE_ERROR(isolate, value, Instance);
+    RETURN_TYPE_ERROR(I, value, Instance);
   }
-  Instance& value_instance = Instance::Handle(isolate);
+  Instance& value_instance = Instance::Handle(Z);
   value_instance ^= value_obj.raw();
 
-  Field& field = Field::Handle(isolate);
-  Function& setter = Function::Handle(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(container));
+  Field& field = Field::Handle(Z);
+  Function& setter = Function::Handle(Z);
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(container));
   if (obj.IsNull()) {
     return Api::NewError("%s expects argument 'container' to be non-null.",
                          CURRENT_FUNC);
@@ -4510,24 +4372,23 @@
 
     // To access a static field we may need to use the Field or the
     // setter Function.
-    Class& cls = Class::Handle(isolate, Type::Cast(obj).type_class());
+    Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
 
     field = cls.LookupStaticField(field_name);
     if (field.IsNull()) {
-      String& setter_name =
-          String::Handle(isolate, Field::SetterName(field_name));
+      String& setter_name = String::Handle(Z, Field::SetterName(field_name));
       setter = cls.LookupStaticFunctionAllowPrivate(setter_name);
     }
 
     if (!setter.IsNull()) {
       // Invoke the setter and return the result.
       const int kNumArgs = 1;
-      const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+      const Array& args = Array::Handle(Z, Array::New(kNumArgs));
       args.SetAt(0, value_instance);
-      const Object& result =
-          Object::Handle(isolate, DartEntry::InvokeFunction(setter, args));
+      const Object& result = Object::Handle(Z,
+          DartEntry::InvokeFunction(setter, args));
       if (result.IsError()) {
-        return Api::NewHandle(isolate, result.raw());
+        return Api::NewHandle(I, result.raw());
       } else {
         return Api::Success();
       }
@@ -4549,9 +4410,8 @@
     // setter in any superclass and use that function to access the
     // field.
     const Instance& instance = Instance::Cast(obj);
-    Class& cls = Class::Handle(isolate, instance.clazz());
-    String& setter_name =
-        String::Handle(isolate, Field::SetterName(field_name));
+    Class& cls = Class::Handle(Z, instance.clazz());
+    String& setter_name = String::Handle(Z, Field::SetterName(field_name));
     while (!cls.IsNull()) {
       field = cls.LookupInstanceField(field_name);
       if (!field.IsNull() && field.is_final()) {
@@ -4567,19 +4427,18 @@
 
     // Invoke the setter and return the result.
     const int kNumArgs = 2;
-    const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+    const Array& args = Array::Handle(Z, Array::New(kNumArgs));
     args.SetAt(0, instance);
     args.SetAt(1, value_instance);
     if (setter.IsNull()) {
       const Array& args_descriptor =
-          Array::Handle(ArgumentsDescriptor::New(args.Length()));
-      return Api::NewHandle(isolate,
-                            DartEntry::InvokeNoSuchMethod(instance,
-                                                          setter_name,
-                                                          args,
-                                                          args_descriptor));
+          Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
+      return Api::NewHandle(I, DartEntry::InvokeNoSuchMethod(instance,
+                                                             setter_name,
+                                                             args,
+                                                             args_descriptor));
     }
-    return Api::NewHandle(isolate, DartEntry::InvokeFunction(setter, args));
+    return Api::NewHandle(I, DartEntry::InvokeFunction(setter, args));
 
   } else if (obj.IsLibrary()) {
     // To access a top-level we may need to use the Field or the
@@ -4595,19 +4454,19 @@
     field = lib.LookupFieldAllowPrivate(field_name);
     if (field.IsNull()) {
       const String& setter_name =
-          String::Handle(isolate, Field::SetterName(field_name));
+          String::Handle(Z, Field::SetterName(field_name));
       setter ^= lib.LookupFunctionAllowPrivate(setter_name);
     }
 
     if (!setter.IsNull()) {
       // Invoke the setter and return the result.
       const int kNumArgs = 1;
-      const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
+      const Array& args = Array::Handle(Z, Array::New(kNumArgs));
       args.SetAt(0, value_instance);
       const Object& result =
-          Object::Handle(isolate, DartEntry::InvokeFunction(setter, args));
+          Object::Handle(Z, DartEntry::InvokeFunction(setter, args));
       if (result.IsError()) {
-        return Api::NewHandle(isolate, result.raw());
+        return Api::NewHandle(I, result.raw());
       }
       return Api::Success();
     }
@@ -4715,30 +4574,29 @@
 DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library,
                                                       Dart_Handle name,
                                                       int field_count) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const String& cls_name = Api::UnwrapStringHandle(isolate, name);
+  DARTSCOPE(Thread::Current());
+  const String& cls_name = Api::UnwrapStringHandle(I, name);
   if (cls_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, name, String);
+    RETURN_TYPE_ERROR(I, name, String);
   }
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
   if (!Utils::IsUint(16, field_count)) {
     return Api::NewError(
         "Invalid field_count passed to Dart_CreateNativeWrapperClass");
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
-  String& cls_symbol = String::Handle(isolate, Symbols::New(cls_name));
-  const Class& cls = Class::Handle(
-      isolate, Class::NewNativeWrapper(lib, cls_symbol, field_count));
+  String& cls_symbol = String::Handle(Z, Symbols::New(cls_name));
+  const Class& cls = Class::Handle(Z,
+      Class::NewNativeWrapper(lib, cls_symbol, field_count));
   if (cls.IsNull()) {
     return Api::NewError(
         "Unable to create native wrapper class : already exists");
   }
-  return Api::NewHandle(isolate, cls.RareType());
+  return Api::NewHandle(I, cls.RareType());
 }
 
 
@@ -4779,11 +4637,10 @@
 DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
                                                     int index,
                                                     intptr_t value) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Instance& instance = Api::UnwrapInstanceHandle(isolate, obj);
+  DARTSCOPE(Thread::Current());
+  const Instance& instance = Api::UnwrapInstanceHandle(I, obj);
   if (instance.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, obj, Instance);
+    RETURN_TYPE_ERROR(I, obj, Instance);
   }
   if (!instance.IsValidNativeIndex(index)) {
     return Api::NewError(
@@ -5207,22 +5064,19 @@
                                         Dart_Handle source,
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_script_loading);
-  const String& url_str = Api::UnwrapStringHandle(isolate, url);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_script_loading);
+  const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, url, String);
+    RETURN_TYPE_ERROR(I, url, String);
   }
-  const String& source_str = Api::UnwrapStringHandle(isolate, source);
+  const String& source_str = Api::UnwrapStringHandle(I, source);
   if (source_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, source, String);
+    RETURN_TYPE_ERROR(I, source, String);
   }
-  Library& library =
-      Library::Handle(isolate, isolate->object_store()->root_library());
+  Library& library = Library::Handle(Z, I->object_store()->root_library());
   if (!library.IsNull()) {
-    const String& library_url = String::Handle(isolate, library.url());
+    const String& library_url = String::Handle(Z, library.url());
     return Api::NewError("%s: A script has already been loaded from '%s'.",
                          CURRENT_FUNC, library_url.ToCString());
   }
@@ -5234,31 +5088,29 @@
     return Api::NewError("%s: argument 'column_offset' must be positive number",
                          CURRENT_FUNC);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
   library = Library::New(url_str);
   library.set_debuggable(true);
   library.Register();
-  isolate->object_store()->set_root_library(library);
+  I->object_store()->set_root_library(library);
 
-  const Script& script = Script::Handle(
-      isolate, Script::New(url_str, source_str, RawScript::kScriptTag));
+  const Script& script = Script::Handle(Z,
+      Script::New(url_str, source_str, RawScript::kScriptTag));
   script.SetLocationOffset(line_offset, column_offset);
   Dart_Handle result;
-  CompileSource(isolate, library, script, &result);
+  CompileSource(I, library, script, &result);
   return result;
 }
 
 
 DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
                                                     intptr_t buffer_len) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_script_loading);
-  StackZone zone(isolate);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_script_loading);
+  StackZone zone(T);
   if (buffer == NULL) {
     RETURN_NULL_ERROR(buffer);
   }
@@ -5274,28 +5126,24 @@
                          " which is the expected length in the snapshot.",
                          CURRENT_FUNC, buffer_len, snapshot->length());
   }
-  Library& library =
-      Library::Handle(isolate, isolate->object_store()->root_library());
+  Library& library = Library::Handle(Z, I->object_store()->root_library());
   if (!library.IsNull()) {
-    const String& library_url = String::Handle(isolate, library.url());
+    const String& library_url = String::Handle(Z, library.url());
     return Api::NewError("%s: A script has already been loaded from '%s'.",
                          CURRENT_FUNC, library_url.ToCString());
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   ASSERT(snapshot->kind() == Snapshot::kScript);
-  ScriptSnapshotReader reader(snapshot->content(),
-                              snapshot->length(),
-                              isolate,
-                              zone.GetZone());
-  const Object& tmp = Object::Handle(isolate, reader.ReadScriptSnapshot());
+  ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
+  const Object& tmp = Object::Handle(Z, reader.ReadScriptSnapshot());
   if (tmp.IsError()) {
-    return Api::NewHandle(isolate, tmp.raw());
+    return Api::NewHandle(I, tmp.raw());
   }
   library ^= tmp.raw();
   library.set_debuggable(true);
-  isolate->object_store()->set_root_library(library);
-  return Api::NewHandle(isolate, library.raw());
+  I->object_store()->set_root_library(library);
+  return Api::NewHandle(I, library.raw());
 }
 
 
@@ -5308,25 +5156,23 @@
 
 DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library,
                                       Dart_Handle class_name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const String& cls_name = Api::UnwrapStringHandle(isolate, class_name);
+  const String& cls_name = Api::UnwrapStringHandle(I, class_name);
   if (cls_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, class_name, String);
+    RETURN_TYPE_ERROR(I, class_name, String);
   }
-  const Class& cls = Class::Handle(
-      isolate, lib.LookupClassAllowPrivate(cls_name));
+  const Class& cls = Class::Handle(Z, lib.LookupClassAllowPrivate(cls_name));
   if (cls.IsNull()) {
     // TODO(turnidge): Return null or error in this case?
-    const String& lib_name = String::Handle(isolate, lib.name());
+    const String& lib_name = String::Handle(Z, lib.name());
     return Api::NewError("Class '%s' not found in library '%s'.",
                          cls_name.ToCString(), lib_name.ToCString());
   }
-  return Api::NewHandle(isolate, cls.RareType());
+  return Api::NewHandle(I, cls.RareType());
 }
 
 
@@ -5334,27 +5180,25 @@
                                      Dart_Handle class_name,
                                      intptr_t number_of_type_arguments,
                                      Dart_Handle* type_arguments) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
   // Validate the input arguments.
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
   if (!lib.Loaded()) {
     return Api::NewError(
         "%s expects library argument 'library' to be loaded.",
         CURRENT_FUNC);
   }
-  const String& name_str = Api::UnwrapStringHandle(isolate, class_name);
+  const String& name_str = Api::UnwrapStringHandle(I, class_name);
   if (name_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, class_name, String);
+    RETURN_TYPE_ERROR(I, class_name, String);
   }
-  const Class& cls =
-      Class::Handle(isolate, lib.LookupClassAllowPrivate(name_str));
+  const Class& cls = Class::Handle(Z, lib.LookupClassAllowPrivate(name_str));
   if (cls.IsNull()) {
-    const String& lib_name = String::Handle(isolate, lib.name());
+    const String& lib_name = String::Handle(Z, lib.name());
     return Api::NewError("Type '%s' not found in library '%s'.",
                          name_str.ToCString(), lib_name.ToCString());
   }
@@ -5363,7 +5207,7 @@
       return Api::NewError("Invalid number of type arguments specified, "
                            "got %" Pd " expected 0", number_of_type_arguments);
     }
-    return Api::NewHandle(isolate, Type::NewNonParameterizedType(cls));
+    return Api::NewHandle(I, Type::NewNonParameterizedType(cls));
   }
   intptr_t num_expected_type_arguments = cls.NumTypeParameters();
   TypeArguments& type_args_obj = TypeArguments::Handle();
@@ -5377,9 +5221,9 @@
                            number_of_type_arguments,
                            num_expected_type_arguments);
     }
-    const Array& array = Api::UnwrapArrayHandle(isolate, *type_arguments);
+    const Array& array = Api::UnwrapArrayHandle(I, *type_arguments);
     if (array.IsNull()) {
-      RETURN_TYPE_ERROR(isolate, *type_arguments, Array);
+      RETURN_TYPE_ERROR(I, *type_arguments, Array);
     }
     if (array.Length() != num_expected_type_arguments) {
       return Api::NewError("Invalid type arguments specified, expected an "
@@ -5401,59 +5245,55 @@
       Type::New(cls, type_args_obj, Scanner::kNoSourcePos));
   instantiated_type ^= ClassFinalizer::FinalizeType(
       cls, instantiated_type, ClassFinalizer::kCanonicalize);
-  return Api::NewHandle(isolate, instantiated_type.raw());
+  return Api::NewHandle(I, instantiated_type.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const String& url = String::Handle(isolate, lib.url());
+  const String& url = String::Handle(Z, lib.url());
   ASSERT(!url.IsNull());
-  return Api::NewHandle(isolate, url.raw());
+  return Api::NewHandle(I, url.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const String& url_str = Api::UnwrapStringHandle(isolate, url);
+  DARTSCOPE(Thread::Current());
+  const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, url, String);
+    RETURN_TYPE_ERROR(I, url, String);
   }
-  const Library& library =
-      Library::Handle(isolate, Library::LookupLibrary(url_str));
+  const Library& library = Library::Handle(Z, Library::LookupLibrary(url_str));
   if (library.IsNull()) {
     return Api::NewError("%s: library '%s' not found.",
                          CURRENT_FUNC, url_str.ToCString());
   } else {
-    return Api::NewHandle(isolate, library.raw());
+    return Api::NewHandle(I, library.raw());
   }
 }
 
 
 DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library_in,
                                                 Dart_Handle error_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library_in);
+  const Library& lib = Api::UnwrapLibraryHandle(I, library_in);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library_in, Library);
+    RETURN_TYPE_ERROR(I, library_in, Library);
   }
-  const Instance& err = Api::UnwrapInstanceHandle(isolate, error_in);
+  const Instance& err = Api::UnwrapInstanceHandle(I, error_in);
   if (err.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, error_in, Instance);
+    RETURN_TYPE_ERROR(I, error_in, Instance);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   const GrowableObjectArray& pending_deferred_loads =
-      GrowableObjectArray::Handle(
-          isolate->object_store()->pending_deferred_loads());
+      GrowableObjectArray::Handle(Z,
+          I->object_store()->pending_deferred_loads());
   for (intptr_t i = 0; i < pending_deferred_loads.Length(); i++) {
     if (pending_deferred_loads.At(i) == lib.raw()) {
       lib.SetLoadError(err);
@@ -5468,17 +5308,15 @@
                                          Dart_Handle source,
                                          intptr_t line_offset,
                                          intptr_t column_offset) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_script_loading);
-  const String& url_str = Api::UnwrapStringHandle(isolate, url);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_script_loading);
+  const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, url, String);
+    RETURN_TYPE_ERROR(I, url, String);
   }
-  const String& source_str = Api::UnwrapStringHandle(isolate, source);
+  const String& source_str = Api::UnwrapStringHandle(I, source);
   if (source_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, source, String);
+    RETURN_TYPE_ERROR(I, source, String);
   }
   if (line_offset < 0) {
     return Api::NewError("%s: argument 'line_offset' must be positive number",
@@ -5488,11 +5326,11 @@
     return Api::NewError("%s: argument 'column_offset' must be positive number",
                          CURRENT_FUNC);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
-  Library& library = Library::Handle(isolate, Library::LookupLibrary(url_str));
+  Library& library = Library::Handle(Z, Library::LookupLibrary(url_str));
   if (library.IsNull()) {
     library = Library::New(url_str);
     library.Register();
@@ -5504,11 +5342,11 @@
     return Api::NewError("%s: library '%s' has already been loaded.",
                          CURRENT_FUNC, url_str.ToCString());
   }
-  const Script& script = Script::Handle(
-      isolate, Script::New(url_str, source_str, RawScript::kLibraryTag));
+  const Script& script = Script::Handle(Z,
+      Script::New(url_str, source_str, RawScript::kLibraryTag));
   script.SetLocationOffset(line_offset, column_offset);
   Dart_Handle result;
-  CompileSource(isolate, library, script, &result);
+  CompileSource(I, library, script, &result);
   // Propagate the error out right now.
   if (::Dart_IsError(result)) {
     return result;
@@ -5516,8 +5354,8 @@
 
   // If this is the dart:_builtin library, register it with the VM.
   if (url_str.Equals("dart:_builtin")) {
-    isolate->object_store()->set_builtin_library(library);
-    Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
+    I->object_store()->set_builtin_library(library);
+    Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
     if (::Dart_IsError(state)) {
       return state;
     }
@@ -5529,29 +5367,26 @@
 DART_EXPORT Dart_Handle Dart_LibraryImportLibrary(Dart_Handle library,
                                                   Dart_Handle import,
                                                   Dart_Handle prefix) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& library_vm = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& library_vm = Api::UnwrapLibraryHandle(I, library);
   if (library_vm.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const Library& import_vm = Api::UnwrapLibraryHandle(isolate, import);
+  const Library& import_vm = Api::UnwrapLibraryHandle(I, import);
   if (import_vm.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, import, Library);
+    RETURN_TYPE_ERROR(I, import, Library);
   }
-  const Object& prefix_object =
-      Object::Handle(isolate, Api::UnwrapHandle(prefix));
+  const Object& prefix_object = Object::Handle(Z, Api::UnwrapHandle(prefix));
   const String& prefix_vm = prefix_object.IsNull()
       ? Symbols::Empty()
       : String::Cast(prefix_object);
   if (prefix_vm.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, prefix, String);
+    RETURN_TYPE_ERROR(I, prefix, String);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
-  const String& prefix_symbol =
-      String::Handle(isolate, Symbols::New(prefix_vm));
-  const Namespace& import_ns = Namespace::Handle(
+  const String& prefix_symbol = String::Handle(Z, Symbols::New(prefix_vm));
+  const Namespace& import_ns = Namespace::Handle(Z,
       Namespace::New(import_vm, Object::null_array(), Object::null_array()));
   if (prefix_vm.Length() == 0) {
     library_vm.AddImport(import_ns);
@@ -5575,21 +5410,19 @@
                                         Dart_Handle source,
                                         intptr_t line_offset,
                                         intptr_t column_offset) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_script_loading);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_script_loading);
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const String& url_str = Api::UnwrapStringHandle(isolate, url);
+  const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, url, String);
+    RETURN_TYPE_ERROR(I, url, String);
   }
-  const String& source_str = Api::UnwrapStringHandle(isolate, source);
+  const String& source_str = Api::UnwrapStringHandle(I, source);
   if (source_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, source, String);
+    RETURN_TYPE_ERROR(I, source, String);
   }
   if (line_offset < 0) {
     return Api::NewError("%s: argument 'line_offset' must be positive number",
@@ -5599,15 +5432,15 @@
     return Api::NewError("%s: argument 'column_offset' must be positive number",
                          CURRENT_FUNC);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
-  const Script& script = Script::Handle(
-      isolate, Script::New(url_str, source_str, RawScript::kSourceTag));
+  const Script& script = Script::Handle(Z,
+      Script::New(url_str, source_str, RawScript::kSourceTag));
   script.SetLocationOffset(line_offset, column_offset);
   Dart_Handle result;
-  CompileSource(isolate, lib, script, &result);
+  CompileSource(I, lib, script, &result);
   return result;
 }
 
@@ -5615,30 +5448,28 @@
 DART_EXPORT Dart_Handle Dart_LibraryLoadPatch(Dart_Handle library,
                                               Dart_Handle url,
                                               Dart_Handle patch_source) {
-  Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
-  DARTSCOPE(isolate);
-  TIMERSCOPE(thread, time_script_loading);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  TIMERSCOPE(T, time_script_loading);
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const String& url_str = Api::UnwrapStringHandle(isolate, url);
+  const String& url_str = Api::UnwrapStringHandle(I, url);
   if (url_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, url, String);
+    RETURN_TYPE_ERROR(I, url, String);
   }
-  const String& source_str = Api::UnwrapStringHandle(isolate, patch_source);
+  const String& source_str = Api::UnwrapStringHandle(I, patch_source);
   if (source_str.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, patch_source, String);
+    RETURN_TYPE_ERROR(I, patch_source, String);
   }
-  CHECK_CALLBACK_STATE(isolate);
+  CHECK_CALLBACK_STATE(I);
 
   NoHeapGrowthControlScope no_growth_control;
 
-  const Script& script = Script::Handle(
-      isolate, Script::New(url_str, source_str, RawScript::kPatchTag));
+  const Script& script = Script::Handle(Z,
+      Script::New(url_str, source_str, RawScript::kPatchTag));
   Dart_Handle result;
-  CompileSource(isolate, lib, script, &result);
+  CompileSource(I, lib, script, &result);
   return result;
 }
 
@@ -5646,17 +5477,16 @@
 // Finalizes classes and invokes Dart core library function that completes
 // futures of loadLibrary calls (deferred library loading).
 DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  CHECK_CALLBACK_STATE(isolate);
+  DARTSCOPE(Thread::Current());
+  CHECK_CALLBACK_STATE(I);
 
-  isolate->DoneLoading();
+  I->DoneLoading();
 
   // TODO(hausner): move the remaining code below (finalization and
   // invoing of _completeDeferredLoads) into Isolate::DoneLoading().
 
   // Finalize all classes if needed.
-  Dart_Handle state = Api::CheckAndFinalizePendingClasses(isolate);
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
   if (::Dart_IsError(state)) {
     return state;
   }
@@ -5666,31 +5496,29 @@
   // the new code, the debugger convert them to unresolved source breakpoints.
   // The code that completes the futures (invoked below) may call into the
   // newly loaded code and trigger one of these breakpoints.
-  isolate->debugger()->NotifyDoneLoading();
+  I->debugger()->NotifyDoneLoading();
 
   // Notify mirrors that MirrorSystem.libraries needs to be recomputed.
-  const Library& libmirrors =
-      Library::Handle(isolate, Library::MirrorsLibrary());
-  const Field& dirty_bit = Field::Handle(isolate,
+  const Library& libmirrors = Library::Handle(Z, Library::MirrorsLibrary());
+  const Field& dirty_bit = Field::Handle(Z,
       libmirrors.LookupLocalField(String::Handle(String::New("dirty"))));
   ASSERT(!dirty_bit.IsNull() && dirty_bit.is_static());
   dirty_bit.set_value(Bool::True());
 
   if (complete_futures) {
-    const Library& corelib = Library::Handle(isolate, Library::CoreLibrary());
+    const Library& corelib = Library::Handle(Z, Library::CoreLibrary());
     const String& function_name =
-        String::Handle(isolate, String::New("_completeDeferredLoads"));
-    const Function& function =
-        Function::Handle(isolate,
-                         corelib.LookupFunctionAllowPrivate(function_name));
+        String::Handle(Z, String::New("_completeDeferredLoads"));
+    const Function& function = Function::Handle(Z,
+        corelib.LookupFunctionAllowPrivate(function_name));
     ASSERT(!function.IsNull());
     const Array& args = Array::empty_array();
 
     const Object& res =
-        Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
-    isolate->object_store()->clear_pending_deferred_loads();
+        Object::Handle(Z, DartEntry::InvokeFunction(function, args));
+    I->object_store()->clear_pending_deferred_loads();
     if (res.IsError() || res.IsUnhandledException()) {
-      return Api::NewHandle(isolate, res.raw());
+      return Api::NewHandle(I, res.raw());
     }
   }
   return Api::Success();
@@ -5701,11 +5529,10 @@
     Dart_Handle library,
     Dart_NativeEntryResolver resolver,
     Dart_NativeEntrySymbol symbol) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
   lib.set_native_entry_resolver(resolver);
   lib.set_native_entry_symbol_resolver(symbol);
@@ -5827,8 +5654,7 @@
                                                   const char* event_kind,
                                                   const uint8_t* bytes,
                                                   intptr_t bytes_length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (stream_id == NULL) {
     RETURN_NULL_ERROR(stream_id);
   }
@@ -5842,7 +5668,7 @@
     return Api::NewError("%s expects argument 'bytes_length' to be >= 0.",
                          CURRENT_FUNC);
   }
-  Service::SendEmbedderEvent(isolate, stream_id, event_kind,
+  Service::SendEmbedderEvent(I, stream_id, event_kind,
                              bytes, bytes_length);
   return Api::Success();
 }
@@ -6044,4 +5870,73 @@
   return Api::Success();
 }
 
+
+static void Precompile(Isolate* isolate, Dart_Handle* result) {
+  ASSERT(isolate != NULL);
+  const Error& error = Error::Handle(isolate, Precompiler::CompileAll());
+  if (error.IsNull()) {
+    *result = Api::Success();
+  } else {
+    *result = Api::NewHandle(isolate, error.raw());
+  }
+}
+
+
+DART_EXPORT Dart_Handle Dart_Precompile() {
+  DARTSCOPE(Thread::Current());
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
+  if (::Dart_IsError(result)) {
+    return result;
+  }
+  CHECK_CALLBACK_STATE(I);
+  Precompile(I, &result);
+  return result;
+}
+
+
+DART_EXPORT Dart_Handle Dart_CreatePrecompiledSnapshot(
+    uint8_t** vm_isolate_snapshot_buffer,
+    intptr_t* vm_isolate_snapshot_size,
+    uint8_t** isolate_snapshot_buffer,
+    intptr_t* isolate_snapshot_size,
+    uint8_t** instructions_snapshot_buffer,
+    intptr_t* instructions_snapshot_size) {
+  ASSERT(FLAG_load_deferred_eagerly);
+  DARTSCOPE(Thread::Current());
+  if (vm_isolate_snapshot_buffer == NULL) {
+    RETURN_NULL_ERROR(vm_isolate_snapshot_buffer);
+  }
+  if (vm_isolate_snapshot_size == NULL) {
+    RETURN_NULL_ERROR(vm_isolate_snapshot_size);
+  }
+  if (isolate_snapshot_buffer == NULL) {
+    RETURN_NULL_ERROR(isolate_snapshot_buffer);
+  }
+  if (isolate_snapshot_size == NULL) {
+    RETURN_NULL_ERROR(isolate_snapshot_size);
+  }
+  if (instructions_snapshot_buffer == NULL) {
+    RETURN_NULL_ERROR(instructions_snapshot_buffer);
+  }
+  if (instructions_snapshot_size == NULL) {
+    RETURN_NULL_ERROR(instructions_snapshot_size);
+  }
+  // Finalize all classes if needed.
+  Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+  if (::Dart_IsError(state)) {
+    return state;
+  }
+  I->heap()->CollectAllGarbage();
+  PrecompiledSnapshotWriter writer(vm_isolate_snapshot_buffer,
+                                   isolate_snapshot_buffer,
+                                   instructions_snapshot_buffer,
+                                   ApiReallocate);
+  writer.WriteFullSnapshot();
+  *vm_isolate_snapshot_size = writer.VmIsolateSnapshotSize();
+  *isolate_snapshot_size = writer.IsolateSnapshotSize();
+  *instructions_snapshot_size = writer.InstructionsSnapshotSize();
+
+  return Api::Success();
+}
+
 }  // namespace dart
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 46f85aa..742f80c 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -68,10 +68,11 @@
     }                                                                          \
   } while (0)
 
-#define DARTSCOPE(isolate)                                                     \
-  Isolate* __temp_isolate__ = (isolate);                                       \
-  CHECK_ISOLATE_SCOPE(__temp_isolate__);                                       \
-  HANDLESCOPE(__temp_isolate__);
+#define DARTSCOPE(thread)                                                      \
+  Thread* T = (thread);                                                        \
+  Isolate* I = T->isolate();                                                   \
+  CHECK_ISOLATE_SCOPE(I);                                                      \
+  HANDLESCOPE(T);
 
 
 #define RETURN_TYPE_ERROR(isolate, dart_handle, type)                          \
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 70d59d9..f79106e 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -616,8 +616,7 @@
 
   // Non-instance objects.
   {
-    Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -662,8 +661,7 @@
 
   // Non-instance objects.
   {
-    Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -1175,7 +1173,6 @@
 
 
 TEST_CASE(ExternalStringPretenure) {
-  Isolate* isolate = Isolate::Current();
   {
     Dart_EnterScope();
     static const uint8_t big_data8[16*MB] = {0, };
@@ -1206,7 +1203,7 @@
         NULL);
     EXPECT_VALID(small16);
     {
-      DARTSCOPE(isolate);
+      DARTSCOPE(Thread::Current());
       String& handle = String::Handle();
       handle ^= Api::UnwrapHandle(big8);
       EXPECT(handle.IsOld());
@@ -1223,7 +1220,6 @@
 
 
 TEST_CASE(ExternalTypedDataPretenure) {
-  Isolate* isolate = Isolate::Current();
   {
     Dart_EnterScope();
     static const int kBigLength = 16*MB/8;
@@ -1241,7 +1237,7 @@
         kSmallLength);
     EXPECT_VALID(small);
     {
-      DARTSCOPE(isolate);
+      DARTSCOPE(Thread::Current());
       ExternalTypedData& handle = ExternalTypedData::Handle();
       handle ^= Api::UnwrapHandle(big);
       EXPECT(handle.IsOld());
@@ -2368,7 +2364,7 @@
   Dart_EnterScope();
   {
     EXPECT(state->top_scope() != NULL);
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     const String& str1 = String::Handle(String::New("Test String"));
     Dart_Handle ref = Api::NewHandle(isolate, str1.raw());
     String& str2 = String::Handle();
@@ -2385,7 +2381,8 @@
   const char* kTestString1 = "Test String1";
   const char* kTestString2 = "Test String2";
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
@@ -2393,7 +2390,7 @@
   Dart_PersistentHandle handles[2000];
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
     for (int i = 0; i < 1000; i++) {
       handles[i] = Dart_NewPersistentHandle(ref1);
@@ -2417,8 +2414,8 @@
   }
   Dart_ExitScope();
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     for (int i = 0; i < 500; i++) {
       String& str = String::Handle();
       str ^= PersistentHandle::Cast(handles[i])->raw();
@@ -2455,7 +2452,7 @@
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
   // Start with a known persistent handle.
   Dart_PersistentHandle obj1 = Dart_NewPersistentHandle(Dart_True());
@@ -2486,7 +2483,7 @@
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   String& str = String::Handle();
 
   // Start with a known persistent handle.
@@ -2566,7 +2563,7 @@
     Dart_Handle old_ref;
     {
       Isolate* isolate = Isolate::Current();
-      DARTSCOPE(isolate);
+      DARTSCOPE(Thread::Current());
       old_ref = Api::NewHandle(isolate, String::New("old string", Heap::kOld));
       EXPECT_VALID(old_ref);
     }
@@ -2821,8 +2818,8 @@
     // After the two scavenges above, 'obj' should now be promoted, hence its
     // external size charged to old space.
     {
-      DARTSCOPE(Isolate::Current());
-      String& handle = String::Handle();
+      DARTSCOPE(thread);
+      String& handle = String::Handle(thread->zone());
       handle ^= Api::UnwrapHandle(obj);
       EXPECT(handle.IsOld());
     }
@@ -2932,7 +2929,7 @@
   Dart_EnterScope();
   {
     Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
 
     Dart_Handle local = Api::NewHandle(
         isolate, String::New("strongly reachable", Heap::kOld));
@@ -3174,7 +3171,7 @@
 
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
 
     // Strong handle to keep the reference set alive.
     Dart_Handle local = Api::NewHandle(isolate, String::New("string"));
@@ -3227,7 +3224,7 @@
   Dart_EnterScope();
   {
     Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     new_pwph = Dart_NewPrologueWeakPersistentHandle(
         Api::NewHandle(isolate,
                        String::New("new space prologue weak", Heap::kNew)),
@@ -3325,7 +3322,7 @@
   Dart_EnterScope();
   {
     Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
 
     Dart_Handle local = Api::NewHandle(
         isolate, String::New("strongly reachable", Heap::kOld));
@@ -3436,7 +3433,7 @@
   Dart_EnterScope();
   {
     Isolate* isolate = Isolate::Current();
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
 
     Dart_Handle local = Api::NewHandle(
         isolate, String::New("strongly reachable", Heap::kOld));
@@ -3692,15 +3689,16 @@
 // scope.
 UNIT_TEST_CASE(LocalHandles) {
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
   ApiLocalScope* scope = state->top_scope();
   Dart_Handle handles[300];
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Smi& val = Smi::Handle();
 
     // Start a new scope and allocate some local handles.
@@ -4471,7 +4469,7 @@
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
-  DARTSCOPE(Isolate::Current());
+  DARTSCOPE(Thread::Current());
   Instance& obj = Instance::Handle();
   obj ^= Api::UnwrapHandle(result);
   const Class& cls = Class::Handle(obj.clazz());
@@ -4541,7 +4539,7 @@
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
-  DARTSCOPE(Isolate::Current());
+  DARTSCOPE(Thread::Current());
   Instance& obj = Instance::Handle();
   obj ^= Api::UnwrapHandle(result);
   const Class& cls = Class::Handle(obj.clazz());
@@ -4885,7 +4883,7 @@
       "  return () {};\n"
       "}\n";
   Dart_Handle result;
-  DARTSCOPE(Isolate::Current());
+  DARTSCOPE(Thread::Current());
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -4963,7 +4961,7 @@
       "  };\n"
       "}\n";
 
-  DARTSCOPE(Isolate::Current());
+  DARTSCOPE(Thread::Current());
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -5664,7 +5662,7 @@
       "  return InvokeClosure.method2(10);\n"
       "}\n";
   Dart_Handle result;
-  DARTSCOPE(Isolate::Current());
+  DARTSCOPE(Thread::Current());
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -8257,7 +8255,7 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle str = NewString("a string");
     EXPECT_VALID(str);
     EXPECT(Dart_IsString(str));
@@ -8330,7 +8328,7 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle s1 = NewString("s1");
     EXPECT_VALID(s1);
     EXPECT(Dart_IsString(s1));
@@ -8414,7 +8412,7 @@
   isolate->heap()->CollectGarbage(Heap::kNew);
   isolate->heap()->CollectGarbage(Heap::kNew);
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     String& handle = String::Handle();
     handle ^= Api::UnwrapHandle(str);
     EXPECT(handle.IsOld());
@@ -8467,7 +8465,7 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
     EXPECT_VALID(str);
     EXPECT(Dart_IsString(str));
@@ -8543,7 +8541,7 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
     Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
     EXPECT_VALID(s1);
     EXPECT(Dart_IsString(s1));
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 9a5b92f..92e8562 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -91,6 +91,8 @@
   // A cache of VM heap allocated arguments descriptors.
   static RawArray* cached_args_descriptors_[kCachedDescriptorCount];
 
+  friend class FullSnapshotWriter;
+  friend class VmIsolateSnapshotReader;
   DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
 };
 
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 84c245a..9fd26d8 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -15,6 +15,10 @@
 
 namespace dart {
 
+// Facilitate quick access to the current zone once we have the curren thread.
+#define Z (T->zone())
+
+
 #define UNWRAP_AND_CHECK_PARAM(type, var, param)                               \
   type& var = type::Handle();                                                  \
   do {                                                                         \
@@ -51,32 +55,29 @@
 
 
 DART_EXPORT intptr_t Dart_CacheObject(Dart_Handle object_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(Api::UnwrapHandle(object_in));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object_in));
   if (obj.IsApiError()) {
     return -1;
   }
-  return isolate->debugger()->CacheObject(obj);
+  return I->debugger()->CacheObject(obj);
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetCachedObject(intptr_t obj_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (!isolate->debugger()->IsValidObjectId(obj_id)) {
+  DARTSCOPE(Thread::Current());
+  if (!I->debugger()->IsValidObjectId(obj_id)) {
     return Api::NewError("%s: object id %" Pd " is invalid",
                          CURRENT_FUNC, obj_id);
   }
-  return Api::NewHandle(isolate, isolate->debugger()->GetCachedObject(obj_id));
+  return Api::NewHandle(I, I->debugger()->GetCachedObject(obj_id));
 }
 
 
 DART_EXPORT Dart_Handle Dart_StackTraceLength(
                             Dart_StackTrace trace,
                             intptr_t* length) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_NOT_NULL(length);
   CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace);
   *length = stack_trace->Length();
@@ -88,8 +89,7 @@
                             Dart_StackTrace trace,
                             int frame_index,
                             Dart_ActivationFrame* frame) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_NOT_NULL(frame);
   CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace);
   if ((frame_index < 0) || (frame_index >= stack_trace->Length())) {
@@ -196,45 +196,41 @@
 
 DART_EXPORT Dart_Handle Dart_SetExceptionPauseInfo(
                             Dart_ExceptionPauseInfo pause_info) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  isolate->debugger()->SetExceptionPauseInfo(pause_info);
+  DARTSCOPE(Thread::Current());
+  I->debugger()->SetExceptionPauseInfo(pause_info);
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_ExceptionPauseInfo Dart_GetExceptionPauseInfo() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  return isolate->debugger()->GetExceptionPauseInfo();
+  DARTSCOPE(Thread::Current());
+  return I->debugger()->GetExceptionPauseInfo();
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetStackTrace(Dart_StackTrace* trace) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_NOT_NULL(trace);
   *trace = reinterpret_cast<Dart_StackTrace>(
-      isolate->debugger()->CurrentStackTrace());
+      I->debugger()->CurrentStackTrace());
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetStackTraceFromError(Dart_Handle handle,
                                                     Dart_StackTrace* trace) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_NOT_NULL(trace);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle));
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
   if (obj.IsUnhandledException()) {
     const UnhandledException& error = UnhandledException::Cast(obj);
-    Stacktrace& dart_stacktrace = Stacktrace::Handle(isolate);
+    Stacktrace& dart_stacktrace = Stacktrace::Handle(Z);
     dart_stacktrace ^= error.stacktrace();
     if (dart_stacktrace.IsNull()) {
       *trace = NULL;
     } else {
       *trace = reinterpret_cast<Dart_StackTrace>(
-        isolate->debugger()->StackTraceFrom(dart_stacktrace));
+        I->debugger()->StackTraceFrom(dart_stacktrace));
     }
     return Api::Success();
   } else {
@@ -250,14 +246,13 @@
                             Dart_Handle* script_url,
                             intptr_t* line_number,
                             intptr_t* column_number) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   if (function_name != NULL) {
-    *function_name = Api::NewHandle(isolate, frame->QualifiedFunctionName());
+    *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
   }
   if (script_url != NULL) {
-    *script_url = Api::NewHandle(isolate, frame->SourceUrl());
+    *script_url = Api::NewHandle(I, frame->SourceUrl());
   }
   if (line_number != NULL) {
     *line_number = frame->LineNumber();
@@ -276,19 +271,18 @@
                             Dart_CodeLocation* location) {
   // TODO(hausner): Implement a way to recognize when there
   // is no source code for the code in the frame.
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   if (function_name != NULL) {
-    *function_name = Api::NewHandle(isolate, frame->QualifiedFunctionName());
+    *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
   }
   if (function != NULL) {
-    *function = Api::NewHandle(isolate, frame->function().raw());
+    *function = Api::NewHandle(I, frame->function().raw());
   }
 
   if (location != NULL) {
-    location->script_url = Api::NewHandle(isolate, frame->SourceUrl());
-    const Library& lib = Library::Handle(frame->Library());
+    location->script_url = Api::NewHandle(I, frame->SourceUrl());
+    const Library& lib = Library::Handle(Z, frame->Library());
     location->library_id = lib.index();
     location->token_pos = frame->TokenPos();
   }
@@ -298,8 +292,7 @@
 DART_EXPORT Dart_Handle Dart_ActivationFrameGetFramePointer(
                             Dart_ActivationFrame activation_frame,
                             uintptr_t* frame_pointer) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
 
   if (frame_pointer != NULL) {
@@ -310,11 +303,10 @@
 
 
 DART_EXPORT Dart_Handle Dart_GetFunctionOrigin(Dart_Handle function_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Function, function, function_in);
 
-  const Class& cls = Class::Handle(function.origin());
+  const Class& cls = Class::Handle(Z, function.origin());
   if (!cls.IsTopLevel()) {
     return Dart_NewInteger(cls.id());
   }
@@ -324,21 +316,19 @@
 
 DART_EXPORT Dart_Handle Dart_GetLocalVariables(
                             Dart_ActivationFrame activation_frame) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
-  return Api::NewHandle(isolate, frame->GetLocalVariables());
+  return Api::NewHandle(I, frame->GetLocalVariables());
 }
 
 
 DART_EXPORT Dart_Handle Dart_SetBreakpoint(
                             Dart_Handle script_url_in,
                             intptr_t line_number) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
 
-  Debugger* debugger = isolate->debugger();
+  Debugger* debugger = I->debugger();
   Breakpoint* bpt =
       debugger->SetBreakpointAtLine(script_url, line_number);
   if (bpt == NULL) {
@@ -350,23 +340,21 @@
 
 
 DART_EXPORT Dart_Handle Dart_GetBreakpointURL(intptr_t bp_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Debugger* debugger = isolate->debugger();
+  DARTSCOPE(Thread::Current());
+  Debugger* debugger = I->debugger();
 
   Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
   if (bpt == NULL) {
     return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
                            CURRENT_FUNC, bp_id);
   }
-  return Api::NewHandle(isolate, bpt->bpt_location()->url());
+  return Api::NewHandle(I, bpt->bpt_location()->url());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetBreakpointLine(intptr_t bp_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Debugger* debugger = isolate->debugger();
+  DARTSCOPE(Thread::Current());
+  Debugger* debugger = I->debugger();
 
   Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
   if (bpt == NULL) {
@@ -381,8 +369,7 @@
                             Dart_Handle library_in,
                             Dart_Handle class_name_in,
                             Dart_Handle function_name_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -395,7 +382,7 @@
   }
 
   // Resolve the breakpoint target function.
-  Debugger* debugger = isolate->debugger();
+  Debugger* debugger = I->debugger();
   const Function& bp_target = Function::Handle(
       debugger->ResolveFunction(library, class_name, function_name));
   if (bp_target.IsNull()) {
@@ -421,8 +408,7 @@
                             Dart_Handle library_in,
                             Dart_Handle class_name_in,
                             Dart_Handle function_name_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
   UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
   UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -435,7 +421,7 @@
   }
 
   // Resolve the breakpoint target function.
-  Debugger* debugger = isolate->debugger();
+  Debugger* debugger = I->debugger();
   const Function& bp_target = Function::Handle(
       debugger->ResolveFunction(library, class_name, function_name));
   if (bp_target.IsNull()) {
@@ -447,111 +433,101 @@
                          function_name.ToCString());
   }
 
-  const Error& error =
-      Error::Handle(isolate, debugger->OneTimeBreakAtEntry(bp_target));
+  const Error& error = Error::Handle(Z,
+      debugger->OneTimeBreakAtEntry(bp_target));
   if (!error.IsNull()) {
-    return Api::NewHandle(isolate, error.raw());
+    return Api::NewHandle(I, error.raw());
   }
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_RemoveBreakpoint(intptr_t bp_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  isolate->debugger()->RemoveBreakpoint(bp_id);
+  DARTSCOPE(Thread::Current());
+  I->debugger()->RemoveBreakpoint(bp_id);
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_SetStepOver() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  isolate->debugger()->SetStepOver();
+  DARTSCOPE(Thread::Current());
+  I->debugger()->SetStepOver();
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_SetStepInto() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  isolate->debugger()->SetSingleStep();
+  DARTSCOPE(Thread::Current());
+  I->debugger()->SetSingleStep();
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_SetStepOut() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  isolate->debugger()->SetStepOut();
+  DARTSCOPE(Thread::Current());
+  I->debugger()->SetStepOut();
   return Api::Success();
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetInstanceFields(Dart_Handle object_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
-  return Api::NewHandle(isolate, isolate->debugger()->GetInstanceFields(obj));
+  return Api::NewHandle(I, I->debugger()->GetInstanceFields(obj));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetStaticFields(Dart_Handle target) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Type& type_obj = Api::UnwrapTypeHandle(isolate, target);
+  DARTSCOPE(Thread::Current());
+  const Type& type_obj = Api::UnwrapTypeHandle(I, target);
   if (type_obj.IsNull()) {
     return Api::NewError("%s expects argument 'target' to be a type",
                          CURRENT_FUNC);
   }
-  const Class& cls = Class::Handle(isolate, type_obj.type_class());
-  return Api::NewHandle(isolate, isolate->debugger()->GetStaticFields(cls));
+  const Class& cls = Class::Handle(Z, type_obj.type_class());
+  return Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryFields(intptr_t library_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   const Library& lib =
-      Library::Handle(isolate, Library::GetLibrary(library_id));
+      Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(isolate, isolate->debugger()->GetLibraryFields(lib));
+  return Api::NewHandle(I, I->debugger()->GetLibraryFields(lib));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetGlobalVariables(intptr_t library_id) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
-  const Library& lib = Library::Handle(Library::GetLibrary(library_id));
+  DARTSCOPE(Thread::Current());
+
+  const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(isolate, isolate->debugger()->GetGlobalFields(lib));
+  return Api::NewHandle(I, I->debugger()->GetGlobalFields(lib));
 }
 
 
 DART_EXPORT Dart_Handle Dart_ActivationFrameEvaluate(
                             Dart_ActivationFrame activation_frame,
                             Dart_Handle expr_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
   UNWRAP_AND_CHECK_PARAM(String, expr, expr_in);
-  return Api::NewHandle(isolate, frame->Evaluate(expr));
+  return Api::NewHandle(I, frame->Evaluate(expr));
 }
 
 
 DART_EXPORT Dart_Handle Dart_EvaluateExpr(Dart_Handle target_in,
                                           Dart_Handle expr_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
-  const Object& target = Object::Handle(isolate, Api::UnwrapHandle(target_in));
+  const Object& target = Object::Handle(Z, Api::UnwrapHandle(target_in));
   if (target.IsError()) return target_in;
   if (target.IsNull()) {
     return Api::NewError("%s expects argument 'target' to be non-null",
@@ -560,42 +536,40 @@
   UNWRAP_AND_CHECK_PARAM(String, expr, expr_in);
   // Type extends Instance, must check first.
   if (target.IsType()) {
-    const Class& cls = Class::Handle(isolate, Type::Cast(target).type_class());
-    return Api::NewHandle(isolate, cls.Evaluate(expr,
-                                                Array::empty_array(),
-                                                Array::empty_array()));
+    const Class& cls = Class::Handle(Z, Type::Cast(target).type_class());
+    return Api::NewHandle(I, cls.Evaluate(expr,
+                                          Array::empty_array(),
+                                          Array::empty_array()));
   } else if (target.IsInstance()) {
     const Instance& inst = Instance::Cast(target);
-    return Api::NewHandle(isolate, inst.Evaluate(expr,
-                                                 Array::empty_array(),
-                                                 Array::empty_array()));
+    return Api::NewHandle(I, inst.Evaluate(expr,
+                                           Array::empty_array(),
+                                           Array::empty_array()));
   } else if (target.IsLibrary()) {
     const Library& lib = Library::Cast(target);
-    return Api::NewHandle(isolate, lib.Evaluate(expr,
-                                                Array::empty_array(),
-                                                Array::empty_array()));
+    return Api::NewHandle(I, lib.Evaluate(expr,
+                                          Array::empty_array(),
+                                          Array::empty_array()));
   } else if (target.IsClass()) {
     const Class& cls = Class::Cast(target);
-    return Api::NewHandle(isolate, cls.Evaluate(expr,
-                                                Array::empty_array(),
-                                                Array::empty_array()));
+    return Api::NewHandle(I, cls.Evaluate(expr,
+                                          Array::empty_array(),
+                                          Array::empty_array()));
   }
   return Api::NewError("%s: unsupported target type", CURRENT_FUNC);
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetObjClass(Dart_Handle object_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
-  return Api::NewHandle(isolate, obj.GetType());
+  return Api::NewHandle(I, obj.GetType());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetObjClassId(Dart_Handle object_in,
                                            intptr_t* class_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
   CHECK_NOT_NULL(class_id);
   *class_id = obj.GetClassId();
@@ -604,19 +578,17 @@
 
 
 DART_EXPORT Dart_Handle Dart_GetClassFromId(intptr_t class_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (!isolate->class_table()->IsValidIndex(class_id)) {
+  DARTSCOPE(Thread::Current());
+  if (!I->class_table()->IsValidIndex(class_id)) {
     return Api::NewError("%s: %" Pd " is not a valid class id",
                          CURRENT_FUNC, class_id);
   }
-  return Api::NewHandle(isolate, isolate->class_table()->At(class_id));
+  return Api::NewHandle(I, I->class_table()->At(class_id));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetSupertype(Dart_Handle type_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
   UNWRAP_AND_CHECK_PARAM(Type, type, type_in);
   if (!type.IsFinalized()) {
@@ -635,7 +607,7 @@
     if (type.IsNull()) {
       return Dart_Null();
     }
-    return Api::NewHandle(isolate, type.Canonicalize());
+    return Api::NewHandle(I, type.Canonicalize());
   }
   // Set up the type arguments array for the super class type.
   const Class& super_cls = Class::Handle(cls.SuperClass());
@@ -657,7 +629,7 @@
       Type::New(super_cls, super_type_args_array, Scanner::kNoSourcePos));
   ASSERT(!instantiated_type.IsNull());
   instantiated_type.SetIsFinalized();
-  return Api::NewHandle(isolate, instantiated_type.Canonicalize());
+  return Api::NewHandle(I, instantiated_type.Canonicalize());
 }
 
 
@@ -666,8 +638,7 @@
                             Dart_Handle* name,
                             Dart_Handle* signature,
                             Dart_CodeLocation* location) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(Instance, instance, closure);
   CHECK_NOT_NULL(location);
 
@@ -677,26 +648,26 @@
   const Function& func = Function::Handle(Closure::function(instance));
   ASSERT(!func.IsNull());
   if (name != NULL) {
-    *name = Api::NewHandle(isolate, func.QualifiedUserVisibleName());
+    *name = Api::NewHandle(I, func.QualifiedUserVisibleName());
   }
   if (signature != NULL) {
-    *signature = Api::NewHandle(isolate, func.UserVisibleSignature());
+    *signature = Api::NewHandle(I, func.UserVisibleSignature());
   }
 
   if (location != NULL) {
     if (func.token_pos() >= 0) {
-      const Class& cls = Class::Handle(func.origin());
+      const Class& cls = Class::Handle(Z, func.origin());
       ASSERT(!cls.IsNull());
-      const Library& lib = Library::Handle(isolate, cls.library());
+      const Library& lib = Library::Handle(Z, cls.library());
       ASSERT(!lib.IsNull());
       // Note func.script() is not the same as cls.script() for eval functions.
-      const Script& script = Script::Handle(func.script());
+      const Script& script = Script::Handle(Z, func.script());
       ASSERT(!script.IsNull());
-      location->script_url = Api::NewHandle(isolate, script.url());
+      location->script_url = Api::NewHandle(I, script.url());
       location->library_id = lib.index();
       location->token_pos = func.token_pos();
     } else {
-      location->script_url = Api::NewHandle(isolate, String::null());
+      location->script_url = Api::NewHandle(I, String::null());
       location->library_id = -1;
       location->token_pos = -1;
     }
@@ -711,30 +682,29 @@
                             intptr_t* library_id,
                             intptr_t* super_class_id,
                             Dart_Handle* static_fields) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  if (!isolate->class_table()->IsValidIndex(cls_id)) {
+  DARTSCOPE(Thread::Current());
+  if (!I->class_table()->IsValidIndex(cls_id)) {
     return Api::NewError("%s: %" Pd " is not a valid class id",
                          CURRENT_FUNC, cls_id);
   }
-  Class& cls = Class::Handle(isolate, isolate->class_table()->At(cls_id));
+  Class& cls = Class::Handle(Z, I->class_table()->At(cls_id));
   if (class_name != NULL) {
-    *class_name = Api::NewHandle(isolate, cls.Name());
+    *class_name = Api::NewHandle(I, cls.Name());
   }
   if (library_id != NULL) {
-    const Library& lib = Library::Handle(isolate, cls.library());
+    const Library& lib = Library::Handle(Z, cls.library());
     *library_id = lib.index();
   }
   if (super_class_id != NULL) {
     *super_class_id = 0;
-    Class& super_cls = Class::Handle(isolate, cls.SuperClass());
+    Class& super_cls = Class::Handle(Z, cls.SuperClass());
     if (!super_cls.IsNull()) {
       *super_class_id = super_cls.id();
     }
   }
   if (static_fields != NULL) {
     *static_fields =
-        Api::NewHandle(isolate, isolate->debugger()->GetStaticFields(cls));
+        Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
   }
   return Api::Success();
 }
@@ -743,8 +713,7 @@
 DART_EXPORT Dart_Handle Dart_ScriptGetSource(
                             intptr_t library_id,
                             Dart_Handle script_url_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   const Library& lib = Library::Handle(Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
@@ -757,15 +726,14 @@
                          CURRENT_FUNC, script_url.ToCString(),
                          String::Handle(lib.url()).ToCString());
   }
-  return Api::NewHandle(isolate, script.Source());
+  return Api::NewHandle(I, script.Source());
 }
 
 
 DART_EXPORT Dart_Handle Dart_ScriptGetTokenInfo(
                             intptr_t library_id,
                             Dart_Handle script_url_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   const Library& lib = Library::Handle(Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
@@ -781,14 +749,13 @@
 
   const GrowableObjectArray& info =
       GrowableObjectArray::Handle(script.GenerateLineNumberArray());
-  return Api::NewHandle(isolate, Array::MakeArray(info));
+  return Api::NewHandle(I, Array::MakeArray(info));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GenerateScriptSource(Dart_Handle library_url_in,
                                                   Dart_Handle script_url_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(String, library_url, library_url_in);
   UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
 
@@ -805,13 +772,12 @@
                          library_url.ToCString());
   }
 
-  return Api::NewHandle(isolate, script.GenerateSource());
+  return Api::NewHandle(I, script.GenerateSource());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetScriptURLs(Dart_Handle library_url_in) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   UNWRAP_AND_CHECK_PARAM(String, library_url, library_url_in);
 
   const Library& library = Library::Handle(Library::LookupLibrary(library_url));
@@ -830,52 +796,47 @@
     url = script.url();
     script_list.SetAt(i, url);
   }
-  return Api::NewHandle(isolate, script_list.raw());
+  return Api::NewHandle(I, script_list.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryIds() {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
 
   const GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(isolate->object_store()->libraries());
+      GrowableObjectArray::Handle(Z, I->object_store()->libraries());
   int num_libs = libs.Length();
 
   // Create new list and populate with the url of loaded libraries.
   Library &lib = Library::Handle();
-  const Array& library_id_list = Array::Handle(Array::New(num_libs));
+  const Array& library_id_list = Array::Handle(Z, Array::New(num_libs));
   for (int i = 0; i < num_libs; i++) {
     lib ^= libs.At(i);
     ASSERT(!lib.IsNull());
     ASSERT(Smi::IsValid(lib.index()));
     library_id_list.SetAt(i, Smi::Handle(Smi::New(lib.index())));
   }
-  return Api::NewHandle(isolate, library_id_list.raw());
+  return Api::NewHandle(I, library_id_list.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryFromId(intptr_t library_id) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
-  const Library& lib = Library::Handle(Library::GetLibrary(library_id));
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(isolate, lib.raw());
+  return Api::NewHandle(I, lib.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_LibraryId(Dart_Handle library,
                                        intptr_t* library_id) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
   if (library_id == NULL) {
     RETURN_NULL_ERROR(library_id);
@@ -886,9 +847,7 @@
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryImports(intptr_t library_id) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   const Library& lib = Library::Handle(Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
@@ -897,18 +856,18 @@
   const GrowableObjectArray& import_list =
       GrowableObjectArray::Handle(GrowableObjectArray::New(8));
 
-  String& prefix_name = String::Handle(isolate);
-  Library& imported = Library::Handle(isolate);
+  String& prefix_name = String::Handle(Z);
+  Library& imported = Library::Handle(Z);
   intptr_t num_imports = lib.num_imports();
   for (int i = 0; i < num_imports; i++) {
     import_list.Add(prefix_name);  // Null prefix name means no prefix.
     imported = lib.ImportLibraryAt(i);
     ASSERT(!imported.IsNull());
     ASSERT(Smi::IsValid(imported.index()));
-    import_list.Add(Smi::Handle(Smi::New(imported.index())));
+    import_list.Add(Smi::Handle(Z, Smi::New(imported.index())));
   }
   LibraryPrefixIterator it(lib);
-  LibraryPrefix& prefix = LibraryPrefix::Handle(isolate);
+  LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
   while (it.HasNext()) {
     prefix = it.GetNext();
     prefix_name = prefix.name();
@@ -920,28 +879,24 @@
       import_list.Add(Smi::Handle(Smi::New(imported.index())));
     }
   }
-  return Api::NewHandle(isolate, Array::MakeArray(import_list));
+  return Api::NewHandle(I, Array::MakeArray(import_list));
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryURL(intptr_t library_id) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
-  const Library& lib = Library::Handle(Library::GetLibrary(library_id));
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
   }
-  return Api::NewHandle(isolate, lib.url());
+  return Api::NewHandle(I, lib.url());
 }
 
 
 DART_EXPORT Dart_Handle Dart_GetLibraryDebuggable(intptr_t library_id,
                                                   bool* is_debuggable) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   CHECK_NOT_NULL(is_debuggable);
   const Library& lib = Library::Handle(Library::GetLibrary(library_id));
   if (lib.IsNull()) {
@@ -955,10 +910,8 @@
 
 DART_EXPORT Dart_Handle Dart_SetLibraryDebuggable(intptr_t library_id,
                                                   bool is_debuggable) {
-  Isolate* isolate = Isolate::Current();
-  ASSERT(isolate != NULL);
-  DARTSCOPE(isolate);
-  const Library& lib = Library::Handle(Library::GetLibrary(library_id));
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
   if (lib.IsNull()) {
     return Api::NewError("%s: %" Pd " is not a valid library id",
                          CURRENT_FUNC, library_id);
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index f67b684..96ff8d3 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -27,7 +27,7 @@
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
 
-  StackZone zone(isolate);
+  StackZone zone(thread);
   String& url = String::Handle(String::New("dart-test:FindCodeObject"));
   String& source = String::Handle();
   Script& script = Script::Handle();
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 8214f69..371ec0e 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2331,10 +2331,11 @@
   // We need to create a new await state which involves:
   // * Increase the jump counter. Sanity check against the list of targets.
   // * Save the current context for resuming.
-  ASSERT(node->scope() != NULL);
-  LocalVariable* jump_var = node->scope()->LookupVariable(
+  ASSERT(node->async_scope() != NULL);
+  ASSERT(node->await_scope() != NULL);
+  LocalVariable* jump_var = node->async_scope()->LookupVariable(
       Symbols::AwaitJumpVar(), false);
-  LocalVariable* ctx_var = node->scope()->LookupVariable(
+  LocalVariable* ctx_var = node->async_scope()->LookupVariable(
       Symbols::AwaitContextVar(), false);
   ASSERT((jump_var != NULL) && jump_var->is_captured());
   ASSERT((ctx_var != NULL) && ctx_var->is_captured());
diff --git a/runtime/vm/growable_array.h b/runtime/vm/growable_array.h
index 88163fb..9023948 100644
--- a/runtime/vm/growable_array.h
+++ b/runtime/vm/growable_array.h
@@ -215,6 +215,10 @@
     return operator[](index);
   }
 
+  void SetAt(intptr_t index, const T& t) {
+    array_[index] = &T::ZoneHandle(zone_, t.raw());
+  }
+
   intptr_t length() const { return array_.length(); }
 
   const GrowableArray<T*>& growable_array() const { return array_; }
diff --git a/runtime/vm/handles.cc b/runtime/vm/handles.cc
index c053542..7057739 100644
--- a/runtime/vm/handles.cc
+++ b/runtime/vm/handles.cc
@@ -109,11 +109,6 @@
 }
 
 
-HandleScope::HandleScope(Isolate* isolate) : StackResource(isolate) {
-  Initialize();
-}
-
-
 HandleScope::~HandleScope() {
   ASSERT(thread()->zone() != NULL);
   VMHandles* handles = thread()->zone()->handles();
@@ -130,13 +125,8 @@
 
 
 #if defined(DEBUG)
-NoHandleScope::NoHandleScope(Isolate* isolate) : StackResource(isolate) {
-  thread()->IncrementNoHandleScopeDepth();
-}
-
-
-NoHandleScope::NoHandleScope() : StackResource(Thread::Current()) {
-  thread()->IncrementNoHandleScopeDepth();
+NoHandleScope::NoHandleScope(Thread* thread) : StackResource(thread) {
+  thread->IncrementNoHandleScopeDepth();
 }
 
 
diff --git a/runtime/vm/handles.h b/runtime/vm/handles.h
index f86d0bb..343d139 100644
--- a/runtime/vm/handles.h
+++ b/runtime/vm/handles.h
@@ -301,8 +301,6 @@
 class HandleScope : public StackResource {
  public:
   explicit HandleScope(Thread* thread);
-  // DEPRECATED: Use Thread version.
-  explicit HandleScope(Isolate* isolate);
   ~HandleScope();
 
  private:
@@ -337,9 +335,6 @@
 class NoHandleScope : public StackResource {
  public:
   explicit NoHandleScope(Thread* thread);
-  // DEPRECATED: Use Thread version.
-  explicit NoHandleScope(Isolate* isolate);
-  NoHandleScope();
   ~NoHandleScope();
 
  private:
diff --git a/runtime/vm/handles_test.cc b/runtime/vm/handles_test.cc
index cc82f26..b871f97 100644
--- a/runtime/vm/handles_test.cc
+++ b/runtime/vm/handles_test.cc
@@ -49,8 +49,8 @@
   static const int kNumHandles = 65;
   // Create some scoped handles.
   {
-    Isolate* isolate = Isolate::Current();
-    HANDLESCOPE(isolate);
+    Thread* thread = Thread::Current();
+    HANDLESCOPE(thread);
     for (int i = 0; i < kNumHandles; i++) {
       const Smi& handle = Smi::Handle(Smi::New(i));
       EXPECT(handle.IsSmi());
@@ -59,7 +59,7 @@
     EXPECT_EQ((handle_count + kNumHandles), VMHandles::ScopedHandleCount());
     // Create lots of scoped handles in a loop with a nested scope.
     for (int loop = 0; loop < 1000; loop++) {
-      HANDLESCOPE(isolate);
+      HANDLESCOPE(thread);
       for (int i = 0; i < 2; i++) {
         const Smi& handle = Smi::Handle(Smi::New(i + loop));
         EXPECT(handle.IsSmi());
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index b7bacba..7f4a862 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1630,7 +1630,9 @@
 
   switch (op_kind()) {
     case Token::kNEGATE:
-      result = value.ArithmeticOp(Token::kMUL, Smi::Handle(Smi::New(-1)));
+      result = value.ArithmeticOp(Token::kMUL,
+                                  Smi::Handle(Smi::New(-1)),
+                                  Heap::kOld);
       break;
 
     case Token::kBIT_NOT:
@@ -1675,7 +1677,7 @@
     case Token::kADD:
     case Token::kSUB:
     case Token::kMUL: {
-      result = left.ArithmeticOp(op_kind(), right);
+      result = left.ArithmeticOp(op_kind(), right, Heap::kOld);
       break;
     }
     case Token::kSHL:
@@ -3428,50 +3430,52 @@
       !num_elements->BoundConstant().IsSmi()) {
     return this;
   }
-  intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
-  GrowableArray<ConstantInstr*> constants(length);
+  const intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+  Zone* zone = Thread::Current()->zone();
+  GrowableHandlePtrArray<const String> pieces(zone, length);
   for (intptr_t i = 0; i < length; i++) {
-    constants.Add(NULL);
+    pieces.Add(Object::null_string());
   }
+
   for (Value::Iterator it(create_array->input_use_list());
        !it.Done();
        it.Advance()) {
     Instruction* curr = it.Current()->instruction();
-    if (curr != this) {
-      StoreIndexedInstr* store = curr->AsStoreIndexed();
-      ASSERT(store != NULL);
-      if (store->value()->definition()->IsConstant()) {
-        ASSERT(store->index()->BindsToConstant());
-        const Object& obj = store->value()->definition()->AsConstant()->value();
-        if (obj.IsNumber() || obj.IsString() || obj.IsBool() || obj.IsNull()) {
-          constants[Smi::Cast(store->index()->BoundConstant()).Value()] =
-              store->value()->definition()->AsConstant();
-        } else {
-          return this;
-        }
+    if (curr == this) continue;
+
+    StoreIndexedInstr* store = curr->AsStoreIndexed();
+    if (!store->index()->BindsToConstant() ||
+        !store->index()->BoundConstant().IsSmi()) {
+      return this;
+    }
+    intptr_t store_index = Smi::Cast(store->index()->BoundConstant()).Value();
+    ASSERT(store_index < length);
+    ASSERT(store != NULL);
+    if (store->value()->definition()->IsConstant()) {
+      ASSERT(store->index()->BindsToConstant());
+      const Object& obj = store->value()->definition()->AsConstant()->value();
+      // TODO(srdjan): Verify if any other types should be converted as well.
+      if (obj.IsString()) {
+        pieces.SetAt(store_index, String::Cast(obj));
+      } else if (obj.IsSmi()) {
+        const char* cstr = obj.ToCString();
+        pieces.SetAt(store_index, String::Handle(zone, String::New(cstr)));
+      } else if (obj.IsBool()) {
+        pieces.SetAt(store_index,
+            Bool::Cast(obj).value() ? Symbols::True() : Symbols::False());
+      } else if (obj.IsNull()) {
+        pieces.SetAt(store_index, Symbols::Null());
       } else {
         return this;
       }
+    } else {
+      return this;
     }
   }
-  // Interpolate string at compile time.
-  const Array& array_argument =
-      Array::Handle(Array::New(length));
-  for (intptr_t i = 0; i < constants.length(); i++) {
-    array_argument.SetAt(i, constants[i]->value());
-  }
-  // Build argument array to pass to the interpolation function.
-  const Array& interpolate_arg = Array::Handle(Array::New(1));
-  interpolate_arg.SetAt(0, array_argument);
-  // Call interpolation function.
-  const Object& result = Object::Handle(
-      DartEntry::InvokeFunction(CallFunction(), interpolate_arg));
-  if (result.IsUnhandledException()) {
-    return this;
-  }
-  ASSERT(result.IsString());
-  const String& concatenated =
-      String::ZoneHandle(Symbols::New(String::Cast(result)));
+
+  ASSERT(pieces.length() == length);
+  const String& concatenated = String::ZoneHandle(zone,
+      Symbols::FromConcatAll(pieces));
   return flow_graph->GetConstant(concatenated);
 }
 
@@ -3518,71 +3522,71 @@
 typedef double (*UnaryMathCFunction) (double x);
 typedef double (*BinaryMathCFunction) (double x, double y);
 
-extern const RuntimeEntry kPowRuntimeEntry(
-    "libc_pow", reinterpret_cast<RuntimeFunction>(
-        static_cast<BinaryMathCFunction>(&pow)), 2, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcPow, 2, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<BinaryMathCFunction>(&pow)));
 
-extern const RuntimeEntry kModRuntimeEntry(
-    "DartModulo", reinterpret_cast<RuntimeFunction>(
-        static_cast<BinaryMathCFunction>(&DartModulo)), 2, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(DartModulo, 2, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<BinaryMathCFunction>(&DartModulo)));
 
-extern const RuntimeEntry kFloorRuntimeEntry(
-    "libc_floor", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&floor)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcFloor, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&floor)));
 
-extern const RuntimeEntry kCeilRuntimeEntry(
-    "libc_ceil", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&ceil)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCeil, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&ceil)));
 
-extern const RuntimeEntry kTruncRuntimeEntry(
-    "libc_trunc", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&trunc)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTrunc, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&trunc)));
 
-extern const RuntimeEntry kRoundRuntimeEntry(
-    "libc_round", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&round)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcRound, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&round)));
 
 
 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const {
   switch (recognized_kind_) {
     case MethodRecognizer::kDoubleTruncate:
-      return kTruncRuntimeEntry;
+      return kLibcTruncRuntimeEntry;
     case MethodRecognizer::kDoubleRound:
-      return kRoundRuntimeEntry;
+      return kLibcRoundRuntimeEntry;
     case MethodRecognizer::kDoubleFloor:
-      return kFloorRuntimeEntry;
+      return kLibcFloorRuntimeEntry;
     case MethodRecognizer::kDoubleCeil:
-      return kCeilRuntimeEntry;
+      return kLibcCeilRuntimeEntry;
     case MethodRecognizer::kMathDoublePow:
-      return kPowRuntimeEntry;
+      return kLibcPowRuntimeEntry;
     case MethodRecognizer::kDoubleMod:
-      return kModRuntimeEntry;
+      return kDartModuloRuntimeEntry;
     default:
       UNREACHABLE();
   }
-  return kPowRuntimeEntry;
+  return kLibcPowRuntimeEntry;
 }
 
 
-extern const RuntimeEntry kCosRuntimeEntry(
-    "libc_cos", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&cos)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCos, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&cos)));
 
-extern const RuntimeEntry kSinRuntimeEntry(
-    "libc_sin", reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&sin)), 1, true, true);
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcSin, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&sin)));
 
 
 const RuntimeEntry& MathUnaryInstr::TargetFunction() const {
   switch (kind()) {
     case MathUnaryInstr::kSin:
-      return kSinRuntimeEntry;
+      return kLibcSinRuntimeEntry;
     case MathUnaryInstr::kCos:
-      return kCosRuntimeEntry;
+      return kLibcCosRuntimeEntry;
     default:
       UNREACHABLE();
   }
-  return kSinRuntimeEntry;
+  return kLibcSinRuntimeEntry;
 }
 
 
@@ -3598,18 +3602,6 @@
   return "";
 }
 
-typedef RawBool* (*CaseInsensitiveCompareUC16Function) (
-    RawString* string_raw,
-    RawSmi* lhs_index_raw,
-    RawSmi* rhs_index_raw,
-    RawSmi* length_raw);
-
-
-extern const RuntimeEntry kCaseInsensitiveCompareUC16RuntimeEntry(
-    "CaseInsensitiveCompareUC16", reinterpret_cast<RuntimeFunction>(
-        static_cast<CaseInsensitiveCompareUC16Function>(
-        &IRRegExpMacroAssembler::CaseInsensitiveCompareUC16)), 4, true, false);
-
 
 const RuntimeEntry& CaseInsensitiveCompareUC16Instr::TargetFunction() const {
   return kCaseInsensitiveCompareUC16RuntimeEntry;
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 4d6c56c..bb1fe76 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -95,7 +95,8 @@
                     "Enable checked mode.");
 
 
-// Quick access to the locally defined isolate() method.
+// Quick access to the locally defined thread() and isolate() methods.
+#define T (thread())
 #define I (isolate())
 
 #if defined(DEBUG)
@@ -418,9 +419,7 @@
   }
 
   // Parse the message.
-  MessageSnapshotReader reader(message->data(),
-                               message->len(),
-                               I, zone);
+  MessageSnapshotReader reader(message->data(), message->len(), thread);
   const Object& msg_obj = Object::Handle(zone, reader.ReadObject());
   if (msg_obj.IsError()) {
     // An error occurred while reading the message.
@@ -508,28 +507,28 @@
 
 void IsolateMessageHandler::NotifyPauseOnStart() {
   if (Service::debug_stream.enabled()) {
-    StartIsolateScope start_isolate(isolate());
-    StackZone zone(I);
-    HandleScope handle_scope(I);
-    ServiceEvent pause_event(isolate(), ServiceEvent::kPauseStart);
+    StartIsolateScope start_isolate(I);
+    StackZone zone(T);
+    HandleScope handle_scope(T);
+    ServiceEvent pause_event(I, ServiceEvent::kPauseStart);
     Service::HandleEvent(&pause_event);
   } else if (FLAG_trace_service) {
     OS::Print("vm-service: Dropping event of type PauseStart (%s)\n",
-              isolate()->name());
+              I->name());
   }
 }
 
 
 void IsolateMessageHandler::NotifyPauseOnExit() {
   if (Service::debug_stream.enabled()) {
-    StartIsolateScope start_isolate(isolate());
-    StackZone zone(I);
-    HandleScope handle_scope(I);
-    ServiceEvent pause_event(isolate(), ServiceEvent::kPauseExit);
+    StartIsolateScope start_isolate(I);
+    StackZone zone(T);
+    HandleScope handle_scope(T);
+    ServiceEvent pause_event(I, ServiceEvent::kPauseExit);
     Service::HandleEvent(&pause_event);
   } else if (FLAG_trace_service) {
     OS::Print("vm-service: Dropping event of type PauseExit (%s)\n",
-              isolate()->name());
+              I->name());
   }
 }
 
@@ -1265,6 +1264,7 @@
 static bool RunIsolate(uword parameter) {
   Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
   IsolateSpawnState* state = NULL;
+  Thread* thread = Thread::Current();
   {
     // TODO(turnidge): Is this locking required here at all anymore?
     MutexLocker ml(isolate->mutex());
@@ -1272,8 +1272,9 @@
   }
   {
     StartIsolateScope start_scope(isolate);
-    StackZone zone(isolate);
-    HandleScope handle_scope(isolate);
+    ASSERT(thread->isolate() == isolate);
+    StackZone zone(thread);
+    HandleScope handle_scope(thread);
 
     // If particular values were requested for this newly spawned isolate, then
     // they are set here before the isolate starts executing user code.
@@ -1342,8 +1343,8 @@
     const Array& args = Array::Handle(Array::New(7));
     args.SetAt(0, SendPort::Handle(SendPort::New(state->parent_port())));
     args.SetAt(1, Instance::Handle(func.ImplicitStaticClosure()));
-    args.SetAt(2, Instance::Handle(state->BuildArgs(zone.GetZone())));
-    args.SetAt(3, Instance::Handle(state->BuildMessage(zone.GetZone())));
+    args.SetAt(2, Instance::Handle(state->BuildArgs(thread)));
+    args.SetAt(3, Instance::Handle(state->BuildMessage(thread)));
     args.SetAt(4, is_spawn_uri ? Bool::True() : Bool::False());
     args.SetAt(5, ReceivePort::Handle(
         ReceivePort::New(isolate->main_port(), true /* control port */)));
@@ -1370,9 +1371,11 @@
   {
     // Print the error if there is one.  This may execute dart code to
     // print the exception object, so we need to use a StartIsolateScope.
+    Thread* thread = Thread::Current();
     StartIsolateScope start_scope(isolate);
-    StackZone zone(isolate);
-    HandleScope handle_scope(isolate);
+    ASSERT(thread->isolate() == isolate);
+    StackZone zone(thread);
+    HandleScope handle_scope(thread);
     Error& error = Error::Handle();
     error = isolate->object_store()->sticky_error();
     if (!error.IsNull() && !error.IsUnwindError()) {
@@ -1493,11 +1496,13 @@
   }
 #endif  // DEBUG
 
+  Thread* thread = Thread::Current();
+
   // First, perform higher-level cleanup that may need to allocate.
   {
     // Ensure we have a zone and handle scope so that we can call VM functions.
-    StackZone stack_zone(this);
-    HandleScope handle_scope(this);
+    StackZone stack_zone(thread);
+    HandleScope handle_scope(thread);
 
     // Write out the coverage data if collection has been enabled.
     CodeCoverage::Write(this);
@@ -1521,8 +1526,8 @@
   {
     // Ensure we have a zone and handle scope so that we can call VM functions,
     // but we no longer allocate new heap objects.
-    StackZone stack_zone(this);
-    HandleScope handle_scope(this);
+    StackZone stack_zone(thread);
+    HandleScope handle_scope(thread);
     NoSafepointScope no_safepoint_scope;
 
     if (compiler_stats_ != NULL) {
@@ -2145,28 +2150,25 @@
 }
 
 
-template<class T>
-T* Isolate::AllocateReusableHandle() {
-  T* handle = reinterpret_cast<T*>(reusable_handles_.AllocateScopedHandle());
-  T::initializeHandle(handle, T::null());
+template<class C>
+C* Isolate::AllocateReusableHandle() {
+  C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle());
+  C::initializeHandle(handle, C::null());
   return handle;
 }
 
 
-static RawInstance* DeserializeObject(Isolate* isolate,
-                                      Zone* zone,
+static RawInstance* DeserializeObject(Thread* thread,
                                       uint8_t* obj_data,
                                       intptr_t obj_len) {
   if (obj_data == NULL) {
     return Instance::null();
   }
-  MessageSnapshotReader reader(obj_data,
-                               obj_len,
-                               isolate,
-                               zone);
-  const Object& obj = Object::Handle(isolate, reader.ReadObject());
+  MessageSnapshotReader reader(obj_data, obj_len, thread);
+  Zone* zone = thread->zone();
+  const Object& obj = Object::Handle(zone, reader.ReadObject());
   ASSERT(!obj.IsError());
-  Instance& instance = Instance::Handle(isolate);
+  Instance& instance = Instance::Handle(zone);
   instance ^= obj.raw();  // Can't use Instance::Cast because may be null.
   return instance.raw();
 }
@@ -2341,14 +2343,13 @@
 }
 
 
-RawInstance* IsolateSpawnState::BuildArgs(Zone* zone) {
-  return DeserializeObject(isolate_, zone,
-                           serialized_args_, serialized_args_len_);
+RawInstance* IsolateSpawnState::BuildArgs(Thread* thread) {
+  return DeserializeObject(thread, serialized_args_, serialized_args_len_);
 }
 
 
-RawInstance* IsolateSpawnState::BuildMessage(Zone* zone) {
-  return DeserializeObject(isolate_, zone,
+RawInstance* IsolateSpawnState::BuildMessage(Thread* thread) {
+  return DeserializeObject(thread,
                            serialized_message_, serialized_message_len_);
 }
 
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 90f97c4..b8e7a4c 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1102,8 +1102,8 @@
   Isolate::Flags* isolate_flags() { return &isolate_flags_; }
 
   RawObject* ResolveFunction();
-  RawInstance* BuildArgs(Zone* zone);
-  RawInstance* BuildMessage(Zone* zone);
+  RawInstance* BuildArgs(Thread* thread);
+  RawInstance* BuildMessage(Thread* thread);
   void Cleanup();
 
  private:
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index 78c5f6c..4a939ae 100644
--- a/runtime/vm/message_handler.h
+++ b/runtime/vm/message_handler.h
@@ -184,6 +184,9 @@
   virtual void NotifyPauseOnStart() {}
   virtual void NotifyPauseOnExit() {}
 
+  // TODO(iposva): Set a local field before entering MessageHandler methods.
+  Thread* thread() const { return Thread::Current(); }
+
  private:
   friend class PortMap;
   friend class MessageHandlerTestPeer;
diff --git a/runtime/vm/metrics_test.cc b/runtime/vm/metrics_test.cc
index 9082739..cb204b9 100644
--- a/runtime/vm/metrics_test.cc
+++ b/runtime/vm/metrics_test.cc
@@ -46,9 +46,9 @@
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
   {
-    Isolate* isolate = Isolate::Current();
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    Thread* thread = Thread::Current();
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     MyMetric metric;
 
     metric.Init(Isolate::Current(), "a.b.c", "foobar", Metric::kByte);
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index d775e22..3d83d44 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -19,37 +19,38 @@
 
 namespace dart {
 
+// Facilitate quick access to the current zone once we have the curren thread.
+#define Z (T->zone())
+
 
 // --- Classes and Interfaces Reflection ---
 
 DART_EXPORT Dart_Handle Dart_TypeName(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(I, Api::UnwrapHandle(object));
   if (obj.IsType()) {
     const Class& cls = Class::Handle(Type::Cast(obj).type_class());
-    return Api::NewHandle(isolate, cls.UserVisibleName());
+    return Api::NewHandle(I, cls.UserVisibleName());
   } else {
-    RETURN_TYPE_ERROR(isolate, object, Class/Type);
+    RETURN_TYPE_ERROR(I, object, Class/Type);
   }
 }
 
 
 DART_EXPORT Dart_Handle Dart_QualifiedTypeName(Dart_Handle object) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
   if (obj.IsType() || obj.IsClass()) {
     const Class& cls = (obj.IsType()) ?
-        Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
+        Class::Handle(Z, Type::Cast(obj).type_class()) : Class::Cast(obj);
     const char* str = cls.ToCString();
     if (str == NULL) {
       RETURN_NULL_ERROR(str);
     }
-    CHECK_CALLBACK_STATE(isolate);
-    return Api::NewHandle(isolate, String::New(str));
+    CHECK_CALLBACK_STATE(I);
+    return Api::NewHandle(I, String::New(str));
   } else {
-    RETURN_TYPE_ERROR(isolate, object, Class/Type);
+    RETURN_TYPE_ERROR(I, object, Class/Type);
   }
 }
 
@@ -69,25 +70,24 @@
 
 
 DART_EXPORT Dart_Handle Dart_GetFunctionNames(Dart_Handle target) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(target));
   if (obj.IsError()) {
     return target;
   }
 
   const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
-  Function& func = Function::Handle();
-  String& name = String::Handle();
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+  Function& func = Function::Handle(Z);
+  String& name = String::Handle(Z);
 
   if (obj.IsType()) {
-    const Class& cls = Class::Handle(Type::Cast(obj).type_class());
-    const Error& error = Error::Handle(isolate, cls.EnsureIsFinalized(isolate));
+    const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
+    const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(I));
     if (!error.IsNull()) {
-      return Api::NewHandle(isolate, error.raw());
+      return Api::NewHandle(I, error.raw());
     }
-    const Array& func_array = Array::Handle(cls.functions());
+    const Array& func_array = Array::Handle(Z, cls.functions());
 
     // Some special types like 'dynamic' have a null functions list.
     if (!func_array.IsNull()) {
@@ -124,27 +124,26 @@
         "%s expects argument 'target' to be a class or library.",
         CURRENT_FUNC);
   }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
+  return Api::NewHandle(I, Array::MakeArray(names));
 }
 
 
 DART_EXPORT Dart_Handle Dart_LookupFunction(Dart_Handle target,
                                             Dart_Handle function_name) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target));
+  DARTSCOPE(Thread::Current());
+  const Object& obj = Object::Handle(Z, Api::UnwrapHandle(target));
   if (obj.IsError()) {
     return target;
   }
-  const String& func_name = Api::UnwrapStringHandle(isolate, function_name);
+  const String& func_name = Api::UnwrapStringHandle(I, function_name);
   if (func_name.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function_name, String);
+    RETURN_TYPE_ERROR(I, function_name, String);
   }
 
-  Function& func = Function::Handle(isolate);
-  String& tmp_name = String::Handle(isolate);
+  Function& func = Function::Handle(Z);
+  String& tmp_name = String::Handle(Z);
   if (obj.IsType()) {
-    const Class& cls = Class::Handle(Type::Cast(obj).type_class());
+    const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
 
     // Case 1.  Lookup the unmodified function name.
     func = cls.LookupFunctionAllowPrivate(func_name);
@@ -206,60 +205,57 @@
            func_kind == RawFunction::kConstructor);
   }
 #endif
-  return Api::NewHandle(isolate, func.raw());
+  return Api::NewHandle(I, func.raw());
 }
 
 
 DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  DARTSCOPE(Thread::Current());
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
-  return Api::NewHandle(isolate, func.UserVisibleName());
+  return Api::NewHandle(I, func.UserVisibleName());
 }
 
 
 DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  DARTSCOPE(Thread::Current());
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
   if (func.IsNonImplicitClosureFunction()) {
     RawFunction* parent_function = func.parent_function();
-    return Api::NewHandle(isolate, parent_function);
+    return Api::NewHandle(I, parent_function);
   }
-  const Class& owner = Class::Handle(func.Owner());
+  const Class& owner = Class::Handle(Z, func.Owner());
   ASSERT(!owner.IsNull());
   if (owner.IsTopLevel()) {
     // Top-level functions are implemented as members of a hidden class. We hide
     // that class here and instead answer the library.
 #if defined(DEBUG)
-    const Library& lib = Library::Handle(owner.library());
+    const Library& lib = Library::Handle(Z, owner.library());
     if (lib.IsNull()) {
       ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
     }
 #endif
-    return Api::NewHandle(isolate, owner.library());
+    return Api::NewHandle(I, owner.library());
   } else {
-    return Api::NewHandle(isolate, owner.RareType());
+    return Api::NewHandle(I, owner.RareType());
   }
 }
 
 
 DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
                                               bool* is_static) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (is_static == NULL) {
     RETURN_NULL_ERROR(is_static);
   }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
   *is_static = func.is_static();
   return Api::Success();
@@ -268,14 +264,13 @@
 
 DART_EXPORT Dart_Handle Dart_FunctionIsConstructor(Dart_Handle function,
                                                    bool* is_constructor) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (is_constructor == NULL) {
     RETURN_NULL_ERROR(is_constructor);
   }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
   *is_constructor = func.kind() == RawFunction::kConstructor;
   return Api::Success();
@@ -284,14 +279,13 @@
 
 DART_EXPORT Dart_Handle Dart_FunctionIsGetter(Dart_Handle function,
                                               bool* is_getter) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (is_getter == NULL) {
     RETURN_NULL_ERROR(is_getter);
   }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
   *is_getter = func.IsGetterFunction();
   return Api::Success();
@@ -300,14 +294,13 @@
 
 DART_EXPORT Dart_Handle Dart_FunctionIsSetter(Dart_Handle function,
                                               bool* is_setter) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
+  DARTSCOPE(Thread::Current());
   if (is_setter == NULL) {
     RETURN_NULL_ERROR(is_setter);
   }
-  const Function& func = Api::UnwrapFunctionHandle(isolate, function);
+  const Function& func = Api::UnwrapFunctionHandle(I, function);
   if (func.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, function, Function);
+    RETURN_TYPE_ERROR(I, function, Function);
   }
   *is_setter = (func.kind() == RawFunction::kSetterFunction);
   return Api::Success();
@@ -317,30 +310,28 @@
 // --- Libraries Reflection ---
 
 DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
-  const String& name = String::Handle(isolate, lib.name());
+  const String& name = String::Handle(Z, lib.name());
   ASSERT(!name.IsNull());
-  return Api::NewHandle(isolate, name.raw());
+  return Api::NewHandle(I, name.raw());
 }
 
 DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Library& lib = Api::UnwrapLibraryHandle(isolate, library);
+  DARTSCOPE(Thread::Current());
+  const Library& lib = Api::UnwrapLibraryHandle(I, library);
   if (lib.IsNull()) {
-    RETURN_TYPE_ERROR(isolate, library, Library);
+    RETURN_TYPE_ERROR(I, library, Library);
   }
 
   const GrowableObjectArray& names =
-      GrowableObjectArray::Handle(isolate, GrowableObjectArray::New());
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
   ClassDictionaryIterator it(lib);
-  Class& cls = Class::Handle();
-  String& name = String::Handle();
+  Class& cls = Class::Handle(Z);
+  String& name = String::Handle(Z);
   while (it.HasNext()) {
     cls = it.GetNextClass();
     if (cls.IsSignatureClass()) {
@@ -356,24 +347,23 @@
       names.Add(name);
     }
   }
-  return Api::NewHandle(isolate, Array::MakeArray(names));
+  return Api::NewHandle(I, Array::MakeArray(names));
 }
 
 
 // --- Closures Reflection ---
 
 DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  const Instance& closure_obj = Api::UnwrapInstanceHandle(isolate, closure);
+  DARTSCOPE(Thread::Current());
+  const Instance& closure_obj = Api::UnwrapInstanceHandle(I, closure);
   if (closure_obj.IsNull() || !closure_obj.IsClosure()) {
-    RETURN_TYPE_ERROR(isolate, closure, Instance);
+    RETURN_TYPE_ERROR(I, closure, Instance);
   }
 
   ASSERT(ClassFinalizer::AllClassesFinalized());
 
   RawFunction* rf = Closure::function(closure_obj);
-  return Api::NewHandle(isolate, rf);
+  return Api::NewHandle(I, rf);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index a668897..da1d099 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -11,7 +11,6 @@
 #include "vm/message.h"
 #include "vm/native_message_handler.h"
 #include "vm/port.h"
-#include "vm/precompiler.h"
 
 namespace dart {
 
@@ -80,39 +79,15 @@
   }
 }
 
-static void Precompile(Isolate* isolate, Dart_Handle* result) {
-  ASSERT(isolate != NULL);
-  const Error& error = Error::Handle(isolate, Precompiler::CompileAll());
-  if (error.IsNull()) {
-    *result = Api::Success();
-  } else {
-    *result = Api::NewHandle(isolate, error.raw());
-  }
-}
-
 
 DART_EXPORT Dart_Handle Dart_CompileAll() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Dart_Handle result = Api::CheckAndFinalizePendingClasses(isolate);
+  DARTSCOPE(Thread::Current());
+  Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
   if (::Dart_IsError(result)) {
     return result;
   }
-  CHECK_CALLBACK_STATE(isolate);
-  CompileAll(isolate, &result);
-  return result;
-}
-
-
-DART_EXPORT Dart_Handle Dart_Precompile() {
-  Isolate* isolate = Isolate::Current();
-  DARTSCOPE(isolate);
-  Dart_Handle result = Api::CheckAndFinalizePendingClasses(isolate);
-  if (::Dart_IsError(result)) {
-    return result;
-  }
-  CHECK_CALLBACK_STATE(isolate);
-  Precompile(isolate, &result);
+  CHECK_CALLBACK_STATE(I);
+  CompileAll(I, &result);
   return result;
 }
 
diff --git a/runtime/vm/native_entry_test.h b/runtime/vm/native_entry_test.h
index 7e51a24..706b4b6 100644
--- a/runtime/vm/native_entry_test.h
+++ b/runtime/vm/native_entry_test.h
@@ -10,9 +10,6 @@
 
 namespace dart {
 
-DECLARE_RUNTIME_ENTRY(TestSmiSub)
-DECLARE_LEAF_RUNTIME_ENTRY(RawObject*, TestLeafSmiAdd, RawObject*, RawObject*)
-
 void TestSmiSub(Dart_NativeArguments args);
 void TestSmiSum(Dart_NativeArguments args);
 void TestNonNullSmiSum(Dart_NativeArguments args);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 1d6e33b..86d461a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -115,6 +115,7 @@
 LanguageError* Object::snapshot_writer_error_ = NULL;
 LanguageError* Object::branch_offset_error_ = NULL;
 Array* Object::vm_isolate_snapshot_object_table_ = NULL;
+const uint8_t* Object::instructions_snapshot_buffer_ = NULL;
 
 RawObject* Object::null_ = reinterpret_cast<RawObject*>(RAW_NULL);
 RawClass* Object::class_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -2103,7 +2104,7 @@
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->functions_, value.raw());
   const intptr_t len = value.Length();
-  ClassFunctionsSet set(HashTables::New<ClassFunctionsSet>(len));
+  ClassFunctionsSet set(HashTables::New<ClassFunctionsSet>(len, Heap::kOld));
   if (len >= kFunctionLookupHashTreshold) {
     Function& func = Function::Handle();
     for (intptr_t i = 0; i < len; ++i) {
@@ -4831,7 +4832,8 @@
 RawTypeArguments* TypeArguments::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
   ASSERT(!IsInstantiated());
   if (!instantiator_type_arguments.IsNull() &&
       IsUninstantiatedIdentity() &&
@@ -4840,7 +4842,7 @@
   }
   const intptr_t num_types = Length();
   TypeArguments& instantiated_array =
-      TypeArguments::Handle(TypeArguments::New(num_types, Heap::kNew));
+      TypeArguments::Handle(TypeArguments::New(num_types, space));
   AbstractType& type = AbstractType::Handle();
   for (intptr_t i = 0; i < num_types; i++) {
     type = TypeAt(i);
@@ -4853,7 +4855,8 @@
     if (!type.IsNull() && !type.IsInstantiated()) {
       type = type.InstantiateFrom(instantiator_type_arguments,
                                   bound_error,
-                                  trail);
+                                  trail,
+                                  space);
     }
     instantiated_array.SetTypeAt(i, type);
   }
@@ -9027,7 +9030,8 @@
   if (LoadError() != Instance::null()) {
     return LoadError();
   }
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   ObjectStore* object_store = isolate->object_store();
   LibraryLoadErrorSet set(object_store->library_load_error_table());
   bool present = false;
@@ -9042,7 +9046,7 @@
   Library& lib = Library::Handle(isolate);
   Instance& error = Instance::Handle(isolate);
   for (intptr_t i = 0; i < num_imp; i++) {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     lib = ImportLibraryAt(i);
     error = lib.TransitiveLoadError();
     if (!error.IsNull()) {
@@ -10312,7 +10316,8 @@
 
 
 RawInstance* LibraryPrefix::LoadError() const {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   ObjectStore* object_store = isolate->object_store();
   GrowableObjectArray& libs =
       GrowableObjectArray::Handle(isolate, object_store->libraries());
@@ -10324,7 +10329,7 @@
   for (int32_t i = 0; i < num_imports(); i++) {
     lib = GetLibrary(i);
     ASSERT(!lib.IsNull());
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     error = lib.TransitiveLoadError();
     if (!error.IsNull()) {
       break;
@@ -10980,7 +10985,8 @@
 
 
 const char* ObjectPool::ToCString() const {
-  return "ObjectPool";
+  Zone* zone = Thread::Current()->zone();
+  return zone->PrintToString("ObjectPool len:%" Pd, Length());
 }
 
 
@@ -11709,7 +11715,7 @@
 
 const char* ExceptionHandlers::ToCString() const {
   if (num_entries() == 0) {
-    return "No exception handlers\n";
+    return "empty ExceptionHandlers\n";
   }
   Array& handled_types = Array::Handle();
   Type& type = Type::Handle();
@@ -13784,7 +13790,8 @@
     result ^= raw;
   }
   const intptr_t capacity = kInitialCapacity;
-  const Array& buckets = Array::Handle(Array::New(kEntryLength * capacity));
+  const Array& buckets = Array::Handle(
+      Array::New(kEntryLength * capacity, Heap::kOld));
   ASSERT(Isolate::Current()->megamorphic_cache_table()->miss_handler() != NULL);
   const Function& handler = Function::Handle(
       Isolate::Current()->megamorphic_cache_table()->miss_handler());
@@ -14188,7 +14195,7 @@
 const char* UnhandledException::ToErrorCString() const {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
   Object& strtmp = Object::Handle();
   const char* exc_str;
   if (exception() == isolate->object_store()->out_of_memory()) {
@@ -14921,7 +14928,8 @@
 RawAbstractType* AbstractType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
   // AbstractType is an abstract class.
   UNREACHABLE();
   return NULL;
@@ -15522,7 +15530,9 @@
 RawAbstractType* Type::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
+  Zone* zone = Thread::Current()->zone();
   ASSERT(IsFinalized() || IsBeingFinalized());
   ASSERT(!IsInstantiated());
   // Return the uninstantiated type unchanged if malformed. No copy needed.
@@ -15535,7 +15545,7 @@
     return raw();
   }
   // If this type is recursive, we may already be instantiating it.
-  Type& instantiated_type = Type::Handle();
+  Type& instantiated_type = Type::Handle(zone);
   instantiated_type ^= OnlyBuddyInTrail(trail);
   if (!instantiated_type.IsNull()) {
     ASSERT(IsRecursive());
@@ -15544,19 +15554,20 @@
   // Note that the type class has to be resolved at this time, but not
   // necessarily finalized yet. We may be checking bounds at compile time or
   // finalizing the type argument vector of a recursive type.
-  const Class& cls = Class::Handle(type_class());
+  const Class& cls = Class::Handle(zone, type_class());
 
   // This uninstantiated type is not modified, as it can be instantiated
   // with different instantiators. Allocate a new instantiated version of it.
-  instantiated_type = Type::New(cls, TypeArguments::Handle(), token_pos());
-  TypeArguments& type_arguments = TypeArguments::Handle(arguments());
+  instantiated_type = Type::New(cls, TypeArguments::Handle(zone), token_pos());
+  TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
   ASSERT(type_arguments.Length() == cls.NumTypeArguments());
   if (type_arguments.IsRecursive()) {
     AddOnlyBuddyToTrail(&trail, instantiated_type);
   }
   type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
                                                   bound_error,
-                                                  trail);
+                                                  trail,
+                                                  space);
   instantiated_type.set_arguments(type_arguments);
   if (IsFinalized()) {
     instantiated_type.SetIsFinalized();
@@ -15963,7 +15974,8 @@
 RawTypeRef* TypeRef::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
   TypeRef& instantiated_type_ref = TypeRef::Handle();
   instantiated_type_ref ^= OnlyBuddyInTrail(trail);
   if (!instantiated_type_ref.IsNull()) {
@@ -15973,7 +15985,7 @@
   ASSERT(!ref_type.IsTypeRef());
   AbstractType& instantiated_ref_type = AbstractType::Handle();
   instantiated_ref_type = ref_type.InstantiateFrom(
-      instantiator_type_arguments, bound_error, trail);
+      instantiator_type_arguments, bound_error, trail, space);
   ASSERT(!instantiated_ref_type.IsTypeRef());
   instantiated_type_ref = TypeRef::New(instantiated_ref_type);
   AddOnlyBuddyToTrail(&trail, instantiated_type_ref);
@@ -16177,7 +16189,8 @@
 RawAbstractType* TypeParameter::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
   ASSERT(IsFinalized());
   if (instantiator_type_arguments.IsNull()) {
     return Type::DynamicType();
@@ -16440,14 +16453,16 @@
 RawAbstractType* BoundedType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail) const {
+    TrailPtr trail,
+    Heap::Space space) const {
   ASSERT(IsFinalized());
   AbstractType& bounded_type = AbstractType::Handle(type());
   ASSERT(bounded_type.IsFinalized());
   if (!bounded_type.IsInstantiated()) {
     bounded_type = bounded_type.InstantiateFrom(instantiator_type_arguments,
                                                 bound_error,
-                                                trail);
+                                                trail,
+                                                space);
     // In case types of instantiator_type_arguments are not finalized, then
     // the instantiated bounded_type is not finalized either.
     // Note that instantiator_type_arguments must have the final length, though.
@@ -16461,7 +16476,8 @@
     if (!upper_bound.IsInstantiated()) {
       upper_bound = upper_bound.InstantiateFrom(instantiator_type_arguments,
                                                 bound_error,
-                                                trail);
+                                                trail,
+                                                space);
       // Instantiated upper_bound may not be finalized. See comment above.
     }
     if (bound_error->IsNull()) {
@@ -16852,7 +16868,8 @@
 
 
 RawInteger* Integer::ArithmeticOp(Token::Kind operation,
-                                  const Integer& other) const {
+                                  const Integer& other,
+                                  Heap::Space space) const {
   // In 32-bit mode, the result of any operation between two Smis will fit in a
   // 32-bit signed result, except the product of two Smis, which will be 64-bit.
   // In 64-bit mode, the result of any operation between two Smis will fit in a
@@ -16862,14 +16879,15 @@
     const intptr_t right_value = Smi::Value(Smi::RawCast(other.raw()));
     switch (operation) {
       case Token::kADD:
-        return Integer::New(left_value + right_value);
+        return Integer::New(left_value + right_value, space);
       case Token::kSUB:
-        return Integer::New(left_value - right_value);
+        return Integer::New(left_value - right_value, space);
       case Token::kMUL: {
         if (Smi::kBits < 32) {
           // In 32-bit mode, the product of two Smis fits in a 64-bit result.
           return Integer::New(static_cast<int64_t>(left_value) *
-                              static_cast<int64_t>(right_value));
+                              static_cast<int64_t>(right_value),
+                              space);
         } else {
           // In 64-bit mode, the product of two signed integers fits in a
           // 64-bit result if the sum of the highest bits of their absolute
@@ -16877,24 +16895,24 @@
           ASSERT(sizeof(intptr_t) == sizeof(int64_t));
           if ((Utils::HighestBit(left_value) +
                Utils::HighestBit(right_value)) < 62) {
-            return Integer::New(left_value * right_value);
+            return Integer::New(left_value * right_value, space);
           }
         }
         // Perform a Bigint multiplication below.
         break;
       }
       case Token::kTRUNCDIV:
-        return Integer::New(left_value / right_value);
+        return Integer::New(left_value / right_value, space);
       case Token::kMOD: {
         const intptr_t remainder = left_value % right_value;
         if (remainder < 0) {
           if (right_value < 0) {
-            return Integer::New(remainder - right_value);
+            return Integer::New(remainder - right_value, space);
           } else {
-            return Integer::New(remainder + right_value);
+            return Integer::New(remainder + right_value, space);
           }
         }
-        return Integer::New(remainder);
+        return Integer::New(remainder, space);
       }
       default:
         UNIMPLEMENTED();
@@ -16907,27 +16925,27 @@
       case Token::kADD: {
         if (((left_value < 0) != (right_value < 0)) ||
             ((left_value + right_value) < 0) == (left_value < 0)) {
-          return Integer::New(left_value + right_value);
+          return Integer::New(left_value + right_value, space);
         }
         break;
       }
       case Token::kSUB: {
         if (((left_value < 0) == (right_value < 0)) ||
             ((left_value - right_value) < 0) == (left_value < 0)) {
-          return Integer::New(left_value - right_value);
+          return Integer::New(left_value - right_value, space);
         }
         break;
       }
       case Token::kMUL: {
         if ((Utils::HighestBit(left_value) +
              Utils::HighestBit(right_value)) < 62) {
-          return Integer::New(left_value * right_value);
+          return Integer::New(left_value * right_value, space);
         }
         break;
       }
       case Token::kTRUNCDIV: {
         if ((left_value != Mint::kMinValue) || (right_value != -1)) {
-          return Integer::New(left_value / right_value);
+          return Integer::New(left_value / right_value, space);
         }
         break;
       }
@@ -16935,12 +16953,12 @@
         const int64_t remainder = left_value % right_value;
         if (remainder < 0) {
           if (right_value < 0) {
-            return Integer::New(remainder - right_value);
+            return Integer::New(remainder - right_value, space);
           } else {
-            return Integer::New(remainder + right_value);
+            return Integer::New(remainder + right_value, space);
           }
         }
-        return Integer::New(remainder);
+        return Integer::New(remainder, space);
       }
       default:
         UNIMPLEMENTED();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a271d16..369f87a 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -488,6 +488,12 @@
     return *vm_isolate_snapshot_object_table_;
   }
   static void InitVmIsolateSnapshotObjectTable(intptr_t len);
+  static const uint8_t* instructions_snapshot_buffer() {
+    return instructions_snapshot_buffer_;
+  }
+  static void set_instructions_snapshot_buffer(const uint8_t* buffer) {
+    instructions_snapshot_buffer_ = buffer;
+  }
 
   static RawClass* class_class() { return class_class_; }
   static RawClass* dynamic_class() { return dynamic_class_; }
@@ -813,6 +819,7 @@
   static LanguageError* snapshot_writer_error_;
   static LanguageError* branch_offset_error_;
   static Array* vm_isolate_snapshot_object_table_;
+  static const uint8_t* instructions_snapshot_buffer_;
 
   friend void ClassTable::Register(const Class& cls);
   friend void RawObject::Validate(Isolate* isolate) const;
@@ -1650,7 +1657,8 @@
   RawTypeArguments* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
 
   // Runtime instantiation with canonicalization. Not to be used during type
   // finalization at compile time.
@@ -5006,7 +5014,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
 
   // Return a clone of this unfinalized type or the type itself if it is
   // already finalized. Apply recursively to type arguments, i.e. finalized
@@ -5179,7 +5188,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* malformed_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner,
@@ -5300,7 +5310,8 @@
   virtual RawTypeRef* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
   virtual RawTypeRef* CloneUninstantiated(
       const Class& new_owner,
       TrailPtr trail = NULL) const;
@@ -5380,7 +5391,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner, TrailPtr trail = NULL) const;
@@ -5464,7 +5476,8 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL) const;
+      TrailPtr trail = NULL,
+      Heap::Space space = Heap::kNew) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner, TrailPtr trail = NULL) const;
@@ -5600,7 +5613,9 @@
   RawInteger* AsValidInteger() const;
 
   // Returns null to indicate that a bigint operation is required.
-  RawInteger* ArithmeticOp(Token::Kind operation, const Integer& other) const;
+  RawInteger* ArithmeticOp(Token::Kind operation,
+                           const Integer& other,
+                           Heap::Space space = Heap::kNew) const;
   RawInteger* BitOp(Token::Kind operation, const Integer& other) const;
 
   // Returns true if the Integer does not fit in a Javascript integer.
@@ -6316,6 +6331,7 @@
 
   friend class Class;
   friend class String;
+  friend class Symbols;
   friend class ExternalOneByteString;
   friend class SnapshotReader;
   friend class StringHasher;
@@ -6431,6 +6447,7 @@
   friend class Class;
   friend class String;
   friend class SnapshotReader;
+  friend class Symbols;
 };
 
 
@@ -6513,6 +6530,7 @@
   friend class Class;
   friend class String;
   friend class SnapshotReader;
+  friend class Symbols;
 };
 
 
@@ -6591,6 +6609,7 @@
   friend class Class;
   friend class String;
   friend class SnapshotReader;
+  friend class Symbols;
 };
 
 
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index ad6f861..b32fa20 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -255,7 +255,7 @@
  public:
   // We cannot use a GrowableObjectArray, since we must not trigger GC.
   RetainingPathVisitor(RawObject* obj, const Array& path)
-      : obj_(obj), path_(path), length_(0) {
+      : thread_(Thread::Current()), obj_(obj), path_(path), length_(0) {
     ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
   }
 
@@ -281,7 +281,7 @@
         return kProceed;
       }
     } else {
-      HANDLESCOPE(Isolate::Current());
+      HANDLESCOPE(thread_);
       Object& current = Object::Handle();
       Smi& offset_from_parent = Smi::Handle();
       do {
@@ -300,6 +300,7 @@
   }
 
  private:
+  Thread* thread_;
   RawObject* obj_;
   const Array& path_;
   intptr_t length_;
diff --git a/runtime/vm/object_graph_test.cc b/runtime/vm/object_graph_test.cc
index 00f7768..3e0259a 100644
--- a/runtime/vm/object_graph_test.cc
+++ b/runtime/vm/object_graph_test.cc
@@ -39,7 +39,7 @@
 
 
 TEST_CASE(ObjectGraph) {
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
   // Create a simple object graph with objects a, b, c, d:
   //  a+->b+->c
   //  +   +
@@ -99,7 +99,7 @@
     ObjectGraph graph(isolate);
     // A retaining path should end like this: c <- b <- a <- ...
     {
-      HANDLESCOPE(isolate);
+      HANDLESCOPE(thread);
       // Test null, empty, and length 1 array.
       intptr_t null_length = graph.RetainingPath(&c, Object::null_array());
       intptr_t empty_length = graph.RetainingPath(&c, Object::empty_array());
@@ -110,7 +110,7 @@
       EXPECT_LE(3, null_length);
     }
     {
-      HANDLESCOPE(isolate);
+      HANDLESCOPE(thread);
       Array& path = Array::Handle(Array::New(6, Heap::kNew));
       // Trigger a full GC to increase probability of concurrent tasks.
       isolate->heap()->CollectAllGarbage();
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a344bb2..5e006a0 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3333,7 +3333,7 @@
   WeakProperty& weak = WeakProperty::Handle();
   {
     // Weak property and value in new. Key in old.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key", Heap::kOld);
     String& value = String::Handle();
@@ -3351,7 +3351,7 @@
   EXPECT(weak.value() != Object::null());
   {
     // Weak property and value in old. Key in new.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key", Heap::kNew);
     String& value = String::Handle();
@@ -3369,7 +3369,7 @@
   EXPECT(weak.value() != Object::null());
   {
     // Weak property and value in new. Key is a Smi.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     Integer& key = Integer::Handle();
     key ^= Integer::New(31);
     String& value = String::Handle();
@@ -3387,7 +3387,7 @@
   EXPECT(weak.value() != Object::null());
   {
     // Weak property and value in old. Key is a Smi.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     Integer& key = Integer::Handle();
     key ^= Integer::New(32);
     String& value = String::Handle();
@@ -3405,7 +3405,7 @@
   EXPECT(weak.value() != Object::null());
   {
     // Weak property and value in new. Key in VM isolate.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value = String::Handle();
     value ^= OneByteString::New("value", Heap::kNew);
     weak ^= WeakProperty::New(Heap::kNew);
@@ -3422,7 +3422,7 @@
   EXPECT(weak.value() != Object::null());
   {
     // Weak property and value in old. Key in VM isolate.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value = String::Handle();
     value ^= OneByteString::New("value", Heap::kOld);
     weak ^= WeakProperty::New(Heap::kOld);
@@ -3447,7 +3447,7 @@
   WeakProperty& weak = WeakProperty::Handle();
   Array& arr = Array::Handle(Array::New(1));
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key");
     arr.SetAt(0, key);
@@ -3469,7 +3469,7 @@
   String& key = String::Handle();
   key ^= OneByteString::New("key");
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value = String::Handle();
     value ^= OneByteString::New("value");
     weak ^= WeakProperty::New();
@@ -3491,7 +3491,7 @@
   String& key2 = String::Handle();
   key2 ^= OneByteString::New("key2");
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value1 = String::Handle();
     value1 ^= OneByteString::New("value1");
     weak1 ^= WeakProperty::New();
@@ -3518,7 +3518,7 @@
   String& key = String::Handle();
   key ^= OneByteString::New("key");
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value1 = String::Handle();
     value1 ^= OneByteString::New("value1");
     weak1 ^= WeakProperty::New();
@@ -3544,7 +3544,7 @@
   String& key = String::Handle();
   key ^= OneByteString::New("key", Heap::kOld);
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value = String::Handle();
     value ^= OneByteString::New("value", Heap::kOld);
     weak ^= WeakProperty::New(Heap::kOld);
@@ -3566,7 +3566,7 @@
   String& key2 = String::Handle();
   key2 ^= OneByteString::New("key2", Heap::kOld);
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value1 = String::Handle();
     value1 ^= OneByteString::New("value1", Heap::kOld);
     weak1 ^= WeakProperty::New(Heap::kOld);
@@ -3593,7 +3593,7 @@
   String& key = String::Handle();
   key ^= OneByteString::New("key", Heap::kOld);
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& value1 = String::Handle();
     value1 ^= OneByteString::New("value1", Heap::kOld);
     weak1 ^= WeakProperty::New(Heap::kOld);
@@ -3617,7 +3617,7 @@
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key");
     String& value = String::Handle();
@@ -3639,7 +3639,7 @@
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key");
     String& value1 = String::Handle();
@@ -3665,7 +3665,7 @@
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key", Heap::kOld);
     String& value = String::Handle();
@@ -3687,7 +3687,7 @@
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     String& key = String::Handle();
     key ^= OneByteString::New("key", Heap::kOld);
     String& value1 = String::Handle();
@@ -4709,4 +4709,76 @@
   EXPECT(!iterator.MoveNext());
 }
 
+
+static void CheckConcatAll(const String* data[], intptr_t n) {
+  Zone* zone = Thread::Current()->zone();
+  GrowableHandlePtrArray<const String> pieces(zone, n);
+  const Array& array = Array::Handle(zone, Array::New(n));
+  for (int i = 0; i < n; i++) {
+    pieces.Add(*data[i]);
+    array.SetAt(i, *data[i]);
+  }
+  const String& res1 = String::Handle(zone, Symbols::FromConcatAll(pieces));
+  const String& res2 = String::Handle(zone, String::ConcatAll(array));
+  EXPECT(res1.Equals(res2));
+}
+
+
+TEST_CASE(Symbols_FromConcatAll) {
+  {
+    const String* data[3] = { &Symbols::FallThroughError(),
+                              &Symbols::Dot(),
+                              &Symbols::isPaused() };
+    CheckConcatAll(data, 3);
+  }
+
+  {
+    const intptr_t kWideCharsLen = 7;
+    uint16_t wide_chars[kWideCharsLen] = { 'H', 'e', 'l', 'l', 'o', 256, '!' };
+    const String& two_str = String::Handle(String::FromUTF16(wide_chars,
+                                                             kWideCharsLen));
+
+    const String* data[3] = { &two_str, &Symbols::Dot(), &two_str };
+    CheckConcatAll(data, 3);
+  }
+
+  {
+    uint8_t characters[] = { 0xF6, 0xF1, 0xE9 };
+    intptr_t len = ARRAY_SIZE(characters);
+
+    const String& str = String::Handle(
+        ExternalOneByteString::New(characters, len, NULL, NULL, Heap::kNew));
+    const String* data[3] = { &str, &Symbols::Dot(), &str };
+    CheckConcatAll(data, 3);
+  }
+
+  {
+    uint16_t characters[] =
+        { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
+    intptr_t len = ARRAY_SIZE(characters);
+
+    const String& str = String::Handle(
+        ExternalTwoByteString::New(characters, len, NULL, NULL, Heap::kNew));
+    const String* data[3] = { &str, &Symbols::Dot(), &str };
+    CheckConcatAll(data, 3);
+  }
+
+  {
+    uint8_t characters1[] = { 0xF6, 0xF1, 0xE9 };
+    intptr_t len1 = ARRAY_SIZE(characters1);
+
+    const String& str1 = String::Handle(
+        ExternalOneByteString::New(characters1, len1, NULL, NULL, Heap::kNew));
+
+    uint16_t characters2[] =
+        { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
+    intptr_t len2 = ARRAY_SIZE(characters2);
+
+    const String& str2 = String::Handle(
+        ExternalTwoByteString::New(characters2, len2, NULL, NULL, Heap::kNew));
+    const String* data[3] = { &str1, &Symbols::Dot(), &str2 };
+    CheckConcatAll(data, 3);
+  }
+}
+
 }  // namespace dart
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index f7e3a27..604e453 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -2397,8 +2397,9 @@
     if (ctor_name.Length() > class_name.Length() + 1) {
       // Generating a forwarding call to a named constructor 'C.n'.
       // Add the constructor name 'n' to the super constructor.
-      ctor_name = String::SubString(ctor_name, class_name.Length() + 1);
-      super_ctor_name = String::Concat(super_ctor_name, ctor_name);
+      const intptr_t kLen =  class_name.Length() + 1;
+      ctor_name = Symbols::New(ctor_name, kLen, ctor_name.Length() - kLen);
+      super_ctor_name = Symbols::FromConcat(super_ctor_name, ctor_name);
     }
   }
 
@@ -2790,13 +2791,14 @@
   const intptr_t call_pos = TokenPos();
   ConsumeToken();
   String& ctor_name = String::Handle(Z, cls.Name());
-
-  ctor_name = String::Concat(ctor_name, Symbols::Dot());
+  GrowableHandlePtrArray<const String> pieces(Z, 3);
+  pieces.Add(ctor_name);
+  pieces.Add(Symbols::Dot());
   if (CurrentToken() == Token::kPERIOD) {
     ConsumeToken();
-    ctor_name = String::Concat(ctor_name,
-                               *ExpectIdentifier("constructor name expected"));
+    pieces.Add(*ExpectIdentifier("constructor name expected"));
   }
+  ctor_name = Symbols::FromConcatAll(pieces);
   CheckToken(Token::kLPAREN, "parameter list expected");
 
   ArgumentListNode* arguments = new ArgumentListNode(call_pos);
@@ -3489,7 +3491,7 @@
     body = CloseSyncGenFunction(generated_body_closure, body);
     generated_body_closure.set_end_token_pos(end_token_pos);
   } else if (func.IsSyncGenClosure()) {
-    body->scope()->RecursivelyCaptureAllVariables();
+    // body is unchanged.
   } else if (func.IsAsyncGenerator()) {
     body = CloseAsyncGeneratorFunction(generated_body_closure, body);
     generated_body_closure.set_end_token_pos(end_token_pos);
@@ -3690,7 +3692,7 @@
       ASSERT(method->IsSetter());
       expected_num_parameters = (method->has_static) ? 1 : 2;
       method->dict_name = &String::ZoneHandle(Z,
-          String::Concat(*method->name, Symbols::Equals()));
+          Symbols::FromConcat(*method->name, Symbols::Equals()));
       method->name = &String::ZoneHandle(Z, Field::SetterSymbol(*method->name));
     }
     if ((method->params.num_fixed_parameters != expected_num_parameters) ||
@@ -6318,8 +6320,8 @@
             no_args));
 
     // Suspend after the close.
-    AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode();
-    await_marker->set_scope(current_block_->scope);
+    AwaitMarkerNode* await_marker =
+        new(Z) AwaitMarkerNode(async_temp_scope_, current_block_->scope);
     current_block_->statements->Add(await_marker);
     ReturnNode* continuation_ret = new(Z) ReturnNode(try_end_pos);
     continuation_ret->set_return_type(ReturnNode::kContinuationTarget);
@@ -6608,6 +6610,8 @@
 
 SequenceNode* Parser::CloseSyncGenFunction(const Function& closure,
                                            SequenceNode* closure_body) {
+  // Explicitly reference variables of the sync generator function from the
+  // closure body in order to mark them as captured.
   LocalVariable* existing_var =
       closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
   ASSERT((existing_var != NULL) && existing_var->is_captured());
@@ -6753,11 +6757,9 @@
   LocalVariable* await_jump_var = new (Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), dynamic_type);
   current_block_->scope->AddVariable(await_jump_var);
-  current_block_->scope->CaptureVariable(await_jump_var);
   LocalVariable* await_ctx_var = new (Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AwaitContextVar(), dynamic_type);
   current_block_->scope->AddVariable(await_ctx_var);
-  current_block_->scope->CaptureVariable(await_ctx_var);
 }
 
 
@@ -6771,19 +6773,15 @@
   LocalVariable* async_op_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
   current_block_->scope->AddVariable(async_op_var);
-  current_block_->scope->CaptureVariable(async_op_var);
   LocalVariable* async_then_callback_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncThenCallback(), dynamic_type);
   current_block_->scope->AddVariable(async_then_callback_var);
-  current_block_->scope->CaptureVariable(async_then_callback_var);
   LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncCatchErrorCallback(), dynamic_type);
   current_block_->scope->AddVariable(async_catch_error_callback_var);
-  current_block_->scope->CaptureVariable(async_catch_error_callback_var);
   LocalVariable* async_completer = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncCompleter(), dynamic_type);
   current_block_->scope->AddVariable(async_completer);
-  current_block_->scope->CaptureVariable(async_completer);
 }
 
 
@@ -6802,19 +6800,15 @@
   LocalVariable* controller_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::Controller(), dynamic_type);
   current_block_->scope->AddVariable(controller_var);
-  current_block_->scope->CaptureVariable(controller_var);
   LocalVariable* async_op_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncOperation(), dynamic_type);
   current_block_->scope->AddVariable(async_op_var);
-  current_block_->scope->CaptureVariable(async_op_var);
   LocalVariable* async_then_callback_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncThenCallback(), dynamic_type);
   current_block_->scope->AddVariable(async_then_callback_var);
-  current_block_->scope->CaptureVariable(async_then_callback_var);
   LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
       Scanner::kNoSourcePos, Symbols::AsyncCatchErrorCallback(), dynamic_type);
   current_block_->scope->AddVariable(async_catch_error_callback_var);
-  current_block_->scope->CaptureVariable(async_catch_error_callback_var);
 }
 
 
@@ -6906,8 +6900,8 @@
   ASSERT(!closure_func.IsNull());
   ASSERT(closure_body != NULL);
 
-  // Make sure the implicit variables of the async generator function
-  // are captured.
+  // Explicitly reference variables of the async genenerator function from the
+  // closure body in order to mark them as captured.
   LocalVariable* existing_var = closure_body->scope()->LookupVariable(
       Symbols::AwaitJumpVar(), false);
   ASSERT((existing_var != NULL) && existing_var->is_captured());
@@ -7045,29 +7039,6 @@
   SequenceNode* new_body = CloseAsyncGeneratorTryBlock(body);
   ASSERT(new_body != NULL);
   ASSERT(new_body->scope() != NULL);
-
-  // Implicitly mark those variables below as captured. We currently mark all
-  // variables of all scopes as captured, but as soon as we do something
-  // smarter we rely on these internal variables to be available.
-  LocalVariable* existing_var = new_body->scope()->LookupVariable(
-      Symbols::AwaitJumpVar(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  existing_var = new_body->scope()->LookupVariable(
-      Symbols::AwaitContextVar(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  existing_var = new_body->scope()->LookupVariable(
-      Symbols::Controller(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  existing_var = new_body->scope()->LookupVariable(
-      Symbols::AsyncOperationParam(), false);
-  ASSERT(existing_var != NULL);
-  existing_var = new_body->scope()->LookupVariable(
-      Symbols::AsyncOperationErrorParam(), false);
-  ASSERT(existing_var != NULL);
-  existing_var = new_body->scope()->LookupVariable(
-      Symbols::AsyncOperationStackTraceParam(), false);
-  ASSERT(existing_var != NULL);
-  new_body->scope()->RecursivelyCaptureAllVariables();
   return new_body;
 }
 
@@ -7107,6 +7078,8 @@
   ASSERT(!closure.IsNull());
   ASSERT(closure_body != NULL);
 
+  // Explicitly reference variables of the async function from the
+  // closure body in order to mark them as captured.
   LocalVariable* existing_var =
       closure_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
   ASSERT((existing_var != NULL) && existing_var->is_captured());
@@ -7250,22 +7223,10 @@
 SequenceNode* Parser::CloseAsyncClosure(SequenceNode* body) {
   // We need a temporary expression to store intermediate return values.
   parsed_function()->EnsureExpressionTemp();
-  // Implicitly mark those variables below as captured. We currently mark all
-  // variables of all scopes as captured (below), but as soon as we do something
-  // smarter we rely on these internal variables to be available.
+
   SequenceNode* new_body = CloseAsyncTryBlock(body);
   ASSERT(new_body != NULL);
   ASSERT(new_body->scope() != NULL);
-  LocalVariable* existing_var =
-      new_body->scope()->LookupVariable(Symbols::AwaitJumpVar(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  existing_var =
-      new_body->scope()->LookupVariable(Symbols::AwaitContextVar(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  existing_var =
-      new_body->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
-  ASSERT((existing_var != NULL) && existing_var->is_captured());
-  new_body->scope()->RecursivelyCaptureAllVariables();
   return new_body;
 }
 
@@ -8542,7 +8503,7 @@
               Symbols::AsyncSavedTryCtxVarPrefix().ToCString(),
               try_index))));
   LocalVariable* var = scope->LocalLookupVariable(async_saved_try_ctx_name);
-  ASSERT((var != NULL) && var->is_captured());
+  ASSERT(var != NULL);
   return var;
 }
 
@@ -8734,14 +8695,15 @@
       new(Z) LoadLocalNode(stream_pos, iterator_var),
                            Symbols::MoveNext(),
                            no_args);
+  OpenBlock();
   AstNode* await_moveNext =
       new(Z) AwaitNode(stream_pos,
                        iterator_moveNext,
                        saved_try_ctx,
                        async_saved_try_ctx,
                        outer_saved_try_ctx,
-                       outer_async_saved_try_ctx);
-  OpenBlock();
+                       outer_async_saved_try_ctx,
+                       current_block_->scope);
   AwaitTransformer at(current_block_->statements, async_temp_scope_);
   await_moveNext = at.Transform(await_moveNext);
   SequenceNode* await_preamble = CloseBlock();
@@ -9573,7 +9535,6 @@
       Type::ZoneHandle(Z, Type::DynamicType()));
   ASSERT(async_temp_scope_ != NULL);
   async_temp_scope_->AddVariable(async_saved_try_ctx);
-  current_block_->scope->CaptureVariable(async_saved_try_ctx);
   ASSERT(saved_try_context != NULL);
   current_block_->statements->Add(new(Z) StoreLocalNode(
       Scanner::kNoSourcePos,
@@ -9907,8 +9868,8 @@
               new(Z) LiteralNode(TokenPos(), Bool::True()));
       yield->AddNode(set_is_yield_each);
     }
-    AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode();
-    await_marker->set_scope(current_block_->scope);
+    AwaitMarkerNode* await_marker =
+        new(Z) AwaitMarkerNode(async_temp_scope_, current_block_->scope);
     yield->AddNode(await_marker);
     // Return true to indicate that a value has been generated.
     ReturnNode* return_true = new(Z) ReturnNode(yield_pos,
@@ -9975,8 +9936,8 @@
        new(Z) IfNode(Scanner::kNoSourcePos, add_call, true_branch, NULL);
     yield->AddNode(if_is_cancelled);
 
-    AwaitMarkerNode* await_marker = new(Z) AwaitMarkerNode();
-    await_marker->set_scope(current_block_->scope);
+    AwaitMarkerNode* await_marker =
+        new(Z) AwaitMarkerNode(async_temp_scope_, current_block_->scope);
     yield->AddNode(await_marker);
     ReturnNode* continuation_return = new(Z) ReturnNode(yield_pos);
     continuation_return->set_return_type(ReturnNode::kContinuationTarget);
@@ -10633,9 +10594,9 @@
 
 // Evaluates the value of the compile time constant expression
 // and returns a literal node for the value.
-AstNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) {
+LiteralNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) {
   if (expr->IsLiteralNode()) {
-    return expr;
+    return expr->AsLiteralNode();
   }
   if (expr->EvalConstExpr() == NULL) {
     ReportError(expr_pos, "expression is not a valid compile-time constant");
@@ -10882,13 +10843,27 @@
     AstNode* expr = ParseExpr(require_compiletime_const, consume_cascades);
     return new(Z) ThrowNode(expr_pos, expr, NULL);
   }
+
+  if (require_compiletime_const) {
+    // Check whether we already have evaluated a compile-time constant
+    // at this source location.
+    Instance& existing_const = Instance::ZoneHandle(Z);
+    if (GetCachedConstant(expr_pos, &existing_const)) {
+      SkipConditionalExpr();
+      return new(Z) LiteralNode(expr_pos, existing_const);
+    }
+  }
+
   AstNode* expr = ParseConditionalExpr();
   if (!Token::IsAssignmentOperator(CurrentToken())) {
     if ((CurrentToken() == Token::kCASCADE) && consume_cascades) {
       return ParseCascades(expr);
     }
     if (require_compiletime_const) {
-      expr = FoldConstExpr(expr_pos, expr);
+      const bool use_cache = !expr->IsLiteralNode();
+      LiteralNode* const_value = FoldConstExpr(expr_pos, expr);
+      if (use_cache) CacheConstantValue(expr_pos, const_value->literal());
+      expr = const_value;
     } else {
       expr = LiteralIfStaticConst(Z, expr);
     }
@@ -10982,7 +10957,8 @@
                              saved_try_ctx,
                              async_saved_try_ctx,
                              outer_saved_try_ctx,
-                             outer_async_saved_try_ctx);
+                             outer_async_saved_try_ctx,
+                             current_block_->scope);
   } else if (IsPrefixOperator(CurrentToken())) {
     Token::Kind unary_op = CurrentToken();
     if (unary_op == Token::kSUB) {
@@ -13670,15 +13646,13 @@
     if (has_interpolation) {
       primary = new(Z) LiteralNode(literal_start, Interpolate(values_list));
     } else {
-      const Array& strings = Array::Handle(Z, Array::New(values_list.length()));
+      GrowableHandlePtrArray<const String> pieces(Z, values_list.length());
       for (int i = 0; i < values_list.length(); i++) {
         const Instance& part = values_list[i]->AsLiteralNode()->literal();
         ASSERT(part.IsString());
-        strings.SetAt(i, String::Cast(part));
+        pieces.Add(String::Cast(part));
       }
-      String& lit = String::ZoneHandle(Z,
-                                       String::ConcatAll(strings, Heap::kOld));
-      lit = Symbols::New(lit);
+      const String& lit = String::ZoneHandle(Z, Symbols::FromConcatAll(pieces));
       primary = new(Z) LiteralNode(literal_start, lit);
     }
   } else {
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index ece2729..f081a7a 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -399,7 +399,7 @@
                                           const TypeArguments& type_arguments,
                                           const Function& constructor,
                                           ArgumentListNode* arguments);
-  AstNode* FoldConstExpr(intptr_t expr_pos, AstNode* expr);
+  LiteralNode* FoldConstExpr(intptr_t expr_pos, AstNode* expr);
 
   // Support for parsing of scripts.
   void ParseTopLevel();
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 1c2c118..abb5bb0 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -2194,11 +2194,12 @@
 }
 
 
-void ProfilerService::PrintJSONImpl(Isolate* isolate,
+void ProfilerService::PrintJSONImpl(Thread* thread,
                                     JSONStream* stream,
                                     Profile::TagOrder tag_order,
                                     intptr_t extra_tags,
                                     SampleFilter* filter) {
+  Isolate* isolate = thread->isolate();
   // Disable profile interrupts while processing the buffer.
   Profiler::EndExecution(isolate);
 
@@ -2212,8 +2213,8 @@
   }
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     profile.Build(filter, tag_order, extra_tags);
     profile.PrintJSON(stream);
@@ -2239,9 +2240,10 @@
 void ProfilerService::PrintJSON(JSONStream* stream,
                                 Profile::TagOrder tag_order,
                                 intptr_t extra_tags) {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   NoAllocationSampleFilter filter(isolate);
-  PrintJSONImpl(isolate, stream, tag_order, extra_tags, &filter);
+  PrintJSONImpl(thread, stream, tag_order, extra_tags, &filter);
 }
 
 
@@ -2266,9 +2268,10 @@
 void ProfilerService::PrintAllocationJSON(JSONStream* stream,
                                           Profile::TagOrder tag_order,
                                           const Class& cls) {
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   ClassAllocationSampleFilter filter(isolate, cls);
-  PrintJSONImpl(isolate, stream, tag_order, kNoExtraTags, &filter);
+  PrintJSONImpl(thread, stream, tag_order, kNoExtraTags, &filter);
 }
 
 
diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
index 7f0b9a3..621db01 100644
--- a/runtime/vm/profiler_service.h
+++ b/runtime/vm/profiler_service.h
@@ -387,7 +387,7 @@
   static void ClearSamples();
 
  private:
-  static void PrintJSONImpl(Isolate* isolate,
+  static void PrintJSONImpl(Thread* thread,
                             JSONStream* stream,
                             Profile::TagOrder tag_order,
                             intptr_t extra_tags,
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index ac7309b..bc43d5f 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -566,7 +566,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& double_class =
       Class::Handle(isolate->object_store()->double_class());
@@ -578,8 +578,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, double_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -592,8 +592,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, double_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -616,8 +616,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, double_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -636,7 +636,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& array_class =
       Class::Handle(isolate->object_store()->array_class());
@@ -646,8 +646,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, array_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -660,8 +660,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, array_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -684,8 +684,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, array_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -708,8 +708,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, array_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -743,7 +743,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& context_class =
       Class::Handle(Object::context_class());
@@ -753,8 +753,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, context_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -767,8 +767,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, context_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -787,8 +787,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, context_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -818,7 +818,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& class_class =
       Class::Handle(Object::class_class());
@@ -830,8 +830,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, class_class.id());
     filter.set_enable_embedder_ticks(true);
@@ -859,8 +859,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, class_class.id());
     filter.set_enable_embedder_ticks(true);
@@ -880,7 +880,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Library& typed_data_library =
       Library::Handle(isolate->object_store()->typed_data_library());
@@ -893,8 +893,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, float32_list_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -907,8 +907,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, float32_list_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -933,8 +933,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, float32_list_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -947,8 +947,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, float32_list_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -965,7 +965,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& one_byte_string_class =
       Class::Handle(isolate->object_store()->one_byte_string_class());
@@ -977,8 +977,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -991,8 +991,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1013,8 +1013,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1027,8 +1027,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1045,7 +1045,7 @@
   EXPECT_VALID(lib);
   Library& root_library = Library::Handle();
   root_library ^= Api::UnwrapHandle(lib);
-  Isolate* isolate = Isolate::Current();
+  Isolate* isolate = thread->isolate();
 
   const Class& one_byte_string_class =
       Class::Handle(isolate->object_store()->one_byte_string_class());
@@ -1057,8 +1057,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1071,8 +1071,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1097,8 +1097,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
@@ -1111,8 +1111,8 @@
   EXPECT_VALID(result);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     Profile profile(isolate);
     AllocationFilter filter(isolate, one_byte_string_class.id());
     profile.Build(&filter, Profile::kNoTags);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 16d5728..0c4fcf6 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -584,6 +584,7 @@
   friend class SizeExcludingClassVisitor;  // GetClassId
   friend class RetainingPathVisitor;  // GetClassId
   friend class SkippedCodeFunctions;  // StorePointer
+  friend class InstructionsReader;  // tags_ check
   friend class SnapshotReader;
   friend class SnapshotWriter;
   friend class String;
@@ -1002,11 +1003,11 @@
   RawLocalVarDescriptors* var_descriptors_;
   RawArray* inlined_metadata_;
   RawArray* comments_;
-  // If return_address_info_ is a Smi, it is the offset to the prologue.
-  // Else, return_address_info_ is null.
+  // If return_address_metadata_ is a Smi, it is the offset to the prologue.
+  // Else, return_address_metadata_ is null.
   RawObject* return_address_metadata_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->comments_);
+    return reinterpret_cast<RawObject**>(&ptr()->return_address_metadata_);
   }
   uword entry_point_;
 
@@ -1053,6 +1054,7 @@
   Entry* first_entry() { return &ptr()->data()[0]; }
 
   friend class Object;
+  friend class SnapshotReader;
 };
 
 
@@ -1084,6 +1086,7 @@
   friend class MarkingVisitor;
   friend class SkippedCodeFunctions;
   friend class Function;
+  friend class InstructionsReader;
 };
 
 
@@ -1141,6 +1144,7 @@
   const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
 
   friend class Object;
+  friend class SnapshotReader;
 };
 
 
@@ -1148,9 +1152,8 @@
 // PC. The stack map representation consists of a bit map which marks each
 // live object index starting from the base of the frame.
 //
-// The Stackmap also consists of a link to the code object corresponding to
-// the frame which the stack map is describing.  The bit map representation
-// is optimized for dense and small bit maps, without any upper bound.
+// The bit map representation is optimized for dense and small bit maps, without
+// any upper bound.
 class RawStackmap : public RawObject {
   RAW_HEAP_OBJECT_IMPLEMENTATION(Stackmap);
 
@@ -1168,6 +1171,8 @@
   // Variable length data follows here (bitmap of the stack layout).
   uint8_t* data() { OPEN_ARRAY_START(uint8_t, uint8_t); }
   const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, uint8_t); }
+
+  friend class SnapshotReader;
 };
 
 
@@ -1242,6 +1247,7 @@
   }
 
   friend class Object;
+  friend class SnapshotReader;
 };
 
 
@@ -1271,6 +1277,7 @@
   HandlerInfo* data() { OPEN_ARRAY_START(HandlerInfo, intptr_t); }
 
   friend class Object;
+  friend class SnapshotReader;
 };
 
 
@@ -1335,6 +1342,7 @@
 
   friend class Object;
   friend class RawClosureData;
+  friend class SnapshotReader;
 };
 
 
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 3bb7b96..ff8c438 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -26,6 +26,18 @@
 #define OFFSET_OF_FROM(obj)                                                    \
   obj.raw()->from() - reinterpret_cast<RawObject**>(obj.raw()->ptr())
 
+// TODO(18854): Need to assert No GC can happen here, even though
+// allocations may happen.
+#define READ_OBJECT_FIELDS(object, from, to, as_reference)                     \
+  intptr_t num_flds = (to) - (from);                                           \
+  intptr_t from_offset = OFFSET_OF_FROM(object);                               \
+  for (intptr_t i = 0; i <= num_flds; i++) {                                   \
+    (*reader->PassiveObjectHandle()) =                                         \
+        reader->ReadObjectImpl(as_reference, object_id, (i + from_offset));    \
+    object.StorePointer(((from) + i),                                          \
+                        reader->PassiveObjectHandle()->raw());                 \
+  }
+
 RawClass* Class::ReadFrom(SnapshotReader* reader,
                           intptr_t object_id,
                           intptr_t tags,
@@ -66,16 +78,8 @@
     cls.set_state_bits(reader->Read<uint16_t>());
 
     // Set all the object fields.
-    // TODO(5411462): Need to assert No GC can happen here, even though
-    // allocations may happen.
-    intptr_t num_flds = (cls.raw()->to() - cls.raw()->from());
-    intptr_t from_offset = OFFSET_OF_FROM(cls);
-    for (intptr_t i = 0; i <= num_flds; i++) {
-      (*reader->PassiveObjectHandle()) =
-          reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-      cls.StorePointer((cls.raw()->from() + i),
-                       reader->PassiveObjectHandle()->raw());
-    }
+    READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
+
     ASSERT(!cls.IsInFullSnapshot() || (kind == Snapshot::kFull));
   } else {
     cls ^= reader->ReadClassId(object_id);
@@ -155,15 +159,11 @@
   unresolved_class.set_token_pos(reader->Read<int32_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (unresolved_class.raw()->to() -
-                       unresolved_class.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    unresolved_class.StorePointer((unresolved_class.raw()->from() + i),
-                                  reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(unresolved_class,
+                     unresolved_class.raw()->from(),
+                     unresolved_class.raw()->to(),
+                     kAsReference);
+
   return unresolved_class.raw();
 }
 
@@ -226,16 +226,7 @@
   type.set_type_state(reader->Read<int8_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (type.raw()->to() - type.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(type);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    type.StorePointer((type.raw()->from() + i),
-                      reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
 
   // Set the canonical bit.
   if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
@@ -296,16 +287,9 @@
   reader->AddBackRef(object_id, &type_ref, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (type_ref.raw()->to() - type_ref.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(type_ref);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    type_ref.StorePointer((type_ref.raw()->from() + i),
-                          reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(type_ref,
+                     type_ref.raw()->from(), type_ref.raw()->to(),
+                     kAsReference);
 
   return type_ref.raw();
 }
@@ -346,17 +330,9 @@
   type_parameter.set_type_state(reader->Read<int8_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (type_parameter.raw()->to() -
-                       type_parameter.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(type_parameter);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    type_parameter.StorePointer((type_parameter.raw()->from() + i),
-                                reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(type_parameter,
+                     type_parameter.raw()->from(), type_parameter.raw()->to(),
+                     kAsReference);
 
   return type_parameter.raw();
 }
@@ -400,17 +376,9 @@
   reader->AddBackRef(object_id, &bounded_type, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (bounded_type.raw()->to() -
-                       bounded_type.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(bounded_type);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    bounded_type.StorePointer((bounded_type.raw()->from() + i),
-                              reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(bounded_type,
+                     bounded_type.raw()->from(), bounded_type.raw()->to(),
+                     kAsReference);
 
   return bounded_type.raw();
 }
@@ -534,14 +502,8 @@
   reader->AddBackRef(object_id, &cls, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (cls.raw()->to() - cls.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    cls.StorePointer((cls.raw()->from() + i),
-                     reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
+
   ASSERT(((kind == Snapshot::kScript) &&
           !Class::IsInFullSnapshot(cls.source_class())) ||
          (kind == Snapshot::kFull));
@@ -581,12 +543,7 @@
   reader->AddBackRef(object_id, &data, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (data.raw()->to() - data.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    *(data.raw()->from() + i) = reader->ReadObjectImpl(kAsReference);
-  }
+  READ_OBJECT_FIELDS(data, data.raw()->from(), data.raw()->to(), kAsReference);
 
   return data.raw();
 }
@@ -617,8 +574,6 @@
     }
   }
 
-  writer->WriteObjectImpl(Object::null(), kAsInlinedObject);
-
   // Parent function.
   writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject);
 
@@ -644,16 +599,7 @@
   reader->AddBackRef(object_id, &data, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (data.raw()->to() - data.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(data);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    data.StorePointer((data.raw()->from() + i),
-                      reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(data, data.raw()->from(), data.raw()->to(), kAsReference);
 
   return data.raw();
 }
@@ -702,23 +648,18 @@
   func.set_optimized_call_site_count(reader->Read<uint16_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  RawObject** toaddr = reader->snapshot_code() ? func.raw()->to()
-                                               : func.raw()->to_snapshot();
-  intptr_t num_flds = toaddr - func.raw()->from();
-  intptr_t from_offset = OFFSET_OF_FROM(func);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    func.StorePointer((func.raw()->from() + i),
-                      reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(func,
+                     func.raw()->from(),
+                     reader->snapshot_code() ? func.raw()->to()
+                                             : func.raw()->to_snapshot(),
+                     kAsReference);
 
   if (!reader->snapshot_code()) {
     // Initialize all fields that are not part of the snapshot.
     func.ClearICDataArray();
     func.ClearCode();
+  } else {
+    // TODO(rmacnak): Fix entry_point_.
   }
   return func.raw();
 }
@@ -777,16 +718,9 @@
   field.set_kind_bits(reader->Read<uint8_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (field.raw()->to() - field.raw()->from());
-  intptr_t from_offset = OFFSET_OF_FROM(field);
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) =
-        reader->ReadObjectImpl(kAsReference, object_id, (i + from_offset));
-    field.StorePointer((field.raw()->from() + i),
-                       reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(field,
+                     field.raw()->from(), field.raw()->to(),
+                     kAsReference);
 
   field.InitializeGuardedListLengthInObjectOffset();
 
@@ -836,14 +770,9 @@
   literal_token.set_kind(token_kind);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (literal_token.raw()->to() - literal_token.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    literal_token.StorePointer((literal_token.raw()->from() + i),
-                               reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(literal_token,
+                     literal_token.raw()->from(), literal_token.raw()->to(),
+                     kAsReference);
 
   return literal_token.raw();
 }
@@ -1124,14 +1053,9 @@
   prefix.StoreNonPointer(&prefix.raw_ptr()->is_loaded_, reader->Read<bool>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (prefix.raw()->to() - prefix.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    prefix.StorePointer((prefix.raw()->from() + i),
-                         reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(prefix,
+                     prefix.raw()->from(), prefix.raw()->to(),
+                     kAsReference);
 
   return prefix.raw();
 }
@@ -1174,14 +1098,7 @@
   reader->AddBackRef(object_id, &ns, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (ns.raw()->to() - ns.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    ns.StorePointer((ns.raw()->from() + i),
-                    reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(ns, ns.raw()->from(), ns.raw()->to(), kAsReference);
 
   return ns.raw();
 }
@@ -1210,7 +1127,6 @@
                         intptr_t object_id,
                         intptr_t tags,
                         Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
@@ -1224,14 +1140,11 @@
   result.set_lazy_deopt_pc_offset(reader->Read<int32_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (result.raw()->to() - result.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    result.StorePointer((result.raw()->from() + i),
-                        reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(result,
+                     result.raw()->from(), result.raw()->to(),
+                     kAsReference);
+
+  // TODO(rmacnak): Fix entry_point_.
 
   return result.raw();
 }
@@ -1274,15 +1187,22 @@
                                         intptr_t object_id,
                                         intptr_t tags,
                                         Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
-  intptr_t id = reader->Read<int32_t>();
+  intptr_t full_tags = static_cast<uword>(reader->Read<intptr_t>());
+  intptr_t offset = reader->Read<int32_t>();
   Instructions& result =
       Instructions::ZoneHandle(reader->zone(),
-                               reader->GetInstructionsById(id));
+                               reader->GetInstructionsAt(offset, full_tags));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
+
+  {
+    // TODO(rmacnak): Drop after calling convention change.
+    Code::CheckedHandle(reader->ReadObjectImpl(kAsReference));
+    ObjectPool::CheckedHandle(reader->ReadObjectImpl(kAsReference));
+  }
+
   return result.raw();
 }
 
@@ -1298,11 +1218,23 @@
     writer->WriteInlinedObjectHeader(object_id);
     writer->WriteVMIsolateObject(kInstructionsCid);
     writer->WriteTags(writer->GetObjectTags(this));
+  }
+
+  writer->Write<intptr_t>(writer->GetObjectTags(this));  // For sanity check.
+
+  // Temporarily restore the object header for writing to the text section.
+  // TODO(asiva): Don't mutate object headers during serialization.
+  uword object_tags = writer->GetObjectTags(this);
+  uword snapshot_tags = ptr()->tags_;
+  ptr()->tags_ = object_tags;
+  writer->Write<int32_t>(writer->GetInstructionsId(this));
+  ptr()->tags_ = snapshot_tags;
+
+  {
+    // TODO(rmacnak): Drop after calling convention change.
     writer->WriteObjectImpl(ptr()->code_, kAsReference);
     writer->WriteObjectImpl(ptr()->object_pool_, kAsReference);
   }
-
-  writer->Write<int32_t>(writer->GetInstructionsId(this));
 }
 
 
@@ -1310,7 +1242,6 @@
                                     intptr_t object_id,
                                     intptr_t tags,
                                     Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
@@ -1321,15 +1252,15 @@
                              NEW_OBJECT_WITH_LEN(ObjectPool, length));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  RawTypedData* info_array = result.raw_ptr()->info_array_->ptr();
+  const TypedData& info_array =
+      TypedData::Handle(reader->NewTypedData(kTypedDataInt8ArrayCid, length));
+  result.set_info_array(info_array);
 
-  // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
+  NoSafepointScope no_safepoint;
   for (intptr_t i = 0; i < length; i++) {
     ObjectPool::EntryType entry_type =
-        static_cast<ObjectPool::EntryType>(reader->Read<uint8_t>());
-    info_array->data()[i] = entry_type;
+        static_cast<ObjectPool::EntryType>(reader->Read<int8_t>());
+    *reinterpret_cast<int8_t*>(info_array.DataAddr(i)) = entry_type;
     switch (entry_type) {
       case ObjectPool::kTaggedObject: {
         (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
@@ -1377,7 +1308,7 @@
   for (intptr_t i = 0; i < length; i++) {
     ObjectPool::EntryType entry_type =
         static_cast<ObjectPool::EntryType>(info_array->data()[i]);
-    writer->Write<uint8_t>(entry_type);
+    writer->Write<int8_t>(entry_type);
     Entry& entry = ptr()->data()[i];
     switch (entry_type) {
       case ObjectPool::kTaggedObject:
@@ -1401,12 +1332,13 @@
                                           intptr_t object_id,
                                           intptr_t tags,
                                           Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   const int32_t length = reader->Read<int32_t>();
-  PcDescriptors& result = PcDescriptors::ZoneHandle(reader->zone(),
-                                                    PcDescriptors::New(length));
+  PcDescriptors& result =
+      PcDescriptors::ZoneHandle(reader->zone(),
+                                NEW_OBJECT_WITH_LEN(PcDescriptors, length));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
   if (result.Length() > 0) {
@@ -1424,6 +1356,7 @@
                                intptr_t object_id,
                                Snapshot::Kind kind) {
   ASSERT(writer->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -1442,19 +1375,19 @@
                                 intptr_t object_id,
                                 intptr_t tags,
                                 Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   const int32_t length = reader->Read<int32_t>();
-  const int32_t register_bit_count = reader->Read<int32_t>();
-  const uword pc_offset = reader->Read<uint32_t>();
-
   Stackmap& result =
       Stackmap::ZoneHandle(reader->zone(),
-        Stackmap::New(length, register_bit_count, pc_offset));
+                           reader->NewStackmap(length));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  if (result.Length() > 0) {
+  result.SetRegisterBitCount(reader->Read<int32_t>());
+  result.SetPcOffset(reader->Read<uint32_t>());
+
+  if (length > 0) {
     NoSafepointScope no_safepoint;
     intptr_t len = (result.Length() + 7) / 8;
     uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
@@ -1469,11 +1402,13 @@
                           intptr_t object_id,
                           Snapshot::Kind kind) {
   ASSERT(writer->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
   writer->WriteIndexedObject(kStackmapCid);
   writer->WriteTags(writer->GetObjectTags(this));
+
   writer->Write<int32_t>(ptr()->length_);
   writer->Write<int32_t>(ptr()->register_bit_count_);
   writer->Write<uint32_t>(ptr()->pc_offset_);
@@ -1489,14 +1424,15 @@
                                                       intptr_t object_id,
                                                       intptr_t tags,
                                                       Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   const int32_t num_entries = reader->Read<int32_t>();
 
   LocalVarDescriptors& result =
       LocalVarDescriptors::ZoneHandle(reader->zone(),
-        LocalVarDescriptors::New(num_entries));
+                                      NEW_OBJECT_WITH_LEN(LocalVarDescriptors,
+                                                          num_entries));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
   for (intptr_t i = 0; i < num_entries; i++) {
@@ -1521,6 +1457,7 @@
                                      intptr_t object_id,
                                      Snapshot::Kind kind) {
   ASSERT(writer->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -1528,7 +1465,7 @@
   writer->WriteTags(writer->GetObjectTags(this));
   writer->Write<int32_t>(ptr()->num_entries_);
   for (intptr_t i = 0; i < ptr()->num_entries_; i++) {
-    writer->WriteObjectImpl(ptr()->names()[i], kAsInlinedObject);
+    writer->WriteObjectImpl(ptr()->names()[i], kAsReference);
   }
   if (ptr()->num_entries_ > 0) {
     intptr_t len = ptr()->num_entries_ * sizeof(VarInfo);
@@ -1542,15 +1479,14 @@
                                                   intptr_t object_id,
                                                   intptr_t tags,
                                                   Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
-  // handled_types_data.
-  *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
-
+  const int32_t num_entries = reader->Read<int32_t>();
   ExceptionHandlers& result =
       ExceptionHandlers::ZoneHandle(reader->zone(),
-        ExceptionHandlers::New(*reader->ArrayHandle()));
+                                    NEW_OBJECT_WITH_LEN(ExceptionHandlers,
+                                                        num_entries));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
   if (result.num_entries() > 0) {
@@ -1562,6 +1498,10 @@
     reader->ReadBytes(data, len);
   }
 
+  *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
+  result.StorePointer(&result.raw_ptr()->handled_types_data_,
+                      reader->ArrayHandle()->raw());
+
   return result.raw();
 }
 
@@ -1570,18 +1510,21 @@
                                    intptr_t object_id,
                                    Snapshot::Kind kind) {
   ASSERT(writer->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
   writer->WriteIndexedObject(kExceptionHandlersCid);
   writer->WriteTags(writer->GetObjectTags(this));
-  writer->WriteObjectImpl(ptr()->handled_types_data_, kAsInlinedObject);
+  writer->Write<int32_t>(ptr()->num_entries_);
 
   if (ptr()->num_entries_ > 0) {
     intptr_t len = ptr()->num_entries_ * sizeof(HandlerInfo);
     uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
     writer->WriteBytes(data, len);
   }
+
+  writer->WriteObjectImpl(ptr()->handled_types_data_, kAsInlinedObject);
 }
 
 
@@ -1646,8 +1589,13 @@
   // Allocate context object.
   bool is_implicit = reader->Read<bool>();
   if (is_implicit) {
-    ContextScope& context_scope =
-        ContextScope::ZoneHandle(ContextScope::New(1, true));
+    ContextScope& context_scope = ContextScope::ZoneHandle();
+    if (kind == Snapshot::kFull) {
+      context_scope = reader->NewContextScope(1);
+      context_scope.set_is_implicit(true);
+    } else {
+      context_scope = ContextScope::New(1, true);
+    }
     reader->AddBackRef(object_id, &context_scope, kIsDeserialized);
 
     *reader->TypeHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
@@ -1699,7 +1647,6 @@
                             intptr_t object_id,
                             intptr_t tags,
                             Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
@@ -1710,14 +1657,9 @@
   result.set_state_bits(reader->Read<uint32_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (result.raw()->to() - result.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    result.StorePointer((result.raw()->from() + i),
-                        reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(result,
+                     result.raw()->from(), result.raw()->to(),
+                     kAsReference);
 
   return result.raw();
 }
@@ -1750,7 +1692,6 @@
                                                 intptr_t object_id,
                                                 intptr_t tags,
                                                 Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
@@ -1762,14 +1703,9 @@
   result.set_filled_entry_count(reader->Read<int32_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (result.raw()->to() - result.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    result.StorePointer((result.raw()->from() + i),
-                        reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(result,
+                     result.raw()->from(), result.raw()->to(),
+                     kAsReference);
 
   return result.raw();
 }
@@ -1801,7 +1737,6 @@
                                                 intptr_t object_id,
                                                 intptr_t tags,
                                                 Snapshot::Kind kind) {
-  UNREACHABLE();  // Untested.
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
@@ -1867,14 +1802,9 @@
   reader->AddBackRef(object_id, &api_error, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (api_error.raw()->to() - api_error.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    api_error.StorePointer((api_error.raw()->from() + i),
-                           reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(api_error,
+                     api_error.raw()->from(), api_error.raw()->to(),
+                     kAsReference);
 
   return api_error.raw();
 }
@@ -1914,15 +1844,9 @@
   language_error.set_kind(reader->Read<uint8_t>());
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds =
-      (language_error.raw()->to() - language_error.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    language_error.StorePointer((language_error.raw()->from() + i),
-                                reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(language_error,
+                     language_error.raw()->from(), language_error.raw()->to(),
+                     kAsReference);
 
   return language_error.raw();
 }
@@ -1959,14 +1883,9 @@
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (result.raw()->to() - result.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    result.StorePointer((result.raw()->from() + i),
-                         reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(result,
+                     result.raw()->from(), result.raw()->to(),
+                     kAsReference);
 
   return result.raw();
 }
@@ -2118,14 +2037,7 @@
   reader->AddBackRef(object_id, &obj, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (obj.raw()->to() - obj.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsInlinedObject);
-    obj.StorePointer(obj.raw()->from() + i,
-                     reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(obj, obj.raw()->from(), obj.raw()->to(), kAsInlinedObject);
 
   // If it is a canonical constant make it one.
   // When reading a full snapshot we don't need to canonicalize the object
@@ -2603,13 +2515,18 @@
 
   LinkedHashMap& map = LinkedHashMap::ZoneHandle(
       reader->zone(), LinkedHashMap::null());
-  if (kind == Snapshot::kFull || kind == Snapshot::kScript) {
+  if ((kind == Snapshot::kFull && !reader->snapshot_code()) ||
+      kind == Snapshot::kScript) {
     // The immutable maps that seed map literals are not yet VM-internal, so
     // we don't reach this.
     UNREACHABLE();
   } else {
     // Since the map might contain itself as a key or value, allocate first.
-    map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
+    if (kind == Snapshot::kFull) {
+      map = reader->NewLinkedHashMap();
+    } else {
+      map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
+    }
   }
   reader->AddBackRef(object_id, &map, kIsDeserialized);
 
@@ -2630,7 +2547,9 @@
       Utils::RoundUpToPowerOfTwo(used_data),
       static_cast<uintptr_t>(LinkedHashMap::kInitialIndexSize));
   Array& data = Array::ZoneHandle(reader->zone(),
-                                  Array::New(data_size, HEAP_SPACE(kind)));
+                                  NEW_OBJECT_WITH_LEN_SPACE(Array,
+                                                            data_size,
+                                                            kind));
   map.SetData(data);
   map.SetDeletedKeys(0);
 
@@ -2654,10 +2573,10 @@
 void RawLinkedHashMap::WriteTo(SnapshotWriter* writer,
                                intptr_t object_id,
                                Snapshot::Kind kind) {
-  if (kind == Snapshot::kFull || kind == Snapshot::kScript) {
+  if ((kind == Snapshot::kFull && !writer->snapshot_code()) ||
+      kind == Snapshot::kScript) {
     // The immutable maps that seed map literals are not yet VM-internal, so
     // we don't reach this.
-    UNREACHABLE();
   }
   ASSERT(writer != NULL);
 
@@ -3103,11 +3022,18 @@
                                 intptr_t object_id,
                                 intptr_t tags,
                                 Snapshot::Kind kind) {
+  ASSERT(kind == Snapshot::kMessage || reader->snapshot_code());
+
   uint64_t id = reader->Read<uint64_t>();
   uint64_t origin_id = reader->Read<uint64_t>();
 
-  SendPort& result = SendPort::ZoneHandle(reader->zone(),
-                                          SendPort::New(id, origin_id));
+  SendPort& result = SendPort::ZoneHandle(reader->zone());
+  if (reader->snapshot_code()) {
+    // TODO(rmacnak): Reset fields in precompiled snapshots and assert
+    // this is unreachable.
+  } else {
+    result = SendPort::New(id, origin_id);
+  }
   reader->AddBackRef(object_id, &result, kIsDeserialized);
   return result.raw();
 }
@@ -3137,19 +3063,14 @@
                                                 reader->NewStacktrace());
     reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-    // Set all the object fields.
-    // TODO(5411462): Need to assert No GC can happen here, even though
-    // allocations may happen.
-    intptr_t num_flds = (result.raw()->to() - result.raw()->from());
-    for (intptr_t i = 0; i <= num_flds; i++) {
-      (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-      result.StorePointer((result.raw()->from() + i),
-                          reader->PassiveObjectHandle()->raw());
-    }
-
     bool expand_inlined = reader->Read<bool>();
     result.set_expand_inlined(expand_inlined);
 
+    // Set all the object fields.
+    READ_OBJECT_FIELDS(result,
+                       result.raw()->from(), result.raw()->to(),
+                       kAsReference);
+
     return result.raw();
   }
   UNREACHABLE();  // Stacktraces are not sent in a snapshot.
@@ -3172,11 +3093,11 @@
     writer->WriteIndexedObject(kStacktraceCid);
     writer->WriteTags(writer->GetObjectTags(this));
 
+    writer->Write(ptr()->expand_inlined_);
+
     // Write out all the object pointer fields.
     SnapshotWriterVisitor visitor(writer);
     visitor.VisitPointers(from(), to());
-
-    writer->Write(ptr()->expand_inlined_);
   } else {
     // Stacktraces are not allowed in other snapshot forms.
     writer->SetWriteException(Exceptions::kArgument,
@@ -3246,15 +3167,9 @@
   reader->AddBackRef(object_id, &weak_property, kIsDeserialized);
 
   // Set all the object fields.
-  // TODO(5411462): Need to assert No GC can happen here, even though
-  // allocations may happen.
-  intptr_t num_flds = (weak_property.raw()->to() -
-                       weak_property.raw()->from());
-  for (intptr_t i = 0; i <= num_flds; i++) {
-    (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
-    weak_property.StorePointer((weak_property.raw()->from() + i),
-                               reader->PassiveObjectHandle()->raw());
-  }
+  READ_OBJECT_FIELDS(weak_property,
+                     weak_property.raw()->from(), weak_property.raw()->to(),
+                     kAsReference);
 
   return weak_property.raw();
 }
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index 6851926..5704b12 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -12,6 +12,7 @@
 #include "vm/object_store.h"
 #include "vm/regexp.h"
 #include "vm/resolver.h"
+#include "vm/runtime_entry.h"
 #include "vm/stack_frame.h"
 #include "vm/unibrow-inl.h"
 #include "vm/unicode.h"
@@ -335,11 +336,10 @@
 }
 
 
-RawBool* IRRegExpMacroAssembler::CaseInsensitiveCompareUC16(
-    RawString* str_raw,
-    RawSmi* lhs_index_raw,
-    RawSmi* rhs_index_raw,
-    RawSmi* length_raw) {
+static RawBool* CaseInsensitiveCompareUC16(RawString* str_raw,
+                                           RawSmi* lhs_index_raw,
+                                           RawSmi* rhs_index_raw,
+                                           RawSmi* length_raw) {
   const String& str = String::Handle(str_raw);
   const Smi& lhs_index = Smi::Handle(lhs_index_raw);
   const Smi& rhs_index = Smi::Handle(rhs_index_raw);
@@ -368,6 +368,11 @@
 }
 
 
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(
+    CaseInsensitiveCompareUC16, 4, false /* is_float */,
+    reinterpret_cast<RuntimeFunction>(&CaseInsensitiveCompareUC16));
+
+
 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
                                                  intptr_t index) const {
   const Type& local_type = Type::ZoneHandle(Z, Type::DynamicType());
diff --git a/runtime/vm/regexp_assembler_ir.h b/runtime/vm/regexp_assembler_ir.h
index 77d09d5..1bd3930 100644
--- a/runtime/vm/regexp_assembler_ir.h
+++ b/runtime/vm/regexp_assembler_ir.h
@@ -37,14 +37,6 @@
 
   virtual bool CanReadUnaligned();
 
-  // Compares two-byte strings case insensitively.
-  // Called from generated RegExp code.
-  static RawBool* CaseInsensitiveCompareUC16(
-      RawString* str_raw,
-      RawSmi* lhs_index_raw,
-      RawSmi* rhs_index_raw,
-      RawSmi* length_raw);
-
   static RawArray* Execute(const Function& function,
                            const String& input,
                            const Smi& start_offset,
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
new file mode 100644
index 0000000..f177a10
--- /dev/null
+++ b/runtime/vm/runtime_entry.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/runtime_entry.h"
+
+#include "vm/object.h"
+#include "vm/symbols.h"
+#include "vm/verifier.h"
+
+namespace dart {
+
+
+// Add function to a class and that class to the class dictionary so that
+// frame walking can be used.
+const Function& RegisterFakeFunction(const char* name, const Code& code) {
+  const String& class_name = String::Handle(Symbols::New("ownerClass"));
+  const Script& script = Script::Handle();
+  const Class& owner_class =
+      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const String& function_name = String::ZoneHandle(Symbols::New(name));
+  const Function& function = Function::ZoneHandle(
+      Function::New(function_name, RawFunction::kRegularFunction,
+                    true, false, false, false, false, owner_class, 0));
+  const Array& functions = Array::Handle(Array::New(1));
+  functions.SetAt(0, function);
+  owner_class.SetFunctions(functions);
+  Library& lib = Library::Handle(Library::CoreLibrary());
+  lib.AddClass(owner_class);
+  function.AttachCode(code);
+  return function;
+}
+
+}  // namespace dart
diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h
index 2d4790f..97b5623 100644
--- a/runtime/vm/runtime_entry.h
+++ b/runtime/vm/runtime_entry.h
@@ -8,6 +8,7 @@
 #include "vm/allocation.h"
 #include "vm/flags.h"
 #include "vm/native_arguments.h"
+#include "vm/runtime_entry_list.h"
 #include "vm/tags.h"
 
 namespace dart {
@@ -18,51 +19,6 @@
 
 typedef void (*RuntimeFunction)(NativeArguments arguments);
 
-#define RUNTIME_ENTRY_LIST(V)                                                  \
-  V(AllocateArray)                                                             \
-  V(AllocateContext)                                                           \
-  V(AllocateObject)                                                            \
-  V(BreakpointRuntimeHandler)                                                  \
-  V(SingleStepHandler)                                                         \
-  V(CloneContext)                                                              \
-  V(FixCallersTarget)                                                          \
-  V(FixAllocationStubTarget)                                                   \
-  V(InlineCacheMissHandlerOneArg)                                              \
-  V(InlineCacheMissHandlerTwoArgs)                                             \
-  V(InlineCacheMissHandlerThreeArgs)                                           \
-  V(StaticCallMissHandlerOneArg)                                               \
-  V(StaticCallMissHandlerTwoArgs)                                              \
-  V(Instanceof)                                                                \
-  V(TypeCheck)                                                                 \
-  V(BadTypeError)                                                              \
-  V(NonBoolTypeError)                                                          \
-  V(InstantiateType)                                                           \
-  V(InstantiateTypeArguments)                                                  \
-  V(InvokeClosureNoSuchMethod)                                                 \
-  V(InvokeNoSuchMethodDispatcher)                                              \
-  V(MegamorphicCacheMissHandler)                                               \
-  V(OptimizeInvokedFunction)                                                   \
-  V(TraceICCall)                                                               \
-  V(PatchStaticCall)                                                           \
-  V(ReThrow)                                                                   \
-  V(StackOverflow)                                                             \
-  V(Throw)                                                                     \
-  V(TraceFunctionEntry)                                                        \
-  V(TraceFunctionExit)                                                         \
-  V(DeoptimizeMaterialize)                                                     \
-  V(UpdateFieldCid)                                                            \
-  V(InitStaticField)                                                           \
-  V(GrowRegExpStack)                                                           \
-  V(CompileFunction)                                                           \
-
-#define LEAF_RUNTIME_ENTRY_LIST(V)                                             \
-  V(void, PrintStopMessage, const char*)                                       \
-  V(intptr_t, DeoptimizeCopyFrame, uword)                                      \
-  V(void, DeoptimizeFillFrame, uword)                                          \
-  V(void, StoreBufferBlockProcess, Thread*)                                    \
-  V(intptr_t, BigintCompare, RawBigint*, RawBigint*)                           \
-
-
 enum RuntimeFunctionId {
   kNoRuntimeFunctionId = -1,
 #define DECLARE_ENUM_VALUE(name) \
@@ -99,7 +55,7 @@
   intptr_t argument_count() const { return argument_count_; }
   bool is_leaf() const { return is_leaf_; }
   bool is_float() const { return is_float_; }
-  uword GetEntryPoint() const { return reinterpret_cast<uword>(function()); }
+  uword GetEntryPoint() const;
 
   // Generate code to call the runtime entry.
   void Call(Assembler* assembler, intptr_t argument_count) const;
@@ -142,7 +98,7 @@
       ASSERT(thread == Thread::Current());                                     \
       Isolate* isolate = thread->isolate();                                    \
       StackZone zone(thread);                                                  \
-      HANDLESCOPE(isolate);                                                    \
+      HANDLESCOPE(thread);                                                     \
       DRT_Helper##name(isolate, thread, zone.GetZone(), arguments);            \
     }                                                                          \
     VERIFY_ON_TRANSITION;                                                      \
@@ -167,6 +123,12 @@
 
 #define END_LEAF_RUNTIME_ENTRY }
 
+// TODO(rmacnak): Fix alignment issue on simarm and simmips and use
+// DEFINE_LEAF_RUNTIME_ENTRY instead.
+#define DEFINE_RAW_LEAF_RUNTIME_ENTRY(name, argument_count, is_float, func)    \
+  extern const RuntimeEntry k##name##RuntimeEntry(                             \
+      "DFLRT_"#name, func, argument_count, true, is_float)                     \
+
 #define DECLARE_LEAF_RUNTIME_ENTRY(type, name, ...)                            \
   extern const RuntimeEntry k##name##RuntimeEntry;                             \
   extern "C" type DLRT_##name(__VA_ARGS__);                                    \
@@ -185,12 +147,12 @@
 uword RuntimeEntry::AddressFromId(RuntimeFunctionId id) {
     switch (id) {
 #define DEFINE_RUNTIME_CASE(name)                                              \
-    case k##name##Id: return reinterpret_cast<uword>(&DRT_##name);
+    case k##name##Id: return k##name##RuntimeEntry.GetEntryPoint();
     RUNTIME_ENTRY_LIST(DEFINE_RUNTIME_CASE)
 #undef DEFINE_RUNTIME_CASE
 
 #define DEFINE_LEAF_RUNTIME_CASE(type, name, ...)                              \
-    case k##name##Id: return reinterpret_cast<uword>(&DLRT_##name);
+    case k##name##Id: return k##name##RuntimeEntry.GetEntryPoint();
     LEAF_RUNTIME_ENTRY_LIST(DEFINE_LEAF_RUNTIME_CASE)
 #undef DEFINE_LEAF_RUNTIME_CASE
     default:
@@ -202,12 +164,12 @@
 
 RuntimeFunctionId RuntimeEntry::RuntimeFunctionIdFromAddress(uword address) {
 #define CHECK_RUNTIME_ADDRESS(name)                                            \
-  if (address == reinterpret_cast<uword>(&DRT_##name)) return k##name##Id;
+  if (address == k##name##RuntimeEntry.GetEntryPoint()) return k##name##Id;
   RUNTIME_ENTRY_LIST(CHECK_RUNTIME_ADDRESS)
 #undef CHECK_RUNTIME_ADDRESS
 
 #define CHECK_LEAF_RUNTIME_ADDRESS(type, name, ...)                            \
-  if (address == reinterpret_cast<uword>(&DLRT_##name)) return k##name##Id;
+  if (address == k##name##RuntimeEntry.GetEntryPoint()) return k##name##Id;
   LEAF_RUNTIME_ENTRY_LIST(CHECK_LEAF_RUNTIME_ADDRESS)
 #undef CHECK_LEAF_RUNTIME_ADDRESS
   return kNoRuntimeFunctionId;
diff --git a/runtime/vm/runtime_entry_arm.cc b/runtime/vm/runtime_entry_arm.cc
index b373811..a2c9d49 100644
--- a/runtime/vm/runtime_entry_arm.cc
+++ b/runtime/vm/runtime_entry_arm.cc
@@ -16,38 +16,42 @@
 #define __ assembler->
 
 
+uword RuntimeEntry::GetEntryPoint() const {
+  // Compute the effective address. When running under the simulator,
+  // this is a redirection address that forces the simulator to call
+  // into the runtime system.
+  uword entry = reinterpret_cast<uword>(function());
+#if defined(USING_SIMULATOR)
+  // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
+  // in registers (maximum 2 double arguments for leaf float runtime calls).
+  ASSERT(argument_count() >= 0);
+  ASSERT(!is_leaf() ||
+         (!is_float() && (argument_count() <= 4)) ||
+         (argument_count() <= 2));
+  Simulator::CallKind call_kind =
+      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
+                              : Simulator::kLeafRuntimeCall)
+                : Simulator::kRuntimeCall;
+  entry =
+      Simulator::RedirectExternalReference(entry, call_kind, argument_count());
+#endif
+  return entry;
+}
+
+
 // Generate code to call into the stub which will call the runtime
 // function. Input for the stub is as follows:
 //   SP : points to the arguments and return value array.
 //   R5 : address of the runtime function to call.
 //   R4 : number of arguments to the call.
 void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
-  // Compute the effective address. When running under the simulator,
-  // this is a redirection address that forces the simulator to call
-  // into the runtime system.
-  uword entry = GetEntryPoint();
-#if defined(USING_SIMULATOR)
-  // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
-  // in registers (maximum 2 double arguments for leaf float runtime calls).
-  ASSERT(argument_count >= 0);
-  ASSERT(!is_leaf() ||
-         (!is_float() && (argument_count <= 4)) ||
-         (argument_count <= 2));
-  Simulator::CallKind call_kind =
-      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
-                              : Simulator::kLeafRuntimeCall)
-                : Simulator::kRuntimeCall;
-  entry =
-      Simulator::RedirectExternalReference(entry, call_kind, argument_count);
-#endif
-  ExternalLabel label(entry);
   if (is_leaf()) {
     ASSERT(argument_count == this->argument_count());
-    __ BranchLink(&label, kNotPatchable);
+    __ BranchLinkOffset(THR, Thread::OffsetFromThread(this));
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
-    __ LoadExternalLabel(R5, &label, kNotPatchable);
+    __ LoadFromOffset(kWord, R5, THR, Thread::OffsetFromThread(this));
     __ LoadImmediate(R4, argument_count);
     __ BranchLink(*StubCode::CallToRuntime_entry(), kNotPatchable);
   }
diff --git a/runtime/vm/runtime_entry_arm64.cc b/runtime/vm/runtime_entry_arm64.cc
index 38dbe43..626d940 100644
--- a/runtime/vm/runtime_entry_arm64.cc
+++ b/runtime/vm/runtime_entry_arm64.cc
@@ -15,29 +15,36 @@
 
 #define __ assembler->
 
+
+uword RuntimeEntry::GetEntryPoint() const {
+  // Compute the effective address. When running under the simulator,
+  // this is a redirection address that forces the simulator to call
+  // into the runtime system.
+  uword entry = reinterpret_cast<uword>(function());
+#if defined(USING_SIMULATOR)
+  // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
+  // in registers (maximum 2 double arguments for leaf float runtime calls).
+  ASSERT(argument_count() >= 0);
+  ASSERT(!is_leaf() ||
+         (!is_float() && (argument_count() <= 4)) ||
+         (argument_count() <= 2));
+  Simulator::CallKind call_kind =
+      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
+                              : Simulator::kLeafRuntimeCall)
+                : Simulator::kRuntimeCall;
+  entry =
+      Simulator::RedirectExternalReference(entry, call_kind, argument_count());
+#endif
+  return entry;
+}
+
+
 // Generate code to call into the stub which will call the runtime
 // function. Input for the stub is as follows:
 //   SP : points to the arguments and return value array.
 //   R5 : address of the runtime function to call.
 //   R4 : number of arguments to the call.
 void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
-  // Compute the effective address. When running under the simulator,
-  // this is a redirection address that forces the simulator to call
-  // into the runtime system.
-  uword entry = GetEntryPoint();
-#if defined(USING_SIMULATOR)
-  // Redirection to leaf runtime calls supports a maximum of 8 arguments passed
-  // in registers.
-  ASSERT(argument_count >= 0);
-  ASSERT(!is_leaf() || (argument_count <= 8));
-  Simulator::CallKind call_kind =
-      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
-                              : Simulator::kLeafRuntimeCall)
-                : Simulator::kRuntimeCall;
-  entry =
-      Simulator::RedirectExternalReference(entry, call_kind, argument_count);
-#endif
-  ExternalLabel label(entry);
   if (is_leaf()) {
     ASSERT(argument_count == this->argument_count());
     // Since we are entering C++ code, we must restore the C stack pointer from
@@ -49,13 +56,14 @@
     __ mov(R26, SP);
     __ ReserveAlignedFrameSpace(0);
     __ mov(CSP, SP);
-    __ BranchLink(&label);
+    __ ldr(TMP, Address(THR, Thread::OffsetFromThread(this)));
+    __ blr(TMP);
     __ mov(SP, R26);
     __ mov(CSP, R25);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
-    __ LoadExternalLabel(R5, &label);
+    __ ldr(R5, Address(THR, Thread::OffsetFromThread(this)));
     __ LoadImmediate(R4, argument_count);
     __ BranchLink(*StubCode::CallToRuntime_entry());
   }
diff --git a/runtime/vm/runtime_entry_ia32.cc b/runtime/vm/runtime_entry_ia32.cc
index 33b0e5a..f16db03 100644
--- a/runtime/vm/runtime_entry_ia32.cc
+++ b/runtime/vm/runtime_entry_ia32.cc
@@ -15,6 +15,11 @@
 #define __ assembler->
 
 
+uword RuntimeEntry::GetEntryPoint() const {
+  return reinterpret_cast<uword>(function());
+}
+
+
 // Generate code to call into the stub which will call the runtime
 // function. Input for the stub is as follows:
 // For regular runtime calls -
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
new file mode 100644
index 0000000..acdb5bf
--- /dev/null
+++ b/runtime/vm/runtime_entry_list.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_RUNTIME_ENTRY_LIST_H_
+#define VM_RUNTIME_ENTRY_LIST_H_
+
+namespace dart {
+
+#define RUNTIME_ENTRY_LIST(V)                                                  \
+  V(AllocateArray)                                                             \
+  V(AllocateContext)                                                           \
+  V(AllocateObject)                                                            \
+  V(BreakpointRuntimeHandler)                                                  \
+  V(SingleStepHandler)                                                         \
+  V(CloneContext)                                                              \
+  V(FixCallersTarget)                                                          \
+  V(FixAllocationStubTarget)                                                   \
+  V(InlineCacheMissHandlerOneArg)                                              \
+  V(InlineCacheMissHandlerTwoArgs)                                             \
+  V(InlineCacheMissHandlerThreeArgs)                                           \
+  V(StaticCallMissHandlerOneArg)                                               \
+  V(StaticCallMissHandlerTwoArgs)                                              \
+  V(Instanceof)                                                                \
+  V(TypeCheck)                                                                 \
+  V(BadTypeError)                                                              \
+  V(NonBoolTypeError)                                                          \
+  V(InstantiateType)                                                           \
+  V(InstantiateTypeArguments)                                                  \
+  V(InvokeClosureNoSuchMethod)                                                 \
+  V(InvokeNoSuchMethodDispatcher)                                              \
+  V(MegamorphicCacheMissHandler)                                               \
+  V(OptimizeInvokedFunction)                                                   \
+  V(TraceICCall)                                                               \
+  V(PatchStaticCall)                                                           \
+  V(ReThrow)                                                                   \
+  V(StackOverflow)                                                             \
+  V(Throw)                                                                     \
+  V(TraceFunctionEntry)                                                        \
+  V(TraceFunctionExit)                                                         \
+  V(DeoptimizeMaterialize)                                                     \
+  V(UpdateFieldCid)                                                            \
+  V(InitStaticField)                                                           \
+  V(GrowRegExpStack)                                                           \
+  V(CompileFunction)                                                           \
+
+#define LEAF_RUNTIME_ENTRY_LIST(V)                                             \
+  V(void, PrintStopMessage, const char*)                                       \
+  V(intptr_t, DeoptimizeCopyFrame, uword)                                      \
+  V(void, DeoptimizeFillFrame, uword)                                          \
+  V(void, StoreBufferBlockProcess, Thread*)                                    \
+  V(intptr_t, BigintCompare, RawBigint*, RawBigint*)                           \
+  V(double, LibcPow, double, double)                                           \
+  V(double, DartModulo, double, double)                                        \
+  V(double, LibcFloor, double)                                                 \
+  V(double, LibcCeil, double)                                                  \
+  V(double, LibcTrunc, double)                                                 \
+  V(double, LibcRound, double)                                                 \
+  V(double, LibcCos, double)                                                   \
+  V(double, LibcSin, double)                                                   \
+  V(RawBool*, CaseInsensitiveCompareUC16,                                      \
+    RawString*, RawSmi*, RawSmi*, RawSmi*)                                     \
+
+}  // namespace dart
+
+#endif  // VM_RUNTIME_ENTRY_LIST_H_
diff --git a/runtime/vm/runtime_entry_mips.cc b/runtime/vm/runtime_entry_mips.cc
index e4a5dbf..31970fe 100644
--- a/runtime/vm/runtime_entry_mips.cc
+++ b/runtime/vm/runtime_entry_mips.cc
@@ -16,38 +16,43 @@
 #define __ assembler->
 
 
+uword RuntimeEntry::GetEntryPoint() const {
+  // Compute the effective address. When running under the simulator,
+  // this is a redirection address that forces the simulator to call
+  // into the runtime system.
+  uword entry = reinterpret_cast<uword>(function());
+#if defined(USING_SIMULATOR)
+  // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
+  // in registers (maximum 2 double arguments for leaf float runtime calls).
+  ASSERT(argument_count() >= 0);
+  ASSERT(!is_leaf() ||
+         (!is_float() && (argument_count() <= 4)) ||
+         (argument_count() <= 2));
+  Simulator::CallKind call_kind =
+      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
+                              : Simulator::kLeafRuntimeCall)
+                : Simulator::kRuntimeCall;
+  entry =
+      Simulator::RedirectExternalReference(entry, call_kind, argument_count());
+#endif
+  return entry;
+}
+
+
 // Generate code to call into the stub which will call the runtime
 // function. Input for the stub is as follows:
 //   SP : points to the arguments and return value array.
 //   S5 : address of the runtime function to call.
 //   S4 : number of arguments to the call.
 void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
-  // Compute the effective address. When running under the simulator,
-  // this is a redirection address that forces the simulator to call
-  // into the runtime system.
-  uword entry = GetEntryPoint();
-#if defined(USING_SIMULATOR)
-  // Redirection to leaf runtime calls supports a maximum of 4 arguments passed
-  // in registers (maximum 2 double arguments for leaf float runtime calls).
-  ASSERT(argument_count >= 0);
-  ASSERT(!is_leaf() ||
-         (!is_float() && (argument_count <= 4)) ||
-         (argument_count <= 2));
-  Simulator::CallKind call_kind =
-      is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
-                              : Simulator::kLeafRuntimeCall)
-                : Simulator::kRuntimeCall;
-  entry =
-      Simulator::RedirectExternalReference(entry, call_kind, argument_count);
-#endif
-  ExternalLabel label(entry);
   if (is_leaf()) {
     ASSERT(argument_count == this->argument_count());
-    __ BranchLink(&label, kNotPatchable);
+    __ lw(T9, Address(THR, Thread::OffsetFromThread(this)));
+    __ jalr(T9);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
-    __ LoadExternalLabel(S5, &label, kNotPatchable);
+    __ lw(S5, Address(THR, Thread::OffsetFromThread(this)));
     __ LoadImmediate(S4, argument_count);
     __ BranchLink(*StubCode::CallToRuntime_entry(), kNotPatchable);
   }
diff --git a/runtime/vm/runtime_entry_test.cc b/runtime/vm/runtime_entry_test.cc
deleted file mode 100644
index f02f6f7..0000000
--- a/runtime/vm/runtime_entry_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/runtime_entry.h"
-
-#include "vm/object.h"
-#include "vm/symbols.h"
-#include "vm/verifier.h"
-
-namespace dart {
-
-DECLARE_RUNTIME_ENTRY(TestSmiSub)
-DECLARE_LEAF_RUNTIME_ENTRY(RawObject*, TestLeafSmiAdd, RawObject*, RawObject*)
-
-
-// Add function to a class and that class to the class dictionary so that
-// frame walking can be used.
-const Function& RegisterFakeFunction(const char* name, const Code& code) {
-  const String& class_name = String::Handle(Symbols::New("ownerClass"));
-  const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
-  const String& function_name = String::ZoneHandle(Symbols::New(name));
-  const Function& function = Function::ZoneHandle(
-      Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
-  const Array& functions = Array::Handle(Array::New(1));
-  functions.SetAt(0, function);
-  owner_class.SetFunctions(functions);
-  Library& lib = Library::Handle(Library::CoreLibrary());
-  lib.AddClass(owner_class);
-  function.AttachCode(code);
-  return function;
-}
-
-
-// A runtime call for test purposes.
-// Arg0: a smi.
-// Arg1: a smi.
-// Result: a smi representing arg0 - arg1.
-DEFINE_RUNTIME_ENTRY(TestSmiSub, 2) {
-  const Smi& left = Smi::CheckedHandle(arguments.ArgAt(0));
-  const Smi& right = Smi::CheckedHandle(arguments.ArgAt(1));
-  // Ignoring overflow in the calculation below.
-  intptr_t result = left.Value() - right.Value();
-  arguments.SetReturn(Smi::Handle(Smi::New(result)));
-}
-
-
-// A leaf runtime call for test purposes.
-// arg0: a smi.
-// arg1: a smi.
-// returns a smi representing arg0 + arg1.
-DEFINE_LEAF_RUNTIME_ENTRY(RawObject*, TestLeafSmiAdd, 2,
-                          RawObject* arg0, RawObject* arg1) {
-  // Ignoring overflow in the calculation below and using the internal
-  // representation of Smi directly without using any handlized code.
-  intptr_t result = reinterpret_cast<intptr_t>(arg0) +
-      reinterpret_cast<intptr_t>(arg1);
-  return reinterpret_cast<RawObject*>(result);
-}
-END_LEAF_RUNTIME_ENTRY
-
-}  // namespace dart
diff --git a/runtime/vm/runtime_entry_x64.cc b/runtime/vm/runtime_entry_x64.cc
index a6ff635..c3afdd8 100644
--- a/runtime/vm/runtime_entry_x64.cc
+++ b/runtime/vm/runtime_entry_x64.cc
@@ -15,6 +15,11 @@
 #define __ assembler->
 
 
+uword RuntimeEntry::GetEntryPoint() const {
+  return reinterpret_cast<uword>(function());
+}
+
+
 // Generate code to call into the stub which will call the runtime
 // function. Input for the stub is as follows:
 //   RSP : points to the arguments and return value array.
@@ -23,15 +28,13 @@
 void RuntimeEntry::Call(Assembler* assembler, intptr_t argument_count) const {
   if (is_leaf()) {
     ASSERT(argument_count == this->argument_count());
-    ExternalLabel label(GetEntryPoint());
     COMPILE_ASSERT(CallingConventions::kVolatileCpuRegisters & (1 << RAX));
-    __ LoadExternalLabel(RAX, &label, kNotPatchable);
+    __ movq(RAX, Address(THR, Thread::OffsetFromThread(this)));
     __ CallCFunction(RAX);
   } else {
     // Argument count is not checked here, but in the runtime entry for a more
     // informative error message.
-    ExternalLabel label(GetEntryPoint());
-    __ LoadExternalLabel(RBX, &label, kNotPatchable);
+    __ movq(RBX, Address(THR, Thread::OffsetFromThread(this)));
     __ movq(R10, Immediate(argument_count));
     __ Call(*StubCode::CallToRuntime_entry());
   }
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index f0c5080..139705a 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -617,19 +617,23 @@
 }
 
 
-void LocalScope::RecursivelyCaptureAllVariables() {
-  for (intptr_t i = 0; i < num_variables(); i++) {
-    if ((VariableAt(i)->name().raw() == Symbols::StackTraceVar().raw()) ||
-        (VariableAt(i)->name().raw() == Symbols::ExceptionVar().raw()) ||
-        (VariableAt(i)->name().raw() == Symbols::SavedTryContextVar().raw())) {
-      // Don't capture those variables because the VM expects them to be on the
-      // stack.
-      continue;
+void LocalScope::CaptureLocalVariables(LocalScope* top_scope) {
+  ASSERT(top_scope->function_level() == function_level());
+  LocalScope* scope = this;
+  while (scope != top_scope->parent()) {
+    for (intptr_t i = 0; i < scope->num_variables(); i++) {
+      LocalVariable* variable = scope->VariableAt(i);
+      if ((variable->name().raw() == Symbols::StackTraceVar().raw()) ||
+          (variable->name().raw() == Symbols::ExceptionVar().raw()) ||
+          (variable->name().raw() == Symbols::SavedTryContextVar().raw())) {
+        // Don't capture those variables because the VM expects them to be on
+        // the stack.
+        continue;
+      }
+      scope->CaptureVariable(variable);
     }
-    CaptureVariable(VariableAt(i));
+    scope = scope->parent();
   }
-  if (sibling() != NULL) { sibling()->RecursivelyCaptureAllVariables(); }
-  if (child() != NULL) { child()->RecursivelyCaptureAllVariables(); }
 }
 
 
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index b9a2b1a..5faf502 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -327,9 +327,9 @@
   // from this scope and belonging to outer scopes.
   RawContextScope* PreserveOuterScope(int current_context_level) const;
 
-  // Recursively traverses all siblings and children and marks all variables as
-  // captured.
-  void RecursivelyCaptureAllVariables();
+  // Mark all local variables that are accessible from this scope up to
+  // top_scope (included) as captured.
+  void CaptureLocalVariables(LocalScope* top_scope);
 
   // Creates a LocalScope representing the outer scope of a local function to be
   // compiled. This outer scope contains the variables captured by the function
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 5c57b1f..c0959e3 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -37,6 +37,9 @@
 
 namespace dart {
 
+#define Z (T->zone())
+
+
 DECLARE_FLAG(bool, trace_service);
 DECLARE_FLAG(bool, trace_service_pause_events);
 
@@ -511,9 +514,9 @@
                         const Instance& reply_port,
                         const Instance& id,
                         const Error& error) {
-  Isolate* isolate = Isolate::Current();
-  StackZone zone(isolate);
-  HANDLESCOPE(isolate);
+  Thread* T = Thread::Current();
+  StackZone zone(T);
+  HANDLESCOPE(T);
   JSONStream js;
   js.Setup(zone.GetZone(), SendPort::Cast(reply_port).Id(),
            id, method_name, parameter_keys, parameter_values);
@@ -524,20 +527,22 @@
 }
 
 
-void Service::InvokeMethod(Isolate* isolate, const Array& msg) {
-  ASSERT(isolate != NULL);
+void Service::InvokeMethod(Isolate* I, const Array& msg) {
+  Thread* T = Thread::Current();
+  ASSERT(I == T->isolate());
+  ASSERT(I != NULL);
   ASSERT(!msg.IsNull());
   ASSERT(msg.Length() == 6);
 
   {
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    StackZone zone(T);
+    HANDLESCOPE(T);
 
-    Instance& reply_port = Instance::Handle(isolate);
-    Instance& seq = String::Handle(isolate);
-    String& method_name = String::Handle(isolate);
-    Array& param_keys = Array::Handle(isolate);
-    Array& param_values = Array::Handle(isolate);
+    Instance& reply_port = Instance::Handle(Z);
+    Instance& seq = String::Handle(Z);
+    String& method_name = String::Handle(Z);
+    Array& param_keys = Array::Handle(Z);
+    Array& param_values = Array::Handle(Z);
     reply_port ^= msg.At(1);
     seq ^= msg.At(2);
     method_name ^= msg.At(3);
@@ -589,7 +594,7 @@
         js.PostReply();
         return;
       }
-      if (method->entry(isolate, &js)) {
+      if (method->entry(I, &js)) {
         js.PostReply();
       } else {
         // NOTE(turnidge): All message handlers currently return true,
@@ -610,8 +615,8 @@
       return;
     }
 
-    const Instance& extension_handler =
-        Instance::Handle(isolate->LookupServiceExtensionHandler(method_name));
+    const Instance& extension_handler = Instance::Handle(Z,
+        I->LookupServiceExtensionHandler(method_name));
     if (!extension_handler.IsNull()) {
       ScheduleExtensionHandler(extension_handler,
                                method_name,
@@ -650,9 +655,10 @@
   if (!ServiceIsolate::IsRunning()) {
     return;
   }
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
 
   const Array& list = Array::Handle(Array::New(2));
   ASSERT(!list.IsNull());
@@ -1478,8 +1484,7 @@
       }
       MessageSnapshotReader reader(message->data(),
                                    message->len(),
-                                   isolate,
-                                   Thread::Current()->zone());
+                                   Thread::Current());
       const Object& msg_obj = Object::Handle(reader.ReadObject());
       msg_obj.PrintJSON(js);
       return true;
@@ -1546,6 +1551,9 @@
 
 
 static bool GetInboundReferences(Isolate* isolate, JSONStream* js) {
+  Thread* thread = Thread::Current();
+  ASSERT(isolate == thread->isolate());
+
   const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
     PrintMissingParamError(js, "targetId");
@@ -1565,7 +1573,7 @@
   Object& obj = Object::Handle(isolate);
   ObjectIdRing::LookupResult lookup_result;
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     obj = LookupHeapObject(isolate, target_id, &lookup_result);
   }
   if (obj.raw() == Object::sentinel().raw()) {
@@ -1645,6 +1653,9 @@
 
 
 static bool GetRetainingPath(Isolate* isolate, JSONStream* js) {
+  Thread* thread = Thread::Current();
+  ASSERT(isolate == thread->isolate());
+
   const char* target_id = js->LookupParam("targetId");
   if (target_id == NULL) {
     PrintMissingParamError(js, "targetId");
@@ -1664,7 +1675,7 @@
   Object& obj = Object::Handle(isolate);
   ObjectIdRing::LookupResult lookup_result;
   {
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     obj = LookupHeapObject(isolate, target_id, &lookup_result);
   }
   if (obj.raw() == Object::sentinel().raw()) {
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index 177129d..2068e40 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -22,6 +22,9 @@
 
 namespace dart {
 
+#define Z (T->zone())
+
+
 DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests.");
 DEFINE_FLAG(bool, trace_service_pause_events, false,
             "Trace VM service isolate pause events.");
@@ -219,15 +222,16 @@
  public:
   static void SendIsolateServiceMessage(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone stack_zone(isolate);
+    Thread* thread = arguments->thread();
+    StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
     GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
 
     // Set the type of the OOB message.
-    message.SetAt(0, Smi::Handle(isolate, Smi::New(Message::kServiceOOBMsg)));
+    message.SetAt(0, Smi::Handle(thread->zone(),
+                                 Smi::New(Message::kServiceOOBMsg)));
 
     // Serialize message.
     uint8_t* data = NULL;
@@ -243,19 +247,20 @@
 
   static void SendRootServiceMessage(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone stack_zone(isolate);
+    Thread* thread = arguments->thread();
+    StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
     Service::HandleRootMessage(message);
   }
 
   static void OnStart(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    Thread* thread = arguments->thread();
+    Isolate* isolate = thread->isolate();
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     {
       if (FLAG_trace_service) {
         OS::Print("vm-service: Booting dart:vmservice library.\n");
@@ -287,9 +292,9 @@
 
   static void OnExit(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+    Thread* thread = arguments->thread();
+    StackZone zone(thread);
+    HANDLESCOPE(thread);
     {
       if (FLAG_trace_service) {
         OS::Print("vm-service: processed exit message.\n");
@@ -299,10 +304,10 @@
 
   static void ListenStream(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone stack_zone(isolate);
+    Thread* thread = arguments->thread();
+    StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
     bool result = Service::ListenStream(stream_id.ToCString());
     arguments->SetReturn(Bool::Get(result));
@@ -310,10 +315,10 @@
 
   static void CancelStream(Dart_NativeArguments args) {
     NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-    Isolate* isolate = arguments->thread()->isolate();
-    StackZone stack_zone(isolate);
+    Thread* thread = arguments->thread();
+    StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();  // Used by GET_NON_NULL_NATIVE_ARGUMENT.
-    HANDLESCOPE(isolate);
+    HANDLESCOPE(thread);
     GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
     Service::CancelStream(stream_id.ToCString());
   }
@@ -424,12 +429,13 @@
   if (!IsRunning()) {
     return false;
   }
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   if (IsServiceIsolateDescendant(isolate)) {
     return false;
   }
   ASSERT(isolate != NULL);
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
   const String& name = String::Handle(String::New(isolate->name()));
   ASSERT(!name.IsNull());
   const Array& list = Array::Handle(
@@ -455,12 +461,13 @@
   if (!IsRunning()) {
     return false;
   }
-  Isolate* isolate = Isolate::Current();
+  Thread* thread = Thread::Current();
+  Isolate* isolate = thread->isolate();
   if (IsServiceIsolateDescendant(isolate)) {
     return false;
   }
   ASSERT(isolate != NULL);
-  HANDLESCOPE(isolate);
+  HANDLESCOPE(thread);
   const String& name = String::Handle(String::New(isolate->name()));
   ASSERT(!name.IsNull());
   const Array& list = Array::Handle(
@@ -522,10 +529,12 @@
 }
 
 
-void ServiceIsolate::MaybeInjectVMServiceLibrary(Isolate* isolate) {
-  ASSERT(isolate != NULL);
-  ASSERT(isolate->name() != NULL);
-  if (!ServiceIsolate::NameEquals(isolate->name())) {
+void ServiceIsolate::MaybeInjectVMServiceLibrary(Isolate* I) {
+  Thread* T = Thread::Current();
+  ASSERT(I == T->isolate());
+  ASSERT(I != NULL);
+  ASSERT(I->name() != NULL);
+  if (!ServiceIsolate::NameEquals(I->name())) {
     // Not service isolate.
     return;
   }
@@ -533,19 +542,19 @@
     // Service isolate already exists.
     return;
   }
-  SetServiceIsolate(isolate);
+  SetServiceIsolate(I);
 
-  StackZone zone(isolate);
-  HANDLESCOPE(isolate);
+  StackZone zone(T);
+  HANDLESCOPE(T);
 
   // Register dart:vmservice library.
-  const String& url_str = String::Handle(Symbols::DartVMService().raw());
-  const Library& library = Library::Handle(Library::New(url_str));
+  const String& url_str = String::Handle(Z, Symbols::DartVMService().raw());
+  const Library& library = Library::Handle(Z, Library::New(url_str));
   library.Register();
   library.set_native_entry_resolver(ServiceNativeResolver);
 
   // Temporarily install our library tag handler.
-  isolate->set_library_tag_handler(LibraryTagHandler);
+  I->set_library_tag_handler(LibraryTagHandler);
 
   // Get script source.
   const char* resource = NULL;
@@ -553,17 +562,16 @@
   intptr_t r = Resources::ResourceLookup(path, &resource);
   ASSERT(r != Resources::kNoSuchInstance);
   ASSERT(resource != NULL);
-  const String& source_str = String::Handle(
+  const String& source_str = String::Handle(Z,
       String::FromUTF8(reinterpret_cast<const uint8_t*>(resource), r));
   ASSERT(!source_str.IsNull());
-  const Script& script = Script::Handle(
-    isolate, Script::New(url_str, source_str, RawScript::kLibraryTag));
+  const Script& script = Script::Handle(Z,
+      Script::New(url_str, source_str, RawScript::kLibraryTag));
 
   // Compile script.
   Dart_EnterScope();  // Need to enter scope for tag handler.
   library.SetLoadInProgress();
-  const Error& error = Error::Handle(isolate,
-                                     Compiler::Compile(library, script));
+  const Error& error = Error::Handle(Z, Compiler::Compile(library, script));
   if (!error.IsNull()) {
     OS::PrintErr("vm-service: Isolate creation error: %s\n",
           error.ToErrorCString());
@@ -574,19 +582,22 @@
   Dart_ExitScope();
 
   // Uninstall our library tag handler.
-  isolate->set_library_tag_handler(NULL);
+  I->set_library_tag_handler(NULL);
 }
 
 
-void ServiceIsolate::ConstructExitMessageAndCache(Isolate* isolate) {
+void ServiceIsolate::ConstructExitMessageAndCache(Isolate* I) {
   // Construct and cache exit message here so we can send it without needing an
   // isolate.
-  StartIsolateScope iso_scope(isolate);
-  StackZone zone(isolate);
-  HANDLESCOPE(isolate);
+  StartIsolateScope iso_scope(I);
+  Thread* T = Thread::Current();
+  ASSERT(I == T->isolate());
+  ASSERT(I != NULL);
+  StackZone zone(T);
+  HANDLESCOPE(T);
   ASSERT(exit_message_ == NULL);
   ASSERT(exit_message_length_ == 0);
-  const Array& list = Array::Handle(MakeServiceExitMessage());
+  const Array& list = Array::Handle(Z, MakeServiceExitMessage());
   ASSERT(!list.IsNull());
   MessageWriter writer(&exit_message_, &allocator, false);
   writer.WriteMessage(list);
@@ -662,16 +673,18 @@
 
  protected:
   static void ShutdownIsolate(uword parameter) {
-    Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
-    ASSERT(ServiceIsolate::IsServiceIsolate(isolate));
+    Isolate* I = reinterpret_cast<Isolate*>(parameter);
+    ASSERT(ServiceIsolate::IsServiceIsolate(I));
     {
       // Print the error if there is one.  This may execute dart code to
       // print the exception object, so we need to use a StartIsolateScope.
-      StartIsolateScope start_scope(isolate);
-      StackZone zone(isolate);
-      HandleScope handle_scope(isolate);
-      Error& error = Error::Handle();
-      error = isolate->object_store()->sticky_error();
+      StartIsolateScope start_scope(I);
+      Thread* T = Thread::Current();
+      ASSERT(I == T->isolate());
+      StackZone zone(T);
+      HandleScope handle_scope(T);
+      Error& error = Error::Handle(Z);
+      error = I->object_store()->sticky_error();
       if (!error.IsNull()) {
         OS::PrintErr("vm-service: Error: %s\n", error.ToErrorCString());
       }
@@ -679,7 +692,7 @@
     }
     {
       // Shut the isolate down.
-      SwitchIsolateScope switch_scope(isolate);
+      SwitchIsolateScope switch_scope(I);
       Dart::ShutdownIsolate();
     }
     ServiceIsolate::SetServiceIsolate(NULL);
@@ -690,13 +703,15 @@
     ServiceIsolate::FinishedExiting();
   }
 
-  void RunMain(Isolate* isolate) {
-    StartIsolateScope iso_scope(isolate);
-    StackZone zone(isolate);
-    HANDLESCOPE(isolate);
+  void RunMain(Isolate* I) {
+    StartIsolateScope iso_scope(I);
+    Thread* T = Thread::Current();
+    ASSERT(I == T->isolate());
+    StackZone zone(T);
+    HANDLESCOPE(T);
     // Invoke main which will return the loadScriptPort.
-    const Library& root_library =
-        Library::Handle(isolate, isolate->object_store()->root_library());
+    const Library& root_library = Library::Handle(Z,
+        I->object_store()->root_library());
     if (root_library.IsNull()) {
       if (FLAG_trace_service) {
         OS::Print("vm-service: Embedder did not install a script.");
@@ -705,11 +720,10 @@
       return;
     }
     ASSERT(!root_library.IsNull());
-    const String& entry_name = String::Handle(isolate, String::New("main"));
+    const String& entry_name = String::Handle(Z, String::New("main"));
     ASSERT(!entry_name.IsNull());
-    const Function& entry =
-        Function::Handle(isolate,
-                         root_library.LookupFunctionAllowPrivate(entry_name));
+    const Function& entry = Function::Handle(Z,
+        root_library.LookupFunctionAllowPrivate(entry_name));
     if (entry.IsNull()) {
       // Service isolate is not supported by embedder.
       if (FLAG_trace_service) {
@@ -718,10 +732,8 @@
       return;
     }
     ASSERT(!entry.IsNull());
-    const Object& result =
-        Object::Handle(isolate,
-                       DartEntry::InvokeFunction(entry,
-                                                 Object::empty_array()));
+    const Object& result = Object::Handle(Z,
+        DartEntry::InvokeFunction(entry, Object::empty_array()));
     ASSERT(!result.IsNull());
     if (result.IsError()) {
       // Service isolate did not initialize properly.
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index f5fe86f..0bae8ad 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -35,10 +35,8 @@
     }
 
     // Parse the message.
-    MessageSnapshotReader reader(message->data(),
-                                 message->len(),
-                                 Isolate::Current(),
-                                 Thread::Current()->zone());
+    Thread* thread = Thread::Current();
+    MessageSnapshotReader reader(message->data(), message->len(), thread);
     const Object& response_obj = Object::Handle(reader.ReadObject());
     String& response = String::Handle();
     response ^= response_obj.raw();
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 415d1ed..5ab4697 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -16,6 +16,7 @@
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/snapshot_ids.h"
+#include "vm/stub_code.h"
 #include "vm/symbols.h"
 #include "vm/verified_memory.h"
 #include "vm/version.h"
@@ -23,7 +24,7 @@
 // We currently only expect the Dart mutator to read snapshots.
 #define ASSERT_NO_SAFEPOINT_SCOPE()                            \
     isolate()->AssertCurrentThreadIsMutator();                 \
-    ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0)
+    ASSERT(thread()->no_safepoint_scope_depth() != 0)
 
 namespace dart {
 
@@ -171,35 +172,41 @@
 SnapshotReader::SnapshotReader(
     const uint8_t* buffer,
     intptr_t size,
+    const uint8_t* instructions_buffer,
     Snapshot::Kind kind,
     ZoneGrowableArray<BackRefNode>* backward_refs,
-    Isolate* isolate,
-    Zone* zone)
+    Thread* thread)
     : BaseReader(buffer, size),
+      instructions_buffer_(instructions_buffer),
       kind_(kind),
-      snapshot_code_(false),
-      isolate_(isolate),
-      zone_(zone),
-      heap_(isolate->heap()),
-      old_space_(isolate->heap()->old_space()),
-      cls_(Class::Handle(isolate)),
-      obj_(Object::Handle(isolate)),
-      pobj_(PassiveObject::Handle(isolate)),
-      array_(Array::Handle(isolate)),
-      field_(Field::Handle(isolate)),
-      str_(String::Handle(isolate)),
-      library_(Library::Handle(isolate)),
-      type_(AbstractType::Handle(isolate)),
-      type_arguments_(TypeArguments::Handle(isolate)),
-      tokens_(Array::Handle(isolate)),
-      stream_(TokenStream::Handle(isolate)),
-      data_(ExternalTypedData::Handle(isolate)),
-      typed_data_(TypedData::Handle(isolate)),
-      error_(UnhandledException::Handle(isolate)),
+      snapshot_code_(instructions_buffer != NULL),
+      thread_(thread),
+      zone_(thread->zone()),
+      heap_(isolate()->heap()),
+      old_space_(thread_->isolate()->heap()->old_space()),
+      cls_(Class::Handle(zone_)),
+      obj_(Object::Handle(zone_)),
+      pobj_(PassiveObject::Handle(zone_)),
+      array_(Array::Handle(zone_)),
+      field_(Field::Handle(zone_)),
+      str_(String::Handle(zone_)),
+      library_(Library::Handle(zone_)),
+      type_(AbstractType::Handle(zone_)),
+      type_arguments_(TypeArguments::Handle(zone_)),
+      tokens_(Array::Handle(zone_)),
+      stream_(TokenStream::Handle(zone_)),
+      data_(ExternalTypedData::Handle(zone_)),
+      typed_data_(TypedData::Handle(zone_)),
+      code_(Code::Handle(zone_)),
+      error_(UnhandledException::Handle(zone_)),
       max_vm_isolate_object_id_(
           (kind == Snapshot::kFull) ?
               Object::vm_isolate_snapshot_object_table().Length() : 0),
-      backward_references_(backward_refs) {
+      backward_references_(backward_refs),
+      instructions_reader_(NULL) {
+  if (instructions_buffer != NULL) {
+    instructions_reader_ = new InstructionsReader(instructions_buffer);
+  }
 }
 
 
@@ -304,21 +311,19 @@
 
 
 void SnapshotReader::SetReadException(const char* msg) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  const String& error_str = String::Handle(zone, String::New(msg));
-  const Array& args = Array::Handle(zone, Array::New(1));
+  const String& error_str = String::Handle(zone(), String::New(msg));
+  const Array& args = Array::Handle(zone(), Array::New(1));
   args.SetAt(0, error_str);
-  Object& result = Object::Handle(zone);
-  const Library& library = Library::Handle(zone, Library::CoreLibrary());
+  Object& result = Object::Handle(zone());
+  const Library& library = Library::Handle(zone(), Library::CoreLibrary());
   result = DartLibraryCalls::InstanceCreate(library,
                                             Symbols::ArgumentError(),
                                             Symbols::Dot(),
                                             args);
-  const Stacktrace& stacktrace = Stacktrace::Handle(zone);
+  const Stacktrace& stacktrace = Stacktrace::Handle(zone());
   const UnhandledException& error = UnhandledException::Handle(
-      zone, UnhandledException::New(Instance::Cast(result), stacktrace));
-  thread->long_jump_base()->Jump(1, error);
+      zone(), UnhandledException::New(Instance::Cast(result), stacktrace));
+  thread()->long_jump_base()->Jump(1, error);
 }
 
 
@@ -328,7 +333,7 @@
 
 
 bool SnapshotReader::is_vm_isolate() const {
-  return isolate_ == Dart::vm_isolate();
+  return isolate() == Dart::vm_isolate();
 }
 
 
@@ -505,7 +510,9 @@
       ASSERT(!cls_.IsNull());
       instance_size = cls_.instance_size();
     }
-    intptr_t next_field_offset = cls_.next_field_offset();
+    intptr_t next_field_offset = Class::IsSignatureClass(cls_.raw())
+      ? Closure::InstanceSize() : cls_.next_field_offset();
+
     intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
     ASSERT(next_field_offset > 0);
     // Instance::NextFieldOffset() returns the offset of the first field in
@@ -778,6 +785,82 @@
 }
 
 
+RawObjectPool* SnapshotReader::NewObjectPool(intptr_t len) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawObjectPool* obj = reinterpret_cast<RawObjectPool*>(
+      AllocateUninitialized(kObjectPoolCid, ObjectPool::InstanceSize(len)));
+  obj->ptr()->length_ = len;
+  return obj;
+}
+
+
+RawLocalVarDescriptors* SnapshotReader::NewLocalVarDescriptors(
+    intptr_t num_entries) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawLocalVarDescriptors* obj = reinterpret_cast<RawLocalVarDescriptors*>(
+      AllocateUninitialized(kLocalVarDescriptorsCid,
+                            LocalVarDescriptors::InstanceSize(num_entries)));
+  obj->ptr()->num_entries_ = num_entries;
+  return obj;
+}
+
+
+RawExceptionHandlers* SnapshotReader::NewExceptionHandlers(
+    intptr_t num_entries) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawExceptionHandlers* obj = reinterpret_cast<RawExceptionHandlers*>(
+      AllocateUninitialized(kExceptionHandlersCid,
+                            ExceptionHandlers::InstanceSize(num_entries)));
+  obj->ptr()->num_entries_ = num_entries;
+  return obj;
+}
+
+
+RawPcDescriptors* SnapshotReader::NewPcDescriptors(intptr_t len) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawPcDescriptors* obj = reinterpret_cast<RawPcDescriptors*>(
+      AllocateUninitialized(kPcDescriptorsCid,
+                            PcDescriptors::InstanceSize(len)));
+  obj->ptr()->length_ = len;
+  return obj;
+}
+
+
+RawStackmap* SnapshotReader::NewStackmap(intptr_t len) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawStackmap* obj = reinterpret_cast<RawStackmap*>(
+      AllocateUninitialized(kStackmapCid, Stackmap::InstanceSize(len)));
+  obj->ptr()->length_ = len;
+  return obj;
+}
+
+
+RawContextScope* SnapshotReader::NewContextScope(intptr_t num_variables) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawContextScope* obj = reinterpret_cast<RawContextScope*>(
+      AllocateUninitialized(kContextScopeCid,
+                            ContextScope::InstanceSize(num_variables)));
+  obj->ptr()->num_variables_ = num_variables;
+  return obj;
+}
+
+
+RawCode* SnapshotReader::NewCode(intptr_t pointer_offsets_length) {
+  ASSERT(pointer_offsets_length == 0);
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawCode* obj = reinterpret_cast<RawCode*>(
+      AllocateUninitialized(kCodeCid, Code::InstanceSize(0)));
+  return obj;
+}
+
+
 RawTokenStream* SnapshotReader::NewTokenStream(intptr_t len) {
   ASSERT(kind_ == Snapshot::kFull);
   ASSERT_NO_SAFEPOINT_SCOPE();
@@ -927,22 +1010,16 @@
 }
 
 
-RawCode* SnapshotReader::NewCode(intptr_t pointer_offsets_length) {
-  ASSERT(pointer_offsets_length == 0);
-  ALLOC_NEW_OBJECT(Code);
-}
-
-
-RawObjectPool* SnapshotReader::NewObjectPool(intptr_t length) {
-  ALLOC_NEW_OBJECT(ObjectPool);
-}
-
-
 RawICData* SnapshotReader::NewICData() {
   ALLOC_NEW_OBJECT(ICData);
 }
 
 
+RawLinkedHashMap* SnapshotReader::NewLinkedHashMap() {
+  ALLOC_NEW_OBJECT(LinkedHashMap);
+}
+
+
 RawMegamorphicCache* SnapshotReader::NewMegamorphicCache() {
   ALLOC_NEW_OBJECT(MegamorphicCache);
 }
@@ -1060,8 +1137,36 @@
 }
 
 
-RawInstructions* SnapshotReader::GetInstructionsById(int32_t id) {
-  // TODO(rmacnak): Read from shared library.
+int32_t InstructionsWriter::GetOffsetFor(RawInstructions* instructions) {
+  // Instructions are allocated with the code alignment and we don't write
+  // anything else in the text section.
+  ASSERT(Utils::IsAligned(stream_.bytes_written(),
+                          OS::PreferredCodeAlignment()));
+
+  intptr_t offset = stream_.bytes_written();
+  stream_.WriteBytes(reinterpret_cast<uint8_t*>(instructions) - kHeapObjectTag,
+                     instructions->Size());
+  return offset;
+}
+
+
+RawInstructions* InstructionsReader::GetInstructionsAt(int32_t offset,
+                                                       uword expected_tags) {
+  ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment()));
+
+  RawInstructions* result =
+      reinterpret_cast<RawInstructions*>(
+          reinterpret_cast<uword>(buffer_) + offset + kHeapObjectTag);
+
+  uword actual_tags = result->ptr()->tags_;
+  if (actual_tags != expected_tags) {
+    FATAL2("Instructions tag mismatch: expected %" Pd ", saw %" Pd,
+           expected_tags,
+           actual_tags);
+  }
+
+  // TODO(rmacnak): The above contains stale pointers to a Code and an
+  // ObjectPool. Return the actual result after calling convention change.
   return Instructions::null();
 }
 
@@ -1076,7 +1181,7 @@
   }
   ASSERT(SerializedHeaderTag::decode(class_header) == kObjectId);
   intptr_t class_id = SerializedHeaderData::decode(class_header);
-  ASSERT(IsObjectStoreClassId(class_id));
+  ASSERT(IsObjectStoreClassId(class_id) || IsSingletonClassId(class_id));
   return class_id;
 }
 
@@ -1099,7 +1204,7 @@
     // read part and return the error object back.
     const UnhandledException& error = UnhandledException::Handle(
         object_store()->preallocated_unhandled_exception());
-    Thread::Current()->long_jump_base()->Jump(1, error);
+    thread()->long_jump_base()->Jump(1, error);
   }
   VerifiedMemory::Accept(address, size);
 
@@ -1274,16 +1379,18 @@
 }
 
 
-VmIsolateSnapshotReader::VmIsolateSnapshotReader(const uint8_t* buffer,
-                                                 intptr_t size,
-                                                 Zone* zone)
-    : SnapshotReader(buffer,
-                     size,
-                     Snapshot::kFull,
-                     new ZoneGrowableArray<BackRefNode>(
-                         kNumVmIsolateSnapshotReferences),
-                     Dart::vm_isolate(),
-                     zone) {
+VmIsolateSnapshotReader::VmIsolateSnapshotReader(
+    const uint8_t* buffer,
+    intptr_t size,
+    const uint8_t* instructions_buffer,
+    Thread* thread)
+      : SnapshotReader(buffer,
+                       size,
+                       instructions_buffer,
+                       Snapshot::kFull,
+                       new ZoneGrowableArray<BackRefNode>(
+                           kNumVmIsolateSnapshotReferences),
+                       thread) {
 }
 
 
@@ -1296,6 +1403,7 @@
         i, *(backrefs->At(i).reference()));
   }
   ResetBackwardReferenceTable();
+  Object::set_instructions_snapshot_buffer(instructions_buffer_);
 }
 
 
@@ -1329,6 +1437,29 @@
     // only memory.
     *(ArrayHandle()) ^= ReadObject();
 
+
+    if (snapshot_code()) {
+      for (intptr_t i = 0;
+           i < ArgumentsDescriptor::kCachedDescriptorCount;
+           i++) {
+        *(ArrayHandle()) ^= ReadObject();
+        // TODO(rmacnak):
+        // ArgumentsDescriptor::InitOnceFromSnapshot(i, *(ArrayHandle()));
+      }
+
+      ObjectPool::CheckedHandle(ReadObject());  // empty pool
+      PcDescriptors::CheckedHandle(ReadObject());  // empty pc desc
+      LocalVarDescriptors::CheckedHandle(ReadObject());  // empty var desc
+      ExceptionHandlers::CheckedHandle(ReadObject());  // empty exc handlers
+
+#define READ_STUB(name)                                                       \
+      *(CodeHandle()) ^= ReadObject();
+      // TODO(rmacnak):
+      // StubCode::name##_entry()->InitOnceFromSnapshot(CodeHandle())
+      VM_STUB_CODE_LIST(READ_STUB);
+#undef READ_STUB
+    }
+
     // Validate the class table.
 #if defined(DEBUG)
     isolate->ValidateClassTable();
@@ -1341,15 +1472,15 @@
 
 IsolateSnapshotReader::IsolateSnapshotReader(const uint8_t* buffer,
                                              intptr_t size,
-                                             Isolate* isolate,
-                                             Zone* zone)
+                                             const uint8_t* instructions_buffer,
+                                             Thread* thread)
     : SnapshotReader(buffer,
                      size,
+                     instructions_buffer,
                      Snapshot::kFull,
                      new ZoneGrowableArray<BackRefNode>(
                          kNumInitialReferencesInFullSnapshot),
-                     isolate,
-                     zone) {
+                     thread) {
 }
 
 
@@ -1360,14 +1491,13 @@
 
 ScriptSnapshotReader::ScriptSnapshotReader(const uint8_t* buffer,
                                            intptr_t size,
-                                           Isolate* isolate,
-                                           Zone* zone)
+                                           Thread* thread)
     : SnapshotReader(buffer,
                      size,
+                     NULL, /* instructions_buffer */
                      Snapshot::kScript,
                      new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
-                     isolate,
-                     zone) {
+                     thread) {
 }
 
 
@@ -1378,14 +1508,13 @@
 
 MessageSnapshotReader::MessageSnapshotReader(const uint8_t* buffer,
                                              intptr_t size,
-                                             Isolate* isolate,
-                                             Zone* zone)
+                                             Thread* thread)
     : SnapshotReader(buffer,
                      size,
+                     NULL, /* instructions_buffer */
                      Snapshot::kMessage,
                      new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
-                     isolate,
-                     zone) {
+                     thread) {
 }
 
 
@@ -1399,19 +1528,23 @@
                                ReAlloc alloc,
                                intptr_t initial_size,
                                ForwardList* forward_list,
+                               InstructionsWriter* instructions_writer,
                                bool can_send_any_object,
-                               bool snapshot_code)
+                               bool snapshot_code,
+                               bool vm_isolate_is_symbolic)
     : BaseWriter(buffer, alloc, initial_size),
       kind_(kind),
-      isolate_(Isolate::Current()),
-      object_store_(isolate_->object_store()),
-      class_table_(isolate_->class_table()),
+      thread_(Thread::Current()),
+      object_store_(thread_->isolate()->object_store()),
+      class_table_(thread_->isolate()->class_table()),
       forward_list_(forward_list),
+      instructions_writer_(instructions_writer),
       exception_type_(Exceptions::kNone),
       exception_msg_(NULL),
       unmarked_objects_(false),
       can_send_any_object_(can_send_any_object),
-      snapshot_code_(snapshot_code) {
+      snapshot_code_(snapshot_code),
+      vm_isolate_is_symbolic_(vm_isolate_is_symbolic) {
   ASSERT(forward_list_ != NULL);
 }
 
@@ -1433,80 +1566,80 @@
     object_id = forward_list_->AddObject(rawobj, kIsSerialized);               \
     Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(rawobj);               \
     raw_obj->WriteTo(this, object_id, kind());                                 \
-    return;                                                                    \
+    return true;                                                               \
   }                                                                            \
 
-void SnapshotWriter::HandleVMIsolateObject(RawObject* rawobj) {
+bool SnapshotWriter::HandleVMIsolateObject(RawObject* rawobj) {
   // Check if it is a singleton null object.
   if (rawobj == Object::null()) {
     WriteVMIsolateObject(kNullObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton sentinel object.
   if (rawobj == Object::sentinel().raw()) {
     WriteVMIsolateObject(kSentinelObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton sentinel object.
   if (rawobj == Object::transition_sentinel().raw()) {
     WriteVMIsolateObject(kTransitionSentinelObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton empty array object.
   if (rawobj == Object::empty_array().raw()) {
     WriteVMIsolateObject(kEmptyArrayObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton zero array object.
   if (rawobj == Object::zero_array().raw()) {
     WriteVMIsolateObject(kZeroArrayObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton dyanmic Type object.
   if (rawobj == Object::dynamic_type()) {
     WriteVMIsolateObject(kDynamicType);
-    return;
+    return true;
   }
 
   // Check if it is a singleton void Type object.
   if (rawobj == Object::void_type()) {
     WriteVMIsolateObject(kVoidType);
-    return;
+    return true;
   }
 
   // Check if it is a singleton boolean true object.
   if (rawobj == Bool::True().raw()) {
     WriteVMIsolateObject(kTrueValue);
-    return;
+    return true;
   }
 
   // Check if it is a singleton boolean false object.
   if (rawobj == Bool::False().raw()) {
     WriteVMIsolateObject(kFalseValue);
-    return;
+    return true;
   }
 
   // Check if it is a singleton extractor parameter types array.
   if (rawobj == Object::extractor_parameter_types().raw()) {
     WriteVMIsolateObject(kExtractorParameterTypes);
-    return;
+    return true;
   }
 
   // Check if it is a singleton extractor parameter names array.
   if (rawobj == Object::extractor_parameter_names().raw()) {
     WriteVMIsolateObject(kExtractorParameterNames);
-    return;
+    return true;
   }
 
   // Check if it is a singleton empty context scope object.
   if (rawobj == Object::empty_context_scope().raw()) {
     WriteVMIsolateObject(kEmptyContextScopeObject);
-    return;
+    return true;
   }
 
   // Check if it is a singleton class object which is shared by
@@ -1518,7 +1651,7 @@
     if (IsSingletonClassId(class_id)) {
       intptr_t object_id = ObjectIdFromClassId(class_id);
       WriteVMIsolateObject(object_id);
-      return;
+      return true;
     }
   }
 
@@ -1527,14 +1660,14 @@
     id = Symbols::LookupVMSymbol(rawobj);
     if (id != kInvalidIndex) {
       WriteVMIsolateObject(id);
-      return;
+      return true;
     }
 
     // Check if it is an object from the vm isolate snapshot object table.
     id = FindVmSnapshotObject(rawobj);
     if (id != kInvalidIndex) {
       WriteIndexedObject(id);
-      return;
+      return true;
     }
   } else {
     // In the case of script snapshots or for messages we do not use
@@ -1543,7 +1676,7 @@
     intptr_t object_id = forward_list_->FindObject(rawobj);
     if (object_id != -1) {
       WriteIndexedObject(object_id);
-      return;
+      return true;
     } else {
       switch (id) {
         VM_OBJECT_CLASS_LIST(VM_OBJECT_WRITE)
@@ -1551,7 +1684,7 @@
           object_id = forward_list_->AddObject(rawobj, kIsSerialized);
           RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(rawobj);
           raw_obj->WriteTo(this, object_id, kind());
-          return;
+          return true;
         }
         default:
           OS::Print("class id = %" Pd "\n", id);
@@ -1560,8 +1693,13 @@
     }
   }
 
+  if (!vm_isolate_is_symbolic()) {
+    return false;
+  }
+
   const Object& obj = Object::Handle(rawobj);
   FATAL1("Unexpected reference to object in VM isolate: %s\n", obj.ToCString());
+  return false;
 }
 
 #undef VM_OBJECT_WRITE
@@ -1606,18 +1744,24 @@
 
 FullSnapshotWriter::FullSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
                                        uint8_t** isolate_snapshot_buffer,
+                                       uint8_t** instructions_snapshot_buffer,
                                        ReAlloc alloc,
-                                       bool snapshot_code)
+                                       bool snapshot_code,
+                                       bool vm_isolate_is_symbolic)
     : isolate_(Isolate::Current()),
       vm_isolate_snapshot_buffer_(vm_isolate_snapshot_buffer),
       isolate_snapshot_buffer_(isolate_snapshot_buffer),
+      instructions_snapshot_buffer_(instructions_snapshot_buffer),
       alloc_(alloc),
       vm_isolate_snapshot_size_(0),
       isolate_snapshot_size_(0),
+      instructions_snapshot_size_(0),
       forward_list_(NULL),
+      instructions_writer_(NULL),
       scripts_(Array::Handle(isolate_)),
       symbol_table_(Array::Handle(isolate_)),
-      snapshot_code_(snapshot_code) {
+      snapshot_code_(snapshot_code),
+      vm_isolate_is_symbolic_(vm_isolate_is_symbolic) {
   ASSERT(isolate_snapshot_buffer_ != NULL);
   ASSERT(alloc_ != NULL);
   ASSERT(isolate_ != NULL);
@@ -1651,6 +1795,12 @@
 
   forward_list_ = new ForwardList(SnapshotWriter::FirstObjectId());
   ASSERT(forward_list_ != NULL);
+
+  if (instructions_snapshot_buffer != NULL) {
+    instructions_writer_ = new InstructionsWriter(instructions_snapshot_buffer,
+                                                  alloc,
+                                                  kInitialSize);
+  }
 }
 
 
@@ -1668,8 +1818,10 @@
                         alloc_,
                         kInitialSize,
                         forward_list_,
+                        instructions_writer_,
                         true, /* can_send_any_object */
-                        snapshot_code_);
+                        snapshot_code_,
+                        vm_isolate_is_symbolic_);
   // Write full snapshot for the VM isolate.
   // Setup for long jump in case there is an exception while writing
   // the snapshot.
@@ -1695,8 +1847,26 @@
     // read only memory.
     writer.WriteObject(scripts_.raw());
 
-    // Write out all forwarded objects.
-    writer.WriteForwardedObjects();
+    if (snapshot_code_) {
+      ASSERT(!vm_isolate_is_symbolic_);
+
+      for (intptr_t i = 0;
+           i < ArgumentsDescriptor::kCachedDescriptorCount;
+           i++) {
+        writer.WriteObject(ArgumentsDescriptor::cached_args_descriptors_[i]);
+      }
+
+      writer.WriteObject(Object::empty_object_pool().raw());
+      writer.WriteObject(Object::empty_descriptors().raw());
+      writer.WriteObject(Object::empty_var_descriptors().raw());
+      writer.WriteObject(Object::empty_exception_handlers().raw());
+
+#define WRITE_STUB(name)                                                       \
+      writer.WriteObject(StubCode::name##_entry()->code());
+      VM_STUB_CODE_LIST(WRITE_STUB);
+#undef WRITE_STUB
+    }
+
 
     writer.FillHeader(writer.kind());
 
@@ -1713,8 +1883,10 @@
                         alloc_,
                         kInitialSize,
                         forward_list_,
+                        instructions_writer_,
                         true, /* can_send_any_object */
-                        snapshot_code_);
+                        snapshot_code_,
+                        true /* vm_isolate_is_symbolic */);
   ObjectStore* object_store = isolate_->object_store();
   ASSERT(object_store != NULL);
 
@@ -1749,22 +1921,50 @@
 }
 
 
-void FullSnapshotWriter::WriteFullSnapshot() {
-  if (vm_isolate_snapshot_buffer() != NULL) {
-    WriteVmIsolateSnapshot();
+class WritableVMIsolateScope : StackResource {
+ public:
+  explicit WritableVMIsolateScope(Thread* thread) : StackResource(thread) {
+    Dart::vm_isolate()->heap()->WriteProtect(false);
   }
-  WriteIsolateFullSnapshot();
+
+  ~WritableVMIsolateScope() {
+    ASSERT(Dart::vm_isolate()->heap()->UsedInWords(Heap::kNew) == 0);
+    Dart::vm_isolate()->heap()->WriteProtect(true);
+  }
+};
+
+
+void FullSnapshotWriter::WriteFullSnapshot() {
+  if (!vm_isolate_is_symbolic_) {
+    // TODO(asiva): Don't mutate object headers during serialization.
+    WritableVMIsolateScope scope(Thread::Current());
+
+    if (vm_isolate_snapshot_buffer() != NULL) {
+      WriteVmIsolateSnapshot();
+    }
+    WriteIsolateFullSnapshot();
+
+    instructions_snapshot_size_ = instructions_writer_->BytesWritten();
+  } else {
+    if (vm_isolate_snapshot_buffer() != NULL) {
+      WriteVmIsolateSnapshot();
+    }
+    WriteIsolateFullSnapshot();
+  }
 }
 
 
 PrecompiledSnapshotWriter::PrecompiledSnapshotWriter(
     uint8_t** vm_isolate_snapshot_buffer,
     uint8_t** isolate_snapshot_buffer,
+    uint8_t** instructions_snapshot_buffer,
     ReAlloc alloc)
   : FullSnapshotWriter(vm_isolate_snapshot_buffer,
                        isolate_snapshot_buffer,
+                       instructions_snapshot_buffer,
                        alloc,
-                       true /* snapshot_code */) {
+                       true, /* snapshot_code */
+                       false /* vm_isolate_is_symbolic */) {
 }
 
 
@@ -1894,8 +2094,7 @@
   // Now check if it is an object from the VM isolate (NOTE: premarked objects
   // are considered to be objects in the VM isolate). These objects are shared
   // by all isolates.
-  if (rawobj->IsVMHeapObject()) {
-    HandleVMIsolateObject(rawobj);
+  if (rawobj->IsVMHeapObject() && HandleVMIsolateObject(rawobj)) {
     return true;
   }
 
@@ -2087,7 +2286,9 @@
 #undef SNAPSHOT_WRITE
     default: break;
   }
-  UNREACHABLE();
+
+  const Object& obj = Object::Handle(raw);
+  FATAL1("Unexpected inlined object: %s\n", obj.ToCString());
 }
 
 
@@ -2218,7 +2419,7 @@
     }
     // Not a closure of a top level method or static function, throw an
     // exception as we do not allow these objects to be serialized.
-    HANDLESCOPE(isolate());
+    HANDLESCOPE(thread());
 
     const Class& clazz = Class::Handle(isolate(), cls);
     const Function& errorFunc = Function::Handle(isolate(), func);
@@ -2230,7 +2431,7 @@
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
     intptr_t len = OS::SNPrint(NULL, 0, format,
                                clazz.ToCString(), errorFunc.ToCString()) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
+    char* chars = thread()->zone()->Alloc<char>(len);
     OS::SNPrint(chars, len, format, clazz.ToCString(), errorFunc.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
@@ -2253,13 +2454,13 @@
 void SnapshotWriter::CheckForNativeFields(RawClass* cls) {
   if (cls->ptr()->num_native_fields_ != 0) {
     // We do not allow objects with native fields in an isolate message.
-    HANDLESCOPE(isolate());
+    HANDLESCOPE(thread());
     const char* format = "Illegal argument in isolate message"
                          " : (object extends NativeWrapper - %s)";
     UnmarkAll();  // Unmark objects now as we are about to print stuff.
     const Class& clazz = Class::Handle(isolate(), cls);
     intptr_t len = OS::SNPrint(NULL, 0, format, clazz.ToCString()) + 1;
-    char* chars = Thread::Current()->zone()->Alloc<char>(len);
+    char* chars = thread()->zone()->Alloc<char>(len);
     OS::SNPrint(chars, len, format, clazz.ToCString());
     SetWriteException(Exceptions::kArgument, chars);
   }
@@ -2283,12 +2484,14 @@
   // Check if the instance has native fields and throw an exception if it does.
   CheckForNativeFields(cls);
 
-  // Check if object is a closure that is serializable, if the object is a
-  // closure that is not serializable this will throw an exception.
-  RawFunction* func = IsSerializableClosure(cls, raw);
-  if (func != Function::null()) {
-    WriteStaticImplicitClosure(object_id, func, tags);
-    return;
+  if ((kind() == Snapshot::kMessage) || (kind() == Snapshot::kScript)) {
+    // Check if object is a closure that is serializable, if the object is a
+    // closure that is not serializable this will throw an exception.
+    RawFunction* func = IsSerializableClosure(cls, raw);
+    if (func != Function::null()) {
+      WriteStaticImplicitClosure(object_id, func, tags);
+      return;
+    }
   }
 
   // Object is regular dart instance.
@@ -2418,8 +2621,10 @@
                      alloc,
                      kInitialSize,
                      &forward_list_,
+                     NULL, /* instructions_writer */
                      true, /* can_send_any_object */
-                     false /* snapshot_code */),
+                     false, /* snapshot_code */
+                     true /* vm_isolate_is_symbolic */),
       forward_list_(kMaxPredefinedObjectIds) {
   ASSERT(buffer != NULL);
   ASSERT(alloc != NULL);
@@ -2473,8 +2678,10 @@
                      alloc,
                      kInitialSize,
                      &forward_list_,
+                     NULL, /* instructions_writer */
                      can_send_any_object,
-                     false /* snapshot_code */),
+                     false, /* snapshot_code */
+                     true /* vm_isolate_is_symbolic */),
       forward_list_(kMaxPredefinedObjectIds) {
   ASSERT(buffer != NULL);
   ASSERT(alloc != NULL);
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index d58490e..d84d3fe 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -39,7 +39,9 @@
 class RawClass;
 class RawClosureData;
 class RawContext;
+class RawContextScope;
 class RawDouble;
+class RawExceptionHandlers;
 class RawField;
 class RawFloat32x4;
 class RawFloat64x2;
@@ -54,6 +56,7 @@
 class RawLibraryPrefix;
 class RawLinkedHashMap;
 class RawLiteralToken;
+class RawLocalVarDescriptors;
 class RawMegamorphicCache;
 class RawMint;
 class RawMixinAppType;
@@ -63,11 +66,13 @@
 class RawObjectPool;
 class RawOneByteString;
 class RawPatchClass;
+class RawPcDescriptors;
 class RawReceivePort;
 class RawRedirectionData;
 class RawScript;
 class RawSendPort;
 class RawSmi;
+class RawStackmap;
 class RawStacktrace;
 class RawSubtypeTestCache;
 class RawTokenStream;
@@ -295,14 +300,33 @@
 };
 
 
+class InstructionsReader : public ZoneAllocated {
+ public:
+  explicit InstructionsReader(const uint8_t* buffer)
+    : buffer_(buffer) {
+    ASSERT(buffer != NULL);
+    ASSERT(Utils::IsAligned(reinterpret_cast<uword>(buffer),
+                            OS::PreferredCodeAlignment()));
+  }
+
+  RawInstructions* GetInstructionsAt(int32_t offset, uword expected_tags);
+
+ private:
+  const uint8_t* buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionsReader);
+};
+
+
 // Reads a snapshot into objects.
 class SnapshotReader : public BaseReader {
  public:
+  Thread* thread() const { return thread_; }
   Zone* zone() const { return zone_; }
-  Isolate* isolate() const { return isolate_; }
+  Isolate* isolate() const { return thread_->isolate(); }
   Heap* heap() const { return heap_; }
-  ObjectStore* object_store() const { return isolate_->object_store(); }
-  ClassTable* class_table() const { return isolate_->class_table(); }
+  ObjectStore* object_store() const { return isolate()->object_store(); }
+  ClassTable* class_table() const { return isolate()->class_table(); }
   PassiveObject* PassiveObjectHandle() { return &pobj_; }
   Array* ArrayHandle() { return &array_; }
   String* StringHandle() { return &str_; }
@@ -312,6 +336,7 @@
   TokenStream* StreamHandle() { return &stream_; }
   ExternalTypedData* DataHandle() { return &data_; }
   TypedData* TypedDataHandle() { return &typed_data_; }
+  Code* CodeHandle() { return &code_; }
   Snapshot::Kind kind() const { return kind_; }
   bool snapshot_code() const { return snapshot_code_; }
 
@@ -364,9 +389,15 @@
   RawFunction* NewFunction();
   RawCode* NewCode(intptr_t pointer_offsets_length);
   RawObjectPool* NewObjectPool(intptr_t length);
+  RawPcDescriptors* NewPcDescriptors(intptr_t length);
+  RawLocalVarDescriptors* NewLocalVarDescriptors(intptr_t num_entries);
+  RawExceptionHandlers* NewExceptionHandlers(intptr_t num_entries);
+  RawStackmap* NewStackmap(intptr_t length);
+  RawContextScope* NewContextScope(intptr_t num_variables);
   RawICData* NewICData();
   RawMegamorphicCache* NewMegamorphicCache();
   RawSubtypeTestCache* NewSubtypeTestCache();
+  RawLinkedHashMap* NewLinkedHashMap();
   RawField* NewField();
   RawLibrary* NewLibrary();
   RawLibraryPrefix* NewLibraryPrefix();
@@ -383,15 +414,19 @@
   RawObject* NewInteger(int64_t value);
   RawStacktrace* NewStacktrace();
 
-  RawInstructions* GetInstructionsById(int32_t id);
+  RawInstructions* GetInstructionsAt(int32_t offset, uword expected_tags) {
+    return instructions_reader_->GetInstructionsAt(offset, expected_tags);
+  }
+
+  const uint8_t* instructions_buffer_;
 
  protected:
   SnapshotReader(const uint8_t* buffer,
                  intptr_t size,
+                 const uint8_t* instructions_buffer,
                  Snapshot::Kind kind,
                  ZoneGrowableArray<BackRefNode>* backward_references,
-                 Isolate* isolate,
-                 Zone* zone);
+                 Thread* thread);
   ~SnapshotReader() { }
 
   ZoneGrowableArray<BackRefNode>* GetBackwardReferenceTable() const {
@@ -466,7 +501,7 @@
 
   Snapshot::Kind kind_;  // Indicates type of snapshot(full, script, message).
   bool snapshot_code_;
-  Isolate* isolate_;  // Current isolate.
+  Thread* thread_;  // Current thread.
   Zone* zone_;  // Zone for allocations while reading snapshot.
   Heap* heap_;  // Heap of the current isolate.
   PageSpace* old_space_;  // Old space of the current isolate.
@@ -483,9 +518,11 @@
   TokenStream& stream_;  // Temporary token stream handle.
   ExternalTypedData& data_;  // Temporary stream data handle.
   TypedData& typed_data_;  // Temporary typed data handle.
+  Code& code_;  // Temporary code handle.
   UnhandledException& error_;  // Error handle.
   intptr_t max_vm_isolate_object_id_;
   ZoneGrowableArray<BackRefNode>* backward_references_;
+  InstructionsReader* instructions_reader_;
 
   friend class ApiError;
   friend class Array;
@@ -502,6 +539,7 @@
   friend class GrowableObjectArray;
   friend class ICData;
   friend class ImmutableArray;
+  friend class Instructions;
   friend class JSRegExp;
   friend class LanguageError;
   friend class Library;
@@ -533,7 +571,10 @@
 
 class VmIsolateSnapshotReader : public SnapshotReader {
  public:
-  VmIsolateSnapshotReader(const uint8_t* buffer, intptr_t size, Zone* zone);
+  VmIsolateSnapshotReader(const uint8_t* buffer,
+                          intptr_t size,
+                          const uint8_t* instructions_buffer,
+                          Thread* thread);
   ~VmIsolateSnapshotReader();
 
   RawApiError* ReadVmIsolateSnapshot();
@@ -547,8 +588,8 @@
  public:
   IsolateSnapshotReader(const uint8_t* buffer,
                         intptr_t size,
-                        Isolate* isolate,
-                        Zone* zone);
+                        const uint8_t* instructions_buffer,
+                        Thread* thread);
   ~IsolateSnapshotReader();
 
  private:
@@ -560,8 +601,7 @@
  public:
   ScriptSnapshotReader(const uint8_t* buffer,
                        intptr_t size,
-                       Isolate* isolate,
-                       Zone* zone);
+                       Thread* thread);
   ~ScriptSnapshotReader();
 
  private:
@@ -573,8 +613,7 @@
  public:
   MessageSnapshotReader(const uint8_t* buffer,
                         intptr_t size,
-                        Isolate* isolate,
-                        Zone* zone);
+                        Thread* thread);
   ~MessageSnapshotReader();
 
  private:
@@ -733,6 +772,28 @@
 };
 
 
+class InstructionsWriter : public ZoneAllocated {
+ public:
+  InstructionsWriter(uint8_t** buffer,
+                     ReAlloc alloc,
+                     intptr_t initial_size)
+    : stream_(buffer, alloc, initial_size) {
+    ASSERT(buffer != NULL);
+    ASSERT(alloc != NULL);
+  }
+
+  // Size of the snapshot.
+  intptr_t BytesWritten() const { return stream_.bytes_written(); }
+
+  int32_t GetOffsetFor(RawInstructions* instructions);
+
+ private:
+  WriteStream stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(InstructionsWriter);
+};
+
+
 class SnapshotWriter : public BaseWriter {
  protected:
   SnapshotWriter(Snapshot::Kind kind,
@@ -740,8 +801,10 @@
                  ReAlloc alloc,
                  intptr_t initial_size,
                  ForwardList* forward_list,
+                 InstructionsWriter* instructions_writer,
                  bool can_send_any_object,
-                 bool snapshot_code);
+                 bool snapshot_code,
+                 bool vm_isolate_is_symbolic);
 
  public:
   // Snapshot kind.
@@ -764,6 +827,7 @@
   }
   bool can_send_any_object() const { return can_send_any_object_; }
   bool snapshot_code() const { return snapshot_code_; }
+  bool vm_isolate_is_symbolic() const { return vm_isolate_is_symbolic_; }
   void ThrowException(Exceptions::ExceptionType type, const char* msg);
 
   // Write a version string for the snapshot.
@@ -771,7 +835,9 @@
 
   static intptr_t FirstObjectId();
 
-  int32_t GetInstructionsId(RawInstructions* instructions) { return 0; }
+  int32_t GetInstructionsId(RawInstructions* instructions) {
+    return instructions_writer_->GetOffsetFor(instructions);
+  }
 
  protected:
   void UnmarkAll() {
@@ -782,7 +848,7 @@
   }
 
   bool CheckAndWritePredefinedObject(RawObject* raw);
-  void HandleVMIsolateObject(RawObject* raw);
+  bool HandleVMIsolateObject(RawObject* raw);
 
   void WriteClassId(RawClass* cls);
   void WriteStaticImplicitClosure(intptr_t object_id,
@@ -819,20 +885,23 @@
     forward_list_ = NULL;
   }
 
-  Isolate* isolate() const { return isolate_; }
+  Thread* thread() const { return thread_; }
+  Isolate* isolate() const { return thread_->isolate(); }
   ObjectStore* object_store() const { return object_store_; }
 
  private:
   Snapshot::Kind kind_;
-  Isolate* isolate_;
+  Thread* thread_;
   ObjectStore* object_store_;  // Object store for common classes.
   ClassTable* class_table_;  // Class table for the class index to class lookup.
   ForwardList* forward_list_;
+  InstructionsWriter* instructions_writer_;
   Exceptions::ExceptionType exception_type_;  // Exception type.
   const char* exception_msg_;  // Message associated with exception.
   bool unmarked_objects_;  // True if marked objects have been unmarked.
   bool can_send_any_object_;  // True if any Dart instance can be sent.
   bool snapshot_code_;
+  bool vm_isolate_is_symbolic_;
 
   friend class FullSnapshotWriter;
   friend class RawArray;
@@ -868,8 +937,10 @@
   static const intptr_t kInitialSize = 64 * KB;
   FullSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
                      uint8_t** isolate_snapshot_buffer,
+                     uint8_t** instructions_snapshot_buffer,
                      ReAlloc alloc,
-                     bool snapshot_code);
+                     bool snapshot_code,
+                     bool vm_isolate_is_symbolic);
   ~FullSnapshotWriter();
 
   uint8_t** vm_isolate_snapshot_buffer() {
@@ -889,6 +960,9 @@
   intptr_t IsolateSnapshotSize() const {
     return isolate_snapshot_size_;
   }
+  intptr_t InstructionsSnapshotSize() const {
+    return instructions_snapshot_size_;
+  }
 
  private:
   // Writes a snapshot of the VM Isolate.
@@ -900,13 +974,17 @@
   Isolate* isolate_;
   uint8_t** vm_isolate_snapshot_buffer_;
   uint8_t** isolate_snapshot_buffer_;
+  uint8_t** instructions_snapshot_buffer_;
   ReAlloc alloc_;
   intptr_t vm_isolate_snapshot_size_;
   intptr_t isolate_snapshot_size_;
+  intptr_t instructions_snapshot_size_;
   ForwardList* forward_list_;
+  InstructionsWriter* instructions_writer_;
   Array& scripts_;
   Array& symbol_table_;
   bool snapshot_code_;
+  bool vm_isolate_is_symbolic_;
 
   DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter);
 };
@@ -916,6 +994,7 @@
  public:
   PrecompiledSnapshotWriter(uint8_t** vm_isolate_snapshot_buffer,
                             uint8_t** isolate_snapshot_buffer,
+                            uint8_t** instructions_snapshot_buffer,
                             ReAlloc alloc);
   ~PrecompiledSnapshotWriter();
 };
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 9c67df8..56cbfd6 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -152,7 +152,7 @@
 
 
 TEST_CASE(SerializeNull) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with object content.
   const Object& null_object = Object::Handle();
@@ -162,10 +162,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   EXPECT(Equals(null_object, serialized_object));
 
@@ -180,7 +177,7 @@
 
 
 TEST_CASE(SerializeSmi1) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with object content.
   const Smi& smi = Smi::Handle(Smi::New(124));
@@ -190,10 +187,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   EXPECT(Equals(smi, serialized_object));
 
@@ -209,7 +203,7 @@
 
 
 TEST_CASE(SerializeSmi2) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with object content.
   const Smi& smi = Smi::Handle(Smi::New(-1));
@@ -219,10 +213,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   EXPECT(Equals(smi, serialized_object));
 
@@ -246,12 +237,10 @@
 
   {
     // Switch to a regular zone, where VM handle allocation is allowed.
-    StackZone zone(Thread::Current());
+    Thread* thread = Thread::Current();
+    StackZone zone(thread);
     // Read object back from the snapshot.
-    MessageSnapshotReader reader(buffer,
-                                 buffer_len,
-                                 Isolate::Current(),
-                                 Thread::Current()->zone());
+    MessageSnapshotReader reader(buffer, buffer_len, thread);
     const Object& serialized_object = Object::Handle(reader.ReadObject());
     EXPECT(serialized_object.IsMint());
   }
@@ -312,7 +301,7 @@
 
 
 TEST_CASE(SerializeDouble) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with object content.
   const Double& dbl = Double::Handle(Double::New(101.29));
@@ -322,10 +311,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   EXPECT(Equals(dbl, serialized_object));
 
@@ -341,7 +327,7 @@
 
 
 TEST_CASE(SerializeTrue) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with true object.
   const Bool& bl = Bool::True();
@@ -351,10 +337,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   fprintf(stderr, "%s / %s\n", bl.ToCString(), serialized_object.ToCString());
 
@@ -372,7 +355,7 @@
 
 
 TEST_CASE(SerializeFalse) {
-  StackZone zone(Thread::Current());
+  StackZone zone(thread);
 
   // Write snapshot with false object.
   const Bool& bl = Bool::False();
@@ -382,10 +365,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   const Object& serialized_object = Object::Handle(reader.ReadObject());
   EXPECT(Equals(bl, serialized_object));
 
@@ -406,8 +386,6 @@
 
 
 TEST_CASE(SerializeCapability) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const Capability& capability = Capability::Handle(Capability::New(12345));
   uint8_t* buffer;
@@ -416,10 +394,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   Capability& obj = Capability::Handle();
   obj ^= reader.ReadObject();
 
@@ -438,8 +413,6 @@
 
 
 TEST_CASE(SerializeBigint) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const char* cstr = "0x270FFFFFFFFFFFFFD8F0";
   const String& str = String::Handle(String::New(cstr));
@@ -451,10 +424,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   Bigint& obj = Bigint::Handle();
   obj ^= reader.ReadObject();
 
@@ -482,12 +452,10 @@
 
   {
     // Switch to a regular zone, where VM handle allocation is allowed.
-    StackZone zone(Thread::Current());
+    Thread* thread = Thread::Current();
+    StackZone zone(thread);
     // Read object back from the snapshot.
-    MessageSnapshotReader reader(buffer,
-                                 buffer_len,
-                                 Isolate::Current(),
-                                 Thread::Current()->zone());
+    MessageSnapshotReader reader(buffer, buffer_len, thread);
     Bigint& serialized_bigint = Bigint::Handle();
     serialized_bigint ^= reader.ReadObject();
     const char* str1 = bigint.ToHexCString(allocator);
@@ -550,10 +518,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                                 buffer_len,
-                                 Isolate::Current(),
-                                 Thread::Current()->zone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   EXPECT(Object::class_class() == reader.ReadObject());
   EXPECT(Object::type_arguments_class() == reader.ReadObject());
   EXPECT(Object::function_class() == reader.ReadObject());
@@ -573,7 +538,7 @@
 
 
 static void TestString(const char* cstr) {
-  StackZone zone(Thread::Current());
+  Thread* thread = Thread::Current();
   EXPECT(Utf8::IsValid(reinterpret_cast<const uint8_t*>(cstr), strlen(cstr)));
   // Write snapshot with object content.
   String& str = String::Handle(String::New(cstr));
@@ -583,10 +548,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   String& serialized_str = String::Handle();
   serialized_str ^= reader.ReadObject();
   EXPECT(str.Equals(serialized_str));
@@ -617,8 +579,6 @@
 
 
 TEST_CASE(SerializeArray) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const int kArrayLength = 10;
   Array& array = Array::Handle(Array::New(kArrayLength));
@@ -633,10 +593,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   Array& serialized_array = Array::Handle();
   serialized_array ^= reader.ReadObject();
   EXPECT(array.CanonicalizeEquals(serialized_array));
@@ -709,8 +666,6 @@
 
 
 TEST_CASE(SerializeEmptyArray) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const int kArrayLength = 0;
   Array& array = Array::Handle(Array::New(kArrayLength));
@@ -720,10 +675,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   Array& serialized_array = Array::Handle();
   serialized_array ^= reader.ReadObject();
   EXPECT(array.CanonicalizeEquals(serialized_array));
@@ -740,8 +692,6 @@
 
 
 TEST_CASE(SerializeByteArray) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const int kTypedDataLength = 256;
   TypedData& typed_data = TypedData::Handle(
@@ -755,10 +705,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   TypedData& serialized_typed_data = TypedData::Handle();
   serialized_typed_data ^= reader.ReadObject();
   EXPECT(serialized_typed_data.IsTypedData());
@@ -776,54 +723,50 @@
 }
 
 
-#define TEST_TYPED_ARRAY(darttype, ctype)                                     \
-  {                                                                           \
-    StackZone zone(Thread::Current());                                       \
-    const int kArrayLength = 127;                                             \
-    TypedData& array = TypedData::Handle(                                     \
-        TypedData::New(kTypedData##darttype##ArrayCid, kArrayLength));        \
-    intptr_t scale = array.ElementSizeInBytes();                              \
-    for (int i = 0; i < kArrayLength; i++) {                                  \
-      array.Set##darttype((i * scale), i);                                    \
-    }                                                                         \
-    uint8_t* buffer;                                                          \
-    MessageWriter writer(&buffer, &zone_allocator, true);                     \
-    writer.WriteMessage(array);                                               \
-    intptr_t buffer_len = writer.BytesWritten();                              \
-    MessageSnapshotReader reader(buffer, buffer_len,                          \
-                          Isolate::Current(),                                 \
-                          zone.GetZone());                                    \
-    TypedData& serialized_array = TypedData::Handle();                        \
-    serialized_array ^= reader.ReadObject();                                  \
-    for (int i = 0; i < kArrayLength; i++) {                                  \
-      EXPECT_EQ(static_cast<ctype>(i),                                        \
-                serialized_array.Get##darttype(i*scale));                     \
-    }                                                                         \
+#define TEST_TYPED_ARRAY(darttype, ctype)                                      \
+  {                                                                            \
+    StackZone zone(thread);                                                    \
+    const int kArrayLength = 127;                                              \
+    TypedData& array = TypedData::Handle(                                      \
+        TypedData::New(kTypedData##darttype##ArrayCid, kArrayLength));         \
+    intptr_t scale = array.ElementSizeInBytes();                               \
+    for (int i = 0; i < kArrayLength; i++) {                                   \
+      array.Set##darttype((i * scale), i);                                     \
+    }                                                                          \
+    uint8_t* buffer;                                                           \
+    MessageWriter writer(&buffer, &zone_allocator, true);                      \
+    writer.WriteMessage(array);                                                \
+    intptr_t buffer_len = writer.BytesWritten();                               \
+    MessageSnapshotReader reader(buffer, buffer_len, thread);                  \
+    TypedData& serialized_array = TypedData::Handle();                         \
+    serialized_array ^= reader.ReadObject();                                   \
+    for (int i = 0; i < kArrayLength; i++) {                                   \
+      EXPECT_EQ(static_cast<ctype>(i),                                         \
+                serialized_array.Get##darttype(i*scale));                      \
+    }                                                                          \
   }
 
 
-#define TEST_EXTERNAL_TYPED_ARRAY(darttype, ctype)                            \
-  {                                                                           \
-    StackZone zone(Thread::Current());                                       \
-    ctype data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };                         \
-    intptr_t length = ARRAY_SIZE(data);                                       \
-    ExternalTypedData& array = ExternalTypedData::Handle(                     \
-        ExternalTypedData::New(kExternalTypedData##darttype##ArrayCid,        \
-                               reinterpret_cast<uint8_t*>(data), length));    \
-    intptr_t scale = array.ElementSizeInBytes();                              \
-    uint8_t* buffer;                                                          \
-    MessageWriter writer(&buffer, &zone_allocator, true);                     \
-    writer.WriteMessage(array);                                               \
-    intptr_t buffer_len = writer.BytesWritten();                              \
-    MessageSnapshotReader reader(buffer, buffer_len,                          \
-                          Isolate::Current(),                                 \
-                          zone.GetZone());                                    \
-    TypedData& serialized_array = TypedData::Handle();                        \
-    serialized_array ^= reader.ReadObject();                                  \
-    for (int i = 0; i < length; i++) {                                        \
-      EXPECT_EQ(static_cast<ctype>(data[i]),                                  \
-                serialized_array.Get##darttype(i*scale));                     \
-    }                                                                         \
+#define TEST_EXTERNAL_TYPED_ARRAY(darttype, ctype)                             \
+  {                                                                            \
+    StackZone zone(thread);                                                    \
+    ctype data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };                          \
+    intptr_t length = ARRAY_SIZE(data);                                        \
+    ExternalTypedData& array = ExternalTypedData::Handle(                      \
+        ExternalTypedData::New(kExternalTypedData##darttype##ArrayCid,         \
+                               reinterpret_cast<uint8_t*>(data), length));     \
+    intptr_t scale = array.ElementSizeInBytes();                               \
+    uint8_t* buffer;                                                           \
+    MessageWriter writer(&buffer, &zone_allocator, true);                      \
+    writer.WriteMessage(array);                                                \
+    intptr_t buffer_len = writer.BytesWritten();                               \
+    MessageSnapshotReader reader(buffer, buffer_len, thread);                  \
+    TypedData& serialized_array = TypedData::Handle();                         \
+    serialized_array ^= reader.ReadObject();                                   \
+    for (int i = 0; i < length; i++) {                                         \
+      EXPECT_EQ(static_cast<ctype>(data[i]),                                   \
+                serialized_array.Get##darttype(i*scale));                      \
+    }                                                                          \
   }
 
 
@@ -856,8 +799,6 @@
 
 
 TEST_CASE(SerializeEmptyByteArray) {
-  StackZone zone(Thread::Current());
-
   // Write snapshot with object content.
   const int kTypedDataLength = 0;
   TypedData& typed_data = TypedData::Handle(
@@ -868,10 +809,7 @@
   intptr_t buffer_len = writer.BytesWritten();
 
   // Read object back from the snapshot.
-  MessageSnapshotReader reader(buffer,
-                               buffer_len,
-                               Isolate::Current(),
-                               zone.GetZone());
+  MessageSnapshotReader reader(buffer, buffer_len, thread);
   TypedData& serialized_typed_data = TypedData::Handle();
   serialized_typed_data ^= reader.ReadObject();
   EXPECT(serialized_typed_data.IsTypedData());
@@ -897,8 +835,10 @@
                        alloc,
                        kInitialSize,
                        &forward_list_,
+                       NULL, /* test_writer */
                        true, /* can_send_any_object */
-                       false /* snapshot_code */),
+                       false, /* snapshot_code */
+                       true /* vm_isolate_is_symbolic */),
         forward_list_(kMaxPredefinedObjectIds) {
     ASSERT(buffer != NULL);
     ASSERT(alloc != NULL);
@@ -1010,11 +950,8 @@
   writer.WriteScript(script);
 
   // Read object back from the snapshot.
-  ScriptSnapshotReader reader(buffer,
-                              writer.BytesWritten(),
-                              Isolate::Current(),
-                              Thread::Current()->zone());
-  Script& serialized_script = Script::Handle();
+  ScriptSnapshotReader reader(buffer, writer.BytesWritten(), thread);
+  Script& serialized_script = Script::Handle(thread->zone());
   serialized_script ^= reader.ReadObject();
 
   // Check if the serialized script object matches the original script.
@@ -1231,13 +1168,13 @@
   {
     TestIsolateScope __test_isolate__;
 
-    Isolate* isolate = Isolate::Current();
-    StackZone zone(isolate);
-    HandleScope scope(isolate);
+    Thread* thread = Thread::Current();
+    StackZone zone(thread);
+    HandleScope scope(thread);
 
     // Create a test library and Load up a test script in it.
     TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1245,8 +1182,10 @@
     {
       FullSnapshotWriter writer(NULL,
                                 &isolate_snapshot_buffer,
+                                NULL, /* instructions_snapshot_buffer */
                                 &malloc_allocator,
-                                false /* snapshot_code */);
+                                false, /* snapshot_code */
+                                true);
       writer.WriteFullSnapshot();
     }
   }
@@ -1290,13 +1229,13 @@
   {
     TestIsolateScope __test_isolate__;
 
-    Isolate* isolate = Isolate::Current();
-    StackZone zone(isolate);
-    HandleScope scope(isolate);
+    Thread* thread = Thread::Current();
+    StackZone zone(thread);
+    HandleScope scope(thread);
 
     // Create a test library and Load up a test script in it.
     Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
-    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(isolate));
+    EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
     timer1.Stop();
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
@@ -1304,8 +1243,10 @@
     {
       FullSnapshotWriter writer(NULL,
                                 &isolate_snapshot_buffer,
+                                NULL, /* instructions_snapshot_buffer */
                                 &malloc_allocator,
-                                false /* snapshot_code */);
+                                false, /* snapshot_code */
+                                true /* vm_isolate_is_symbolic */);
       writer.WriteFullSnapshot();
     }
 
@@ -1897,7 +1838,7 @@
   EXPECT(Dart_IsString(crappy_string_result));
 
   {
-    DARTSCOPE(isolate);
+    DARTSCOPE(Thread::Current());
 
     {
       StackZone zone(Thread::Current());
@@ -1981,16 +1922,16 @@
       "}\n";
 
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->isolate() != NULL);
   Dart_EnterScope();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(isolate);
-    StackZone zone(isolate);
+    DARTSCOPE(thread);
+    StackZone zone(thread);
     intptr_t buf_len = 0;
     {
       // Generate a list of nulls from Dart code.
@@ -2105,16 +2046,16 @@
       "}\n";
 
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->isolate() != NULL);
   Dart_EnterScope();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(isolate);
-    StackZone zone(isolate);
+    DARTSCOPE(thread);
+    StackZone zone(thread);
     intptr_t buf_len = 0;
     {
       // Generate a list of nulls from Dart code.
@@ -2344,16 +2285,16 @@
       "}\n";
 
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->isolate() != NULL);
   Dart_EnterScope();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(isolate);
-    StackZone zone(isolate);
+    DARTSCOPE(thread);
+    StackZone zone(thread);
     intptr_t buf_len = 0;
     {
       // Generate a list of strings from Dart code.
@@ -2569,16 +2510,16 @@
       "}\n";
 
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->isolate() != NULL);
   Dart_EnterScope();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(isolate);
-    StackZone zone(isolate);
+    DARTSCOPE(thread);
+    StackZone zone(thread);
     intptr_t buf_len = 0;
     {
       // Generate a list of strings from Dart code.
@@ -2810,16 +2751,16 @@
       "}\n";
 
   TestCase::CreateTestIsolate();
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate != NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->isolate() != NULL);
   Dart_EnterScope();
 
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(isolate);
-    StackZone zone(isolate);
+    DARTSCOPE(thread);
+    StackZone zone(thread);
     intptr_t buf_len = 0;
     {
       // Generate a list of Uint8Lists from Dart code.
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index 1c93003..eba3949 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -36,16 +36,15 @@
 
 // Test calls to stub code which calls into the runtime.
 static void GenerateCallToCallRuntimeStub(Assembler* assembler,
-                                          int value1, int value2) {
+                                          int length) {
   const int argc = 2;
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+  const Smi& smi_length = Smi::ZoneHandle(Smi::New(length));
   __ EnterDartFrame(0);
   __ PushObject(Object::null_object());  // Push Null obj for return value.
-  __ PushObject(smi1);  // Push argument 1 smi1.
-  __ PushObject(smi2);  // Push argument 2 smi2.
-  ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
-  __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
+  __ PushObject(smi_length);             // Push argument 1: length.
+  __ PushObject(Object::null_object());  // Push argument 2: type arguments.
+  ASSERT(kAllocateArrayRuntimeEntry.argument_count() == argc);
+  __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ add(SP, SP, Operand(argc * kWordSize));
   __ Pop(R0);  // Pop return value from return slot.
   __ LeaveDartFrame();
@@ -56,31 +55,33 @@
 TEST_CASE(CallRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const int length = 10;
   const char* kName = "Test_CallRuntimeStubCode";
   Assembler _assembler_;
-  GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
+  GenerateCallToCallRuntimeStub(&_assembler_, length);
   const Code& code = Code::Handle(Code::FinalizeCode(
       *CreateFunction("Test_CallRuntimeStubCode"), &_assembler_));
   const Function& function = RegisterFakeFunction(kName, code);
-  Smi& result = Smi::Handle();
+  Array& result = Array::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 - value2), result.Value());
+  EXPECT_EQ(length, result.Length());
 }
 
 
 // Test calls to stub code which calls into a leaf runtime entry.
 static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
-                                              int value1,
-                                              int value2) {
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+                                              const char* value1,
+                                              const char* value2) {
+  const Bigint& bigint1 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value1, Heap::kOld));
+  const Bigint& bigint2 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value2, Heap::kOld));
   __ EnterDartFrame(0);
   __ ReserveAlignedFrameSpace(0);
-  __ LoadObject(R0, smi1);  // Set up argument 1 smi1.
-  __ LoadObject(R1, smi2);  // Set up argument 2 smi2.
-  __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
+  __ LoadObject(R0, bigint1);  // Set up argument 1 bigint1.
+  __ LoadObject(R1, bigint2);  // Set up argument 2 bigint2.
+  __ CallRuntime(kBigintCompareRuntimeEntry, 2);
+  __ SmiTag(R0);
   __ LeaveDartFrame();
   __ ret();  // Return value is in R0.
 }
@@ -89,8 +90,8 @@
 TEST_CASE(CallLeafRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const char* value1 = "0xAAABBCCDDAABBCCDD";
+  const char* value2 = "0xAABBCCDDAABBCCDD";
   const char* kName = "Test_CallLeafRuntimeStubCode";
   Assembler _assembler_;
   GenerateCallToCallLeafRuntimeStub(&_assembler_, value1, value2);
@@ -99,7 +100,7 @@
   const Function& function = RegisterFakeFunction(kName, code);
   Smi& result = Smi::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 + value2), result.Value());
+  EXPECT_EQ(1, result.Value());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index ae1ce83..39aa9e6 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -36,16 +36,15 @@
 
 // Test calls to stub code which calls into the runtime.
 static void GenerateCallToCallRuntimeStub(Assembler* assembler,
-                                          int value1, int value2) {
+                                          int length) {
   const int argc = 2;
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+  const Smi& smi_length = Smi::ZoneHandle(Smi::New(length));
   __ EnterDartFrame(0);
   __ PushObject(Object::null_object());  // Push Null object for return value.
-  __ PushObject(smi1);  // Push argument 1 smi1.
-  __ PushObject(smi2);  // Push argument 2 smi2.
-  ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
-  __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
+  __ PushObject(smi_length);             // Push argument 1: length.
+  __ PushObject(Object::null_object());  // Push argument 2: type arguments.
+  ASSERT(kAllocateArrayRuntimeEntry.argument_count() == argc);
+  __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ AddImmediate(SP, argc * kWordSize);
   __ Pop(R0);  // Pop return value from return slot.
   __ LeaveDartFrame();
@@ -56,31 +55,33 @@
 TEST_CASE(CallRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const int length = 10;
   const char* kName = "Test_CallRuntimeStubCode";
   Assembler _assembler_;
-  GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
+  GenerateCallToCallRuntimeStub(&_assembler_, length);
   const Code& code = Code::Handle(Code::FinalizeCode(
       *CreateFunction("Test_CallRuntimeStubCode"), &_assembler_));
   const Function& function = RegisterFakeFunction(kName, code);
-  Smi& result = Smi::Handle();
+  Array& result = Array::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 - value2), result.Value());
+  EXPECT_EQ(length, result.Length());
 }
 
 
 // Test calls to stub code which calls into a leaf runtime entry.
 static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
-                                              int value1,
-                                              int value2) {
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+                                              const char* value1,
+                                              const char* value2) {
+  const Bigint& bigint1 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value1, Heap::kOld));
+  const Bigint& bigint2 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value2, Heap::kOld));
   __ EnterDartFrame(0);
   __ ReserveAlignedFrameSpace(0);
-  __ LoadObject(R0, smi1);  // Set up argument 1 smi1.
-  __ LoadObject(R1, smi2);  // Set up argument 2 smi2.
-  __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
+  __ LoadObject(R0, bigint1);  // Set up argument 1 bigint1.
+  __ LoadObject(R1, bigint2);  // Set up argument 2 bigint2.
+  __ CallRuntime(kBigintCompareRuntimeEntry, 2);
+  __ SmiTag(R0);
   __ LeaveDartFrame();
   __ Ret();  // Return value is in R0.
 }
@@ -89,8 +90,8 @@
 TEST_CASE(CallLeafRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const char* value1 = "0xAAABBCCDDAABBCCDD";
+  const char* value2 = "0xAABBCCDDAABBCCDD";
   const char* kName = "Test_CallLeafRuntimeStubCode";
   Assembler _assembler_;
   GenerateCallToCallLeafRuntimeStub(&_assembler_, value1, value2);
@@ -99,7 +100,7 @@
   const Function& function = RegisterFakeFunction(kName, code);
   Smi& result = Smi::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 + value2), result.Value());
+  EXPECT_EQ(1, result.Value());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 301259b..1ab200b 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -36,16 +36,15 @@
 
 // Test calls to stub code which calls into the runtime.
 static void GenerateCallToCallRuntimeStub(Assembler* assembler,
-                                          int value1, int value2) {
+                                          int length) {
   const int argc = 2;
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+  const Smi& smi_length = Smi::ZoneHandle(Smi::New(length));
   __ enter(Immediate(0));
   __ PushObject(Object::null_object());  // Push Null object for return value.
-  __ PushObject(smi1);  // Push argument 1 smi1.
-  __ PushObject(smi2);  // Push argument 2 smi2.
-  ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
-  __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
+  __ PushObject(smi_length);             // Push argument 1: length.
+  __ PushObject(Object::null_object());  // Push argument 2: type arguments.
+  ASSERT(kAllocateArrayRuntimeEntry.argument_count() == argc);
+  __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ AddImmediate(ESP, Immediate(argc * kWordSize));
   __ popl(EAX);  // Pop return value from return slot.
   __ leave();
@@ -56,33 +55,35 @@
 TEST_CASE(CallRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const int length = 10;
   const char* kName = "Test_CallRuntimeStubCode";
   Assembler _assembler_;
-  GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
+  GenerateCallToCallRuntimeStub(&_assembler_, length);
   const Code& code = Code::Handle(Code::FinalizeCode(
       *CreateFunction("Test_CallRuntimeStubCode"), &_assembler_));
   const Function& function = RegisterFakeFunction(kName, code);
-  Smi& result = Smi::Handle();
+  Array& result = Array::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 - value2), result.Value());
+  EXPECT_EQ(length, result.Length());
 }
 
 
 // Test calls to stub code which calls into a leaf runtime entry.
 static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
-                                              int value1,
-                                              int value2) {
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+                                              const char* value1,
+                                              const char* value2) {
+  const Bigint& bigint1 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value1, Heap::kOld));
+  const Bigint& bigint2 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value2, Heap::kOld));
   __ enter(Immediate(0));
   __ ReserveAlignedFrameSpace(2 * kWordSize);
-  __ LoadObject(EAX, smi1);
-  __ movl(Address(ESP, 0), EAX);  // Push argument 1 smi1.
-  __ LoadObject(EAX, smi2);
-  __ movl(Address(ESP, kWordSize), EAX);  // Push argument 2 smi2.
-  __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
+  __ LoadObject(EAX, bigint1);
+  __ movl(Address(ESP, 0), EAX);  // Push argument 1 bigint1.
+  __ LoadObject(EAX, bigint2);
+  __ movl(Address(ESP, kWordSize), EAX);  // Push argument 2 bigint2.
+  __ CallRuntime(kBigintCompareRuntimeEntry, 2);
+  __ SmiTag(EAX);
   __ leave();
   __ ret();  // Return value is in EAX.
 }
@@ -91,8 +92,8 @@
 TEST_CASE(CallLeafRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const char* value1 = "0xAAABBCCDDAABBCCDD";
+  const char* value2 = "0xAABBCCDDAABBCCDD";
   const char* kName = "Test_CallLeafRuntimeStubCode";
   Assembler _assembler_;
   GenerateCallToCallLeafRuntimeStub(&_assembler_, value1, value2);
@@ -101,7 +102,7 @@
   const Function& function = RegisterFakeFunction(kName, code);
   Smi& result = Smi::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 + value2), result.Value());
+  EXPECT_EQ(1, result.Value());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index c01edf5..512baaf 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -36,16 +36,15 @@
 
 // Test calls to stub code which calls into the runtime.
 static void GenerateCallToCallRuntimeStub(Assembler* assembler,
-                                          int value1, int value2) {
+                                          int length) {
   const int argc = 2;
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+  const Smi& smi_length = Smi::ZoneHandle(Smi::New(length));
   __ EnterDartFrame(0);
   __ PushObject(Object::null_object());  // Push Null object for return value.
-  __ PushObject(smi1);  // Push argument 1 smi1.
-  __ PushObject(smi2);  // Push argument 2 smi2.
-  ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
-  __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
+  __ PushObject(smi_length);             // Push argument 1: length.
+  __ PushObject(Object::null_object());  // Push argument 2: type arguments.
+  ASSERT(kAllocateArrayRuntimeEntry.argument_count() == argc);
+  __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ addiu(SP, SP, Immediate(argc * kWordSize));
   __ Pop(V0);  // Pop return value from return slot.
   __ LeaveDartFrameAndReturn();
@@ -55,31 +54,33 @@
 TEST_CASE(CallRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const int length = 10;
   const char* kName = "Test_CallRuntimeStubCode";
   Assembler _assembler_;
-  GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
+  GenerateCallToCallRuntimeStub(&_assembler_, length);
   const Code& code = Code::Handle(Code::FinalizeCode(
       *CreateFunction("Test_CallRuntimeStubCode"), &_assembler_));
   const Function& function = RegisterFakeFunction(kName, code);
-  Smi& result = Smi::Handle();
+  Array& result = Array::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 - value2), result.Value());
+  EXPECT_EQ(length, result.Length());
 }
 
 
 // Test calls to stub code which calls into a leaf runtime entry.
 static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
-                                              int value1,
-                                              int value2) {
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+                                              const char* value1,
+                                              const char* value2) {
+  const Bigint& bigint1 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value1, Heap::kOld));
+  const Bigint& bigint2 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value2, Heap::kOld));
   __ EnterDartFrame(0);
   __ ReserveAlignedFrameSpace(0);
-  __ LoadObject(A0, smi1);  // Set up argument 1 smi1.
-  __ LoadObject(A1, smi2);  // Set up argument 2 smi2.
-  __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
+  __ LoadObject(A0, bigint1);  // Set up argument 1 bigint1.
+  __ LoadObject(A1, bigint2);  // Set up argument 2 bigint2.
+  __ CallRuntime(kBigintCompareRuntimeEntry, 2);
+  __ SmiTag(V0);
   __ LeaveDartFrameAndReturn();  // Return value is in V0.
 }
 
@@ -87,8 +88,8 @@
 TEST_CASE(CallLeafRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const char* value1 = "0xAAABBCCDDAABBCCDD";
+  const char* value2 = "0xAABBCCDDAABBCCDD";
   const char* kName = "Test_CallLeafRuntimeStubCode";
   Assembler _assembler_;
   GenerateCallToCallLeafRuntimeStub(&_assembler_, value1, value2);
@@ -97,7 +98,7 @@
   const Function& function = RegisterFakeFunction(kName, code);
   Smi& result = Smi::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 + value2), result.Value());
+  EXPECT_EQ(1, result.Value());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index d3b94dc..ff020e7 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -36,16 +36,15 @@
 
 // Test calls to stub code which calls into the runtime.
 static void GenerateCallToCallRuntimeStub(Assembler* assembler,
-                                          int value1, int value2) {
+                                          int length) {
   const int argc = 2;
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+  const Smi& smi_length = Smi::ZoneHandle(Smi::New(length));
   __ EnterStubFrame();
   __ PushObject(Object::null_object());  // Push Null obj for return value.
-  __ PushObject(smi1);  // Push argument 1 smi1.
-  __ PushObject(smi2);  // Push argument 2 smi2.
-  ASSERT(kTestSmiSubRuntimeEntry.argument_count() == argc);
-  __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
+  __ PushObject(smi_length);             // Push argument 1: length.
+  __ PushObject(Object::null_object());  // Push argument 2: type arguments.
+  ASSERT(kAllocateArrayRuntimeEntry.argument_count() == argc);
+  __ CallRuntime(kAllocateArrayRuntimeEntry, argc);
   __ AddImmediate(RSP, Immediate(argc * kWordSize));
   __ popq(RAX);  // Pop return value from return slot.
   __ LeaveStubFrame();
@@ -56,31 +55,33 @@
 TEST_CASE(CallRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const int length = 10;
   const char* kName = "Test_CallRuntimeStubCode";
   Assembler _assembler_;
-  GenerateCallToCallRuntimeStub(&_assembler_, value1, value2);
+  GenerateCallToCallRuntimeStub(&_assembler_, length);
   const Code& code = Code::Handle(Code::FinalizeCode(
       *CreateFunction("Test_CallRuntimeStubCode"), &_assembler_));
   const Function& function = RegisterFakeFunction(kName, code);
-  Smi& result = Smi::Handle();
+  Array& result = Array::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 - value2), result.Value());
+  EXPECT_EQ(length, result.Length());
 }
 
 
 // Test calls to stub code which calls into a leaf runtime entry.
 static void GenerateCallToCallLeafRuntimeStub(Assembler* assembler,
-                                              int value1,
-                                              int value2) {
-  const Smi& smi1 = Smi::ZoneHandle(Smi::New(value1));
-  const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
+                                              const char* value1,
+                                              const char* value2) {
+  const Bigint& bigint1 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value1, Heap::kOld));
+  const Bigint& bigint2 =
+      Bigint::ZoneHandle(Bigint::NewFromCString(value2, Heap::kOld));
   __ EnterStubFrame();
   __ ReserveAlignedFrameSpace(0);
-  __ LoadObject(CallingConventions::kArg1Reg, smi1);
-  __ LoadObject(CallingConventions::kArg2Reg, smi2);
-  __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
+  __ LoadObject(CallingConventions::kArg1Reg, bigint1);
+  __ LoadObject(CallingConventions::kArg2Reg, bigint2);
+  __ CallRuntime(kBigintCompareRuntimeEntry, 2);
+  __ SmiTag(RAX);
   __ LeaveStubFrame();
   __ ret();  // Return value is in RAX.
 }
@@ -89,8 +90,8 @@
 TEST_CASE(CallLeafRuntimeStubCode) {
   extern const Function& RegisterFakeFunction(const char* name,
                                               const Code& code);
-  const int value1 = 10;
-  const int value2 = 20;
+  const char* value1 = "0xAAABBCCDDAABBCCDD";
+  const char* value2 = "0xAABBCCDDAABBCCDD";
   const char* kName = "Test_CallLeafRuntimeStubCode";
   Assembler _assembler_;
   GenerateCallToCallLeafRuntimeStub(&_assembler_, value1, value2);
@@ -99,7 +100,7 @@
   const Function& function = RegisterFakeFunction(kName, code);
   Smi& result = Smi::Handle();
   result ^= DartEntry::InvokeFunction(function, Object::empty_array());
-  EXPECT_EQ((value1 + value2), result.Value());
+  EXPECT_EQ(1, result.Value());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index be08181..c827704 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -394,30 +394,77 @@
 
 
 // TODO(srdjan): If this becomes performance critical code, consider looking
-// up symbol from pieces instead of concatenating them first into a big string.
+// up symbol from hash of pieces instead of concatenating them first into
+// a string.
 RawString* Symbols::FromConcatAll(
     const GrowableHandlePtrArray<const String>& strs) {
-  GrowableArray<const char*> cchars(strs.length());
-  GrowableArray<intptr_t> lengths(strs.length());
+  const intptr_t strs_length = strs.length();
+  GrowableArray<intptr_t> lengths(strs_length);
+
   intptr_t len_sum = 0;
-  for (intptr_t i = 0; i < strs.length(); i++) {
-    const char* to_cstr = strs[i].ToCString();
-    intptr_t len = strlen(to_cstr);
-    cchars.Add(to_cstr);
-    lengths.Add(len);
-    len_sum += len;
+  const intptr_t kOneByteChar = 1;
+  intptr_t char_size = kOneByteChar;
+
+  for (intptr_t i = 0; i < strs_length; i++) {
+    const String& str = strs[i];
+    const intptr_t str_len = str.Length();
+    if ((String::kMaxElements - len_sum) < str_len) {
+      Exceptions::ThrowOOM();
+      UNREACHABLE();
+    }
+    len_sum += str_len;
+    lengths.Add(str_len);
+    char_size = Utils::Maximum(char_size, str.CharSize());
   }
+  const bool is_one_byte_string = char_size == kOneByteChar;
 
   Zone* zone = Thread::Current()->zone();
-  char* buffer = zone->Alloc<char>(len_sum);
-  const char* const orig_buffer = buffer;
-  for (intptr_t i = 0; i < cchars.length(); i++) {
-    intptr_t len = lengths[i];
-    strncpy(buffer, cchars[i], len);
-    buffer += len;
+  if (is_one_byte_string) {
+    uint8_t* buffer = zone->Alloc<uint8_t>(len_sum);
+    const uint8_t* const orig_buffer = buffer;
+    for (intptr_t i = 0; i < strs_length; i++) {
+      NoSafepointScope no_safepoint;
+      intptr_t str_len = lengths[i];
+      if (str_len > 0) {
+        const String& str = strs[i];
+        ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
+        const uint8_t* src_p = str.IsOneByteString() ?
+            OneByteString::CharAddr(str, 0) :
+            ExternalOneByteString::CharAddr(str, 0);
+        memmove(buffer, src_p, str_len);
+        buffer += str_len;
+      }
+    }
+    ASSERT(len_sum == buffer - orig_buffer);
+    return Symbols::FromLatin1(orig_buffer, len_sum);
+  } else {
+    uint16_t* buffer = zone->Alloc<uint16_t>(len_sum);
+    const uint16_t* const orig_buffer = buffer;
+    for (intptr_t i = 0; i < strs_length; i++) {
+      NoSafepointScope no_safepoint;
+      intptr_t str_len = lengths[i];
+      if (str_len > 0) {
+        const String& str = strs[i];
+        if (str.IsTwoByteString()) {
+          memmove(buffer, TwoByteString::CharAddr(str, 0), str_len * 2);
+        } else if (str.IsExternalTwoByteString()) {
+          memmove(buffer, ExternalTwoByteString::CharAddr(str, 0), str_len * 2);
+        } else {
+          // One-byte to two-byte string copy.
+          ASSERT(str.IsOneByteString() || str.IsExternalOneByteString());
+          const uint8_t* src_p = str.IsOneByteString() ?
+              OneByteString::CharAddr(str, 0) :
+              ExternalOneByteString::CharAddr(str, 0);
+          for (int n = 0; n < str_len; n++) {
+            buffer[n] = src_p[n];
+          }
+        }
+        buffer += str_len;
+      }
+    }
+    ASSERT(len_sum == buffer - orig_buffer);
+    return Symbols::FromUTF16(orig_buffer, len_sum);
   }
-  ASSERT(len_sum == buffer - orig_buffer);
-  return Symbols::New(orig_buffer, len_sum);
 }
 
 
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 29682eb..f5f7bbf 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -115,6 +115,7 @@
   V(AsyncErrorWrapperHelper, "_asyncErrorWrapperHelper")                       \
   V(AsyncAwaitHelper, "_awaitHelper")                                          \
   V(Await, "await")                                                            \
+  V(AwaitTempVarPrefix, ":await_temp_var_")                                    \
   V(AwaitContextVar, ":await_ctx_var")                                         \
   V(AwaitJumpVar, ":await_jump_var")                                           \
   V(Future, "Future")                                                          \
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index a52c1bc..d0c4651 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -10,6 +10,7 @@
 #include "vm/object.h"
 #include "vm/os_thread.h"
 #include "vm/profiler.h"
+#include "vm/runtime_entry.h"
 #include "vm/stub_code.h"
 #include "vm/thread_interrupter.h"
 #include "vm/thread_registry.h"
@@ -108,10 +109,22 @@
       heap_(NULL),
       store_buffer_block_(NULL) {
   ClearState();
+
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
   member_name = default_init_value;
 CACHED_CONSTANTS_LIST(DEFAULT_INIT)
 #undef DEFAULT_INIT
+
+#define DEFAULT_INIT(name)                                                     \
+  name##_entry_point_ = 0;
+RUNTIME_ENTRY_LIST(DEFAULT_INIT)
+#undef DEFAULT_INIT
+
+#define DEFAULT_INIT(returntype, name, ...)                                    \
+  name##_entry_point_ = 0;
+LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT)
+#undef DEFAULT_INIT
+
   if (init_vm_constants) {
     InitVMConstants();
   }
@@ -130,6 +143,18 @@
   member_name = (init_expr);
 CACHED_CONSTANTS_LIST(INIT_VALUE)
 #undef INIT_VALUE
+
+#define INIT_VALUE(name)                                                       \
+  ASSERT(name##_entry_point_ == 0);                                            \
+  name##_entry_point_ = k##name##RuntimeEntry.GetEntryPoint();
+RUNTIME_ENTRY_LIST(INIT_VALUE)
+#undef INIT_VALUE
+
+#define INIT_VALUE(returntype, name, ...)                                      \
+  ASSERT(name##_entry_point_ == 0);                                            \
+  name##_entry_point_ = k##name##RuntimeEntry.GetEntryPoint();
+LEAF_RUNTIME_ENTRY_LIST(INIT_VALUE)
+#undef INIT_VALUE
 }
 
 
@@ -326,4 +351,23 @@
   return -1;
 }
 
+intptr_t Thread::OffsetFromThread(const RuntimeEntry* runtime_entry) {
+#define COMPUTE_OFFSET(name)                                                   \
+  if (runtime_entry->function() == k##name##RuntimeEntry.function())         { \
+    return Thread::name##_entry_point_offset();                                \
+  }
+RUNTIME_ENTRY_LIST(COMPUTE_OFFSET)
+#undef COMPUTE_OFFSET
+
+#define COMPUTE_OFFSET(returntype, name, ...)                                  \
+  if (runtime_entry->function() == k##name##RuntimeEntry.function())         { \
+    return Thread::name##_entry_point_offset();                                \
+  }
+LEAF_RUNTIME_ENTRY_LIST(COMPUTE_OFFSET)
+#undef COMPUTE_OFFSET
+
+  UNREACHABLE();
+  return -1;
+}
+
 }  // namespace dart
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 904d751..9643c33 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -8,6 +8,7 @@
 #include "vm/globals.h"
 #include "vm/os_thread.h"
 #include "vm/store_buffer.h"
+#include "vm/runtime_entry_list.h"
 
 namespace dart {
 
@@ -19,11 +20,11 @@
 class Object;
 class RawBool;
 class RawObject;
+class RuntimeEntry;
 class StackResource;
 class TimelineEventBlock;
 class Zone;
 
-
 // List of VM-global objects/addresses cached in each Thread object.
 #define CACHED_VM_OBJECTS_LIST(V)                                              \
   V(RawObject*, object_null_, Object::null(), NULL)                            \
@@ -32,11 +33,11 @@
 
 #define CACHED_ADDRESSES_LIST(V)                                               \
   V(uword, update_store_buffer_entry_point_,                                   \
-    StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)
+    StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0)                      \
 
 #define CACHED_CONSTANTS_LIST(V)                                               \
   CACHED_VM_OBJECTS_LIST(V)                                                    \
-  CACHED_ADDRESSES_LIST(V)
+  CACHED_ADDRESSES_LIST(V)                                                     \
 
 struct InterruptedThreadState {
   ThreadId tid;
@@ -226,8 +227,23 @@
 CACHED_CONSTANTS_LIST(DEFINE_OFFSET_METHOD)
 #undef DEFINE_OFFSET_METHOD
 
+#define DEFINE_OFFSET_METHOD(name)                                             \
+  static intptr_t name##_entry_point_offset() {                                \
+    return OFFSET_OF(Thread, name##_entry_point_);                             \
+  }
+RUNTIME_ENTRY_LIST(DEFINE_OFFSET_METHOD)
+#undef DEFINE_OFFSET_METHOD
+
+#define DEFINE_OFFSET_METHOD(returntype, name, ...)                            \
+  static intptr_t name##_entry_point_offset() {                                \
+    return OFFSET_OF(Thread, name##_entry_point_);                             \
+  }
+LEAF_RUNTIME_ENTRY_LIST(DEFINE_OFFSET_METHOD)
+#undef DEFINE_OFFSET_METHOD
+
   static bool CanLoadFromThread(const Object& object);
   static intptr_t OffsetFromThread(const Object& object);
+  static intptr_t OffsetFromThread(const RuntimeEntry* runtime_entry);
 
   TimelineEventBlock* timeline_block() const {
     return state_.timeline_block;
@@ -267,6 +283,16 @@
 CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
 #undef DECLARE_MEMBERS
 
+#define DECLARE_MEMBERS(name)      \
+  uword name##_entry_point_;
+RUNTIME_ENTRY_LIST(DECLARE_MEMBERS)
+#undef DECLARE_MEMBERS
+
+#define DECLARE_MEMBERS(returntype, name, ...)      \
+  uword name##_entry_point_;
+LEAF_RUNTIME_ENTRY_LIST(DECLARE_MEMBERS)
+#undef DECLARE_MEMBERS
+
   explicit Thread(bool init_vm_constants = true);
 
   void InitVMConstants();
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 560aa1c..545ed8a 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -385,7 +385,6 @@
 // organized by
 // - helpers.
 TEST_CASE(SafepointTestVM) {
-  Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   Mutex mutex;
   intptr_t expected_count = 0;
@@ -415,7 +414,6 @@
 // - main thread, and
 // - helpers.
 TEST_CASE(SafepointTestVM2) {
-  Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   Mutex mutex;
   intptr_t expected_count = 0;
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 6657e04..8cb358f 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -322,7 +322,6 @@
   TimelineTestHelper::FakeThreadEvent(block_2_0, 2, "E");
   TimelineTestHelper::FakeThreadEvent(block_2_0, 2, "F");
 
-  Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
 
@@ -440,7 +439,6 @@
 TEST_CASE(TimelinePauses_Basic) {
   TimelineEventEndlessRecorder* recorder = new TimelineEventEndlessRecorder();
   ASSERT(recorder != NULL);
-  Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   ThreadId tid = OSThread::GetCurrentThreadId();
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index c9c4812..1edeb15 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -30,7 +30,7 @@
 // The TEST_CASE macro is used for tests that need an isolate and zone
 // in order to test its functionality.
 #define TEST_CASE(name)                                                        \
-  static void Dart_TestHelper##name();                                         \
+  static void Dart_TestHelper##name(Thread* thread);                           \
   UNIT_TEST_CASE(name)                                                         \
   {                                                                            \
     TestIsolateScope __test_isolate__;                                         \
@@ -38,9 +38,9 @@
     ASSERT(__thread__->isolate() == __test_isolate__.isolate());               \
     StackZone __zone__(__thread__);                                            \
     HandleScope __hs__(__thread__);                                            \
-    Dart_TestHelper##name();                                                   \
+    Dart_TestHelper##name(__thread__);                                         \
   }                                                                            \
-  static void Dart_TestHelper##name()
+  static void Dart_TestHelper##name(Thread* thread)
 
 // The ASSEMBLER_TEST_GENERATE macro is used to generate a unit test
 // for the assembler.
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index e6902f8..6eb0056 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -377,11 +377,12 @@
     'ring_buffer.h',
     'ring_buffer_test.cc',
     'runtime_entry.h',
+    'runtime_entry_list.h',
     'runtime_entry_arm.cc',
     'runtime_entry_arm64.cc',
     'runtime_entry_ia32.cc',
     'runtime_entry_mips.cc',
-    'runtime_entry_test.cc',
+    'runtime_entry.cc',
     'runtime_entry_x64.cc',
     'scanner.cc',
     'scanner.h',
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 79591a5..4850e5e 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -178,13 +178,15 @@
  public:
   // Create an empty zone and set is at the current zone for the Thread.
   explicit StackZone(Thread* thread) : StackResource(thread), zone_() {
-    Initialize();
-  }
-
-  // DEPRECATED: Use Thread-based interface. During migration, this defaults
-  // to using the mutator thread (which must also be the current thread).
-  explicit StackZone(Isolate* isolate) : StackResource(isolate), zone_() {
-    Initialize();
+#ifdef DEBUG
+    if (FLAG_trace_zones) {
+      OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
+                   reinterpret_cast<intptr_t>(this),
+                   reinterpret_cast<intptr_t>(&zone_));
+    }
+#endif
+    zone_.Link(thread->zone());
+    thread->set_zone(&zone_);
   }
 
   // Delete all memory associated with the zone.
@@ -209,18 +211,6 @@
  private:
   Zone zone_;
 
-  void Initialize() {
-#ifdef DEBUG
-    if (FLAG_trace_zones) {
-      OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
-                   reinterpret_cast<intptr_t>(this),
-                   reinterpret_cast<intptr_t>(&zone_));
-    }
-#endif
-    zone_.Link(thread()->zone());
-    thread()->set_zone(&zone_);
-  }
-
   template<typename T> friend class GrowableArray;
   template<typename T> friend class ZoneGrowableArray;
 
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index 9c43743..dceddbf 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -18,11 +18,11 @@
 #endif
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate->current_zone() == NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->zone() == NULL);
   {
-    StackZone stack_zone(isolate);
-    EXPECT(isolate->current_zone() != NULL);
+    StackZone stack_zone(thread);
+    EXPECT(thread->zone() != NULL);
     Zone* zone = stack_zone.GetZone();
     intptr_t allocated_size = 0;
 
@@ -69,7 +69,7 @@
     allocated_size += (kSegmentSize + kWordSize);
     EXPECT_LE(allocated_size, zone->SizeInBytes());
   }
-  EXPECT(isolate->current_zone() == NULL);
+  EXPECT(thread->zone() == NULL);
   Dart_ShutdownIsolate();
 }
 
@@ -80,11 +80,11 @@
 #endif
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate->current_zone() == NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->zone() == NULL);
   {
-    StackZone zone(isolate);
-    EXPECT(isolate->current_zone() != NULL);
+    StackZone zone(thread);
+    EXPECT(thread->zone() != NULL);
     intptr_t allocated_size = 0;
 
     const intptr_t kNumElements = 1000;
@@ -92,7 +92,7 @@
     allocated_size += sizeof(uint32_t) * kNumElements;
     EXPECT_LE(allocated_size, zone.SizeInBytes());
   }
-  EXPECT(isolate->current_zone() == NULL);
+  EXPECT(thread->zone() == NULL);
   Dart_ShutdownIsolate();
 }
 
@@ -104,11 +104,11 @@
 #endif
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate->current_zone() == NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->zone() == NULL);
   {
-    StackZone zone(isolate);
-    EXPECT(isolate->current_zone() != NULL);
+    StackZone zone(thread);
+    EXPECT(thread->zone() != NULL);
 
     const intptr_t kNumElements = (kIntptrMax / sizeof(uint32_t)) + 1;
     zone.GetZone()->Alloc<uint32_t>(kNumElements);
@@ -123,8 +123,8 @@
 #endif
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
-  Isolate* isolate = Isolate::Current();
-  EXPECT(isolate->current_zone() == NULL);
+  Thread* thread = Thread::Current();
+  EXPECT(thread->zone() == NULL);
   static int marker;
 
   class SimpleZoneObject : public ZoneAllocated {
@@ -140,7 +140,7 @@
 
   // Create a few zone allocated objects.
   {
-    StackZone zone(isolate);
+    StackZone zone(thread);
     EXPECT_EQ(0, zone.SizeInBytes());
     SimpleZoneObject* first = new SimpleZoneObject();
     EXPECT(first != NULL);
@@ -160,7 +160,7 @@
     EXPECT_EQ(42, first->slot);
     EXPECT_EQ(87, second->slot);
   }
-  EXPECT(isolate->current_zone() == NULL);
+  EXPECT(thread->zone() == NULL);
   Dart_ShutdownIsolate();
 }
 
diff --git a/sdk/bin/dartdoc.bat b/sdk/bin/dartdoc.bat
index 58c2017..c313e7f 100644
--- a/sdk/bin/dartdoc.bat
+++ b/sdk/bin/dartdoc.bat
@@ -14,7 +14,7 @@
 set DART=%BIN_DIR%\dart
 set SNAPSHOT=%BIN_DIR%\snapshots\dartdoc.dart.snapshot
 
-"%DART%" --packages="$BIN_DIR/snapshots/resources/dartdoc/.packages" "%SNAPSHOT%" %*
+"%DART%" --packages="%BIN_DIR%/snapshots/resources/dartdoc/.packages" "%SNAPSHOT%" %*
 
 endlocal
 
diff --git a/site/try/poi/poi.dart b/site/try/poi/poi.dart
index d523f80..b9f7753 100644
--- a/site/try/poi/poi.dart
+++ b/site/try/poi/poi.dart
@@ -60,13 +60,17 @@
 import 'package:compiler/src/dart_types.dart' show
     DartType;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
+import 'package:compiler/src/parser/partial_elements.dart' show
+    PartialClassElement,
+    PartialElement;
+
+import 'package:compiler/src/tokens/token.dart' show
+    Token;
+
+import 'package:compiler/src/tokens/token_constants.dart' show
     EOF_TOKEN,
     IDENTIFIER_TOKEN,
-    KEYWORD_TOKEN,
-    PartialClassElement,
-    PartialElement,
-    Token;
+    KEYWORD_TOKEN;
 
 import 'package:compiler/src/js/js.dart' show
     js;
diff --git a/site/try/src/editor.dart b/site/try/src/editor.dart
index 1345404..abe3f3c 100644
--- a/site/try/src/editor.dart
+++ b/site/try/src/editor.dart
@@ -6,12 +6,16 @@
 
 import 'dart:html';
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
-    EOF_TOKEN,
+import 'package:compiler/src/scanner/string_scanner.dart' show
+    StringScanner;
+
+import 'package:compiler/src/tokens/token.dart' show
     ErrorToken,
-    StringScanner,
     Token;
 
+import 'package:compiler/src/tokens/token_constants.dart' show
+    EOF_TOKEN;
+
 import 'ui.dart' show
     currentTheme,
     hackDiv,
diff --git a/site/try/src/interaction_manager.dart b/site/try/src/interaction_manager.dart
index 2c566e3..89ddf76 100644
--- a/site/try/src/interaction_manager.dart
+++ b/site/try/src/interaction_manager.dart
@@ -21,18 +21,22 @@
 import 'dart:collection' show
     Queue;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
+import 'package:compiler/src/scanner/string_scanner.dart' show
+    StringScanner;
+
+import 'package:compiler/src/tokens/token.dart' show
     BeginGroupToken,
-    EOF_TOKEN,
     ErrorToken,
-    STRING_INTERPOLATION_IDENTIFIER_TOKEN,
-    STRING_INTERPOLATION_TOKEN,
-    STRING_TOKEN,
-    StringScanner,
     Token,
     UnmatchedToken,
     UnterminatedToken;
 
+import 'package:compiler/src/tokens/token_constants.dart' show
+    EOF_TOKEN,
+    STRING_INTERPOLATION_IDENTIFIER_TOKEN,
+    STRING_INTERPOLATION_TOKEN,
+    STRING_TOKEN;
+
 import 'package:compiler/src/io/source_file.dart' show
     StringSourceFile;
 
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 0d1832d..019e273 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -4,8 +4,8 @@
 
 [ $compiler == dart2js ]
 Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # Issue 1533 (int/double related)
-Language/03_Overview/1_Scoping_A02_t05: CompileTimeError # Issue 21072
-Language/03_Overview/1_Scoping_A02_t06: CompileTimeError # Issue 21072
+Language/03_Overview/1_Scoping_A02_t05: RuntimeError # co19 issue 3
+Language/03_Overview/1_Scoping_A02_t06: RuntimeError # co19 issue 3
 Language/03_Overview/1_Scoping_A02_t28: fail # Issue 21092 and co19 issue 713
 Language/05_Variables/05_Variables_A05_t01: fail # Issue 21093
 Language/05_Variables/05_Variables_A05_t02: fail # Issue 21093
@@ -26,9 +26,6 @@
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A13_t01: RuntimeError # compiler cancelled: cannot resolve type T
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A13_t01: RuntimeError, OK # co19 issue 258
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A20_t02: fail # Issue 13363
-Language/07_Classes/6_Constructors/2_Factories_A08_t02: fail # Issue 21202
-Language/07_Classes/6_Constructors/2_Factories_A10_t02: fail # Issue 21202
-Language/07_Classes/6_Constructors/2_Factories_A10_t03: fail # Issue 21202
 Language/10_Generics/09_Generics_A01_t17: fail # Issue 21203
 Language/12_Expressions/00_Object_Identity/1_Object_Identity_A02_t02: fail # Issue 11551, also related to issue 563, 18738
 Language/12_Expressions/00_Object_Identity/1_Object_Identity_A06_t01: fail # Issue 11551, also related to issue 563, 18738
@@ -36,11 +33,6 @@
 Language/12_Expressions/03_Numbers_A01_t06: fail # Issue 21098
 Language/12_Expressions/03_Numbers_A01_t09: fail # Issue 21098
 Language/12_Expressions/07_Maps_A11_t01: CompileTimeError # Maybe ok. Issue 17207
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t03: fail # Issue 21092 and co19 issue 713
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t05: fail # Issue 21092 and co19 issue 713
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t06: fail # Issue 21092 and co19 issue 713
-Language/12_Expressions/12_Instance_Creation/1_New_A02_t07: fail # Issue 21092 and co19 issue 713
-Language/12_Expressions/12_Instance_Creation/1_New_A06_t15: CompileTimeError # Issue 21092
 Language/12_Expressions/12_Instance_Creation/2_Const_A11_t01: fail # Issue 21134 and co19 issue 714
 Language/12_Expressions/12_Instance_Creation/2_Const_A11_t03: fail # Issue 21134 and co19 issue 714
 Language/12_Expressions/30_Identifier_Reference_A02_t01: fail # Issue 21154
diff --git a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
index 3ab7e86..801b75d 100644
--- a/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
+++ b/tests/compiler/dart2js/backend_dart/dart_printer_test.dart
@@ -13,7 +13,11 @@
 import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
 import 'package:compiler/src/diagnostics/messages.dart';
 import 'package:compiler/src/diagnostics/spannable.dart' show Spannable;
-import 'package:compiler/src/scanner/scannerlib.dart';
+import 'package:compiler/src/parser/listener.dart';
+import 'package:compiler/src/parser/parser.dart';
+import 'package:compiler/src/scanner/scanner.dart';
+import 'package:compiler/src/tokens/token.dart';
+import 'package:compiler/src/tokens/token_constants.dart';
 import 'package:compiler/src/io/source_file.dart';
 import 'package:compiler/src/string_validator.dart';
 import 'package:compiler/src/tree/tree.dart' show DartString;
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 30c61ac..70b8172 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -27,7 +27,7 @@
 import 'package:compiler/src/null_compiler_output.dart';
 import 'package:compiler/src/old_to_new_api.dart';
 import 'package:compiler/src/resolution/resolution.dart';
-import 'package:compiler/src/scanner/scannerlib.dart';
+import 'package:compiler/src/scanner/scanner_task.dart';
 
 class TestCompiler extends apiimpl.Compiler {
   final String testMarker;
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
index f5345c0..820be3e 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
@@ -20,10 +20,26 @@
 """,
 r"""
 function(x) {
-  var _box_0 = {};
+  P.print(J.getInterceptor$ns(x).$add(x, "1"));
+}"""),
+
+  const TestEntry("""
+main(x) {
+  a() {
+    return x;
+  }
+  x = x + '1';
+  print(a());
+  return a;
+}
+""",
+r"""
+function(x) {
+  var _box_0 = {}, a = new V.main_a(_box_0);
   _box_0._captured_x_0 = x;
   _box_0._captured_x_0 = J.getInterceptor$ns(x = _box_0._captured_x_0).$add(x, "1");
-  P.print(new V.main_a(_box_0).call$0());
+  P.print(a.call$0());
+  return a;
 }"""),
 
   const TestEntry("""
@@ -36,7 +52,23 @@
 """,
 r"""
 function(x) {
-  P.print(new V.main_a(x).call$0());
+  P.print(x);
+}"""),
+
+  const TestEntry("""
+main(x) {
+  a() {
+    return x;
+  }
+  print(a());
+  return a;
+}
+""",
+r"""
+function(x) {
+  var a = new V.main_a(x);
+  P.print(a.call$0());
+  return a;
 }"""),
 
   const TestEntry("""
@@ -49,10 +81,25 @@
 """,
 r"""
 function() {
-  var _box_0 = {};
+  P.print(122 + 1);
+}"""),
+
+  const TestEntry("""
+main() {
+  var x = 122;
+  var a = () => x;
+  x = x + 1;
+  print(a());
+  return a;
+}
+""",
+r"""
+function() {
+  var _box_0 = {}, a = new V.main_closure(_box_0);
   _box_0._captured_x_0 = 122;
   _box_0._captured_x_0 = _box_0._captured_x_0 + 1;
-  P.print(new V.main_closure(_box_0).call$0());
+  P.print(a.call$0());
+  return a;
 }"""),
 
   const TestEntry("""
@@ -68,10 +115,28 @@
 """,
 r"""
 function() {
-  var _box_0 = {};
+  P.print(122 + 1);
+}"""),
+
+  const TestEntry("""
+main() {
+  var x = 122;
+  var a = () {
+    var y = x;
+    return () => y;
+  };
+  x = x + 1;
+  print(a()());
+  return a;
+}
+""",
+r"""
+function() {
+  var _box_0 = {}, a = new V.main_closure(_box_0);
   _box_0._captured_x_0 = 122;
   _box_0._captured_x_0 = _box_0._captured_x_0 + 1;
-  P.print(new V.main_closure(_box_0).call$0().call$0());
+  P.print(a.call$0().call$0());
+  return a;
 }"""),
 
   const TestEntry("""
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
index 97de317..1665195 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_operators_test.dart
@@ -40,14 +40,14 @@
 main() { print(foo && foo); }
 """, """
 function() {
-  P.print(V.foo() ? V.foo() === true : false);
+  P.print(V.foo() ? !!V.foo() : false);
 }"""),
   const TestEntry("""
 get foo => foo;
 main() { print(foo || foo); }
 ""","""
 function() {
-  P.print(V.foo() ? true : V.foo() === true);
+  P.print(V.foo() ? true : !!V.foo());
 }"""),
 
 // Needs interceptor calling convention
diff --git a/tests/compiler/dart2js/lookup_map_test.dart b/tests/compiler/dart2js/lookup_map_test.dart
new file mode 100644
index 0000000..d73bc75
--- /dev/null
+++ b/tests/compiler/dart2js/lookup_map_test.dart
@@ -0,0 +1,261 @@
+// 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 tests.dart2js.lookup_map_test;
+
+import 'package:test/test.dart';
+import 'compiler_helper.dart';
+
+main() {
+  test('live entries are kept', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        const map = const LookupMap(const [
+            A, "the-text-for-A",
+        ]);
+        main() => print(map[A]);
+    """);
+    expect(generated, contains("the-text-for-A"));
+  });
+
+  test('live entries are kept - single-pair', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        const map = const LookupMap.pair(A, "the-text-for-A");
+        main() => print(map[A]);
+    """);
+    expect(generated, contains("the-text-for-A"));
+  });
+
+  test('unused entries are removed', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const map = const LookupMap(const [
+            A, "the-text-for-A",
+            B, "the-text-for-B",
+        ]);
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('unused entries are removed - nested maps', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const map = const LookupMap(const [], const [
+          const LookupMap(const [
+              A, "the-text-for-A",
+              B, "the-text-for-B",
+          ]),
+        ]);
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('unused entries are removed - single-pair', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const map = const LookupMap.pair(A, "the-text-for-A");
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('unused entries are removed - nested single-pair', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const map = const LookupMap(const [], const [
+          const LookupMap.pair(A, "the-text-for-A"),
+          const LookupMap.pair(B, "the-text-for-B"),
+        ]);
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('works if entries are declared separate from map', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const entries = const [
+            A, "the-text-for-A",
+            B, "the-text-for-B",
+        ];
+        const map = const LookupMap(entries);
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('escaping entries disable tree-shaking', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        const entries = const [
+            A, "the-text-for-A",
+            B, "the-text-for-B",
+        ];
+        const map = const LookupMap(entries);
+        main() {
+          entries.forEach(print);
+          print(map[A]);
+        }
+    """);
+    expect(generated, contains("the-text-for-B"));
+  });
+
+  test('uses include recursively reachable data', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        class C{}
+        class D{}
+        class E{}
+        const map = const LookupMap(const [
+            A, const ["the-text-for-A", B],
+            B, const ["the-text-for-B", C],
+            C, const ["the-text-for-C"],
+            D, const ["the-text-for-D", E],
+            E, const ["the-text-for-E"],
+        ]);
+        main() => print(map[map[A][1]]);
+    """);
+    expect(generated, contains("the-text-for-A"));
+    expect(generated, contains("the-text-for-B"));
+    expect(generated, contains("the-text-for-C"));
+    expect(generated, isNot(contains("the-text-for-D")));
+    expect(generated, isNot(contains("the-text-for-E")));
+  });
+
+  test('uses are found through newly discovered code', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{ A(B x);}
+        class B{}
+        class C{}
+        class D{}
+        class E{}
+        createA() => new A(map[B][1]());
+        createB() => new B();
+        const map = const LookupMap(const [
+            A, const ["the-text-for-A", createA],
+            B, const ["the-text-for-B", createB],
+            C, const ["the-text-for-C"],
+        ]);
+        main() => print(map[A][1]());
+    """);
+    expect(generated, contains("the-text-for-A"));
+    expect(generated, contains("the-text-for-B"));
+    expect(generated, isNot(contains("the-text-for-C")));
+  });
+
+  test('generic type allocations are considered used', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class M<T>{ get type => T; }
+        const map = const LookupMap(const [
+            A, "the-text-for-A",
+        ]);
+        main() => print(map[new M<A>().type]);
+    """);
+    expect(generated, contains("the-text-for-A"));
+  });
+
+  test('generics in type signatures are ignored', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        class M<T>{ get type => T; }
+        _factory(M<B> t) => t;
+        const map = const LookupMap(const [
+            A, const ["the-text-for-A", _factory],
+            B, "the-text-for-B",
+        ]);
+        main() => print(map[A]);
+    """);
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+
+  test('metadata is ignored', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{ const A(); }
+
+        @A()
+        class M {}
+        const map = const LookupMap(const [
+            A, "the-text-for-A",
+        ]);
+        main() => print(map[M]);
+    """);
+    expect(generated, isNot(contains("the-text-for-A")));
+  });
+
+  test('shared constants used in metadata are ignored', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        const annot = const B(foo: A);
+
+        @B(foo: annot)
+        class A{ const A(); }
+        class B{ final Type foo; const B({this.foo}); }
+
+        class M {}
+        const map = const LookupMap(const [
+            A, const ["the-text-for-A", annot]
+        ]);
+        main() => print(map[M]);
+    """);
+    expect(generated, isNot(contains("the-text-for-A")));
+  });
+
+  // regression test for a failure when looking up `dynamic` in a generic.
+  test('do not choke on dynamic types', () async {
+    await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class M<T>{ get type => T; }
+        const map = const LookupMap(const [
+            A, "the-text-for-A",
+        ]);
+        main() => print(map[new M<dynamic>().type]);
+    """);
+  });
+
+
+  test('support subclassing LookupMap', () async {
+    String generated = await compileAll(r"""
+        import 'package:lookup_map/lookup_map.dart';
+        class A{}
+        class B{}
+        class S extends LookupMap {
+          const S(list) : super(list);
+        }
+        const map = const S(const [
+            A, "the-text-for-A",
+            B, "the-text-for-B",
+        ]);
+
+        main() => print(map[A]);
+    """);
+    expect(generated, contains("the-text-for-A"));
+    expect(generated, isNot(contains("the-text-for-B")));
+  });
+}
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 847f469..b304b4f 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -7,7 +7,8 @@
     show PrimitiveConstantValue;
 import 'package:expect/expect.dart';
 import 'compiler_helper.dart';
-import 'parser_helper.dart';
+import 'package:compiler/src/parser/partial_elements.dart' show
+    PartialMetadataAnnotation;
 
 void checkPosition(Spannable spannable, Node node, String source, compiler) {
   SourceSpan span = compiler.spanFromSpannable(spannable);
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 2a9a39f..e185712 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -134,6 +134,8 @@
     }
     registerSource(Uris.dart_async,
                    buildLibrarySource(asyncLibrarySource));
+    registerSource(JavaScriptBackend.PACKAGE_LOOKUP_MAP,
+                   buildLibrarySource(DEFAULT_LOOKUP_MAP_LIBRARY));
   }
 
   String get patchVersion {
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index d70afdb..2031cf0 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -398,3 +398,19 @@
   'MirrorSystem': 'class MirrorSystem {}',
   'MirrorsUsed': 'class MirrorsUsed {}',
 };
+
+const Map<String, String> DEFAULT_LOOKUP_MAP_LIBRARY = const <String, String>{
+  'LookupMap': r'''
+  class LookupMap<T> {
+    final _key;
+    final _value;
+    final _entries;
+    final _nestedMaps;
+
+    const LookupMap(this._entries, [this._nestedMaps = const []])
+        : _key = null, _value = null;
+
+    const LookupMap.pair(this._key, this._value)
+        : _entries = const [], _nestedMaps = const [];
+  }''',
+};
diff --git a/tests/compiler/dart2js/parser_helper.dart b/tests/compiler/dart2js/parser_helper.dart
index c2d3bdf..da04e38 100644
--- a/tests/compiler/dart2js/parser_helper.dart
+++ b/tests/compiler/dart2js/parser_helper.dart
@@ -8,7 +8,13 @@
 
 import "package:compiler/src/elements/elements.dart";
 import "package:compiler/src/tree/tree.dart";
-import "package:compiler/src/scanner/scannerlib.dart";
+import "package:compiler/src/parser/element_listener.dart";
+import "package:compiler/src/parser/node_listener.dart";
+import "package:compiler/src/parser/parser.dart";
+import "package:compiler/src/parser/partial_parser.dart";
+import "package:compiler/src/scanner/string_scanner.dart";
+import "package:compiler/src/tokens/token.dart";
+import "package:compiler/src/tokens/token_constants.dart";
 import "package:compiler/src/io/source_file.dart";
 import "package:compiler/src/util/util.dart";
 
@@ -23,8 +29,13 @@
 import "package:compiler/src/script.dart";
 
 export "package:compiler/src/diagnostics/diagnostic_listener.dart";
-// TODO(ahe): We should have token library to export instead.
-export "package:compiler/src/scanner/scannerlib.dart";
+export 'package:compiler/src/parser/listener.dart';
+export 'package:compiler/src/parser/node_listener.dart';
+export 'package:compiler/src/parser/parser.dart';
+export 'package:compiler/src/parser/partial_parser.dart';
+export 'package:compiler/src/parser/partial_elements.dart';
+export "package:compiler/src/tokens/token.dart";
+export "package:compiler/src/tokens/token_constants.dart";
 
 class LoggerCanceler implements DiagnosticListener {
   void log(message) {
diff --git a/tests/compiler/dart2js/scanner_offset_length_test.dart b/tests/compiler/dart2js/scanner_offset_length_test.dart
index 4c428dd..3eb5bb5 100644
--- a/tests/compiler/dart2js/scanner_offset_length_test.dart
+++ b/tests/compiler/dart2js/scanner_offset_length_test.dart
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'package:compiler/src/scanner/scannerlib.dart';
+import 'package:compiler/src/scanner/string_scanner.dart';
+import 'package:compiler/src/tokens/token.dart';
+import 'package:compiler/src/tokens/token_constants.dart';
 
 Token scan(String text) =>
     new StringScanner.fromString(text, includeComments: true).tokenize();
diff --git a/tests/compiler/dart2js/scanner_test.dart b/tests/compiler/dart2js/scanner_test.dart
index e3a82fb..453ba42 100644
--- a/tests/compiler/dart2js/scanner_test.dart
+++ b/tests/compiler/dart2js/scanner_test.dart
@@ -3,7 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import 'package:compiler/src/scanner/scannerlib.dart';
+import 'package:compiler/src/scanner/utf8_bytes_scanner.dart';
+import 'package:compiler/src/tokens/precedence_constants.dart';
+import 'package:compiler/src/tokens/token.dart';
 import 'package:compiler/src/util/characters.dart';
 import 'dart:typed_data';
 
diff --git a/tests/compiler/dart2js/unparser2_test.dart b/tests/compiler/dart2js/unparser2_test.dart
index 00a3030..a4a8aed 100644
--- a/tests/compiler/dart2js/unparser2_test.dart
+++ b/tests/compiler/dart2js/unparser2_test.dart
@@ -3,7 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "package:expect/expect.dart";
-import "package:compiler/src/scanner/scannerlib.dart";
+import "package:compiler/src/parser/node_listener.dart";
+import "package:compiler/src/parser/parser.dart";
+import "package:compiler/src/scanner/string_scanner.dart";
+import "package:compiler/src/tokens/token.dart";
 import "package:compiler/src/tree/tree.dart";
 
 import "package:compiler/src/diagnostics/diagnostic_listener.dart";
diff --git a/tests/compiler/dart2js_extra/lookup_map/dead_entry_single_nested_pairs_test.dart b/tests/compiler/dart2js_extra/lookup_map/dead_entry_single_nested_pairs_test.dart
new file mode 100644
index 0000000..79446f2
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/dead_entry_single_nested_pairs_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+class B{}
+const map = const LookupMap(const [], const [
+    const LookupMap.pair(A, "the-text-for-A"),
+    const LookupMap.pair(B, "the-text-for-B"),
+]);
+
+main() {
+  Expect.equals(map[A], "the-text-for-A");
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/dead_entry_test.dart b/tests/compiler/dart2js_extra/lookup_map/dead_entry_test.dart
new file mode 100644
index 0000000..c5fb956
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/dead_entry_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+class B{}
+const map = const LookupMap(const [
+    A, "the-text-for-A",
+    B, "the-text-for-B",
+]);
+
+main() {
+  Expect.equals(map[A], "the-text-for-A");
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/discovered_code_test.dart b/tests/compiler/dart2js_extra/lookup_map/discovered_code_test.dart
new file mode 100644
index 0000000..a20af73
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/discovered_code_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+
+class A{ A(B x);}
+class B{}
+class C{}
+class D{}
+class E{}
+createA() => new A(map[B][1]());
+createB() => new B();
+const map = const LookupMap(const [
+    A, const ["the-text-for-A", createA],
+    B, const ["the-text-for-B", createB],
+    C, const ["the-text-for-C"],
+]);
+
+main() {
+  Expect.isTrue(map[A][1]() is A);
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/entries_aside_test.dart b/tests/compiler/dart2js_extra/lookup_map/entries_aside_test.dart
new file mode 100644
index 0000000..6f72418
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/entries_aside_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+
+class A{}
+class B{}
+const entries = const [
+  A, "the-text-for-A",
+  B, "the-text-for-B",
+];
+const map = const LookupMap(entries );
+
+main() {
+  Expect.equals(map[A], 'the-text-for-A');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/escaping_entries_test.dart b/tests/compiler/dart2js_extra/lookup_map/escaping_entries_test.dart
new file mode 100644
index 0000000..30fa3d3
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/escaping_entries_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+class B{}
+const entries = const [
+  A, "the-text-for-A",
+  B, "the-text-for-B",
+];
+const map = const LookupMap(entries);
+main() {
+  entries.forEach(print);
+  Expect.equals(map[A], 'the-text-for-A');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/generic_type_test.dart b/tests/compiler/dart2js_extra/lookup_map/generic_type_test.dart
new file mode 100644
index 0000000..1a2fd6e
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/generic_type_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+
+class A{}
+class M<T>{ get type => T; }
+const map = const LookupMap(const [
+    A, 'the-text-for-A',
+]);
+
+main() {
+  Expect.equals(map[new M<A>().type], 'the-text-for-A');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/live_entry_single_pair_test.dart b/tests/compiler/dart2js_extra/lookup_map/live_entry_single_pair_test.dart
new file mode 100644
index 0000000..2954e23
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/live_entry_single_pair_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+const map = const LookupMap.pair(A, "the-text-for-A");
+main() {
+  Expect.equals(map[A], 'the-text-for-A');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/live_entry_test.dart b/tests/compiler/dart2js_extra/lookup_map/live_entry_test.dart
new file mode 100644
index 0000000..aa835a8
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/live_entry_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+const map = const LookupMap(const [
+    A, "the-text-for-A",
+]);
+main() {
+  Expect.equals(map[A], 'the-text-for-A');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/reachable_data_test.dart b/tests/compiler/dart2js_extra/lookup_map/reachable_data_test.dart
new file mode 100644
index 0000000..8e71ea7
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/reachable_data_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+
+class A{}
+class B{}
+class C{}
+class D{}
+class E{}
+const map = const LookupMap(const [
+    A, const ["the-text-for-A", B],
+    B, const ["the-text-for-B", C],
+    C, const ["the-text-for-C"],
+    D, const ["the-text-for-D", E],
+    E, const ["the-text-for-E"],
+]);
+main() {
+  Expect.equals(map[map[A][1]][0], 'the-text-for-B');
+}
diff --git a/tests/compiler/dart2js_extra/lookup_map/subclass_lookup_map_test.dart b/tests/compiler/dart2js_extra/lookup_map/subclass_lookup_map_test.dart
new file mode 100644
index 0000000..ebf7416
--- /dev/null
+++ b/tests/compiler/dart2js_extra/lookup_map/subclass_lookup_map_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:lookup_map/lookup_map.dart';
+import 'package:expect/expect.dart';
+class A{}
+class B{}
+class S extends LookupMap {
+  const S(list) : super(list);
+}
+const map = const S(const [
+    A, "the-text-for-A",
+    B, "the-text-for-B",
+]);
+
+main() {
+  Expect.equals(map[A], "the-text-for-A");
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 704bd09..092e399 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -83,7 +83,7 @@
 # and only looks at the first 20 significant digits.
 # The Dart VM and the other ECMAScript implementations follow the correct
 # IEEE-754 rounding algorithm.
-double_parse_test: Fail, OK
+double_parse_test/02: Fail, OK
 
 [ $runtime == safari || $runtime == safarimobilesim ]
 double_round3_test: Fail, OK # Runtime rounds 0.49999999999999994 to 1.
diff --git a/tests/corelib/double_parse_test.dart b/tests/corelib/double_parse_test.dart
index 5fb6e76..6f7e8fb 100644
--- a/tests/corelib/double_parse_test.dart
+++ b/tests/corelib/double_parse_test.dart
@@ -232,26 +232,26 @@
             "4555072551893136908362547791869486679949683240497058210285131854"
             "51396213837722826145437693412532098591327667236328125",
             0.0);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000024703282292062327208828439643411068627545332140664243314532"
-            "8041234170109088178685677591650492652607243027730579814636067699"
-            "1112238669661707327453443265068702897439863329200619332642599205"
-            "1806252781222000513169502627641523911022607448403553068808609405"
-            "1727798181294290864842608522062097649849550765341204993205100587"
-            "2127469658709242016690593998242808606978027857019419997429604579"
-            "7572623273334010723772922131119806567715298322567005234345331218"
-            "5169920860031716486480793611343761679481328431956040281530986197"
-            "8304604971452253283193290744072288902141724247846767401941767720"
-            "8561650585989659548591956327689896895290365125294085321852619688"
-            "9863888974446146846024033780172178553364579041996676675092137151"
-            "9705456298034409473812692774776868254618683783877327369245051207"
-            "5931578479504396230612962142122846982018227555473696607567828620"
-            "5497859173707553281928994692862033843994140625",
-            5e-324);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000024703282292062327208828439643411068627545332140664243314532" /// 03: ok
+            "8041234170109088178685677591650492652607243027730579814636067699" /// 03: ok
+            "1112238669661707327453443265068702897439863329200619332642599205" /// 03: ok
+            "1806252781222000513169502627641523911022607448403553068808609405" /// 03: ok
+            "1727798181294290864842608522062097649849550765341204993205100587" /// 03: ok
+            "2127469658709242016690593998242808606978027857019419997429604579" /// 03: ok
+            "7572623273334010723772922131119806567715298322567005234345331218" /// 03: ok
+            "5169920860031716486480793611343761679481328431956040281530986197" /// 03: ok
+            "8304604971452253283193290744072288902141724247846767401941767720" /// 03: ok
+            "8561650585989659548591956327689896895290365125294085321852619688" /// 03: ok
+            "9863888974446146846024033780172178553364579041996676675092137151" /// 03: ok
+            "9705456298034409473812692774776868254618683783877327369245051207" /// 03: ok
+            "5931578479504396230612962142122846982018227555473696607567828620" /// 03: ok
+            "5497859173707553281928994692862033843994140625",                  /// 03: ok
+            5e-324);                                                           /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -368,44 +368,44 @@
             "8136843040991207538774075715754306035963544889052606784864342758"
             "900428165258489343614201061427593231201171875",
             5e-324);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000074109846876186981626485318930233205854758970392148714663837"
-            "8523751013260905313127797949754542453988569694847043168576596389"
-            "9850655339096945981621940161728171894510697854671067917687257517"
-            "7347315553307795408549809608457500958111373034747658096871009590"
-            "9754422710047573078097111189357848386756539987835030152280559340"
-            "4659373979179073872386829939581848166016912201945649993128979841"
-            "1362062484498678713572180352209017023903285791732520220528974020"
-            "8029068540216066123755499834026713000358124864790413857434018755"
-            "2090159017259254714629617513415977493871857473787096164563890871"
-            "8119841271673056017045493004705269590165763776884908267986972573"
-            "3665217655679410725087643375608460039849049721491174630855395563"
-            "54188641513168478436313080237596295773983001708984375",
-            1e-323);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000074109846876186981626485318930233205873343654412044724850344"
-            "8923718677971811461747287833219166123210675953743507352131000861"
-            "5508029119022396648780866584046796426383292609958261304514284249"
-            "6061610746879932829188941791435548141415672575056325503240888674"
-            "0040403932604439422384254107243478095284614859960753370503720954"
-            "5808063977144841990843464643012899935961693114687389992568869106"
-            "5599267374834247685403237712975952143398358575711517208866987110"
-            "6349531233468788347546753834029761025748698485508885182206645314"
-            "0639262948657591471263120659283236968907400986955900192071499065"
-            "6496581595870337769532410323614883653969318176216473399700896902"
-            "4282850500785430600410615352213843786678841324490411560469406158"
-            "4550533979841101562169154890806946368370134291387467238490102415"
-            "1863156959008792461225924284245693964036455110947393215135657241"
-            "099571834741510656385798938572406768798828125",
-            1e-323);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000074109846876186981626485318930233205854758970392148714663837" /// 02: ok
+            "8523751013260905313127797949754542453988569694847043168576596389" /// 02: ok
+            "9850655339096945981621940161728171894510697854671067917687257517" /// 02: ok
+            "7347315553307795408549809608457500958111373034747658096871009590" /// 02: ok
+            "9754422710047573078097111189357848386756539987835030152280559340" /// 02: ok
+            "4659373979179073872386829939581848166016912201945649993128979841" /// 02: ok
+            "1362062484498678713572180352209017023903285791732520220528974020" /// 02: ok
+            "8029068540216066123755499834026713000358124864790413857434018755" /// 02: ok
+            "2090159017259254714629617513415977493871857473787096164563890871" /// 02: ok
+            "8119841271673056017045493004705269590165763776884908267986972573" /// 02: ok
+            "3665217655679410725087643375608460039849049721491174630855395563" /// 02: ok
+            "54188641513168478436313080237596295773983001708984375",           /// 02: ok
+            1e-323);                                                           /// 02: ok
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000074109846876186981626485318930233205873343654412044724850344" /// 03: ok
+            "8923718677971811461747287833219166123210675953743507352131000861" /// 03: ok
+            "5508029119022396648780866584046796426383292609958261304514284249" /// 03: ok
+            "6061610746879932829188941791435548141415672575056325503240888674" /// 03: ok
+            "0040403932604439422384254107243478095284614859960753370503720954" /// 03: ok
+            "5808063977144841990843464643012899935961693114687389992568869106" /// 03: ok
+            "5599267374834247685403237712975952143398358575711517208866987110" /// 03: ok
+            "6349531233468788347546753834029761025748698485508885182206645314" /// 03: ok
+            "0639262948657591471263120659283236968907400986955900192071499065" /// 03: ok
+            "6496581595870337769532410323614883653969318176216473399700896902" /// 03: ok
+            "4282850500785430600410615352213843786678841324490411560469406158" /// 03: ok
+            "4550533979841101562169154890806946368370134291387467238490102415" /// 03: ok
+            "1863156959008792461225924284245693964036455110947393215135657241" /// 03: ok
+            "099571834741510656385798938572406768798828125",                   /// 03: ok
+            1e-323);                                                           /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -482,26 +482,26 @@
             "0239620254961370692713747131027132020441991845959370908649389667"
             "01396213837722826145437693412532098591327667236328125",
             1.1125369292536007e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000011125369292"
-            "5360093857793927928947412039400442434185228365340521456608629527"
-            "0200315929606120759250932815416474352736201659755028987189999989"
-            "3220987486513026766686796443888026815774211444057134206415720396"
-            "3510525564718487986029401249963455450110781777556316353975973978"
-            "4825173851725161436876623857879887229903814003929524302244972629"
-            "6795040225381805100879491255387164751912585073962051947893527710"
-            "5170790163081944841764003984818943810636714040207972316616704045"
-            "0220895038833513659790739432367709097880422198053807344762226099"
-            "3129277744388529754345873069706690065083079768940685222309466301"
-            "4235389404255004774284573740536646273496781023858510820692328908"
-            "0857253100067390568036719107632515767271783448958607838263400261"
-            "9271291212296536333081616208300526650104600844121842238490102415"
-            "1863156959008792461225924284245693964036455110947393215135657241"
-            "099571834741510656385798938572406768798828125",
-            1.112536929253601e-308);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000011125369292" /// 03: ok
+            "5360093857793927928947412039400442434185228365340521456608629527" /// 03: ok
+            "0200315929606120759250932815416474352736201659755028987189999989" /// 03: ok
+            "3220987486513026766686796443888026815774211444057134206415720396" /// 03: ok
+            "3510525564718487986029401249963455450110781777556316353975973978" /// 03: ok
+            "4825173851725161436876623857879887229903814003929524302244972629" /// 03: ok
+            "6795040225381805100879491255387164751912585073962051947893527710" /// 03: ok
+            "5170790163081944841764003984818943810636714040207972316616704045" /// 03: ok
+            "0220895038833513659790739432367709097880422198053807344762226099" /// 03: ok
+            "3129277744388529754345873069706690065083079768940685222309466301" /// 03: ok
+            "4235389404255004774284573740536646273496781023858510820692328908" /// 03: ok
+            "0857253100067390568036719107632515767271783448958607838263400261" /// 03: ok
+            "9271291212296536333081616208300526650104600844121842238490102415" /// 03: ok
+            "1863156959008792461225924284245693964036455110947393215135657241" /// 03: ok
+            "099571834741510656385798938572406768798828125",                   /// 03: ok
+            1.112536929253601e-308);                                           /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -560,44 +560,44 @@
             "8136843040991207538774075715754306035963544889052606784864342758"
             "900428165258489343614201061427593231201171875",
             1.112536929253601e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000011125369292"
-            "5360143264358512053601829696279729256322446286636762993074885578"
-            "5482848940402484819383308231788212319506475197423260249353326444"
-            "4130717265985540087275830129388183546908748591883986098046865342"
-            "9694440740018214171090142139290408905547397593746087678853434622"
-            "7708807769200010477987555066232823112546765790360487852208850575"
-            "8752599546868752897347409845010678425979078962517411943872958339"
-            "1841626929078828345647733525524686707077165117383988808631340302"
-            "3919811372391502185169818655049136406061931820528945258278945377"
-            "2640279824496362807465448266116748919295441238296611971177785355"
-            "4605209927839760366494651758097211936470402475783551200969719627"
-            "9349765358747644509438842714766105380341358326953487329219653376"
-            "04188641513168478436313080237596295773983001708984375",
-            1.1125369292536017e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000011125369292"
-            "5360143264358512053601829696279729256322464871320782889085072085"
-            "5882816605113390968002798115252835988728581456319724432907730915"
-            "9788091045910990754434756551706808078781343347171179484873892074"
-            "8408735933590351591729274322268456088851697134054755085223313705"
-            "7994788991756876822274697984118452821074840662486211070432012189"
-            "9901289544834521015804044548441730195923859875259151943312847604"
-            "6078831819414397317478790886291621826572237901362985796969353392"
-            "2240274065644224408961072655052184431452505441247416583051571936"
-            "1189383755894699564098951411984008394330984751465415998685393549"
-            "2981950252037042118981569077006826000273956875115116332683643956"
-            "9967398203853664384761814691371489127171149929952724258833663970"
-            "9550533979841101562169154890806946368370134291387467238490102415"
-            "1863156959008792461225924284245693964036455110947393215135657241"
-            "099571834741510656385798938572406768798828125",
-            1.1125369292536017e-308);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 02: ok
+            "0000000000000000000000000000000000000000000000000000011125369292" /// 02: ok
+            "5360143264358512053601829696279729256322446286636762993074885578" /// 02: ok
+            "5482848940402484819383308231788212319506475197423260249353326444" /// 02: ok
+            "4130717265985540087275830129388183546908748591883986098046865342" /// 02: ok
+            "9694440740018214171090142139290408905547397593746087678853434622" /// 02: ok
+            "7708807769200010477987555066232823112546765790360487852208850575" /// 02: ok
+            "8752599546868752897347409845010678425979078962517411943872958339" /// 02: ok
+            "1841626929078828345647733525524686707077165117383988808631340302" /// 02: ok
+            "3919811372391502185169818655049136406061931820528945258278945377" /// 02: ok
+            "2640279824496362807465448266116748919295441238296611971177785355" /// 02: ok
+            "4605209927839760366494651758097211936470402475783551200969719627" /// 02: ok
+            "9349765358747644509438842714766105380341358326953487329219653376" /// 02: ok
+            "04188641513168478436313080237596295773983001708984375",           /// 02: ok
+            1.1125369292536017e-308);                                          /// 02: ok
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000011125369292" /// 03: ok
+            "5360143264358512053601829696279729256322464871320782889085072085" /// 03: ok
+            "5882816605113390968002798115252835988728581456319724432907730915" /// 03: ok
+            "9788091045910990754434756551706808078781343347171179484873892074" /// 03: ok
+            "8408735933590351591729274322268456088851697134054755085223313705" /// 03: ok
+            "7994788991756876822274697984118452821074840662486211070432012189" /// 03: ok
+            "9901289544834521015804044548441730195923859875259151943312847604" /// 03: ok
+            "6078831819414397317478790886291621826572237901362985796969353392" /// 03: ok
+            "2240274065644224408961072655052184431452505441247416583051571936" /// 03: ok
+            "1189383755894699564098951411984008394330984751465415998685393549" /// 03: ok
+            "2981950252037042118981569077006826000273956875115116332683643956" /// 03: ok
+            "9967398203853664384761814691371489127171149929952724258833663970" /// 03: ok
+            "9550533979841101562169154890806946368370134291387467238490102415" /// 03: ok
+            "1863156959008792461225924284245693964036455110947393215135657241" /// 03: ok
+            "099571834741510656385798938572406768798828125",                   /// 03: ok
+            1.1125369292536017e-308);                                          /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -673,26 +673,26 @@
             "5924167958029604477064946470184777360934300451421683607013647479"
             "51396213837722826145437693412532098591327667236328125",
             2.2250738585072014e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000022250738585"
-            "0720163012305563795567615250361241457301819893006892300968851267"
-            "7159413856747700265506443097450144218254107162331246067966730043"
-            "7501049413401620872340686411548038468172262181270052386775328221"
-            "5857650751428906748569733780796363397546806336554745935958399010"
-            "2779558910877598836767067734754861955694039806454982002173263865"
-            "0888265793071484125840071160815995011874751834533813898637506208"
-            "5650354607662094473839557158134613493810593365859440904719070326"
-            "6111637871008949721205058253390132503584229153792338745607152721"
-            "3679398551625637847181703822407461490506663533450201028923360785"
-            "0720758060421709123733732493928588619801419722757153753675075962"
-            "6541800803135624352387918446790161107764092054420920536627658074"
-            "4271291212296536333081616208300526650104600844121842238490102415"
-            "1863156959008792461225924284245693964036455110947393215135657241"
-            "099571834741510656385798938572406768798828125",
-            2.225073858507202e-308);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000022250738585" /// 03: ok
+            "0720163012305563795567615250361241457301819893006892300968851267" /// 03: ok
+            "7159413856747700265506443097450144218254107162331246067966730043" /// 03: ok
+            "7501049413401620872340686411548038468172262181270052386775328221" /// 03: ok
+            "5857650751428906748569733780796363397546806336554745935958399010" /// 03: ok
+            "2779558910877598836767067734754861955694039806454982002173263865" /// 03: ok
+            "0888265793071484125840071160815995011874751834533813898637506208" /// 03: ok
+            "5650354607662094473839557158134613493810593365859440904719070326" /// 03: ok
+            "6111637871008949721205058253390132503584229153792338745607152721" /// 03: ok
+            "3679398551625637847181703822407461490506663533450201028923360785" /// 03: ok
+            "0720758060421709123733732493928588619801419722757153753675075962" /// 03: ok
+            "6541800803135624352387918446790161107764092054420920536627658074" /// 03: ok
+            "4271291212296536333081616208300526650104600844121842238490102415" /// 03: ok
+            "1863156959008792461225924284245693964036455110947393215135657241" /// 03: ok
+            "099571834741510656385798938572406768798828125",                   /// 03: ok
+            2.225073858507202e-308);                                           /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -751,44 +751,44 @@
             "8136843040991207538774075715754306035963544889052606784864342758"
             "900428165258489343614201061427593231201171875",
             2.225073858507202e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000022250738585"
-            "0720212418870147920222032907240528279439037814303133837435107319"
-            "2441946867544064325638818513821882185024380699999477330130056498"
-            "8410779192874134192929720097048195199306799329096904278406473168"
-            "2041565926728632933630474670123316852983422152744517260835859654"
-            "5663192828352447877877998943107797838336991592885945552137141811"
-            "2845825114558431922307989750439508685941245723089173894616936837"
-            "2321191373658977977723286698840356390251044443035457396733706583"
-            "9810554204566938246584137476071559811765738776267476659123871999"
-            "3190400631733470900301279018817520344719025002806127777791679839"
-            "1090578584006464715943810511489154282775041174682194133952466682"
-            "5034313061815878293790042053923750720833666932415800027583911188"
-            "54188641513168478436313080237596295773983001708984375",
-            2.2250738585072024e-308);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000022250738585"
-            "0720212418870147920222032907240528279439056398987153733445293826"
-            "2841914532254970474258308397286505854246486958895941513684460970"
-            "4068152972799584860088646519366819731179394084384097665233499900"
-            "0755861120300770354269606853101364036287721693053184667205738737"
-            "5949174050909314222165141860993427546865066465011668770360303425"
-            "3994515112524200040764624453870560455886026635830913894056826102"
-            "6558396263994546949554344059607291509746117227014454385071719673"
-            "8131016897819660470375391476074607837156312396985947983896498558"
-            "1739504563131807656934782164684779819754568515974931805299288032"
-            "9467318908203746468430727830398768346578595574013759265666391011"
-            "5651945906921898169113014030529134467663458535415036957197921783"
-            "4550533979841101562169154890806946368370134291387467238490102415"
-            "1863156959008792461225924284245693964036455110947393215135657241"
-            "099571834741510656385798938572406768798828125",
-            2.2250738585072024e-308);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000022250738585" /// 03: ok
+            "0720212418870147920222032907240528279439037814303133837435107319" /// 03: ok
+            "2441946867544064325638818513821882185024380699999477330130056498" /// 03: ok
+            "8410779192874134192929720097048195199306799329096904278406473168" /// 03: ok
+            "2041565926728632933630474670123316852983422152744517260835859654" /// 03: ok
+            "5663192828352447877877998943107797838336991592885945552137141811" /// 03: ok
+            "2845825114558431922307989750439508685941245723089173894616936837" /// 03: ok
+            "2321191373658977977723286698840356390251044443035457396733706583" /// 03: ok
+            "9810554204566938246584137476071559811765738776267476659123871999" /// 03: ok
+            "3190400631733470900301279018817520344719025002806127777791679839" /// 03: ok
+            "1090578584006464715943810511489154282775041174682194133952466682" /// 03: ok
+            "5034313061815878293790042053923750720833666932415800027583911188" /// 03: ok
+            "54188641513168478436313080237596295773983001708984375",           /// 03: ok
+            2.2250738585072024e-308);                                          /// 03: ok
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000022250738585" /// 03: ok
+            "0720212418870147920222032907240528279439056398987153733445293826" /// 03: ok
+            "2841914532254970474258308397286505854246486958895941513684460970" /// 03: ok
+            "4068152972799584860088646519366819731179394084384097665233499900" /// 03: ok
+            "0755861120300770354269606853101364036287721693053184667205738737" /// 03: ok
+            "5949174050909314222165141860993427546865066465011668770360303425" /// 03: ok
+            "3994515112524200040764624453870560455886026635830913894056826102" /// 03: ok
+            "6558396263994546949554344059607291509746117227014454385071719673" /// 03: ok
+            "8131016897819660470375391476074607837156312396985947983896498558" /// 03: ok
+            "1739504563131807656934782164684779819754568515974931805299288032" /// 03: ok
+            "9467318908203746468430727830398768346578595574013759265666391011" /// 03: ok
+            "5651945906921898169113014030529134467663458535415036957197921783" /// 03: ok
+            "4550533979841101562169154890806946368370134291387467238490102415" /// 03: ok
+            "1863156959008792461225924284245693964036455110947393215135657241" /// 03: ok
+            "099571834741510656385798938572406768798828125",                   /// 03: ok
+            2.2250738585072024e-308);                                          /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -862,25 +862,25 @@
             "8909645359318233784351199339157645340492308605462312698364257812"
             "5",
             1.0020841800044864e-292);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000100208418000448650025174695"
-            "1035150178458809017822159251011531515138151971877843746285762442"
-            "8545112214057342269294258292239779301929355259416640067909319649"
-            "7365336576866690449490575153391617964764463657240626936945707789"
-            "0322677840073401894046998179185686691822730198820493814317137229"
-            "5822164306994752582767555905533610628109411569344063803273395309"
-            "4016739578124191615155910675820643598048478728683293279406596985"
-            "3795142966229399885915374796852136102192598807080147602085351627"
-            "7462738186176388661491270541112149644974737467220377156516124492"
-            "5297987696655648150350049348782647584189423429523649017245633309"
-            "0650703736050481424426844685046761507858235356421727632283550512"
-            "9294184882356332903145058239310065886479547694117011957754993659"
-            "5152049332041520812604025151794328168042160636342216519487980314"
-            "421878240614097350935640662328296457417309284210205078125",
-            1.0020841800044866e-292);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000100208418000448650025174695" /// 03: ok
+            "1035150178458809017822159251011531515138151971877843746285762442" /// 03: ok
+            "8545112214057342269294258292239779301929355259416640067909319649" /// 03: ok
+            "7365336576866690449490575153391617964764463657240626936945707789" /// 03: ok
+            "0322677840073401894046998179185686691822730198820493814317137229" /// 03: ok
+            "5822164306994752582767555905533610628109411569344063803273395309" /// 03: ok
+            "4016739578124191615155910675820643598048478728683293279406596985" /// 03: ok
+            "3795142966229399885915374796852136102192598807080147602085351627" /// 03: ok
+            "7462738186176388661491270541112149644974737467220377156516124492" /// 03: ok
+            "5297987696655648150350049348782647584189423429523649017245633309" /// 03: ok
+            "0650703736050481424426844685046761507858235356421727632283550512" /// 03: ok
+            "9294184882356332903145058239310065886479547694117011957754993659" /// 03: ok
+            "5152049332041520812604025151794328168042160636342216519487980314" /// 03: ok
+            "421878240614097350935640662328296457417309284210205078125",       /// 03: ok
+            1.0020841800044866e-292);                                          /// 03: ok
   testParse("0.00000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
             "0000000000000000000000000000000000000000000000000000000000000000"
@@ -936,43 +936,43 @@
             "4847950667958479187395974848205671831957839363657783480512019685"
             "578121759385902649064359337671703542582690715789794921875",
             2.0041683600089726e-292);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000200416836000897266674241512"
-            "5990092893382710435783708701744713907322363070003179054747514262"
-            "7385611700512865061525449421701203817286652851291627374287240329"
-            "3753705169156289950978164746871212513772283206234057202629821353"
-            "8809538439162226010550634208659737749820025430842192660178060615"
-            "3474267718174236120090795958487048484027109406716660005865875254"
-            "7540730218997620056025234843183240653494745917236268600971966054"
-            "2572750817920844689872038240532666937066187074066929436725783508"
-            "0513647350599865639683590212819431367049178252060735656411044144"
-            "5314088186163138416702979387974756763836546863081940712096908853"
-            "9929165937080868658779320353585122361868059050079309936626251244"
-            "0765647609431766215648800660842354659507691394537687301635742187"
-            "5",
-            2.004168360008973e-292);
-  testParse("0.00000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000000000000000000000000000000"
-            "0000000000000000000000000000000000000200416836000897266674241512"
-            "5990092893382710435783708785442689934124446215379877007119186963"
-            "1799271173601405540673717580039876412295823431198128133887844732"
-            "7822096271111944266498822575337206743053529154538278267721206728"
-            "1206759279588886755511816487266193645578706075743945771432529989"
-            "5627720577353214542977288069464672781437627568914207256313896083"
-            "6647266336088483105727658239269018534852601546443784653776612265"
-            "4362171708319597782738064157144965045964873355636409438294693959"
-            "3883447613213167389211587415988230219943616159642947883454256631"
-            "7129850578881555219447792913718868827972321214300345663373246010"
-            "5887233720340859229642766731751409169335306833113418201122555553"
-            "1150187132469865334442659560994775205494930483192386561026478034"
-            "5152049332041520812604025151794328168042160636342216519487980314"
-            "421878240614097350935640662328296457417309284210205078125",
-            2.004168360008973e-292);
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000200416836000897266674241512" /// 03: ok
+            "5990092893382710435783708701744713907322363070003179054747514262" /// 03: ok
+            "7385611700512865061525449421701203817286652851291627374287240329" /// 03: ok
+            "3753705169156289950978164746871212513772283206234057202629821353" /// 03: ok
+            "8809538439162226010550634208659737749820025430842192660178060615" /// 03: ok
+            "3474267718174236120090795958487048484027109406716660005865875254" /// 03: ok
+            "7540730218997620056025234843183240653494745917236268600971966054" /// 03: ok
+            "2572750817920844689872038240532666937066187074066929436725783508" /// 03: ok
+            "0513647350599865639683590212819431367049178252060735656411044144" /// 03: ok
+            "5314088186163138416702979387974756763836546863081940712096908853" /// 03: ok
+            "9929165937080868658779320353585122361868059050079309936626251244" /// 03: ok
+            "0765647609431766215648800660842354659507691394537687301635742187" /// 03: ok
+            "5",                                                               /// 03: ok
+            2.004168360008973e-292);                                           /// 03: ok
+  testParse("0.00000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000000000000000000000000000000" /// 03: ok
+            "0000000000000000000000000000000000000200416836000897266674241512" /// 03: ok
+            "5990092893382710435783708785442689934124446215379877007119186963" /// 03: ok
+            "1799271173601405540673717580039876412295823431198128133887844732" /// 03: ok
+            "7822096271111944266498822575337206743053529154538278267721206728" /// 03: ok
+            "1206759279588886755511816487266193645578706075743945771432529989" /// 03: ok
+            "5627720577353214542977288069464672781437627568914207256313896083" /// 03: ok
+            "6647266336088483105727658239269018534852601546443784653776612265" /// 03: ok
+            "4362171708319597782738064157144965045964873355636409438294693959" /// 03: ok
+            "3883447613213167389211587415988230219943616159642947883454256631" /// 03: ok
+            "7129850578881555219447792913718868827972321214300345663373246010" /// 03: ok
+            "5887233720340859229642766731751409169335306833113418201122555553" /// 03: ok
+            "1150187132469865334442659560994775205494930483192386561026478034" /// 03: ok
+            "5152049332041520812604025151794328168042160636342216519487980314" /// 03: ok
+            "421878240614097350935640662328296457417309284210205078125",       /// 03: ok
+            2.004168360008973e-292);                                           /// 03: ok
   testParse("0.99999999999999988897769753748434595763683319091796875",
             0.9999999999999999);
   testParse("0.99999999999999988897769753748434595763683319091796879176194859"
@@ -983,12 +983,12 @@
             "4809443029054117700758095643512548748358614094344726684993771234"
             "576088145773464788135242997668683528900146484375",
             0.9999999999999999);
-  testParse("0.999999999999999944488848768742172978818416595458984375",
-            1.0);
-  testParse("0.99999999999999994448884876874217297881841659545898441676194859"
-            "5190556970945882299241904356487451251641385905655273315006228765"
-            "423911854226535211864757002331316471099853515625",
-            1.0);
+  testParse("0.999999999999999944488848768742172978818416595458984375", /// 03: ok
+            1.0);                                                       /// 03: ok
+  testParse("0.99999999999999994448884876874217297881841659545898441676194859" /// 03: ok
+            "5190556970945882299241904356487451251641385905655273315006228765" /// 03: ok
+            "423911854226535211864757002331316471099853515625",                /// 03: ok
+            1.0);                                                              /// 03: ok
   testParse("0.499999999999999944488848768742172978818416595458984375",
             0.49999999999999994);
   testParse("0.49999999999999994448884876874217297881841659545898439588097429"
@@ -999,12 +999,12 @@
             "2404721514527058850379047821756274374179307047172363342496885617"
             "2880440728867323940676214988343417644500732421875",
             0.49999999999999994);
-  testParse("0.4999999999999999722444243843710864894092082977294921875",
-            0.5);
-  testParse("0.49999999999999997224442438437108648940920829772949220838097429"
-            "7595278485472941149620952178243725625820692952827636657503114382"
-            "7119559271132676059323785011656582355499267578125",
-            0.5);
+  testParse("0.4999999999999999722444243843710864894092082977294921875", /// 03: ok
+            0.5);                                                        /// 03: ok
+  testParse("0.49999999999999997224442438437108648940920829772949220838097429" /// 03: ok
+            "7595278485472941149620952178243725625820692952827636657503114382" /// 03: ok
+            "7119559271132676059323785011656582355499267578125",               /// 03: ok
+            0.5);                                                              /// 03: ok
   testParse("1.9999999999999997779553950749686919152736663818359375",
             1.9999999999999998);
   testParse("1.99999999999999977795539507496869191527366638183593758352389719"
@@ -1015,12 +1015,12 @@
             "9618886058108235401516191287025097496717228188689453369987542469"
             "15217629154692957627048599533736705780029296875",
             1.9999999999999998);
-  testParse("1.99999999999999988897769753748434595763683319091796875",
-            2.0);
-  testParse("1.99999999999999988897769753748434595763683319091796883352389719"
-            "0381113941891764598483808712974902503282771811310546630012457530"
-            "84782370845307042372951400466263294219970703125",
-            2.0);
+  testParse("1.99999999999999988897769753748434595763683319091796875", /// 03: ok
+            2.0);                                                      /// 03: ok
+  testParse("1.99999999999999988897769753748434595763683319091796883352389719" /// 03: ok
+            "0381113941891764598483808712974902503282771811310546630012457530" /// 03: ok
+            "84782370845307042372951400466263294219970703125",                 /// 03: ok
+            2.0);                                                              /// 03: ok
   testParse("4503599627370495.5",
             4503599627370495.5);
   testParse("4503599627370495.50000000000000000000000000000000000018807909613"
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 03eba0f..05eec1c 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -36,7 +36,6 @@
 stacktrace_test: Pass, RuntimeError # # Issue 12698
 stacktrace_rethrow_nonerror_test: Pass, RuntimeError # Issue 12698
 stacktrace_rethrow_error_test: Pass, RuntimeError # Issue 12698
-instantiate_type_variable_test/01: CompileTimeError # Issue 13631
 type_variable_conflict_test/01: Fail # Issue 13702
 type_variable_conflict_test/02: Fail # Issue 13702
 type_variable_conflict_test/03: Fail # Issue 13702
@@ -146,12 +145,9 @@
 integer_division_by_zero_test: RuntimeError # Issue 8301
 built_in_identifier_prefix_test: CompileTimeError # Issue 6972
 number_identity2_test: RuntimeError # Issue 12596
-new_expression_type_args_test/00: CompileTimeError # Issue 5519
-new_expression_type_args_test/01: CompileTimeError # Issue 5519
 double_int_to_string_test: RuntimeError # Issue 1533
 mint_arithmetic_test: RuntimeError # Issue 1533
 left_shift_test: RuntimeError # Issue 1533
-factory_redirection_test/01: CompileTimeError # Issue 12752
 bad_override_test/01: CompileTimeError # Issue 11496
 bad_override_test/02: CompileTimeError # Issue 11496
 constructor_named_arguments_test/01: CompileTimeError # Issue 5519
@@ -292,7 +288,6 @@
 await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
 await_future_test: RuntimeError # Please triage this failure.
 await_regression_test: RuntimeError # Please triage this failure.
-await_test: RuntimeError # $async$temp1.S is not a function
 cha_deopt1_test: Crash # (d.make_u()): deferred access is not implemented
 cha_deopt2_test: Crash # (d.make_u()): deferred access is not implemented
 cha_deopt3_test: Crash # (d.make_u()): deferred access is not implemented
diff --git a/tests/try/poi/apply_updates_test.dart b/tests/try/poi/apply_updates_test.dart
index 6fc3428..361ee03 100644
--- a/tests/try/poi/apply_updates_test.dart
+++ b/tests/try/poi/apply_updates_test.dart
@@ -11,7 +11,7 @@
     LibraryUpdater,
     Update;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
+import 'package:compiler/src/parser/partial_elements.dart' show
     PartialFunctionElement;
 
 import 'package:compiler/src/script.dart' show
diff --git a/tests/try/poi/forget_element_test.dart b/tests/try/poi/forget_element_test.dart
index e1ebd3b..22b61ce 100644
--- a/tests/try/poi/forget_element_test.dart
+++ b/tests/try/poi/forget_element_test.dart
@@ -20,7 +20,7 @@
 
 import 'package:compiler/src/tree/tree.dart' as tree;
 
-import 'package:compiler/src/scanner/scannerlib.dart' show
+import 'package:compiler/src/parser/partial_elements.dart' show
     PartialMetadataAnnotation;
 
 import 'package:compiler/src/elements/visitor.dart' show
diff --git a/tools/VERSION b/tools/VERSION
index aeb856f..5ef9ccf 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 13
 PATCH 0
-PRERELEASE 0
+PRERELEASE 1
 PRERELEASE_PATCH 0
diff --git a/tools/create_tarball.py b/tools/create_tarball.py
index f51e4bb..462bd9d 100755
--- a/tools/create_tarball.py
+++ b/tools/create_tarball.py
@@ -41,6 +41,7 @@
 
 # Ignore Git/SVN files, checked-in binaries, backup files, etc..
 ignoredPaths = ['tools/testing/bin',
+                'tools/sdks',
                 'third_party/7zip', 'third_party/android_tools',
                 'third_party/clang', 'third_party/d8',
                 'third_party/firefox_jsshell']
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 38f937d5..b79b1dc 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -238,8 +238,24 @@
     "--no_resume",
     "--bucket",
     "dart-dependencies",
-    "-d",
-    "-r",
+    "--recursive",
+    "--directory",
     "src/dart/tools/testing/bin",
   ],
 })
+hooks.append({
+  "name": "checked_in_dart_sdks",
+  "pattern": ".",
+  "action": [
+    "download_from_google_storage",
+    "--no_auth",
+    "--no_resume",
+    "--bucket",
+    "dart-dependencies",
+    "--recursive",
+    "--auto_platform",
+    "--extract",
+    "--directory",
+    "src/dart/tools/sdks",
+  ],
+})
diff --git a/tools/precompilation/create_instructions_snapshot_assembly.dart b/tools/precompilation/create_instructions_snapshot_assembly.dart
new file mode 100644
index 0000000..98cccb2
--- /dev/null
+++ b/tools/precompilation/create_instructions_snapshot_assembly.dart
@@ -0,0 +1,21 @@
+import 'dart:io';
+
+void main(List<String> args) {
+  print(args[0]);
+  print(args[1]);
+
+  var bytes = new File(args[0]).readAsBytesSync();
+  print(bytes.length);
+
+  var out = new StringBuffer();
+  out.writeln(".text");
+  out.writeln("  .globl _kInstructionsSnapshot");
+  out.writeln("_kInstructionsSnapshot:");
+  out.writeln("  .balign 32, 0");
+  for (var i = 0; i < bytes.length; i++) {
+    var byte = bytes[i];
+    out.writeln("  .byte $byte");
+  }
+
+  new File(args[1]).writeAsString(out.toString());
+}
diff --git a/tools/precompilation/test_linux.sh b/tools/precompilation/test_linux.sh
new file mode 100755
index 0000000..14f7fa4
--- /dev/null
+++ b/tools/precompilation/test_linux.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -ex
+
+# Usage:
+#   cd sdk
+#   ./tools/precompilation/test_linux.sh
+
+./tools/build.py -mdebug -ax64 runtime
+
+./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot ~/hello.dart
+
+./out/DebugX64/dart ./tools/precompilation/create_instructions_snapshot_assembly.dart precompiled.instructions precompiled.S
+
+gcc -m64 -c -o precompiled.o precompiled.S
+
+gcc -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.o
+
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_macos.sh b/tools/precompilation/test_macos.sh
new file mode 100755
index 0000000..a233004
--- /dev/null
+++ b/tools/precompilation/test_macos.sh
@@ -0,0 +1,15 @@
+#!/bin/bash -ex
+
+# Usage:
+#   cd sdk
+#   ./tools/precompilation/test_macos.sh
+
+./tools/build.py -mdebug -ax64 runtime
+
+./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot ~/hello.dart
+
+./xcodebuild/DebugX64/dart ./tools/precompilation/create_instructions_snapshot_assembly.dart precompiled.instructions precompiled.S
+
+clang -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
+
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart --run-precompiled-snapshot not_used.dart
diff --git a/tools/sdks/.gitignore b/tools/sdks/.gitignore
new file mode 100644
index 0000000..2610d85
--- /dev/null
+++ b/tools/sdks/.gitignore
@@ -0,0 +1,6 @@
+/linux/dart-sdk
+/linux/dart-sdk.tar.gz
+/win/dart-sdk
+/win/dart-sdk.tar.gz
+/mac/dart-sdk
+/mac/dart-sdk.tar.gz
diff --git a/tools/sdks/README b/tools/sdks/README
new file mode 100644
index 0000000..f1f1fd3
--- /dev/null
+++ b/tools/sdks/README
@@ -0,0 +1,20 @@
+This directory contains the hashes of tar.gz files uploaded to cloud storage.
+Hooks in the DEPS files run "download_from_google_storage" to download these
+tarfiles, and unpack them.  These tar files contain a stable Dart SDK, which
+is used to build the observatory and to run the test scripts.
+
+The hooks use the --auto-platform feature, so that only the SDK for the
+current platform (linux, macos, or windows) is downloaded.  This requires
+the subdirectories to have the special names "linux", "win", and "mac", which
+the download script is hardcoded to recognize.
+
+The linux SDK has had two extra dart executables added to the bin directory.
+'dart-mips' and 'dart-arm' are executables compiled to run on mips and arm
+processors, respectively.
+
+To upload new versions of these tar files, use the "upload_to_google_storage"
+tool in depot_tools, and download the new stable SDKs from the dartlang.org
+web page.  The mips and arm executables must be copied from the machines that
+build them, and stripped.  There should be no need to update these tar files
+for every new stable version of Dart.
+
diff --git a/tools/sdks/linux/dart-sdk.tar.gz.sha1 b/tools/sdks/linux/dart-sdk.tar.gz.sha1
new file mode 100644
index 0000000..b9db509
--- /dev/null
+++ b/tools/sdks/linux/dart-sdk.tar.gz.sha1
@@ -0,0 +1 @@
+e525a9271e840f53382edfab773ad330384d8caa
\ 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
new file mode 100644
index 0000000..d88e4ae
--- /dev/null
+++ b/tools/sdks/mac/dart-sdk.tar.gz.sha1
@@ -0,0 +1 @@
+b80cd51c9fe293de25273102de5b2721aacc8aba
\ 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
new file mode 100644
index 0000000..97a2743
--- /dev/null
+++ b/tools/sdks/win/dart-sdk.tar.gz.sha1
@@ -0,0 +1 @@
+e098625fb19d40c9554f88e3306987c2c5988963
\ No newline at end of file