Version 1.12.0-dev.2.0

Merge commit '0590f7e630152f5b5265a8101016456c0da71a69' into dev
diff --git a/.gitattributes b/.gitattributes
index f9b1135..d77d09b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -23,7 +23,6 @@
 tests/lib/mirrors/method_mirror_source_line_ending_lf.dart -text
 tests/lib/mirrors/method_mirror_source_test.dart -text
 tests/lib/mirrors/method_mirror_source_other.dart -text
-pkg/js_ast/test/printer_callback_test.dart -text
 
 # Files to leave alone and not diff.
 *.png binary
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 884a584..164dd2c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,11 @@
     `setInnerHtml` or other methods that create DOM from text. It is
     also more efficient, skipping the creation of a `DocumentFragment`.
 
+* `dart:io`
+  * Added two new file modes, `WRITE_ONLY` and `WRITE_ONLY_APPEND` for
+    opening a file write only.
+    [eaeecf2](https://github.com/dart-lang/sdk/commit/eaeecf2ed13ba6c7fbfd653c3c592974a7120960)
+
 ### Tool changes
 
 * Pub
@@ -53,7 +58,7 @@
   * List iterators may not throw `ConcurrentModificationError` as eagerly in
     release mode. In checked mode, the modification check is still as eager
     as possible.
-    [r45198](https://code.google.com/p/dart/source/detail?r=45198)
+    [r45198](https://github.com/dart-lang/sdk/commit/5a79c03)
 
 * `dart:developer` - **NEW**
   * Replaces the deprecated `dart:profiler` library.
@@ -102,9 +107,9 @@
   * **POTENTIALLY BREAKING** Fix behavior of `HtmlEscape`. It no longer escapes
   no-break space (U+00A0) anywhere or forward slash (`/`, `U+002F`) in element
   context. Slash is still escaped using `HtmlEscapeMode.UNKNOWN`.
-  [r45003](https://code.google.com/p/dart/source/detail?r=45003),
-  [r45153](https://code.google.com/p/dart/source/detail?r=45153),
-  [r45189](https://code.google.com/p/dart/source/detail?r=45189)
+  [r45003](https://github.com/dart-lang/sdk/commit/8b8223d),
+  [r45153](https://github.com/dart-lang/sdk/commit/8a5d049),
+  [r45189](https://github.com/dart-lang/sdk/commit/3c39ad2)
 
 * `dart:core`
   * `Uri.parse` added `start` and `end` positional arguments.
diff --git a/DEPS b/DEPS
index 321d387..ef0d4fa 100644
--- a/DEPS
+++ b/DEPS
@@ -40,6 +40,7 @@
   "7zip_rev" : "@19997",
   "analyzer_cli_rev" : "@8bf3516dd645ca289d7ebc641f7c228d5b3d37c4",
   "args_tag": "@0.13.0",
+  "async_tag": "@1.2.0",
   "barback_rev" : "@29ee90dbcf77cfd64632fa2797a4c8a4f29a4b51",
   "charcode_tag": "@1.1.0",
   "chrome_rev" : "@19997",
@@ -50,7 +51,7 @@
   "csslib_tag" : "@0.12.0",
   "dartdoc_rev" : "@9f677ec40f9beeb8933374885ef3af4c63d35d25",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
-  "dart_style_tag": "@0.1.8",
+  "dart_style_tag": "@0.1.8+1",
   "dev_compiler_rev": "@0.1.1",
   "fake_async_rev" : "@38614",
   "firefox_jsshell_rev" : "@45554",
@@ -82,23 +83,24 @@
   "petitparser_rev" : "@37878",
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "plugin_tag": "@0.1.0",
-  "pool_rev": "@22e12aeb16ad0b626900dbe79e4a25391ddfb28c",
-  "pub_rev": "@0c02113cc761ec5f142a8c41ff277505fafa5e10",
+  "pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
+  "pub_rev": "@e05cfca67574acfdbce55a8422c6bc458be93d10",
   "pub_cache_tag": "@v0.0.1+2",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
-  "scheduled_test_tag": "@0.11.8+1",
+  "scheduled_test_tag": "@0.12.1+2",
   "shelf_rev": "@1e87b79b21ac5e6fa2f93576d6c06eaa65285ef4",
   "smoke_rev" : "@f3361191cc2a85ebc1e4d4c33aec672d7915aba9",
-  "source_maps_rev": "@379b4f31c4e2987eb15934d1ad8b419c6cc897b3",
+  "source_maps_tag": "@0.10.1",
   "sqlite_rev": "@38811b79f42801662adc0458a25270ab690a6b81",
   "shelf_static_rev": "@v0.2.1",
   "shelf_web_socket_rev": "@ff170cec2c0e4e5722cdf47c557be63b5035a602",
-  "source_span_rev": "@42501132e43599a151ba6727d340e44442f86c05",
-  "stack_trace_tag": "@1.2.1",
+  "source_map_stack_trace_tag": "@1.0.4",
+  "source_span_tag": "@1.1.2",
+  "stack_trace_tag": "@1.3.4",
   "string_scanner_rev": "@3e7617d6f74ba382e9b6130b1cc12091d89a9bc5",
   "sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
-  "test_tag": "@0.12.1",
+  "test_tag": "@0.12.3+4",
   "test_reflective_loader_tag": "@0.0.3",
   "utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
   "unittest_tag": "@0.11.6",
@@ -180,6 +182,8 @@
       (Var("github_mirror") % "analyzer_cli") + Var("analyzer_cli_rev"),
   Var("dart_root") + "/third_party/pkg/args":
       (Var("github_mirror") % "args") + Var("args_tag"),
+  Var("dart_root") + "/third_party/pkg/async":
+      "https://github.com/dart-lang/async.git" + Var("async_tag"),
   Var("dart_root") + "/third_party/pkg/barback":
       (Var("github_mirror") % "barback") + Var("barback_rev"),
   Var("dart_root") + "/third_party/pkg/charcode":
@@ -270,9 +274,12 @@
   Var("dart_root") + "/third_party/pkg/smoke":
       (Var("github_mirror") % "smoke") + Var("smoke_rev"),
   Var("dart_root") + "/third_party/pkg/source_maps":
-      (Var("github_mirror") % "source_maps") + Var("source_maps_rev"),
+      (Var("github_mirror") % "source_maps") + Var("source_maps_tag"),
   Var("dart_root") + "/third_party/pkg/source_span":
-      (Var("github_mirror") % "source_span") + Var("source_span_rev"),
+      (Var("github_mirror") % "source_span") + Var("source_span_tag"),
+  Var("dart_root") + "/third_party/pkg/source_map_stack_trace":
+      "https://github.com/dart-lang/source_map_stack_trace.git" +
+      Var("source_map_stack_trace_tag"),
   Var("dart_root") + "/third_party/pkg/stack_trace":
       (Var("github_mirror") % "stack_trace") + Var("stack_trace_tag"),
   Var("dart_root") + "/third_party/pkg/string_scanner":
diff --git a/WATCHLISTS b/WATCHLISTS
index 1bbea0d..762e901 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -14,14 +14,18 @@
       'filepath': 'tools/',
     },
     'observatory': {
-      'filepath': 'runtime/observatory/',
+      'filepath': 'runtime/bin/vmservice/' \
+                  '|runtime/bin/vmservice*' \
+                  '|runtime/observatory/' \
+                  '|runtime/vm/service/' \
+                  '|runtime/vm/service*'
     },
   },
 
   'WATCHLISTS': {
     'runtime': ['vm-dev@dartlang.org'],
     'tools': ['ricow@google.com'],
-    'observatory': ['johnmccutchan@google.com', 'turnidge@google.com'],
+    'observatory': ['johnmccutchan@google.com', 'turnidge@google.com', 'rmacnak@google.com'],
   },
 }
 
diff --git a/pkg/analysis_server/test/performance/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
similarity index 79%
rename from pkg/analysis_server/test/performance/driver.dart
rename to pkg/analysis_server/benchmark/integration/driver.dart
index 4418227..19243ea 100644
--- a/pkg/analysis_server/test/performance/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -5,12 +5,13 @@
 library server.driver;
 
 import 'dart:async';
-import 'dart:math' show max;
+import 'dart:math' show max, sqrt;
 
+import 'package:analyzer/src/generated/engine.dart' as engine;
 import 'package:logging/logging.dart';
 
-import '../integration/integration_test_methods.dart';
-import '../integration/integration_tests.dart';
+import '../../test/integration/integration_test_methods.dart';
+import '../../test/integration/integration_tests.dart';
 import 'operation.dart';
 
 final SPACE = ' '.codeUnitAt(0);
@@ -96,7 +97,7 @@
    * Launch the analysis server.
    * Return a [Future] that completes when analysis server has started.
    */
-  Future startServer() async {
+  Future startServer({int diagnosticPort}) async {
     logger.log(Level.FINE, 'starting server');
     initializeInttestMixin();
     server = new Server();
@@ -106,7 +107,9 @@
       serverConnected.complete();
     });
     running = true;
-    return server.start(/*profileServer: true*/).then((params) {
+    return server
+        .start(diagnosticPort: diagnosticPort /*profileServer: true*/)
+        .then((params) {
       server.listenToOutput(dispatchNotification);
       server.exitCode.then((_) {
         logger.log(Level.FINE, 'server stopped');
@@ -169,14 +172,29 @@
       minTime = minTime.compareTo(elapsed) < 0 ? minTime : elapsed;
       totalTimeMicros += timeMicros;
     }
-    int averageTimeMicros = (totalTimeMicros / count).round();
+    int meanTime = (totalTimeMicros / count).round();
+    List<Duration> sorted = elapsedTimes.toList()..sort();
+    Duration time90th = sorted[(sorted.length * 0.90).round() - 1];
+    Duration time99th = sorted[(sorted.length * 0.99).round() - 1];
+    int differenceFromMeanSquared = 0;
+    for (Duration elapsed in elapsedTimes) {
+      int timeMicros = elapsed.inMicroseconds;
+      int differenceFromMean = timeMicros - meanTime;
+      differenceFromMeanSquared += differenceFromMean * differenceFromMean;
+    }
+    double variance = differenceFromMeanSquared / count;
+    int standardDeviation = sqrt(variance).round();
+
     StringBuffer sb = new StringBuffer();
     _printColumn(sb, tag, keyLen);
     _printColumn(sb, count.toString(), 6, rightJustified: true);
     _printColumn(sb, errorCount.toString(), 6, rightJustified: true);
     _printColumn(sb, unexpectedResultCount.toString(), 6, rightJustified: true);
+    _printDuration(sb, new Duration(microseconds: meanTime));
+    _printDuration(sb, time90th);
+    _printDuration(sb, time99th);
+    _printColumn(sb, standardDeviation.toString(), 15, rightJustified: true);
     _printDuration(sb, minTime);
-    _printDuration(sb, new Duration(microseconds: averageTimeMicros));
     _printDuration(sb, maxTime);
     _printDuration(sb, new Duration(microseconds: totalTimeMicros));
     print(sb.toString());
@@ -213,6 +231,11 @@
   void printResults() {
     print('');
     print('==================================================================');
+    if (engine.AnalysisEngine.instance.useTaskModel) {
+      print('New task model');
+    } else {
+      print('Old task model');
+    }
     print('');
     List<String> keys = measurements.keys.toList()..sort();
     int keyLen = keys.fold(0, (int len, String key) => max(len, key.length));
@@ -229,7 +252,8 @@
         totalUnexpectedResultCount += m.unexpectedResultCount;
       }
     }
-    _printTotals(keyLen, totalCount, totalErrorCount, totalUnexpectedResultCount);
+    _printTotals(
+        keyLen, totalCount, totalErrorCount, totalUnexpectedResultCount);
     print('');
     _printGroupHeader('Notifications', keyLen);
     for (String tag in keys) {
@@ -265,19 +289,23 @@
 
   void _printGroupHeader(String groupName, int keyLen) {
     StringBuffer sb = new StringBuffer();
-        _printColumn(sb, groupName, keyLen);
-        _printColumn(sb, 'count', 6, rightJustified: true);
-        _printColumn(sb, 'error', 6, rightJustified: true);
-        _printColumn(sb, 'uxr(1)', 6, rightJustified: true);
-        sb.write('  ');
-        _printColumn(sb, 'minimum', 15);
-        _printColumn(sb, 'average', 15);
-        _printColumn(sb, 'maximum', 15);
-        _printColumn(sb, 'total', 15);
-        print(sb.toString());
+    _printColumn(sb, groupName, keyLen);
+    _printColumn(sb, 'count', 6, rightJustified: true);
+    _printColumn(sb, 'error', 6, rightJustified: true);
+    _printColumn(sb, 'uxr(1)', 6, rightJustified: true);
+    sb.write('  ');
+    _printColumn(sb, 'mean', 15);
+    _printColumn(sb, '90th', 15);
+    _printColumn(sb, '99th', 15);
+    _printColumn(sb, 'std-dev', 15);
+    _printColumn(sb, 'minimum', 15);
+    _printColumn(sb, 'maximum', 15);
+    _printColumn(sb, 'total', 15);
+    print(sb.toString());
   }
 
-  void _printTotals(int keyLen, int totalCount, int totalErrorCount, int totalUnexpectedResultCount) {
+  void _printTotals(int keyLen, int totalCount, int totalErrorCount,
+      int totalUnexpectedResultCount) {
     StringBuffer sb = new StringBuffer();
     _printColumn(sb, 'Totals', keyLen);
     _printColumn(sb, totalCount.toString(), 6, rightJustified: true);
diff --git a/pkg/analysis_server/test/performance/input_converter.dart b/pkg/analysis_server/benchmark/integration/input_converter.dart
similarity index 95%
rename from pkg/analysis_server/test/performance/input_converter.dart
rename to pkg/analysis_server/benchmark/integration/input_converter.dart
index ccf598e..ef90131 100644
--- a/pkg/analysis_server/test/performance/input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/input_converter.dart
@@ -70,7 +70,13 @@
    */
   final String tmpSrcDirPath;
 
-  CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap);
+  /**
+   * The diagnostic port for Analysis Server or `null` if none.
+   */
+  final int diagnosticPort;
+
+  CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap,
+      {this.diagnosticPort});
 
   /**
    * Return an operation for the notification or `null` if none.
@@ -89,7 +95,7 @@
     }
     if (event == SERVER_CONNECTED) {
       // {"event":"server.connected","params":{"version":"1.7.0"}}
-      return new StartServerOperation();
+      return new StartServerOperation(diagnosticPort: diagnosticPort);
     }
     if (eventsSeen.add(event)) {
       logger.log(Level.INFO, 'Ignored notification: $event\n  $json');
@@ -284,6 +290,11 @@
   final String tmpSrcDirPath;
 
   /**
+   * The diagnostic port for Analysis Server or `null` if none.
+   */
+  final int diagnosticPort;
+
+  /**
    * The number of lines read before the underlying converter was determined
    * or the end of file was reached.
    */
@@ -301,7 +312,7 @@
    */
   bool active = true;
 
-  InputConverter(this.tmpSrcDirPath, this.srcPathMap);
+  InputConverter(this.tmpSrcDirPath, this.srcPathMap, {this.diagnosticPort});
 
   @override
   Operation convert(String line) {
@@ -320,9 +331,11 @@
       throw 'Failed to determine input file format';
     }
     if (InstrumentationInputConverter.isFormat(line)) {
-      converter = new InstrumentationInputConverter(tmpSrcDirPath, srcPathMap);
+      converter = new InstrumentationInputConverter(tmpSrcDirPath, srcPathMap,
+          diagnosticPort: diagnosticPort);
     } else if (LogFileInputConverter.isFormat(line)) {
-      converter = new LogFileInputConverter(tmpSrcDirPath, srcPathMap);
+      converter = new LogFileInputConverter(tmpSrcDirPath, srcPathMap,
+          diagnosticPort: diagnosticPort);
     }
     if (converter != null) {
       return converter.convert(line);
diff --git a/pkg/analysis_server/test/performance/instrumentation_input_converter.dart b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
similarity index 96%
rename from pkg/analysis_server/test/performance/instrumentation_input_converter.dart
rename to pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
index 32974c2..11e2f9a 100644
--- a/pkg/analysis_server/test/performance/instrumentation_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/instrumentation_input_converter.dart
@@ -30,8 +30,9 @@
   StringBuffer readBuffer = null;
 
   InstrumentationInputConverter(
-      String tmpSrcDirPath, Map<String, String> srcPathMap)
-      : super(tmpSrcDirPath, srcPathMap);
+      String tmpSrcDirPath, Map<String, String> srcPathMap,
+      {int diagnosticPort})
+      : super(tmpSrcDirPath, srcPathMap, diagnosticPort: diagnosticPort);
 
   @override
   Operation convert(String line) {
diff --git a/pkg/analysis_server/test/performance/local_runner.dart b/pkg/analysis_server/benchmark/integration/local_runner.dart
similarity index 94%
rename from pkg/analysis_server/test/performance/local_runner.dart
rename to pkg/analysis_server/benchmark/integration/local_runner.dart
index 0cbe6e1..1d8d245 100644
--- a/pkg/analysis_server/test/performance/local_runner.dart
+++ b/pkg/analysis_server/benchmark/integration/local_runner.dart
@@ -62,12 +62,10 @@
    */
   performance.main([
     //'-vv', // very verbose
-    '-i',
-    inputFile.path,
-    '-t',
-    tmpSrcDirPath,
-    '-m',
-    '${gitDir.path},$tmpSrcDirPath',
+    //'-d8081', // analysis server localhost diagnostic port
+    '-i${inputFile.path}',
+    '-t$tmpSrcDirPath',
+    '-m${gitDir.path},$tmpSrcDirPath',
   ]);
 }
 
diff --git a/pkg/analysis_server/test/performance/log_file_input_converter.dart b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
similarity index 95%
rename from pkg/analysis_server/test/performance/log_file_input_converter.dart
rename to pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
index 6e9e74e..dd6c35c 100644
--- a/pkg/analysis_server/test/performance/log_file_input_converter.dart
+++ b/pkg/analysis_server/benchmark/integration/log_file_input_converter.dart
@@ -23,8 +23,9 @@
  * into a series of operations to be sent to the analysis server.
  */
 class LogFileInputConverter extends CommonInputConverter {
-  LogFileInputConverter(String tmpSrcDirPath, Map<String, String> srcPathMap)
-      : super(tmpSrcDirPath, srcPathMap);
+  LogFileInputConverter(String tmpSrcDirPath, Map<String, String> srcPathMap,
+      {int diagnosticPort})
+      : super(tmpSrcDirPath, srcPathMap, diagnosticPort: diagnosticPort);
 
   @override
   Operation convert(String line) {
diff --git a/pkg/analysis_server/test/performance/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
similarity index 83%
rename from pkg/analysis_server/test/performance/main.dart
rename to pkg/analysis_server/benchmark/integration/main.dart
index d7ec220..793110d 100644
--- a/pkg/analysis_server/test/performance/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -10,18 +10,13 @@
 
 import 'package:args/args.dart';
 import 'package:logging/logging.dart';
+import 'package:path/path.dart' as path;
 
 import 'driver.dart';
 import 'input_converter.dart';
 import 'operation.dart';
 
 /**
- * The amount of time to give the server to respond to a shutdown request
- * before forcibly terminating it.
- */
-const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 25);
-
-/**
  * Launch and interact with the analysis server.
  */
 main(List<String> rawArgs) {
@@ -57,9 +52,17 @@
   });
 }
 
+const DIAGNOSTIC_PORT_OPTION = 'diagnosticPort';
 const HELP_CMDLINE_OPTION = 'help';
 const INPUT_CMDLINE_OPTION = 'input';
 const MAP_OPTION = 'map';
+
+/**
+ * The amount of time to give the server to respond to a shutdown request
+ * before forcibly terminating it.
+ */
+const Duration SHUTDOWN_TIMEOUT = const Duration(seconds: 25);
+
 const TMP_SRC_DIR_OPTION = 'tmpSrcDir';
 const VERBOSE_CMDLINE_OPTION = 'verbose';
 const VERY_VERBOSE_CMDLINE_OPTION = 'vv';
@@ -84,7 +87,8 @@
   return inputRaw
       .transform(SYSTEM_ENCODING.decoder)
       .transform(new LineSplitter())
-      .transform(new InputConverter(args.tmpSrcDirPath, args.srcPathMap));
+      .transform(new InputConverter(args.tmpSrcDirPath, args.srcPathMap,
+          diagnosticPort: args.diagnosticPort));
 }
 
 /**
@@ -109,6 +113,9 @@
   parser.addOption(TMP_SRC_DIR_OPTION, abbr: 't', help: '<dirPath>\n'
       'The temporary directory containing source used during performance measurement.\n'
       'WARNING: The contents of the target directory will be modified');
+  parser.addOption(DIAGNOSTIC_PORT_OPTION,
+      abbr: 'd',
+      help: 'localhost port on which server will provide diagnostic web pages');
   parser.addFlag(VERBOSE_CMDLINE_OPTION,
       abbr: 'v', help: 'Verbose logging', negatable: false);
   parser.addFlag(VERY_VERBOSE_CMDLINE_OPTION,
@@ -141,10 +148,9 @@
     if (pair is String) {
       int index = pair.indexOf(',');
       if (index != -1 && pair.indexOf(',', index + 1) == -1) {
-        String oldSrcPath = pair.substring(0, index);
-        String newSrcPath = pair.substring(index + 1);
-        if (new Directory(oldSrcPath).existsSync() &&
-            new Directory(newSrcPath).existsSync()) {
+        String oldSrcPath = _withTrailingSeparator(pair.substring(0, index));
+        String newSrcPath = _withTrailingSeparator(pair.substring(index + 1));
+        if (new Directory(newSrcPath).existsSync()) {
           perfArgs.srcPathMap[oldSrcPath] = newSrcPath;
           continue;
         }
@@ -154,12 +160,20 @@
     showHelp = true;
   }
 
-  perfArgs.tmpSrcDirPath = args[TMP_SRC_DIR_OPTION];
+  perfArgs.tmpSrcDirPath = _withTrailingSeparator(args[TMP_SRC_DIR_OPTION]);
   if (isMissing(TMP_SRC_DIR_OPTION)) {
     print('missing $TMP_SRC_DIR_OPTION argument');
     showHelp = true;
   }
 
+  String portText = args[DIAGNOSTIC_PORT_OPTION];
+  if (portText != null) {
+    perfArgs.diagnosticPort = int.parse(portText, onError: (s) {
+      print('invalid $DIAGNOSTIC_PORT_OPTION: $s');
+      showHelp = true;
+    });
+  }
+
   if (args[VERY_VERBOSE_CMDLINE_OPTION] || rawArgs.contains('-vv')) {
     Logger.root.level = Level.FINE;
   } else if (args[VERBOSE_CMDLINE_OPTION]) {
@@ -184,12 +198,24 @@
 }
 
 /**
+ * Ensure that the given path has a trailing separator
+ */
+String _withTrailingSeparator(String dirPath) {
+  if (dirPath != null && dirPath.length > 4) {
+    if (!dirPath.endsWith(path.separator)) {
+      return '$dirPath${path.separator}';
+    }
+  }
+  return dirPath;
+}
+
+/**
  * The performance measurement arguments specified on the command line.
  */
 class PerfArgs {
 
   /**
-   * The file path of the instrumentation or log file 
+   * The file path of the instrumentation or log file
    * used to drive performance measurement,
    * or 'stdin' if this information should be read from standard input.
    */
@@ -206,4 +232,9 @@
    * The temporary directory containing source used during performance measurement.
    */
   String tmpSrcDirPath;
+
+  /**
+   * The diagnostic port for Analysis Server or `null` if none.
+   */
+  int diagnosticPort;
 }
diff --git a/pkg/analysis_server/test/performance/operation.dart b/pkg/analysis_server/benchmark/integration/operation.dart
similarity index 95%
rename from pkg/analysis_server/test/performance/operation.dart
rename to pkg/analysis_server/benchmark/integration/operation.dart
index 641cf31..f9ee62a 100644
--- a/pkg/analysis_server/test/performance/operation.dart
+++ b/pkg/analysis_server/benchmark/integration/operation.dart
@@ -13,7 +13,7 @@
 import 'input_converter.dart';
 
 /**
- * A [CompletionRequestOperation] tracks response time along with 
+ * A [CompletionRequestOperation] tracks response time along with
  * the first and last completion notifications.
  */
 class CompletionRequestOperation extends RequestOperation {
@@ -80,6 +80,7 @@
     Stopwatch stopwatch = new Stopwatch();
     String originalId = json['id'];
     String method = json['method'];
+    json['clientRequestTime'] = new DateTime.now().millisecondsSinceEpoch;
     driver.logger.log(Level.FINE, 'Sending request: $method\n  $json');
     stopwatch.start();
 
@@ -178,9 +179,13 @@
 }
 
 class StartServerOperation extends Operation {
+  final int diagnosticPort;
+
+  StartServerOperation({this.diagnosticPort});
+
   @override
   Future perform(Driver driver) {
-    return driver.startServer();
+    return driver.startServer(diagnosticPort: diagnosticPort);
   }
 }
 
@@ -194,7 +199,6 @@
     Completer completer = new Completer();
     bool isAnalyzing = false;
     subscription = driver.onServerStatus.listen((ServerStatusParams params) {
-      // TODO (danrubel) ensure that server.setSubscriptions STATUS is set
       if (params.analysis != null) {
         if (params.analysis.isAnalyzing) {
           isAnalyzing = true;
@@ -218,10 +222,10 @@
         completer.complete();
         return;
       }
-      // Timeout if no communcation received within the last 10 seconds.
+      // Timeout if no communcation received within the last 60 seconds.
       double currentTime = driver.server.currentElapseTime;
       double lastTime = driver.server.lastCommunicationTime;
-      if (currentTime - lastTime > 10) {
+      if (currentTime - lastTime > 60) {
         subscription.cancel();
         timer.cancel();
         String message = 'gave up waiting for analysis to complete';
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index db15b5f..6d8be8a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -22,6 +22,7 @@
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/ast.dart';
@@ -260,13 +261,14 @@
       OptimizingPubPackageMapProvider packageMapProvider, Index _index,
       this.serverPlugin, AnalysisServerOptions analysisServerOptions,
       this.defaultSdk, this.instrumentationService,
-      {this.rethrowExceptions: true})
+      {ResolverProvider packageResolverProvider: null,
+      this.rethrowExceptions: true})
       : index = _index,
         searchEngine = _index != null ? createSearchEngine(_index) : null {
     _performance = performanceDuringStartup;
     operationQueue = new ServerOperationQueue();
-    contextDirectoryManager = new ServerContextManager(
-        this, resourceProvider, packageMapProvider, instrumentationService);
+    contextDirectoryManager = new ServerContextManager(this, resourceProvider,
+        packageResolverProvider, packageMapProvider, instrumentationService);
     contextDirectoryManager.defaultOptions.incremental = true;
     contextDirectoryManager.defaultOptions.incrementalApi =
         analysisServerOptions.enableIncrementalResolutionApi;
@@ -1310,9 +1312,11 @@
   StreamController<ContextsChangedEvent> _onContextsChangedController;
 
   ServerContextManager(this.analysisServer, ResourceProvider resourceProvider,
+      ResolverProvider packageResolverProvider,
       OptimizingPubPackageMapProvider packageMapProvider,
       InstrumentationService service)
-      : super(resourceProvider, packageMapProvider, service) {
+      : super(resourceProvider, packageResolverProvider, packageMapProvider,
+          service) {
     _onContextsChangedController =
         new StreamController<ContextsChangedEvent>.broadcast();
   }
diff --git a/pkg/analysis_server/lib/src/computer/computer_navigation.dart b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
index 504bf40..14a47ec 100644
--- a/pkg/analysis_server/lib/src/computer/computer_navigation.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_navigation.dart
@@ -246,17 +246,15 @@
     }
     // add regions
     TypeName typeName = node.type;
+    computer._addRegionForNode(typeName.name, element);
+    // <TypeA, TypeB>
     TypeArgumentList typeArguments = typeName.typeArguments;
-    if (typeArguments == null) {
-      computer._addRegion_nodeStart_nodeEnd(parent, node, element);
-    } else {
-      computer._addRegion_nodeStart_nodeEnd(parent, typeName.name, element);
-      // <TypeA, TypeB>
+    if (typeArguments != null) {
       typeArguments.accept(this);
-      // optional ".name"
-      if (node.period != null) {
-        computer._addRegion_tokenStart_nodeEnd(node.period, node, element);
-      }
+    }
+    // optional "name"
+    if (node.name != null) {
+      computer._addRegionForNode(node.name, element);
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 275df09..f75b702 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -10,6 +10,7 @@
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
@@ -80,6 +81,13 @@
   Map<String, String> normalizedPackageRoots = <String, String>{};
 
   /**
+   * A function that will return a [UriResolver] that can be used to resolve
+   * `package:` URI's within a given folder, or `null` if we should fall back
+   * to the standard URI resolver.
+   */
+  final ResolverProvider packageResolverProvider;
+
+  /**
    * Provider which is used to determine the mapping from package name to
    * package folder.
    */
@@ -90,8 +98,8 @@
    */
   final InstrumentationService _instrumentationService;
 
-  ContextManager(this.resourceProvider, this._packageMapProvider,
-      this._instrumentationService) {
+  ContextManager(this.resourceProvider, this.packageResolverProvider,
+      this._packageMapProvider, this._instrumentationService) {
     pathContext = resourceProvider.pathContext;
   }
 
@@ -431,6 +439,12 @@
       return new PackageUriResolver([packagesDir]);
     } else {
       beginComputePackageMap();
+      if (packageResolverProvider != null) {
+        UriResolver resolver = packageResolverProvider(folder);
+        if (resolver != null) {
+          return resolver;
+        }
+      }
       OptimizingPubPackageMapInfo packageMapInfo;
       ServerPerformanceStatistics.pub.makeCurrentWhile(() {
         packageMapInfo =
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 0c1f9db9b..7604fc0 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -14,6 +14,7 @@
 import 'package:analysis_server/src/server/stdio_server.dart';
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analysis_server/starter.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/file_instrumentation.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -283,6 +284,12 @@
   InstrumentationServer instrumentationServer;
 
   /**
+   * The package resolver provider used to override the way package URI's are
+   * resolved in some contexts.
+   */
+  ResolverProvider packageResolverProvider;
+
+  /**
    * The plugins that are defined outside the analysis_server package.
    */
   List<Plugin> _userDefinedPlugins = <Plugin>[];
@@ -388,8 +395,8 @@
     //
     // Create the sockets and start listening for requests.
     //
-    socketServer = new SocketServer(
-        analysisServerOptions, defaultSdk, service, serverPlugin);
+    socketServer = new SocketServer(analysisServerOptions, defaultSdk, service,
+        serverPlugin, packageResolverProvider);
     httpServer = new HttpAnalysisServer(socketServer);
     stdioServer = new StdioAnalysisServer(socketServer);
     socketServer.userDefinedPlugins = _userDefinedPlugins;
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 8234ed8..5bdbe24 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -57,6 +57,10 @@
       const AssistKind('CONVERT_INTO_IS_NOT', 30, "Convert into is!");
   static const CONVERT_INTO_IS_NOT_EMPTY = const AssistKind(
       'CONVERT_INTO_IS_NOT_EMPTY', 30, "Convert into 'isNotEmpty'");
+  static const CONVERT_TO_FIELD_PARAMETER = const AssistKind(
+      'CONVERT_TO_FIELD_PARAMETER', 30, "Convert to field formal parameter");
+  static const CONVERT_TO_NORMAL_PARAMETER = const AssistKind(
+      'CONVERT_TO_NORMAL_PARAMETER', 30, "Convert to normal parameter");
   static const ENCAPSULATE_FIELD =
       const AssistKind('ENCAPSULATE_FIELD', 30, "Encapsulate field");
   static const EXCHANGE_OPERANDS =
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 5d03c83..9c5e9ba 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -87,6 +87,8 @@
     _addProposal_convertToIsNot_onIs();
     _addProposal_convertToIsNot_onNot();
     _addProposal_convertToIsNotEmpty();
+    _addProposal_convertToFieldParameter();
+    _addProposal_convertToNormalParameter();
     _addProposal_encapsulateField();
     _addProposal_exchangeOperands();
     _addProposal_importAddShow();
@@ -443,6 +445,93 @@
     _addAssist(DartAssistKind.CONVERT_INTO_EXPRESSION_BODY, []);
   }
 
+  void _addProposal_convertToFieldParameter() {
+    if (node == null) {
+      return;
+    }
+    // prepare ConstructorDeclaration
+    ConstructorDeclaration constructor =
+        node.getAncestor((node) => node is ConstructorDeclaration);
+    if (constructor == null) {
+      return;
+    }
+    FormalParameterList parameterList = constructor.parameters;
+    List<ConstructorInitializer> initializers = constructor.initializers;
+    // prepare parameter
+    SimpleFormalParameter parameter;
+    if (node.parent is SimpleFormalParameter &&
+        node.parent.parent is FormalParameterList &&
+        node.parent.parent.parent is ConstructorDeclaration) {
+      parameter = node.parent;
+    }
+    if (node is SimpleIdentifier &&
+        node.parent is ConstructorFieldInitializer) {
+      String name = (node as SimpleIdentifier).name;
+      ConstructorFieldInitializer initializer = node.parent;
+      if (initializer.expression == node) {
+        for (FormalParameter formalParameter in parameterList.parameters) {
+          if (formalParameter is SimpleFormalParameter &&
+              formalParameter.identifier.name == name) {
+            parameter = formalParameter;
+          }
+        }
+      }
+    }
+    // analyze parameter
+    if (parameter != null) {
+      String parameterName = parameter.identifier.name;
+      ParameterElement parameterElement = parameter.element;
+      // check number of references
+      {
+        int numOfReferences = 0;
+        AstVisitor visitor = new _SimpleIdentifierRecursiveAstVisitor(
+            (SimpleIdentifier node) {
+          if (node.staticElement == parameterElement) {
+            numOfReferences++;
+          }
+        });
+        for (ConstructorInitializer initializer in initializers) {
+          initializer.accept(visitor);
+        }
+        if (numOfReferences != 1) {
+          return;
+        }
+      }
+      // find the field initializer
+      ConstructorFieldInitializer parameterInitializer;
+      for (ConstructorInitializer initializer in initializers) {
+        if (initializer is ConstructorFieldInitializer) {
+          Expression expression = initializer.expression;
+          if (expression is SimpleIdentifier &&
+              expression.name == parameterName) {
+            parameterInitializer = initializer;
+          }
+        }
+      }
+      if (parameterInitializer == null) {
+        return;
+      }
+      String fieldName = parameterInitializer.fieldName.name;
+      // replace parameter
+      _addReplaceEdit(rangeNode(parameter), 'this.$fieldName');
+      // remove initializer
+      int initializerIndex = initializers.indexOf(parameterInitializer);
+      if (initializers.length == 1) {
+        _addRemoveEdit(rangeEndEnd(parameterList, parameterInitializer));
+      } else {
+        if (initializerIndex == 0) {
+          ConstructorInitializer next = initializers[initializerIndex + 1];
+          _addRemoveEdit(rangeStartStart(parameterInitializer, next));
+        } else {
+          ConstructorInitializer prev = initializers[initializerIndex - 1];
+          _addRemoveEdit(rangeEndEnd(prev, parameterInitializer));
+        }
+      }
+      // add proposal
+      _addAssist(DartAssistKind.CONVERT_TO_FIELD_PARAMETER, []);
+    }
+  }
+
   void _addProposal_convertToForIndexLoop() {
     // find enclosing ForEachStatement
     ForEachStatement forEachStatement =
@@ -673,6 +762,38 @@
     _addAssist(DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY, []);
   }
 
+  void _addProposal_convertToNormalParameter() {
+    if (node is SimpleIdentifier &&
+        node.parent is FieldFormalParameter &&
+        node.parent.parent is FormalParameterList &&
+        node.parent.parent.parent is ConstructorDeclaration) {
+      ConstructorDeclaration constructor = node.parent.parent.parent;
+      FormalParameterList parameterList = node.parent.parent;
+      FieldFormalParameter parameter = node.parent;
+      ParameterElement parameterElement = parameter.element;
+      String name = (node as SimpleIdentifier).name;
+      // prepare type
+      DartType type = parameterElement.type;
+      Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
+      String typeCode = utils.getTypeSource(type, librariesToImport);
+      // replace parameter
+      if (type.isDynamic) {
+        _addReplaceEdit(rangeNode(parameter), name);
+      } else {
+        _addReplaceEdit(rangeNode(parameter), '$typeCode $name');
+      }
+      // add field initializer
+      List<ConstructorInitializer> initializers = constructor.initializers;
+      if (initializers.isEmpty) {
+        _addInsertEdit(parameterList.end, ' : $name = $name');
+      } else {
+        _addInsertEdit(initializers.last.end, ', $name = $name');
+      }
+      // add proposal
+      _addAssist(DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, []);
+    }
+  }
+
   void _addProposal_encapsulateField() {
     // find FieldDeclaration
     FieldDeclaration fieldDeclaraton =
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index 5f95186..36e7836 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -11,6 +11,7 @@
 import 'package:analysis_server/src/services/index/index.dart';
 import 'package:analysis_server/src/services/index/local_file_index.dart';
 import 'package:analysis_server/src/source/optimizing_pub_package_map_provider.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
@@ -27,6 +28,7 @@
   final DirectoryBasedDartSdk defaultSdk;
   final InstrumentationService instrumentationService;
   final ServerPlugin serverPlugin;
+  final ResolverProvider packageResolverProvider;
 
   /**
    * The analysis server that was created when a client established a
@@ -40,7 +42,8 @@
   List<Plugin> userDefinedPlugins;
 
   SocketServer(this.analysisServerOptions, this.defaultSdk,
-      this.instrumentationService, this.serverPlugin);
+      this.instrumentationService, this.serverPlugin,
+      this.packageResolverProvider);
 
   /**
    * Create an analysis server which will communicate with the client using the
@@ -78,7 +81,9 @@
     analysisServer = new AnalysisServer(serverChannel, resourceProvider,
         new OptimizingPubPackageMapProvider(resourceProvider, defaultSdk),
         index, serverPlugin, analysisServerOptions, defaultSdk,
-        instrumentationService, rethrowExceptions: false);
+        instrumentationService,
+        packageResolverProvider: packageResolverProvider,
+        rethrowExceptions: false);
     analysisServer.userDefinedPlugins = userDefinedPlugins;
   }
 }
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 01a330a..3e18f8a 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -298,106 +298,68 @@
       _writePage(buffer, 'Analysis Server - Analysis Performance', [],
           (StringBuffer buffer) {
         buffer.write('<h3>Analysis Performance</h3>');
-
         //
         // Write performance tags.
         //
-        {
-          buffer.write('<p><b>Time spent in each phase of analysis</b></p>');
-          buffer.write(
-              '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
-          _writeRow(buffer, ['Time (in ms)', 'Percent', 'Analysis Phase'],
-              header: true);
-          // prepare sorted tags
-          List<PerformanceTag> tags = PerformanceTag.all.toList();
-          tags.remove(ServerPerformanceStatistics.idle);
-          tags.sort((a, b) => b.elapsedMs - a.elapsedMs);
-          // prepare total time
-          int totalTime = 0;
-          tags.forEach((PerformanceTag tag) {
-            totalTime += tag.elapsedMs;
-          });
-          // write rows
-          void writeRow(PerformanceTag tag) {
-            double percent = (tag.elapsedMs * 100) / totalTime;
-            String percentStr = '${percent.toStringAsFixed(2)}%';
-            _writeRow(buffer, [tag.elapsedMs, percentStr, tag.label],
-                classes: ["right", "right", null]);
-          }
-          tags.forEach(writeRow);
-          buffer.write('</table>');
+        buffer.write('<p><b>Performance tag data</b></p>');
+        buffer.write(
+            '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+        _writeRow(buffer, ['Time (in ms)', 'Percent', 'Tag name'],
+            header: true);
+        // prepare sorted tags
+        List<PerformanceTag> tags = PerformanceTag.all.toList();
+        tags.remove(ServerPerformanceStatistics.idle);
+        tags.sort((a, b) => b.elapsedMs - a.elapsedMs);
+        // prepare total time
+        int totalTagTime = 0;
+        tags.forEach((PerformanceTag tag) {
+          totalTagTime += tag.elapsedMs;
+        });
+        // write rows
+        void writeRow(PerformanceTag tag) {
+          double percent = (tag.elapsedMs * 100) / totalTagTime;
+          String percentStr = '${percent.toStringAsFixed(2)}%';
+          _writeRow(buffer, [tag.elapsedMs, percentStr, tag.label],
+              classes: ["right", "right", null]);
         }
+        tags.forEach(writeRow);
+        buffer.write('</table>');
+        //
+        // Write task model timing information.
+        //
+        buffer.write('<p><b>Task performace data</b></p>');
+        buffer.write(
+            '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+        _writeRow(buffer, [
+          'Task Name',
+          'Count',
+          'Total Time (in ms)',
+          'Average Time (in ms)'
+        ], header: true);
 
-        //
-        // Write new task model timing information.
-        //
-        if (AnalysisEngine.instance.useTaskModel) {
-          buffer.write('<p><b>Task performace data</b></p>');
-          buffer.write(
-              '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+        Map<Type, int> countMap = AnalysisTask.countMap;
+        Map<Type, Stopwatch> stopwatchMap = AnalysisTask.stopwatchMap;
+        List<Type> taskClasses = stopwatchMap.keys.toList();
+        taskClasses.sort((Type first, Type second) =>
+            first.toString().compareTo(second.toString()));
+        int totalTaskTime = 0;
+        taskClasses.forEach((Type taskClass) {
+          int count = countMap[taskClass];
+          if (count == null) {
+            count = 0;
+          }
+          int taskTime = stopwatchMap[taskClass].elapsedMilliseconds;
+          totalTaskTime += taskTime;
           _writeRow(buffer, [
-            'Task Name',
-            'Count',
-            'Total Time (in ms)',
-            'Average Time (in ms)'
-          ], header: true);
-
-          Map<Type, int> countMap = AnalysisTask.countMap;
-          Map<Type, Stopwatch> stopwatchMap = AnalysisTask.stopwatchMap;
-          List<Type> taskClasses = stopwatchMap.keys.toList();
-          taskClasses.sort((Type first, Type second) =>
-              first.toString().compareTo(second.toString()));
-          int totalTime = 0;
-          taskClasses.forEach((Type taskClass) {
-            int count = countMap[taskClass];
-            if (count == null) {
-              count = 0;
-            }
-            int taskTime = stopwatchMap[taskClass].elapsedMilliseconds;
-            totalTime += taskTime;
-            _writeRow(buffer, [
-              taskClass.toString(),
-              count,
-              taskTime,
-              count <= 0 ? '-' : (taskTime / count).toStringAsFixed(3)
-            ], classes: [null, "right", "right", "right"]);
-          });
-          _writeRow(buffer, ['Total', '-', totalTime, '-'],
-              classes: [null, "right", "right", "right"]);
-          buffer.write('</table>');
-        }
-
-        //
-        // Write old task model transition information.
-        //
-        {
-          Map<DataDescriptor, Map<CacheState, int>> transitionMap =
-              SourceEntry.transitionMap;
-          buffer.write(
-              '<p><b>Number of times a state transitioned to VALID (grouped by descriptor)</b></p>');
-          if (transitionMap.isEmpty) {
-            buffer.write('<p>none</p>');
-          } else {
-            List<DataDescriptor> descriptors = transitionMap.keys.toList();
-            descriptors.sort((DataDescriptor first, DataDescriptor second) =>
-                first.toString().compareTo(second.toString()));
-            for (DataDescriptor key in descriptors) {
-              Map<CacheState, int> countMap = transitionMap[key];
-              List<CacheState> oldStates = countMap.keys.toList();
-              oldStates.sort((CacheState first, CacheState second) =>
-                  first.toString().compareTo(second.toString()));
-              buffer.write('<p>${key.toString()}</p>');
-              buffer.write(
-                  '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
-              _writeRow(buffer, ['Count', 'Previous State'], header: true);
-              for (CacheState state in oldStates) {
-                _writeRow(buffer, [countMap[state], state.toString()],
-                    classes: ["right", null]);
-              }
-              buffer.write('</table>');
-            }
-          }
-        }
+            taskClass.toString(),
+            count,
+            taskTime,
+            count <= 0 ? '-' : (taskTime / count).toStringAsFixed(3)
+          ], classes: [null, "right", "right", "right"]);
+        });
+        _writeRow(buffer, ['Total', '-', totalTaskTime, '-'],
+            classes: [null, "right", "right", "right"]);
+        buffer.write('</table>');
       });
     });
   }
diff --git a/pkg/analysis_server/lib/starter.dart b/pkg/analysis_server/lib/starter.dart
index dae6a05..e96c8b3 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -5,6 +5,7 @@
 library driver;
 
 import 'package:analysis_server/src/server/driver.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:plugin/plugin.dart';
 
@@ -23,6 +24,13 @@
   void set instrumentationServer(InstrumentationServer server);
 
   /**
+   * Set the package resolver provider used to override the way package URI's
+   * are resolved in some contexts. The provider should return `null` if the
+   * default package resolution scheme should be used instead.
+   */
+  void set packageResolverProvider(ResolverProvider provider);
+
+  /**
    * Set the [plugins] that are defined outside the analysis_server package.
    */
   void set userDefinedPlugins(List<Plugin> plugins);
diff --git a/pkg/analysis_server/lib/uri/resolver_provider.dart b/pkg/analysis_server/lib/uri/resolver_provider.dart
new file mode 100644
index 0000000..36ae274
--- /dev/null
+++ b/pkg/analysis_server/lib/uri/resolver_provider.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.
+
+library analysis_server.uri.resolver_provider;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A function that will return a [UriResolver] that can be used to resolve a
+ * specific kind of URI within the analysis context rooted at the given folder.
+ * This is currently being used to provide a package URI resolver that will be
+ * used by the server (see [ServerStarter.packageResolverProvider]).
+ */
+typedef UriResolver ResolverProvider(Folder folder);
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index cc24ca3..16d1bcd 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -295,8 +295,14 @@
 }
 ''');
     return prepareNavigation().then((_) {
-      assertHasRegionString('B.named');
-      assertHasTarget('named();');
+      {
+        assertHasRegionString('B.named;', 'B'.length);
+        assertHasTarget('named();');
+      }
+      {
+        assertHasRegionString('named;', 'named'.length);
+        assertHasTarget('named();');
+      }
     });
   }
 
@@ -320,7 +326,7 @@
         assertHasTarget('A {');
       }
       {
-        assertHasRegion('.named;', '.named'.length);
+        assertHasRegion('named;', 'named'.length);
         assertHasTarget('named() {}');
       }
     });
@@ -445,7 +451,7 @@
 }
 ''');
     return prepareNavigation().then((_) {
-      assertHasRegionString('new A');
+      assertHasRegionString('A()', 'A'.length);
       assertHasTarget('A {');
     });
   }
@@ -460,7 +466,7 @@
 ''');
     return prepareNavigation().then((_) {
       {
-        assertHasRegion('new B<A>', 'new B'.length);
+        assertHasRegion('B<A>', 'B'.length);
         assertHasTarget('B<T> {');
       }
       {
@@ -480,8 +486,14 @@
 }
 ''');
     return prepareNavigation().then((_) {
-      assertHasRegionString('new A.named');
-      assertHasTarget('named() {}');
+      {
+        assertHasRegionString('A.named();', 'A'.length);
+        assertHasTarget('named() {}');
+      }
+      {
+        assertHasRegionString('named();', 'named'.length);
+        assertHasTarget('named() {}');
+      }
     });
   }
 
@@ -497,7 +509,7 @@
 ''');
     return prepareNavigation().then((_) {
       {
-        assertHasRegionString('new B');
+        assertHasRegionString('B<A>', 'B'.length);
         assertHasTarget('named() {}');
       }
       {
@@ -505,7 +517,7 @@
         assertHasTarget('A {');
       }
       {
-        assertHasRegion('.named();', '.named'.length);
+        assertHasRegion('named();', 'named'.length);
         assertHasTarget('named() {}');
       }
     });
@@ -521,7 +533,7 @@
 }
 ''');
     return prepareNavigation().then((_) {
-      assertHasRegionString('new A');
+      assertHasRegionString('A();', 'A'.length);
       assertHasTarget('A() {}', 0);
     });
   }
@@ -538,7 +550,7 @@
 ''');
     return prepareNavigation().then((_) {
       {
-        assertHasRegionString('new B');
+        assertHasRegionString('B<A>();', 'B'.length);
         assertHasTarget('B() {}', 0);
       }
       {
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index b8c313d..135ce6a 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -4,6 +4,7 @@
 
 library test.analysis.updateContent;
 
+import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/services/index/index.dart';
@@ -177,6 +178,24 @@
     expect(_getUserSources(context2), isEmpty);
   }
 
+  test_removeOverlay_incrementalChange() async {
+    createProject();
+    addTestFile('main() { print(1); }');
+    await server.onAnalysisComplete;
+    CompilationUnit unit = _getTestUnit();
+    // add an overlay
+    server.updateContent(
+        '1', {testFile: new AddContentOverlay('main() { print(2); }')});
+    // it was an incremental change
+    await server.onAnalysisComplete;
+    expect(_getTestUnit(), same(unit));
+    // remove overlay
+    server.updateContent('2', {testFile: new RemoveContentOverlay()});
+    // it was an incremental change
+    await server.onAnalysisComplete;
+    expect(_getTestUnit(), same(unit));
+  }
+
   test_sendNoticesAfterNopChange() async {
     createProject();
     addTestFile('');
@@ -214,6 +233,13 @@
     expect(filesErrors, isNotEmpty);
   }
 
+  CompilationUnit _getTestUnit() {
+    ContextSourcePair pair = server.getContextSourcePair(testFile);
+    AnalysisContext context = pair.context;
+    Source source = pair.source;
+    return context.getResolvedCompilationUnit2(source, source);
+  }
+
   List<Source> _getUserSources(AnalysisContext context) {
     List<Source> sources = <Source>[];
     context.sources.forEach((source) {
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 2908cde..092fc85 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -20,6 +20,7 @@
 import 'package:unittest/unittest.dart';
 
 import 'mocks.dart';
+import 'package:analysis_server/uri/resolver_provider.dart';
 
 main() {
   groupSep = ' | ';
@@ -59,6 +60,8 @@
 
   MockPackageMapProvider packageMapProvider;
 
+  UriResolver packageResolver = null;
+
   String projPath = '/my/proj';
 
   String newFile(List<String> pathComponents, [String content = '']) {
@@ -73,10 +76,14 @@
     return folderPath;
   }
 
+  UriResolver providePackageResolver(Folder folder) {
+    return packageResolver;
+  }
+
   void setUp() {
     resourceProvider = new MemoryResourceProvider();
     packageMapProvider = new MockPackageMapProvider();
-    manager = new TestContextManager(resourceProvider, packageMapProvider);
+    manager = new TestContextManager(resourceProvider, providePackageResolver, packageMapProvider);
     resourceProvider.newFolder(projPath);
   }
 
@@ -195,6 +202,29 @@
     var filePaths = manager.currentContextFilePaths[projPath];
     expect(filePaths, hasLength(1));
     expect(filePaths, contains(filePath));
+    List<AnalysisContext> contextsInAnalysisRoot = manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contextsInAnalysisRoot, hasLength(1));
+    AnalysisContext context = contextsInAnalysisRoot[0];
+    expect(context, isNotNull);
+    Source result = context.sourceFactory.forUri('package:foo/foo.dart');
+    expect(result, isNotNull);
+    expect(result.exists(), isFalse);
+  }
+
+  void test_setRoots_packageResolver() {
+    Uri uri = Uri.parse('package:foo/foo.dart');
+    Source source = new TestSource();
+    packageResolver = new TestUriResolver({uri : source});
+    String filePath = posix.join(projPath, 'foo.dart');
+    resourceProvider.newFile(filePath, 'contents');
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+    List<AnalysisContext> contextsInAnalysisRoot = manager.contextsInAnalysisRoot(resourceProvider.newFolder(projPath));
+    expect(contextsInAnalysisRoot, hasLength(1));
+    AnalysisContext context = contextsInAnalysisRoot[0];
+    expect(context, isNotNull);
+    Source result = context.sourceFactory.forUri2(uri);
+    expect(result, same(source));
   }
 
   void test_setRoots_addFolderWithDartFileInSubfolder() {
@@ -981,8 +1011,9 @@
       <String, UriResolver>{};
 
   TestContextManager(MemoryResourceProvider resourceProvider,
+                     ResolverProvider packageResolverProvider,
       OptimizingPubPackageMapProvider packageMapProvider)
-      : super(resourceProvider, packageMapProvider,
+      : super(resourceProvider, packageResolverProvider, packageMapProvider,
           InstrumentationService.NULL_SERVICE);
 
   /**
@@ -1066,3 +1097,24 @@
     currentContextPackageUriResolvers[contextFolder.path] = packageUriResolver;
   }
 }
+
+class TestUriResolver extends UriResolver {
+  Map<Uri, Source> uriMap;
+
+  TestUriResolver(this.uriMap);
+
+  @override
+  Source resolveAbsolute(Uri uri) {
+    return uriMap[uri];
+  }
+}
+
+/**
+ * A [Source] that knows it's [fullName].
+ */
+class TestSource implements Source {
+  TestSource();
+
+  @override
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analysis_server/test/integration/analysis/navigation_test.dart b/pkg/analysis_server/test/integration/analysis/navigation_test.dart
index 87b2e31..310e882 100644
--- a/pkg/analysis_server/test/integration/analysis/navigation_test.dart
+++ b/pkg/analysis_server/test/integration/analysis/navigation_test.dart
@@ -41,7 +41,7 @@
 int topLevelVariable;
 
 main() {
-  Class<int> localVariable = new Class<int>.constructor();
+  Class<int> localVariable = new Class<int>.constructor(); // usage
   function(() => localVariable.field);
   localVariable.method();
   localVariable.field = 1;
@@ -101,7 +101,10 @@
       checkLocal('Class<int>', 'Class<TypeParameter>', ElementKind.CLASS);
       checkRemote(
           "part 'test2.dart';", r'test2.dart$', ElementKind.COMPILATION_UNIT);
-      checkLocal('new Class<int>.constructor',
+      checkLocal('Class<int>.constructor',
+          'constructor(); /* constructor declaration */',
+          ElementKind.CONSTRUCTOR);
+      checkLocal('constructor(); // usage',
           'constructor(); /* constructor declaration */',
           ElementKind.CONSTRUCTOR);
       checkLocal('field;', 'field;', ElementKind.FIELD);
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index 3b7e13a..faec89f 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -462,7 +462,7 @@
    * upward to the 'test' dir, and then going up one more directory.
    */
   String findRoot(String pathname) {
-    while (basename(pathname) != 'test') {
+    while (!['benchmark', 'test'].contains(basename(pathname))) {
       String parent = dirname(pathname);
       if (parent.length >= pathname.length) {
         throw new Exception("Can't find root directory");
@@ -584,7 +584,7 @@
    * `true`, the server will be started with "--observe" and
    * "--pause-isolates-on-exit", allowing the observatory to be used.
    */
-  Future start({bool debugServer: false, bool profileServer: false}) {
+  Future start({bool debugServer: false, int diagnosticPort, bool profileServer: false}) {
     if (_process != null) {
       throw new Exception('Process already started');
     }
@@ -606,6 +606,10 @@
     }
     arguments.add('--checked');
     arguments.add(serverPath);
+    if (diagnosticPort != null) {
+      arguments.add('--port');
+      arguments.add(diagnosticPort.toString());
+    }
     return Process.start(dartBinary, arguments).then((Process process) {
       _process = process;
       process.exitCode.then((int code) {
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 57f49d0..8e27fa5 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -939,6 +939,95 @@
     assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
   }
 
+  void test_convertToFieldParameter_BAD_additionalUse() {
+    resolveTestUnit('''
+class A {
+  int aaa2;
+  int bbb2;
+  A(int aaa) : aaa2 = aaa, bbb2 = aaa;
+}
+''');
+    assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+  }
+
+  void test_convertToFieldParameter_BAD_notPureAssignment() {
+    resolveTestUnit('''
+class A {
+  int aaa2;
+  A(int aaa) : aaa2 = aaa * 2;
+}
+''');
+    assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+  }
+
+  void test_convertToFieldParameter_OK_firstInitializer() {
+    resolveTestUnit('''
+class A {
+  double aaa2;
+  int bbb2;
+  A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
+}
+''');
+    assertHasAssistAt('aaa, ', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+class A {
+  double aaa2;
+  int bbb2;
+  A(this.aaa2, int bbb) : bbb2 = bbb;
+}
+''');
+  }
+
+  void test_convertToFieldParameter_OK_onParameterName_inInitializer() {
+    resolveTestUnit('''
+class A {
+  int test2;
+  A(int test) : test2 = test {
+  }
+}
+''');
+    assertHasAssistAt('test {', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+class A {
+  int test2;
+  A(this.test2) {
+  }
+}
+''');
+  }
+
+  void test_convertToFieldParameter_OK_onParameterName_inParameters() {
+    resolveTestUnit('''
+class A {
+  int test;
+  A(int test) : test = test {
+  }
+}
+''');
+    assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+class A {
+  int test;
+  A(this.test) {
+  }
+}
+''');
+  }
+
+  void test_convertToFieldParameter_OK_secondInitializer() {
+    resolveTestUnit('''
+class A {
+  double aaa2;
+  int bbb2;
+  A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
+}
+''');
+    assertHasAssistAt('bbb)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER, '''
+class A {
+  double aaa2;
+  int bbb2;
+  A(int aaa, this.bbb2) : aaa2 = aaa;
+}
+''');
+  }
+
   void test_convertToForIndex_BAD_bodyNotBlock() {
     resolveTestUnit('''
 main(List<String> items) {
@@ -1339,6 +1428,57 @@
     assertNoAssistAt('isEven;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
   }
 
+  void test_convertToNormalParameter_OK_dynamic() {
+    resolveTestUnit('''
+class A {
+  var test;
+  A(this.test) {
+  }
+}
+''');
+    assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+class A {
+  var test;
+  A(test) : test = test {
+  }
+}
+''');
+  }
+
+  void test_convertToNormalParameter_OK_firstInitializer() {
+    resolveTestUnit('''
+class A {
+  int test;
+  A(this.test) {
+  }
+}
+''');
+    assertHasAssistAt('test)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+class A {
+  int test;
+  A(int test) : test = test {
+  }
+}
+''');
+  }
+
+  void test_convertToNormalParameter_OK_secondInitializer() {
+    resolveTestUnit('''
+class A {
+  double aaa;
+  int bbb;
+  A(this.bbb) : aaa = 1.0;
+}
+''');
+    assertHasAssistAt('bbb)', DartAssistKind.CONVERT_TO_NORMAL_PARAMETER, '''
+class A {
+  double aaa;
+  int bbb;
+  A(int bbb) : aaa = 1.0, bbb = bbb;
+}
+''');
+  }
+
   void test_encapsulateField_BAD_alreadyPrivate() {
     resolveTestUnit('''
 class A {
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index e98aa2a..8e74cef 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -111,7 +111,7 @@
     manager.processPlugins([serverPlugin]);
     return new SocketServer(new AnalysisServerOptions(),
         DirectoryBasedDartSdk.defaultSdk, InstrumentationService.NULL_SERVICE,
-        serverPlugin);
+        serverPlugin, null);
   }
 }
 
diff --git a/pkg/analysis_server/tool/spec/codegen_tools.dart b/pkg/analysis_server/tool/spec/codegen_tools.dart
index 84a95ab..0d7e95f 100644
--- a/pkg/analysis_server/tool/spec/codegen_tools.dart
+++ b/pkg/analysis_server/tool/spec/codegen_tools.dart
@@ -286,7 +286,11 @@
         String expectedContents = fileContentsComputer();
         File outputFile =
             new File(joinAll(posix.split(posix.join(outputDirPath, file))));
-        if (expectedContents != outputFile.readAsStringSync()) {
+        String actualContents = outputFile.readAsStringSync();
+        // Normalize Windows line endings to Unix line endings so that the
+        // comparison doesn't fail on Windows.
+        actualContents = actualContents.replaceAll('\r\n', '\n');
+        if (expectedContents != actualContents) {
           return false;
         }
       }
@@ -370,7 +374,11 @@
   bool check() {
     String expectedContents = computeContents();
     try {
-      return expectedContents == outputFile.readAsStringSync();
+      String actualContents = outputFile.readAsStringSync();
+      // Normalize Windows line endings to Unix line endings so that the
+      // comparison doesn't fail on Windows.
+      actualContents = actualContents.replaceAll('\r\n', '\n');
+      return expectedContents == actualContents;
     } catch (e) {
       // There was a problem reading the file (most likely because it didn't
       // exist).  Treat that the same as if the file doesn't have the expected
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 62c158b..899d6c5 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -139,6 +139,20 @@
   Context get pathContext;
 
   /**
+   * Return a [File] that corresponds to the given [path].
+   * 
+   * A file may or may not exist at this location.
+   */
+  File getFile(String path);
+
+  /**
+   * Return a [Folder] that corresponds to the given [path].
+   * 
+   * A folder may or may not exist at this location.
+   */
+  Folder getFolder(String path);
+
+  /**
    * Return the [Resource] that corresponds to the given [path].
    */
   Resource getResource(String path);
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index b0a5469..8ce2472 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -65,6 +65,12 @@
   }
 
   @override
+  File getFile(String path) => new _MemoryFile(this, path);
+
+  @override
+  Folder getFolder(String path) => newFolder(path);
+
+  @override
   Resource getResource(String path) {
     path = posix.normalize(path);
     Resource resource = _pathToResource[path];
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index d9497df..b8fdcf1 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -41,13 +41,17 @@
   Context get pathContext => io.Platform.isWindows ? windows : posix;
 
   @override
+  File getFile(String path) => new _PhysicalFile(new io.File(path));
+
+  @override
+  Folder getFolder(String path) => new _PhysicalFolder(new io.Directory(path));
+
+  @override
   Resource getResource(String path) {
     if (io.FileSystemEntity.isDirectorySync(path)) {
-      io.Directory directory = new io.Directory(path);
-      return new _PhysicalFolder(directory);
+      return getFolder(path);
     } else {
-      io.File file = new io.File(path);
-      return new _PhysicalFile(file);
+      return getFile(path);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index b211067..0d67817 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -319,6 +319,22 @@
   List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList();
 
   /**
+   * Notifies the entry that the client is going to stop using it.
+   */
+  void dispose() {
+    _resultMap.forEach((descriptor, data) {
+      TargetedResult result = new TargetedResult(target, descriptor);
+      for (TargetedResult dependedOnResult in data.dependedOnResults) {
+        ResultData dependedOnData = _partition._getDataFor(dependedOnResult);
+        if (dependedOnData != null) {
+          dependedOnData.dependentResults.remove(result);
+        }
+      }
+    });
+    _resultMap.clear();
+  }
+
+  /**
    * Fix the state of the [exception] to match the current state of the entry.
    */
   void fixExceptionState() {
@@ -520,7 +536,7 @@
     // Stop depending on other results.
     TargetedResult thisResult = new TargetedResult(target, descriptor);
     for (TargetedResult dependedOnResult in thisData.dependedOnResults) {
-      ResultData data = _partition._getDataFor(dependedOnResult, orNull: true);
+      ResultData data = _partition._getDataFor(dependedOnResult);
       if (data != null) {
         data.dependentResults.remove(thisResult);
       }
@@ -559,14 +575,14 @@
   void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
       List<TargetedResult> dependedOn) {
     thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
-      ResultData data = _partition._getDataFor(dependedOnResult, orNull: true);
+      ResultData data = _partition._getDataFor(dependedOnResult);
       if (data != null) {
         data.dependentResults.remove(thisResult);
       }
     });
     thisData.dependedOnResults = dependedOn;
     thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) {
-      ResultData data = _partition._getDataFor(dependedOnResult, orNull: true);
+      ResultData data = _partition._getDataFor(dependedOnResult);
       if (data != null) {
         data.dependentResults.add(thisResult);
       }
@@ -829,6 +845,16 @@
       _onResultInvalidated.stream;
 
   /**
+   * Notifies the partition that the client is going to stop using it.
+   */
+  void dispose() {
+    for (CacheEntry entry in _targetMap.values) {
+      entry.dispose();
+    }
+    _targetMap.clear();
+  }
+
+  /**
    * Return the entry associated with the given [target].
    */
   CacheEntry get(AnalysisTarget target) => _targetMap[target];
@@ -929,13 +955,9 @@
     }
   }
 
-  ResultData _getDataFor(TargetedResult result, {bool orNull: false}) {
+  ResultData _getDataFor(TargetedResult result) {
     CacheEntry entry = context.analysisCache.get(result.target);
-    if (orNull) {
-      return entry != null ? entry._resultMap[result.result] : null;
-    } else {
-      return entry.getResultData(result.result);
-    }
+    return entry != null ? entry._resultMap[result.result] : null;
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index a0e7f1f..095c293 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -678,6 +678,7 @@
       }
     }
     _pendingFutureTargets.clear();
+    _privatePartition.dispose();
   }
 
   @override
@@ -954,7 +955,7 @@
     }
     bool changed = newContents != originalContents;
     if (newContents != null) {
-      if (newContents != originalContents) {
+      if (changed) {
         if (!analysisOptions.incremental ||
             !_tryPoorMansIncrementalResolution(source, newContents)) {
           _sourceChanged(source);
@@ -965,22 +966,24 @@
         entry.modificationTime = _contentCache.getModificationStamp(source);
       }
     } else if (originalContents != null) {
-      changed = newContents != originalContents;
       // We are removing the overlay for the file, check if the file's
       // contents is the same as it was in the overlay.
       try {
         TimestampedData<String> fileContents = getContents(source);
-        String fileContentsData = fileContents.data;
-        if (fileContentsData == originalContents) {
-          entry.setValue(CONTENT, fileContentsData, TargetedResult.EMPTY_LIST);
-          entry.modificationTime = fileContents.modificationTime;
+        newContents = fileContents.data;
+        entry.modificationTime = fileContents.modificationTime;
+        if (newContents == originalContents) {
+          entry.setValue(CONTENT, newContents, TargetedResult.EMPTY_LIST);
           changed = false;
         }
       } catch (e) {}
       // If not the same content (e.g. the file is being closed without save),
       // then force analysis.
       if (changed) {
-        _sourceChanged(source);
+        if (!analysisOptions.incremental ||
+            !_tryPoorMansIncrementalResolution(source, newContents)) {
+          _sourceChanged(source);
+        }
       }
     }
     if (notify && changed) {
@@ -1094,7 +1097,6 @@
       setValue(LIBRARY_ELEMENT3, library);
       setValue(LIBRARY_ELEMENT4, library);
       setValue(LIBRARY_ELEMENT5, library);
-      setValue(LIBRARY_ELEMENT6, library);
       setValue(LINE_INFO, new LineInfo(<int>[0]));
       setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
       entry.setState(PARSED_UNIT, CacheState.FLUSHED);
@@ -1718,8 +1720,8 @@
               dartDelta.hasDirectiveChange = unitDelta.hasDirectiveChange;
               unitDelta.addedDeclarations.forEach(dartDelta.elementAdded);
               unitDelta.removedDeclarations.forEach(dartDelta.elementRemoved);
-              print(
-                  'dartDelta: add=${dartDelta.addedNames} remove=${dartDelta.removedNames}');
+//              print(
+//                  'dartDelta: add=${dartDelta.addedNames} remove=${dartDelta.removedNames}');
               delta = dartDelta;
               entry.setState(CONTENT, CacheState.INVALID, delta: delta);
               return;
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 52ef4f5..24344aa 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -501,9 +501,15 @@
   List<PropertyAccessorElement> _accessors = PropertyAccessorElement.EMPTY_LIST;
 
   /**
-   * A list containing all of the constructors contained in this class.
+   * For classes which are not mixin applications, a list containing all of the
+   * constructors contained in this class, or `null` if the list of
+   * constructors has not yet been built.
+   *
+   * For classes which are mixin applications, the list of constructors is
+   * computed on the fly by the [constructors] getter, and this field is
+   * `null`.
    */
-  List<ConstructorElement> _constructors = ConstructorElement.EMPTY_LIST;
+  List<ConstructorElement> _constructors;
 
   /**
    * A list containing all of the fields contained in this class.
@@ -586,12 +592,24 @@
   }
 
   @override
-  List<ConstructorElement> get constructors => _constructors;
+  List<ConstructorElement> get constructors {
+    if (!isMixinApplication) {
+      assert(_constructors != null);
+      return _constructors == null
+          ? ConstructorElement.EMPTY_LIST
+          : _constructors;
+    }
+
+    return _computeMixinAppConstructors();
+  }
 
   /**
    * Set the constructors contained in this class to the given [constructors].
+   *
+   * Should only be used for class elements that are not mixin applications.
    */
   void set constructors(List<ConstructorElement> constructors) {
+    assert(!isMixinApplication);
     for (ConstructorElement constructor in constructors) {
       (constructor as ConstructorElementImpl).enclosingElement = this;
     }
@@ -599,6 +617,50 @@
   }
 
   /**
+   * Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
+   * be reported for this class.
+   */
+  bool get doesMixinLackConstructors {
+    if (!isMixinApplication && mixins.isEmpty) {
+      // This class is not a mixin application and it doesn't have a "with"
+      // clause, so CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS is
+      // inapplicable.
+      return false;
+    }
+    if (supertype == null) {
+      // Should never happen, since Object is the only class that has no
+      // supertype, and it should have been caught by the test above.
+      assert(false);
+      return false;
+    }
+    // Find the nearest class in the supertype chain that is not a mixin
+    // application.
+    ClassElement nearestNonMixinClass = supertype.element;
+    if (nearestNonMixinClass.isMixinApplication) {
+      // Use a list to keep track of the classes we've seen, so that we won't
+      // go into an infinite loop in the event of a non-trivial loop in the
+      // class hierarchy.
+      List<ClassElementImpl> classesSeen = <ClassElementImpl>[this];
+      while (nearestNonMixinClass.isMixinApplication) {
+        if (classesSeen.contains(nearestNonMixinClass)) {
+          // Loop in the class hierarchy (which is reported elsewhere).  Don't
+          // confuse the user with further errors.
+          return false;
+        }
+        classesSeen.add(nearestNonMixinClass);
+        if (nearestNonMixinClass.supertype == null) {
+          // Should never happen, since Object is the only class that has no
+          // supertype, and it is not a mixin application.
+          assert(false);
+          return false;
+        }
+        nearestNonMixinClass = nearestNonMixinClass.supertype.element;
+      }
+    }
+    return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
+  }
+
+  /**
    * Set whether this class is defined by an enum declaration.
    */
   void set enum2(bool isEnum) {
@@ -732,16 +794,6 @@
     setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
   }
 
-  bool get mixinErrorsReported => hasModifier(Modifier.MIXIN_ERRORS_REPORTED);
-
-  /**
-   * Set whether an error has reported explaining why this class is an
-   * invalid mixin application.
-   */
-  void set mixinErrorsReported(bool value) {
-    setModifier(Modifier.MIXIN_ERRORS_REPORTED, value);
-  }
-
   @override
   List<TypeParameterElement> get typeParameters => _typeParameters;
 
@@ -996,6 +1048,103 @@
     }
   }
 
+  /**
+   * Compute a list of constructors for this class, which is a mixin
+   * application.  If specified, [visitedClasses] is a list of the other mixin
+   * application classes which have been visited on the way to reaching this
+   * one (this is used to detect circularities).
+   */
+  List<ConstructorElement> _computeMixinAppConstructors(
+      [List<ClassElementImpl> visitedClasses = null]) {
+    // First get the list of constructors of the superclass which need to be
+    // forwarded to this class.
+    Iterable<ConstructorElement> constructorsToForward;
+    if (supertype == null) {
+      // Shouldn't ever happen, since the only class with no supertype is
+      // Object, and it isn't a mixin application.  But for safety's sake just
+      // assume an empty list.
+      assert(false);
+      constructorsToForward = <ConstructorElement>[];
+    } else if (!supertype.element.isMixinApplication) {
+      List<ConstructorElement> superclassConstructors =
+          supertype.element.constructors;
+      // Filter out any constructors with optional parameters (see
+      // dartbug.com/15101).
+      constructorsToForward =
+          superclassConstructors.where(isSuperConstructorAccessible);
+    } else {
+      if (visitedClasses == null) {
+        visitedClasses = <ClassElementImpl>[this];
+      } else {
+        if (visitedClasses.contains(this)) {
+          // Loop in the class hierarchy.  Don't try to forward any
+          // constructors.
+          return <ConstructorElement>[];
+        }
+        visitedClasses.add(this);
+      }
+      try {
+        ClassElementImpl superclass = supertype.element;
+        constructorsToForward =
+            superclass._computeMixinAppConstructors(visitedClasses);
+      } finally {
+        visitedClasses.removeLast();
+      }
+    }
+
+    // Figure out the type parameter substitution we need to perform in order
+    // to produce constructors for this class.  We want to be robust in the
+    // face of errors, so drop any extra type arguments and fill in any missing
+    // ones with `dynamic`.
+    List<DartType> parameterTypes =
+        TypeParameterTypeImpl.getTypes(supertype.typeParameters);
+    List<DartType> argumentTypes = new List<DartType>.filled(
+        parameterTypes.length, DynamicTypeImpl.instance);
+    for (int i = 0; i < supertype.typeArguments.length; i++) {
+      if (i >= argumentTypes.length) {
+        break;
+      }
+      argumentTypes[i] = supertype.typeArguments[i];
+    }
+
+    // Now create an implicit constructor for every constructor found above,
+    // substituting type parameters as appropriate.
+    return constructorsToForward
+        .map((ConstructorElement superclassConstructor) {
+      ConstructorElementImpl implicitConstructor =
+          new ConstructorElementImpl(superclassConstructor.name, -1);
+      implicitConstructor.synthetic = true;
+      implicitConstructor.redirectedConstructor = superclassConstructor;
+      implicitConstructor.const2 = superclassConstructor.isConst;
+      implicitConstructor.returnType = type;
+      List<ParameterElement> superParameters = superclassConstructor.parameters;
+      int count = superParameters.length;
+      if (count > 0) {
+        List<ParameterElement> implicitParameters =
+            new List<ParameterElement>(count);
+        for (int i = 0; i < count; i++) {
+          ParameterElement superParameter = superParameters[i];
+          ParameterElementImpl implicitParameter =
+              new ParameterElementImpl(superParameter.name, -1);
+          implicitParameter.const3 = superParameter.isConst;
+          implicitParameter.final2 = superParameter.isFinal;
+          implicitParameter.parameterKind = superParameter.parameterKind;
+          implicitParameter.synthetic = true;
+          implicitParameter.type =
+              superParameter.type.substitute2(argumentTypes, parameterTypes);
+          implicitParameters[i] = implicitParameter;
+        }
+        implicitConstructor.parameters = implicitParameters;
+      }
+      FunctionTypeImpl constructorType =
+          new FunctionTypeImpl(implicitConstructor);
+      constructorType.typeArguments = type.typeArguments;
+      implicitConstructor.type = constructorType;
+      implicitConstructor.enclosingElement = this;
+      return implicitConstructor;
+    }).toList();
+  }
+
   PropertyAccessorElement _internalLookUpConcreteGetter(
       String getterName, LibraryElement library, bool includeThisClass) {
     PropertyAccessorElement getter =
@@ -8073,41 +8222,34 @@
       const Modifier('MIXIN_APPLICATION', 12);
 
   /**
-   * Indicates that an error has reported explaining why this class is an
-   * invalid mixin application.
-   */
-  static const Modifier MIXIN_ERRORS_REPORTED =
-      const Modifier('MIXIN_ERRORS_REPORTED', 13);
-
-  /**
    * Indicates that the value of a parameter or local variable might be mutated
    * within the context.
    */
   static const Modifier POTENTIALLY_MUTATED_IN_CONTEXT =
-      const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 14);
+      const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 13);
 
   /**
    * Indicates that the value of a parameter or local variable might be mutated
    * within the scope.
    */
   static const Modifier POTENTIALLY_MUTATED_IN_SCOPE =
-      const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 15);
+      const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 14);
 
   /**
    * Indicates that a class contains an explicit reference to 'super'.
    */
   static const Modifier REFERENCES_SUPER =
-      const Modifier('REFERENCES_SUPER', 16);
+      const Modifier('REFERENCES_SUPER', 15);
 
   /**
    * Indicates that the pseudo-modifier 'set' was applied to the element.
    */
-  static const Modifier SETTER = const Modifier('SETTER', 17);
+  static const Modifier SETTER = const Modifier('SETTER', 16);
 
   /**
    * Indicates that the modifier 'static' was applied to the element.
    */
-  static const Modifier STATIC = const Modifier('STATIC', 18);
+  static const Modifier STATIC = const Modifier('STATIC', 17);
 
   /**
    * Indicates that the element does not appear in the source code but was
@@ -8115,7 +8257,7 @@
    * constructors, an implicit zero-argument constructor will be created and it
    * will be marked as being synthetic.
    */
-  static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 19);
+  static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 18);
 
   static const List<Modifier> values = const [
     ABSTRACT,
@@ -8131,7 +8273,6 @@
     HAS_EXT_URI,
     MIXIN,
     MIXIN_APPLICATION,
-    MIXIN_ERRORS_REPORTED,
     POTENTIALLY_MUTATED_IN_CONTEXT,
     POTENTIALLY_MUTATED_IN_SCOPE,
     REFERENCES_SUPER,
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index c047654..b93931f 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -1049,7 +1049,7 @@
     ConstructorElement element =
         superType.lookUpConstructor(superName, _definingLibrary);
     if (element == null ||
-        (!enclosingClass.mixinErrorsReported &&
+        (!enclosingClass.doesMixinLackConstructors &&
             !enclosingClass.isSuperConstructorAccessible(element))) {
       if (name != null) {
         _resolver.reportErrorForNode(
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 7d3f7e6..5195922 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -2170,7 +2170,7 @@
     }
     bool changed = newContents != originalContents;
     if (newContents != null) {
-      if (newContents != originalContents) {
+      if (changed) {
         _incrementalAnalysisCache =
             IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
         if (!analysisOptions.incremental ||
@@ -2187,22 +2187,24 @@
     } else if (originalContents != null) {
       _incrementalAnalysisCache =
           IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
-      changed = newContents != originalContents;
       // We are removing the overlay for the file, check if the file's
       // contents is the same as it was in the overlay.
       try {
         TimestampedData<String> fileContents = getContents(source);
-        String fileContentsData = fileContents.data;
-        if (fileContentsData == originalContents) {
-          sourceEntry.setValue(SourceEntry.CONTENT, fileContentsData);
-          sourceEntry.modificationTime = fileContents.modificationTime;
+        newContents = fileContents.data;
+        sourceEntry.modificationTime = fileContents.modificationTime;
+        if (newContents == originalContents) {
+          sourceEntry.setValue(SourceEntry.CONTENT, newContents);
           changed = false;
         }
       } catch (e) {}
       // If not the same content (e.g. the file is being closed without save),
       // then force analysis.
       if (changed) {
-        _sourceChanged(source);
+        if (!analysisOptions.incremental ||
+            !_tryPoorMansIncrementalResolution(source, newContents)) {
+          _sourceChanged(source);
+        }
       }
     }
     if (notify && changed) {
@@ -2222,7 +2224,7 @@
     // Prepare sources to invalidate hints in.
     List<Source> sources = <Source>[librarySource];
     sources.addAll(dartEntry.getValue(DartEntry.INCLUDED_PARTS));
-    // Invalidate hints.
+    // Invalidate hints and lints.
     for (Source source in sources) {
       DartEntry dartEntry = _cache.get(source);
       if (dartEntry.getStateInLibrary(DartEntry.HINTS, librarySource) ==
@@ -2230,6 +2232,11 @@
         dartEntry.setStateInLibrary(
             DartEntry.HINTS, librarySource, CacheState.INVALID);
       }
+      if (dartEntry.getStateInLibrary(DartEntry.LINTS, librarySource) ==
+          CacheState.VALID) {
+        dartEntry.setStateInLibrary(
+            DartEntry.LINTS, librarySource, CacheState.INVALID);
+      }
     }
   }
 
@@ -10728,7 +10735,7 @@
     // Resolve the type names.
     //
     RecordingErrorListener errorListener = new RecordingErrorListener();
-    TypeResolverVisitor typeResolverVisitor = new TypeResolverVisitor.con2(
+    TypeResolverVisitor typeResolverVisitor = new TypeResolverVisitor(
         _libraryElement, source, typeProvider, errorListener);
     unit.accept(typeResolverVisitor);
     //
@@ -10736,8 +10743,9 @@
     //
     InheritanceManager inheritanceManager =
         new InheritanceManager(_libraryElement);
-    ResolverVisitor resolverVisitor = new ResolverVisitor.con2(_libraryElement,
-        source, typeProvider, inheritanceManager, errorListener);
+    ResolverVisitor resolverVisitor = new ResolverVisitor(
+        _libraryElement, source, typeProvider, errorListener,
+        inheritanceManager: inheritanceManager);
     unit.accept(resolverVisitor);
     //
     // Perform additional error checking.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 85ea901..e80e02a 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -422,6 +422,7 @@
           _checkForConflictingInstanceGetterAndSuperclassMember();
           _checkImplementsSuperClass(node);
           _checkImplementsFunctionWithoutCall(node);
+          _checkForMixinHasNoConstructors(node);
         }
       }
       visitClassDeclarationIncrementally(node);
@@ -474,6 +475,7 @@
         _checkForImplementsDeferredClass(implementsClause);
         _checkForRecursiveInterfaceInheritance(_enclosingClass);
         _checkForNonAbstractClassInheritsAbstractMember(node.name);
+        _checkForMixinHasNoConstructors(node);
       }
     } finally {
       _enclosingClass = outerClassElement;
@@ -4165,6 +4167,18 @@
   }
 
   /**
+   * Report the error [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] if
+   * appropriate.
+   */
+  void _checkForMixinHasNoConstructors(AstNode node) {
+    if ((_enclosingClass as ClassElementImpl).doesMixinLackConstructors) {
+      ErrorCode errorCode = CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS;
+      _errorReporter.reportErrorForNode(
+          errorCode, node, [_enclosingClass.supertype]);
+    }
+  }
+
+  /**
    * Verify that the given mixin has the 'Object' superclass. The [mixinName] is
    * the node to report problem on. The [mixinElement] is the mixing to
    * evaluate.
@@ -4290,7 +4304,7 @@
       ClassDeclaration declaration) {
     // do nothing if mixin errors have already been reported for this class.
     ClassElementImpl enclosingClass = _enclosingClass;
-    if (enclosingClass.mixinErrorsReported) {
+    if (enclosingClass.doesMixinLackConstructors) {
       return false;
     }
     // do nothing if there is explicit constructor
@@ -5183,7 +5197,7 @@
     }
     // do nothing if mixin errors have already been reported for this class.
     ClassElementImpl enclosingClass = _enclosingClass;
-    if (enclosingClass.mixinErrorsReported) {
+    if (enclosingClass.doesMixinLackConstructors) {
       return false;
     }
     //
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 3cc0626..33f470f 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -184,7 +184,6 @@
     _enclosingClass = element;
     _processElement(element);
     _assertSameTypeParameters(node.typeParameters, element.typeParameters);
-    _processElement(element.unnamedConstructor);
     super.visitClassTypeAlias(node);
   }
 
@@ -900,7 +899,6 @@
 
   List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
   List<AnalysisError> _verifyErrors = AnalysisError.NO_ERRORS;
-  List<AnalysisError> _lints = AnalysisError.NO_ERRORS;
 
   /**
    * Initialize a newly created incremental resolver to resolve a node in the
@@ -942,7 +940,6 @@
       // verify
       _verify(rootNode);
       _context.invalidateLibraryHints(_librarySource);
-      _generateLints(rootNode);
       // update entry errors
       _updateEntry();
       // notify unit
@@ -1054,24 +1051,6 @@
     throw new AnalysisException("Cannot resolve node: no resolvable node");
   }
 
-  void _generateLints(AstNode node) {
-    LoggingTimer timer = logger.startTimer();
-    try {
-      if (_context.analysisOptions.lint) {
-        RecordingErrorListener errorListener = new RecordingErrorListener();
-        CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
-        LintGenerator lintGenerator =
-            new LintGenerator(<CompilationUnit>[unit], errorListener);
-        lintGenerator.generate();
-        _lints = errorListener.getErrorsForSource(_source);
-      } else {
-        _lints = AnalysisError.NO_ERRORS;
-      }
-    } finally {
-      timer.stop('generate lints');
-    }
-  }
-
   /**
    * Return the element defined by [node], or `null` if the node does not
    * define an element.
@@ -1099,20 +1078,23 @@
       Scope scope = _resolutionContext.scope;
       // resolve types
       {
-        TypeResolverVisitor visitor = new TypeResolverVisitor.con3(
-            _definingLibrary, _source, _typeProvider, scope, errorListener);
+        TypeResolverVisitor visitor = new TypeResolverVisitor(
+            _definingLibrary, _source, _typeProvider, errorListener,
+            nameScope: scope);
         node.accept(visitor);
       }
       // resolve variables
       {
-        VariableResolverVisitor visitor = new VariableResolverVisitor.con2(
-            _definingLibrary, _source, _typeProvider, scope, errorListener);
+        VariableResolverVisitor visitor = new VariableResolverVisitor(
+            _definingLibrary, _source, _typeProvider, errorListener,
+            nameScope: scope);
         node.accept(visitor);
       }
       // resolve references
       {
-        ResolverVisitor visitor = new ResolverVisitor.con3(
-            _definingLibrary, _source, _typeProvider, scope, errorListener);
+        ResolverVisitor visitor = new ResolverVisitor(
+            _definingLibrary, _source, _typeProvider, errorListener,
+            nameScope: scope);
         if (_resolutionContext.enclosingClassDeclaration != null) {
           visitor.visitClassDeclarationIncrementally(
               _resolutionContext.enclosingClassDeclaration);
@@ -1202,21 +1184,8 @@
   }
 
   void _updateEntry_OLD() {
-    {
-      List<AnalysisError> oldErrors = oldEntry.getValueInLibrary(
-          DartEntry.RESOLUTION_ERRORS, _librarySource);
-      List<AnalysisError> errors = _updateErrors(oldErrors, _resolveErrors);
-      oldEntry.setValueInLibrary(
-          DartEntry.RESOLUTION_ERRORS, _librarySource, errors);
-    }
-    {
-      List<AnalysisError> oldErrors = oldEntry.getValueInLibrary(
-          DartEntry.VERIFICATION_ERRORS, _librarySource);
-      List<AnalysisError> errors = _updateErrors(oldErrors, _verifyErrors);
-      oldEntry.setValueInLibrary(
-          DartEntry.VERIFICATION_ERRORS, _librarySource, errors);
-    }
-    oldEntry.setValueInLibrary(DartEntry.LINTS, _librarySource, _lints);
+    _updateErrors_OLD(DartEntry.RESOLUTION_ERRORS, _resolveErrors);
+    _updateErrors_OLD(DartEntry.VERIFICATION_ERRORS, _verifyErrors);
   }
 
   List<AnalysisError> _updateErrors(
@@ -1250,6 +1219,14 @@
     newUnitEntry.setValueIncremental(descriptor, errors);
   }
 
+  void _updateErrors_OLD(DataDescriptor<List<AnalysisError>> descriptor,
+      List<AnalysisError> newErrors) {
+    List<AnalysisError> oldErrors =
+        oldEntry.getValueInLibrary(descriptor, _librarySource);
+    List<AnalysisError> errors = _updateErrors(oldErrors, newErrors);
+    oldEntry.setValueInLibrary(descriptor, _librarySource, errors);
+  }
+
   void _verify(AstNode node) {
     LoggingTimer timer = logger.startTimer();
     try {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 422a8e2..c01e769 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -5,9 +5,6 @@
 library engine.resolver;
 
 import 'dart:collection';
-import "dart:math" as math;
-
-import 'package:analyzer/src/generated/utilities_collection.dart';
 
 import 'ast.dart';
 import 'constant.dart';
@@ -2506,7 +2503,6 @@
     interfaceType.typeArguments = typeArguments;
     element.type = interfaceType;
     // set default constructor
-    element.constructors = _createDefaultConstructors(interfaceType);
     for (FunctionTypeImpl functionType in _functionTypesToFix) {
       functionType.typeArguments = typeArguments;
     }
@@ -2631,6 +2627,11 @@
     enumElement.enum2 = true;
     InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
     enumElement.type = enumType;
+    // The equivalent code for enums in the spec shows a single constructor,
+    // but that constructor is not callable (since it is a compile-time error
+    // to subclass, mix-in, implement, or explicitly instantiate an enum).  So
+    // we represent this as having no constructors.
+    enumElement.constructors = ConstructorElement.EMPTY_LIST;
     _currentHolder.addEnum(enumElement);
     enumName.staticElement = enumElement;
     return super.visitEnumDeclaration(node);
@@ -5145,275 +5146,6 @@
 }
 
 /**
- * Instances of the class `ImplicitConstructorBuilder` are used to build
- * implicit constructors for mixin applications, and to check for errors
- * related to super constructor calls in class declarations with mixins.
- *
- * The visitor methods don't directly build the implicit constructors or check
- * for errors, since they don't in general visit the classes in the proper
- * order to do so correctly.  Instead, they pass closures to
- * ImplicitConstructorBuilderCallback to inform it of the computations to be
- * done and their ordering dependencies.
- */
-class ImplicitConstructorBuilder extends SimpleElementVisitor {
-  final AnalysisErrorListener errorListener;
-
-  /**
-   * Callback to receive the computations to be performed.
-   */
-  final ImplicitConstructorBuilderCallback _callback;
-
-  /**
-   * Initialize a newly created visitor to build implicit constructors.
-   *
-   * The visit methods will pass closures to [_callback] to indicate what
-   * computation needs to be performed, and its dependency order.
-   */
-  ImplicitConstructorBuilder(this.errorListener, this._callback);
-
-  @override
-  void visitClassElement(ClassElement classElement) {
-    (classElement as ClassElementImpl).mixinErrorsReported = false;
-    if (classElement.isMixinApplication) {
-      _visitClassTypeAlias(classElement);
-    } else {
-      _visitClassDeclaration(classElement);
-    }
-  }
-
-  @override
-  void visitCompilationUnitElement(CompilationUnitElement element) {
-    element.types.forEach(visitClassElement);
-  }
-
-  @override
-  void visitLibraryElement(LibraryElement element) {
-    element.units.forEach(visitCompilationUnitElement);
-  }
-
-  /**
-   * Create an implicit constructor that is copied from the given constructor, but that is in the
-   * given class.
-   *
-   * @param classType the class in which the implicit constructor is defined
-   * @param explicitConstructor the constructor on which the implicit constructor is modeled
-   * @param parameterTypes the types to be replaced when creating parameters
-   * @param argumentTypes the types with which the parameters are to be replaced
-   * @return the implicit constructor that was created
-   */
-  ConstructorElement _createImplicitContructor(InterfaceType classType,
-      ConstructorElement explicitConstructor, List<DartType> parameterTypes,
-      List<DartType> argumentTypes) {
-    ConstructorElementImpl implicitConstructor =
-        new ConstructorElementImpl(explicitConstructor.name, -1);
-    implicitConstructor.synthetic = true;
-    implicitConstructor.redirectedConstructor = explicitConstructor;
-    implicitConstructor.const2 = explicitConstructor.isConst;
-    implicitConstructor.returnType = classType;
-    List<ParameterElement> explicitParameters = explicitConstructor.parameters;
-    int count = explicitParameters.length;
-    if (count > 0) {
-      List<ParameterElement> implicitParameters =
-          new List<ParameterElement>(count);
-      for (int i = 0; i < count; i++) {
-        ParameterElement explicitParameter = explicitParameters[i];
-        ParameterElementImpl implicitParameter =
-            new ParameterElementImpl(explicitParameter.name, -1);
-        implicitParameter.const3 = explicitParameter.isConst;
-        implicitParameter.final2 = explicitParameter.isFinal;
-        implicitParameter.parameterKind = explicitParameter.parameterKind;
-        implicitParameter.synthetic = true;
-        implicitParameter.type =
-            explicitParameter.type.substitute2(argumentTypes, parameterTypes);
-        implicitParameters[i] = implicitParameter;
-      }
-      implicitConstructor.parameters = implicitParameters;
-    }
-    FunctionTypeImpl type = new FunctionTypeImpl(implicitConstructor);
-    type.typeArguments = classType.typeArguments;
-    implicitConstructor.type = type;
-    return implicitConstructor;
-  }
-
-  /**
-   * Find all the constructors that should be forwarded from the given
-   * [superType], to the class or mixin application [classElement],
-   * and pass information about them to [callback].
-   *
-   * Return true if some constructors were considered.  (A false return value
-   * can only happen if the supeclass is a built-in type, in which case it
-   * can't be used as a mixin anyway).
-   */
-  bool _findForwardedConstructors(ClassElementImpl classElement,
-      InterfaceType superType, void callback(
-          ConstructorElement explicitConstructor, List<DartType> parameterTypes,
-          List<DartType> argumentTypes)) {
-    ClassElement superclassElement = superType.element;
-    List<ConstructorElement> constructors = superclassElement.constructors;
-    int count = constructors.length;
-    if (count == 0) {
-      return false;
-    }
-    List<DartType> parameterTypes =
-        TypeParameterTypeImpl.getTypes(superType.typeParameters);
-    List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes);
-    for (int i = 0; i < count; i++) {
-      ConstructorElement explicitConstructor = constructors[i];
-      if (!explicitConstructor.isFactory &&
-          classElement.isSuperConstructorAccessible(explicitConstructor)) {
-        callback(explicitConstructor, parameterTypes, argumentTypes);
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Return a list of argument types that corresponds to the [parameterTypes]
-   * and that are derived from the type arguments of the given [superType].
-   */
-  List<DartType> _getArgumentTypes(
-      InterfaceType superType, List<DartType> parameterTypes) {
-    DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
-    int parameterCount = parameterTypes.length;
-    List<DartType> types = new List<DartType>(parameterCount);
-    if (superType == null) {
-      types = new List<DartType>.filled(parameterCount, dynamic);
-    } else {
-      List<DartType> typeArguments = superType.typeArguments;
-      int argumentCount = math.min(typeArguments.length, parameterCount);
-      for (int i = 0; i < argumentCount; i++) {
-        types[i] = typeArguments[i];
-      }
-      for (int i = argumentCount; i < parameterCount; i++) {
-        types[i] = dynamic;
-      }
-    }
-    return types;
-  }
-
-  void _visitClassDeclaration(ClassElementImpl classElement) {
-    DartType superType = classElement.supertype;
-    if (superType != null && classElement.mixins.isNotEmpty) {
-      // We don't need to build any implicitly constructors for the mixin
-      // application (since there isn't an explicit element for it), but we
-      // need to verify that they _could_ be built.
-      if (superType is! InterfaceType) {
-        TypeProvider typeProvider = classElement.context.typeProvider;
-        superType = typeProvider.objectType;
-      }
-      ClassElement superElement = superType.element;
-      if (superElement != null) {
-        _callback(classElement, superElement, () {
-          bool constructorFound = false;
-          void callback(ConstructorElement explicitConstructor,
-              List<DartType> parameterTypes, List<DartType> argumentTypes) {
-            constructorFound = true;
-          }
-          if (_findForwardedConstructors(classElement, superType, callback) &&
-              !constructorFound) {
-            SourceRange withRange = classElement.withClauseRange;
-            errorListener.onError(new AnalysisError(classElement.source,
-                withRange.offset, withRange.length,
-                CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
-                [superElement.name]));
-            classElement.mixinErrorsReported = true;
-          }
-        });
-      }
-    }
-  }
-
-  void _visitClassTypeAlias(ClassElementImpl classElement) {
-    InterfaceType superType = classElement.supertype;
-    if (superType is InterfaceType) {
-      ClassElement superElement = superType.element;
-      _callback(classElement, superElement, () {
-        List<ConstructorElement> implicitConstructors =
-            new List<ConstructorElement>();
-        void callback(ConstructorElement explicitConstructor,
-            List<DartType> parameterTypes, List<DartType> argumentTypes) {
-          implicitConstructors.add(_createImplicitContructor(classElement.type,
-              explicitConstructor, parameterTypes, argumentTypes));
-        }
-        if (_findForwardedConstructors(classElement, superType, callback)) {
-          if (implicitConstructors.isEmpty) {
-            errorListener.onError(new AnalysisError(classElement.source,
-                classElement.nameOffset, classElement.name.length,
-                CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
-                [superElement.name]));
-          } else {
-            classElement.constructors = implicitConstructors;
-          }
-        }
-      });
-    }
-  }
-}
-
-/**
- * An instance of this class is capable of running ImplicitConstructorBuilder
- * over all classes in a library cycle.
- */
-class ImplicitConstructorComputer {
-  /**
-   * Directed graph of dependencies between classes that need to have their
-   * implicit constructors computed.  Each edge in the graph points from a
-   * derived class to its superclass.  Implicit constructors will be computed
-   * for the superclass before they are compute for the derived class.
-   */
-  DirectedGraph<ClassElement> _dependencies = new DirectedGraph<ClassElement>();
-
-  /**
-   * Map from ClassElement to the function which will compute the class's
-   * implicit constructors.
-   */
-  Map<ClassElement, VoidFunction> _computations =
-      new HashMap<ClassElement, VoidFunction>();
-
-  /**
-   * Add the given [libraryElement] to the list of libraries which need to have
-   * implicit constructors built for them.
-   */
-  void add(AnalysisErrorListener errorListener, LibraryElement libraryElement) {
-    libraryElement
-        .accept(new ImplicitConstructorBuilder(errorListener, _defer));
-  }
-
-  /**
-   * Compute the implicit constructors for all compilation units that have been
-   * passed to [add].
-   */
-  void compute() {
-    List<List<ClassElement>> topologicalSort =
-        _dependencies.computeTopologicalSort();
-    for (List<ClassElement> classesInCycle in topologicalSort) {
-      // Note: a cycle could occur if there is a loop in the inheritance graph.
-      // Such loops are forbidden by Dart but could occur in the analysis of
-      // incorrect code.  If this happens, we simply visit the classes
-      // constituting the loop in any order.
-      for (ClassElement classElement in classesInCycle) {
-        VoidFunction computation = _computations[classElement];
-        if (computation != null) {
-          computation();
-        }
-      }
-    }
-  }
-
-  /**
-   * Defer execution of [computation], which builds implicit constructors for
-   * [classElement], until after implicit constructors have been built for
-   * [superclassElement].
-   */
-  void _defer(ClassElement classElement, ClassElement superclassElement,
-      void computation()) {
-    assert(!_computations.containsKey(classElement));
-    _computations[classElement] = computation;
-    _dependencies.addEdge(classElement, superclassElement);
-  }
-}
-
-/**
  * Instances of the class `ImplicitLabelScope` represent the scope statements
  * that can be the target of unlabeled break and continue statements.
  */
@@ -6037,9 +5769,14 @@
               String key = map.getKey(j);
               ExecutableElement value = map.getValue(j);
               if (key != null) {
-                if (resultMap.get(key) == null ||
-                    (resultMap.get(key) != null && !_isAbstract(value))) {
-                  resultMap.put(key, value);
+                ClassElement definingClass = value
+                    .getAncestor((Element element) => element is ClassElement);
+                if (!definingClass.type.isObject) {
+                  ExecutableElement existingValue = resultMap.get(key);
+                  if (existingValue == null ||
+                      (existingValue != null && !_isAbstract(value))) {
+                    resultMap.put(key, value);
+                  }
                 }
               }
             }
@@ -6872,7 +6609,7 @@
   /**
    * The listener to which analysis errors will be reported.
    */
-  final AnalysisErrorListener _errorListener;
+  final AnalysisErrorListener errorListener;
 
   /**
    * The source specifying the defining compilation unit of this library.
@@ -6924,7 +6661,7 @@
    * @param errorListener the listener to which analysis errors will be reported
    * @param librarySource the source specifying the defining compilation unit of this library
    */
-  Library(this._analysisContext, this._errorListener, this.librarySource) {
+  Library(this._analysisContext, this.errorListener, this.librarySource) {
     this._libraryElement =
         _analysisContext.getLibraryElement(librarySource) as LibraryElementImpl;
   }
@@ -7063,7 +6800,7 @@
    */
   LibraryScope get libraryScope {
     if (_libraryScope == null) {
-      _libraryScope = new LibraryScope(_libraryElement, _errorListener);
+      _libraryScope = new LibraryScope(_libraryElement, errorListener);
     }
     return _libraryScope;
   }
@@ -7094,7 +6831,7 @@
   Source getSource(UriBasedDirective directive) {
     StringLiteral uriLiteral = directive.uri;
     if (uriLiteral is StringInterpolation) {
-      _errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
+      errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
           uriLiteral.length, CompileTimeErrorCode.URI_WITH_INTERPOLATION));
       return null;
     }
@@ -7111,13 +6848,13 @@
       Source source =
           _analysisContext.sourceFactory.resolveUri(librarySource, uriContent);
       if (!_analysisContext.exists(source)) {
-        _errorListener.onError(new AnalysisError(librarySource,
+        errorListener.onError(new AnalysisError(librarySource,
             uriLiteral.offset, uriLiteral.length,
             CompileTimeErrorCode.URI_DOES_NOT_EXIST, [uriContent]));
       }
       return source;
     } on URISyntaxException {
-      _errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
+      errorListener.onError(new AnalysisError(librarySource, uriLiteral.offset,
           uriLiteral.length, CompileTimeErrorCode.INVALID_URI, [uriContent]));
     }
     return null;
@@ -7917,7 +7654,6 @@
     _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
     _buildEnumMembers();
     _buildTypeHierarchies();
-    _buildImplicitConstructors();
     //
     // Perform resolution and type analysis.
     //
@@ -8198,22 +7934,6 @@
   }
 
   /**
-   * Finish steps that the [buildTypeHierarchies] could not perform, see
-   * [ImplicitConstructorBuilder].
-   *
-   * @throws AnalysisException if any of the type hierarchies could not be resolved
-   */
-  void _buildImplicitConstructors() {
-    PerformanceStatistics.resolve.makeCurrentWhile(() {
-      ImplicitConstructorComputer computer = new ImplicitConstructorComputer();
-      for (Library library in _librariesInCycles) {
-        computer.add(_errorListener, library.libraryElement);
-      }
-      computer.compute();
-    });
-  }
-
-  /**
    * Resolve the type hierarchy across all of the types declared in the libraries in the current
    * cycle.
    *
@@ -8226,7 +7946,9 @@
           TypeResolverVisitorFactory typeResolverVisitorFactory =
               analysisContext.typeResolverVisitorFactory;
           TypeResolverVisitor visitor = (typeResolverVisitorFactory == null)
-              ? new TypeResolverVisitor.con1(library, source, _typeProvider)
+              ? new TypeResolverVisitor(library.libraryElement, source,
+                  _typeProvider, library.errorListener,
+                  nameScope: library.libraryScope)
               : typeResolverVisitorFactory(library, source, _typeProvider);
           library.getAST(source).accept(visitor);
         }
@@ -8485,13 +8207,17 @@
     PerformanceStatistics.resolve.makeCurrentWhile(() {
       for (Source source in library.compilationUnitSources) {
         CompilationUnit ast = library.getAST(source);
-        ast.accept(
-            new VariableResolverVisitor.con1(library, source, _typeProvider));
+        ast.accept(new VariableResolverVisitor(library.libraryElement, source,
+            _typeProvider, library.errorListener,
+            nameScope: library.libraryScope));
         ResolverVisitorFactory visitorFactory =
             analysisContext.resolverVisitorFactory;
         ResolverVisitor visitor = visitorFactory != null
             ? visitorFactory(library, source, _typeProvider)
-            : new ResolverVisitor.con1(library, source, _typeProvider);
+            : new ResolverVisitor(library.libraryElement, source, _typeProvider,
+                library.errorListener,
+                nameScope: library.libraryScope,
+                inheritanceManager: library.inheritanceManager);
         ast.accept(visitor);
       }
     });
@@ -8653,7 +8379,6 @@
     _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
     _buildEnumMembers();
     _buildTypeHierarchies();
-    _buildImplicitConstructors();
     //
     // Perform resolution and type analysis.
     //
@@ -8855,22 +8580,6 @@
     });
   }
 
-  /**
-   * Finish steps that the [buildTypeHierarchies] could not perform, see
-   * [ImplicitConstructorBuilder].
-   *
-   * @throws AnalysisException if any of the type hierarchies could not be resolved
-   */
-  void _buildImplicitConstructors() {
-    PerformanceStatistics.resolve.makeCurrentWhile(() {
-      ImplicitConstructorComputer computer = new ImplicitConstructorComputer();
-      for (ResolvableLibrary library in _librariesInCycle) {
-        computer.add(_errorListener, library.libraryElement);
-      }
-      computer.compute();
-    });
-  }
-
   HashMap<Source, ResolvableLibrary> _buildLibraryMap() {
     HashMap<Source, ResolvableLibrary> libraryMap =
         new HashMap<Source, ResolvableLibrary>();
@@ -8903,8 +8612,10 @@
             in library.resolvableCompilationUnits) {
           Source source = unit.source;
           CompilationUnit ast = unit.compilationUnit;
-          TypeResolverVisitor visitor =
-              new TypeResolverVisitor.con4(library, source, _typeProvider);
+          TypeResolverVisitor visitor = new TypeResolverVisitor(
+              library.libraryElement, source, _typeProvider,
+              library.libraryScope.errorListener,
+              nameScope: library.libraryScope);
           ast.accept(visitor);
         }
       }
@@ -8985,10 +8696,13 @@
           in library.resolvableCompilationUnits) {
         Source source = unit.source;
         CompilationUnit ast = unit.compilationUnit;
-        ast.accept(
-            new VariableResolverVisitor.con3(library, source, _typeProvider));
-        ResolverVisitor visitor =
-            new ResolverVisitor.con4(library, source, _typeProvider);
+        ast.accept(new VariableResolverVisitor(library.libraryElement, source,
+            _typeProvider, library.libraryScope.errorListener,
+            nameScope: library.libraryScope));
+        ResolverVisitor visitor = new ResolverVisitor(library.libraryElement,
+            source, _typeProvider, library._libraryScope.errorListener,
+            nameScope: library._libraryScope,
+            inheritanceManager: library.inheritanceManager);
         ast.accept(visitor);
       }
     });
@@ -10273,63 +9987,41 @@
   bool resolveOnlyCommentInFunctionBody = false;
 
   /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   */
-  ResolverVisitor.con1(
-      Library library, Source source, TypeProvider typeProvider,
-      {StaticTypeAnalyzer typeAnalyzer,
-      StaticTypeAnalyzerFactory typeAnalyzerFactory})
-      : super.con1(library, source, typeProvider) {
-    this._inheritanceManager = library.inheritanceManager;
-    this.elementResolver = new ElementResolver(this);
-    this.typeAnalyzer = typeAnalyzer != null
-        ? typeAnalyzer
-        : (typeAnalyzerFactory != null
-            ? typeAnalyzerFactory(this)
-            : new StaticTypeAnalyzer(this));
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param definingLibrary the element for the library containing the compilation unit being
-   *          visited
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
-   */
-  ResolverVisitor.con2(LibraryElement definingLibrary, Source source,
-      TypeProvider typeProvider, InheritanceManager inheritanceManager,
-      AnalysisErrorListener errorListener)
-      : super.con2(definingLibrary, source, typeProvider, errorListener) {
-    this._inheritanceManager = inheritanceManager;
-    this.elementResolver = new ElementResolver(this);
-    this.typeAnalyzer = new StaticTypeAnalyzer(this);
-  }
-
-  /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
-   * @param definingLibrary the element for the library containing the node being visited
-   * @param source the source representing the compilation unit containing the node being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param nameScope the scope used to resolve identifiers in the node that will first be visited
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
+   * [definingLibrary] is the element for the library containing the node being
+   * visited.
+   * [source] is the source representing the compilation unit containing the
+   * node being visited.
+   * [typeProvider] the object used to access the types from the core library.
+   * [errorListener] the error listener that will be informed of any errors
+   * that are found during resolution.
+   * [nameScope] is the scope used to resolve identifiers in the node that will
+   * first be visited.  If `null` or unspecified, a new [LibraryScope] will be
+   * created based on [definingLibrary] and [typeProvider].
+   * [inheritanceManager] is used to perform inheritance lookups.  If `null` or
+   * unspecified, a new [InheritanceManager] will be created based on
+   * [definingLibrary].
+   * [typeAnalyzerFactory] is used to create the type analyzer.  If `null` or
+   * unspecified, a type analyzer of type [StaticTypeAnalyzer] will be created.
    */
-  ResolverVisitor.con3(LibraryElement definingLibrary, Source source,
-      TypeProvider typeProvider, Scope nameScope,
-      AnalysisErrorListener errorListener)
-      : super.con3(
-          definingLibrary, source, typeProvider, nameScope, errorListener) {
-    this._inheritanceManager = new InheritanceManager(definingLibrary);
+  ResolverVisitor(LibraryElement definingLibrary, Source source,
+      TypeProvider typeProvider, AnalysisErrorListener errorListener,
+      {Scope nameScope, InheritanceManager inheritanceManager,
+      StaticTypeAnalyzerFactory typeAnalyzerFactory})
+      : super(definingLibrary, source, typeProvider, errorListener,
+          nameScope: nameScope) {
+    if (inheritanceManager == null) {
+      this._inheritanceManager = new InheritanceManager(definingLibrary);
+    } else {
+      this._inheritanceManager = inheritanceManager;
+    }
     this.elementResolver = new ElementResolver(this);
-    this.typeAnalyzer = new StaticTypeAnalyzer(this);
+    if (typeAnalyzerFactory == null) {
+      this.typeAnalyzer = new StaticTypeAnalyzer(this);
+    } else {
+      this.typeAnalyzer = typeAnalyzerFactory(this);
+    }
   }
 
   /**
@@ -10338,14 +10030,18 @@
    * @param library the library containing the compilation unit being resolved
    * @param source the source representing the compilation unit being visited
    * @param typeProvider the object used to access the types from the core library
+   *
+   * Deprecated.  Please use unnamed constructor instead.
    */
-  ResolverVisitor.con4(
-      ResolvableLibrary library, Source source, TypeProvider typeProvider)
-      : super.con4(library, source, typeProvider) {
-    this._inheritanceManager = library.inheritanceManager;
-    this.elementResolver = new ElementResolver(this);
-    this.typeAnalyzer = new StaticTypeAnalyzer(this);
-  }
+  @deprecated
+  ResolverVisitor.con1(
+      Library library, Source source, TypeProvider typeProvider,
+      {StaticTypeAnalyzerFactory typeAnalyzerFactory})
+      : this(
+          library.libraryElement, source, typeProvider, library.errorListener,
+          nameScope: library.libraryScope,
+          inheritanceManager: library.inheritanceManager,
+          typeAnalyzerFactory: typeAnalyzerFactory);
 
   /**
    * Return the element representing the function containing the current node, or `null` if
@@ -11966,67 +11662,29 @@
   ClassElement enclosingClass;
 
   /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
+   * Initialize a newly created visitor to resolve the nodes in a compilation
+   * unit.
    *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
+   * [definingLibrary] is the element for the library containing the
+   * compilation unit being visited.
+   * [source] is the source representing the compilation unit being visited.
+   * [typeProvider] is the object used to access the types from the core
+   * library.
+   * [errorListener] is the error listener that will be informed of any errors
+   * that are found during resolution.
+   * [nameScope] is the scope used to resolve identifiers in the node that will
+   * first be visited.  If `null` or unspecified, a new [LibraryScope] will be
+   * created based on [definingLibrary] and [typeProvider].
    */
-  ScopedVisitor.con1(Library library, this.source, this.typeProvider) {
-    this._definingLibrary = library.libraryElement;
-    LibraryScope libraryScope = library.libraryScope;
-    this._errorListener = libraryScope.errorListener;
-    this.nameScope = libraryScope;
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param definingLibrary the element for the library containing the compilation unit being
-   *          visited
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
-   */
-  ScopedVisitor.con2(LibraryElement definingLibrary, this.source,
-      this.typeProvider, AnalysisErrorListener errorListener) {
+  ScopedVisitor(LibraryElement definingLibrary, this.source, this.typeProvider,
+      AnalysisErrorListener errorListener, {Scope nameScope}) {
     this._definingLibrary = definingLibrary;
     this._errorListener = errorListener;
-    this.nameScope = new LibraryScope(definingLibrary, errorListener);
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param definingLibrary the element for the library containing the compilation unit being
-   *          visited
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param nameScope the scope used to resolve identifiers in the node that will first be visited
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
-   */
-  ScopedVisitor.con3(LibraryElement definingLibrary, this.source,
-      this.typeProvider, Scope nameScope, AnalysisErrorListener errorListener) {
-    this._definingLibrary = definingLibrary;
-    this._errorListener = errorListener;
-    this.nameScope = nameScope;
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   */
-  ScopedVisitor.con4(
-      ResolvableLibrary library, this.source, this.typeProvider) {
-    this._definingLibrary = library.libraryElement;
-    LibraryScope libraryScope = library.libraryScope;
-    this._errorListener = libraryScope.errorListener;
-    this.nameScope = libraryScope;
+    if (nameScope == null) {
+      this.nameScope = new LibraryScope(definingLibrary, errorListener);
+    } else {
+      this.nameScope = nameScope;
+    }
   }
 
   /**
@@ -13663,65 +13321,25 @@
   bool _hasReferenceToSuper = false;
 
   /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   */
-  TypeResolverVisitor.con1(
-      Library library, Source source, TypeProvider typeProvider)
-      : super.con1(library, source, typeProvider) {
-    _dynamicType = typeProvider.dynamicType;
-    _undefinedType = typeProvider.undefinedType;
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param definingLibrary the element for the library containing the compilation unit being
-   *          visited
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
-   */
-  TypeResolverVisitor.con2(LibraryElement definingLibrary, Source source,
-      TypeProvider typeProvider, AnalysisErrorListener errorListener)
-      : super.con2(definingLibrary, source, typeProvider, errorListener) {
-    _dynamicType = typeProvider.dynamicType;
-    _undefinedType = typeProvider.undefinedType;
-  }
-
-  /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
-   * @param definingLibrary the element for the library containing the node being visited
-   * @param source the source representing the compilation unit containing the node being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param nameScope the scope used to resolve identifiers in the node that will first be visited
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
+   * [definingLibrary] is the element for the library containing the node being
+   * visited.
+   * [source] is the source representing the compilation unit containing the
+   * node being visited.
+   * [typeProvider] is the object used to access the types from the core
+   * library.
+   * [errorListener] is the error listener that will be informed of any errors
+   * that are found during resolution.
+   * [nameScope] is the scope used to resolve identifiers in the node that will
+   * first be visited.  If `null` or unspecified, a new [LibraryScope] will be
+   * created based on [definingLibrary] and [typeProvider].
    */
-  TypeResolverVisitor.con3(LibraryElement definingLibrary, Source source,
-      TypeProvider typeProvider, Scope nameScope,
-      AnalysisErrorListener errorListener)
-      : super.con3(
-          definingLibrary, source, typeProvider, nameScope, errorListener) {
-    _dynamicType = typeProvider.dynamicType;
-    _undefinedType = typeProvider.undefinedType;
-  }
-
-  /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   */
-  TypeResolverVisitor.con4(
-      ResolvableLibrary library, Source source, TypeProvider typeProvider)
-      : super.con4(library, source, typeProvider) {
+  TypeResolverVisitor(LibraryElement definingLibrary, Source source,
+      TypeProvider typeProvider, AnalysisErrorListener errorListener,
+      {Scope nameScope})
+      : super(definingLibrary, source, typeProvider, errorListener,
+          nameScope: nameScope) {
     _dynamicType = typeProvider.dynamicType;
     _undefinedType = typeProvider.undefinedType;
   }
@@ -15231,31 +14849,25 @@
   ExecutableElement _enclosingFunction;
 
   /**
-   * Initialize a newly created visitor to resolve the nodes in a compilation unit.
-   *
-   * @param library the library containing the compilation unit being resolved
-   * @param source the source representing the compilation unit being visited
-   * @param typeProvider the object used to access the types from the core library
-   */
-  VariableResolverVisitor.con1(
-      Library library, Source source, TypeProvider typeProvider)
-      : super.con1(library, source, typeProvider);
-
-  /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
-   * @param definingLibrary the element for the library containing the node being visited
-   * @param source the source representing the compilation unit containing the node being visited
-   * @param typeProvider the object used to access the types from the core library
-   * @param nameScope the scope used to resolve identifiers in the node that will first be visited
-   * @param errorListener the error listener that will be informed of any errors that are found
-   *          during resolution
+   * [definingLibrary] is the element for the library containing the node being
+   * visited.
+   * [source] is the source representing the compilation unit containing the
+   * node being visited
+   * [typeProvider] is the object used to access the types from the core
+   * library.
+   * [errorListener] is the error listener that will be informed of any errors
+   * that are found during resolution.
+   * [nameScope] is the scope used to resolve identifiers in the node that will
+   * first be visited.  If `null` or unspecified, a new [LibraryScope] will be
+   * created based on [definingLibrary] and [typeProvider].
    */
-  VariableResolverVisitor.con2(LibraryElement definingLibrary, Source source,
-      TypeProvider typeProvider, Scope nameScope,
-      AnalysisErrorListener errorListener)
-      : super.con3(
-          definingLibrary, source, typeProvider, nameScope, errorListener);
+  VariableResolverVisitor(LibraryElement definingLibrary, Source source,
+      TypeProvider typeProvider, AnalysisErrorListener errorListener,
+      {Scope nameScope})
+      : super(definingLibrary, source, typeProvider, errorListener,
+          nameScope: nameScope);
 
   /**
    * Initialize a newly created visitor to resolve the nodes in a compilation unit.
@@ -15263,10 +14875,15 @@
    * @param library the library containing the compilation unit being resolved
    * @param source the source representing the compilation unit being visited
    * @param typeProvider the object used to access the types from the core library
+   *
+   * Deprecated.  Please use unnamed constructor instead.
    */
-  VariableResolverVisitor.con3(
-      ResolvableLibrary library, Source source, TypeProvider typeProvider)
-      : super.con4(library, source, typeProvider);
+  @deprecated
+  VariableResolverVisitor.con1(
+      Library library, Source source, TypeProvider typeProvider)
+      : this(
+          library.libraryElement, source, typeProvider, library.errorListener,
+          nameScope: library.libraryScope);
 
   @override
   Object visitExportDirective(ExportDirective node) => null;
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 4900cf6..75c175a 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -11,8 +11,11 @@
 import "dart:math" as math;
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
 import 'package:analyzer/task/model.dart';
+import 'package:package_config/packages.dart';
 import 'package:path/path.dart' as pathos;
 
 import 'engine.dart';
@@ -575,6 +578,17 @@
   AnalysisContext context;
 
   /**
+   * URI processor used to find mappings for `package:` URIs found in a `.packages` config
+   * file.
+   */
+  final Packages _packages;
+
+  /**
+   * Resource provider used in working with package maps.
+   */
+  final ResourceProvider _resourceProvider;
+
+  /**
    * The resolvers used to resolve absolute URI's.
    */
   final List<UriResolver> _resolvers;
@@ -585,11 +599,14 @@
   LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
 
   /**
-   * Initialize a newly created source factory.
-   *
-   * @param resolvers the resolvers used to resolve absolute URI's
+   * Initialize a newly created source factory with the given absolute URI [resolvers] and
+   * optional [packages] resolution helper.
    */
-  SourceFactory(this._resolvers);
+  SourceFactory(this._resolvers,
+      [this._packages, ResourceProvider resourceProvider])
+      : _resourceProvider = resourceProvider != null
+          ? resourceProvider
+          : PhysicalResourceProvider.INSTANCE;
 
   /**
    * Return the [DartSdk] associated with this [SourceFactory], or `null` if there
@@ -620,6 +637,19 @@
   /// A table mapping package names to paths of directories containing
   /// the package (or [null] if there is no registered package URI resolver).
   Map<String, List<Folder>> get packageMap {
+    // Start by looking in .packages.
+    if (_packages != null) {
+      Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
+      _packages.asMap().forEach((String name, Uri uri) {
+        if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
+          packageMap[name] =
+              <Folder>[_resourceProvider.getFolder(uri.toFilePath())];
+        }
+      });
+      return packageMap;
+    }
+
+    // Default to the PackageMapUriResolver.
     PackageMapUriResolver resolver = _resolvers.firstWhere(
         (r) => r is PackageMapUriResolver, orElse: () => null);
     return resolver != null ? resolver.packageMap : null;
@@ -727,15 +757,44 @@
    * @return the absolute URI representing the given source
    */
   Uri restoreUri(Source source) {
+    // First see if a resolver can restore the URI.
     for (UriResolver resolver in _resolvers) {
       Uri uri = resolver.restoreAbsolute(source);
       if (uri != null) {
+        // Now see if there's a package mapping.
+        Uri packageMappedUri = _getPackageMapping(uri);
+        if (packageMappedUri != null) {
+          return packageMappedUri;
+        }
+        // Fall back to the resolver's computed URI.
         return uri;
       }
     }
+
     return null;
   }
 
+  Uri _getPackageMapping(Uri sourceUri) {
+    if (_packages == null) {
+      return null;
+    }
+    if (sourceUri.scheme != 'file') {
+      //TODO(pquitslund): verify this works for non-file URIs.
+      return null;
+    }
+
+    Uri packageUri;
+    _packages.asMap().forEach((String name, Uri uri) {
+      if (packageUri == null) {
+        if (utils.startsWith(sourceUri, uri)) {
+          packageUri = Uri.parse(
+              'package:$name/${sourceUri.path.substring(uri.path.length)}');
+        }
+      }
+    });
+    return packageUri;
+  }
+
   /**
    * Return a source object representing the URI that results from resolving the given (possibly
    * relative) contained URI against the URI associated with an existing source object, or
@@ -755,6 +814,15 @@
       }
       containedUri = containingSource.resolveRelativeUri(containedUri);
     }
+    // Now check .packages.
+    if (_packages != null && containedUri.scheme == 'package') {
+      Uri packageUri =
+          _packages.resolve(containedUri, notFound: (Uri packageUri) => null);
+      //TODO(pquitslund): package_config needs to be updated to set schemes for file URIs.
+      if (packageUri != null && packageUri.scheme == '') {
+        containedUri = packageUri.replace(scheme: 'file');
+      }
+    }
     for (UriResolver resolver in _resolvers) {
       Source result = resolver.resolveAbsolute(containedUri);
       if (result != null) {
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 1c60f5d..9c40d74 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -283,6 +283,14 @@
     return new FileBasedSource(new JavaFile.fromUri(uri), uri);
   }
 
+  @override
+  Uri restoreAbsolute(Source source) {
+    if (source is FileBasedSource) {
+      return new Uri.file(source.fullName);
+    }
+    return null;
+  }
+  
   /**
    * Return `true` if the given URI is a `file` URI.
    *
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index cc90ec6..217a0d8 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -268,6 +268,7 @@
             "iterator", false, iteratorType.substitute4(<DartType>[eType])),
         ElementFactory.getterElement("last", false, eType)
       ]);
+      iterableElement.constructors = ConstructorElement.EMPTY_LIST;
       _propagateTypeArguments(iterableElement);
     }
     return _iterableType;
@@ -282,6 +283,7 @@
       _setAccessors(iteratorElement, <PropertyAccessorElement>[
         ElementFactory.getterElement("current", false, eType)
       ]);
+      iteratorElement.constructors = ConstructorElement.EMPTY_LIST;
       _propagateTypeArguments(iteratorElement);
     }
     return _iteratorType;
@@ -330,6 +332,7 @@
         ElementFactory.methodElement(
             "[]=", VoidTypeImpl.instance, [kType, vType])
       ];
+      mapElement.constructors = ConstructorElement.EMPTY_LIST;
       _propagateTypeArguments(mapElement);
     }
     return _mapType;
@@ -356,7 +359,9 @@
   @override
   InterfaceType get nullType {
     if (_nullType == null) {
-      _nullType = ElementFactory.classElement2("Null").type;
+      ClassElementImpl nullElement = ElementFactory.classElement2("Null");
+      nullElement.constructors = ConstructorElement.EMPTY_LIST;
+      _nullType = nullElement.type;
     }
     return _nullType;
   }
@@ -552,7 +557,9 @@
     ];
     fromEnvironment.factory = true;
     fromEnvironment.isCycleFree = true;
+    numElement.constructors = ConstructorElement.EMPTY_LIST;
     intElement.constructors = <ConstructorElement>[fromEnvironment];
+    doubleElement.constructors = ConstructorElement.EMPTY_LIST;
     List<FieldElement> fields = <FieldElement>[
       ElementFactory.fieldElement("NAN", true, false, true, _doubleType),
       ElementFactory.fieldElement("INFINITY", true, false, true, _doubleType),
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index 26456a5..cd9753c 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -38,3 +38,27 @@
   const ParameterKind(String name, int ordinal, this.isOptional)
       : super(name, ordinal);
 }
+
+/**
+ * Check whether [uri1] starts with (or 'is prefixed by') [uri2] by checking
+ * path segments.
+ */
+bool startsWith(Uri uri1, Uri uri2) {
+  List<String> uri1Segments = uri1.pathSegments;
+  List<String> uri2Segments = uri2.pathSegments.toList();
+  // Trim trailing empty segments ('/foo/' => ['foo', ''])
+  if (uri2Segments.last == '') {
+    uri2Segments.removeLast();
+  }
+
+  if (uri2Segments.length > uri1Segments.length) {
+    return false;
+  }
+
+  for (int i = 0; i < uri2Segments.length; ++i) {
+    if (uri2Segments[i] != uri1Segments[i]) {
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 6269cf7..eb516de 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -62,12 +62,10 @@
     //
     // Register Dart tasks.
     //
-    registerExtension(taskId, BuildClassConstructorsTask.DESCRIPTOR);
     registerExtension(taskId, BuildCompilationUnitElementTask.DESCRIPTOR);
     registerExtension(taskId, BuildDirectiveElementsTask.DESCRIPTOR);
     registerExtension(taskId, BuildEnumMemberElementsTask.DESCRIPTOR);
     registerExtension(taskId, BuildExportNamespaceTask.DESCRIPTOR);
-    registerExtension(taskId, BuildLibraryConstructorsTask.DESCRIPTOR);
     registerExtension(taskId, BuildLibraryElementTask.DESCRIPTOR);
     registerExtension(taskId, BuildPublicNamespaceTask.DESCRIPTOR);
     registerExtension(taskId, BuildSourceExportClosureTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 849ae33..ff5b0cb 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -5,7 +5,6 @@
 library analyzer.src.task.dart;
 
 import 'dart:collection';
-import 'dart:math' as math;
 
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/generated/ast.dart';
@@ -59,17 +58,6 @@
         'BUILD_LIBRARY_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
- * The [ClassElement]s of a [Source] representing a Dart library.
- *
- * The list contains the elements for all of the classes defined in the library,
- * not just those in the defining compilation unit. The list will be empty if
- * there are no classes, but will not be `null`.
- */
-final ListResultDescriptor<ClassElement> CLASS_ELEMENTS =
-    new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null,
-        cachingPolicy: ELEMENT_CACHING_POLICY);
-
-/**
  * A list of the [ConstantEvaluationTarget]s defined in a unit.  This includes
  * constants defined at top level, statically inside classes, and local to
  * functions, as well as constant constructors, annotations, and default values
@@ -112,23 +100,6 @@
         cachingPolicy: ELEMENT_CACHING_POLICY);
 
 /**
- * The [ConstructorElement]s of a [ClassElement].
- */
-final ListResultDescriptor<ConstructorElement> CONSTRUCTORS =
-    new ListResultDescriptor<ConstructorElement>('CONSTRUCTORS', null);
-
-/**
- * The errors produced while building a [ClassElement] constructors.
- *
- * The list will be empty if there were no errors, but will not be `null`.
- *
- * The result is only available for targets representing a [ClassElement].
- */
-final ListResultDescriptor<AnalysisError> CONSTRUCTORS_ERRORS =
-    new ListResultDescriptor<AnalysisError>(
-        'CONSTRUCTORS_ERRORS', AnalysisError.NO_ERRORS);
-
-/**
  * The sources representing the libraries that include a given source as a part.
  *
  * The result is only available for [Source]s representing a compilation unit.
@@ -233,17 +204,6 @@
         cachingPolicy: ELEMENT_CACHING_POLICY);
 
 /**
- * The partial [LibraryElement] associated with a library.
- *
- * [LIBRARY_ELEMENT5] plus resolved elements and types for all expressions.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT6 =
-    new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT6', null,
-        cachingPolicy: ELEMENT_CACHING_POLICY);
-
-/**
  * The flag specifying whether all analysis errors are computed in a specific
  * library.
  *
@@ -427,234 +387,6 @@
 }
 
 /**
- * A task that builds implicit constructors for a [ClassElement], or keeps
- * the existing explicit constructors if the class has them.
- */
-class BuildClassConstructorsTask extends SourceBasedAnalysisTask {
-  /**
-   * The name of the [CONSTRUCTORS] input for the superclass.
-   */
-  static const String SUPER_CONSTRUCTORS = 'SUPER_CONSTRUCTORS';
-
-  /**
-   * The task descriptor describing this kind of task.
-   */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'BuildConstructorsForClassTask', createTask, buildInputs,
-      <ResultDescriptor>[CONSTRUCTORS, CONSTRUCTORS_ERRORS]);
-
-  BuildClassConstructorsTask(
-      InternalAnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  void internalPerform() {
-    List<AnalysisError> errors = <AnalysisError>[];
-    //
-    // Prepare inputs.
-    //
-    ClassElementImpl classElement = this.target;
-    List<ConstructorElement> superConstructors = inputs[SUPER_CONSTRUCTORS];
-    DartType superType = classElement.supertype;
-    if (superType == null) {
-      return;
-    }
-    //
-    // Shortcut for ClassElement(s) without implicit constructors.
-    //
-    if (superConstructors == null) {
-      outputs[CONSTRUCTORS] = classElement.constructors;
-      outputs[CONSTRUCTORS_ERRORS] = AnalysisError.NO_ERRORS;
-      return;
-    }
-    //
-    // ClassTypeAlias
-    //
-    if (classElement.isMixinApplication) {
-      List<ConstructorElement> implicitConstructors =
-          new List<ConstructorElement>();
-      void callback(ConstructorElement explicitConstructor,
-          List<DartType> parameterTypes, List<DartType> argumentTypes) {
-        implicitConstructors.add(_createImplicitContructor(classElement.type,
-            explicitConstructor, parameterTypes, argumentTypes));
-      }
-      if (_findForwardedConstructors(classElement, superType, callback)) {
-        if (implicitConstructors.isEmpty) {
-          errors.add(new AnalysisError(classElement.source,
-              classElement.nameOffset, classElement.name.length,
-              CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
-              [superType.element.name]));
-        } else {
-          classElement.constructors = implicitConstructors;
-        }
-      }
-      outputs[CONSTRUCTORS] = classElement.constructors;
-      outputs[CONSTRUCTORS_ERRORS] = errors;
-    }
-    //
-    // ClassDeclaration
-    //
-    if (!classElement.isMixinApplication) {
-      bool constructorFound = false;
-      void callback(ConstructorElement explicitConstructor,
-          List<DartType> parameterTypes, List<DartType> argumentTypes) {
-        constructorFound = true;
-      }
-      if (_findForwardedConstructors(classElement, superType, callback) &&
-          !constructorFound) {
-        SourceRange withRange = classElement.withClauseRange;
-        errors.add(new AnalysisError(classElement.source, withRange.offset,
-            withRange.length, CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
-            [superType.element.name]));
-        classElement.mixinErrorsReported = true;
-      }
-      outputs[CONSTRUCTORS] = classElement.constructors;
-      outputs[CONSTRUCTORS_ERRORS] = errors;
-    }
-  }
-
-  /**
-   * Return a map from the names of the inputs of this kind of task to the task
-   * input descriptors describing those inputs for a task with the
-   * given [classElement].
-   */
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    ClassElement element = target;
-    Source librarySource = element.library.source;
-    DartType superType = element.supertype;
-    if (superType is InterfaceType) {
-      if (element.isMixinApplication || element.mixins.isNotEmpty) {
-        ClassElement superElement = superType.element;
-        return <String, TaskInput>{
-          'libraryDep': LIBRARY_ELEMENT5.of(librarySource),
-          SUPER_CONSTRUCTORS: CONSTRUCTORS.of(superElement)
-        };
-      }
-    }
-    // No implicit constructors.
-    // Depend on LIBRARY_ELEMENT5 for invalidation.
-    return <String, TaskInput>{
-      'libraryDep': LIBRARY_ELEMENT5.of(librarySource)
-    };
-  }
-
-  /**
-   * Create a [BuildClassConstructorsTask] based on the given
-   * [target] in the given [context].
-   */
-  static BuildClassConstructorsTask createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new BuildClassConstructorsTask(context, target);
-  }
-
-  /**
-   * Create an implicit constructor that is copied from the given
-   * [explicitConstructor], but that is in the given class.
-   *
-   * [classType] - the class in which the implicit constructor is defined.
-   * [explicitConstructor] - the constructor on which the implicit constructor
-   *    is modeled.
-   * [parameterTypes] - the types to be replaced when creating parameters.
-   * [argumentTypes] - the types with which the parameters are to be replaced.
-   */
-  static ConstructorElement _createImplicitContructor(InterfaceType classType,
-      ConstructorElement explicitConstructor, List<DartType> parameterTypes,
-      List<DartType> argumentTypes) {
-    ConstructorElementImpl implicitConstructor =
-        new ConstructorElementImpl(explicitConstructor.name, -1);
-    implicitConstructor.synthetic = true;
-    implicitConstructor.redirectedConstructor = explicitConstructor;
-    implicitConstructor.const2 = explicitConstructor.isConst;
-    implicitConstructor.returnType = classType;
-    List<ParameterElement> explicitParameters = explicitConstructor.parameters;
-    int count = explicitParameters.length;
-    if (count > 0) {
-      List<ParameterElement> implicitParameters =
-          new List<ParameterElement>(count);
-      for (int i = 0; i < count; i++) {
-        ParameterElement explicitParameter = explicitParameters[i];
-        ParameterElementImpl implicitParameter =
-            new ParameterElementImpl(explicitParameter.name, -1);
-        implicitParameter.const3 = explicitParameter.isConst;
-        implicitParameter.final2 = explicitParameter.isFinal;
-        implicitParameter.parameterKind = explicitParameter.parameterKind;
-        implicitParameter.synthetic = true;
-        implicitParameter.type =
-            explicitParameter.type.substitute2(argumentTypes, parameterTypes);
-        implicitParameters[i] = implicitParameter;
-      }
-      implicitConstructor.parameters = implicitParameters;
-    }
-    FunctionTypeImpl type = new FunctionTypeImpl(implicitConstructor);
-    type.typeArguments = classType.typeArguments;
-    implicitConstructor.type = type;
-    return implicitConstructor;
-  }
-
-  /**
-   * Find all the constructors that should be forwarded from the given
-   * [superType], to the class or mixin application [classElement],
-   * and pass information about them to [callback].
-   *
-   * Return `true` if some constructors were considered. (A `false` return value
-   * can only happen if the supeclass is a built-in type, in which case it
-   * can't be used as a mixin anyway).
-   */
-  static bool _findForwardedConstructors(ClassElementImpl classElement,
-      InterfaceType superType, void callback(
-          ConstructorElement explicitConstructor, List<DartType> parameterTypes,
-          List<DartType> argumentTypes)) {
-    if (superType == null) {
-      return false;
-    }
-    ClassElement superclassElement = superType.element;
-    List<ConstructorElement> constructors = superclassElement.constructors;
-    int count = constructors.length;
-    if (count == 0) {
-      return false;
-    }
-    List<DartType> parameterTypes =
-        TypeParameterTypeImpl.getTypes(superType.typeParameters);
-    List<DartType> argumentTypes = _getArgumentTypes(superType, parameterTypes);
-    for (int i = 0; i < count; i++) {
-      ConstructorElement explicitConstructor = constructors[i];
-      if (!explicitConstructor.isFactory &&
-          classElement.isSuperConstructorAccessible(explicitConstructor)) {
-        callback(explicitConstructor, parameterTypes, argumentTypes);
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Return a list of argument types that corresponds to the [parameterTypes]
-   * and that are derived from the type arguments of the given [superType].
-   */
-  static List<DartType> _getArgumentTypes(
-      InterfaceType superType, List<DartType> parameterTypes) {
-    DynamicTypeImpl dynamic = DynamicTypeImpl.instance;
-    int parameterCount = parameterTypes.length;
-    List<DartType> types = new List<DartType>(parameterCount);
-    if (superType == null) {
-      types = new List<DartType>.filled(parameterCount, dynamic);
-    } else {
-      List<DartType> typeArguments = superType.typeArguments;
-      int argumentCount = math.min(typeArguments.length, parameterCount);
-      for (int i = 0; i < argumentCount; i++) {
-        types[i] = typeArguments[i];
-      }
-      for (int i = argumentCount; i < parameterCount; i++) {
-        types[i] = dynamic;
-      }
-    }
-    return types;
-  }
-}
-
-/**
  * A task that builds a compilation unit element for a single compilation unit.
  */
 class BuildCompilationUnitElementTask extends SourceBasedAnalysisTask {
@@ -1128,59 +860,6 @@
 }
 
 /**
- * This task builds [LIBRARY_ELEMENT6] by forcing building constructors for
- * all the classes of the defining and part units of a library.
- */
-class BuildLibraryConstructorsTask extends SourceBasedAnalysisTask {
-  /**
-   * The name of the [LIBRARY_ELEMENT5] input.
-   */
-  static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
-
-  /**
-   * The task descriptor describing this kind of task.
-   */
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'BuildLibraryConstructorsTask', createTask, buildInputs,
-      <ResultDescriptor>[LIBRARY_ELEMENT6]);
-
-  BuildLibraryConstructorsTask(
-      InternalAnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  void internalPerform() {
-    LibraryElement library = getRequiredInput(LIBRARY_INPUT);
-    outputs[LIBRARY_ELEMENT6] = library;
-  }
-
-  /**
-   * Return a map from the names of the inputs of this kind of task to the task
-   * input descriptors describing those inputs for a task with the
-   * given [target].
-   */
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    Source source = target;
-    return <String, TaskInput>{
-      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
-      'resolvedConstructors': CLASS_ELEMENTS.of(source).toListOf(CONSTRUCTORS),
-    };
-  }
-
-  /**
-   * Create a [BuildLibraryConstructorsTask] based on the given [target] in
-   * the given [context].
-   */
-  static BuildLibraryConstructorsTask createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new BuildLibraryConstructorsTask(context, target);
-  }
-}
-
-/**
  * A task that builds a library element for a Dart library.
  */
 class BuildLibraryElementTask extends SourceBasedAnalysisTask {
@@ -1201,7 +880,6 @@
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
       'BuildLibraryElementTask', createTask, buildInputs, <ResultDescriptor>[
     BUILD_LIBRARY_ERRORS,
-    CLASS_ELEMENTS,
     LIBRARY_ELEMENT1,
     IS_LAUNCHABLE
   ]);
@@ -1337,17 +1015,9 @@
       _patchTopLevelAccessors(libraryElement);
     }
     //
-    // Prepare all class elements.
-    //
-    List<ClassElement> classElements = libraryElement.units
-        .map((CompilationUnitElement unitElement) => unitElement.types)
-        .expand((List<ClassElement> unitClassElements) => unitClassElements)
-        .toList();
-    //
     // Record outputs.
     //
     outputs[BUILD_LIBRARY_ERRORS] = errors;
-    outputs[CLASS_ELEMENTS] = classElements;
     outputs[LIBRARY_ELEMENT1] = libraryElement;
     outputs[IS_LAUNCHABLE] = entryPoint != null;
   }
@@ -2614,11 +2284,6 @@
   static const String VERIFY_ERRORS_INPUT = 'VERIFY_ERRORS';
 
   /**
-   * The name of the [CONSTRUCTORS_ERRORS] input.
-   */
-  static const String CONSTRUCTORS_ERRORS_INPUT = 'CONSTRUCTORS_ERRORS';
-
-  /**
    * The task descriptor describing this kind of task.
    */
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
@@ -2637,7 +2302,6 @@
     // Prepare inputs.
     //
     List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
-    errorLists.addAll(getRequiredInput(CONSTRUCTORS_ERRORS_INPUT));
     errorLists.add(getRequiredInput(HINTS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_REFERENCES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_TYPE_NAMES_ERRORS_INPUT));
@@ -2657,10 +2321,6 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      CONSTRUCTORS_ERRORS_INPUT: COMPILATION_UNIT_ELEMENT
-          .of(unit)
-          .mappedToList((CompilationUnitElement element) => element.types)
-          .toListOf(CONSTRUCTORS_ERRORS),
       HINTS_INPUT: HINTS.of(unit),
       RESOLVE_REFERENCES_ERRORS_INPUT: RESOLVE_REFERENCES_ERRORS.of(unit),
       RESOLVE_TYPE_NAMES_ERRORS_INPUT: RESOLVE_TYPE_NAMES_ERRORS.of(unit),
@@ -3010,7 +2670,7 @@
  */
 class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [LIBRARY_ELEMENT6] input.
+   * The name of the [LIBRARY_ELEMENT5] input.
    */
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
@@ -3060,7 +2720,7 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     Source source = target;
     return <String, TaskInput>{
-      LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source),
+      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
       UNITS_INPUT: UNITS.of(source).toList((Source unit) =>
           RESOLVED_UNIT5.of(new LibrarySpecificUnit(source, unit))),
       'resolvedUnits': IMPORT_EXPORT_SOURCE_CLOSURE
@@ -3140,7 +2800,7 @@
  */
 class ResolveUnitReferencesTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [LIBRARY_ELEMENT6] input.
+   * The name of the [LIBRARY_ELEMENT5] input.
    */
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
@@ -3185,8 +2845,9 @@
     //
     InheritanceManager inheritanceManager =
         new InheritanceManager(libraryElement);
-    AstVisitor visitor = new ResolverVisitor.con2(libraryElement,
-        unitElement.source, typeProvider, inheritanceManager, errorListener);
+    AstVisitor visitor = new ResolverVisitor(
+        libraryElement, unitElement.source, typeProvider, errorListener,
+        inheritanceManager: inheritanceManager);
     unit.accept(visitor);
     //
     // Record outputs.
@@ -3206,8 +2867,8 @@
     return <String, TaskInput>{
       'fullyBuiltLibraryElements': IMPORT_EXPORT_SOURCE_CLOSURE
           .of(unit.library)
-          .toListOf(LIBRARY_ELEMENT6),
-      LIBRARY_INPUT: LIBRARY_ELEMENT6.of(unit.library),
+          .toListOf(LIBRARY_ELEMENT5),
+      LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
       UNIT_INPUT: RESOLVED_UNIT4.of(unit),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
@@ -3271,7 +2932,7 @@
     //
     // Resolve TypeName nodes.
     //
-    TypeResolverVisitor visitor = new TypeResolverVisitor.con2(
+    TypeResolverVisitor visitor = new TypeResolverVisitor(
         library, unitElement.source, typeProvider, errorListener);
     unit.accept(visitor);
     //
@@ -3313,7 +2974,7 @@
  */
 class ResolveVariableReferencesTask extends SourceBasedAnalysisTask {
   /**
-   * The name of the [LIBRARY_ELEMENT6] input.
+   * The name of the [LIBRARY_ELEMENT1] input.
    */
   static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
 
@@ -3355,8 +3016,9 @@
     //
     TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     Scope nameScope = new LibraryScope(libraryElement, errorListener);
-    AstVisitor visitor = new VariableResolverVisitor.con2(libraryElement,
-        unitElement.source, typeProvider, nameScope, errorListener);
+    AstVisitor visitor = new VariableResolverVisitor(
+        libraryElement, unitElement.source, typeProvider, errorListener,
+        nameScope: nameScope);
     unit.accept(visitor);
     //
     // Record outputs.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index ab17aa4..961627c 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.25.1-alpha.4
+version: 0.25.1
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
@@ -8,6 +8,7 @@
 dependencies:
   args: '>=0.12.1 <0.14.0'
   html: ^0.12.0
+  package_config: ^0.1.1
   path: '>=0.9.0 <2.0.0'
   plugin: ^0.1.0
   watcher: '>=0.9.6 <0.10.0'
diff --git a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
index cd9cfbb..7898bb9 100644
--- a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
+++ b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
@@ -296,7 +296,14 @@
       file.deleteSync();
       return _delayed(() {
         expect(changesReceived, hasLength(1));
-        expect(changesReceived[0].type, equals(ChangeType.REMOVE));
+        if (io.Platform.isWindows) {
+          // TODO(danrubel) https://github.com/dart-lang/sdk/issues/23762
+          // This test fails on Windows but a similar test in the underlying
+          // watcher package passes on Windows.
+          expect(changesReceived[0].type, equals(ChangeType.MODIFY));
+        } else {
+          expect(changesReceived[0].type, equals(ChangeType.REMOVE));
+        }
         expect(changesReceived[0].path, equals(path));
       });
     });
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index e163fd0..0a1b03a 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -1061,6 +1061,8 @@
           ElementFactory.constructorElement(classElement, '', true);
       constructorDeclaration.element = constructorElement;
       classElement.constructors = <ConstructorElement>[constructorElement];
+    } else {
+      classElement.constructors = ConstructorElement.EMPTY_LIST;
     }
     return variableDeclaration;
   }
@@ -8256,7 +8258,6 @@
   }
 }
 
-
 @reflectiveTest
 class StringScannerTest extends AbstractScannerTest {
   @override
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index cfc2f62..e212444 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -1912,10 +1912,7 @@
 class M {}
 class C = bool with M;''');
     computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
-      CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
-    ]);
+    assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
     verify([source]);
   }
 
@@ -1933,10 +1930,7 @@
 class M {}
 class C = int with M;''');
     computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
-      CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
-    ]);
+    assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
     verify([source]);
   }
 
@@ -1963,10 +1957,7 @@
 class M {}
 class C = String with M;''');
     computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS,
-      CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS
-    ]);
+    assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
     verify([source]);
   }
 
@@ -5282,6 +5273,22 @@
     verify([source]);
   }
 
+  void test_recursiveInterfaceInheritance_mixin_superclass() {
+    // Make sure we don't get CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS in
+    // addition--that would just be confusing.
+    Source source = addSource('''
+class C = D with M;
+class D = C with M;
+class M {}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE,
+      CompileTimeErrorCode.RECURSIVE_INTERFACE_INHERITANCE
+    ]);
+    verify([source]);
+  }
+
   void test_recursiveInterfaceInheritance_tail() {
     Source source = addSource(r'''
 abstract class A implements A {}
diff --git a/pkg/analyzer/test/generated/element_test.dart b/pkg/analyzer/test/generated/element_test.dart
index 5bdceca..d5f9ffb 100644
--- a/pkg/analyzer/test/generated/element_test.dart
+++ b/pkg/analyzer/test/generated/element_test.dart
@@ -2380,6 +2380,7 @@
 
   void test_getConstructors_empty() {
     ClassElementImpl typeElement = ElementFactory.classElement2("A");
+    typeElement.constructors = ConstructorElement.EMPTY_LIST;
     InterfaceTypeImpl type = new InterfaceTypeImpl(typeElement);
     expect(type.constructors, isEmpty);
   }
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index eb87ea7..8d9365c 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -10,6 +10,7 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/cancelable_future.dart';
 import 'package:analyzer/src/context/cache.dart' show CacheEntry;
 import 'package:analyzer/src/generated/ast.dart';
@@ -447,6 +448,42 @@
     });
   }
 
+  /**
+   * IDEA uses the following scenario:
+   * 1. Add overlay.
+   * 2. Change overlay.
+   * 3. If the contents of the document buffer is the same as the contents
+   *    of the file, remove overlay.
+   * So, we need to try to use incremental resolution for removing overlays too.
+   */
+  void test_applyChanges_remove_incremental() {
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    Source source = resourceProvider.newFile('/test.dart', r'''
+main() {
+  print(1);
+}
+''').createSource();
+    _context = AnalysisContextFactory.oldContextWithCore();
+    _context.analysisOptions = new AnalysisOptionsImpl()..incremental = true;
+    _context.applyChanges(new ChangeSet()..addedSource(source));
+    // remember compilation unit
+    _analyzeAll_assertFinished();
+    CompilationUnit unit = _context.getResolvedCompilationUnit2(source, source);
+    // add overlay
+    _context.setContents(source, r'''
+main() {
+  print(12);
+}
+''');
+    _analyzeAll_assertFinished();
+    expect(_context.getResolvedCompilationUnit2(source, source), unit);
+    // remove overlay
+    _context.setContents(source, null);
+    _context.validateCacheConsistency();
+    _analyzeAll_assertFinished();
+    expect(_context.getResolvedCompilationUnit2(source, source), unit);
+  }
+
   Future test_applyChanges_removeContainer() {
     _context = AnalysisContextFactory.oldContextWithCore();
     SourcesChangedListener listener = new SourcesChangedListener();
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 98f6d23..ed41b59 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -2486,7 +2486,7 @@
   void resetWithOptions(AnalysisOptions options) {
     if (AnalysisEngine.instance.useTaskModel) {
       analysisContext2 =
-                AnalysisContextFactory.contextWithCoreAndOptions(options);
+          AnalysisContextFactory.contextWithCoreAndOptions(options);
     } else {
       analysisContext2 =
           AnalysisContextFactory.oldContextWithCoreAndOptions(options);
@@ -3711,7 +3711,7 @@
     expect(errors, isEmpty);
   }
 
-  void test_updateErrors_addNew_hint() {
+  void test_updateErrors_addNew_hint1() {
     _resolveUnit(r'''
 int main() {
   return 42;
@@ -3723,7 +3723,7 @@
 ''');
   }
 
-  void test_updateErrors_addNew_hints() {
+  void test_updateErrors_addNew_hint2() {
     _resolveUnit(r'''
 main() {
   int v = 0;
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index e36ab22..06336a4 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -3393,6 +3393,18 @@
     verify([source]);
   }
 
+  void test_nonAbstractClassInheritsAbstractMemberOne_overridesMethodInObject() {
+    Source source = addSource(r'''
+class A {
+  String toString([String prefix = '']) => '${prefix}Hello';
+}
+class C {}
+class B extends A with C {}''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_nonBoolExpression_functionType() {
     Source source = addSource(r'''
 bool makeAssertion() => true;
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index a796d5e..e07053d 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1934,7 +1934,10 @@
     _definingLibrary.definingCompilationUnit = definingCompilationUnit;
     Library library = new Library(context, _listener, source);
     library.libraryElement = _definingLibrary;
-    _visitor = new ResolverVisitor.con1(library, source, _typeProvider);
+    _visitor = new ResolverVisitor(
+        library.libraryElement, source, _typeProvider, library.errorListener,
+        nameScope: library.libraryScope,
+        inheritanceManager: library.inheritanceManager);
     try {
       return _visitor.elementResolver;
     } catch (exception) {
@@ -11084,7 +11087,10 @@
     definingLibrary.definingCompilationUnit = definingCompilationUnit;
     Library library = new Library(context, _listener, source);
     library.libraryElement = definingLibrary;
-    _visitor = new ResolverVisitor.con1(library, source, _typeProvider);
+    _visitor = new ResolverVisitor(
+        library.libraryElement, source, _typeProvider, library.errorListener,
+        nameScope: library.libraryScope,
+        inheritanceManager: library.inheritanceManager);
     _visitor.overrideManager.enterScope();
     try {
       return _visitor.typeAnalyzer;
@@ -13365,11 +13371,6 @@
    */
   TypeResolverVisitor _visitor;
 
-  /**
-   * The visitor used to resolve types needed to form the type hierarchy.
-   */
-  ImplicitConstructorBuilder _implicitConstructorBuilder;
-
   void fail_visitConstructorDeclaration() {
     fail("Not yet tested");
     _listener.assertNoErrors();
@@ -13418,16 +13419,9 @@
         new CompilationUnitElementImpl("lib.dart");
     _library.libraryElement = element;
     _typeProvider = new TestTypeProvider();
-    _visitor =
-        new TypeResolverVisitor.con1(_library, librarySource, _typeProvider);
-    _implicitConstructorBuilder = new ImplicitConstructorBuilder(_listener,
-        (ClassElement classElement, ClassElement superclassElement,
-            void computation()) {
-      // For these tests, we assume the classes for which implicit
-      // constructors need to be built are visited in proper dependency order,
-      // so we just invoke the computation immediately.
-      computation();
-    });
+    _visitor = new TypeResolverVisitor(_library.libraryElement, librarySource,
+        _typeProvider, _library.errorListener,
+        nameScope: _library.libraryScope);
   }
 
   void test_visitCatchClause_exception() {
@@ -13827,9 +13821,6 @@
       }
     }
     node.accept(_visitor);
-    if (node is Declaration) {
-      node.element.accept(_implicitConstructorBuilder);
-    }
   }
 }
 
diff --git a/pkg/analyzer/test/generated/source_factory_test.dart b/pkg/analyzer/test/generated/source_factory_test.dart
index 26b3942..e510949 100644
--- a/pkg/analyzer/test/generated/source_factory_test.dart
+++ b/pkg/analyzer/test/generated/source_factory_test.dart
@@ -7,6 +7,8 @@
 
 library analyzer.test.generated.source_factory;
 
+import 'dart:convert';
+
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
@@ -15,6 +17,10 @@
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
+import 'package:package_config/packages.dart';
+import 'package:package_config/packages_file.dart' as pkgfile show parse;
+import 'package:package_config/src/packages_impl.dart';
 import 'package:path/path.dart';
 import 'package:unittest/unittest.dart';
 
@@ -24,6 +30,147 @@
 main() {
   groupSep = ' | ';
   runReflectiveTests(SourceFactoryTest);
+  runPackageMapTests();
+}
+
+void runPackageMapTests() {
+  final Uri baseUri = new Uri.file('test/base');
+  final List<UriResolver> testResolvers = [new FileUriResolver()];
+
+  Packages createPackageMap(Uri base, String configFileContents) {
+    List<int> bytes = UTF8.encode(configFileContents);
+    Map<String, Uri> map = pkgfile.parse(bytes, base);
+    return new MapPackages(map);
+  }
+
+  Map<String, List<Folder>> getPackageMap(String config) {
+    Packages packages = createPackageMap(baseUri, config);
+    SourceFactory factory = new SourceFactory(testResolvers, packages);
+    return factory.packageMap;
+  }
+
+  String resolvePackageUri({String uri, String config, Source containingSource,
+      UriResolver customResolver}) {
+    Packages packages = createPackageMap(baseUri, config);
+    List<UriResolver> resolvers = testResolvers.toList();
+    if (customResolver != null) {
+      resolvers.add(customResolver);
+    }
+    SourceFactory factory = new SourceFactory(resolvers, packages);
+    Source source = factory.resolveUri(containingSource, uri);
+    return source != null ? source.fullName : null;
+  }
+
+  Uri restorePackageUri(
+      {Source source, String config, UriResolver customResolver}) {
+    Packages packages = createPackageMap(baseUri, config);
+    List<UriResolver> resolvers = testResolvers.toList();
+    if (customResolver != null) {
+      resolvers.add(customResolver);
+    }
+    SourceFactory factory = new SourceFactory(resolvers, packages);
+    return factory.restoreUri(source);
+  }
+
+  group('SourceFactoryTest', () {
+    group('package mapping', () {
+      group('resolveUri', () {
+        test('URI in mapping', () {
+          String uri = resolvePackageUri(config: '''
+unittest:/home/somebody/.pub/cache/unittest-0.9.9/lib/
+async:/home/somebody/.pub/cache/async-1.1.0/lib/
+quiver:/home/somebody/.pub/cache/quiver-1.2.1/lib
+''', uri: 'package:unittest/unittest.dart');
+          expect(uri, equals(
+              '/home/somebody/.pub/cache/unittest-0.9.9/lib/unittest.dart'));
+        });
+        test('URI not in mapping', () {
+          String uri = resolvePackageUri(
+              config: 'unittest:/home/somebody/.pub/cache/unittest-0.9.9/lib/',
+              uri: 'package:foo/foo.dart');
+          expect(uri, isNull);
+        });
+        test('Non-package URI', () {
+          var testResolver = new CustomUriResolver(uriPath: 'test_uri');
+          String uri = resolvePackageUri(
+              config: 'unittest:/home/somebody/.pub/cache/unittest-0.9.9/lib/',
+              uri: 'custom:custom.dart',
+              customResolver: testResolver);
+          expect(uri, testResolver.uriPath);
+        });
+        test('Invalid URI', () {
+          // TODO(pquitslund): fix clients to handle errors appropriately
+          //   CLI: print message 'invalid package file format'
+          //   SERVER: best case tell user somehow and recover...
+          expect(() => resolvePackageUri(
+                  config: 'foo:<:&%>', uri: 'package:foo/bar.dart'),
+              throwsA(new isInstanceOf('FormatException')));
+        });
+        test('Valid URI that cannot be further resolved', () {
+          String uri = resolvePackageUri(
+              config: 'foo:http://www.google.com', uri: 'package:foo/bar.dart');
+          expect(uri, isNull);
+        });
+        test('Relative URIs', () {
+          Source containingSource = createSource(
+              path: '/foo/bar/baz/foo.dart', uri: 'package:foo/foo.dart');
+          String uri = resolvePackageUri(
+              config: 'foo:/foo/bar/baz',
+              uri: 'bar.dart',
+              containingSource: containingSource);
+          expect(uri, isNotNull);
+          expect(uri, equals('/foo/bar/baz/bar.dart'));
+        });
+      });
+      group('restoreUri', () {
+        test('URI in mapping', () {
+          Uri uri = restorePackageUri(config: '''
+unittest:/home/somebody/.pub/cache/unittest-0.9.9/lib/
+async:/home/somebody/.pub/cache/async-1.1.0/lib/
+quiver:/home/somebody/.pub/cache/quiver-1.2.1/lib
+''',
+              source: new FileBasedSource(FileUtilities2.createFile(
+                  '/home/somebody/.pub/cache/unittest-0.9.9/lib/unittest.dart')));
+          expect(uri, isNotNull);
+          expect(uri.toString(), equals('package:unittest/unittest.dart'));
+        });
+      });
+      group('packageMap', () {
+        test('non-file URIs filtered', () {
+          Map<String, List<Folder>> map = getPackageMap('''
+quiver:/home/somebody/.pub/cache/quiver-1.2.1/lib
+foo:http://www.google.com
+''');
+          expect(map.keys, unorderedEquals(['quiver']));
+        });
+      });
+    });
+  });
+
+  group('URI utils', () {
+    group('URI', () {
+      test('startsWith', () {
+        expect(utils.startsWith(Uri.parse('/foo/bar/'), Uri.parse('/foo/')),
+            isTrue);
+        expect(utils.startsWith(Uri.parse('/foo/bar/'), Uri.parse('/foo/bar/')),
+            isTrue);
+        expect(utils.startsWith(Uri.parse('/foo/bar'), Uri.parse('/foo/b')),
+            isFalse);
+      });
+    });
+  });
+}
+
+Source createSource({String path, String uri}) => new MemoryResourceProvider()
+    .getFile(path)
+    .createSource(uri != null ? Uri.parse(uri) : null);
+
+class CustomUriResolver extends UriResolver {
+  String uriPath;
+  CustomUriResolver({this.uriPath});
+
+  @override
+  Source resolveAbsolute(Uri uri) => createSource(path: uriPath);
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index 2a3952a..c6d9254 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -237,6 +237,27 @@
 
 @reflectiveTest
 class CacheEntryTest extends AbstractCacheTest {
+  test_dispose() {
+    ResultDescriptor descriptor1 = new ResultDescriptor('result1', -1);
+    ResultDescriptor descriptor2 = new ResultDescriptor('result2', -2);
+    AnalysisTarget target1 = new TestSource('1.dart');
+    AnalysisTarget target2 = new TestSource('2.dart');
+    TargetedResult result1 = new TargetedResult(target1, descriptor1);
+    TargetedResult result2 = new TargetedResult(target2, descriptor2);
+    CacheEntry entry1 = new CacheEntry(target1);
+    CacheEntry entry2 = new CacheEntry(target2);
+    cache.put(entry1);
+    cache.put(entry2);
+    entry1.setValue(descriptor1, 1, TargetedResult.EMPTY_LIST);
+    entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
+    // target2 is listed as dependent in target1
+    expect(
+        entry1.getResultData(descriptor1).dependentResults, contains(result2));
+    // dispose entry2, result2 is removed from result1
+    entry2.dispose();
+    expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
+  }
+
   test_explicitlyAdded() {
     AnalysisTarget target = new TestSource();
     CacheEntry entry = new CacheEntry(target);
@@ -983,6 +1004,37 @@
     return new UniversalCachePartition(null);
   }
 
+  test_dispose() {
+    InternalAnalysisContext context = new _InternalAnalysisContextMock();
+    CachePartition partition1 = new UniversalCachePartition(context);
+    CachePartition partition2 = new UniversalCachePartition(context);
+    AnalysisCache cache = new AnalysisCache([partition1, partition2]);
+    when(context.analysisCache).thenReturn(cache);
+    // configure
+    // prepare entries
+    ResultDescriptor descriptor1 = new ResultDescriptor('result1', -1);
+    ResultDescriptor descriptor2 = new ResultDescriptor('result2', -2);
+    AnalysisTarget target1 = new TestSource('1.dart');
+    AnalysisTarget target2 = new TestSource('2.dart');
+    TargetedResult result1 = new TargetedResult(target1, descriptor1);
+    TargetedResult result2 = new TargetedResult(target2, descriptor2);
+    CacheEntry entry1 = new CacheEntry(target1);
+    CacheEntry entry2 = new CacheEntry(target2);
+    partition1.put(entry1);
+    partition2.put(entry2);
+    entry1.setValue(descriptor1, 1, TargetedResult.EMPTY_LIST);
+    entry2.setValue(descriptor2, 2, <TargetedResult>[result1]);
+    // target2 is listed as dependent in target1
+    expect(
+        entry1.getResultData(descriptor1).dependentResults, contains(result2));
+    // dispose
+    partition2.dispose();
+    expect(partition1.get(target1), same(entry1));
+    expect(partition2.get(target2), isNull);
+    // result2 is removed from result1
+    expect(entry1.getResultData(descriptor1).dependentResults, isEmpty);
+  }
+
   void test_contains() {
     UniversalCachePartition partition = new UniversalCachePartition(null);
     TestSource source = new TestSource();
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index af84f24..7bc47ba 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -6,6 +6,7 @@
 
 import 'dart:async';
 
+import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/cancelable_future.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
@@ -277,6 +278,41 @@
     });
   }
 
+  /**
+   * IDEA uses the following scenario:
+   * 1. Add overlay.
+   * 2. Change overlay.
+   * 3. If the contents of the document buffer is the same as the contents
+   *    of the file, remove overlay.
+   * So, we need to try to use incremental resolution for removing overlays too.
+   */
+  void test_applyChanges_remove_incremental() {
+    MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+    Source source = resourceProvider.newFile('/test.dart', r'''
+main() {
+  print(1);
+}
+''').createSource();
+    context.analysisOptions = new AnalysisOptionsImpl()..incremental = true;
+    context.applyChanges(new ChangeSet()..addedSource(source));
+    // remember compilation unit
+    _analyzeAll_assertFinished();
+    CompilationUnit unit = context.getResolvedCompilationUnit2(source, source);
+    // add overlay
+    context.setContents(source, r'''
+main() {
+  print(12);
+}
+''');
+    _analyzeAll_assertFinished();
+    expect(context.getResolvedCompilationUnit2(source, source), unit);
+    // remove overlay
+    context.setContents(source, null);
+    context.validateCacheConsistency();
+    _analyzeAll_assertFinished();
+    expect(context.getResolvedCompilationUnit2(source, source), unit);
+  }
+
   Future test_applyChanges_removeContainer() {
     SourcesChangedListener listener = new SourcesChangedListener();
     context.onSourcesChanged.listen(listener.onData);
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index c89e6e9..77db010 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -28,14 +28,12 @@
 
 main() {
   groupSep = ' | ';
-  runReflectiveTests(BuildClassConstructorsTaskTest);
   runReflectiveTests(BuildCompilationUnitElementTaskTest);
   runReflectiveTests(BuildDirectiveElementsTaskTest);
   runReflectiveTests(BuildEnumMemberElementsTaskTest);
   runReflectiveTests(BuildSourceExportClosureTaskTest);
   runReflectiveTests(BuildSourceImportExportClosureTaskTest);
   runReflectiveTests(BuildExportNamespaceTaskTest);
-  runReflectiveTests(BuildLibraryConstructorsTaskTest);
   runReflectiveTests(BuildLibraryElementTaskTest);
   runReflectiveTests(BuildPublicNamespaceTaskTest);
   runReflectiveTests(BuildTypeProviderTaskTest);
@@ -59,112 +57,6 @@
 }
 
 @reflectiveTest
-class BuildClassConstructorsTaskTest extends _AbstractDartTaskTest {
-  test_perform_ClassDeclaration_errors_mixinHasNoConstructors() {
-    Source source = newSource('/test.dart', '''
-class B {
-  B({x});
-}
-class M {}
-class C extends B with M {}
-''');
-    LibraryElement libraryElement;
-    {
-      computeResult(source, LIBRARY_ELEMENT5);
-      libraryElement = outputs[LIBRARY_ELEMENT5];
-    }
-    // prepare C
-    ClassElement c = libraryElement.getType('C');
-    expect(c, isNotNull);
-    // build constructors
-    computeResult(c, CONSTRUCTORS);
-    expect(task, new isInstanceOf<BuildClassConstructorsTask>());
-    _fillErrorListener(CONSTRUCTORS_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS]);
-  }
-
-  test_perform_ClassDeclaration_explicitConstructors() {
-    Source source = newSource('/test.dart', '''
-class B {
-  B(p);
-}
-class C extends B {
-  C(int a, String b) {}
-}
-''');
-    LibraryElement libraryElement;
-    {
-      computeResult(source, LIBRARY_ELEMENT5);
-      libraryElement = outputs[LIBRARY_ELEMENT5];
-    }
-    // prepare C
-    ClassElement c = libraryElement.getType('C');
-    expect(c, isNotNull);
-    // build constructors
-    computeResult(c, CONSTRUCTORS);
-    expect(task, new isInstanceOf<BuildClassConstructorsTask>());
-    // no errors
-    expect(outputs[CONSTRUCTORS_ERRORS], isEmpty);
-    // explicit constructor
-    List<ConstructorElement> constructors = outputs[CONSTRUCTORS];
-    expect(constructors, hasLength(1));
-    expect(constructors[0].parameters, hasLength(2));
-  }
-
-  test_perform_ClassTypeAlias() {
-    Source source = newSource('/test.dart', '''
-class B {
-  B(int i);
-}
-class M1 {}
-class M2 {}
-
-class C2 = C1 with M2;
-class C1 = B with M1;
-''');
-    LibraryElement libraryElement;
-    {
-      computeResult(source, LIBRARY_ELEMENT5);
-      libraryElement = outputs[LIBRARY_ELEMENT5];
-    }
-    // prepare C2
-    ClassElement class2 = libraryElement.getType('C2');
-    expect(class2, isNotNull);
-    // build constructors
-    computeResult(class2, CONSTRUCTORS);
-    expect(task, new isInstanceOf<BuildClassConstructorsTask>());
-    List<ConstructorElement> constructors = outputs[CONSTRUCTORS];
-    expect(constructors, hasLength(1));
-    expect(constructors[0].parameters, hasLength(1));
-  }
-
-  test_perform_ClassTypeAlias_errors_mixinHasNoConstructors() {
-    Source source = newSource('/test.dart', '''
-class B {
-  B({x});
-}
-class M {}
-class C = B with M;
-''');
-    LibraryElement libraryElement;
-    {
-      computeResult(source, LIBRARY_ELEMENT5);
-      libraryElement = outputs[LIBRARY_ELEMENT5];
-    }
-    // prepare C
-    ClassElement c = libraryElement.getType('C');
-    expect(c, isNotNull);
-    // build constructors
-    computeResult(c, CONSTRUCTORS);
-    expect(task, new isInstanceOf<BuildClassConstructorsTask>());
-    _fillErrorListener(CONSTRUCTORS_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS]);
-  }
-}
-
-@reflectiveTest
 class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest {
   Source source;
   LibrarySpecificUnit target;
@@ -715,40 +607,6 @@
 }
 
 @reflectiveTest
-class BuildLibraryConstructorsTaskTest extends _AbstractDartTaskTest {
-  test_perform() {
-    Source source = newSource('/test.dart', '''
-class B {
-  B(int i);
-}
-class M1 {}
-class M2 {}
-
-class C2 = C1 with M2;
-class C1 = B with M1;
-class C3 = B with M2;
-''');
-    computeResult(source, LIBRARY_ELEMENT6);
-    expect(task, new isInstanceOf<BuildLibraryConstructorsTask>());
-    LibraryElement libraryElement = outputs[LIBRARY_ELEMENT6];
-    // C1
-    {
-      ClassElement classElement = libraryElement.getType('C2');
-      List<ConstructorElement> constructors = classElement.constructors;
-      expect(constructors, hasLength(1));
-      expect(constructors[0].parameters, hasLength(1));
-    }
-    // C3
-    {
-      ClassElement classElement = libraryElement.getType('C3');
-      List<ConstructorElement> constructors = classElement.constructors;
-      expect(constructors, hasLength(1));
-      expect(constructors[0].parameters, hasLength(1));
-    }
-  }
-}
-
-@reflectiveTest
 class BuildLibraryElementTaskTest extends _AbstractDartTaskTest {
   Source librarySource;
   CompilationUnit libraryUnit;
@@ -798,7 +656,7 @@
 part of lib;
 '''
     });
-    expect(outputs, hasLength(4));
+    expect(outputs, hasLength(3));
     // simple outputs
     expect(outputs[BUILD_LIBRARY_ERRORS], isEmpty);
     expect(outputs[IS_LAUNCHABLE], isFalse);
@@ -839,28 +697,6 @@
         (libraryUnit.directives[2] as PartDirective).element, same(secondPart));
   }
 
-  test_perform_classElements() {
-    _performBuildTask({
-      '/lib.dart': '''
-library lib;
-part 'part1.dart';
-part 'part2.dart';
-class A {}
-''',
-      '/part1.dart': '''
-part of lib;
-class B {}
-''',
-      '/part2.dart': '''
-part of lib;
-class C {}
-'''
-    });
-    List<ClassElement> classElements = outputs[CLASS_ELEMENTS];
-    List<String> classNames = classElements.map((c) => c.displayName).toList();
-    expect(classNames, unorderedEquals(['A', 'B', 'C']));
-  }
-
   test_perform_error_missingLibraryDirectiveWithPart_hasCommon() {
     _performBuildTask({
       '/lib.dart': '''
@@ -2054,7 +1890,6 @@
         .buildInputs(new LibrarySpecificUnit(emptySource, emptySource));
     expect(inputs, isNotNull);
     expect(inputs.keys, unorderedEquals([
-      LibraryUnitErrorsTask.CONSTRUCTORS_ERRORS_INPUT,
       LibraryUnitErrorsTask.HINTS_INPUT,
       LibraryUnitErrorsTask.RESOLVE_REFERENCES_ERRORS_INPUT,
       LibraryUnitErrorsTask.RESOLVE_TYPE_NAMES_ERRORS_INPUT,
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index a940dbf..9fd865a 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -60,6 +60,8 @@
             trustPrimitives:
                 hasOption(options, '--trust-primitives'),
             enableMinification: hasOption(options, '--minify'),
+            useFrequencyNamer:
+                !hasOption(options, "--no-frequency-based-minification"),
             preserveUris: hasOption(options, '--preserve-uris'),
             enableNativeLiveTypeAnalysis:
                 !hasOption(options, '--disable-native-live-type-analysis'),
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 88368dd..8360a5d 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -26,8 +26,6 @@
    */
   final AstElement element;
 
-  TreeElements get resolutionTree;
-
   WorkItem(this.element, this.compilationContext) {
     assert(invariant(element, element.isDeclaration));
   }
@@ -37,7 +35,7 @@
 
 /// [WorkItem] used exclusively by the [ResolutionEnqueuer].
 class ResolutionWorkItem extends WorkItem {
-  TreeElements resolutionTree;
+  bool _isAnalyzed = false;
 
   ResolutionWorkItem(AstElement element,
                      ItemCompilationContext compilationContext)
@@ -45,11 +43,11 @@
 
   WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
     WorldImpact impact = compiler.analyze(this, world);
-    resolutionTree = element.resolvedAst.elements;
+    _isAnalyzed = true;
     return impact;
   }
 
-  bool isAnalyzed() => resolutionTree != null;
+  bool get isAnalyzed => _isAnalyzed;
 }
 
 // TODO(johnniwinther): Split this class into interface and implementation.
@@ -272,6 +270,11 @@
   /// Backend callback methods for the resolution phase.
   ResolutionCallbacks get resolutionCallbacks;
 
+  /// The strategy used for collecting and emitting source information.
+  SourceInformationStrategy get sourceInformationStrategy {
+    return const SourceInformationStrategy();
+  }
+
   // TODO(johnniwinther): Move this to the JavaScriptBackend.
   String get patchVersion => null;
 
@@ -699,6 +702,8 @@
 
   final bool enableMinification;
 
+  final bool useFrequencyNamer;
+
   /// When `true` emits URIs in the reflection metadata.
   final bool preserveUris;
 
@@ -944,6 +949,7 @@
   ParserTask parser;
   PatchParserTask patchParser;
   LibraryLoaderTask libraryLoader;
+  SerializationTask serialization;
   ResolverTask resolver;
   closureMapping.ClosureTask closureToClassMapper;
   TypeCheckerTask checker;
@@ -1042,6 +1048,7 @@
             bool analyzeSignaturesOnly: false,
             this.preserveComments: false,
             this.useCpsIr: false,
+            this.useFrequencyNamer: false,
             this.verbose: false,
             this.sourceMapUri: null,
             this.outputUri: null,
@@ -1093,17 +1100,10 @@
     globalDependencies =
         new CodegenRegistry(this, new TreeElementMapping(null));
 
-    SourceInformationFactory sourceInformationFactory =
-        const SourceInformationFactory();
-    if (generateSourceMap) {
-      sourceInformationFactory =
-          const bool.fromEnvironment('USE_NEW_SOURCE_INFO', defaultValue: false)
-              ? const PositionSourceInformationFactory()
-              : const StartEndSourceInformationFactory();
-    }
     if (emitJavaScript) {
-      js_backend.JavaScriptBackend jsBackend = new js_backend.JavaScriptBackend(
-      this, sourceInformationFactory, generateSourceMap: generateSourceMap);
+      js_backend.JavaScriptBackend jsBackend =
+          new js_backend.JavaScriptBackend(
+              this, generateSourceMap: generateSourceMap);
       backend = jsBackend;
     } else {
       backend = new dart_backend.DartBackend(this, strips,
@@ -1115,6 +1115,7 @@
 
     tasks = [
       libraryLoader = new LibraryLoaderTask(this),
+      serialization = new SerializationTask(this),
       scanner = new ScannerTask(this),
       dietParser = new DietParserTask(this),
       parser = new ParserTask(this),
@@ -1122,7 +1123,7 @@
       resolver = new ResolverTask(this, backend.constantCompilerTask),
       closureToClassMapper = new closureMapping.ClosureTask(this),
       checker = new TypeCheckerTask(this),
-      irBuilder = new IrBuilderTask(this, sourceInformationFactory),
+      irBuilder = new IrBuilderTask(this, backend.sourceInformationStrategy),
       typesTask = new ti.TypesTask(this),
       constants = backend.constantCompilerTask,
       deferredLoadTask = new DeferredLoadTask(this),
@@ -1815,7 +1816,7 @@
 
   WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
     assert(invariant(work.element, identical(world, enqueuer.resolution)));
-    assert(invariant(work.element, !work.isAnalyzed(),
+    assert(invariant(work.element, !work.isAnalyzed,
         message: 'Element ${work.element} has already been analyzed'));
     if (shouldPrintProgress) {
       // TODO(ahe): Add structured diagnostics to the compiler API and
@@ -2239,6 +2240,20 @@
     return f(beginOffset, endOffset);
   }
 
+  int get hashCode {
+    return 13 * uri.hashCode +
+           17 * begin.hashCode +
+           19 * end.hashCode;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! SourceSpan) return false;
+    return uri == other.uri &&
+           begin == other.begin &&
+           end == other.end;
+  }
+
   String toString() => 'SourceSpan($uri, $begin, $end)';
 }
 
@@ -2413,22 +2428,22 @@
 class _CompilerCoreTypes implements CoreTypes {
   final Compiler compiler;
 
-  ClassElementX objectClass;
-  ClassElementX boolClass;
-  ClassElementX numClass;
-  ClassElementX intClass;
-  ClassElementX doubleClass;
-  ClassElementX stringClass;
-  ClassElementX functionClass;
-  ClassElementX nullClass;
-  ClassElementX listClass;
-  ClassElementX typeClass;
-  ClassElementX mapClass;
-  ClassElementX symbolClass;
-  ClassElementX stackTraceClass;
-  ClassElementX futureClass;
-  ClassElementX iterableClass;
-  ClassElementX streamClass;
+  ClassElement objectClass;
+  ClassElement boolClass;
+  ClassElement numClass;
+  ClassElement intClass;
+  ClassElement doubleClass;
+  ClassElement stringClass;
+  ClassElement functionClass;
+  ClassElement nullClass;
+  ClassElement listClass;
+  ClassElement typeClass;
+  ClassElement mapClass;
+  ClassElement symbolClass;
+  ClassElement stackTraceClass;
+  ClassElement futureClass;
+  ClassElement iterableClass;
+  ClassElement streamClass;
 
   _CompilerCoreTypes(this.compiler);
 
diff --git a/pkg/compiler/lib/src/constants/constructors.dart b/pkg/compiler/lib/src/constants/constructors.dart
index a92edcc..1e588a8 100644
--- a/pkg/compiler/lib/src/constants/constructors.dart
+++ b/pkg/compiler/lib/src/constants/constructors.dart
@@ -135,7 +135,7 @@
       NodeList parameters,
       Node body, _) {
     // TODO(johnniwinther): Handle constant constructors with errors.
-    internalError(node, "Factory constructor cannot be constant.");
+    internalError(node, "Factory constructor cannot be constant: $node.");
   }
 
   applyParameters(NodeList parameters, _) {
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index dc0a3d9..4b1060c 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -108,6 +108,22 @@
   Map<FieldElement, ConstantExpression> computeInstanceFields(
       List<ConstantExpression> arguments,
       CallStructure callStructure);
+
+  accept(ConstantConstructorVisitor visitor, arg);
+}
+
+abstract class ConstantConstructorVisitor<R, A> {
+  const ConstantConstructorVisitor();
+
+  R visit(ConstantConstructor constantConstructor, A context) {
+    return constantConstructor.accept(this, context);
+  }
+
+  R visitGenerative(GenerativeConstantConstructor constructor, A arg);
+  R visitRedirectingGenerative(
+      RedirectingGenerativeConstantConstructor constructor, A arg);
+  R visitRedirectingFactory(
+      RedirectingFactoryConstantConstructor constructor, A arg);
 }
 
 /// A generative constant constructor.
@@ -142,6 +158,10 @@
     return appliedFieldMap;
   }
 
+  accept(ConstantConstructorVisitor visitor, arg) {
+    return visitor.visitGenerative(this, arg);
+  }
+
   int get hashCode {
     int hash = Hashing.objectHash(type);
     hash = Hashing.mapHash(defaultValues, hash);
@@ -233,6 +253,10 @@
     return appliedFieldMap;
   }
 
+  accept(ConstantConstructorVisitor visitor, arg) {
+    return visitor.visitRedirectingGenerative(this, arg);
+  }
+
   int get hashCode {
     int hash = Hashing.objectHash(thisConstructorInvocation);
     return Hashing.mapHash(defaultValues, hash);
@@ -282,6 +306,10 @@
     return constantConstructor.computeInstanceFields(arguments, callStructure);
   }
 
+  accept(ConstantConstructorVisitor visitor, arg) {
+    return visitor.visitRedirectingFactory(this, arg);
+  }
+
   int get hashCode {
     return Hashing.objectHash(targetConstructorInvocation);
   }
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 df98350..6c324d8 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -191,6 +191,12 @@
       }
     }
   }
+
+  /// True if a jump inserted now will escape from a try block.
+  /// 
+  /// Concretely, this is true when [enterTry] has been called without
+  /// its corresponding [leaveTry] call.
+  bool get isEscapingTry => _boxedTryVariables.isNotEmpty;
 }
 
 /// A class to collect 'forward' jumps.
@@ -241,7 +247,8 @@
   void addJump(IrBuilder builder, [ir.Primitive value]) {
     assert(_continuation == null);
     _buildTryExit(builder);
-    ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
+    ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(
+        isEscapingTry: isEscapingTry);
     builder.add(invoke);
     _invocations.add(invoke);
     // Truncate the environment at the invocation site so it only includes
@@ -360,7 +367,8 @@
     if (value != null) builder.environment.extend(null, value);
     builder.add(new ir.InvokeContinuation(_continuation,
         builder.environment.index2value,
-        isRecursive: true));
+        isRecursive: true,
+        isEscapingTry: isEscapingTry));
     builder._current = null;
   }
 }
@@ -632,7 +640,7 @@
     assert(isOpen);
     return _continueWithExpression(
         (k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k,
-            sourceInformation: sourceInformation));
+                                   sourceInformation));
   }
 
   ir.Primitive _buildInvokeCall(ir.Primitive target,
@@ -746,8 +754,7 @@
     thenContinuation.body = thenBuilder._root;
     elseContinuation.body = elseBuilder._root;
     add(new ir.LetCont(join.continuation,
-            new ir.LetCont.many(<ir.Continuation>[thenContinuation,
-                                                  elseContinuation],
+            new ir.LetCont.two(thenContinuation, elseContinuation,
                 new ir.Branch(new ir.IsTrue(condition),
                               thenContinuation,
                               elseContinuation))));
@@ -862,8 +869,15 @@
                                Selector selector,
                                TypeMask mask) {
     assert(selector.isGetter);
-    return _buildInvokeDynamic(
-        receiver, selector, mask, const <ir.Primitive>[]);
+    FieldElement field = program.locateSingleField(selector, mask);
+    if (field != null) {
+      // If the world says this resolves to a unique field, then it MUST be
+      // treated as a field access, since the getter might not be emitted.
+      return buildFieldGet(receiver, field);
+    } else {
+      return _buildInvokeDynamic(
+          receiver, selector, mask, const <ir.Primitive>[]);
+    }
   }
 
   /// Create a dynamic setter invocation on [receiver] where the setter name and
@@ -873,7 +887,14 @@
                                TypeMask mask,
                                ir.Primitive value) {
     assert(selector.isSetter);
-    _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value]);
+    FieldElement field = program.locateSingleField(selector, mask);
+    if (field != null) {
+      // If the world says this resolves to a unique field, then it MUST be
+      // treated as a field access, since the setter might not be emitted.
+      buildFieldSet(receiver, field, value);
+    } else {
+      _buildInvokeDynamic(receiver, selector, mask, <ir.Primitive>[value]);
+    }
     return value;
   }
 
@@ -1223,8 +1244,7 @@
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
-        new ir.LetCont.many(<ir.Continuation>[exitContinuation,
-                                              bodyContinuation],
+        new ir.LetCont.two(exitContinuation, bodyContinuation,
             new ir.Branch(new ir.IsTrue(condition),
                           bodyContinuation,
                           exitContinuation));
@@ -1384,8 +1404,7 @@
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
-        new ir.LetCont.many(<ir.Continuation>[exitContinuation,
-                                              bodyContinuation],
+        new ir.LetCont.two(exitContinuation, bodyContinuation,
             new ir.Branch(new ir.IsTrue(condition),
                           bodyContinuation,
                           exitContinuation));
@@ -1460,8 +1479,7 @@
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
-        new ir.LetCont.many(<ir.Continuation>[exitContinuation,
-                                              bodyContinuation],
+        new ir.LetCont.two(exitContinuation, bodyContinuation,
             new ir.Branch(new ir.IsTrue(condition),
                           bodyContinuation,
                           exitContinuation));
@@ -1547,8 +1565,7 @@
     repeatContinuation.body = repeatBuilder._root;
 
     continueBuilder.add(
-        new ir.LetCont.many(<ir.Continuation>[exitContinuation,
-                                              repeatContinuation],
+        new ir.LetCont.two(exitContinuation, repeatContinuation,
             new ir.Branch(new ir.IsTrue(condition),
                           repeatContinuation,
                           exitContinuation)));
@@ -1614,8 +1631,7 @@
       // continuation, to be plugged by the translation.  Therefore put the
       // else continuation first.
       casesBuilder.add(
-          new ir.LetCont.many(<ir.Continuation>[elseContinuation,
-                                                thenContinuation],
+          new ir.LetCont.two(elseContinuation, thenContinuation,
               new ir.Branch(new ir.IsTrue(condition),
                             thenContinuation,
                             elseContinuation)));
@@ -1820,8 +1836,7 @@
             checkBuilder.buildTypeOperator(exceptionParameter,
                 clause.type,
                 isTypeTest: true);
-        checkBuilder.add(new ir.LetCont.many([thenContinuation,
-                                              elseContinuation],
+        checkBuilder.add(new ir.LetCont.two(thenContinuation, elseContinuation,
                 new ir.Branch(new ir.IsTrue(typeMatches),
                     thenContinuation,
                     elseContinuation)));
@@ -2092,8 +2107,7 @@
         ..plug(new ir.InvokeContinuation(joinContinuation, [trueConstant]));
 
     add(new ir.LetCont(joinContinuation,
-          new ir.LetCont.many(<ir.Continuation>[thenContinuation,
-                                                elseContinuation],
+          new ir.LetCont.two(thenContinuation, elseContinuation,
               new ir.Branch(new ir.IsTrue(condition),
                             thenContinuation,
                             elseContinuation))));
@@ -2153,8 +2167,7 @@
     rightFalseContinuation.body = rightFalseBuilder._root;
     // The right subexpression has two continuations.
     rightBuilder.add(
-        new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation,
-                                              rightFalseContinuation],
+        new ir.LetCont.two(rightTrueContinuation, rightFalseContinuation,
             new ir.Branch(new ir.IsTrue(rightValue),
                           rightTrueContinuation,
                           rightFalseContinuation)));
@@ -2170,8 +2183,7 @@
     }
 
     add(new ir.LetCont(join.continuation,
-            new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation,
-                                                  leftFalseContinuation],
+            new ir.LetCont.two(leftTrueContinuation, leftFalseContinuation,
                 new ir.Branch(new ir.IsTrue(leftValue),
                               leftTrueContinuation,
                               leftFalseContinuation))));
@@ -2397,6 +2409,16 @@
     return state.thisParameter;
   }
 
+  ir.Primitive buildFieldGet(ir.Primitive receiver, FieldElement target) {
+    return addPrimitive(new ir.GetField(receiver, target));
+  }
+
+  void buildFieldSet(ir.Primitive receiver, 
+                     FieldElement target, 
+                     ir.Primitive value) {
+    add(new ir.SetField(receiver, target, value));
+  }
+
   ir.Primitive buildSuperFieldGet(FieldElement target) {
     return addPrimitive(new ir.GetField(buildThis(), target));
   }
@@ -2585,6 +2607,10 @@
       }
       return addPrimitive(new ir.TypeTest(value, type, typeArguments));
     } else {
+      if (type.isObject || type.isDynamic) {
+        // `x as Object` and `x as dynamic` are the same as `x`.
+        return value;
+      }
       return _continueWithExpression(
               (k) => new ir.TypeCast(value, type, typeArguments, k));
     }
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index dd10751..8b81f39 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -43,7 +43,7 @@
 /// This class is mainly there to correctly measure how long building the IR
 /// takes.
 class IrBuilderTask extends CompilerTask {
-  final SourceInformationFactory sourceInformationFactory;
+  final SourceInformationStrategy sourceInformationStrategy;
 
   String bailoutMessage = null;
 
@@ -51,7 +51,7 @@
   /// [ir.FunctionDefinition] node that has been built.
   IrBuilderCallback builderCallback;
 
-  IrBuilderTask(Compiler compiler, this.sourceInformationFactory,
+  IrBuilderTask(Compiler compiler, this.sourceInformationStrategy,
       [this.builderCallback])
       : super(compiler);
 
@@ -65,7 +65,7 @@
       element = element.implementation;
       return compiler.withCurrentElement(element, () {
         SourceInformationBuilder sourceInformationBuilder =
-            sourceInformationFactory.forContext(element);
+            sourceInformationStrategy.createBuilderForContext(element);
 
         IrBuilderVisitor builder =
             new JsIrBuilderVisitor(
@@ -2187,6 +2187,10 @@
   TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
     return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
   }
+
+  FieldElement locateSingleField(Selector selector, TypeMask type) {
+    return _compiler.world.locateSingleField(selector, type);
+  }
 }
 
 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
@@ -3034,7 +3038,8 @@
           element, CallStructure.TWO_ARGS);
       return irBuilder.buildStaticFunctionInvocation(element,
           CallStructure.TWO_ARGS, arguments,
-          sourceInformation: sourceInformationBuilder.buildCall(node));
+          sourceInformation:
+                sourceInformationBuilder.buildCall(node, node.selector));
     }
 
     /// Lookup the value of the enum described by [node].
@@ -3181,14 +3186,18 @@
         if (!compiler.hasIsolateSupport) {
           // If the isolate library is not used, we just generate code
           // to fetch the current isolate.
-          String name = backend.namer.currentIsolate;
-          return irBuilder.buildForeignCode(js.js.parseForeignJS(name),
-              const <ir.Primitive>[], NativeBehavior.PURE);
-        } else {
-          return buildIsolateHelperInvocation('_currentIsolate',
-              CallStructure.NO_ARGS);
+          continue GET_CURRENT_ISOLATE;
         }
-        break;
+        return buildIsolateHelperInvocation('_currentIsolate',
+            CallStructure.NO_ARGS);
+
+      GET_CURRENT_ISOLATE: case 'JS_CURRENT_ISOLATE':
+        validateArgumentCount(exactly: 0);
+
+        return irBuilder.buildForeignCode(
+            js.js.parseForeignJS(backend.namer.currentIsolate),
+            const <ir.Primitive>[],
+            NativeBehavior.PURE);
 
       case 'JS_CALL_IN_ISOLATE':
         validateArgumentCount(exactly: 2);
@@ -3197,11 +3206,9 @@
           ir.Primitive closure = visit(argumentNodes.tail.head);
           return irBuilder.buildCallInvocation(closure, CallStructure.NO_ARGS,
               const <ir.Primitive>[]);
-        } else {
-          return buildIsolateHelperInvocation('_callInIsolate',
-              CallStructure.TWO_ARGS);
         }
-        break;
+        return buildIsolateHelperInvocation('_callInIsolate',
+            CallStructure.TWO_ARGS);
 
       default:
         giveup(node, 'unplemented native construct: ${function.name}');
@@ -3220,7 +3227,8 @@
     } else {
       return irBuilder.buildStaticFunctionInvocation(function, callStructure,
           translateStaticArguments(argumentList, function, callStructure),
-          sourceInformation: sourceInformationBuilder.buildCall(node));
+          sourceInformation:
+              sourceInformationBuilder.buildCall(node, node.selector));
     }
   }
 }
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 fec259b..29d324e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -3,13 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 library dart2js.ir_nodes;
 
-import '../constants/expressions.dart';
 import '../constants/values.dart' as values show ConstantValue;
 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
 import '../elements/elements.dart';
 import '../io/source_information.dart' show SourceInformation;
 import '../types/types.dart' show TypeMask;
-import '../universe/universe.dart' show Selector, SelectorKind;
+import '../universe/universe.dart' show Selector;
 
 import 'builtin_operator.dart';
 export 'builtin_operator.dart';
@@ -19,7 +18,6 @@
 // abstractions for native code and its type and effect system.
 import '../js/js.dart' as js show Template;
 import '../native/native.dart' as native show NativeBehavior;
-import '../types/types.dart' as types show TypeMask;
 
 abstract class Node {
   /// A pointer to the parent node. Is null until set by optimization passes.
@@ -97,7 +95,11 @@
   ///
   /// False must be returned for primitives that may throw, diverge, or have
   /// observable side-effects.
-  bool get isSafeForElimination => true;
+  bool get isSafeForElimination;
+
+  /// True if time-of-evaluation is irrelevant for the given primitive,
+  /// assuming its inputs are the same values.
+  bool get isSafeForReordering;
 }
 
 /// Operands to invocations and primitives are always variables.  They point to
@@ -169,6 +171,9 @@
   LetCont(Continuation continuation, this.body)
       : continuations = <Continuation>[continuation];
 
+  LetCont.two(Continuation first, Continuation second, this.body)
+      : continuations = <Continuation>[first, second];
+
   LetCont.many(this.continuations, this.body);
 
   Expression plug(Expression expr) {
@@ -223,9 +228,10 @@
   accept(Visitor visitor) => visitor.visitLetMutable(this);
 }
 
-abstract class Invoke {
+abstract class Invoke implements Expression {
   Selector get selector;
   List<Reference<Primitive>> get arguments;
+  Reference<Continuation> get continuation;
 }
 
 /// Represents a node with a child node, which can be accessed through the
@@ -260,10 +266,16 @@
                this.selector,
                List<Primitive> args,
                Continuation cont,
-               this.sourceInformation)
+               [this.sourceInformation])
       : arguments = _referenceList(args),
         continuation = new Reference<Continuation>(cont);
 
+  InvokeStatic.byReference(this.target,
+                           this.selector,
+                           this.arguments,
+                           this.continuation,
+                           [this.sourceInformation]);
+
   accept(Visitor visitor) => visitor.visitInvokeStatic(this);
 }
 
@@ -276,10 +288,6 @@
 ///
 /// The [selector] records the names of named arguments. The value of named
 /// arguments occur at the end of the [arguments] list, in normalized order.
-///
-/// Discussion:
-/// If the [selector] is a [TypedSelector], the type information contained
-/// there is used by optimization passes. This is likely to change.
 class InvokeMethod extends Expression implements Invoke {
   Reference<Primitive> receiver;
   Selector selector;
@@ -296,11 +304,18 @@
                this.mask,
                List<Primitive> arguments,
                Continuation continuation,
-               {this.sourceInformation})
+               [this.sourceInformation])
       : this.receiver = new Reference<Primitive>(receiver),
         this.arguments = _referenceList(arguments),
         this.continuation = new Reference<Continuation>(continuation);
 
+  InvokeMethod.byReference(this.receiver,
+                           this.selector,
+                           this.mask,
+                           this.arguments,
+                           this.continuation,
+                           [this.sourceInformation]);
+
   accept(Visitor visitor) => visitor.visitInvokeMethod(this);
 }
 
@@ -406,6 +421,9 @@
     this.typeArguments = _referenceList(typeArguments);
 
   accept(Visitor visitor) => visitor.visitTypeTest(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// An "as" type cast.
@@ -448,6 +466,9 @@
       : this.arguments = _referenceList(arguments);
 
   accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Throw a value.
@@ -483,6 +504,9 @@
   NonTailThrow(Primitive value) : value = new Reference<Primitive>(value);
 
   accept(Visitor visitor) => visitor.visitNonTailThrow(this);
+
+  bool get isSafeForElimination => false;
+  bool get isSafeForReordering => false;
 }
 
 /// An expression that is known to be unreachable.
@@ -507,6 +531,9 @@
       : this.variable = new Reference<MutableVariable>(variable);
 
   accept(Visitor visitor) => visitor.visitGetMutableVariable(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => false;
 }
 
 /// Assign a [MutableVariable].
@@ -541,8 +568,13 @@
   // the continuation itself.
   bool isRecursive;
 
+  /// True if this invocation escapes from the body of a [LetHandler]
+  /// (i.e. a try block). Notably, such an invocation cannot be inlined.
+  bool isEscapingTry;
+
   InvokeContinuation(Continuation cont, List<Primitive> args,
-                     {this.isRecursive: false})
+                     {this.isRecursive: false,
+                      this.isEscapingTry: false})
       : continuation = new Reference<Continuation>(cont),
         arguments = _referenceList(args) {
     assert(cont.parameters == null || cont.parameters.length == args.length);
@@ -554,7 +586,8 @@
   ///
   /// Used as a placeholder for a jump whose target is not yet created
   /// (e.g., in the translation of break and continue).
-  InvokeContinuation.uninitialized({this.isRecursive: false})
+  InvokeContinuation.uninitialized({this.isRecursive: false, 
+                                    this.isEscapingTry: false})
       : continuation = null,
         arguments = null;
 
@@ -624,19 +657,28 @@
 
   accept(Visitor visitor) => visitor.visitGetField(this);
 
-  @override
   bool get isSafeForElimination => objectIsNotNull;
+  bool get isSafeForReordering => objectIsNotNull && field.isFinal;
 }
 
 /// Reads the value of a static field or tears off a static method.
+///
+/// Note that lazily initialized fields should be read using GetLazyStatic.
 class GetStatic extends Primitive {
   /// Can be [FieldElement] or [FunctionElement].
   final Element element;
   final SourceInformation sourceInformation;
 
-  GetStatic(this.element, this.sourceInformation);
+  GetStatic(this.element, [this.sourceInformation]);
 
   accept(Visitor visitor) => visitor.visitGetStatic(this);
+  
+  bool get isSafeForElimination {
+    return true;
+  }
+  bool get isSafeForReordering {
+    return element is FunctionElement || element.isFinal;
+  }
 }
 
 /// Sets the value of a static field.
@@ -646,7 +688,7 @@
   Expression body;
   final SourceInformation sourceInformation;
 
-  SetStatic(this.element, Primitive value, this.sourceInformation)
+  SetStatic(this.element, Primitive value, [this.sourceInformation])
       : this.value = new Reference<Primitive>(value);
 
   Expression plug(Expression expr) {
@@ -670,7 +712,7 @@
 
   GetLazyStatic(this.element,
                 Continuation continuation,
-                this.sourceInformation)
+                [this.sourceInformation])
       : continuation = new Reference<Continuation>(continuation);
 
   accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
@@ -679,6 +721,9 @@
 /// Creates an object for holding boxed variables captured by a closure.
 class CreateBox extends Primitive {
   accept(Visitor visitor) => visitor.visitCreateBox(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Creates an instance of a class and initializes its fields and runtime type
@@ -703,6 +748,9 @@
         this.typeInformation = _referenceList(typeInformation);
 
   accept(Visitor visitor) => visitor.visitCreateInstance(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 class Interceptor extends Primitive {
@@ -711,6 +759,9 @@
   Interceptor(Primitive input, this.interceptedClasses)
       : this.input = new Reference<Primitive>(input);
   accept(Visitor visitor) => visitor.visitInterceptor(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Create an instance of [Invocation] for use in a call to `noSuchMethod`.
@@ -722,11 +773,14 @@
       : this.arguments = _referenceList(arguments);
 
   accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 class ForeignCode extends Expression {
   final js.Template codeTemplate;
-  final types.TypeMask type;
+  final TypeMask type;
   final List<Reference<Primitive>> arguments;
   final native.NativeBehavior nativeBehavior;
   final FunctionElement dependency;
@@ -750,6 +804,9 @@
   Constant(this.value);
 
   accept(Visitor visitor) => visitor.visitConstant(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 class LiteralList extends Primitive {
@@ -761,6 +818,9 @@
       : this.values = _referenceList(values);
 
   accept(Visitor visitor) => visitor.visitLiteralList(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 class LiteralMapEntry {
@@ -779,6 +839,9 @@
   LiteralMap(this.type, this.entries);
 
   accept(Visitor visitor) => visitor.visitLiteralMap(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Currently unused.
@@ -797,6 +860,9 @@
   CreateFunction(this.definition);
 
   accept(Visitor visitor) => visitor.visitCreateFunction(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 class Parameter extends Primitive {
@@ -813,6 +879,9 @@
   accept(Visitor visitor) => visitor.visitParameter(this);
 
   String toString() => 'Parameter(${hint == null ? null : hint.name})';
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Continuations are normally bound by 'let cont'.  A continuation with one
@@ -834,7 +903,9 @@
 
   Continuation(this.parameters, {this.isRecursive: false});
 
-  Continuation.retrn() : parameters = <Parameter>[new Parameter(null)];
+  Continuation.retrn() 
+    : parameters = <Parameter>[new Parameter(null)],
+      isRecursive = false;
 
   accept(Visitor visitor) => visitor.visitContinuation(this);
 }
@@ -879,6 +950,9 @@
 
   @override
   accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Read the value the type variable [variable] from the target object.
@@ -895,6 +969,9 @@
 
   @override
   accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 /// Representation of a closed type (that is, a type without type variables).
@@ -917,6 +994,9 @@
   accept(Visitor visitor) {
     return visitor.visitTypeExpression(this);
   }
+
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
 }
 
 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) {
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index f93f493..091ca53 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -53,6 +53,10 @@
     return mask.locateSingleElement(selector, mask, classWorld.compiler);
   }
 
+  bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
+    return mask.needsNoSuchMethodHandling(selector, classWorld);
+  }
+
   TypeMask getReceiverType(MethodElement method) {
     assert(method.isInstanceMember);
     return nonNullSubclass(method.enclosingClass);
@@ -170,6 +174,15 @@
     // TODO(asgerf): Support function types, and what else might be missing.
     return AbstractBool.Maybe;
   }
+
+  /// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
+  /// the empty string, or null.
+  AbstractBool boolify(TypeMask type) {
+    if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
+      return AbstractBool.True;
+    }
+    return AbstractBool.Maybe;
+  }
 }
 
 class ConstantPropagationLattice {
@@ -367,6 +380,30 @@
     }
   }
 
+  bool isEmptyString(ConstantValue value) {
+    return value is StringConstantValue && value.primitiveValue.isEmpty;
+  }
+
+  /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
+  /// the empty string, or null.
+  AbstractBool boolify(AbstractValue value) {
+    if (value.isNothing) return AbstractBool.Nothing;
+    if (value.isConstant) {
+      ConstantValue constantValue = value.constant;
+      if (constantValue.isFalse ||
+          constantValue.isNull  ||
+          constantValue.isZero ||
+          constantValue.isMinusZero ||
+          constantValue.isNaN ||
+          isEmptyString(constantValue)) {
+        return AbstractBool.False;
+      } else {
+        return AbstractBool.True;
+      }
+    }
+    return typeSystem.boolify(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.
@@ -426,8 +463,7 @@
     TransformingVisitor transformer = new TransformingVisitor(
         _compiler,
         _lattice,
-        analyzer.reachableNodes,
-        analyzer.values,
+        analyzer,
         replacements,
         _internalError);
     transformer.transform(root);
@@ -455,8 +491,7 @@
  * actual transformations on the CPS graph.
  */
 class TransformingVisitor extends RecursiveVisitor {
-  final Set<Node> reachable;
-  final Map<Node, AbstractValue> values;
+  final TypePropagationVisitor analyzer;
   final Map<Expression, ConstantValue> replacements;
   final ConstantPropagationLattice lattice;
   final dart2js.Compiler compiler;
@@ -464,13 +499,14 @@
   JavaScriptBackend get backend => compiler.backend;
   TypeMaskSystem get typeSystem => lattice.typeSystem;
   types.DartTypes get dartTypes => lattice.dartTypes;
+  Set<Node> get reachable => analyzer.reachableNodes;
+  Map<Node, AbstractValue> get values => analyzer.values;
 
   final dart2js.InternalErrorFunction internalError;
 
   TransformingVisitor(this.compiler,
                       this.lattice,
-                      this.reachable,
-                      this.values,
+                      this.analyzer,
                       this.replacements,
                       this.internalError);
 
@@ -478,20 +514,34 @@
     visit(root);
   }
 
+  /// Sets parent pointers and computes types for the given subtree.
+  void reanalyze(Node node) {
+    new ParentVisitor().visit(node);
+    analyzer.reanalyzeSubtree(node);
+  }
+
   /// Removes the entire subtree of [node] and inserts [replacement].
-  /// All references in the [node] subtree are unlinked, and parent pointers
-  /// in [replacement] are initialized.
+  ///
+  /// By default, all references in the [node] subtree are unlinked, and parent
+  /// pointers in [replacement] are initialized and its types recomputed.
+  ///
+  /// If the caller needs to manually unlink the node, because some references
+  /// were adopted by other nodes, it can be disabled by passing `false`
+  /// as the [unlink] parameter.
   ///
   /// [replacement] must be "fresh", i.e. it must not contain significant parts
   /// of the original IR inside of it since the [ParentVisitor] will
   /// redundantly reprocess it.
-  void replaceSubtree(Expression node, Expression replacement) {
+  void replaceSubtree(Expression node, Expression replacement,
+                      {bool unlink: true}) {
     InteriorNode parent = node.parent;
     parent.body = replacement;
     replacement.parent = parent;
     node.parent = null;
-    RemovalVisitor.remove(node);
-    new ParentVisitor().visit(replacement);
+    if (unlink) {
+      RemovalVisitor.remove(node);
+    }
+    reanalyze(replacement);
   }
 
   /// Make a constant primitive for [constant] and set its entry in [values].
@@ -525,7 +575,8 @@
   /// The new expression will be visited.
   ///
   /// Returns true if the node was replaced.
-  bool constifyExpression(Expression node, Continuation continuation) {
+  bool constifyExpression(Invoke node) {
+    Continuation continuation = node.continuation.definition;
     ConstantValue constant = replacements[node];
     if (constant == null) return false;
     Constant primitive = makeConstantPrimitive(constant);
@@ -542,50 +593,55 @@
   //
   // (Branch (IsTrue true) k0 k1) -> (InvokeContinuation k0)
   void visitBranch(Branch node) {
-    bool trueReachable  = reachable.contains(node.trueContinuation.definition);
-    bool falseReachable = reachable.contains(node.falseContinuation.definition);
-    bool bothReachable  = (trueReachable && falseReachable);
-    bool noneReachable  = !(trueReachable || falseReachable);
+    Continuation trueCont = node.trueContinuation.definition;
+    Continuation falseCont = node.falseContinuation.definition;
+    IsTrue conditionNode = node.condition;
+    Primitive condition = conditionNode.value.definition;
 
-    if (bothReachable || noneReachable) {
-      // Nothing to do, shrinking reductions take care of the unreachable case.
-      super.visitBranch(node);
+    AbstractValue conditionValue = getValue(condition);
+    AbstractBool boolifiedValue = lattice.boolify(conditionValue);
+
+    if (boolifiedValue == AbstractBool.True) {
+      InvokeContinuation invoke = new InvokeContinuation(trueCont, []);
+      replaceSubtree(node, invoke);
+      visitInvokeContinuation(invoke);
+      return;
+    }
+    if (boolifiedValue == AbstractBool.False) {
+      InvokeContinuation invoke = new InvokeContinuation(falseCont, []);
+      replaceSubtree(node, invoke);
+      visitInvokeContinuation(invoke);
       return;
     }
 
-    Continuation successor = (trueReachable) ?
-        node.trueContinuation.definition : node.falseContinuation.definition;
-
-    // Replace the branch by a continuation invocation.
-
-    assert(successor.parameters.isEmpty);
-    InvokeContinuation invoke =
-        new InvokeContinuation(successor, <Primitive>[]);
-
-    replaceSubtree(node, invoke);
-    visitInvokeContinuation(invoke);
-  }
-
-  /// True if the given reference is a use that converts its value to a boolean
-  /// and only uses the coerced value.
-  bool isBoolifyingUse(Reference<Primitive> ref) {
-    Node use = ref.parent;
-    return use is IsTrue ||
-      use is ApplyBuiltinOperator && use.operator == BuiltinOperator.IsFalsy;
-  }
-
-  /// True if all uses of [prim] only use its value after boolean conversion.
-  bool isAlwaysBoolified(Primitive prim) {
-    for (Reference ref = prim.firstRef; ref != null; ref = ref.next) {
-      if (!isBoolifyingUse(ref)) return false;
+    if (condition is ApplyBuiltinOperator && 
+        condition.operator == BuiltinOperator.LooseEq) {
+      Primitive leftArg = condition.arguments[0].definition;
+      Primitive rightArg = condition.arguments[1].definition;
+      AbstractValue left = getValue(leftArg);
+      AbstractValue right = getValue(rightArg);
+      if (right.isNullConstant && 
+          lattice.isDefinitelyNotNumStringBool(left)) {
+        // Rewrite:
+        //   if (x == null) S1 else S2
+        //     =>
+        //   if (x) S2 else S1   (note the swapped branches)
+        Branch branch = new Branch(new IsTrue(leftArg), falseCont, trueCont);
+        replaceSubtree(node, branch);
+        return;
+      } else if (left.isNullConstant && 
+                 lattice.isDefinitelyNotNumStringBool(right)) {
+        Branch branch = new Branch(new IsTrue(rightArg), falseCont, trueCont);
+        replaceSubtree(node, branch);
+        return;
+      }
     }
-    return true;
   }
 
   /// Replaces [node] with a more specialized instruction, if possible.
   ///
   /// Returns `true` if the node was replaced.
-  bool specializeInvoke(InvokeMethod node) {
+  bool specializeOperatorCall(InvokeMethod node) {
     Continuation cont = node.continuation.definition;
     bool replaceWithBinary(BuiltinOperator operator,
                            Primitive left,
@@ -597,15 +653,6 @@
       visitLetPrim(let);
       return true; // So returning early is more convenient.
     }
-    bool replaceWithUnary(BuiltinOperator operator,
-                          Primitive argument) {
-      Primitive prim =
-          new ApplyBuiltinOperator(operator, <Primitive>[argument]);
-      LetPrim let = makeLetPrimInvoke(prim, cont);
-      replaceSubtree(node, let);
-      visitLetPrim(let);
-      return true;
-    }
 
     if (node.selector.isOperator && node.arguments.length == 2) {
       // The operators we specialize are are intercepted calls, so the operands
@@ -619,19 +666,6 @@
         // Equality is special due to its treatment of null values and the
         // fact that Dart-null corresponds to both JS-null and JS-undefined.
         // Please see documentation for IsFalsy, StrictEq, and LooseEq.
-        bool isBoolified = isAlwaysBoolified(cont.parameters.single);
-        // Comparison with null constants.
-        if (isBoolified &&
-            right.isNullConstant &&
-            lattice.isDefinitelyNotNumStringBool(left)) {
-          // TODO(asgerf): This is shorter but might confuse te VM? Evaluate.
-          return replaceWithUnary(BuiltinOperator.IsFalsy, leftArg);
-        }
-        if (isBoolified &&
-            left.isNullConstant &&
-            lattice.isDefinitelyNotNumStringBool(right)) {
-          return replaceWithUnary(BuiltinOperator.IsFalsy, rightArg);
-        }
         if (left.isNullConstant || right.isNullConstant) {
           return replaceWithBinary(BuiltinOperator.LooseEq, leftArg, rightArg);
         }
@@ -664,8 +698,10 @@
         }
         else if (lattice.isDefinitelyString(left, allowNull: false) &&
                  lattice.isDefinitelyString(right, allowNull: false)) {
-          return replaceWithBinary(BuiltinOperator.StringConcatenate,
-                                   leftArg, rightArg);
+          if (node.selector.name == '+') {
+            return replaceWithBinary(BuiltinOperator.StringConcatenate,
+                                     leftArg, rightArg);
+          }
         }
       }
     }
@@ -698,10 +734,9 @@
   /// invocation with a direct access to a field.
   ///
   /// Returns `true` if the node was replaced.
-  bool inlineFieldAccess(InvokeMethod node) {
+  bool specializeFieldAccess(InvokeMethod node) {
     if (!node.selector.isGetter && !node.selector.isSetter) return false;
     AbstractValue receiver = getValue(getDartReceiver(node));
-    if (receiver.isNothing) return false;
     Element target =
         typeSystem.locateSingleElement(receiver.type, node.selector);
     if (target is! FieldElement) return false;
@@ -711,7 +746,6 @@
     Continuation cont = node.continuation.definition;
     if (node.selector.isGetter) {
       GetField get = new GetField(getDartReceiver(node), target);
-      get.objectIsNotNull = receiver.isDefinitelyNotNull;
       LetPrim let = makeLetPrimInvoke(get, cont);
       replaceSubtree(node, let);
       visitLetPrim(let);
@@ -730,11 +764,148 @@
     }
   }
 
+  /// If [prim] is the parameter to a call continuation, returns the
+  /// corresponding call.
+  Invoke getInvocationWithResult(Primitive prim) {
+    if (prim is Parameter && prim.parent is Continuation) {
+      Continuation cont = prim.parent;
+      if (cont.hasExactlyOneUse) {
+        Node use = cont.firstRef.parent;
+        if (use is Invoke) {
+          return use;
+        }
+      }
+    }
+    return null;
+  }
+
+  /// True if any side effect immediately before [current] can safely be
+  /// postponed until immediately before [target].
+  ///
+  /// An expression `e` can be moved right before [target] if
+  /// `canPostponeSideEffects(e.body, target)` is true and no reference
+  /// falls out of scope.
+  ///
+  /// A more sophisticated analysis would track side-effect dependencies
+  /// between `e` and the expressions between `e` and the target.
+  bool canPostponeSideEffects(Expression current, Expression target) {
+    Expression exp = current;
+    while (exp != target) {
+      if (exp is LetPrim && exp.primitive.isSafeForReordering) {
+        LetPrim let = exp;
+        exp = let.body;
+      } else if (exp is LetCont) {
+        LetCont let = exp;
+        exp = let.body;
+      } else {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /// Rewrites an invocation of a torn-off method into a method call directly
+  /// on the receiver. For example:
+  ///
+  ///     obj.get$foo().call$<n>(<args>)
+  ///       =>
+  ///     obj.foo$<n>(<args>)
+  ///
+  bool specializeClosureCall(InvokeMethod node) {
+    Selector call = node.selector;
+    if (!call.isClosureCall) return false;
+
+    assert(!isInterceptedSelector(call));
+    assert(call.argumentCount == node.arguments.length);
+
+    Primitive tearOff = node.receiver.definition;
+    // Note: We don't know if [tearOff] is actually a tear-off.
+    // We name variables based on the pattern we are trying to match.
+
+    if (tearOff is GetStatic && tearOff.element.isFunction) {
+      FunctionElement target = tearOff.element;
+      FunctionSignature signature = target.functionSignature;
+
+      // If the selector does not apply, don't bother (will throw at runtime).
+      if (!call.signatureApplies(target)) return false;
+
+      // If some optional arguments are missing, give up.
+      // TODO(asgerf): Improve optimization by inserting default arguments.
+      if (call.argumentCount != signature.parameterCount) return false;
+
+      InvokeStatic invoke = new InvokeStatic.byReference(
+          target,
+          new Selector.fromElement(target),
+          node.arguments,
+          node.continuation,
+          node.sourceInformation);
+      node.receiver.unlink();
+      replaceSubtree(node, invoke, unlink: false);
+      visitInvokeStatic(invoke);
+      return true;
+    }
+    Invoke tearOffInvoke = getInvocationWithResult(tearOff);
+    if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) {
+      Selector getter = tearOffInvoke.selector;
+      Continuation getterCont = tearOffInvoke.continuation.definition;
+
+      // TODO(asgerf): Support torn-off intercepted methods.
+      if (isInterceptedSelector(getter)) return false;
+
+      Primitive object = tearOffInvoke.receiver.definition;
+
+      // Ensure that the object actually has a foo member, since we might
+      // otherwise alter a noSuchMethod call.
+      TypeMask type = getValue(object).type;
+      if (typeSystem.needsNoSuchMethodHandling(type, getter)) return false;
+
+      // Determine if the getter invocation can have side-effects.
+      Element element = typeSystem.locateSingleElement(type, getter);
+      bool isPure = element != null && !element.isGetter;
+
+      // If there are multiple uses, we cannot eliminate the getter call and
+      // therefore risk duplicating its side effects.
+      if (!isPure && tearOff.hasMultipleUses) return false;
+
+      // If the getter call is impure, we risk reordering side effects.
+      if (!isPure && !canPostponeSideEffects(getterCont.body, node)) {
+        return false;
+      }
+
+      InvokeMethod invoke = new InvokeMethod.byReference(
+        new Reference<Primitive>(object),
+        new Selector(SelectorKind.CALL, getter.memberName, call.callStructure),
+        type,
+        node.arguments,
+        node.continuation,
+        node.sourceInformation);
+      node.receiver.unlink();
+      replaceSubtree(node, invoke, unlink: false);
+
+      if (tearOff.hasNoUses) {
+        // Eliminate the getter call if it has no more uses.
+        // This cannot be delegated to other optimizations because we need to
+        // avoid duplication of side effects.
+        getterCont.parameters.clear();
+        replaceSubtree(tearOffInvoke, new InvokeContinuation(getterCont, []));
+      } else {
+        // There are more uses, so we cannot eliminate the getter call. This
+        // means we duplicated the effects of the getter call, but we should
+        // only get here if the getter has no side effects.
+        assert(isPure);
+      }
+
+      visitInvokeMethod(invoke);
+      return true;
+    }
+    return false;
+  }
+
   void visitInvokeMethod(InvokeMethod node) {
-    Continuation cont = node.continuation.definition;
-    if (constifyExpression(node, cont)) return;
-    if (specializeInvoke(node)) return;
-    if (inlineFieldAccess(node)) return;
+    if (constifyExpression(node)) return;
+    if (specializeOperatorCall(node)) return;
+    if (specializeFieldAccess(node)) return;
+    if (specializeClosureCall(node)) return;
 
     AbstractValue receiver = getValue(node.receiver.definition);
     node.receiverIsNotNull = receiver.isDefinitelyNotNull;
@@ -768,10 +939,10 @@
     super.visitTypeCast(node);
   }
 
-  /// Specialize calls to static methods.
+  /// Specialize calls to internal static methods.
   ///
   /// Returns true if the call was replaced.
-  bool specializeInvokeStatic(InvokeStatic node) {
+  bool specializeInternalMethodCall(InvokeStatic node) {
     // TODO(asgerf): This is written to easily scale to more cases,
     //               either add more cases or clean up.
     Continuation cont = node.continuation.definition;
@@ -794,8 +965,8 @@
   }
 
   void visitInvokeStatic(InvokeStatic node) {
-    if (constifyExpression(node, node.continuation.definition)) return;
-    if (specializeInvokeStatic(node)) return;
+    if (constifyExpression(node)) return;
+    if (specializeInternalMethodCall(node)) return;
   }
 
   AbstractValue getValue(Primitive primitive) {
@@ -848,6 +1019,7 @@
             node.arguments[k] = null; // Remove the argument after the loop.
           }
           node.arguments[startOfSequence] = new Reference<Primitive>(prim);
+          node.arguments[startOfSequence].parent = node;
           argumentsWereRemoved = true;
         }
         if (argumentsWereRemoved) {
@@ -911,16 +1083,15 @@
       newPrim.substituteFor(node.primitive);
       RemovalVisitor.remove(node.primitive);
       node.primitive = newPrim;
+      newPrim.parent = node;
     } else {
       Primitive newPrim = visit(node.primitive);
       if (newPrim != null) {
-        if (!values.containsKey(newPrim)) {
-          // If the type was not set, default to the same type as before.
-          values[newPrim] = values[node.primitive];
-        }
         newPrim.substituteFor(node.primitive);
         RemovalVisitor.remove(node.primitive);
         node.primitive = newPrim;
+        newPrim.parent = node;
+        reanalyze(newPrim);
       }
       if (node.primitive.hasNoUses && node.primitive.isSafeForElimination) {
         // Remove unused primitives before entering the body.
@@ -934,6 +1105,41 @@
     }
     visit(node.body);
   }
+
+  void visitLetCont(LetCont node) {
+    // Visit body before continuations to ensure more information is available
+    // about the parameters. In particular, if this is a call continuation, its
+    // invocation should be specialized before the body is processed, because
+    // we specialize definitions before their uses.
+    visit(node.body);
+    node.continuations.forEach(visit);
+  }
+
+  void visitInvokeContinuation(InvokeContinuation node) {
+    // Inline the single-use continuations. These are often introduced when
+    // specializing an invocation node. These would also be inlined by a later
+    // pass, but doing it here helps simplify pattern matching code, since the
+    // effective definition of a primitive can then be found without going
+    // through redundant InvokeContinuations.
+    Continuation cont = node.continuation.definition;
+    if (cont.hasExactlyOneUse &&
+        !cont.isReturnContinuation &&
+        !cont.isRecursive &&
+        !node.isEscapingTry) {
+      for (int i = 0; i < node.arguments.length; ++i) {
+        node.arguments[i].definition.substituteFor(cont.parameters[i]);
+        node.arguments[i].unlink();
+      }
+      node.continuation.unlink();
+      InteriorNode parent = node.parent;
+      Expression body = cont.body;
+      parent.body = body;
+      body.parent = parent;
+      cont.body = new Unreachable();
+      cont.body.parent = cont;
+      visit(body);
+    }
+  }
 }
 
 /**
@@ -986,12 +1192,20 @@
 
   void analyze(FunctionDefinition root) {
     reachableNodes.clear();
-    defWorkset.clear();
-    nodeWorklist.clear();
 
     // Initially, only the root node is reachable.
     setReachable(root);
 
+    iterateWorklist();
+  }
+
+  void reanalyzeSubtree(Node node) {
+    new ResetAnalysisInfo(reachableNodes, values).visit(node);
+    setReachable(node);
+    iterateWorklist();
+  }
+
+  void iterateWorklist() {
     while (true) {
       if (nodeWorklist.isNotEmpty) {
         // Process a new reachable expression.
@@ -1195,8 +1409,6 @@
   }
 
   void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
-    // Note that most built-in operators do not exist before the transformation
-    // pass after this analysis has finished.
     switch (node.operator) {
       case BuiltinOperator.StringConcatenate:
         DartString stringValue = const LiteralDartString('');
@@ -1252,8 +1464,31 @@
         }
         break;
 
-      default:
-        setValue(node, nonConstant());
+      // TODO(asgerf): Implement constant propagation for builtins.
+      case BuiltinOperator.NumAdd:
+      case BuiltinOperator.NumSubtract:
+      case BuiltinOperator.NumMultiply:
+      case BuiltinOperator.NumAnd:
+      case BuiltinOperator.NumOr:
+      case BuiltinOperator.NumXor:
+        setValue(node, nonConstant(typeSystem.numType));
+        break;
+
+      case BuiltinOperator.NumLt:
+      case BuiltinOperator.NumLe:
+      case BuiltinOperator.NumGt:
+      case BuiltinOperator.NumGe:
+      case BuiltinOperator.StrictEq:
+      case BuiltinOperator.StrictNeq:
+      case BuiltinOperator.LooseEq:
+      case BuiltinOperator.LooseNeq:
+      case BuiltinOperator.IsFalsy:
+      case BuiltinOperator.IsNumber:
+      case BuiltinOperator.IsNotNumber:
+      case BuiltinOperator.IsFloor:
+      case BuiltinOperator.IsNumberAndFloor:
+        setValue(node, nonConstant(typeSystem.boolType));
+        break;
     }
   }
 
@@ -1375,7 +1610,12 @@
 
   void visitConstant(Constant node) {
     ConstantValue value = node.value;
-    setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
+    if (value.isDummy || !value.isConstant) {
+      // TODO(asgerf): Explain how this happens and why we don't want them.
+      setValue(node, nonConstant(typeSystem.getTypeOf(value)));
+    } else {
+      setValue(node, constantValue(value, typeSystem.getTypeOf(value)));
+    }
   }
 
   void visitCreateFunction(CreateFunction node) {
@@ -1538,10 +1778,11 @@
 
   AbstractValue._internal(this.kind, this.constant, this.type) {
     assert(kind != CONSTANT || constant != null);
+    assert(constant is! SyntheticConstantValue);
   }
 
   AbstractValue.nothing()
-      : this._internal(NOTHING, null, null);
+      : this._internal(NOTHING, null, new TypeMask.nonNullEmpty());
 
   AbstractValue.constantValue(ConstantValue constant, TypeMask type)
       : this._internal(CONSTANT, constant, type);
@@ -1583,3 +1824,16 @@
 abstract class InternalMethod {
   static const String Stringify = 'S';
 }
+
+class ResetAnalysisInfo extends RecursiveVisitor {
+  Set<Node> reachableNodes;
+  Map<Definition, AbstractValue> values;
+
+  ResetAnalysisInfo(this.reachableNodes, this.values);
+
+  visit(Node node) {
+    reachableNodes.remove(node);
+    if (node is Definition) values.remove(node);
+    node.accept(this);
+  }
+}
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 3b351af..2cbaf31 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -311,6 +311,7 @@
         '--output-type=dart|--output-type=dart-multi|--output-type=js',
         setOutputType),
     new OptionHandler('--use-cps-ir', passThrough),
+    new OptionHandler('--no-frequency-based-minification', passThrough),
     new OptionHandler('--verbose', setVerbose),
     new OptionHandler('--version', (_) => wantVersion = true),
     new OptionHandler('--library-root=.+', setLibraryRoot),
@@ -648,6 +649,10 @@
 
   --use-cps-ir
     Experimental.  Use the new CPS based backend for code generation.
+
+  --no-frequency-based-minification
+    Experimental.  Disabled the new frequency based minifying namer and use the
+    old namer instead.
 '''.trim());
 }
 
diff --git a/pkg/compiler/lib/src/dart2jslib.dart b/pkg/compiler/lib/src/dart2jslib.dart
index a203791..fcbeecb 100644
--- a/pkg/compiler/lib/src/dart2jslib.dart
+++ b/pkg/compiler/lib/src/dart2jslib.dart
@@ -52,6 +52,7 @@
 import 'resolution/send_structure.dart';
 import 'resolution/operators.dart' as op;
 import 'scanner/scannerlib.dart';
+import 'serialization/task.dart';
 import 'ssa/ssa.dart';
 import 'io/source_file.dart' show SourceFile;
 import 'tracer.dart' show Tracer;
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 21fbc78..17e6472 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -9,30 +9,22 @@
 import 'core_types.dart';
 import 'dart2jslib.dart' show Compiler, invariant, Script, Message;
 import 'elements/modelx.dart'
-    show VoidElementX,
-         LibraryElementX,
-         BaseClassElementX,
+    show LibraryElementX,
          TypeDeclarationElementX,
          TypedefElementX;
 import 'elements/elements.dart';
 import 'ordered_typeset.dart' show OrderedTypeSet;
 import 'util/util.dart' show CURRENT_ELEMENT_SPANNABLE, equalElements;
 
-class TypeKind {
-  final String id;
-
-  const TypeKind(String this.id);
-
-  static const TypeKind FUNCTION = const TypeKind('function');
-  static const TypeKind INTERFACE = const TypeKind('interface');
-  static const TypeKind STATEMENT = const TypeKind('statement');
-  static const TypeKind TYPEDEF = const TypeKind('typedef');
-  static const TypeKind TYPE_VARIABLE = const TypeKind('type variable');
-  static const TypeKind MALFORMED_TYPE = const TypeKind('malformed');
-  static const TypeKind DYNAMIC = const TypeKind('dynamic');
-  static const TypeKind VOID = const TypeKind('void');
-
-  String toString() => id;
+enum TypeKind {
+  FUNCTION,
+  INTERFACE,
+  STATEMENT,
+  TYPEDEF,
+  TYPE_VARIABLE,
+  MALFORMED_TYPE,
+  DYNAMIC,
+  VOID,
 }
 
 abstract class DartType {
@@ -451,9 +443,9 @@
     assert(invariant(element, element.isDeclaration));
   }
 
-  InterfaceType.forUserProvidedBadType(BaseClassElementX element,
-                                       [List<DartType> typeArguments =
-                                           const <DartType>[]])
+  InterfaceType.forUserProvidedBadType(
+      ClassElement element,
+      [List<DartType> typeArguments = const <DartType>[]])
       : super(element, typeArguments, checkTypeArgumentCount: false);
 
   ClassElement get element => super.element;
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index 8c8c4ff..f9013c6 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -126,6 +126,28 @@
   @override
   bool get isInternalLibrary =>
       isPlatformLibrary && canonicalUri.path.startsWith('_');
+
+  String getLibraryOrScriptName() {
+    if (hasLibraryName()) {
+      return getLibraryName();
+    } else {
+      // Use the file name as script name.
+      String path = canonicalUri.path;
+      return path.substring(path.lastIndexOf('/') + 1);
+    }
+  }
+
+  int compareTo(LibraryElement other) {
+    if (this == other) return 0;
+    return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
+  }
+}
+
+abstract class CompilationUnitElementCommon implements CompilationUnitElement {
+  int compareTo(CompilationUnitElement other) {
+    if (this == other) return 0;
+    return '${script.readableUri}'.compareTo('${other.script.readableUri}');
+  }
 }
 
 abstract class ClassElementCommon implements ClassElement {
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 22a0933..2f302b2 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -836,10 +836,8 @@
   get enclosingElement;
 
   Script get script;
-  PartOf get partTag;
 
   void forEachLocalMember(f(Element element));
-  bool get hasMembers;
 
   int compareTo(CompilationUnitElement other);
 }
@@ -902,6 +900,15 @@
 
   bool hasLibraryName();
   String getLibraryName();
+
+  /**
+   * Returns the library name (as defined by the library tag) or for script
+   * (which have no library tag) the script file name. The latter case is used
+   * to provide a 'library name' for scripts to use for instance in dartdoc.
+   *
+   * Note: the returned filename is still escaped ("a%20b.dart" instead of
+   * "a b.dart").
+   */
   String getLibraryOrScriptName();
 
   int compareTo(LibraryElement other);
@@ -976,6 +983,9 @@
 
 /// A top level, static or instance field, a formal parameter or local variable.
 abstract class VariableElement extends ExecutableElement {
+  @override
+  VariableDefinitions get node;
+
   Expression get initializer;
 
   /// The constant expression defining the value of the variable if `const`,
@@ -1490,6 +1500,9 @@
   /// The class or typedef on which this type variable is defined.
   TypeDeclarationElement get typeDeclaration;
 
+  /// The index of this type variable within its type declaration.
+  int get index;
+
   /// The [type] defined by the type variable.
   TypeVariableType get type;
 
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index fc1f93b..1c5f782 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -652,6 +652,7 @@
 }
 
 class CompilationUnitElementX extends ElementX
+    with CompilationUnitElementCommon
     implements CompilationUnitElement {
   final Script script;
   PartOf partTag;
@@ -718,11 +719,6 @@
 
   bool get hasMembers => !localMembers.isEmpty;
 
-  int compareTo(CompilationUnitElement other) {
-    if (this == other) return 0;
-    return '${script.readableUri}'.compareTo('${other.script.readableUri}');
-  }
-
   Element get analyzableElement => library;
 
   accept(ElementVisitor visitor, arg) {
@@ -1070,24 +1066,6 @@
     return libraryTag.name.toString();
   }
 
-  /**
-   * Returns the library name (as defined by the library tag) or for script
-   * (which have no library tag) the script file name. The latter case is used
-   * to private 'library name' for scripts to use for instance in dartdoc.
-   *
-   * Note: the returned filename will still be escaped ("a%20b.dart" instead of
-   * "a b.dart").
-   */
-  String getLibraryOrScriptName() {
-    if (libraryTag != null) {
-      return libraryTag.name.toString();
-    } else {
-      // Use the file name as script name.
-      String path = canonicalUri.path;
-      return path.substring(path.lastIndexOf('/') + 1);
-    }
-  }
-
   Scope buildScope() => new LibraryScope(this);
 
   String toString() {
@@ -1100,11 +1078,6 @@
     }
   }
 
-  int compareTo(LibraryElement other) {
-    if (this == other) return 0;
-    return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
-  }
-
   accept(ElementVisitor visitor, arg) {
     return visitor.visitLibraryElement(this, arg);
   }
@@ -2194,7 +2167,7 @@
   }
 
   accept(ElementVisitor visitor, arg) {
-    return visitor.visitFunctionElement(this, arg);
+    return visitor.visitConstructorElement(this, arg);
   }
 }
 
@@ -2275,12 +2248,12 @@
     // Create types and elements for type variable.
     Link<Node> nodes = parameters.nodes;
     List<DartType> arguments =
-        new List.generate(nodes.slowLength(), (_) {
+        new List.generate(nodes.slowLength(), (int index) {
       TypeVariable node = nodes.head;
       String variableName = node.name.source;
       nodes = nodes.tail;
       TypeVariableElementX variableElement =
-          new TypeVariableElementX(variableName, this, node);
+          new TypeVariableElementX(variableName, this, index, node);
       TypeVariableType variableType = new TypeVariableType(variableElement);
       variableElement.typeCache = variableType;
       return variableType;
@@ -2760,11 +2733,15 @@
 
 class TypeVariableElementX extends ElementX with AstElementMixin
     implements TypeVariableElement {
+  final int index;
   final Node node;
   TypeVariableType typeCache;
   DartType boundCache;
 
-  TypeVariableElementX(String name, TypeDeclarationElement enclosing, this.node)
+  TypeVariableElementX(String name,
+                       TypeDeclarationElement enclosing,
+                       this.index,
+                       this.node)
     : super(name, ElementKind.TYPE_VARIABLE, enclosing);
 
   TypeDeclarationElement get typeDeclaration => enclosingElement;
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 39f08dc..9325653 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -259,7 +259,7 @@
         recentClasses.add(cls);
         cls.ensureResolved(compiler);
         cls.implementation.forEachMember(processInstantiatedClassMember);
-        if (isResolutionQueue) {
+        if (isResolutionQueue && !cls.isSynthesized) {
           compiler.resolver.checkClass(cls);
         }
         // We only tell the backend once that [cls] was instantiated, so
@@ -724,6 +724,7 @@
 
   bool internalAddToWorkList(Element element) {
     if (element.isErroneous) return false;
+
     assert(invariant(element, element is AnalyzableElement,
         message: 'Element $element is not analyzable.'));
     if (hasBeenResolved(element)) return false;
@@ -734,7 +735,15 @@
 
     compiler.world.registerUsedElement(element);
 
-    queue.add(new ResolutionWorkItem(element, itemCompilationContextCreator()));
+    ResolutionWorkItem workItem;
+    if (compiler.serialization.isDeserialized(element)) {
+      workItem = compiler.serialization.createResolutionWorkItem(
+          element, itemCompilationContextCreator());
+    } else {
+      workItem = new ResolutionWorkItem(
+          element, itemCompilationContextCreator());
+    }
+    queue.add(workItem);
 
     // Enable isolate support if we start using something from the isolate
     // library, or timers for the async library.  We exclude constant fields,
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 1b4075d..967de65 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -8,12 +8,26 @@
 
 import 'source_information.dart';
 
+/// Listener interface for [CodeOutput] activity.
 abstract class CodeOutputListener {
+  /// Called when [text] is added to the output.
   void onText(String text);
+
+  /// Called when the output is closed with a final length of [length].
   void onDone(int length);
 }
 
-abstract class CodeOutput {
+/// Interface for a mapping of target offsets to source locations.
+abstract class SourceLocations {
+  /// Adds a [sourceLocation] at the specified [targetOffset].
+  void addSourceLocation(int targetOffset, SourceLocation sourcePosition);
+
+  /// Applies [f] to every target offset and associated source location.
+  void forEachSourceLocation(void f(int targetOffset,
+                                    SourceLocation sourceLocation));
+}
+
+abstract class CodeOutput implements SourceLocations {
   /// Write [text] to this output.
   ///
   /// If the output is closed, a [StateError] is thrown.
@@ -33,13 +47,6 @@
 
   /// Closes the output. Further writes will cause a [StateError].
   void close();
-
-  /// Adds a [sourceLocation] at the specified [targetOffset] in the buffer.
-  void addSourceLocation(int targetOffset, SourceLocation sourcePosition);
-
-  /// Applies [f] to every marker in this output.
-  void forEachSourceLocation(void f(int targetOffset,
-                                    SourceLocation sourceLocation));
 }
 
 abstract class AbstractCodeOutput extends CodeOutput {
diff --git a/pkg/compiler/lib/src/io/line_column_provider.dart b/pkg/compiler/lib/src/io/line_column_provider.dart
index fb3d5db..e8665fb 100644
--- a/pkg/compiler/lib/src/io/line_column_provider.dart
+++ b/pkg/compiler/lib/src/io/line_column_provider.dart
@@ -13,6 +13,9 @@
 
   /// Returns the column number (0-based) for [offset] at the given [line].
   int getColumn(int line, int offset);
+
+  /// Returns the offset for 0-based [line] and [column] numbers.
+  int getOffset(int line, int column);
 }
 
 /// [CodeOutputListener] that collects line information.
@@ -65,6 +68,8 @@
     return offset - lineStarts[line];
   }
 
+  int getOffset(int line, int column) => lineStarts[line] + column;
+
   @override
   void onDone(int length) {
     lineStarts.add(length + 1);
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
new file mode 100644
index 0000000..9b91cab1
--- /dev/null
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -0,0 +1,439 @@
+// 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.
+
+/// Source information system mapping that attempts a semantic mapping between
+/// offsets of JavaScript code points to offsets of Dart code points.
+
+library dart2js.source_information.position;
+
+import '../dart2jslib.dart' show
+    invariant,
+    MessageKind,
+    SourceSpan;
+import '../elements/elements.dart' show
+    AstElement,
+    LocalElement;
+import '../js/js.dart' as js;
+import '../js/js_source_mapping.dart';
+import '../js/js_debug.dart';
+import '../tree/tree.dart' show Node, Send;
+import '../util/util.dart' show NO_LOCATION_SPANNABLE;
+
+import 'source_file.dart';
+import 'source_information.dart';
+
+/// [SourceInformation] that consists of an offset position into the source
+/// code.
+class PositionSourceInformation extends SourceInformation {
+  @override
+  final SourceLocation startPosition;
+
+  @override
+  final SourceLocation closingPosition;
+
+  PositionSourceInformation(this.startPosition,
+                            [this.closingPosition]);
+
+  @override
+  List<SourceLocation> get sourceLocations {
+    List<SourceLocation> list = <SourceLocation>[];
+    if (startPosition != null) {
+      list.add(startPosition);
+    }
+    if (closingPosition != null) {
+      list.add(closingPosition);
+    }
+    return list;
+  }
+
+  @override
+  SourceSpan get sourceSpan {
+    SourceLocation location =
+        startPosition != null ? startPosition : closingPosition;
+    Uri uri = location.sourceUri;
+    int offset = location.offset;
+    return new SourceSpan(uri, offset, offset);
+  }
+
+  int get hashCode {
+    return 0x7FFFFFFF &
+           (startPosition.hashCode * 17 + closingPosition.hashCode * 19);
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! PositionSourceInformation) return false;
+    return startPosition == other.startPosition &&
+           closingPosition == other.closingPosition;
+  }
+
+  /// Create a textual representation of the source information using [uriText]
+  /// as the Uri representation.
+  String _computeText(String uriText) {
+    StringBuffer sb = new StringBuffer();
+    sb.write('$uriText:');
+    // Use 1-based line/column info to match usual dart tool output.
+    if (startPosition != null) {
+      sb.write('[${startPosition.line + 1},'
+                '${startPosition.column + 1}]');
+    }
+    if (closingPosition != null) {
+      sb.write('-[${closingPosition.line + 1},'
+                 '${closingPosition.column + 1}]');
+    }
+    return sb.toString();
+  }
+
+  String get shortText {
+    if (startPosition != null) {
+      return _computeText(startPosition.sourceUri.pathSegments.last);
+    } else {
+      return _computeText(closingPosition.sourceUri.pathSegments.last);
+    }
+  }
+
+  String toString() {
+    if (startPosition != null) {
+      return _computeText('${startPosition.sourceUri}');
+    } else {
+      return _computeText('${closingPosition.sourceUri}');
+    }
+  }
+}
+
+class PositionSourceInformationStrategy
+    implements JavaScriptSourceInformationStrategy {
+  const PositionSourceInformationStrategy();
+
+  @override
+  SourceInformationBuilder createBuilderForContext(AstElement element) {
+    return new PositionSourceInformationBuilder(element);
+  }
+
+  @override
+  SourceInformationProcessor createProcessor(SourceMapper mapper) {
+    return new PositionSourceInformationProcessor(mapper);
+  }
+}
+
+/// [SourceInformationBuilder] that generates [PositionSourceInformation].
+class PositionSourceInformationBuilder implements SourceInformationBuilder {
+  final SourceFile sourceFile;
+  final String name;
+
+  PositionSourceInformationBuilder(AstElement element)
+      : sourceFile = element.implementation.compilationUnit.script.file,
+        name = computeElementNameForSourceMaps(element);
+
+  SourceInformation buildDeclaration(AstElement element) {
+    if (element.isSynthesized) {
+      return new PositionSourceInformation(
+          new OffsetSourceLocation(
+              sourceFile, element.position.charOffset, name));
+    } else {
+      return new PositionSourceInformation(
+          null,
+          new OffsetSourceLocation(sourceFile,
+              element.resolvedAst.node.getEndToken().charOffset, name));
+    }
+  }
+
+  /// Builds a source information object pointing the start position of [node].
+  SourceInformation buildBegin(Node node) {
+    return new PositionSourceInformation(new OffsetSourceLocation(
+        sourceFile, node.getBeginToken().charOffset, name));
+  }
+
+  @override
+  SourceInformation buildGeneric(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildReturn(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildImplicitReturn(AstElement element) {
+    if (element.isSynthesized) {
+      return new PositionSourceInformation(
+          new OffsetSourceLocation(
+              sourceFile, element.position.charOffset, name));
+    } else {
+      return new PositionSourceInformation(
+          new OffsetSourceLocation(sourceFile,
+              element.resolvedAst.node.getEndToken().charOffset, name));
+    }
+ }
+
+
+  @override
+  SourceInformation buildLoop(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildGet(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildCall(Node receiver, Node call) {
+    return new PositionSourceInformation(
+        new OffsetSourceLocation(
+            sourceFile, receiver.getBeginToken().charOffset, name),
+        new OffsetSourceLocation(
+            sourceFile, call.getBeginToken().charOffset, name));
+  }
+
+  @override
+  SourceInformation buildNew(Node node) {
+    return buildBegin(node);
+  }
+
+  @override
+  SourceInformation buildIf(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildThrow(Node node) => buildBegin(node);
+
+  @override
+  SourceInformation buildAssignment(Node node) => buildBegin(node);
+
+  @override
+  SourceInformationBuilder forContext(AstElement element) {
+    return new PositionSourceInformationBuilder(element);
+  }
+}
+
+/// The start, end and closing offsets for a [js.Node].
+class CodePosition {
+  final int startPosition;
+  final int endPosition;
+  final int closingPosition;
+
+  CodePosition(this.startPosition, this.endPosition, this.closingPosition);
+}
+
+/// Registry for mapping [js.Node]s to their [CodePosition].
+class CodePositionRecorder {
+  Map<js.Node, CodePosition> _codePositionMap = <js.Node, CodePosition>{};
+
+  void registerPositions(js.Node node,
+                         int startPosition,
+                         int endPosition,
+                         int closingPosition) {
+    registerCodePosition(node,
+        new CodePosition(startPosition, endPosition, closingPosition));
+  }
+
+  void registerCodePosition(js.Node node, CodePosition codePosition) {
+    _codePositionMap[node] = codePosition;
+  }
+
+  CodePosition operator [](js.Node node) => _codePositionMap[node];
+}
+
+enum SourcePositionKind {
+  START,
+  CLOSING,
+  END,
+}
+
+enum CodePositionKind {
+  START,
+  CLOSING,
+  END,
+}
+
+/// Processor that associates [SourceLocation]s from [SourceInformation] on
+/// [js.Node]s with the target offsets in a [SourceMapper].
+class PositionSourceInformationProcessor
+    extends js.BaseVisitor implements SourceInformationProcessor {
+  final CodePositionRecorder codePositions = new CodePositionRecorder();
+  final SourceMapper sourceMapper;
+
+  PositionSourceInformationProcessor(this.sourceMapper);
+
+  void process(js.Node node) {
+    node.accept(this);
+  }
+
+  void visitChildren(js.Node node) {
+    node.visitChildren(this);
+  }
+
+  CodePosition getCodePosition(js.Node node) {
+    return codePositions[node];
+  }
+
+  /// Associates [sourceInformation] with the JavaScript [node].
+  ///
+  /// The offset into the JavaScript code is computed by pulling the
+  /// [codePositionKind] from the code positions associated with
+  /// [codePositionNode].
+  ///
+  /// The mapped Dart source location is computed by pulling the
+  /// [sourcePositionKind] source location from [sourceInformation].
+  void apply(js.Node node,
+             js.Node codePositionNode,
+             CodePositionKind codePositionKind,
+             SourceInformation sourceInformation,
+             SourcePositionKind sourcePositionKind) {
+    if (sourceInformation != null) {
+      CodePosition codePosition = getCodePosition(codePositionNode);
+      // We should always have recorded the needed code positions.
+      assert(invariant(
+          NO_LOCATION_SPANNABLE,
+          codePosition != null,
+          message:
+            "Code position missing for "
+            "${nodeToString(codePositionNode)}:\n"
+            "${DebugPrinter.prettyPrint(node)}"));
+      if (codePosition == null) return;
+      int codeLocation;
+      SourceLocation sourceLocation;
+      switch (codePositionKind) {
+        case CodePositionKind.START:
+          codeLocation = codePosition.startPosition;
+          break;
+        case CodePositionKind.CLOSING:
+          codeLocation = codePosition.closingPosition;
+          break;
+        case CodePositionKind.END:
+          codeLocation = codePosition.endPosition;
+          break;
+      }
+      switch (sourcePositionKind) {
+        case SourcePositionKind.START:
+          sourceLocation = sourceInformation.startPosition;
+          break;
+        case SourcePositionKind.CLOSING:
+          sourceLocation = sourceInformation.closingPosition;
+          break;
+        case SourcePositionKind.END:
+          sourceLocation = sourceInformation.endPosition;
+          break;
+      }
+      if (codeLocation != null && sourceLocation != null) {
+        sourceMapper.register(node, codeLocation, sourceLocation);
+      }
+    }
+  }
+
+  @override
+  visitNode(js.Node node) {
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      /// Associates the left-most position of the JS code with the left-most
+      /// position of the Dart code.
+      apply(node,
+          node, CodePositionKind.START,
+          sourceInformation, SourcePositionKind.START);
+    }
+    visitChildren(node);
+  }
+
+  @override
+  visitFun(js.Fun node) {
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      /// Associates the end brace of the JavaScript function with the end brace
+      /// of the Dart function (or the `;` in case of arrow notation).
+      apply(node,
+          node, CodePositionKind.CLOSING,
+          sourceInformation, SourcePositionKind.CLOSING);
+    }
+
+    visitChildren(node);
+  }
+
+  @override
+  visitExpressionStatement(js.ExpressionStatement node) {
+    visitChildren(node);
+  }
+
+  @override
+  visitBinary(js.Binary node) {
+    visitChildren(node);
+  }
+
+  @override
+  visitAccess(js.PropertyAccess node) {
+    visitChildren(node);
+  }
+
+  @override
+  visitCall(js.Call node) {
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      if (node.target is js.PropertyAccess) {
+        js.PropertyAccess access = node.target;
+        js.Node target = access;
+        bool pureAccess = false;
+        while (target is js.PropertyAccess) {
+          js.PropertyAccess targetAccess = target;
+          if (targetAccess.receiver is js.VariableUse ||
+              targetAccess.receiver is js.This) {
+            pureAccess = true;
+            break;
+          } else {
+            target = targetAccess.receiver;
+          }
+        }
+        if (pureAccess) {
+          // a.m()   this.m()  a.b.c.d.m()
+          // ^       ^         ^
+          apply(
+              node,
+              node,
+              CodePositionKind.START,
+              sourceInformation,
+              SourcePositionKind.START);
+        } else {
+          // *.m()  *.a.b.c.d.m()
+          //   ^              ^
+          apply(
+              node,
+              access.selector,
+              CodePositionKind.START,
+              sourceInformation,
+              SourcePositionKind.CLOSING);
+        }
+      } else if (node.target is js.VariableUse) {
+        // m()
+        // ^
+        apply(
+            node,
+            node,
+            CodePositionKind.START,
+            sourceInformation,
+            SourcePositionKind.START);
+      } else if (node.target is js.Fun || node.target is js.New) {
+        // function(){}()  new Function("...")()
+        //             ^                      ^
+        apply(
+            node,
+            node.target,
+            CodePositionKind.END,
+            sourceInformation,
+            SourcePositionKind.CLOSING);
+      } else {
+        assert(invariant(NO_LOCATION_SPANNABLE, false,
+            message: "Unexpected property access ${nodeToString(node)}:\n"
+                     "${DebugPrinter.prettyPrint(node)}"));
+        // Don't know....
+        apply(
+            node,
+            node,
+            CodePositionKind.START,
+            sourceInformation,
+            SourcePositionKind.START);
+      }
+    }
+    visitChildren(node);
+  }
+
+  @override
+  void onPositions(js.Node node,
+                   int startPosition,
+                   int endPosition,
+                   int closingPosition) {
+    codePositions.registerPositions(
+        node, startPosition, endPosition, closingPosition);
+  }
+}
diff --git a/pkg/compiler/lib/src/io/source_file.dart b/pkg/compiler/lib/src/io/source_file.dart
index 8fd28ff..d799a9b 100644
--- a/pkg/compiler/lib/src/io/source_file.dart
+++ b/pkg/compiler/lib/src/io/source_file.dart
@@ -115,6 +115,9 @@
     return position - lineStarts[line];
   }
 
+  /// Returns the offset for 0-based [line] and [column] numbers.
+  int getOffset(int line, int column) => lineStarts[line] + column;
+
   String slowSubstring(int start, int end);
 
   /**
@@ -145,13 +148,7 @@
     buf.write('\n$message\n');
 
     if (start != end && includeSourceLine) {
-      String textLine;
-      // +1 for 0-indexing, +1 again to avoid the last line of the file
-      if ((line + 2) < lineStarts.length) {
-        textLine = slowSubstring(lineStarts[line], lineStarts[line+1]);
-      } else {
-        textLine = '${slowSubstring(lineStarts[line], length)}\n';
-      }
+      String textLine = getLineText(line);
 
       int toColumn = min(column + (end-start), textLine.length);
       buf.write(textLine.substring(0, column));
@@ -170,6 +167,20 @@
 
     return buf.toString();
   }
+
+  int get lines => lineStarts.length - 1;
+
+  /// Returns the text of line  at the 0-based [index] within this source file.
+  String getLineText(int index) {
+    // +1 for 0-indexing, +1 again to avoid the last line of the file
+    if ((index + 2) < lineStarts.length) {
+      return slowSubstring(lineStarts[index], lineStarts[index+1]);
+    } else if ((index + 1) < lineStarts.length) {
+      return '${slowSubstring(lineStarts[index], length)}\n';
+    } else {
+      throw new ArgumentError("Line index $index is out of bounds.");
+    }
+  }
 }
 
 List<int> _zeroTerminateIfNecessary(List<int> bytes) {
@@ -212,7 +223,7 @@
   int get length {
     if (lengthCache == -1) {
       // During scanning the length is not yet assigned, so we use a slow path.
-      length = slowText().length;
+      lengthCache = slowText().length;
     }
     return lengthCache;
   }
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index e7b23ea..3c4ea20 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -8,11 +8,14 @@
 import '../elements/elements.dart' show
     AstElement,
     LocalElement;
-import '../scanner/scannerlib.dart' show Token;
-import '../tree/tree.dart' show Node;
-import '../js/js.dart' show JavaScriptNodeSourceInformation;
+import '../tree/tree.dart' show Node, Send;
+import '../js/js.dart' show
+    JavaScriptNodeSourceInformation;
 import 'source_file.dart';
 
+bool useNewSourceInfo =
+    const bool.fromEnvironment('USE_NEW_SOURCE_INFO', defaultValue: false);
+
 /// Interface for passing source information, for instance for use in source
 /// maps, through the backend.
 abstract class SourceInformation extends JavaScriptNodeSourceInformation {
@@ -26,14 +29,20 @@
 
   /// The source location associated with the end of the JS node.
   SourceLocation get endPosition => null;
+
+  /// All source locations associated with this source information.
+  List<SourceLocation> get sourceLocations;
+
+  /// Return a short textual representation of the source location.
+  String get shortText;
 }
 
-/// Factory for creating [SourceInformationBuilder]s.
-class SourceInformationFactory {
-  const SourceInformationFactory();
+/// Strategy for creating, processing and applying [SourceInformation].
+class SourceInformationStrategy {
+  const SourceInformationStrategy();
 
   /// Create a [SourceInformationBuilder] for [element].
-  SourceInformationBuilder forContext(AstElement element) {
+  SourceInformationBuilder createBuilderForContext(AstElement element) {
     return const SourceInformationBuilder();
   }
 }
@@ -43,9 +52,7 @@
   const SourceInformationBuilder();
 
   /// Create a [SourceInformationBuilder] for [element].
-  SourceInformationBuilder forContext(AstElement element) {
-    return this;
-  }
+  SourceInformationBuilder forContext(AstElement element) => this;
 
   /// Generate [SourceInformation] the declaration of [element].
   SourceInformation buildDeclaration(AstElement element) => null;
@@ -57,210 +64,32 @@
   /// Generate [SourceInformation] for the return [node].
   SourceInformation buildReturn(Node node) => null;
 
+  /// Generate [SourceInformation] for an implicit return in [element].
+  SourceInformation buildImplicitReturn(AstElement element) => null;
+
   /// Generate [SourceInformation] for the loop [node].
   SourceInformation buildLoop(Node node) => null;
 
   /// Generate [SourceInformation] for the read access in [node].
   SourceInformation buildGet(Node node) => null;
 
-  /// Generate [SourceInformation] for the invocation in [node].
-  SourceInformation buildCall(Node node) => null;
-}
+  /// Generate [SourceInformation] for an invocation like `a.b()` where
+  /// [receiver] points to the left-most part of the invocation, `a` in the
+  /// example, and [call] points the 'name' of the call, `b` or `()` depending
+  /// on whether `b` is a method or a field/getter.
+  SourceInformation buildCall(Node receiver, Node call) => null;
 
-/// Source information that contains start source position and optionally an
-/// end source position.
-class StartEndSourceInformation extends SourceInformation {
-  @override
-  final SourceLocation startPosition;
+  /// Generate [SourceInformation] for the if statement in [node].
+  SourceInformation buildIf(Node node) => null;
 
-  @override
-  final SourceLocation endPosition;
+  /// Generate [SourceInformation] for the constructor invocation in [node].
+  SourceInformation buildNew(Node node) => null;
 
-  StartEndSourceInformation(this.startPosition, [this.endPosition]);
+  /// Generate [SourceInformation] for the throw in [node].
+  SourceInformation buildThrow(Node node) => null;
 
-  @override
-  SourceSpan get sourceSpan {
-    Uri uri = startPosition.sourceUri;
-    int begin = startPosition.offset;
-    int end = endPosition == null ? begin : endPosition.offset;
-    return new SourceSpan(uri, begin, end);
-  }
-
-  int get hashCode {
-    return 0x7FFFFFFF &
-           (startPosition.hashCode * 17 + endPosition.hashCode * 19);
-  }
-
-  bool operator ==(other) {
-    if (identical(this, other)) return true;
-    if (other is! StartEndSourceInformation) return false;
-    return startPosition == other.startPosition &&
-           endPosition == other.endPosition;
-  }
-
-  // TODO(johnniwinther): Remove this method. Source information should be
-  // computed based on the element by provided from statements and expressions.
-  static StartEndSourceInformation computeSourceInformation(
-      AstElement element) {
-
-    AstElement implementation = element.implementation;
-    SourceFile sourceFile = implementation.compilationUnit.script.file;
-    String name = computeElementNameForSourceMaps(element);
-    Node node = implementation.node;
-    Token beginToken;
-    Token endToken;
-    if (node == null) {
-      // Synthesized node. Use the enclosing element for the location.
-      beginToken = endToken = element.position;
-    } else {
-      beginToken = node.getBeginToken();
-      endToken = node.getEndToken();
-    }
-    // TODO(podivilov): find the right sourceFile here and remove offset
-    // checks below.
-    SourceLocation sourcePosition, endSourcePosition;
-    if (beginToken.charOffset < sourceFile.length) {
-      sourcePosition =
-          new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
-    }
-    if (endToken.charOffset < sourceFile.length) {
-      endSourcePosition =
-          new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
-    }
-    return new StartEndSourceInformation(sourcePosition, endSourcePosition);
-  }
-
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    sb.write('${startPosition.sourceUri}:');
-    // Use 1-based line/column info to match usual dart tool output.
-    sb.write('[${startPosition.line + 1},${startPosition.column + 1}]');
-    if (endPosition != null) {
-      sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]');
-    }
-    return sb.toString();
-  }
-}
-
-class StartEndSourceInformationFactory implements SourceInformationFactory {
-  const StartEndSourceInformationFactory();
-
-  @override
-  SourceInformationBuilder forContext(AstElement element) {
-    return new StartEndSourceInformationBuilder(element);
-  }
-}
-
-/// [SourceInformationBuilder] that generates [PositionSourceInformation].
-class StartEndSourceInformationBuilder extends SourceInformationBuilder {
-  final SourceFile sourceFile;
-  final String name;
-
-  StartEndSourceInformationBuilder(AstElement element)
-      : sourceFile = element.compilationUnit.script.file,
-        name = computeElementNameForSourceMaps(element);
-
-  SourceInformation buildDeclaration(AstElement element) {
-    return StartEndSourceInformation.computeSourceInformation(element);
-  }
-
-  SourceLocation sourceFileLocationForToken(Token token) {
-    SourceLocation location =
-        new OffsetSourceLocation(sourceFile, token.charOffset, name);
-    checkValidSourceFileLocation(location, sourceFile, token.charOffset);
-    return location;
-  }
-
-  void checkValidSourceFileLocation(
-      SourceLocation location, SourceFile sourceFile, int offset) {
-    if (!location.isValid) {
-      throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message(
-          {'offset': offset,
-           'fileName': sourceFile.filename,
-           'length': sourceFile.length});
-    }
-  }
-
-  @override
-  SourceInformation buildLoop(Node node) {
-    return new StartEndSourceInformation(
-        sourceFileLocationForToken(node.getBeginToken()),
-        sourceFileLocationForToken(node.getEndToken()));
-  }
-
-  @override
-  SourceInformation buildGeneric(Node node) {
-    return new StartEndSourceInformation(
-        sourceFileLocationForToken(node.getBeginToken()));
-  }
-
-  @override
-  SourceInformation buildReturn(Node node) => buildGeneric(node);
-
-  @override
-  SourceInformation buildGet(Node node) => buildGeneric(node);
-
-  @override
-  SourceInformation buildCall(Node node) => buildGeneric(node);
-
-  @override
-  SourceInformationBuilder forContext(
-      AstElement element, {SourceInformation sourceInformation}) {
-    return new StartEndSourceInformationBuilder(element);
-  }
-}
-
-/// [SourceInformation] that consists of an offset position into the source
-/// code.
-class PositionSourceInformation extends SourceInformation {
-  @override
-  final SourceLocation startPosition;
-
-  @override
-  final SourceLocation closingPosition;
-
-  PositionSourceInformation(this.startPosition,
-                            [this.closingPosition]);
-
-  @override
-  SourceSpan get sourceSpan {
-    SourceLocation location =
-        startPosition != null ? startPosition : closingPosition;
-    Uri uri = location.sourceUri;
-    int offset = location.offset;
-    return new SourceSpan(uri, offset, offset);
-  }
-
-  int get hashCode {
-    return 0x7FFFFFFF &
-           (startPosition.hashCode * 17 + closingPosition.hashCode * 19);
-  }
-
-  bool operator ==(other) {
-    if (identical(this, other)) return true;
-    if (other is! PositionSourceInformation) return false;
-    return startPosition == other.startPosition &&
-           closingPosition == other.closingPosition;
-  }
-
-  String toString() {
-    StringBuffer sb = new StringBuffer();
-    if (startPosition != null) {
-      sb.write('${startPosition.sourceUri}:');
-    } else {
-      sb.write('${closingPosition.sourceUri}:');
-    }
-    // Use 1-based line/column info to match usual dart tool output.
-    if (startPosition != null) {
-      sb.write('[${startPosition.line + 1},'
-                '${startPosition.column + 1}]');
-    }
-    if (closingPosition != null) {
-      sb.write('-[${closingPosition.line + 1},'
-                 '${closingPosition.column + 1}]');
-    }
-    return sb.toString();
-  }
+  /// Generate [SourceInformation] for the assignment in [node].
+  SourceInformation buildAssignment(Node node) => null;
 }
 
 /// A location in a source file.
@@ -307,6 +136,11 @@
            sourceName == other.sourceName;
   }
 
+  String get shortText {
+    // Use 1-based line/column info to match usual dart tool output.
+    return '${sourceUri.pathSegments.last}:[${line + 1},${column + 1}]';
+  }
+
   String toString() {
     // Use 1-based line/column info to match usual dart tool output.
     return '${sourceUri}:[${line + 1},${column + 1}]';
@@ -320,68 +154,15 @@
   OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName)
       : super(sourceFile);
 
+  String get shortText {
+    return '${super.shortText}:$sourceName';
+  }
+
   String toString() {
     return '${super.toString()}:$sourceName';
   }
 }
 
-class PositionSourceInformationFactory implements SourceInformationFactory {
-  const PositionSourceInformationFactory();
-
-  @override
-  SourceInformationBuilder forContext(AstElement element) {
-    return new PositionSourceInformationBuilder(element);
-  }
-}
-
-/// [SourceInformationBuilder] that generates [PositionSourceInformation].
-class PositionSourceInformationBuilder implements SourceInformationBuilder {
-  final SourceFile sourceFile;
-  final String name;
-
-  PositionSourceInformationBuilder(AstElement element)
-      : sourceFile = element.implementation.compilationUnit.script.file,
-        name = computeElementNameForSourceMaps(element);
-
-  SourceInformation buildDeclaration(AstElement element) {
-    if (element.isSynthesized) {
-      return new PositionSourceInformation(
-          new OffsetSourceLocation(
-              sourceFile, element.position.charOffset, name));
-    } else {
-      return new PositionSourceInformation(
-          null,
-          new OffsetSourceLocation(sourceFile,
-              element.resolvedAst.node.getEndToken().charOffset, name));
-    }
-  }
-
-  SourceInformation buildBegin(Node node) {
-    return new PositionSourceInformation(new OffsetSourceLocation(
-        sourceFile, node.getBeginToken().charOffset, name));
-  }
-
-  @override
-  SourceInformation buildGeneric(Node node) => buildBegin(node);
-
-  @override
-  SourceInformation buildReturn(Node node) => buildBegin(node);
-
-  @override
-  SourceInformation buildLoop(Node node) => buildBegin(node);
-
-  @override
-  SourceInformation buildGet(Node node) => buildBegin(node);
-
-  @override
-  SourceInformation buildCall(Node node) => buildBegin(node);
-
-  @override
-  SourceInformationBuilder forContext(AstElement element) {
-    return new PositionSourceInformationBuilder(element);
-  }
-}
-
 /// Compute the source map name for [element].
 String computeElementNameForSourceMaps(AstElement element) {
   if (element.isClosure) {
@@ -409,4 +190,4 @@
   } else {
     return element.name;
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
new file mode 100644
index 0000000..b76a217
--- /dev/null
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -0,0 +1,232 @@
+// 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.
+
+/// Source information system that maps spans of Dart AST nodes to spans of
+/// JavaScript nodes.
+
+library dart2js.source_information.start_end;
+
+import '../dart2jslib.dart' show
+    MessageKind,
+    SourceSpan;
+import '../elements/elements.dart' show
+    AstElement,
+    LocalElement;
+import '../js/js.dart' as js;
+import '../js/js_source_mapping.dart';
+import '../scanner/scannerlib.dart' show Token;
+import '../tree/tree.dart' show Node, Send;
+
+import 'source_file.dart';
+import 'source_information.dart';
+
+/// Source information that contains start source position and optionally an
+/// end source position.
+class StartEndSourceInformation extends SourceInformation {
+  @override
+  final SourceLocation startPosition;
+
+  @override
+  final SourceLocation endPosition;
+
+  StartEndSourceInformation(this.startPosition, [this.endPosition]);
+
+  @override
+  List<SourceLocation> get sourceLocations {
+    if (endPosition == null) {
+      return <SourceLocation>[startPosition];
+    } else {
+      return <SourceLocation>[startPosition, endPosition];
+    }
+  }
+
+  @override
+  SourceSpan get sourceSpan {
+    Uri uri = startPosition.sourceUri;
+    int begin = startPosition.offset;
+    int end = endPosition == null ? begin : endPosition.offset;
+    return new SourceSpan(uri, begin, end);
+  }
+
+  int get hashCode {
+    return 0x7FFFFFFF &
+           (startPosition.hashCode * 17 + endPosition.hashCode * 19);
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! StartEndSourceInformation) return false;
+    return startPosition == other.startPosition &&
+           endPosition == other.endPosition;
+  }
+
+  // TODO(johnniwinther): Inline this in
+  // [StartEndSourceInformationBuilder.buildDeclaration].
+  static StartEndSourceInformation _computeSourceInformation(
+      AstElement element) {
+
+    AstElement implementation = element.implementation;
+    SourceFile sourceFile = implementation.compilationUnit.script.file;
+    String name = computeElementNameForSourceMaps(element);
+    Node node = implementation.node;
+    Token beginToken;
+    Token endToken;
+    if (node == null) {
+      // Synthesized node. Use the enclosing element for the location.
+      beginToken = endToken = element.position;
+    } else {
+      beginToken = node.getBeginToken();
+      endToken = node.getEndToken();
+    }
+    // TODO(johnniwinther): find the right sourceFile here and remove offset
+    // checks below.
+    SourceLocation sourcePosition, endSourcePosition;
+    if (beginToken.charOffset < sourceFile.length) {
+      sourcePosition =
+          new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
+    }
+    if (endToken.charOffset < sourceFile.length) {
+      endSourcePosition =
+          new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
+    }
+    return new StartEndSourceInformation(sourcePosition, endSourcePosition);
+  }
+
+  /// Create a textual representation of the source information using [uriText]
+  /// as the Uri representation.
+  String _computeText(String uriText) {
+    StringBuffer sb = new StringBuffer();
+    sb.write('$uriText:');
+    // Use 1-based line/startPosition info to match usual dart tool output.
+    sb.write('[${startPosition.line + 1},${startPosition.column + 1}]');
+    if (endPosition != null) {
+      sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]');
+    }
+    return sb.toString();
+  }
+
+  String get shortText {
+    return _computeText(startPosition.sourceUri.pathSegments.last);
+  }
+
+  String toString() {
+    return _computeText('${startPosition.sourceUri}');
+  }
+}
+
+class StartEndSourceInformationStrategy
+    implements JavaScriptSourceInformationStrategy {
+  const StartEndSourceInformationStrategy();
+
+  @override
+  SourceInformationBuilder createBuilderForContext(AstElement element) {
+    return new StartEndSourceInformationBuilder(element);
+  }
+
+  @override
+  SourceInformationProcessor createProcessor(SourceMapper sourceMapper) {
+    return new StartEndSourceInformationProcessor(sourceMapper);
+  }
+}
+
+class StartEndSourceInformationProcessor extends SourceInformationProcessor {
+  final SourceMapper sourceMapper;
+
+  /// Used to track whether a terminating source location marker has been
+  /// registered for the top-most node with source information.
+  bool hasRegisteredRoot = false;
+
+  StartEndSourceInformationProcessor(this.sourceMapper);
+
+  @override
+  void onPositions(js.Node node,
+                   int startPosition,
+                   int endPosition,
+                   int closingPosition) {
+    if (node.sourceInformation != null) {
+      StartEndSourceInformation sourceInformation = node.sourceInformation;
+      sourceMapper.register(
+          node, startPosition, sourceInformation.startPosition);
+      if (sourceInformation.endPosition != null) {
+        sourceMapper.register(node, endPosition, sourceInformation.endPosition);
+      }
+      if (!hasRegisteredRoot) {
+        sourceMapper.register(node, endPosition, null);
+        hasRegisteredRoot = true;
+      }
+    }
+  }
+}
+
+/// [SourceInformationBuilder] that generates [PositionSourceInformation].
+class StartEndSourceInformationBuilder extends SourceInformationBuilder {
+  final SourceFile sourceFile;
+  final String name;
+
+  StartEndSourceInformationBuilder(AstElement element)
+      : sourceFile = element.compilationUnit.script.file,
+        name = computeElementNameForSourceMaps(element);
+
+  SourceInformation buildDeclaration(AstElement element) {
+    return StartEndSourceInformation._computeSourceInformation(element);
+  }
+
+  SourceLocation sourceFileLocationForToken(Token token) {
+    SourceLocation location =
+        new OffsetSourceLocation(sourceFile, token.charOffset, name);
+    checkValidSourceFileLocation(location, sourceFile, token.charOffset);
+    return location;
+  }
+
+  void checkValidSourceFileLocation(
+      SourceLocation location, SourceFile sourceFile, int offset) {
+    if (!location.isValid) {
+      throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message(
+          {'offset': offset,
+           'fileName': sourceFile.filename,
+           'length': sourceFile.length});
+    }
+  }
+
+  @override
+  SourceInformation buildLoop(Node node) {
+    return new StartEndSourceInformation(
+        sourceFileLocationForToken(node.getBeginToken()),
+        sourceFileLocationForToken(node.getEndToken()));
+  }
+
+  @override
+  SourceInformation buildGeneric(Node node) {
+    return new StartEndSourceInformation(
+        sourceFileLocationForToken(node.getBeginToken()));
+  }
+
+  @override
+  SourceInformation buildReturn(Node node) {
+    return buildGeneric(node);
+  }
+
+  @override
+  SourceInformation buildGet(Node node) => buildGeneric(node);
+
+  @override
+  SourceInformation buildAssignment(Node node) => buildGeneric(node);
+
+  @override
+  SourceInformation buildCall(Node receiver, Node call) {
+    return buildGeneric(receiver);
+  }
+
+  @override
+  SourceInformation buildIf(Node node) => buildGeneric(node);
+
+  @override
+  SourceInformationBuilder forContext(
+      AstElement element, {SourceInformation sourceInformation}) {
+    return new StartEndSourceInformationBuilder(element);
+  }
+}
+
+
+
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 2d208a6..f609781 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -7,35 +7,50 @@
 import 'package:js_ast/js_ast.dart';
 export 'package:js_ast/js_ast.dart';
 
-import '../io/code_output.dart' show CodeBuffer;
-import '../io/source_information.dart' show SourceInformation;
-import '../js_emitter/js_emitter.dart' show USE_NEW_EMITTER;
+import '../io/code_output.dart' show CodeOutput, CodeBuffer;
+import '../js_emitter/js_emitter.dart' show USE_LAZY_EMITTER;
 import '../dart2jslib.dart' as leg;
-import '../util/util.dart' show NO_LOCATION_SPANNABLE;
+import '../util/util.dart' show NO_LOCATION_SPANNABLE, Indentation, Tagging;
 import '../dump_info.dart' show DumpInfoTask;
+import 'js_source_mapping.dart';
 
-CodeBuffer prettyPrint(Node node, leg.Compiler compiler,
+CodeBuffer prettyPrint(Node node,
+                       leg.Compiler compiler,
                        {DumpInfoTask monitor,
-                        bool allowVariableMinification: true}) {
+                        bool allowVariableMinification: true,
+                        Renamer renamerForNames:
+                            JavaScriptPrintingOptions.identityRenamer}) {
+  JavaScriptSourceInformationStrategy sourceInformationFactory =
+      compiler.backend.sourceInformationStrategy;
   JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
       shouldCompressOutput: compiler.enableMinification,
       minifyLocalVariables: allowVariableMinification,
-      preferSemicolonToNewlineInMinifiedOutput: USE_NEW_EMITTER);
+      preferSemicolonToNewlineInMinifiedOutput: USE_LAZY_EMITTER,
+      renamerForNames: renamerForNames);
+  CodeBuffer outBuffer = new CodeBuffer();
+  SourceInformationProcessor sourceInformationProcessor =
+      sourceInformationFactory.createProcessor(
+          new SourceLocationsMapper(outBuffer));
   Dart2JSJavaScriptPrintingContext context =
-      new Dart2JSJavaScriptPrintingContext(compiler, monitor);
+      new Dart2JSJavaScriptPrintingContext(
+          compiler, monitor, outBuffer, sourceInformationProcessor);
   Printer printer = new Printer(options, context);
   printer.visit(node);
-  return context.outBuffer;
+  sourceInformationProcessor.process(node);
+  return outBuffer;
 }
 
 class Dart2JSJavaScriptPrintingContext implements JavaScriptPrintingContext {
   final leg.Compiler compiler;
   final DumpInfoTask monitor;
-  final CodeBuffer outBuffer = new CodeBuffer();
-  Node rootNode;
+  final CodeBuffer outBuffer;
+  final CodePositionListener codePositionListener;
 
-  Dart2JSJavaScriptPrintingContext(leg.Compiler this.compiler,
-      DumpInfoTask this.monitor);
+  Dart2JSJavaScriptPrintingContext(
+      this.compiler,
+      this.monitor,
+      this.outBuffer,
+      this.codePositionListener);
 
   @override
   void error(String message) {
@@ -48,40 +63,97 @@
   }
 
   @override
-  void enterNode(Node node, int startPosition) {
-    SourceInformation sourceInformation = node.sourceInformation;
-    if (sourceInformation != null) {
-      if (rootNode == null) {
-        rootNode = node;
-      }
-      if (sourceInformation.startPosition != null) {
-        outBuffer.addSourceLocation(
-            startPosition, sourceInformation.startPosition);
-      }
-    }
-  }
+  void enterNode(Node, int startPosition) {}
 
+  @override
   void exitNode(Node node,
                 int startPosition,
                 int endPosition,
                 int closingPosition) {
-    SourceInformation sourceInformation = node.sourceInformation;
-    if (sourceInformation != null) {
-      if (closingPosition != null &&
-          sourceInformation.closingPosition != null) {
-        outBuffer.addSourceLocation(
-            closingPosition, sourceInformation.closingPosition);
-      }
-      if (sourceInformation.endPosition != null) {
-        outBuffer.addSourceLocation(endPosition, sourceInformation.endPosition);
-      }
-      if (rootNode == node) {
-        outBuffer.addSourceLocation(endPosition, null);
-        rootNode = null;
-      }
-    }
     if (monitor != null) {
       monitor.recordAstSize(node, endPosition - startPosition);
     }
+    codePositionListener.onPositions(
+        node, startPosition, endPosition, closingPosition);
   }
 }
+
+/// Interface for ast nodes that encapsulate an ast that needs to be
+/// traversed when counting tokens.
+abstract class AstContainer implements Node {
+  Iterable<Node> get containedNodes;
+}
+
+/// Interface for tasks in the compiler that need to finalize tokens after
+/// counting them.
+abstract class TokenFinalizer {
+  void finalizeTokens();
+}
+
+/// Implements reference counting for instances of [ReferenceCountedAstNode]
+class TokenCounter extends BaseVisitor {
+  @override
+  visitNode(Node node) {
+    if (node is AstContainer) {
+      for (Node element in node.containedNodes) {
+        element.accept(this);
+      }
+    } else if (node is ReferenceCountedAstNode) {
+      node.markSeen(this);
+    } else {
+      super.visitNode(node);
+    }
+  }
+
+  void countTokens(Node node) => node.accept(this);
+}
+
+abstract class ReferenceCountedAstNode implements Node {
+  markSeen(TokenCounter visitor);
+}
+
+/// Represents the LiteralString resulting from unparsing [expression]. The
+/// actual unparsing is done on demand when requesting the [value] of this
+/// node.
+///
+/// This is used when generated code needs to be represented as a string,
+/// for example by the lazy emitter or when generating code generators.
+class UnparsedNode extends DeferredString
+                   implements AstContainer {
+  @override
+  final Node tree;
+  final leg.Compiler _compiler;
+  final bool _protectForEval;
+  LiteralString _cachedLiteral;
+
+  Iterable<Node> get containedNodes => [tree];
+
+  /// A [js.Literal] that represents the string result of unparsing [ast].
+  ///
+  /// When its string [value] is requested, the node pretty-prints the given
+  /// [ast] and, if [protectForEval] is true, wraps the resulting
+  /// string in parenthesis. The result is also escaped.
+  UnparsedNode(this.tree, this._compiler, this._protectForEval);
+
+  LiteralString get _literal {
+    if (_cachedLiteral == null) {
+      String text = prettyPrint(tree, _compiler).getText();
+      if (_protectForEval) {
+        if (tree is Fun) text = '($text)';
+        if (tree is LiteralExpression) {
+          LiteralExpression literalExpression = tree;
+          String template = literalExpression.template;
+          if (template.startsWith("function ") ||
+          template.startsWith("{")) {
+            text = '($text)';
+          }
+        }
+      }
+      _cachedLiteral = js.escapedString(text);
+    }
+    return _cachedLiteral;
+  }
+
+  @override
+  String get value => _literal.value;
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
new file mode 100644
index 0000000..43ec130
--- /dev/null
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -0,0 +1,65 @@
+// 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.
+
+/// Helper for debug JS nodes.
+
+library js.debug;
+
+import 'package:js_ast/js_ast.dart';
+import '../util/util.dart' show Indentation, Tagging;
+
+/// Unparse the JavaScript [node].
+String nodeToString(Node node) {
+  JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
+      shouldCompressOutput: true,
+      preferSemicolonToNewlineInMinifiedOutput: true);
+  LenientPrintingContext printingContext =
+      new LenientPrintingContext();
+  new Printer(options, printingContext).visit(node);
+  return printingContext.getText();
+}
+
+/// Visitor that creates an XML-like representation of the structure of a
+/// JavaScript [Node].
+class DebugPrinter extends BaseVisitor with Indentation, Tagging<Node> {
+  StringBuffer sb = new StringBuffer();
+
+  void visitNodeWithChildren(Node node, String type) {
+    openNode(node, type);
+    node.visitChildren(this);
+    closeNode();
+  }
+
+  @override
+  void visitNode(Node node) {
+    visitNodeWithChildren(node, '${node.runtimeType}');
+  }
+
+  @override
+  void visitName(Name node) {
+    openAndCloseNode(node, '${node.runtimeType}', {'name': node.name});
+  }
+
+  @override
+  void visitLiteralString(LiteralString node) {
+    openAndCloseNode(node, '${node.runtimeType}', {'value': node.value});
+  }
+
+  /**
+   * Pretty-prints given node tree into string.
+   */
+  static String prettyPrint(Node node) {
+    var p = new DebugPrinter();
+    node.accept(p);
+    return p.sb.toString();
+  }
+}
+
+/// Simple printing context that doesn't throw on errors.
+class LenientPrintingContext extends SimpleJavaScriptPrintingContext {
+  @override
+  void error(String message) {
+    buffer.write('>>$message<<');
+  }
+}
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
new file mode 100644
index 0000000..0378a58
--- /dev/null
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -0,0 +1,68 @@
+// 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 js.source_mapping;
+
+import 'js.dart';
+import '../io/code_output.dart' show SourceLocations;
+import '../io/source_information.dart' show
+    SourceLocation,
+    SourceInformation,
+    SourceInformationStrategy;
+
+/// [SourceInformationStrategy] that can associate source information with
+/// JavaScript output.
+class JavaScriptSourceInformationStrategy
+    extends SourceInformationStrategy {
+  const JavaScriptSourceInformationStrategy();
+
+  /// Creates a processor that can associate source information on [Node] with
+  /// code offsets in the [sourceMapper].
+  SourceInformationProcessor createProcessor(SourceMapper sourceMapper) {
+    return const SourceInformationProcessor();
+  }
+}
+
+/// An observer of code positions of printed JavaScript [Node]s.
+class CodePositionListener {
+  const CodePositionListener();
+
+  /// Called to associate [node] with the provided start, end and closing
+  /// positions.
+  void onPositions(
+      Node node,
+      int startPosition,
+      int endPosition,
+      int closingPosition) {}
+}
+
+/// An interface for mapping code offsets with [SourceLocation]s for JavaScript
+/// [Node]s.
+abstract class SourceMapper {
+  /// Associate [codeOffset] with [sourceLocation] for [node].
+  void register(Node node, int codeOffset, SourceLocation sourceLocation);
+}
+
+/// An implementation of [SourceMapper] that stores the information directly
+/// into a [SourceLocations] object.
+class SourceLocationsMapper implements SourceMapper {
+  final SourceLocations sourceLocations;
+
+  SourceLocationsMapper(this.sourceLocations);
+
+  @override
+  void register(Node node, int codeOffset, SourceLocation sourceLocation) {
+    sourceLocations.addSourceLocation(codeOffset, sourceLocation);
+  }
+}
+
+/// A processor that associates [SourceInformation] with code position of
+/// JavaScript [Node]s.
+class SourceInformationProcessor extends CodePositionListener {
+  const SourceInformationProcessor();
+
+  /// Process the source information and code positions for the [node] and all
+  /// its children.
+  void process(Node node) {}
+}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index ddeacb4..c48fed1 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -242,7 +242,7 @@
   static const String START_ROOT_ISOLATE = 'startRootIsolate';
 
 
-  String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
+  String get patchVersion => USE_LAZY_EMITTER ? 'lazy' : 'full';
 
   final Annotations annotations;
 
@@ -617,8 +617,9 @@
 
   bool enabledNoSuchMethod = false;
 
+  final SourceInformationStrategy sourceInformationStrategy;
+
   JavaScriptBackend(Compiler compiler,
-                    SourceInformationFactory sourceInformationFactory,
                     {bool generateSourceMap: true})
       : namer = determineNamer(compiler),
         oneShotInterceptors = new Map<jsAst.Name, Selector>(),
@@ -626,6 +627,12 @@
         rti = new RuntimeTypes(compiler),
         specializedGetInterceptors = new Map<jsAst.Name, Set<ClassElement>>(),
         annotations = new Annotations(compiler),
+        this.sourceInformationStrategy =
+            generateSourceMap
+                ? (useNewSourceInfo
+                     ? const PositionSourceInformationStrategy()
+                     : const StartEndSourceInformationStrategy())
+                : const JavaScriptSourceInformationStrategy(),
         super(compiler) {
     emitter = new CodeEmitterTask(compiler, namer, generateSourceMap);
     typeVariableHandler = new TypeVariableHandler(compiler);
@@ -636,8 +643,8 @@
     patchResolverTask = new PatchResolverTask(compiler);
     functionCompiler = compiler.useCpsIr
          ? new CpsFunctionCompiler(
-             compiler, this, sourceInformationFactory)
-         : new SsaFunctionCompiler(this, sourceInformationFactory);
+             compiler, this, sourceInformationStrategy)
+         : new SsaFunctionCompiler(this, sourceInformationStrategy);
   }
 
   ConstantSystem get constantSystem => constants.constantSystem;
@@ -676,7 +683,9 @@
 
   static Namer determineNamer(Compiler compiler) {
     return compiler.enableMinification ?
-        new MinifyNamer(compiler) :
+        compiler.useFrequencyNamer ?
+            new FrequencyBasedNamer(compiler) :
+            new MinifyNamer(compiler) :
         new Namer(compiler);
   }
 
@@ -1462,6 +1471,14 @@
    */
   String assembleCode(Element element) {
     assert(invariant(element, element.isDeclaration));
+    var code = generatedCode[element];
+    if (namer is jsAst.TokenFinalizer) {
+      jsAst.TokenCounter counter = new jsAst.TokenCounter();
+      counter.countTokens(code);
+      // Avoid a warning.
+      var finalizer = namer;
+      finalizer.finalizeTokens();
+    }
     return jsAst.prettyPrint(generatedCode[element], compiler).getText();
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index cbead55..1447173 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -191,28 +191,13 @@
     return buildConstant(glue.getConstantValueForVariable(parameter));
   }
 
-  // TODO(karlklose): get rid of the selector argument.
-  js.Expression buildStaticInvoke(Selector selector,
-                                  Element target,
+  js.Expression buildStaticInvoke(Element target,
                                   List<js.Expression> arguments,
                                   {SourceInformation sourceInformation}) {
     registry.registerStaticInvocation(target.declaration);
-    if (target == glue.getInterceptorMethod) {
-      // This generates a call to the specialized interceptor function, which
-      // does not have a specialized element yet, but is emitted as a stub from
-      // the emitter in [InterceptorStubGenerator].
-      // TODO(karlklose): Either change [InvokeStatic] to take an [Entity]
-      //   instead of an [Element] and model the getInterceptor functions as
-      //   [Entity]s or add a specialized Tree-IR node for interceptor calls.
-      registry.registerUseInterceptor();
-      js.VariableUse interceptorLibrary = glue.getInterceptorLibrary();
-      return js.propertyCall(interceptorLibrary, js.string(selector.name),
-                             arguments);
-    } else {
-      js.Expression elementAccess = glue.staticFunctionAccess(target);
-      return new js.Call(elementAccess, arguments,
-          sourceInformation: sourceInformation);
-    }
+    js.Expression elementAccess = glue.staticFunctionAccess(target);
+    return new js.Call(elementAccess, arguments,
+        sourceInformation: sourceInformation);
   }
 
   @override
@@ -220,10 +205,9 @@
     if (node.constant != null) return giveup(node);
 
     registry.registerInstantiatedType(node.type);
-    Selector selector = node.selector;
     FunctionElement target = node.target;
     List<js.Expression> arguments = visitExpressionList(node.arguments);
-    return buildStaticInvoke(selector, target, arguments);
+    return buildStaticInvoke(target, arguments);
   }
 
   void registerMethodInvoke(tree_ir.InvokeMethod node) {
@@ -255,12 +239,10 @@
 
   @override
   js.Expression visitInvokeStatic(tree_ir.InvokeStatic node) {
-    Selector selector = node.selector;
-    assert(selector.isGetter || selector.isSetter || selector.isCall);
     FunctionElement target = node.target;
     List<js.Expression> arguments = visitExpressionList(node.arguments);
-    return buildStaticInvoke(selector, target, arguments,
-        sourceInformation: node.sourceInformation);
+    return buildStaticInvoke(target, arguments,
+          sourceInformation: node.sourceInformation);
   }
 
   @override
@@ -305,10 +287,7 @@
     List<js.Expression> args = entries.isEmpty
          ? <js.Expression>[]
          : <js.Expression>[new js.ArrayInitializer(entries)];
-    return buildStaticInvoke(
-        new Selector.call(constructor.name, constructor.library, 2),
-        constructor,
-        args);
+    return buildStaticInvoke(constructor, args);
   }
 
   @override
@@ -346,6 +325,11 @@
         return js.js(r'!#.immutable$list', <js.Expression>[value]);
       }
 
+      // The helper we use needs the JSArray class to exist, but for some
+      // reason the helper does not cause this dependency to be registered.
+      // TODO(asgerf): Most programs need List anyway, but we should fix this.
+      registry.registerInstantiatedClass(glue.listClass);
+
       // We use one of the two helpers:
       //
       //     checkSubtype(value, $isT, typeArgs, $asT)
@@ -683,8 +667,7 @@
   js.Expression buildStaticHelperInvocation(FunctionElement helper,
                                             List<js.Expression> arguments) {
     registry.registerStaticUse(helper);
-    return buildStaticInvoke(new Selector.fromElement(helper), helper,
-        arguments);
+    return buildStaticInvoke(helper, arguments);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 25492d6..9ed2829 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -20,7 +20,7 @@
     ForwardingTypeMask;
 import '../../elements/elements.dart';
 import '../../js/js.dart' as js;
-import '../../io/source_information.dart' show SourceInformationFactory;
+import '../../io/source_information.dart' show SourceInformationStrategy;
 import '../../tree_ir/tree_ir_builder.dart' as tree_builder;
 import '../../cps_ir/optimizers.dart';
 import '../../cps_ir/optimizers.dart' as cps_opt;
@@ -36,7 +36,7 @@
   final ConstantSystem constantSystem;
   final Compiler compiler;
   final Glue glue;
-  final SourceInformationFactory sourceInformationFactory;
+  final SourceInformationStrategy sourceInformationFactory;
 
   // TODO(karlklose,sigurm): remove and update dart-doc of [compile].
   final FunctionCompiler fallbackCompiler;
@@ -46,7 +46,7 @@
   IrBuilderTask get irBuilderTask => compiler.irBuilder;
 
   CpsFunctionCompiler(Compiler compiler, JavaScriptBackend backend,
-                      SourceInformationFactory sourceInformationFactory)
+                      SourceInformationStrategy sourceInformationFactory)
       : fallbackCompiler =
             new ssa.SsaFunctionCompiler(backend, sourceInformationFactory),
         this.sourceInformationFactory = sourceInformationFactory,
@@ -234,7 +234,7 @@
 
   js.Node attachPosition(js.Node node, AstElement element) {
     return node.withSourceInformation(
-        sourceInformationFactory.forContext(element)
+        sourceInformationFactory.createBuilderForContext(element)
             .buildDeclaration(element));
   }
 }
diff --git a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
index 1666ca5..707e7e76 100644
--- a/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
+++ b/pkg/compiler/lib/src/js_backend/field_naming_mixin.dart
@@ -44,7 +44,7 @@
  * hierarchy is encoded using instances of [_FieldNamingScope].
  */
 class _FieldNamingRegistry {
-  final MinifyNamer namer;
+  final Namer namer;
 
   final Map<Entity, _FieldNamingScope> scopes =
       new Map<Entity, _FieldNamingScope>();
@@ -77,8 +77,7 @@
         nameStore.add(
             new StringBackedName(MinifyNamer._reservedNativeProperties[index]));
       } else {
-        nameStore.add(namer.getFreshName("field$index", namer.usedInstanceNames,
-            namer.suggestedInstanceNames));
+        nameStore.add(namer.getFreshName(NamingScope.instance, "field$index"));
       }
     }
 
diff --git a/pkg/compiler/lib/src/js_backend/frequency_namer.dart b/pkg/compiler/lib/src/js_backend/frequency_namer.dart
new file mode 100644
index 0000000..0aaf8f6
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/frequency_namer.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of js_backend;
+
+class FrequencyBasedNamer extends Namer with _MinifiedFieldNamer,
+    _MinifiedOneShotInterceptorNamer implements jsAst.TokenFinalizer {
+  _FieldNamingRegistry fieldRegistry;
+  List<TokenName> tokens = new List<TokenName>();
+
+  Map<NamingScope, TokenScope> _tokenScopes =
+      new Maplet<NamingScope, TokenScope>();
+
+  // Some basic settings for smaller names
+  String get isolateName => 'I';
+  String get isolatePropertiesName => 'p';
+  bool get shouldMinify => true;
+
+  final String getterPrefix = 'g';
+  final String setterPrefix = 's';
+  final String callPrefix = ''; // this will create function names $<n>
+
+  FrequencyBasedNamer(Compiler compiler) : super(compiler) {
+    fieldRegistry = new _FieldNamingRegistry(this);
+  }
+
+  TokenScope newScopeFor(NamingScope scope) {
+    if (scope == NamingScope.instance) {
+      Set<String> illegalNames = new Set<String>.from(jsReserved);
+      for (String illegal in MinifyNamer._reservedNativeProperties) {
+        illegalNames.add(illegal);
+        if (MinifyNamer._hasBannedPrefix(illegal)) {
+          illegalNames.add(illegal.substring(1));
+        }
+      }
+      return new TokenScope(illegalNames);
+    } else {
+      return new TokenScope(jsReserved);
+    }
+  }
+
+  @override
+  jsAst.Name getFreshName(NamingScope scope, String proposedName,
+                          {bool sanitizeForNatives: false,
+                           bool sanitizeForAnnotations: false}) {
+    // Grab the scope for this token
+    TokenScope tokenScope = _tokenScopes.putIfAbsent(scope,
+                                                     () => newScopeFor(scope));
+
+    // Get the name the normal namer would use as a key.
+    String proposed = _generateFreshStringForName(proposedName,
+                                                  getUsedNames(scope),
+                                                  getSuggestedNames(scope),
+                                                  sanitizeForNatives:
+                                                  sanitizeForNatives,
+                                                  sanitizeForAnnotations:
+                                                  sanitizeForAnnotations);
+
+    TokenName name = new TokenName(tokenScope, proposed);
+    tokens.add(name);
+    return name;
+  }
+
+  @override
+  jsAst.Name instanceFieldPropertyName(Element element) {
+    jsAst.Name proposed = _minifiedInstanceFieldPropertyName(element);
+    if (proposed != null) {
+      return proposed;
+    }
+    return super.instanceFieldPropertyName(element);
+  }
+
+  @override
+  void finalizeTokens() {
+    int compareReferenceCount(TokenName a, TokenName b) {
+      int result = b._rc - a._rc;
+      if (result == 0) result = a.key.compareTo(b.key);
+      return result;
+    }
+
+    List<TokenName> usedNames =
+        tokens.where((TokenName a) => a._rc > 0).toList();
+    usedNames.sort(compareReferenceCount);
+    usedNames.forEach((TokenName token) => token.finalize());
+  }
+}
+
+class TokenScope {
+  List<int> _nextName = [$a];
+  final Set<String> illegalNames;
+
+  TokenScope([this.illegalNames = const ImmutableEmptySet()]);
+
+  /// Increments the letter at [pos] in the current name. Also takes care of
+  /// overflows to the left. Returns the carry bit, i.e., it returns `true`
+  /// if all positions to the left have wrapped around.
+  ///
+  /// If [_nextName] is initially 'a', this will generate the sequence
+  ///
+  /// [a-zA-Z]
+  /// [a-zA-Z][_0-9a-zA-Z]
+  /// [a-zA-Z][_0-9a-zA-Z][_0-9a-zA-Z]
+  /// ...
+  bool _incrementPosition(int pos) {
+    bool overflow = false;
+    if (pos < 0) return true;
+    int value = _nextName[pos];
+    if (value == $_) {
+      value = $0;
+    } else if (value == $9) {
+      value = $a;
+    } else if (value == $z) {
+      value = $A;
+    } else if (value == $Z) {
+      overflow = _incrementPosition(pos - 1);
+      value = (pos > 0) ? $_ : $a;
+    } else {
+      value++;
+    }
+    _nextName[pos] = value;
+    return overflow;
+  }
+
+  _incrementName() {
+    if (_incrementPosition(_nextName.length - 1)) {
+      _nextName.add($_);
+    }
+  }
+
+  String getNextName() {
+    String proposal;
+    do {
+      proposal = new String.fromCharCodes(_nextName);
+      _incrementName();
+    } while (MinifyNamer._hasBannedPrefix(proposal) ||
+             illegalNames.contains(proposal));
+
+    return proposal;
+  }
+}
+
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 36e75ab..8608f00 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -19,16 +19,20 @@
 import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../io/code_output.dart';
-import '../io/source_information.dart' show SourceInformationFactory;
+import '../io/source_information.dart' show
+    SourceInformationStrategy,
+    useNewSourceInfo;
+import '../io/position_information.dart' show
+    PositionSourceInformationStrategy;
+import '../io/start_end_information.dart' show
+    StartEndSourceInformationStrategy;
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
+import '../js/js_source_mapping.dart' show
+    JavaScriptSourceInformationStrategy;
 import '../js_emitter/js_emitter.dart'
-    show Emitter,
-         CodeEmitterTask,
-         ClassBuilder,
-         MetadataCollector,
-         Placeholder,
-         USE_NEW_EMITTER;
+    show ClassBuilder, CodeEmitterTask, Emitter, MetadataCollector, Placeholder,
+        TokenFinalizer, USE_LAZY_EMITTER;
 
 import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
 import '../native/native.dart' as native;
@@ -53,9 +57,11 @@
 part 'constant_emitter.dart';
 part 'constant_handler_javascript.dart';
 part 'custom_elements_analysis.dart';
+part 'frequency_namer.dart';
 part 'field_naming_mixin.dart';
 part 'minify_namer.dart';
 part 'namer.dart';
+part 'namer_names.dart';
 part 'no_such_method_registry.dart';
 part 'runtime_types.dart';
 part 'type_variable_handler.dart';
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index 9a2d1e3..dd01a92 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -7,7 +7,8 @@
 /**
  * Assigns JavaScript identifiers to Dart variables, class-names and members.
  */
-class MinifyNamer extends Namer with _MinifiedFieldNamer {
+class MinifyNamer extends Namer with _MinifiedFieldNamer,
+    _MinifyConstructorBodyNamer, _MinifiedOneShotInterceptorNamer {
   MinifyNamer(Compiler compiler) : super(compiler) {
     reserveBackendNames();
     fieldRegistry = new _FieldNamingRegistry(this);
@@ -32,11 +33,11 @@
   /// [sanitizeForNatives] and [sanitizeForAnnotations] are ignored because the
   /// minified names will always avoid clashing with annotated names or natives.
   @override
-  jsAst.Name getFreshName(String proposedName,
-                          Set<String> usedNames,
-                          Map<String, String> suggestedNames,
-                          {bool sanitizeForNatives: false,
-                           bool sanitizeForAnnotations: false}) {
+  String _generateFreshStringForName(String proposedName,
+      Set<String> usedNames,
+      Map<String, String> suggestedNames,
+      {bool sanitizeForNatives: false,
+       bool sanitizeForAnnotations: false}) {
     String freshName;
     String suggestion = suggestedNames[proposedName];
     if (suggestion != null && !usedNames.contains(suggestion)) {
@@ -46,7 +47,7 @@
           suggestedNames.values);
     }
     usedNames.add(freshName);
-    return new StringBackedName(freshName);
+    return freshName;
   }
 
   // From issue 7554.  These should not be used on objects (as instance
@@ -54,7 +55,7 @@
   // OK to use them as fields, as we only access fields directly if we know
   // the receiver type.
   static const List<String> _reservedNativeProperties = const <String>[
-      'Q', 'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z',
+      'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z', 'Q',
       // 2-letter:
       'ch', 'cx', 'cy', 'db', 'dx', 'dy', 'fr', 'fx', 'fy', 'go', 'id', 'k1',
       'k2', 'k3', 'k4', 'r1', 'r2', 'rx', 'ry', 'x1', 'x2', 'y1', 'y2',
@@ -192,7 +193,7 @@
 
   /// Instance members starting with g and s are reserved for getters and
   /// setters.
-  bool _hasBannedPrefix(String name) {
+  static bool _hasBannedPrefix(String name) {
     int code = name.codeUnitAt(0);
     return code == $g || code == $s;
   }
@@ -255,3 +256,96 @@
   }
 }
 
+/// Implements naming for constructor bodies.
+///
+/// Constructor bodies are only called in settings where the target is
+/// statically known. Therefore, we can share their names between classes.
+/// However, to support calling the constructor body of a super constructor,
+/// each level in the inheritance tree has to use its own names.
+///
+/// This class implements a naming scheme by counting the distance from
+/// a given constructor to [Object], where distance is the number of
+/// constructors declared along the inheritance chain.
+class _ConstructorBodyNamingScope {
+  final int _startIndex;
+  final List _constructors;
+
+  int get numberOfConstructors => _constructors.length;
+
+  _ConstructorBodyNamingScope _superScope;
+
+  _ConstructorBodyNamingScope.rootScope(ClassElement cls)
+      : _superScope = null,
+        _startIndex = 0,
+        _constructors = cls.constructors.toList(growable: false);
+
+  _ConstructorBodyNamingScope.forClass(ClassElement cls,
+                                       _ConstructorBodyNamingScope superScope)
+      : _superScope = superScope,
+        _startIndex = superScope._startIndex + superScope.numberOfConstructors,
+        _constructors = cls.constructors.toList(growable: false);
+
+  // Mixin Applications have constructors but we never generate code for them,
+  // so they do not count in the inheritance chain.
+  _ConstructorBodyNamingScope.forMixinApplication(ClassElement cls,
+      _ConstructorBodyNamingScope superScope)
+      : _superScope = superScope,
+        _startIndex = superScope._startIndex + superScope.numberOfConstructors,
+        _constructors = const [];
+
+  factory _ConstructorBodyNamingScope(ClassElement cls,
+      Map<ClassElement, _ConstructorBodyNamingScope> registry) {
+    return registry.putIfAbsent(cls, () {
+      if (cls.superclass == null) {
+        return new _ConstructorBodyNamingScope.rootScope(cls);
+      } else if (cls.isMixinApplication) {
+        return new _ConstructorBodyNamingScope.forMixinApplication(cls,
+            new _ConstructorBodyNamingScope(cls.superclass, registry));
+      } else {
+        return new _ConstructorBodyNamingScope.forClass(cls,
+            new _ConstructorBodyNamingScope(cls.superclass, registry));
+      }
+    });
+  }
+
+  String constructorBodyKeyFor(ConstructorBodyElement body) {
+    int position = _constructors.indexOf(body.constructor);
+    assert(invariant(body, position >= 0, message: "constructor body missing"));
+    return "@constructorBody@${_startIndex + position}";
+  }
+}
+
+abstract class _MinifyConstructorBodyNamer implements Namer {
+  Map<ClassElement, _ConstructorBodyNamingScope> _constructorBodyScopes =
+      new Map<ClassElement, _ConstructorBodyNamingScope>();
+
+  @override
+  jsAst.Name constructorBodyName(FunctionElement method) {
+    _ConstructorBodyNamingScope scope =
+        new _ConstructorBodyNamingScope(method.enclosingClass,
+                                        _constructorBodyScopes);
+    String key = scope.constructorBodyKeyFor(method);
+    return _disambiguateMemberByKey(key,
+        () => _proposeNameForConstructorBody(method));
+  }
+}
+
+abstract class _MinifiedOneShotInterceptorNamer implements Namer {
+  /// Property name used for the one-shot interceptor method for the given
+  /// [selector] and return-type specialization.
+  @override
+  jsAst.Name nameForGetOneShotInterceptor(Selector selector,
+      Iterable<ClassElement> classes) {
+    String root = selector.isOperator
+        ? operatorNameToIdentifier(selector.name)
+        : privateName(selector.memberName);
+    String prefix = selector.isGetter
+        ? r"$get"
+        : selector.isSetter ? r"$set" : "";
+    String arity = selector.isCall ? "${selector.argumentCount}" : "";
+    String suffix = suffixForGetInterceptor(classes);
+    String fullName = "\$intercepted$prefix\$$root$arity\$$suffix";
+    return _disambiguateInternalGlobal(fullName);
+  }
+}
+
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index 1dac9f9..9ce0b81 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -387,6 +387,20 @@
   final Map<String, jsAst.Name> userInstanceOperators =
       new HashMap<String, jsAst.Name>();
 
+  /// Used to disambiguate names for constants in [constantName].
+  final Set<String> usedConstantNames = new Set<String>();
+
+  Set<String> getUsedNames(NamingScope scope) {
+    if (scope == NamingScope.global) {
+      return usedGlobalNames;
+    } else if (scope == NamingScope.instance){
+      return usedInstanceNames;
+    } else {
+      assert(scope == NamingScope.constant);
+      return usedConstantNames;
+    }
+  }
+
   final Map<String, int> popularNameCounters = <String, int>{};
 
   final Map<LibraryElement, String> libraryLongNames =
@@ -413,6 +427,18 @@
   final Map<String, String> suggestedGlobalNames = <String, String>{};
   final Map<String, String> suggestedInstanceNames = <String, String>{};
 
+  Map<String, String> getSuggestedNames(NamingScope scope) {
+    if (scope == NamingScope.global) {
+      return suggestedGlobalNames;
+    } else if (scope == NamingScope.instance) {
+      return suggestedInstanceNames;
+    } else {
+      assert(scope == NamingScope.constant);
+      return const {};
+    }
+  }
+
+
   /// Used to store unique keys for library names. Keys are not used as names,
   /// nor are they visible in the output. The only serve as an internal
   /// key into maps.
@@ -505,7 +531,7 @@
     jsAst.Name result = constantNames[constant];
     if (result == null) {
       String longName = constantLongName(constant);
-      result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames);
+      result = getFreshName(NamingScope.constant, longName);
       constantNames[constant] = result;
     }
     return result;
@@ -585,11 +611,16 @@
     return '$name\$${suffix.join(r'$')}';
   }
 
+  /// Name for a constructor body.
+  jsAst.Name constructorBodyName(FunctionElement ctor) {
+    return _disambiguateInternalMember(ctor,
+        () => _proposeNameForConstructorBody(ctor));
+  }
+
   /// Annotated name for [method] encoding arity and named parameters.
   jsAst.Name instanceMethodName(FunctionElement method) {
     if (method.isGenerativeConstructorBody) {
-      return _disambiguateInternalMember(method,
-          () => _proposeNameForConstructorBody(method));
+      return constructorBodyName(method);
     }
     return invocationName(new Selector.fromElement(method));
   }
@@ -821,7 +852,7 @@
   jsAst.Name _disambiguateInternalGlobal(String name) {
     jsAst.Name newName = internalGlobals[name];
     if (newName == null) {
-      newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames);
+      newName = getFreshName(NamingScope.global, name);
       internalGlobals[name] = newName;
     }
     return newName;
@@ -868,8 +899,7 @@
     jsAst.Name newName = userGlobals[element];
     if (newName == null) {
       String proposedName = _proposeNameForGlobal(element);
-      newName = getFreshName(proposedName, usedGlobalNames,
-                             suggestedGlobalNames);
+      newName = getFreshName(NamingScope.global, proposedName);
       userGlobals[element] = newName;
     }
     return newName;
@@ -909,8 +939,30 @@
         // proposed name must be a valid identifier, but not necessarily unique.
         proposedName += r'$' + suffixes.join(r'$');
       }
-      newName = getFreshName(proposedName,
-                             usedInstanceNames, suggestedInstanceNames,
+      newName = getFreshName(NamingScope.instance, proposedName,
+                             sanitizeForAnnotations: true);
+      userInstanceMembers[key] = newName;
+    }
+    return newName;
+  }
+
+  /// Returns the disambiguated name for the instance member identified by
+  /// [key].
+  ///
+  /// When a name for an element is requested by key, it may not be requested
+  /// by element at the same time, as two different names would be returned.
+  ///
+  /// If key has not yet been registered, [proposeName] is used to generate
+  /// a name proposal for the given key.
+  ///
+  /// [key] must not clash with valid instance names. This is typically
+  /// achieved by using at least one character in [key] that is not valid in
+  /// identifiers, for example the @ symbol.
+  jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) {
+    jsAst.Name newName = userInstanceMembers[key];
+    if (newName == null) {
+      String name = proposeName();
+      newName = getFreshName(NamingScope.instance, name,
                              sanitizeForAnnotations: true);
       userInstanceMembers[key] = newName;
     }
@@ -949,8 +1001,7 @@
     if (newName == null) {
       String name = proposeName();
       bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass);
-      newName = getFreshName(name,
-                             usedInstanceNames, suggestedInstanceNames,
+      newName = getFreshName(NamingScope.instance, name,
                              sanitizeForAnnotations: true,
                              sanitizeForNatives: mayClashNative);
       internalInstanceMembers[element] = newName;
@@ -967,30 +1018,17 @@
   jsAst.Name _disambiguateOperator(String operatorIdentifier) {
     jsAst.Name newName = userInstanceOperators[operatorIdentifier];
     if (newName == null) {
-      newName = getFreshName(operatorIdentifier, usedInstanceNames,
-                             suggestedInstanceNames);
+      newName = getFreshName(NamingScope.instance, operatorIdentifier);
       userInstanceOperators[operatorIdentifier] = newName;
     }
     return newName;
   }
 
-  /// Returns an unused name.
-  ///
-  /// [proposedName] must be a valid JavaScript identifier.
-  ///
-  /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not
-  /// to have the form of an annotated name.
-  ///
-  /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to
-  /// clash with a property name on a native object.
-  ///
-  /// Note that [MinifyNamer] overrides this method with one that produces
-  /// minified names.
-  jsAst.Name getFreshName(String proposedName,
-                          Set<String> usedNames,
-                          Map<String, String> suggestedNames,
-                          {bool sanitizeForAnnotations: false,
-                           bool sanitizeForNatives: false}) {
+  String _generateFreshStringForName(String proposedName,
+      Set<String> usedNames,
+      Map<String, String> suggestedNames,
+      {bool sanitizeForAnnotations: false,
+       bool sanitizeForNatives: false}) {
     if (sanitizeForAnnotations) {
       proposedName = _sanitizeForAnnotations(proposedName);
     }
@@ -1011,6 +1049,32 @@
       candidate = "$proposedName$i";
     }
     usedNames.add(candidate);
+    return candidate;
+  }
+
+  /// Returns an unused name.
+  ///
+  /// [proposedName] must be a valid JavaScript identifier.
+  ///
+  /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not
+  /// to have the form of an annotated name.
+  ///
+  /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to
+  /// clash with a property name on a native object.
+  ///
+  /// Note that [MinifyNamer] overrides this method with one that produces
+  /// minified names.
+  jsAst.Name getFreshName(NamingScope scope,
+                          String proposedName,
+                          {bool sanitizeForAnnotations: false,
+                           bool sanitizeForNatives: false}) {
+    String candidate =
+        _generateFreshStringForName(proposedName,
+                                    getUsedNames(scope),
+                                    getSuggestedNames(scope),
+                                    sanitizeForAnnotations:
+                                        sanitizeForAnnotations,
+                                    sanitizeForNatives: sanitizeForNatives);
     return new StringBackedName(candidate);
   }
 
@@ -1340,8 +1404,7 @@
   jsAst.Name getFunctionTypeName(FunctionType functionType) {
     return functionTypeNameMap.putIfAbsent(functionType, () {
       String proposedName = functionTypeNamer.computeName(functionType);
-      return getFreshName(proposedName, usedInstanceNames,
-                          suggestedInstanceNames);
+      return getFreshName(NamingScope.instance, proposedName);
     });
   }
 
@@ -1482,133 +1545,6 @@
   }
 }
 
-abstract class _NamerName extends jsAst.Name {
-  int get _kind;
-}
-
-class StringBackedName extends _NamerName {
-  final String name;
-  int get _kind => 1;
-  
-  StringBackedName(this.name);
-
-  toString() => throw new UnsupportedError("Cannot convert a name to a string");
-
-  operator==(other) {
-    if (identical(this, other)) return true;
-    return (other is StringBackedName) && other.name == name;
-  }
-
-  int get hashCode => name.hashCode;
-
-  int compareTo(_NamerName other) {
-    if (other._kind != _kind) return other._kind - _kind;
-    return name.compareTo(other.name);
-  }
-}
-
-abstract class _PrefixedName extends _NamerName {
-  final jsAst.Name prefix;
-  final jsAst.Name base;
-  int get _kind;
-
-  _PrefixedName(this.prefix, this.base);
-  
-  String get name => prefix.name + base.name;
-
-  toString() => throw new UnsupportedError("Cannot convert a name to a string");
-
-  bool operator==(other) {
-    if (identical(this, other)) return true;
-    if (other is! _PrefixedName) return false;
-    return other.base == base && other.prefix == prefix;
-  }
-
-  int get hashCode => base.hashCode * 13 + prefix.hashCode;
-
-  int compareTo(_NamerName other) {
-    if (other._kind != _kind) return other._kind - _kind;
-    _PrefixedName otherSameKind = other;
-    int result = prefix.compareTo(otherSameKind.prefix);
-    if (result == 0) {
-      result = name.compareTo(otherSameKind.name);
-    }
-    return result;
-  }
-}
-
-class GetterName extends _PrefixedName {
-  int get _kind => 2;
-
-  GetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
-}
-
-class SetterName extends _PrefixedName {
-  int get _kind => 3;
-
-  SetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
-}
-
-class _AsyncName extends _PrefixedName {
-  int get _kind => 4;
-
-  _AsyncName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
-
-  @override
-  bool get allowRename => true;
-}
-
-class CompoundName extends _NamerName {
-  final List<_NamerName> _parts;
-  int get _kind => 4;
-  String _cachedName;
-  int _cachedHashCode = -1;
-
-  CompoundName(this._parts);
-
-  String get name {
-    if (_cachedName == null) {
-      _cachedName = _parts.map((jsAst.Name name) => name.name).join();
-    }
-    return _cachedName;
-  }
-
-  toString() => throw new UnsupportedError("Cannot convert a name to a string");
-
-  bool operator==(other) {
-    if (identical(this, other)) return true;
-    if (other is! CompoundName) return false;
-    if (other._parts.length != _parts.length) return false;
-    for (int i = 0; i < _parts.length; ++i) {
-      if (other._parts[i] != _parts[i]) return false;
-    }
-    return true;
-  }
-
-  int get hashCode {
-    if (_cachedHashCode < 0) {
-      _cachedHashCode = 0;
-      for (jsAst.Name name in _parts) {
-        _cachedHashCode = (_cachedHashCode * 17 + name.hashCode) & 0x7fffffff;
-      }
-    }
-    return _cachedHashCode;
-  }
-
-  int compareTo(_NamerName other) {
-    if (other._kind != _kind) return other._kind - _kind;
-    CompoundName otherSameKind = other;
-    if (otherSameKind._parts.length != _parts.length) {
-      return otherSameKind._parts.length - _parts.length;
-    }
-    int result = 0;
-    for (int pos = 0; result == 0 && pos < _parts.length; pos++) {
-      result = _parts[pos].compareTo(otherSameKind._parts[pos]);
-    }
-    return result;
-  }
-}
-
 /**
  * Generator of names for [ConstantValue] values.
  *
@@ -2044,3 +1980,9 @@
     }
   }
 }
+
+enum NamingScope {
+  global,
+  instance,
+  constant
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/js_backend/namer_names.dart b/pkg/compiler/lib/src/js_backend/namer_names.dart
new file mode 100644
index 0000000..3d0e1f3
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/namer_names.dart
@@ -0,0 +1,181 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of js_backend;
+
+abstract class _NamerName extends jsAst.Name {
+  int get _kind;
+
+  toString() => throw new UnsupportedError("Cannot convert a name to a string");
+}
+
+enum _NamerNameKinds {
+  StringBacked,
+  Getter,
+  Setter,
+  Async,
+  Compound,
+  Token
+}
+
+class StringBackedName extends _NamerName {
+  final String name;
+  int get _kind => _NamerNameKinds.StringBacked.index;
+
+  StringBackedName(this.name);
+
+  String get key => name;
+
+  operator==(other) {
+    if (identical(this, other)) return true;
+    return (other is StringBackedName) && other.name == name;
+  }
+
+  int get hashCode => name.hashCode;
+
+  int compareTo(_NamerName other) {
+    if (other._kind != _kind) return other._kind - _kind;
+    return name.compareTo(other.name);
+  }
+}
+
+abstract class _PrefixedName extends _NamerName implements jsAst.AstContainer {
+  final jsAst.Name prefix;
+  final jsAst.Name base;
+  int get _kind;
+
+  Iterable<jsAst.Node> get containedNodes => [prefix, base];
+
+  _PrefixedName(this.prefix, this.base);
+
+  String get name => prefix.name + base.name;
+
+  String get key => prefix.key + base.key;
+
+  bool operator==(other) {
+    if (identical(this, other)) return true;
+    if (other is! _PrefixedName) return false;
+    return other.base == base && other.prefix == prefix;
+  }
+
+  int get hashCode => base.hashCode * 13 + prefix.hashCode;
+
+  int compareTo(_NamerName other) {
+    if (other._kind != _kind) return other._kind - _kind;
+    _PrefixedName otherSameKind = other;
+    int result = prefix.compareTo(otherSameKind.prefix);
+    if (result == 0) {
+      result = prefix.compareTo(otherSameKind.prefix);
+      if (result == 0) {
+        result = base.compareTo(otherSameKind.base);
+      }
+    }
+    return result;
+  }
+}
+
+class GetterName extends _PrefixedName {
+  int get _kind => _NamerNameKinds.Getter.index;
+
+  GetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
+}
+
+class SetterName extends _PrefixedName {
+  int get _kind => _NamerNameKinds.Setter.index;
+
+  SetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
+}
+
+class _AsyncName extends _PrefixedName {
+  int get _kind => _NamerNameKinds.Async.index;
+
+  _AsyncName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
+
+  @override
+  bool get allowRename => true;
+}
+
+class CompoundName extends _NamerName implements jsAst.AstContainer {
+  final List<_NamerName> _parts;
+  int get _kind => _NamerNameKinds.Compound.index;
+  String _cachedName;
+  int _cachedHashCode = -1;
+
+  Iterable<jsAst.Node> get containedNodes => _parts;
+
+  CompoundName(this._parts);
+
+  String get name {
+    if (_cachedName == null) {
+      _cachedName = _parts.map((jsAst.Name name) => name.name).join();
+    }
+    return _cachedName;
+  }
+
+  String get key => _parts.map((_NamerName name) => name.key).join();
+
+  bool operator==(other) {
+    if (identical(this, other)) return true;
+    if (other is! CompoundName) return false;
+    if (other._parts.length != _parts.length) return false;
+    for (int i = 0; i < _parts.length; ++i) {
+      if (other._parts[i] != _parts[i]) return false;
+    }
+    return true;
+  }
+
+  int get hashCode {
+    if (_cachedHashCode < 0) {
+      _cachedHashCode = 0;
+      for (jsAst.Name name in _parts) {
+        _cachedHashCode = (_cachedHashCode * 17 + name.hashCode) & 0x7fffffff;
+      }
+    }
+    return _cachedHashCode;
+  }
+
+  int compareTo(_NamerName other) {
+    if (other._kind != _kind) return other._kind - _kind;
+    CompoundName otherSameKind = other;
+    if (otherSameKind._parts.length != _parts.length) {
+      return otherSameKind._parts.length - _parts.length;
+    }
+    int result = 0;
+    for (int pos = 0; result == 0 && pos < _parts.length; pos++) {
+      result = _parts[pos].compareTo(otherSameKind._parts[pos]);
+    }
+    return result;
+  }
+}
+
+class TokenName extends _NamerName implements jsAst.ReferenceCountedAstNode {
+  int get _kind => _NamerNameKinds.Token.index;
+  String _name;
+  final String key;
+  final TokenScope _scope;
+  int _rc = 0;
+
+  TokenName(this._scope, this.key);
+
+  bool get isFinalized => _name != null;
+
+  String get name {
+    assert(isFinalized);
+    return _name;
+  }
+
+  @override
+  int compareTo(_NamerName other) {
+    if (other._kind != _kind) return other._kind - _kind;
+    TokenName otherToken = other;
+    return key.compareTo(otherToken.key);
+  }
+
+  markSeen(jsAst.TokenCounter counter) => _rc++;
+
+  finalize() {
+    assert(!isFinalized);
+    _name = _scope.getNextName();
+  }
+}
\ No newline at end of file
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 366d769..53e1130 100644
--- a/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/class_stub_generator.dart
@@ -220,52 +220,49 @@
   Compiler compiler = backend.compiler;
 
   Element closureFromTearOff = backend.findHelper('closureFromTearOff');
-  String tearOffAccessText;
   jsAst.Expression tearOffAccessExpression;
-  String tearOffGlobalObjectName;
-  String tearOffGlobalObject;
+  jsAst.Expression tearOffGlobalObjectString;
+  jsAst.Expression tearOffGlobalObject;
   if (closureFromTearOff != null) {
-    // We need both the AST that references [closureFromTearOff] and a string
-    // for the NoCsp version that constructs a function.
     tearOffAccessExpression =
         backend.emitter.staticFunctionAccess(closureFromTearOff);
-    tearOffAccessText =
-        jsAst.prettyPrint(tearOffAccessExpression, compiler).getText();
-    tearOffGlobalObjectName = tearOffGlobalObject =
-        namer.globalObjectFor(closureFromTearOff);
+    tearOffGlobalObject =
+        js.stringPart(namer.globalObjectFor(closureFromTearOff));
+    tearOffGlobalObjectString =
+        js.string(namer.globalObjectFor(closureFromTearOff));
   } else {
     // Default values for mocked-up test libraries.
-    tearOffAccessText =
-        r'''function() { throw "Helper 'closureFromTearOff' missing." }''';
-    tearOffAccessExpression = js(tearOffAccessText);
-    tearOffGlobalObjectName = 'MissingHelperFunction';
-    tearOffGlobalObject = '($tearOffAccessText())';
+    tearOffAccessExpression = js(
+        r'''function() { throw "Helper 'closureFromTearOff' missing." }''');
+    tearOffGlobalObjectString = js.string('MissingHelperFunction');
+    tearOffGlobalObject = js(
+        r'''(function() { throw "Helper 'closureFromTearOff' missing." })()''');
   }
 
   jsAst.Statement tearOffGetter;
   if (!compiler.useContentSecurityPolicy) {
-    // This template is uncached because it is constructed from code fragments
-    // that can change from compilation to compilation.  Some of these could be
-    // avoided, except for the string literals that contain the compiled access
-    // path to 'closureFromTearOff'.
-    tearOffGetter = js.uncachedStatementTemplate('''
+    jsAst.Expression tearOffAccessText =
+        new jsAst.UnparsedNode(tearOffAccessExpression, compiler, false);
+    tearOffGetter = js.statement('''
 function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
   return isIntercepted
       ? new Function("funcs", "reflectionInfo", "name",
-                     "$tearOffGlobalObjectName", "c",
+                     #tearOffGlobalObjectString, "c",
           "return function tearOff_" + name + (functionCounter++) + "(x) {" +
-            "if (c === null) c = $tearOffAccessText(" +
+            "if (c === null) c = " + #tearOffAccessText + "(" +
                 "this, funcs, reflectionInfo, false, [x], name);" +
                 "return new c(this, funcs[0], x, name);" +
-                "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null)
+                "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null)
       : new Function("funcs", "reflectionInfo", "name",
-                     "$tearOffGlobalObjectName", "c",
+                     #tearOffGlobalObjectString, "c",
           "return function tearOff_" + name + (functionCounter++)+ "() {" +
-            "if (c === null) c = $tearOffAccessText(" +
+            "if (c === null) c = " + #tearOffAccessText + "(" +
                 "this, funcs, reflectionInfo, false, [], name);" +
                 "return new c(this, funcs[0], null, name);" +
-                "}")(funcs, reflectionInfo, name, $tearOffGlobalObject, null);
-}''').instantiate([]);
+                "}")(funcs, reflectionInfo, name, #tearOffGlobalObject, null);
+}''', {'tearOffAccessText': tearOffAccessText,
+       'tearOffGlobalObject': tearOffGlobalObject,
+       'tearOffGlobalObjectString': tearOffGlobalObjectString});
   } else {
     tearOffGetter = js.statement('''
       function tearOffGetter(funcs, reflectionInfo, name, isIntercepted) {
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index 6f3f30e..b8fa032 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -4,7 +4,7 @@
 
 part of dart2js.js_emitter;
 
-const USE_NEW_EMITTER = const bool.fromEnvironment("dart2js.use.new.emitter");
+const USE_LAZY_EMITTER = const bool.fromEnvironment("dart2js.use.lazy.emitter");
 
 /**
  * Generates the code for all used classes in the program. Static fields (even
@@ -22,6 +22,7 @@
   Emitter emitter;
 
   final Set<ClassElement> neededClasses = new Set<ClassElement>();
+  Set<ClassElement> classesOnlyNeededForRti;
   final Map<OutputUnit, List<ClassElement>> outputClassLists =
       new Map<OutputUnit, List<ClassElement>>();
   final Map<OutputUnit, List<ConstantValue>> outputConstantLists =
@@ -54,8 +55,8 @@
         this.typeTestRegistry = new TypeTestRegistry(compiler) {
     nativeEmitter = new NativeEmitter(this);
     oldEmitter = new OldEmitter(compiler, namer, generateSourceMap, this);
-    emitter = USE_NEW_EMITTER
-        ? new new_js_emitter.Emitter(compiler, namer, nativeEmitter)
+    emitter = USE_LAZY_EMITTER
+        ? new lazy_js_emitter.Emitter(compiler, namer, nativeEmitter)
         : oldEmitter;
     metadataCollector = new MetadataCollector(compiler, emitter);
   }
@@ -211,7 +212,7 @@
         }
       }
       for (ClassElement cls in neededClasses) {
-        final onlyForRti = typeTestRegistry.rtiNeededClasses.contains(cls);
+        final onlyForRti = classesOnlyNeededForRti.contains(cls);
         if (!onlyForRti) {
           backend.retainMetadataOf(cls);
           oldEmitter.classEmitter.visitFields(cls, false,
@@ -253,7 +254,7 @@
   }
 
   /// Compute all the classes and typedefs that must be emitted.
-  void computeNeededDeclarations() {
+  void computeNeededDeclarations(Set<ClassElement> rtiNeededClasses) {
     // Compute needed typedefs.
     typedefsNeededForReflection = Elements.sortedByPosition(
         compiler.world.allTypedefs
@@ -297,13 +298,9 @@
     // these are thought to not have been instantiated, so we neeed to be able
     // to identify them later and make sure we only emit "empty shells" without
     // fields, etc.
-    typeTestRegistry.computeRtiNeededClasses();
+    classesOnlyNeededForRti = rtiNeededClasses.difference(neededClasses);
 
-    // TODO(floitsch): either change the name, or get the rti-classes
-    // differently.
-    typeTestRegistry.rtiNeededClasses.removeAll(neededClasses);
-    // rtiNeededClasses now contains only the "empty shells".
-    neededClasses.addAll(typeTestRegistry.rtiNeededClasses);
+    neededClasses.addAll(classesOnlyNeededForRti);
 
     // TODO(18175, floitsch): remove once issue 18175 is fixed.
     if (neededClasses.contains(backend.jsIntClass)) {
@@ -330,7 +327,7 @@
 
     for (ClassElement element in sortedClasses) {
       if (Elements.isNativeOrExtendsNative(element) &&
-          !typeTestRegistry.rtiNeededClasses.contains(element)) {
+          !classesOnlyNeededForRti.contains(element)) {
         // For now, native classes and related classes cannot be deferred.
         nativeClassesAndSubclasses.add(element);
         assert(invariant(element,
@@ -390,8 +387,10 @@
     // Compute the required type checks to know which classes need a
     // 'is$' method.
     typeTestRegistry.computeRequiredTypeChecks();
+    // Compute the classes needed by RTI.
+    Set<ClassElement> rtiClasses = typeTestRegistry.computeRtiNeededClasses();
 
-    computeNeededDeclarations();
+    computeNeededDeclarations(rtiClasses);
     computeNeededConstants();
     computeNeededStatics();
     computeNeededStaticNonFinalFields();
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/class_builder.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
similarity index 98%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
index 47bd9ff..3a7ab57 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/class_emitter.dart
@@ -275,8 +275,9 @@
   }
 
   void emitNativeInfo(Class cls, ClassBuilder builder) {
-    if (cls.nativeInfo != null) {
-      builder.addPropertyByName(namer.nativeSpecProperty, cls.nativeInfo);
+    jsAst.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls);
+    if (nativeInfo != null) {
+      builder.addPropertyByName(namer.nativeSpecProperty, nativeInfo);
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/code_emitter_helper.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/code_emitter_helper.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/code_emitter_helper.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/container_builder.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/container_builder.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/declarations.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/declarations.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/declarations.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
similarity index 97%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index 552fd27..ac0bd3a 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -38,11 +38,6 @@
   Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>();
 
   String classesCollector;
-  Set<ClassElement> get neededClasses => task.neededClasses;
-  Map<OutputUnit, List<ClassElement>> get outputClassLists
-      => task.outputClassLists;
-  Map<OutputUnit, List<ConstantValue>> get outputConstantLists
-      => task.outputConstantLists;
   final Map<jsAst.Name, String> mangledFieldNames =
       new HashMap<jsAst.Name, String>();
   final Map<jsAst.Name, String> mangledGlobalFieldNames =
@@ -204,7 +199,7 @@
 
   /// Contains the global state that is needed to initialize and load a
   /// deferred library.
-  jsAst.Name get globalsHolder => namer.internalGlobal("globalsHolder");
+  String get globalsHolder => r"$globals$";
 
   @override
   jsAst.Expression generateEmbeddedGlobalAccess(String global) {
@@ -328,10 +323,10 @@
       jsAst.Expression subclassReadGenerator(jsAst.Expression subclass),
       jsAst.Expression interceptorsByTagAccess,
       jsAst.Expression leafTagsAccess) {
-    return nativeEmitter.buildNativeInfoHandler(infoAccess, constructorAccess,
-                                                subclassReadGenerator,
-                                                interceptorsByTagAccess,
-                                                leafTagsAccess);
+    return NativeGenerator.buildNativeInfoHandler(infoAccess, constructorAccess,
+                                                  subclassReadGenerator,
+                                                  interceptorsByTagAccess,
+                                                  leafTagsAccess);
   }
 
   jsAst.ObjectInitializer generateInterceptedNamesSet() {
@@ -576,32 +571,26 @@
       List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields);
       return js.statement('''
       (function(lazies) {
-        if (#notInMinifiedMode) {
-          var descriptorLength = 4;
-        } else {
-          var descriptorLength = 3;
-        }
-
-        for (var i = 0; i < lazies.length; i += descriptorLength) {
-          var fieldName = lazies [i];
-          var getterName = lazies[i + 1];
-          var lazyValue = lazies[i + 2];
-          if (#notInMinifiedMode) {
-            var staticName = lazies[i + 3];
+        for (var i = 0; i < lazies.length; ) {
+          var fieldName = lazies[i++];
+          var getterName = lazies[i++];
+          if (#notMinified) {
+            var staticName = lazies[i++];
           }
+          var lazyValue = lazies[i++];
 
           // We build the lazy-check here:
           //   lazyInitializer(fieldName, getterName, lazyValue, staticName);
           // 'staticName' is used for error reporting in non-minified mode.
           // 'lazyValue' must be a closure that constructs the initial value.
-          if (#notInMinifiedMode) {
+          if (#notMinified) {
             #lazy(fieldName, getterName, lazyValue, staticName);
           } else {
             #lazy(fieldName, getterName, lazyValue);
           }
         }
       })(#laziesInfo)
-      ''', {'notInMinifiedMode': !compiler.enableMinification,
+      ''', {'notMinified': !compiler.enableMinification,
             'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
             'lazy': js(lazyInitializerName)});
     } else {
@@ -617,20 +606,17 @@
       // initialized field after all because of constant folding
       // before code generation.
       if (code == null) continue;
-      if (compiler.enableMinification) {
-        laziesInfo.addAll([js.quoteName(namer.globalPropertyName(element)),
-                           js.quoteName(namer.lazyInitializerName(element)),
-                           code]);
-      } else {
-        laziesInfo.addAll([js.quoteName(namer.globalPropertyName(element)),
-                           js.quoteName(namer.lazyInitializerName(element)),
-                           code,
-                           js.string(element.name)]);
+      laziesInfo.add(js.quoteName(namer.globalPropertyName(element)));
+      laziesInfo.add(js.quoteName(namer.lazyInitializerName(element)));
+      if (!compiler.enableMinification) {
+        laziesInfo.add(js.string(element.name));
       }
+      laziesInfo.add(code);
     }
     return laziesInfo;
   }
 
+  // TODO(sra): Remove this unused function.
   jsAst.Expression buildLazilyInitializedStaticField(
       VariableElement element, {String isolateProperties}) {
     jsAst.Expression code = backend.generatedCode[element];
@@ -742,12 +728,14 @@
   }
 
   jsAst.Statement buildFunctionThatReturnsNull() {
-    return js.statement('# = function() {}',
-                        [backend.rti.getFunctionThatReturnsNullName]);
+    return js.statement('#.# = function() {}',
+                        [namer.isolateName,
+                         backend.rti.getFunctionThatReturnsNullName]);
   }
 
   jsAst.Expression generateFunctionThatReturnsNull() {
-    return js("#", [backend.rti.getFunctionThatReturnsNullName]);
+    return js("#.#", [namer.isolateName,
+                      backend.rti.getFunctionThatReturnsNullName]);
   }
 
   buildMain(jsAst.Statement invokeMain) {
@@ -887,6 +875,8 @@
           if (#outputContainsConstantList) {
             Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty;
           }
+          Isolate.#functionThatReturnsNullProperty =
+              oldIsolate.#functionThatReturnsNullProperty;
           if (#hasIncrementalSupport) {
             Isolate.#lazyInitializerProperty =
                 oldIsolate.#lazyInitializerProperty;
@@ -904,6 +894,8 @@
             'isolatePropertiesName': namer.isolatePropertiesName,
             'outputContainsConstantList': task.outputContainsConstantList,
             'makeConstListProperty': makeConstListProperty,
+            'functionThatReturnsNullProperty':
+                backend.rti.getFunctionThatReturnsNullName,
             'hasIncrementalSupport': compiler.hasIncrementalSupport,
             'lazyInitializerProperty': lazyInitializerProperty,});
   }
@@ -1632,7 +1624,7 @@
 
       if (descriptors != null && descriptors.isNotEmpty) {
         Iterable<LibraryElement> libraries =
-        task.outputLibraryLists[outputUnit];
+            task.outputLibraryLists[outputUnit];
         if (libraries == null) libraries = [];
 
         // TODO(johnniwinther): Avoid creating [CodeBuffer]s.
@@ -1651,9 +1643,14 @@
 
   void finalizeTokensInAst(jsAst.Program main,
                            Iterable<jsAst.Program> deferredParts) {
-    task.metadataCollector.countTokensInAst(main);
-    deferredParts.forEach(task.metadataCollector.countTokensInAst);
+    jsAst.TokenCounter counter = new jsAst.TokenCounter();
+    counter.countTokens(main);
+    deferredParts.forEach(counter.countTokens);
     task.metadataCollector.finalizeTokens();
+    if (backend.namer is jsAst.TokenFinalizer) {
+      var finalizer = backend.namer;
+      finalizer.finalizeTokens();
+    }
   }
 
   int emitProgram(ProgramBuilder programBuilder) {
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/interceptor_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/interceptor_emitter.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/interceptor_emitter.dart
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
similarity index 97%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
index 134e6cf..5d7df35 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/nsm_emitter.dart
@@ -291,16 +291,17 @@
 ///
 /// See [buildTrivialNsmHandlers].
 class _DiffEncodedListOfNames extends jsAst.DeferredString
-                              implements AstContainer {
+                              implements jsAst.AstContainer {
   String _cachedValue;
-  jsAst.ArrayInitializer ast;
+  List<jsAst.ArrayInitializer> ast;
+
+  Iterable<jsAst.Node> get containedNodes => ast;
 
   _DiffEncodedListOfNames(Iterable<Iterable<jsAst.Name>> names) {
     // Store the names in ArrayInitializer nodes to make them discoverable
     // by traversals of the ast.
-    ast = new jsAst.ArrayInitializer(
-        names.map((Iterable i) => new jsAst.ArrayInitializer(i.toList()))
-             .toList());
+    ast = names.map((Iterable i) => new jsAst.ArrayInitializer(i.toList()))
+               .toList();
   }
 
   void _computeDiffEncodingForList(Iterable<jsAst.Name> names,
@@ -367,7 +368,7 @@
 
   String _computeDiffEncoding() {
     StringBuffer buffer = new StringBuffer();
-    for (jsAst.ArrayInitializer list in ast.elements) {
+    for (jsAst.ArrayInitializer list in ast) {
       if (buffer.isNotEmpty) {
         // Emit period that resets the diff base to zero when we switch to
         // normal calling convention (this avoids the need to code negative
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/old_emitter/setup_program_builder.dart
rename to pkg/compiler/lib/src/js_emitter/full_emitter/setup_program_builder.dart
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index 09d9d18..4049f43 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -34,8 +34,7 @@
 import '../hash/sha1.dart' show Hasher;
 
 import '../js/js.dart' as jsAst;
-import '../js/js.dart' show
-    js;
+import '../js/js.dart' show js;
 
 import 'package:js_ast/src/precedence.dart' as js_precedence;
 
@@ -56,9 +55,9 @@
     TypeVariableHandler;
 
 import 'model.dart';
-import 'program_builder.dart';
+import 'program_builder/program_builder.dart';
 
-import 'new_emitter/emitter.dart' as new_js_emitter;
+import 'lazy_emitter/emitter.dart' as lazy_js_emitter;
 
 import '../io/line_column_provider.dart' show
     LineColumnCollector,
@@ -109,12 +108,12 @@
 part 'runtime_type_generator.dart';
 part 'type_test_registry.dart';
 
-part 'old_emitter/class_builder.dart';
-part 'old_emitter/class_emitter.dart';
-part 'old_emitter/code_emitter_helper.dart';
-part 'old_emitter/container_builder.dart';
-part 'old_emitter/declarations.dart';
-part 'old_emitter/emitter.dart';
-part 'old_emitter/interceptor_emitter.dart';
-part 'old_emitter/nsm_emitter.dart';
-part 'old_emitter/setup_program_builder.dart';
+part 'full_emitter/class_builder.dart';
+part 'full_emitter/class_emitter.dart';
+part 'full_emitter/code_emitter_helper.dart';
+part 'full_emitter/container_builder.dart';
+part 'full_emitter/declarations.dart';
+part 'full_emitter/emitter.dart';
+part 'full_emitter/interceptor_emitter.dart';
+part 'full_emitter/nsm_emitter.dart';
+part 'full_emitter/setup_program_builder.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
similarity index 98%
rename from pkg/compiler/lib/src/js_emitter/new_emitter/emitter.dart
rename to pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
index b431c6d..0c3ae73 100644
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/emitter.dart
@@ -9,7 +9,7 @@
     METADATA,
     TYPES;
 
-import '../program_builder.dart' show ProgramBuilder;
+import '../program_builder/program_builder.dart' show ProgramBuilder;
 import '../model.dart';
 import 'model_emitter.dart';
 import '../../common.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
similarity index 95%
rename from pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
rename to pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index f34051c1..6a05e29 100644
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -33,47 +33,6 @@
 import '../js_emitter.dart' show NativeGenerator, buildTearOffCode;
 import '../model.dart';
 
-/// Represents the LiteralString resulting from unparsing [expression]. The
-/// actual unparsing is done on demand when requesting the [value] of this
-/// node.
-class _UnparsedNode extends js.DeferredString
-                    implements AstContainer {
-  @override
-  final js.Node ast;
-  final Compiler _compiler;
-  final bool _protectForEval;
-  js.LiteralString _cachedLiteral;
-
-  /// A [js.Literal] that represents the string result of unparsing [ast].
-  ///
-  /// When its string [value] is requested, the node pretty-prints the given
-  /// [ast] and, if [protectForEval] is true, wraps the resulting
-  /// string in parenthesis. The result is also escaped.
-  _UnparsedNode(this.ast, this._compiler, this._protectForEval);
-
-  js.LiteralString get _literal {
-    if (_cachedLiteral == null) {
-      String text = js.prettyPrint(ast, _compiler).getText();
-      if (_protectForEval) {
-        if (ast is js.Fun) text = '($text)';
-        if (ast is js.LiteralExpression) {
-          js.LiteralExpression literalExpression = ast;
-          String template = literalExpression.template;
-          if (template.startsWith("function ") ||
-              template.startsWith("{")) {
-            text = '($text)';
-          }
-        }
-      }
-      _cachedLiteral = js.js.escapedString(text);
-    }
-    return _cachedLiteral;
-  }
-
-  @override
-  String get value => _literal.value;
-}
-
 class ModelEmitter {
   final Compiler compiler;
   final Namer namer;
@@ -185,9 +144,11 @@
 
     js.Statement mainAst = emitMainFragment(program);
 
-    fragmentsCode.forEach(program.metadataFinalizer.countTokensInAst);
-    program.metadataFinalizer.countTokensInAst(mainAst);
-    program.metadataFinalizer.finalizeTokens();
+    js.TokenCounter counter = new js.TokenCounter();
+    fragmentsCode.forEach(counter.countTokens);
+    counter.countTokens(mainAst);
+
+    program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
 
     for (int i = 0; i < fragmentsCode.length; ++i) {
       String code = js.prettyPrint(fragmentsCode[i], compiler).getText();
@@ -217,7 +178,7 @@
   /// See [_UnparsedNode] for details.
   js.Literal unparse(Compiler compiler, js.Node value,
                      {bool protectForEval: true}) {
-    return new _UnparsedNode(value, compiler, protectForEval);
+    return new js.UnparsedNode(value, compiler, protectForEval);
   }
 
   String buildGeneratedBy(compiler) {
@@ -292,7 +253,7 @@
         generateEmbeddedGlobalAccess(INTERCEPTORS_BY_TAG);
     js.Expression leafTagsAccess =
         generateEmbeddedGlobalAccess(LEAF_TAGS);
-    js.Statement nativeInfoHandler = nativeEmitter.buildNativeInfoHandler(
+    js.Statement nativeInfoHandler = NativeGenerator.buildNativeInfoHandler(
         nativeInfoAccess,
         constructorAccess,
         subclassReadGenerator,
@@ -630,10 +591,11 @@
       js.Literal name = js.quoteName(cls.name);
       js.LiteralNumber holderIndex = js.number(cls.holder.index);
       js.Expression emittedClass = emitClass(cls);
-      if (cls.nativeInfo == null) {
+      js.Expression nativeInfo = NativeGenerator.encodeNativeInfo(cls);
+      if (nativeInfo == null) {
         return [name, emittedClass, holderIndex];
       } else {
-        return [name, emittedClass, cls.nativeInfo, holderIndex];
+        return [name, emittedClass, nativeInfo, holderIndex];
       }
     });
 
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 68ec03d..8ffda24 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -10,7 +10,7 @@
 /// ast for a program.
 /// [value] is the actual position, once they have been finalized.
 abstract class _MetadataEntry extends jsAst.DeferredNumber
-    implements Comparable {
+    implements Comparable, jsAst.ReferenceCountedAstNode {
   jsAst.Expression get entry;
   int get value;
   int get _rc;
@@ -18,7 +18,7 @@
   // Mark this entry as seen. On the first time this is seen, the visitor
   // will be applied to the [entry] to also mark potential [_MetadataEntry]
   // instances in the [entry] as seen.
-  markSeen(jsAst.BaseVisitor visitor);
+  markSeen(jsAst.TokenCounter visitor);
 }
 
 class _BoundMetadataEntry extends _MetadataEntry {
@@ -107,7 +107,7 @@
   int get precedenceLevel => js_precedence.PRIMARY;
 }
 
-class MetadataCollector implements TokenFinalizer {
+class MetadataCollector implements jsAst.TokenFinalizer {
   final Compiler _compiler;
   final Emitter _emitter;
 
@@ -232,7 +232,10 @@
   }
 
   _MetadataEntry _addGlobalMetadata(jsAst.Node node) {
-    String printed = jsAst.prettyPrint(node, _compiler).getText();
+    String nameToKey(jsAst.Name name) => "${name.key}";
+    String printed = jsAst.prettyPrint(node, _compiler,
+                                       renamerForNames: nameToKey)
+                          .getText();
     return _globalMetadataMap.putIfAbsent(printed, () {
       _BoundMetadataEntry result = new _BoundMetadataEntry(node);
       if (_compiler.hasIncrementalSupport) {
@@ -298,12 +301,6 @@
   }
 
   @override
-  void countTokensInAst(jsAst.Node ast) {
-    TokenCounter visitor = new TokenCounter();
-    visitor.countTokens(ast);
-  }
-
-  @override
   void finalizeTokens() {
     bool checkTokensInTypes(OutputUnit outputUnit, entries) {
       UnBoundDebugger debugger = new UnBoundDebugger(outputUnit);
@@ -316,7 +313,7 @@
       return true;
     }
     void countTokensInTypes(Iterable<_BoundMetadataEntry> entries) {
-      TokenCounter counter = new TokenCounter();
+      jsAst.TokenCounter counter = new jsAst.TokenCounter();
       entries.where((_BoundMetadataEntry e) => e._rc > 0)
              .map((_BoundMetadataEntry e) => e.entry)
              .forEach(counter.countTokens);
@@ -360,39 +357,6 @@
   }
 }
 
-/// Interface for ast nodes that encapsulate an ast that needs to be
-/// traversed when counting tokens.
-///
-/// TODO(herhut): Find a shared place once namer also uses tokens.
-abstract class AstContainer implements jsAst.Node {
-  jsAst.Node get ast;
-}
-
-abstract class TokenFinalizer {
-  void countTokensInAst(jsAst.Node ast);
-  void finalizeTokens();
-}
-
-class TokenCounter extends jsAst.BaseVisitor {
-  @override
-  visitNode(jsAst.Node node) {
-    if (node is AstContainer) {
-      node.ast.accept(this);
-    } else {
-      super.visitNode(node);
-    }
-  }
-
-  @override
-  visitDeferredNumber(jsAst.DeferredNumber token) {
-    if (token is _MetadataEntry) {
-      token.markSeen(this);
-    }
-  }
-
-  void countTokens(jsAst.Node node) => node.accept(this);
-}
-
 class UnBoundDebugger extends jsAst.BaseVisitor {
   OutputUnit outputUnit;
   bool _foundUnboundToken = false;
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 8dec194..6b06eec 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -4,7 +4,8 @@
 
 library dart2js.new_js_emitter.model;
 
-import '../js/js.dart' as js show Expression, Statement, Name, Literal;
+import '../js/js.dart' as js show Expression, Statement, Name, Literal,
+    TokenFinalizer;
 import '../constants/values.dart' show ConstantValue;
 
 import '../deferred_load.dart' show OutputUnit;
@@ -29,13 +30,14 @@
   // TODO(floitsch): we should store the metadata directly instead of storing
   // the collector. However, the old emitter still updates the data.
   final MetadataCollector _metadataCollector;
-  TokenFinalizer get metadataFinalizer => _metadataCollector;
+  final Iterable<js.TokenFinalizer> finalizers;
 
   Program(this.fragments,
           this.holders,
           this.loadMap,
           this.typeToInterceptorMap,
           this._metadataCollector,
+          this.finalizers,
           {this.needsNativeSupport,
            this.outputContainsConstantList,
            this.hasIsolateSupport}) {
@@ -241,8 +243,14 @@
   /// Whether the class must be evaluated eagerly.
   bool isEager = false;
 
-  /// Data that must be emitted with the class for native interop.
-  js.Literal nativeInfo;
+  /// Leaf tags. See [NativeEmitter.prepareNativeClasses].
+  List<String> nativeLeafTags;
+
+  /// Non-leaf tags. See [NativeEmitter.prepareNativeClasses].
+  List<String> nativeNonLeafTags;
+
+  /// Native extensions. See [NativeEmitter.prepareNativeClasses].
+  List<Class> nativeExtensions;
 
   Class(this.element, this.name, this.holder,
         this.methods,
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 3e7b649..56bb8de 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -30,6 +30,7 @@
         cachedBuilders = emitterTask.compiler.cacheStrategy.newMap();
 
   Compiler get compiler => emitterTask.compiler;
+
   JavaScriptBackend get backend => compiler.backend;
 
   jsAst.Expression get defPropFunction {
@@ -43,8 +44,9 @@
    * Removes trivial classes (that can be represented by a super type) and
    * generates properties that have to be added to classes (native or not).
    *
-   * Updates the `nativeInfo` field of the given classes. This data
-   * must be emitted with the corresponding classes.
+   * Updates the `nativeLeafTags`, `nativeNonLeafTags` and `nativeExtensions`
+   * fields of the given classes. This data must be emitted with the
+   * corresponding classes.
    *
    * The interceptors are filtered to avoid emitting trivial interceptors.  For
    * example, if the program contains no code that can distinguish between the
@@ -73,6 +75,7 @@
 
     Class objectClass = null;
     Class jsInterceptorClass = null;
+
     void walk(Class cls) {
       if (cls.element == compiler.objectClass) {
         objectClass = cls;
@@ -94,7 +97,7 @@
     // needed class.
 
     Set<Class> neededClasses = new Set<Class>();
-    Set<Class> nonleafClasses = new Set<Class>();
+    Set<Class> nonLeafClasses = new Set<Class>();
 
     Map<Class, List<Class>> extensionPoints = computeExtensionPoints(preOrder);
 
@@ -130,13 +133,13 @@
       if (cls.isNative &&
           native.nativeTagsForcedNonLeaf(classElement)) {
         needed = true;
-        nonleafClasses.add(cls);
+        nonLeafClasses.add(cls);
       }
 
       if (needed || neededClasses.contains(cls)) {
         neededClasses.add(cls);
         neededClasses.add(cls.superclass);
-        nonleafClasses.add(cls.superclass);
+        nonLeafClasses.add(cls.superclass);
       }
     }
 
@@ -149,7 +152,7 @@
       if (!cls.isNative) continue;
       List<String> nativeTags = native.nativeTagsOfClass(cls.element);
 
-      if (nonleafClasses.contains(cls) ||
+      if (nonLeafClasses.contains(cls) ||
           extensionPoints.containsKey(cls)) {
         nonleafTags
             .putIfAbsent(cls, () => new Set<String>())
@@ -168,51 +171,26 @@
       }
     }
 
+    void fillNativeInfo(Class cls) {
+      assert(cls.nativeLeafTags == null &&
+          cls.nativeNonLeafTags == null &&
+          cls.nativeExtensions == null);
+      if (leafTags[cls] != null) {
+        cls.nativeLeafTags = leafTags[cls].toList(growable: false);
+      }
+      if (nonleafTags[cls] != null) {
+        cls.nativeNonLeafTags = nonleafTags[cls].toList(growable: false);
+      }
+      cls.nativeExtensions = extensionPoints[cls];
+    }
     // Add properties containing the information needed to construct maps used
     // by getNativeInterceptor and custom elements.
     if (compiler.enqueuer.codegen.nativeEnqueuer
         .hasInstantiatedNativeClasses()) {
-      void generateClassInfo(Class cls) {
-        // Property has the form:
-        //
-        //    "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...",
-        //
-        // If there is no data following a semicolon, the semicolon can be
-        // omitted.
-
-        String formatTags(Iterable<String> tags) {
-          if (tags == null) return '';
-          return (tags.toList()..sort()).join('|');
-        }
-
-        List<Class> extensions = extensionPoints[cls];
-
-        String leafStr = formatTags(leafTags[cls]);
-        String nonleafStr = formatTags(nonleafTags[cls]);
-
-        StringBuffer sb = new StringBuffer(leafStr);
-        if (nonleafStr != '') {
-          sb..write(';')..write(nonleafStr);
-        }
-
-        String encoding = sb.toString();
-
-        if (cls.isNative || encoding != '' || extensions != null) {
-          List<jsAst.Literal> parts = <jsAst.Literal>[js.stringPart(encoding)];
-          if (extensions != null) {
-            parts..add(js.stringPart(';'))
-                 ..addAll(
-                     js.joinLiterals(extensions.map((Class cls) => cls.name),
-                                     js.stringPart('|')));
-          }
-          assert(cls.nativeInfo == null);
-          cls.nativeInfo = js.concatenateStrings(parts, addQuotes: true);
-        }
-      }
-      generateClassInfo(jsInterceptorClass);
+      fillNativeInfo(jsInterceptorClass);
       for (Class cls in classes) {
         if (!cls.isNative || neededClasses.contains(cls)) {
-          generateClassInfo(cls);
+          fillNativeInfo(cls);
         }
       }
     }
@@ -367,96 +345,4 @@
     if (Elements.isNativeOrExtendsNative(cls)) return true;
     return isSupertypeOfNativeClass(element);
   }
-
-  /// Returns a JavaScript template that fills the embedded globals referenced
-  /// by [interceptorsByTagAccess] and [leafTagsAccess].
-  ///
-  /// This code must be invoked for every class that has a native info before
-  /// the program starts.
-  ///
-  /// The [infoAccess] parameter must evaluate to an expression that contains
-  /// the info (as a JavaScript string).
-  ///
-  /// The [constructorAccess] parameter must evaluate to an expression that
-  /// contains the constructor of the class. The constructor's prototype must
-  /// be set up.
-  ///
-  /// The [subclassReadGenerator] function must evaluate to a JS expression
-  /// that returns a reference to the constructor (with evaluated prototype)
-  /// of the given JS expression.
-  ///
-  /// The [interceptorsByTagAccess] must point to the embedded global
-  /// [embeddedNames.INTERCEPTORS_BY_TAG] and must be initialized with an empty
-  /// JS Object (used as a map).
-  ///
-  /// Similarly, the [leafTagsAccess] must point to the embedded global
-  /// [embeddedNames.LEAF_TAGS] and must be initialized with an empty JS Object
-  /// (used as a map).
-  ///
-  /// Both variables are passed in (instead of creating the access here) to
-  /// make sure the caller is aware of these globals.
-  jsAst.Statement buildNativeInfoHandler(
-      jsAst.Expression infoAccess,
-      jsAst.Expression constructorAccess,
-      jsAst.Expression subclassReadGenerator(jsAst.Expression subclass),
-      jsAst.Expression interceptorsByTagAccess,
-      jsAst.Expression leafTagsAccess) {
-    jsAst.Expression subclassRead =
-        subclassReadGenerator(js('subclasses[i]', []));
-    return js.statement('''
-          // The native info looks like this:
-          //
-          // HtmlElement: {
-          //     "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton"
-          //
-          // The first two semicolon-separated parts contain dispatch tags, the
-          // third contains the JavaScript names for classes.
-          //
-          // The tags indicate that JavaScript objects with the dispatch tags
-          // (usually constructor names) HTMLDivElement, HTMLAnchorElement and
-          // HTMLElement all map to the Dart native class named HtmlElement.
-          // The first set is for effective leaf nodes in the hierarchy, the
-          // second set is non-leaf nodes.
-          //
-          // The third part contains the JavaScript names of Dart classes that
-          // extend the native class. Here, FancyButton extends HtmlElement, so
-          // the runtime needs to know that window.HTMLElement.prototype is the
-          // prototype that needs to be extended in creating the custom element.
-          //
-          // The information is used to build tables referenced by
-          // getNativeInterceptor and custom element support.
-          {
-            var nativeSpec = #info.split(";");
-            if (nativeSpec[0]) {
-              var tags = nativeSpec[0].split("|");
-              for (var i = 0; i < tags.length; i++) {
-                #interceptorsByTagAccess[tags[i]] = #constructor;
-                #leafTagsAccess[tags[i]] = true;
-              }
-            }
-            if (nativeSpec[1]) {
-              tags = nativeSpec[1].split("|");
-              if (#allowNativesSubclassing) {
-                if (nativeSpec[2]) {
-                  var subclasses = nativeSpec[2].split("|");
-                  for (var i = 0; i < subclasses.length; i++) {
-                    var subclass = #subclassRead;
-                    subclass.#nativeSuperclassTagName = tags[0];
-                  }
-                }
-                for (i = 0; i < tags.length; i++) {
-                  #interceptorsByTagAccess[tags[i]] = #constructor;
-                  #leafTagsAccess[tags[i]] = false;
-                }
-              }
-            }
-          }
-    ''', {'info': infoAccess,
-          'constructor': constructorAccess,
-          'subclassRead': subclassRead,
-          'interceptorsByTagAccess': interceptorsByTagAccess,
-          'leafTagsAccess': leafTagsAccess,
-          'nativeSuperclassTagName': embeddedNames.NATIVE_SUPERCLASS_TAG_NAME,
-          'allowNativesSubclassing': true});
-  }
-}
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/js_emitter/native_generator.dart b/pkg/compiler/lib/src/js_emitter/native_generator.dart
index 60f6c3d..9a4145c 100644
--- a/pkg/compiler/lib/src/js_emitter/native_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_generator.dart
@@ -73,4 +73,141 @@
     // TODO(sra): MD5 of contributing source code or URIs?
     return 'ZxYxX';
   }
+
+  /// Encodes the collected native information so that it can be treated by
+  /// the native info-handler below.
+  ///
+  /// The encoded information has the form:
+  ///
+  //    "%": "leafTag1|leafTag2|...;nonleafTag1|...;Class1|Class2|...",
+  //
+  // If there is no data following a semicolon, the semicolon can be omitted.
+  static jsAst.Expression encodeNativeInfo(Class cls) {
+    List<String> leafTags = cls.nativeLeafTags;
+    List<String> nonLeafTags = cls.nativeNonLeafTags;
+    List<Class> extensions = cls.nativeExtensions;
+
+    String formatTags(Iterable<String> tags) {
+      if (tags == null) return '';
+      return (tags.toList()
+        ..sort()).join('|');
+    }
+
+    String leafStr = formatTags(leafTags);
+    String nonLeafStr = formatTags(nonLeafTags);
+
+    StringBuffer sb = new StringBuffer(leafStr);
+    if (nonLeafStr != '') {
+      sb
+        ..write(';')
+        ..write(nonLeafStr);
+    }
+
+    String encoding = sb.toString();
+
+    if (cls.isNative || encoding != '' || extensions != null) {
+      List<jsAst.Literal> parts = <jsAst.Literal>[js.stringPart(encoding)];
+      if (extensions != null) {
+        parts
+          ..add(js.stringPart(';'))
+          ..addAll(
+            js.joinLiterals(extensions.map((Class cls) => cls.name),
+            js.stringPart('|')));
+      }
+      return jsAst.concatenateStrings(parts, addQuotes: true);
+    }
+    return null;
+  }
+
+  /// Returns a JavaScript template that fills the embedded globals referenced
+  /// by [interceptorsByTagAccess] and [leafTagsAccess].
+  ///
+  /// This code must be invoked for every class that has a native info before
+  /// the program starts.
+  ///
+  /// The [infoAccess] parameter must evaluate to an expression that contains
+  /// the info (as a JavaScript string).
+  ///
+  /// The [constructorAccess] parameter must evaluate to an expression that
+  /// contains the constructor of the class. The constructor's prototype must
+  /// be set up.
+  ///
+  /// The [subclassReadGenerator] function must evaluate to a JS expression
+  /// that returns a reference to the constructor (with evaluated prototype)
+  /// of the given JS expression.
+  ///
+  /// The [interceptorsByTagAccess] must point to the embedded global
+  /// [embeddedNames.INTERCEPTORS_BY_TAG] and must be initialized with an empty
+  /// JS Object (used as a map).
+  ///
+  /// Similarly, the [leafTagsAccess] must point to the embedded global
+  /// [embeddedNames.LEAF_TAGS] and must be initialized with an empty JS Object
+  /// (used as a map).
+  ///
+  /// Both variables are passed in (instead of creating the access here) to
+  /// make sure the caller is aware of these globals.
+  static jsAst.Statement buildNativeInfoHandler(
+      jsAst.Expression infoAccess,
+      jsAst.Expression constructorAccess,
+      jsAst.Expression subclassReadGenerator(jsAst.Expression subclass),
+      jsAst.Expression interceptorsByTagAccess,
+      jsAst.Expression leafTagsAccess) {
+    jsAst.Expression subclassRead =
+        subclassReadGenerator(js('subclasses[i]', []));
+    return js.statement('''
+          // The native info looks like this:
+          //
+          // HtmlElement: {
+          //     "%": "HTMLDivElement|HTMLAnchorElement;HTMLElement;FancyButton"
+          //
+          // The first two semicolon-separated parts contain dispatch tags, the
+          // third contains the JavaScript names for classes.
+          //
+          // The tags indicate that JavaScript objects with the dispatch tags
+          // (usually constructor names) HTMLDivElement, HTMLAnchorElement and
+          // HTMLElement all map to the Dart native class named HtmlElement.
+          // The first set is for effective leaf nodes in the hierarchy, the
+          // second set is non-leaf nodes.
+          //
+          // The third part contains the JavaScript names of Dart classes that
+          // extend the native class. Here, FancyButton extends HtmlElement, so
+          // the runtime needs to know that window.HTMLElement.prototype is the
+          // prototype that needs to be extended in creating the custom element.
+          //
+          // The information is used to build tables referenced by
+          // getNativeInterceptor and custom element support.
+          {
+            var nativeSpec = #info.split(";");
+            if (nativeSpec[0]) {
+              var tags = nativeSpec[0].split("|");
+              for (var i = 0; i < tags.length; i++) {
+                #interceptorsByTagAccess[tags[i]] = #constructor;
+                #leafTagsAccess[tags[i]] = true;
+              }
+            }
+            if (nativeSpec[1]) {
+              tags = nativeSpec[1].split("|");
+              if (#allowNativesSubclassing) {
+                if (nativeSpec[2]) {
+                  var subclasses = nativeSpec[2].split("|");
+                  for (var i = 0; i < subclasses.length; i++) {
+                    var subclass = #subclassRead;
+                    subclass.#nativeSuperclassTagName = tags[0];
+                  }
+                }
+                for (i = 0; i < tags.length; i++) {
+                  #interceptorsByTagAccess[tags[i]] = #constructor;
+                  #leafTagsAccess[tags[i]] = false;
+                }
+              }
+            }
+          }
+    ''', {'info': infoAccess,
+          'constructor': constructorAccess,
+          'subclassRead': subclassRead,
+          'interceptorsByTagAccess': interceptorsByTagAccess,
+          'leafTagsAccess': leafTagsAccess,
+          'nativeSuperclassTagName': embeddedNames.NATIVE_SUPERCLASS_TAG_NAME,
+          'allowNativesSubclassing': true});
+  }
 }
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
similarity index 96%
rename from pkg/compiler/lib/src/js_emitter/program_builder.dart
rename to pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 834fe03..b4a9c37 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -4,18 +4,18 @@
 
 library dart2js.js_emitter.program_builder;
 
-import 'js_emitter.dart' show computeMixinClass;
-import 'model.dart';
+import '../js_emitter.dart' show computeMixinClass;
+import '../model.dart';
 
-import '../common.dart';
-import '../js/js.dart' as js;
+import '../../common.dart';
+import '../../js/js.dart' as js;
 
-import '../js_backend/js_backend.dart' show
+import '../../js_backend/js_backend.dart' show
     Namer,
     JavaScriptBackend,
     JavaScriptConstantCompiler;
 
-import 'js_emitter.dart' show
+import '../js_emitter.dart' show
     ClassStubGenerator,
     CodeEmitterTask,
     InterceptorStubGenerator,
@@ -24,13 +24,15 @@
     RuntimeTypeGenerator,
     TypeTestProperties;
 
-import '../elements/elements.dart' show ParameterElement, MethodElement;
+import '../../elements/elements.dart' show ParameterElement, MethodElement;
 
-import '../universe/universe.dart' show Universe, TypeMaskSet;
-import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
+import '../../universe/universe.dart' show Universe, TypeMaskSet;
+import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit;
 
 part 'registry.dart';
 
+/// Builds a self-contained representation of the program that can then be
+/// emitted more easily by the individual emitters.
 class ProgramBuilder {
   final Compiler _compiler;
   final Namer namer;
@@ -123,12 +125,19 @@
 
     assert(!needsNativeSupport || nativeClasses.isNotEmpty);
 
+    List<js.TokenFinalizer> finalizers = [_task.metadataCollector];
+    if (backend.namer is js.TokenFinalizer) {
+      var namingFinalizer = backend.namer;
+      finalizers.add(namingFinalizer);
+    }
+
     return new Program(
         fragments,
         holders,
         _buildLoadMap(),
         _buildTypeToInterceptorMap(),
         _task.metadataCollector,
+        finalizers,
         needsNativeSupport: needsNativeSupport,
         outputContainsConstantList: _task.outputContainsConstantList,
         hasIsolateSupport: _compiler.hasIsolateSupport);
@@ -316,7 +325,7 @@
   }
 
   Class _buildClass(ClassElement element) {
-    bool onlyForRti = _task.typeTestRegistry.rtiNeededClasses.contains(element);
+    bool onlyForRti = _task.classesOnlyNeededForRti.contains(element);
 
     List<Method> methods = [];
     List<StubMethod> callStubs = <StubMethod>[];
diff --git a/pkg/compiler/lib/src/js_emitter/registry.dart b/pkg/compiler/lib/src/js_emitter/program_builder/registry.dart
similarity index 100%
rename from pkg/compiler/lib/src/js_emitter/registry.dart
rename to pkg/compiler/lib/src/js_emitter/program_builder/registry.dart
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index 227030a..3e6acb5 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -483,7 +483,7 @@
           then((Script sourceScript) {
             if (sourceScript == null) return;
 
-            CompilationUnitElement unit =
+            CompilationUnitElementX unit =
                 new CompilationUnitElementX(sourceScript, library);
             compiler.withCurrentElement(unit, () {
               compiler.scanner.scan(unit);
@@ -524,6 +524,23 @@
         });
   }
 
+  /// Loads the deserialized [library] with the [handler].
+  ///
+  /// All libraries imported or exported transitively from [library] will be
+  /// loaded as well.
+  Future<LibraryElement> loadDeserializedLibrary(
+      LibraryDependencyHandler handler,
+      LibraryElement library) async {
+    compiler.onLibraryCreated(library);
+    libraryCanonicalUriMap[library.canonicalUri] = library;
+    await compiler.onLibraryScanned(library, handler);
+    for (LibraryTag tag in library.tags) {
+      LibraryElement dependency = library.getLibraryFromTag(tag);
+      await createLibrary(handler, library, dependency.canonicalUri);
+    }
+    return library;
+  }
+
   /**
    * Create (or reuse) a library element for the library specified by the
    * [resolvedUri].
@@ -540,6 +557,10 @@
     if (library != null) {
       return new Future.value(library);
     }
+    library = compiler.serialization.readLibrary(resolvedUri);
+    if (library != null) {
+      return loadDeserializedLibrary(handler, library);
+    }
     var readScript = compiler.readScript;
     if (readableUri == null) {
       readableUri = resolvedUri;
diff --git a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
index fd2504a..38925b5 100644
--- a/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
+++ b/pkg/compiler/lib/src/mirrors/dart2js_library_mirror.dart
@@ -33,15 +33,7 @@
    * file name (for scripts without a library tag). The latter case is used to
    * provide a 'library name' for scripts, to use for instance in dartdoc.
    */
-  String get _simpleNameString {
-    if (_element.libraryTag != null) {
-      return _element.libraryTag.name.toString();
-    } else {
-      // Use the file name as script name.
-      String path = _element.canonicalUri.path;
-      return path.substring(path.lastIndexOf('/') + 1);
-    }
-  }
+  String get _simpleNameString => _element.getLibraryOrScriptName();
 
   Symbol get qualifiedName => simpleName;
 
diff --git a/pkg/compiler/lib/src/native/ssa.dart b/pkg/compiler/lib/src/native/ssa.dart
index 09f4e03..e622559 100644
--- a/pkg/compiler/lib/src/native/ssa.dart
+++ b/pkg/compiler/lib/src/native/ssa.dart
@@ -92,7 +92,10 @@
             js.js.uncachedExpressionTemplate(nativeMethodCall),
             backend.dynamicType,
             inputs, effects: new SideEffects()));
-    builder.close(new HReturn(builder.pop())).addSuccessor(builder.graph.exit);
+    // TODO(johnniwinther): Provide source information.
+    builder
+        .close(new HReturn(builder.pop(), null))
+        .addSuccessor(builder.graph.exit);
   } else {
     if (parameters.parameterCount != 0) {
       compiler.internalError(nativeBody,
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 1ec9ff3..c3bb16d7 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -32,7 +32,7 @@
   final Link<DartType> types;
   final Link<DartType> _supertypes;
 
-  OrderedTypeSet._internal(List<Link<DartType>> this._levels,
+  OrderedTypeSet.internal(List<Link<DartType>> this._levels,
                            Link<DartType> this.types,
                            Link<DartType> this._supertypes);
 
@@ -41,7 +41,7 @@
         new LinkEntry<DartType>(type, const Link<DartType>());
     List<Link<DartType>> list = new List<Link<DartType>>(1);
     list[0] = types;
-    return new OrderedTypeSet._internal(list, types, const Link<DartType>());
+    return new OrderedTypeSet.internal(list, types, const Link<DartType>());
   }
 
   /// Creates a new [OrderedTypeSet] for [type] when it directly extends the
@@ -58,7 +58,7 @@
       list[i] = _levels[i];
     }
     list[levels] = extendedTypes;
-    return new OrderedTypeSet._internal(
+    return new OrderedTypeSet.internal(
         list, extendedTypes, _supertypes.prepend(types.head));
   }
 
@@ -75,6 +75,21 @@
     return const Link<DartType>();
   }
 
+  /// Returns the offsets into [types] at which each level begins.
+  List<int> get levelOffsets {
+    List<int> offsets = new List.filled(levels, -1);
+    int offset = 0;
+    Link<DartType> pointer = types;
+    for (int depth = maxDepth; depth >= 0; depth--) {
+      while (!identical(pointer, _levels[depth])) {
+        pointer = pointer.tail;
+        offset++;
+      }
+      offsets[depth] = offset;
+    }
+    return offsets;
+  }
+
   void forEach(int level, void f(DartType type)) {
     if (level < levels) {
       Link<DartType> pointer = _levels[level];
@@ -180,7 +195,7 @@
   OrderedTypeSet toTypeSet() {
     List<Link<DartType>> levels = new List<Link<DartType>>(maxDepth + 1);
     if (maxDepth < 0) {
-      return new OrderedTypeSet._internal(
+      return new OrderedTypeSet.internal(
           levels, const Link<DartType>(), const Link<DartType>());
     }
     Link<DartType> next = const Link<DartType>();
@@ -198,7 +213,7 @@
         next = first;
       }
     }
-    return new OrderedTypeSet._internal(
+    return new OrderedTypeSet.internal(
         levels, levels.last, allSupertypes.toLink());
   }
 
diff --git a/pkg/compiler/lib/src/patch_parser.dart b/pkg/compiler/lib/src/patch_parser.dart
index b0bde83..297897b 100644
--- a/pkg/compiler/lib/src/patch_parser.dart
+++ b/pkg/compiler/lib/src/patch_parser.dart
@@ -436,10 +436,10 @@
     if (annotation.beginToken != null) {
       if (annotation.beginToken.next.value == 'patch') {
         return const PatchVersion(null);
-      } else if (annotation.beginToken.next.value == 'patch_old') {
-        return const PatchVersion('old');
-      } else if (annotation.beginToken.next.value == 'patch_new') {
-        return const PatchVersion('new');
+      } else if (annotation.beginToken.next.value == 'patch_full') {
+        return const PatchVersion('full');
+      } else if (annotation.beginToken.next.value == 'patch_lazy') {
+        return const PatchVersion('lazy');
       }
     }
     return null;
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 13a6855..712e78e 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -270,21 +270,22 @@
         new Modifiers.withFlags(new NodeList.empty(), Modifiers.FLAG_ABSTRACT));
     // Create synthetic type variables for the mixin application.
     List<DartType> typeVariables = <DartType>[];
-    element.typeVariables.forEach((TypeVariableType type) {
+    int index = 0;
+    for (TypeVariableType type in element.typeVariables) {
       TypeVariableElementX typeVariableElement = new TypeVariableElementX(
-          type.name, mixinApplication, type.element.node);
+          type.name, mixinApplication, index, type.element.node);
       TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
       typeVariables.add(typeVariable);
-    });
+      index++;
+    }
     // Setup bounds on the synthetic type variables.
-    int index = 0;
-    element.typeVariables.forEach((TypeVariableType type) {
-      TypeVariableType typeVariable = typeVariables[index++];
+    for (TypeVariableType type in element.typeVariables) {
+      TypeVariableType typeVariable = typeVariables[type.element.index];
       TypeVariableElementX typeVariableElement = typeVariable.element;
       typeVariableElement.typeCache = typeVariable;
       typeVariableElement.boundCache =
           type.element.bound.subst(typeVariables, element.typeVariables);
-    });
+    }
     // Setup this and raw type for the mixin application.
     mixinApplication.computeThisAndRawType(compiler, typeVariables);
     // Substitute in synthetic type variables in super and mixin types.
@@ -309,8 +310,11 @@
 
   FunctionElement createForwardingConstructor(ConstructorElement target,
                                               ClassElement enclosing) {
-    return new SynthesizedConstructorElementX.notForDefault(
-        target.name, target, enclosing);
+    FunctionElement constructor =
+        new SynthesizedConstructorElementX.notForDefault(
+            target.name, target, enclosing);
+    constructor.computeType(compiler);
+    return constructor;
   }
 
   void doApplyMixinTo(MixinApplicationElementX mixinApplication,
@@ -566,8 +570,10 @@
       super(compiler);
 
   void loadSupertype(ClassElement element, Node from) {
-    compiler.resolver.loadSupertypes(element, from);
-    element.ensureResolved(compiler);
+    if (!element.isResolved) {
+      compiler.resolver.loadSupertypes(element, from);
+      element.ensureResolved(compiler);
+    }
   }
 
   void visitNodeList(NodeList node) {
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index bcf6113..f3f6be9 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -221,7 +221,7 @@
           diagnosticNode, kind, {'constructorName': fullConstructorName});
       isValidAsConstant = false;
     } else {
-      lookedupConstructor.computeSignature(visitor.compiler);
+      lookedupConstructor.computeType(visitor.compiler);
       if (!call.signatureApplies(lookedupConstructor.functionSignature)) {
         MessageKind kind = isImplicitSuperCall
                            ? MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT
diff --git a/pkg/compiler/lib/src/resolution/enum_creator.dart b/pkg/compiler/lib/src/resolution/enum_creator.dart
index d68e961..7a25972 100644
--- a/pkg/compiler/lib/src/resolution/enum_creator.dart
+++ b/pkg/compiler/lib/src/resolution/enum_creator.dart
@@ -14,11 +14,9 @@
 
 // TODO(johnniwinther): Merge functionality with the `TreePrinter`.
 class AstBuilder {
-  final Token position;
+  final int charOffset;
 
-  AstBuilder(this.position);
-
-  int get charOffset => position.charOffset;
+  AstBuilder(this.charOffset);
 
   Modifiers modifiers({bool isConst: false,
                        bool isFinal: false,
@@ -43,7 +41,7 @@
   }
 
   Token keywordToken(String text) {
-    return new KeywordToken(Keyword.keywords[text], position.charOffset);
+    return new KeywordToken(Keyword.keywords[text], charOffset);
   }
 
   Token stringToken(String text) {
@@ -183,7 +181,7 @@
   void createMembers() {
     Enum node = enumClass.node;
     InterfaceType enumType = enumClass.thisType;
-    AstBuilder builder = new AstBuilder(enumClass.position);
+    AstBuilder builder = new AstBuilder(enumClass.position.charOffset);
 
     InterfaceType intType = compiler.intClass.computeType(compiler);
     InterfaceType stringType = compiler.stringClass.computeType(compiler);
@@ -239,7 +237,7 @@
          !link.isEmpty;
          link = link.tail) {
       Identifier name = link.head;
-      AstBuilder valueBuilder = new AstBuilder(name.token);
+      AstBuilder valueBuilder = new AstBuilder(name.token.charOffset);
 
       // Add reference for the `values` field.
       valueReferences.add(valueBuilder.reference(name));
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 7c1bdf9..9719345 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -2068,8 +2068,8 @@
       switch (semantics.kind) {
         case AccessKind.STATIC_METHOD:
         case AccessKind.TOPLEVEL_METHOD:
-          MethodElementX method = semantics.element;
-          method.computeSignature(compiler);
+          MethodElement method = semantics.element;
+          method.computeType(compiler);
           if (!callStructure.signatureApplies(method.functionSignature)) {
             registry.registerThrowNoSuchMethod();
             registry.registerDynamicInvocation(
diff --git a/pkg/compiler/lib/src/resolution/operators.dart b/pkg/compiler/lib/src/resolution/operators.dart
index 4b9ec51..ac202aa 100644
--- a/pkg/compiler/lib/src/resolution/operators.dart
+++ b/pkg/compiler/lib/src/resolution/operators.dart
@@ -49,6 +49,14 @@
       default: return null;
     }
   }
+
+  static UnaryOperator fromKind(UnaryOperatorKind kind) {
+    switch (kind) {
+      case UnaryOperatorKind.NOT: return NOT;
+      case UnaryOperatorKind.NEGATE: return NEGATE;
+      case UnaryOperatorKind.COMPLEMENT: return COMPLEMENT;
+    }
+  }
 }
 
 enum BinaryOperatorKind {
@@ -198,6 +206,32 @@
       default: return null;
     }
   }
+
+  static BinaryOperator fromKind(BinaryOperatorKind kind) {
+    switch (kind) {
+      case BinaryOperatorKind.EQ: return EQ;
+      case BinaryOperatorKind.NOT_EQ: return NOT_EQ;
+      case BinaryOperatorKind.INDEX: return INDEX;
+      case BinaryOperatorKind.MUL: return MUL;
+      case BinaryOperatorKind.DIV: return DIV;
+      case BinaryOperatorKind.MOD: return MOD;
+      case BinaryOperatorKind.IDIV: return IDIV;
+      case BinaryOperatorKind.ADD: return ADD;
+      case BinaryOperatorKind.SUB: return SUB;
+      case BinaryOperatorKind.SHL: return SHL;
+      case BinaryOperatorKind.SHR: return SHR;
+      case BinaryOperatorKind.GTEQ: return GTEQ;
+      case BinaryOperatorKind.GT: return GT;
+      case BinaryOperatorKind.LTEQ: return LTEQ;
+      case BinaryOperatorKind.LT: return LT;
+      case BinaryOperatorKind.AND: return AND;
+      case BinaryOperatorKind.XOR: return XOR;
+      case BinaryOperatorKind.OR: return OR;
+      case BinaryOperatorKind.LOGICAL_AND: return LOGICAL_AND;
+      case BinaryOperatorKind.LOGICAL_OR: return LOGICAL_OR;
+      case BinaryOperatorKind.IF_NULL: return IF_NULL;
+    }
+  }
 }
 
 /// The operator !=, which is not user definable operator but instead is a
diff --git a/pkg/compiler/lib/src/serialization/constant_serialization.dart b/pkg/compiler/lib/src/serialization/constant_serialization.dart
new file mode 100644
index 0000000..94dc24f
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/constant_serialization.dart
@@ -0,0 +1,430 @@
+// 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.serialization.constants;
+
+import '../constants/expressions.dart';
+import '../dart_types.dart';
+import '../elements/elements.dart' show FieldElement;
+import '../resolution/operators.dart';
+import '../universe/universe.dart';
+import 'serialization.dart';
+import 'keys.dart';
+
+/// Visitor that serializes a [ConstantExpression] by encoding it into an
+/// [ObjectEncoder].
+///
+/// This class is called from the [Serializer] when a [ConstantExpression] needs
+/// serialization. The [ObjectEncoder] ensures that any [Element], [DartType],
+/// and other [ConstantExpression] that the serialized [ConstantExpression]
+/// depends upon are also serialized.
+class ConstantSerializer
+    extends ConstantExpressionVisitor<dynamic, ObjectEncoder> {
+  const ConstantSerializer();
+
+  @override
+  void visitBinary(BinaryConstantExpression exp,
+                   ObjectEncoder encoder) {
+    encoder.setEnum(Key.OPERATOR, exp.operator.kind);
+    encoder.setConstant(Key.LEFT, exp.left);
+    encoder.setConstant(Key.RIGHT, exp.right);
+  }
+
+  @override
+  void visitConcatenate(ConcatenateConstantExpression exp,
+                        ObjectEncoder encoder) {
+    encoder.setConstants(Key.ARGUMENTS, exp.expressions);
+  }
+
+  @override
+  void visitConditional(ConditionalConstantExpression exp,
+                        ObjectEncoder encoder) {
+    encoder.setConstant(Key.CONDITION, exp.condition);
+    encoder.setConstant(Key.TRUE, exp.trueExp);
+    encoder.setConstant(Key.FALSE, exp.falseExp);
+  }
+
+  @override
+  void visitConstructed(ConstructedConstantExpression exp,
+                        ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, exp.target);
+    encoder.setType(Key.TYPE, exp.type);
+    encoder.setStrings(Key.NAMES, exp.callStructure.namedArguments);
+    encoder.setConstants(Key.ARGUMENTS, exp.arguments);
+  }
+
+  @override
+  void visitFunction(FunctionConstantExpression exp,
+                     ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, exp.element);
+  }
+
+  @override
+  void visitIdentical(IdenticalConstantExpression exp,
+                      ObjectEncoder encoder) {
+    encoder.setConstant(Key.LEFT, exp.left);
+    encoder.setConstant(Key.RIGHT, exp.right);
+  }
+
+  @override
+  void visitList(ListConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setType(Key.TYPE, exp.type);
+    encoder.setConstants(Key.VALUES, exp.values);
+  }
+
+  @override
+  void visitMap(MapConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setType(Key.TYPE, exp.type);
+    encoder.setConstants(Key.KEYS, exp.keys);
+    encoder.setConstants(Key.VALUES, exp.values);
+  }
+
+  @override
+  void visitBool(BoolConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setBool(Key.VALUE, exp.primitiveValue);
+  }
+
+  @override
+  void visitInt(IntConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setInt(Key.VALUE, exp.primitiveValue);
+  }
+
+  @override
+  void visitDouble(DoubleConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setDouble(Key.VALUE, exp.primitiveValue);
+  }
+
+  @override
+  void visitString(StringConstantExpression exp, ObjectEncoder encoder) {
+    encoder.setString(Key.VALUE, exp.primitiveValue);
+  }
+
+  @override
+  void visitNull(NullConstantExpression exp, ObjectEncoder encoder) {
+    // No additional data needed.
+  }
+
+  @override
+  void visitSymbol(SymbolConstantExpression exp,
+                   ObjectEncoder encoder) {
+    throw new UnsupportedError(
+        "ConstantSerializer.visitSymbol: ${exp.getText()}");
+  }
+
+  @override
+  void visitType(TypeConstantExpression exp,
+                 ObjectEncoder encoder) {
+    encoder.setType(Key.TYPE, exp.type);
+  }
+
+  @override
+  void visitUnary(UnaryConstantExpression exp,
+                  ObjectEncoder encoder) {
+    encoder.setEnum(Key.OPERATOR, exp.operator.kind);
+    encoder.setConstant(Key.EXPRESSION, exp.expression);
+  }
+
+  @override
+  void visitVariable(VariableConstantExpression exp,
+                     ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, exp.element);
+  }
+
+  @override
+  void visitPositional(PositionalArgumentReference exp,
+                       ObjectEncoder encoder) {
+    encoder.setInt(Key.INDEX, exp.index);
+  }
+
+  @override
+  void visitNamed(NamedArgumentReference exp, ObjectEncoder encoder) {
+    encoder.setString(Key.NAME, exp.name);
+  }
+
+  @override
+  void visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp,
+                                ObjectEncoder encoder) {
+    encoder.setConstant(Key.NAME, exp.name);
+    if (exp.defaultValue != null) {
+      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
+    }
+  }
+
+  @override
+  void visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp,
+                               ObjectEncoder encoder) {
+    encoder.setConstant(Key.NAME, exp.name);
+    if (exp.defaultValue != null) {
+      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
+    }
+  }
+
+  @override
+  void visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp,
+                                  ObjectEncoder encoder) {
+    encoder.setConstant(Key.NAME, exp.name);
+    if (exp.defaultValue != null) {
+      encoder.setConstant(Key.DEFAULT, exp.defaultValue);
+    }
+  }
+
+  @override
+  void visitStringLength(StringLengthConstantExpression exp,
+                         ObjectEncoder encoder) {
+    encoder.setConstant(Key.EXPRESSION, exp.expression);
+  }
+
+
+  @override
+  void visitDeferred(DeferredConstantExpression exp,
+                     ObjectEncoder encoder) {
+    throw new UnsupportedError(
+        "ConstantSerializer.visitDeferred: ${exp.getText()}");
+  }
+}
+
+/// Utility class for deserializing [ConstantExpression]s.
+///
+/// This is used by the [Deserializer].
+class ConstantDeserializer {
+
+  /// Deserializes a [ConstantExpression] from an [ObjectDecoder].
+  ///
+  /// The class is called from the [Deserializer] when a [ConstantExpression]
+  /// needs deserialization. The [ObjectDecoder] ensures that any [Element],
+  /// [DartType], and other [ConstantExpression] that the deserialized
+  /// [ConstantExpression] depends upon are available.
+  static ConstantExpression deserialize(ObjectDecoder decoder) {
+    ConstantExpressionKind kind =
+        decoder.getEnum(Key.KIND, ConstantExpressionKind.values);
+    switch (kind) {
+      case ConstantExpressionKind.BINARY:
+        BinaryOperator operator = BinaryOperator.fromKind(decoder.getEnum(
+            Key.OPERATOR, BinaryOperatorKind.values));
+        return new BinaryConstantExpression(
+            decoder.getConstant(Key.LEFT),
+            operator,
+            decoder.getConstant(Key.RIGHT));
+      case ConstantExpressionKind.BOOL:
+        return new BoolConstantExpression(
+            decoder.getBool(Key.VALUE));
+      case ConstantExpressionKind.BOOL_FROM_ENVIRONMENT:
+        return new BoolFromEnvironmentConstantExpression(
+            decoder.getConstant(Key.NAME),
+            decoder.getConstant(Key.DEFAULT, isOptional: true));
+      case ConstantExpressionKind.CONCATENATE:
+        return new ConcatenateConstantExpression(
+            decoder.getConstants(Key.ARGUMENTS));
+      case ConstantExpressionKind.CONDITIONAL:
+        return new ConditionalConstantExpression(
+            decoder.getConstant(Key.CONDITION),
+            decoder.getConstant(Key.TRUE),
+            decoder.getConstant(Key.FALSE));
+      case ConstantExpressionKind.CONSTRUCTED:
+        List<String> names =
+            decoder.getStrings(Key.NAMES, isOptional: true);
+        List<ConstantExpression> arguments =
+              decoder.getConstants(Key.ARGUMENTS, isOptional: true);
+        return new ConstructedConstantExpression(
+            decoder.getType(Key.TYPE),
+            decoder.getElement(Key.ELEMENT),
+            new CallStructure(arguments.length, names),
+            arguments);
+      case ConstantExpressionKind.DOUBLE:
+        return new DoubleConstantExpression(decoder.getDouble(Key.VALUE));
+      case ConstantExpressionKind.ERRONEOUS:
+        break;
+      case ConstantExpressionKind.FUNCTION:
+        return new FunctionConstantExpression(
+            decoder.getElement(Key.ELEMENT));
+      case ConstantExpressionKind.IDENTICAL:
+        return new IdenticalConstantExpression(
+            decoder.getConstant(Key.LEFT),
+            decoder.getConstant(Key.RIGHT));
+      case ConstantExpressionKind.INT:
+        return new IntConstantExpression(decoder.getInt(Key.VALUE));
+      case ConstantExpressionKind.INT_FROM_ENVIRONMENT:
+        return new IntFromEnvironmentConstantExpression(
+            decoder.getConstant(Key.NAME),
+            decoder.getConstant(Key.DEFAULT, isOptional: true));
+      case ConstantExpressionKind.LIST:
+        return new ListConstantExpression(
+            decoder.getType(Key.TYPE),
+            decoder.getConstants(Key.VALUES));
+      case ConstantExpressionKind.MAP:
+        return new MapConstantExpression(
+            decoder.getType(Key.TYPE),
+            decoder.getConstants(Key.KEYS),
+            decoder.getConstants(Key.VALUES));
+      case ConstantExpressionKind.NULL:
+        return new NullConstantExpression();
+      case ConstantExpressionKind.STRING:
+        return new StringConstantExpression(
+            decoder.getString(Key.VALUE));
+      case ConstantExpressionKind.STRING_FROM_ENVIRONMENT:
+        return new StringFromEnvironmentConstantExpression(
+            decoder.getConstant(Key.NAME),
+            decoder.getConstant(Key.DEFAULT, isOptional: true));
+      case ConstantExpressionKind.STRING_LENGTH:
+        return new StringLengthConstantExpression(
+            decoder.getConstant(Key.EXPRESSION));
+      case ConstantExpressionKind.SYMBOL:
+        break;
+      case ConstantExpressionKind.TYPE:
+        return new TypeConstantExpression(decoder.getType(Key.TYPE));
+      case ConstantExpressionKind.UNARY:
+        UnaryOperator operator = UnaryOperator.fromKind(
+            decoder.getEnum(Key.OPERATOR, UnaryOperatorKind.values));
+        return new UnaryConstantExpression(
+            operator,
+            decoder.getConstant(Key.EXPRESSION));
+      case ConstantExpressionKind.VARIABLE:
+        return new VariableConstantExpression(
+            decoder.getElement(Key.ELEMENT));
+
+      case ConstantExpressionKind.POSITIONAL_REFERENCE:
+        return new PositionalArgumentReference(
+            decoder.getInt(Key.INDEX));
+      case ConstantExpressionKind.NAMED_REFERENCE:
+        return new NamedArgumentReference(
+            decoder.getString(Key.NAME));
+      case ConstantExpressionKind.DEFERRED:
+      case ConstantExpressionKind.SYNTHETIC:
+    }
+    throw new UnsupportedError(
+        "Unexpected constant kind: ${kind} in $decoder");
+  }
+}
+
+/// Visitor that serializes a [ConstantConstructor] by encoding it into an
+/// [ObjectEncoder].
+///
+/// This class is called from the [ConstructorSerializer] when the [Serializer]
+/// is serializing constant constructor. The [ObjectEncoder] ensures that any
+/// [Element], [DartType], and [ConstantExpression] that the serialized
+/// [ConstantConstructor] depends upon are also serialized.
+class ConstantConstructorSerializer
+    extends ConstantConstructorVisitor<dynamic, ObjectEncoder> {
+  const ConstantConstructorSerializer();
+
+  @override
+  void visit(ConstantConstructor constantConstructor,
+             ObjectEncoder encoder) {
+    encoder.setEnum(Key.KIND, constantConstructor.kind);
+    constantConstructor.accept(this, encoder);
+  }
+
+  @override
+  void visitGenerative(
+      GenerativeConstantConstructor constructor,
+      ObjectEncoder encoder) {
+    encoder.setType(Key.TYPE, constructor.type);
+    MapEncoder defaults = encoder.createMap(Key.DEFAULTS);
+    constructor.defaultValues.forEach((key, e) {
+      defaults.setConstant('$key', e);
+    });
+    ListEncoder fields = encoder.createList(Key.FIELDS);
+    constructor.fieldMap.forEach((FieldElement f, ConstantExpression e) {
+      ObjectEncoder fieldSerializer = fields.createObject();
+      fieldSerializer.setElement(Key.FIELD, f);
+      fieldSerializer.setConstant(Key.CONSTANT, e);
+    });
+    if (constructor.superConstructorInvocation != null) {
+      encoder.setConstant(Key.CONSTRUCTOR,
+          constructor.superConstructorInvocation);
+    }
+  }
+
+  @override
+  void visitRedirectingFactory(
+      RedirectingFactoryConstantConstructor constructor,
+      ObjectEncoder encoder) {
+    encoder.setConstant(Key.CONSTRUCTOR,
+        constructor.targetConstructorInvocation);
+  }
+
+  @override
+  void visitRedirectingGenerative(
+      RedirectingGenerativeConstantConstructor constructor,
+      ObjectEncoder encoder) {
+    MapEncoder defaults = encoder.createMap(Key.DEFAULTS);
+    constructor.defaultValues.forEach((key, ConstantExpression e) {
+      defaults.setConstant('$key', e);
+    });
+    encoder.setConstant(Key.CONSTRUCTOR,
+        constructor.thisConstructorInvocation);
+  }
+}
+/// Utility class for deserializing [ConstantConstructor]s.
+///
+/// This is used by the [ConstructorElementZ].
+class ConstantConstructorDeserializer {
+  /// Deserializes a [ConstantConstructor] from an [ObjectDecoder].
+  ///
+  /// The class is called from the [Deserializer] when a constant constructor
+  /// needs deserialization. The [ObjectDecoder] ensures that any [Element],
+  /// [DartType], and [ConstantExpression] that the deserialized
+  /// [ConstantConstructor] depends upon are available.
+  static ConstantConstructor deserialize(ObjectDecoder decoder) {
+
+    ConstantConstructorKind kind =
+        decoder.getEnum(Key.KIND, ConstantConstructorKind.values);
+
+    DartType readType() {
+      return decoder.getType(Key.TYPE);
+    }
+
+    Map<dynamic/*int|String*/, ConstantExpression> readDefaults() {
+      Map<dynamic, ConstantExpression> defaultValues =
+          <dynamic, ConstantExpression>{};
+      if (decoder.containsKey(Key.DEFAULTS)) {
+        MapDecoder defaultsMap = decoder.getMap(Key.DEFAULTS);
+        defaultsMap.forEachKey((String key) {
+          int index = int.parse(key, onError: (_) => null);
+          if (index != null) {
+            defaultValues[index] = defaultsMap.getConstant(key);
+          } else {
+            defaultValues[key] = defaultsMap.getConstant(key);
+          }
+        });
+      }
+      return defaultValues;
+    }
+
+    Map<FieldElement, ConstantExpression> readFields() {
+      Map<FieldElement, ConstantExpression> fieldMap =
+          <FieldElement, ConstantExpression>{};
+      if (decoder.containsKey(Key.FIELDS)) {
+        ListDecoder fieldsList = decoder.getList(Key.FIELDS);
+        for (int i = 0; i < fieldsList.length; i++) {
+          ObjectDecoder object = fieldsList.getObject(i);
+          FieldElement field = object.getElement(Key.FIELD);
+          ConstantExpression constant = object.getConstant(Key.CONSTANT);
+          fieldMap[field] = constant;
+        }
+      }
+      return fieldMap;
+    }
+
+    ConstructedConstantExpression readConstructorInvocation() {
+      return decoder.getConstant(Key.CONSTRUCTOR, isOptional: true);
+    }
+
+    switch (kind) {
+      case ConstantConstructorKind.GENERATIVE:
+        return new GenerativeConstantConstructor(
+            readType(),
+            readDefaults(),
+            readFields(),
+            readConstructorInvocation());
+      case ConstantConstructorKind.REDIRECTING_GENERATIVE:
+        return new RedirectingGenerativeConstantConstructor(
+            readDefaults(),
+            readConstructorInvocation());
+      case ConstantConstructorKind.REDIRECTING_FACTORY:
+        return new RedirectingFactoryConstantConstructor(
+            readConstructorInvocation());
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
new file mode 100644
index 0000000..9ba4db8
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -0,0 +1,486 @@
+// 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.serialization.elements;
+
+import '../constants/expressions.dart';
+import '../dart_types.dart';
+import '../dart2jslib.dart' show SourceSpan;
+import '../elements/elements.dart';
+import '../tree/tree.dart';
+import 'constant_serialization.dart';
+import 'keys.dart';
+import 'modelz.dart';
+import 'serialization.dart';
+
+/// Enum kinds used for encoding [Element]s.
+enum SerializedElementKind {
+  LIBRARY,
+  COMPILATION_UNIT,
+  CLASS,
+  GENERATIVE_CONSTRUCTOR,
+  FACTORY_CONSTRUCTOR,
+  TOPLEVEL_FIELD,
+  STATIC_FIELD,
+  INSTANCE_FIELD,
+  TOPLEVEL_FUNCTION,
+  TOPLEVEL_GETTER,
+  TOPLEVEL_SETTER,
+  STATIC_FUNCTION,
+  STATIC_GETTER,
+  STATIC_SETTER,
+  INSTANCE_FUNCTION,
+  INSTANCE_GETTER,
+  INSTANCE_SETTER,
+  TYPEDEF,
+  TYPEVARIABLE,
+  PARAMETER,
+  INITIALIZING_FORMAL,
+}
+
+/// Set of serializers used to serialize different kinds of elements by
+/// encoding into them into [ObjectEncoder]s.
+///
+/// This class is called from the [Serializer] when an [Element] needs
+/// serialization. The [ObjectEncoder] ensures that any [Element], [DartType],
+/// and [ConstantExpression] that the serialized [Element] depends upon are also
+/// serialized.
+const List<ElementSerializer> ELEMENT_SERIALIZERS = const [
+    const LibrarySerializer(),
+    const CompilationUnitSerializer(),
+    const ClassSerializer(),
+    const ConstructorSerializer(),
+    const FieldSerializer(),
+    const FunctionSerializer(),
+    const TypedefSerializer(),
+    const TypeVariableSerializer(),
+    const ParameterSerializer(),
+];
+
+/// Interface for a function that can serialize a set of element kinds.
+abstract class ElementSerializer {
+  /// Returns the [SerializedElementKind] for [element] if this serializer
+  /// supports serialization of [element] or `null` otherwise.
+  SerializedElementKind getSerializedKind(Element element);
+
+  /// Serializes [element] into the [encoder] using the [kind] computed
+  /// by [getSerializedKind].
+  void serialize(Element element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind);
+}
+
+class SerializerUtil {
+  /// Serialize the declared members of [element] into [encoder].
+  static void serializeMembers(ScopeContainerElement element,
+                               ObjectEncoder encoder) {
+    MapEncoder mapEncoder = encoder.createMap(Key.MEMBERS);
+    element.forEachLocalMember((Element member) {
+      String name = member.name;
+      if (member.isSetter) {
+        name = '$name,=';
+      }
+      mapEncoder.setElement(name, member);
+    });
+  }
+
+  /// Serialize the source position of [element] into [encoder].
+  static void serializePosition(Element element, ObjectEncoder encoder) {
+    if (element.sourcePosition != null) {
+      SourceSpan position = element.sourcePosition;
+      encoder.setInt(Key.OFFSET, position.begin);
+      if (position.uri != element.compilationUnit.script.resourceUri) {
+        // TODO(johnniwinther): What is the base URI in the case?
+        encoder.setUri(Key.URI, element.library.canonicalUri, position.uri);
+      }
+      int length = position.end - position.begin;
+      if (element.name.length != length) {
+        encoder.setInt(Key.LENGTH, length);
+      }
+    }
+  }
+
+  /// Serialize the parameters of [element] into [encoder].
+  static void serializeParameters(FunctionElement element,
+                                  ObjectEncoder encoder) {
+    FunctionType type = element.type;
+    encoder.setType(Key.RETURN_TYPE, type.returnType);
+    encoder.setElements(Key.PARAMETERS, element.parameters);
+  }
+
+  /// Returns a function that adds the underlying declared elements for a
+  /// particular element into [list].
+  ///
+  /// For instance, for an [AbstractFieldElement] the getter and setter elements
+  /// are added, if available.
+  static flattenElements(List<Element> list) {
+    return (Element element) {
+      // TODO(johnniwinther): Handle ambiguous elements.
+      if (element.isAmbiguous) return;
+      if (element.isAbstractField) {
+        AbstractFieldElement abstractField = element;
+        if (abstractField.getter != null) {
+          list.add(abstractField.getter);
+        }
+        if (abstractField.setter != null) {
+          list.add(abstractField.setter);
+        }
+      } else {
+        list.add(element);
+      }
+    };
+  }
+}
+
+class LibrarySerializer implements ElementSerializer {
+  const LibrarySerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isLibrary) {
+      return SerializedElementKind.LIBRARY;
+    }
+    return null;
+  }
+
+  void serialize(LibraryElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setUri(
+        Key.CANONICAL_URI, element.canonicalUri, element.canonicalUri);
+    encoder.setString(Key.LIBRARY_NAME, element.getLibraryName());
+    SerializerUtil.serializeMembers(element, encoder);
+    encoder.setElement(Key.COMPILATION_UNIT, element.entryCompilationUnit);
+    encoder.setElements(
+        Key.COMPILATION_UNITS, element.compilationUnits.toList());
+    ListEncoder tags = encoder.createList(Key.TAGS);
+
+    for (LibraryTag tag in element.tags) {
+      if (tag is Import) {
+        ObjectEncoder importTag = tags.createObject();
+        importTag.setString(Key.KIND, 'import');
+        importTag.setElement(Key.LIBRARY, element.getLibraryFromTag(tag));
+      } else if (tag is Export) {
+        ObjectEncoder exportTag = tags.createObject();
+        exportTag.setString(Key.KIND, 'export');
+        exportTag.setElement(Key.LIBRARY, element.getLibraryFromTag(tag));
+      }
+    }
+
+    List<Element> imports = <Element>[];
+    element.forEachImport(SerializerUtil.flattenElements(imports));
+    encoder.setElements(Key.IMPORTS, imports);
+
+    List<Element> exports = <Element>[];
+    element.forEachExport(SerializerUtil.flattenElements(exports));
+    encoder.setElements(Key.EXPORTS, exports);
+  }
+}
+
+class CompilationUnitSerializer implements ElementSerializer {
+  const CompilationUnitSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isCompilationUnit) {
+      return SerializedElementKind.COMPILATION_UNIT;
+    }
+    return null;
+  }
+
+  void serialize(CompilationUnitElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setUri(
+        Key.URI, element.library.canonicalUri, element.script.resourceUri);
+    List<Element> elements = <Element>[];
+    element.forEachLocalMember((e) => elements.add(e));
+    encoder.setElements(Key.ELEMENTS, elements);
+  }
+}
+
+class ClassSerializer implements ElementSerializer {
+  const ClassSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isClass) {
+      return SerializedElementKind.CLASS;
+    }
+    return null;
+  }
+
+  void serialize(ClassElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
+    encoder.setBool(Key.IS_ABSTRACT, element.isAbstract);
+    if (element.supertype != null) {
+      encoder.setType(Key.SUPERTYPE, element.supertype);
+    }
+    // TODO(johnniwinther): Make [OrderedTypeSet] easier to (de)serialize.
+    ObjectEncoder supertypes = encoder.createObject(Key.SUPERTYPES);
+    supertypes.setTypes(Key.TYPES,
+        element.allSupertypesAndSelf.types.toList());
+    supertypes.setTypes(Key.SUPERTYPES,
+        element.allSupertypesAndSelf.supertypes.toList());
+    supertypes.setInts(Key.OFFSETS, element.allSupertypesAndSelf.levelOffsets);
+    encoder.setTypes(Key.INTERFACES, element.interfaces.toList());
+    SerializerUtil.serializeMembers(element, encoder);
+  }
+}
+
+class ConstructorSerializer implements ElementSerializer {
+  const ConstructorSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isGenerativeConstructor) {
+      return SerializedElementKind.GENERATIVE_CONSTRUCTOR;
+    } else if (element.isFactoryConstructor) {
+      return SerializedElementKind.FACTORY_CONSTRUCTOR;
+    }
+    return null;
+  }
+
+  void serialize(ConstructorElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.CLASS, element.enclosingClass);
+    encoder.setType(Key.TYPE, element.type);
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    SerializerUtil.serializeParameters(element, encoder);
+    encoder.setBool(Key.IS_CONST, element.isConst);
+    // TODO(johnniwinther): Handle external constructors.
+    encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
+    if (element.isExternal) return;
+    if (element.isConst && !element.isFromEnvironmentConstructor) {
+      ConstantConstructor constantConstructor = element.constantConstructor;
+      ObjectEncoder constantEncoder =
+          encoder.createObject(Key.CONSTRUCTOR);
+      const ConstantConstructorSerializer().visit(
+          constantConstructor, constantEncoder);
+    }
+  }
+}
+
+class FieldSerializer implements ElementSerializer {
+  const FieldSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isField) {
+      if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_FIELD;
+      if (element.isStatic) return SerializedElementKind.STATIC_FIELD;
+      if (element.isInstanceMember) return SerializedElementKind.INSTANCE_FIELD;
+    }
+    return null;
+  }
+
+  void serialize(FieldElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    encoder.setType(Key.TYPE, element.type);
+    encoder.setBool(Key.IS_FINAL, element.isFinal);
+    encoder.setBool(Key.IS_CONST, element.isConst);
+    if (element.isConst) {
+      ConstantExpression constant = element.constant;
+      encoder.setConstant(Key.CONSTANT, constant);
+    }
+    if (kind != SerializedElementKind.TOPLEVEL_FIELD) {
+      encoder.setElement(Key.CLASS, element.enclosingClass);
+    } else {
+      encoder.setElement(Key.LIBRARY, element.library);
+      encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    }
+  }
+}
+
+class FunctionSerializer implements ElementSerializer {
+  const FunctionSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isFunction) {
+      if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_FUNCTION;
+      if (element.isStatic) return SerializedElementKind.STATIC_FUNCTION;
+      if (element.isInstanceMember) {
+        return SerializedElementKind.INSTANCE_FUNCTION;
+      }
+    }
+    if (element.isGetter) {
+      if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_GETTER;
+      if (element.isStatic) return SerializedElementKind.STATIC_GETTER;
+      if (element.isInstanceMember) {
+        return SerializedElementKind.INSTANCE_GETTER;
+      }
+    }
+    if (element.isSetter) {
+      if (element.isTopLevel) return SerializedElementKind.TOPLEVEL_SETTER;
+      if (element.isStatic) return SerializedElementKind.STATIC_SETTER;
+      if (element.isInstanceMember) {
+        return SerializedElementKind.INSTANCE_SETTER;
+      }
+    }
+    return null;
+  }
+
+  void serialize(FunctionElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    SerializerUtil.serializeParameters(element, encoder);
+    encoder.setType(Key.TYPE, element.type);
+    if (element.isFunction) {
+      encoder.setBool(Key.IS_OPERATOR, element.isOperator);
+    }
+    if (element.enclosingClass != null) {
+      encoder.setElement(Key.CLASS, element.enclosingClass);
+    } else {
+      encoder.setElement(Key.LIBRARY, element.library);
+      encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+    }
+  }
+}
+
+class TypedefSerializer implements ElementSerializer {
+  const TypedefSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isTypedef) {
+      return SerializedElementKind.TYPEDEF;
+    }
+    return null;
+  }
+
+  void serialize(TypedefElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    encoder.setType(Key.ALIAS, element.alias);
+    encoder.setElement(Key.LIBRARY, element.library);
+    encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
+    encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
+  }
+}
+
+class TypeVariableSerializer implements ElementSerializer {
+  const TypeVariableSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isTypeVariable) {
+      return SerializedElementKind.TYPEVARIABLE;
+    }
+    return null;
+  }
+
+  void serialize(TypeVariableElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.TYPE_DECLARATION, element.typeDeclaration);
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    TypeDeclarationElement typeDeclaration = element.typeDeclaration;
+    encoder.setType(Key.TYPE, element.type);
+    encoder.setInt(Key.INDEX, element.index);
+    encoder.setType(Key.BOUND, element.bound);
+  }
+}
+
+class ParameterSerializer implements ElementSerializer {
+  const ParameterSerializer();
+
+  SerializedElementKind getSerializedKind(Element element) {
+    if (element.isParameter) {
+      return SerializedElementKind.PARAMETER;
+    } else if (element.isInitializingFormal) {
+      return SerializedElementKind.INITIALIZING_FORMAL;
+    }
+    return null;
+  }
+
+  void serialize(ParameterElement element,
+                 ObjectEncoder encoder,
+                 SerializedElementKind kind) {
+    encoder.setElement(Key.FUNCTION, element.functionDeclaration);
+    encoder.setString(Key.NAME, element.name);
+    SerializerUtil.serializePosition(element, encoder);
+    encoder.setType(Key.TYPE, element.type);
+    encoder.setBool(Key.IS_OPTIONAL, element.isOptional);
+    encoder.setBool(Key.IS_NAMED, element.isNamed);
+    if (element.isOptional) {
+      encoder.setConstant(Key.CONSTANT, element.constant);
+    }
+    if (element.isInitializingFormal) {
+      InitializingFormalElement initializingFormal = element;
+      encoder.setElement(Key.FIELD, initializingFormal.fieldElement);
+    }
+  }
+}
+
+/// Utility class for deserializing [Element]s.
+///
+/// This is used by the [Deserializer].
+class ElementDeserializer {
+
+  /// Deserializes an [Element] from an [ObjectDecoder].
+  ///
+  /// The class is called from the [Deserializer] when an [Element]
+  /// needs deserialization. The [ObjectDecoder] ensures that any [Element],
+  /// [DartType], and [ConstantExpression] that the deserialized [Element]
+  /// depends upon are available.
+  static Element deserialize(ObjectDecoder decoder) {
+    SerializedElementKind elementKind =
+        decoder.getEnum(Key.KIND, SerializedElementKind.values);
+    switch (elementKind) {
+      case SerializedElementKind.LIBRARY:
+        return new LibraryElementZ(decoder);
+      case SerializedElementKind.COMPILATION_UNIT:
+        return new CompilationUnitElementZ(decoder);
+      case SerializedElementKind.CLASS:
+        return new ClassElementZ(decoder);
+      case SerializedElementKind.TOPLEVEL_FIELD:
+        return new TopLevelFieldElementZ(decoder);
+      case SerializedElementKind.STATIC_FIELD:
+        return new StaticFieldElementZ(decoder);
+      case SerializedElementKind.INSTANCE_FIELD:
+        return new InstanceFieldElementZ(decoder);
+      case SerializedElementKind.GENERATIVE_CONSTRUCTOR:
+        return new GenerativeConstructorElementZ(decoder);
+      case SerializedElementKind.FACTORY_CONSTRUCTOR:
+        return new FactoryConstructorElementZ(decoder);
+      case SerializedElementKind.TOPLEVEL_FUNCTION:
+        return new TopLevelFunctionElementZ(decoder);
+      case SerializedElementKind.STATIC_FUNCTION:
+        return new StaticFunctionElementZ(decoder);
+      case SerializedElementKind.INSTANCE_FUNCTION:
+        return new InstanceFunctionElementZ(decoder);
+      case SerializedElementKind.TOPLEVEL_GETTER:
+        return new TopLevelGetterElementZ(decoder);
+      case SerializedElementKind.STATIC_GETTER:
+        return new StaticGetterElementZ(decoder);
+      case SerializedElementKind.INSTANCE_GETTER:
+        return new InstanceGetterElementZ(decoder);
+      case SerializedElementKind.TOPLEVEL_SETTER:
+        return new TopLevelSetterElementZ(decoder);
+      case SerializedElementKind.STATIC_SETTER:
+        return new StaticSetterElementZ(decoder);
+      case SerializedElementKind.INSTANCE_SETTER:
+        return new InstanceSetterElementZ(decoder);
+      case SerializedElementKind.TYPEDEF:
+        return new TypedefElementZ(decoder);
+      case SerializedElementKind.TYPEVARIABLE:
+        return new TypeVariableElementZ(decoder);
+      case SerializedElementKind.PARAMETER:
+        return new ParameterElementZ(decoder);
+      case SerializedElementKind.INITIALIZING_FORMAL:
+        return new InitializingFormalElementZ(decoder);
+    }
+    throw new UnsupportedError("Unexpected element kind '${elementKind}.");
+  }
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/serialization/json_serializer.dart b/pkg/compiler/lib/src/serialization/json_serializer.dart
new file mode 100644
index 0000000..399bdbf
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/json_serializer.dart
@@ -0,0 +1,212 @@
+// 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.serialization.json;
+
+import 'dart:convert';
+import 'keys.dart';
+import 'serialization.dart';
+import 'values.dart';
+
+/// Serialization encoder for JSON.
+class JsonSerializationEncoder implements SerializationEncoder {
+  const JsonSerializationEncoder();
+
+  String encode(ObjectValue objectValue) {
+    return new JsonEncoder.withIndent(' ').convert(
+        const JsonValueEncoder().convert(objectValue));
+  }
+}
+
+/// Serialization decoder for JSON.
+class JsonSerializationDecoder implements SerializationDecoder {
+  const JsonSerializationDecoder();
+
+  Map decode(String text) => JSON.decode(text);
+
+  /// Returns the name of the [key] which used for to store a [Key] into a
+  /// [Map]; corresponding to the encoding of object properties in
+  /// [JsonValueEncoder.visitObject].
+  getObjectPropertyValue(Key key) => key.name;
+}
+
+/// A [ValueVisitor] that computes a JSON object value.
+class JsonValueEncoder implements ValueVisitor {
+  const JsonValueEncoder();
+
+  convert(Value value) => visit(value, null);
+
+  @override
+  visit(Value value, [arg]) => value.accept(this, arg);
+
+  @override
+  bool visitBool(BoolValue value, arg) => value.value;
+
+  @override
+  visitConstant(ConstantValue value, arg) => visit(value.id);
+
+  @override
+  double visitDouble(DoubleValue value, arg) => value.value;
+
+  @override
+  visitElement(ElementValue value, arg) => visit(value.id);
+
+  @override
+  visitEnum(EnumValue value, arg) => value.value.index;
+
+  @override
+  int visitInt(IntValue value, arg) => value.value;
+
+  @override
+  List visitList(ListValue value, arg) => value.values.map(visit).toList();
+
+  @override
+  Map visitMap(MapValue value, arg) {
+    Map<String, dynamic> map = <String, dynamic>{};
+    value.map.forEach((String key, Value value) {
+      map[key] = visit(value);
+    });
+    return map;
+  }
+
+  @override
+  Map visitObject(ObjectValue value, arg) {
+    Map<String, dynamic> map = <String, dynamic>{};
+    value.map.forEach((Key key, Value value) {
+      map[key.name] = visit(value);
+    });
+    return map;
+  }
+
+  @override
+  String visitString(StringValue value, arg) => value.value;
+
+  @override
+  visitType(TypeValue value, arg) => visit(value.id);
+
+  @override
+  visitUri(UriValue value, arg) => '${value.value}';
+}
+
+/// [ValueVisitor] that generates a verbose JSON-like output.
+class PrettyPrintEncoder implements ValueVisitor {
+  StringBuffer buffer;
+
+  String toText(Value value) {
+    buffer = new StringBuffer();
+    visit(value, '');
+    String text = buffer.toString();
+    buffer = null;
+    return text;
+  }
+
+  @override
+  void visit(Value value, String indentation) {
+    value.accept(this, indentation);
+  }
+
+  @override
+  void visitBool(BoolValue value, String indentation) {
+    buffer.write(value.value);
+  }
+
+  @override
+  void visitConstant(ConstantValue value, String indentation) {
+    buffer.write('Constant(${value.id}):${value.constant.getText()}');
+  }
+
+  @override
+  void visitDouble(DoubleValue value, String indentation) {
+    buffer.write(value.value);
+  }
+  @override
+  void visitElement(ElementValue value, String indentation) {
+    buffer.write('Element(${value.id}):${value.element}');
+  }
+
+  @override
+  void visitEnum(EnumValue value, String indentation) {
+    buffer.write(value.value);
+  }
+
+  @override
+  void visitInt(IntValue value, String indentation) {
+    buffer.write(value.value);
+  }
+
+  @override
+  void visitList(ListValue value, String indentation) {
+    if (value.values.isEmpty) {
+      buffer.write('[]');
+    } else {
+      buffer.write('[');
+      bool needsComma = false;
+      String nextIndentation = '${indentation}  ';
+      for (Value element in value.values) {
+        if (needsComma) {
+          buffer.write(',');
+        }
+        buffer.write('\n$nextIndentation');
+        visit(element, nextIndentation);
+        needsComma = true;
+      }
+      buffer.write('\n$indentation]');
+    }
+  }
+
+  @override
+  void visitMap(MapValue value, String indentation) {
+    if (value.map.isEmpty) {
+      buffer.write('{}');
+    } else {
+      buffer.write('{');
+      bool needsComma = false;
+      String nextIndentation = '${indentation}  ';
+      value.map.forEach((String key, Value subvalue) {
+        if (needsComma) {
+          buffer.write(',');
+        }
+        buffer.write('\n$nextIndentation$key: ');
+        visit(subvalue, nextIndentation);
+        needsComma = true;
+      });
+      buffer.write('\n$indentation}');
+    }
+  }
+
+  @override
+  void visitObject(ObjectValue value, String indentation) {
+    if (value.map.isEmpty) {
+      buffer.write('{}');
+    } else {
+      buffer.write('{');
+      bool needsComma = false;
+      String nextIndentation = '${indentation}  ';
+      value.map.forEach((Key key, Value subvalue) {
+        if (needsComma) {
+          buffer.write(',');
+        }
+        buffer.write('\n$nextIndentation$key: ');
+        visit(subvalue, nextIndentation);
+        needsComma = true;
+      });
+      buffer.write('\n$indentation}');
+    }
+  }
+
+  @override
+  void visitString(StringValue value, String indentation) {
+    buffer.write('"${value.value}"');
+  }
+
+  @override
+  void visitType(TypeValue value, String indentation) {
+    buffer.write('Type(${value.id}):${value.type}');
+  }
+
+  @override
+  void visitUri(UriValue value, String indentation) {
+    buffer.write('Uri(${value.value})');
+  }
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
new file mode 100644
index 0000000..a3c276e
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -0,0 +1,80 @@
+// 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.serialization.keys;
+
+/// Keys used for serialization.
+class Key {
+  static const Key ALIAS = const Key('alias');
+  static const Key ARGUMENTS = const Key('arguments');
+  static const Key BOUND = const Key('bound');
+  static const Key CALL_STRUCTURE = const Key('callStructure');
+  static const Key CANONICAL_URI = const Key('canonicalUri');
+  static const Key CLASS = const Key('class');
+  static const Key COMPILATION_UNIT = const Key('compilation-unit');
+  static const Key COMPILATION_UNITS = const Key('compilation-units');
+  static const Key CONDITION = const Key('condition');
+  static const Key CONSTANT = const Key('constant');
+  static const Key CONSTANTS = const Key('constants');
+  static const Key CONSTRUCTOR = const Key('constructor');
+  static const Key DEFAULT = const Key('default');
+  static const Key DEFAULTS = const Key('defaults');
+  static const Key ELEMENT = const Key('element');
+  static const Key ELEMENTS = const Key('elements');
+  static const Key EXPORTS = const Key('exports');
+  static const Key EXPRESSION = const Key('expression');
+  static const Key FALSE = const Key('false');
+  static const Key FIELD = const Key('field');
+  static const Key FIELDS = const Key('fields');
+  static const Key FUNCTION = const Key('function');
+  static const Key ID = const Key('id');
+  static const Key IMPORTS = const Key('imports');
+  static const Key INTERFACES = const Key('interfaces');
+  static const Key INDEX = const Key('index');
+  static const Key IS_ABSTRACT = const Key('isAbstract');
+  static const Key IS_CONST = const Key('isConst');
+  static const Key IS_EXTERNAL = const Key('isExternal');
+  static const Key IS_FINAL = const Key('isFinal');
+  static const Key IS_NAMED = const Key('isNamed');
+  static const Key IS_OPERATOR = const Key('isOperator');
+  static const Key IS_OPTIONAL = const Key('isOptional');
+  static const Key KEYS = const Key('keys');
+  static const Key KIND = const Key('kind');
+  static const Key LEFT = const Key('left');
+  static const Key LENGTH = const Key('length');
+  static const Key LIBRARY = const Key('library');
+  static const Key LIBRARY_NAME = const Key('library-name');
+  static const Key MEMBERS = const Key('members');
+  static const Key NAME = const Key('name');
+  static const Key NAMES = const Key('names');
+  static const Key NAMED_PARAMETERS = const Key('named-parameters');
+  static const Key NAMED_PARAMETER_TYPES = const Key('named-parameter-types');
+  static const Key OFFSET = const Key('offset');
+  static const Key OFFSETS = const Key('offsets');
+  static const Key OPERATOR = const Key('operator');
+  static const Key OPTIONAL_PARAMETER_TYPES =
+      const Key('optional-parameter-types');
+  static const Key PARAMETERS = const Key('parameters');
+  static const Key PARAMETER_TYPES = const Key('parameter-types');
+  static const Key RETURN_TYPE = const Key('return-type');
+  static const Key RIGHT = const Key('right');
+  static const Key SUPERTYPE = const Key('supertype');
+  static const Key SUPERTYPES = const Key('supertypes');
+  static const Key TAGS = const Key('tags');
+  static const Key TRUE = const Key('true');
+  static const Key TYPE = const Key('type');
+  static const Key TYPES = const Key('types');
+  static const Key TYPE_ARGUMENTS = const Key('type-arguments');
+  static const Key TYPE_DECLARATION = const Key('type-declaration');
+  static const Key TYPE_VARIABLES = const Key('type-variables');
+  static const Key URI = const Key('uri');
+  static const Key VALUE = const Key('value');
+  static const Key VALUES = const Key('values');
+
+  final String name;
+
+  const Key(this.name);
+
+  String toString() => name;
+}
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
new file mode 100644
index 0000000..15bfc1e
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -0,0 +1,1449 @@
+// 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.
+
+/// Implementation of the element model used for deserialiation.
+///
+/// These classes are created by [ElementDeserializer] triggered by the
+/// [Deserializer].
+
+library dart2js.serialization.modelz;
+
+import 'serialization.dart';
+import 'keys.dart';
+import '../constants/expressions.dart';
+import '../dart2jslib.dart'
+    show Backend,
+         Compiler,
+         DiagnosticListener,
+         Script,
+         SourceSpan;
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import '../elements/modelx.dart' show FunctionSignatureX;
+import '../elements/common.dart';
+import '../elements/visitor.dart';
+import '../ordered_typeset.dart';
+import '../resolution/resolution.dart';
+import '../resolution/class_members.dart' as class_members;
+import '../resolution/enum_creator.dart' show AstBuilder;
+import '../scanner/scannerlib.dart' show Token, SEMICOLON_INFO;
+import '../serialization/constant_serialization.dart';
+import '../io/source_file.dart';
+import '../tree/tree.dart';
+import '../util/util.dart' show Link, LinkBuilder;
+
+/// Compute a [Link] from an [Iterable].
+Link toLink(Iterable iterable) {
+  LinkBuilder builder = new LinkBuilder();
+  for (var element in iterable) {
+    builder.addLast(element);
+  }
+  return builder.toLink();
+}
+
+abstract class ElementZ extends Element with ElementCommon {
+  @override
+  bool get isFactoryConstructor => false;
+
+  String toString() {
+    if (enclosingElement == null || isTopLevel) return 'Z$kind($name)';
+    return 'Z$kind(${enclosingElement.name}#$name)';
+  }
+
+  _unsupported(text) => throw new UnsupportedError('${this}.$text');
+
+  @override
+  AnalyzableElement get analyzableElement {
+    Element element = this;
+    if (element is AnalyzableElement) {
+      return element;
+    } else if (enclosingElement != null) {
+      return enclosingElement.analyzableElement;
+    }
+    return null;
+  }
+
+  @override
+  FunctionElement asFunctionElement() => null;
+
+  @override
+  Scope buildScope() => _unsupported('analyzableElement');
+
+  @override
+  CompilationUnitElement get compilationUnit {
+    return _unsupported('compilationUnit');
+  }
+
+  @override
+  ClassElement get contextClass => _unsupported('contextClass');
+
+  @override
+  void diagnose(Element context, DiagnosticListener listener) {
+    _unsupported('diagnose');
+  }
+
+  @override
+  ClassElement get enclosingClass => null;
+
+  @override
+  Element get enclosingClassOrCompilationUnit {
+    return _unsupported('enclosingClassOrCompilationUnit');
+  }
+
+  @override
+  String get fixedBackendName => _unsupported('fixedBackendName');
+
+  @override
+  bool get hasFixedBackendName => _unsupported('hasFixedBackendName');
+
+  @override
+  LibraryElement get implementationLibrary => library;
+
+  @override
+  bool get isAbstract => false;
+
+  @override
+  bool get isAssignable => _unsupported('isAssignable');
+
+  @override
+  bool get isClassMember => false;
+
+  @override
+  bool get isClosure => _unsupported('isClosure');
+
+  @override
+  bool get isConst => _unsupported('isConst');
+
+  @override
+  bool get isDeferredLoaderGetter => false;
+
+  @override
+  bool get isFinal => _unsupported('isFinal');
+
+  @override
+  bool get isInstanceMember => false;
+
+  @override
+  bool get isLocal => false;
+
+  @override
+  bool get isMixinApplication => false;
+
+  @override
+  bool get isNative => false;
+
+  @override
+  bool get isOperator => false;
+
+  @override
+  bool get isStatic => false;
+
+  // TODO(johnniwinther): Find a more precise semantics for this.
+  @override
+  bool get isSynthesized => true;
+
+  @override
+  bool get isTopLevel => false;
+
+  // TODO(johnniwinther): Support metadata.
+  @override
+  Link<MetadataAnnotation> get metadata => const Link<MetadataAnnotation>();
+
+  @override
+  Element get outermostEnclosingMemberOrTopLevel {
+    return _unsupported('outermostEnclosingMemberOrTopLevel');
+  }
+
+  @override
+  Token get position => _unsupported('position');
+}
+
+abstract class DeserializedElementZ extends ElementZ {
+  ObjectDecoder _decoder;
+
+  DeserializedElementZ(this._decoder);
+
+  @override
+  String get name => _decoder.getString(Key.NAME);
+
+  @override
+  SourceSpan get sourcePosition {
+    // TODO(johnniwinther): Should this be cached?
+    int offset = _decoder.getInt(Key.OFFSET, isOptional: true);
+    if (offset == null) return null;
+    Uri uri = _decoder.getUri(Key.URI, isOptional: true);
+    if (uri == null) {
+      uri = compilationUnit.script.readableUri;
+    }
+    int length = _decoder.getInt(Key.LENGTH, isOptional: true);
+    if (length == null) {
+      length = name.length;
+    }
+    return new SourceSpan(uri, offset, offset + length);
+  }
+}
+
+/// Deserializer for a collection of member elements serialized as a map from
+/// names to element declarations.
+///
+/// The serialized data contains the declared getters and setters but lookup
+/// into the map returns an [AbstractFieldElement] for pairs of corresponding
+/// getters and setters.
+///
+/// The underlying map encoding allows for lazy computation of the members upon
+/// query.
+class MappedContainer {
+  Map<String, Element> _lookupCache = {};
+
+  Element lookup(String name, MapDecoder members) {
+    if (_lookupCache.containsKey(name)) {
+      Element element = _lookupCache[name];
+      if (element != null) {
+        return element;
+      }
+    }
+    if (members == null) {
+      return null;
+    }
+    bool hasId = members.containsKey(name);
+    String setterName = '$name,=';
+    bool hasSetterId = members.containsKey(setterName);
+    Element element;
+    Element setterElement;
+    if (!hasId && !hasSetterId) {
+      _lookupCache[name] = null;
+      return null;
+    }
+    bool isAccessor = false;
+    if (hasId) {
+      element = members.getElement(name);
+      isAccessor = element.isGetter;
+    }
+    if (hasSetterId) {
+      setterElement = members.getElement(setterName);
+      isAccessor = true;
+    }
+    if (isAccessor) {
+      element = new AbstractFieldElementZ(name, element, setterElement);
+    }
+    _lookupCache[name] = element;
+    return element;
+  }
+}
+
+/// Deserializer for a collection of member elements serialized as a list of
+/// element declarations.
+///
+/// The serialized data contains the declared getters and setters but lookup
+/// into the map returns an [AbstractFieldElement] for pairs of corresponding
+/// getters and setters.
+///
+/// The underlying list encoding requires the complete lookup map to be computed
+/// before query.
+class ListedContainer {
+  final Map<String, Element> _lookupMap = <String, Element>{};
+
+  ListedContainer(List<Element> elements) {
+    Set<String> accessorNames = new Set<String>();
+    Map<String, Element> getters = <String, Element>{};
+    Map<String, Element> setters = <String, Element>{};
+    for (Element element in elements) {
+      String name = element.name;
+      if (element.isGetter) {
+        accessorNames.add(name);
+        getters[name] = element;
+        // Inserting [element] here to ensure insert order of [name].
+        _lookupMap[name] = element;
+      } else if (element.isSetter) {
+        accessorNames.add(name);
+        setters[name] = element;
+        // Inserting [element] here to ensure insert order of [name].
+        _lookupMap[name] = element;
+      } else {
+        _lookupMap[name] = element;
+      }
+    }
+    for (String name in accessorNames) {
+      _lookupMap[name] =
+          new AbstractFieldElementZ(name, getters[name], setters[name]);
+    }
+  }
+
+  Element lookup(String name) => _lookupMap[name];
+
+  void forEach(f(Element element)) => _lookupMap.values.forEach(f);
+
+  Iterable<Element> get values => _lookupMap.values;
+}
+
+
+abstract class AnalyzableElementMixin implements AnalyzableElement, ElementZ {
+  @override
+  bool get hasTreeElements => _unsupported('hasTreeElements');
+
+  @override
+  TreeElements get treeElements => _unsupported('treeElements');
+}
+
+
+abstract class AstElementMixin implements AstElement, ElementZ {
+  @override
+  bool get hasNode => _unsupported('hasNode');
+
+  @override
+  bool get hasResolvedAst => _unsupported('hasResolvedAst');
+
+  @override
+  get node => _unsupported('node');
+
+  @override
+  ResolvedAst get resolvedAst => _unsupported('resolvedAst');
+}
+
+abstract class ContainerMixin
+    implements DeserializedElementZ, ScopeContainerElement {
+  MappedContainer _membersMap = new MappedContainer();
+
+  @override
+  Element localLookup(String name) {
+    return _membersMap.lookup(
+        name, _decoder.getMap(Key.MEMBERS, isOptional: true));
+  }
+
+  @override
+  void forEachLocalMember(f(Element element)) {
+    MapDecoder members =
+        _decoder.getMap(Key.MEMBERS, isOptional: true);
+    if (members == null) return;
+    members.forEachKey((String key) {
+      Element member = members.getElement(key);
+      if (member != null) {
+        f(member);
+      }
+    });
+  }
+}
+
+class AbstractFieldElementZ extends ElementZ implements AbstractFieldElement {
+  final String name;
+  final FunctionElement getter;
+  final FunctionElement setter;
+
+  AbstractFieldElementZ(this.name, this.getter, this.setter);
+
+  @override
+  ElementKind get kind => ElementKind.ABSTRACT_FIELD;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitAbstractFieldElement(this, arg);
+  }
+
+  @override
+  LibraryElement get library {
+    return getter != null ? getter.library : setter.library;
+  }
+
+  @override
+  Element get enclosingElement {
+    return getter != null ? getter.enclosingElement : setter.enclosingElement;
+  }
+
+  @override
+  SourceSpan get sourcePosition {
+    return getter != null ? getter.sourcePosition : setter.sourcePosition;
+  }
+}
+
+class LibraryElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         ContainerMixin,
+         LibraryElementCommon
+    implements LibraryElement {
+  Uri _canonicalUri;
+  CompilationUnitElement _entryCompilationUnit;
+  Link<CompilationUnitElement> _compilationUnits;
+  Link<Element> _exports;
+  ListedContainer _exportsMap;
+  ListedContainer _importsMap;
+  Map<LibraryTag, LibraryElement> _libraryDependencies;
+
+  LibraryElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.LIBRARY;
+
+  @override
+  Element get enclosingElement => null;
+
+  @override
+  String get name => entryCompilationUnit.name;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitLibraryElement(this, arg);
+  }
+
+  @override
+  LibraryElement get library => this;
+
+  @override
+  Uri get canonicalUri {
+    if (_canonicalUri == null) {
+      _canonicalUri = _decoder.getUri(Key.CANONICAL_URI);
+    }
+    return _canonicalUri;
+  }
+
+  @override
+  CompilationUnitElement get entryCompilationUnit {
+    if (_entryCompilationUnit == null) {
+      _entryCompilationUnit = _decoder.getElement(Key.COMPILATION_UNIT);
+    }
+    return _entryCompilationUnit;
+  }
+
+  @override
+  Link<CompilationUnitElement> get compilationUnits {
+    if (_compilationUnits == null) {
+      _compilationUnits =
+          toLink(_decoder.getElements(Key.COMPILATION_UNITS));
+    }
+    return _compilationUnits;
+  }
+
+  @override
+  bool hasLibraryName() {
+    return getLibraryName() != '';
+  }
+
+  @override
+  String getLibraryName() {
+    return _decoder.getString(Key.LIBRARY_NAME);
+  }
+
+  @override
+  bool get exportsHandled => true;
+
+  void _ensureExports() {
+    if (_exports == null) {
+      _exportsMap = new ListedContainer(_decoder.getElements(Key.EXPORTS));
+      _exports = toLink(_exportsMap.values);
+    }
+  }
+
+  Link<Element> get exports {
+    _ensureExports();
+    return _exports;
+  }
+
+  @override
+  void forEachExport(f(Element element)) {
+    exports.forEach(f);
+  }
+
+  @override
+  Element find(String elementName) {
+    Element element = localLookup(elementName);
+    if (element == null) {
+      _ensureImports();
+      element = _importsMap.lookup(elementName);
+    }
+    return element;
+  }
+
+  @override
+  Element findLocal(String elementName) {
+    return localLookup(elementName);
+  }
+
+  void _ensureLibraryDependencies() {
+    if (_libraryDependencies == null) {
+      _libraryDependencies = <LibraryTag, LibraryElement>{};
+      ListDecoder tags = _decoder.getList(Key.TAGS);
+      AstBuilder builder = new AstBuilder(0);
+      for (int i = 0; i < tags.length; i++) {
+        ObjectDecoder dependency = tags.getObject(i);
+        String kind = dependency.getString(Key.KIND);
+        LibraryElement library = dependency.getElement(Key.LIBRARY);
+        // TODO(johnniwinther): Add `ImportElement` and `ExportElement` to the
+        // element model to avoid hacking up nodes.
+        if (kind == 'import') {
+          Import tag = new Import(
+              builder.keywordToken('import'),
+              builder.literalString(library.canonicalUri.toString())
+                  ..getEndToken().next = builder.symbolToken(SEMICOLON_INFO),
+              null, // prefix
+              null, // combinators
+              null, // metadata
+              isDeferred: false);
+          _libraryDependencies[tag] = library;
+        } else if (kind == 'export') {
+          Export tag = new Export(
+              builder.keywordToken('export'),
+              builder.literalString(library.canonicalUri.toString())
+                  ..getEndToken().next = builder.symbolToken(SEMICOLON_INFO),
+              null,  // combinators
+              null); // metadata
+          _libraryDependencies[tag] = library;
+        }
+      }
+    }
+  }
+
+  @override
+  Iterable<LibraryTag> get tags {
+    _ensureLibraryDependencies();
+    return _libraryDependencies.keys;
+  }
+
+  LibraryElement getLibraryFromTag(LibraryDependency tag) {
+    _ensureLibraryDependencies();
+    return _libraryDependencies[tag];
+  }
+
+  @override
+  bool get canUseNative => false;
+
+  @override
+  Element findExported(String elementName) => _unsupported('findExported');
+
+  void _ensureImports() {
+    if (_importsMap == null) {
+      _importsMap = new ListedContainer(_decoder.getElements(Key.IMPORTS));
+    }
+  }
+
+  @override
+  void forEachImport(f(Element element)) {
+    _ensureImports();
+    _importsMap.forEach(f);
+  }
+
+  @override
+  Link<Import> getImportsFor(Element element) => _unsupported('getImportsFor');
+
+  @override
+  LibraryName get libraryTag => _unsupported('libraryTag');
+
+  String toString() {
+    return 'Zlibrary(${canonicalUri})';
+  }
+}
+
+class ScriptZ implements Script {
+  final Uri resourceUri;
+
+  ScriptZ(this.resourceUri);
+
+  @override
+  Script copyWithFile(SourceFile file) {
+    throw new UnsupportedError('ScriptZ.copyWithFile');
+  }
+
+  @override
+  SourceFile get file => throw new UnsupportedError('ScriptZ.file');
+
+  @override
+  bool get isSynthesized => throw new UnsupportedError('ScriptZ.isSynthesized');
+
+  @override
+  String get name => resourceUri.toString();
+
+  // TODO(johnniwinther): Support the distinction between [readableUri] and
+  // [resourceUri]; needed for platform libraries.
+  @override
+  Uri get readableUri => resourceUri;
+
+  @override
+  String get text => throw new UnsupportedError('ScriptZ.text');
+}
+
+class CompilationUnitElementZ extends DeserializedElementZ
+    with LibraryMemberMixin,
+         CompilationUnitElementCommon
+    implements CompilationUnitElement {
+  List<Element> _members;
+  Script _script;
+
+  CompilationUnitElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.COMPILATION_UNIT;
+
+  @override
+  CompilationUnitElement get compilationUnit => this;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitCompilationUnitElement(this, arg);
+  }
+
+  @override
+  void forEachLocalMember(f(Element element)) {
+    if (_members == null) {
+      _members =
+          _decoder.getElements(Key.ELEMENTS, isOptional: true);
+    }
+    _members.forEach(f);
+  }
+
+  @override
+  Script get script {
+    if (_script == null) {
+      Uri resolvedUri = _decoder.getUri(Key.URI);
+      _script = new ScriptZ(resolvedUri);
+    }
+    return _script;
+  }
+
+  @override
+  String get name => script.name;
+}
+
+
+abstract class LibraryMemberMixin implements DeserializedElementZ {
+  LibraryElement _library;
+  CompilationUnitElement _compilationUnit;
+
+  @override
+  LibraryElement get library {
+    if (_library == null) {
+      _library = _decoder.getElement(Key.LIBRARY);
+    }
+    return _library;
+  }
+
+  @override
+  CompilationUnitElement get compilationUnit {
+    if (_compilationUnit == null) {
+      _compilationUnit = _decoder.getElement(Key.COMPILATION_UNIT);
+    }
+    return _compilationUnit;
+  }
+
+  @override
+  Element get enclosingElement => compilationUnit;
+
+  @override
+  ClassElement get enclosingClass => null;
+
+  @override
+  bool get isTopLevel => true;
+
+  @override
+  bool get isStatic => false;
+}
+
+abstract class ClassMemberMixin implements DeserializedElementZ {
+  ClassElement _class;
+
+  @override
+  Element get enclosingElement => enclosingClass;
+
+  @override
+  ClassElement get enclosingClass {
+    if (_class == null) {
+      _class = _decoder.getElement(Key.CLASS);
+    }
+    return _class;
+  }
+
+  @override
+  bool get isClassMember => true;
+
+  @override
+  LibraryElement get library => enclosingClass.library;
+
+  @override
+  CompilationUnitElement get compilationUnit => enclosingClass.compilationUnit;
+}
+
+abstract class InstanceMemberMixin implements DeserializedElementZ {
+  @override
+  bool get isTopLevel => false;
+
+  @override
+  bool get isStatic => false;
+
+  @override
+  bool get isInstanceMember => true;
+}
+
+abstract class StaticMemberMixin implements DeserializedElementZ {
+  @override
+  bool get isTopLevel => false;
+
+  @override
+  bool get isStatic => true;
+}
+
+abstract class TypedElementMixin
+    implements DeserializedElementZ, TypedElement {
+  DartType _type;
+
+  @override
+  DartType get type {
+    if (_type == null) {
+      _type = _decoder.getType(Key.TYPE);
+    }
+    return _type;
+  }
+
+  @override
+  DartType computeType(Compiler compiler) => type;
+}
+
+abstract class ParametersMixin
+    implements DeserializedElementZ, FunctionTypedElement {
+  FunctionSignature _functionSignature;
+  List<ParameterElement> _parameters;
+
+  bool get hasFunctionSignature => true;
+
+  @override
+  FunctionSignature get functionSignature {
+    if (_functionSignature == null) {
+      List<Element> requiredParameters = [];
+      List<Element> optionalParameters = [];
+      List orderedOptionalParameters = [];
+      int requiredParameterCount = 0;
+      int optionalParameterCount = 0;
+      bool optionalParametersAreNamed = false;
+      List<DartType> parameterTypes = <DartType>[];
+      List<DartType> optionalParameterTypes = <DartType>[];
+      List<String> namedParameters = <String>[];
+      List<DartType> namedParameterTypes = <DartType>[];
+      for (ParameterElement parameter in parameters) {
+        if (parameter.isOptional) {
+          optionalParameterCount++;
+          requiredParameters.add(parameter);
+          orderedOptionalParameters.add(parameter);
+          if (parameter.isNamed) {
+            optionalParametersAreNamed = true;
+            namedParameters.add(parameter.name);
+            namedParameterTypes.add(parameter.type);
+          } else {
+            optionalParameterTypes.add(parameter.type);
+          }
+        } else {
+          requiredParameterCount++;
+          optionalParameters.add(parameter);
+          parameterTypes.add(parameter.type);
+        }
+      }
+      if (optionalParametersAreNamed) {
+        orderedOptionalParameters.sort((Element a, Element b) {
+            return a.name.compareTo(b.name);
+        });
+      }
+
+      FunctionType type = new FunctionType(
+          this,
+          _decoder.getType(Key.RETURN_TYPE),
+          parameterTypes,
+          optionalParameterTypes,
+          namedParameters,
+          namedParameterTypes);
+      _functionSignature = new FunctionSignatureX(
+          requiredParameters: requiredParameters,
+          requiredParameterCount: requiredParameterCount,
+          optionalParameters: optionalParameters,
+          optionalParameterCount: optionalParameterCount,
+          optionalParametersAreNamed: optionalParametersAreNamed,
+          orderedOptionalParameters: orderedOptionalParameters,
+          type: type);
+    }
+    return _functionSignature;
+  }
+
+  List<ParameterElement> get parameters {
+    if (_parameters == null) {
+      _parameters = _decoder.getElements(Key.PARAMETERS, isOptional: true);
+    }
+    return _parameters;
+  }
+}
+
+abstract class FunctionTypedElementMixin
+    implements FunctionElement, DeserializedElementZ {
+  @override
+  AsyncMarker get asyncMarker => _unsupported('');
+
+  @override
+  bool get isExternal => _unsupported('');
+
+  @override
+  FunctionElement asFunctionElement() => this;
+}
+
+class ClassElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         ClassElementCommon,
+         class_members.ClassMemberMixin,
+         ContainerMixin,
+         LibraryMemberMixin,
+         TypeDeclarationMixin<InterfaceType>
+    implements ClassElement {
+  bool _isObject;
+  DartType _supertype;
+  OrderedTypeSet _allSupertypesAndSelf;
+  Link<DartType> _interfaces;
+
+  ClassElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  InterfaceType _createType(List<DartType> typeArguments) {
+    return new InterfaceType(this, typeArguments);
+  }
+
+  @override
+  ElementKind get kind => ElementKind.CLASS;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitClassElement(this, arg);
+  }
+
+  @override
+  DartType get supertype {
+    if (_isObject == null) {
+      _supertype = _decoder.getType(Key.SUPERTYPE, isOptional: true);
+      _isObject = _supertype == null;
+    }
+    return _supertype;
+  }
+
+  @override
+  bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);
+
+  @override
+  bool get isObject {
+    return supertype == null;
+  }
+
+  @override
+  void addBackendMember(Element element) => _unsupported('addBackendMember');
+
+  @override
+  OrderedTypeSet get allSupertypesAndSelf {
+    if (_allSupertypesAndSelf == null) {
+      ObjectDecoder supertypesDeserializer =
+          _decoder.getObject(Key.SUPERTYPES);
+      List<int> offsets = supertypesDeserializer.getInts(Key.OFFSETS);
+      List<Link<DartType>> levels = new List<Link<DartType>>(offsets.length);
+      LinkBuilder<DartType> typesBuilder = new LinkBuilder<DartType>();
+      int offset = 0;
+      int depth = offsets.length - 1;
+      for (DartType type in supertypesDeserializer.getTypes(Key.TYPES)) {
+        Link<DartType> link = typesBuilder.addLast(type);
+        if (offsets[depth] == offset) {
+          levels[depth] = link;
+          depth--;
+        }
+        offset++;
+      }
+      LinkBuilder<DartType> supertypesBuilder = new LinkBuilder<DartType>();
+      for (DartType supertype in
+          supertypesDeserializer.getTypes(Key.SUPERTYPES, isOptional: true)) {
+        supertypesBuilder.addLast(supertype);
+      }
+      Link<DartType> types = typesBuilder.toLink();
+      Link<DartType> supertypes = supertypesBuilder.toLink();
+      _allSupertypesAndSelf = new OrderedTypeSet.internal(
+          levels, types, supertypes);
+    }
+    return _allSupertypesAndSelf;
+  }
+
+  @override
+  void forEachBackendMember(void f(Element member)) {
+    _unsupported('forEachBackendMember');
+  }
+
+  @override
+  bool get hasBackendMembers => _unsupported('hasBackendMembers');
+
+  @override
+  bool get hasConstructor => _unsupported('hasConstructor');
+
+  @override
+  bool hasFieldShadowedBy(Element fieldMember) => _unsupported('');
+
+  @override
+  bool get hasIncompleteHierarchy => _unsupported('hasIncompleteHierarchy');
+
+  @override
+  bool get hasLocalScopeMembers => _unsupported('hasLocalScopeMembers');
+
+  @override
+  bool implementsFunction(Compiler compiler) {
+    return _unsupported('implementsFunction');
+  }
+
+  @override
+  Link<DartType> get interfaces {
+    if (_interfaces == null) {
+      _interfaces = toLink(
+          _decoder.getTypes(Key.INTERFACES, isOptional: true));
+    }
+    return _interfaces;
+  }
+
+  @override
+  bool get isEnumClass => false;
+
+  @override
+  bool get isProxy => _unsupported('isProxy');
+
+  @override
+  bool get isUnnamedMixinApplication {
+    return _unsupported('isUnnamedMixinApplication');
+  }
+
+  @override
+  Element lookupBackendMember(String memberName) {
+    return _unsupported('lookupBackendMember');
+  }
+
+  @override
+  ConstructorElement lookupDefaultConstructor() {
+    ConstructorElement constructor = lookupConstructor("");
+    if (constructor != null && constructor.parameters.isEmpty) {
+      return constructor;
+    }
+    return null;
+  }
+
+  @override
+  String get nativeTagInfo => _unsupported('nativeTagInfo');
+
+  @override
+  void reverseBackendMembers() => _unsupported('reverseBackendMembers');
+
+  @override
+  ClassElement get superclass => supertype != null ? supertype.element : null;
+}
+
+abstract class ConstructorElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         ClassMemberMixin,
+         FunctionTypedElementMixin,
+         ParametersMixin,
+         TypedElementMixin,
+         MemberElementMixin
+    implements ConstructorElement {
+  ConstantConstructor _constantConstructor;
+
+  ConstructorElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitConstructorElement(this, arg);
+  }
+
+  @override
+  bool get isConst => _decoder.getBool(Key.IS_CONST);
+
+  @override
+  bool get isExternal => _decoder.getBool(Key.IS_EXTERNAL);
+
+  bool get isFromEnvironmentConstructor {
+    return name == 'fromEnvironment' &&
+           library.isDartCore &&
+           (enclosingClass.name == 'bool' ||
+            enclosingClass.name == 'int' ||
+            enclosingClass.name == 'String');
+  }
+
+  ConstantConstructor get constantConstructor {
+    if (isConst && _constantConstructor == null) {
+      ObjectDecoder data =
+          _decoder.getObject(Key.CONSTRUCTOR, isOptional: true);
+      if (data == null) {
+        assert(isFromEnvironmentConstructor || isExternal);
+        return null;
+      }
+      _constantConstructor = ConstantConstructorDeserializer.deserialize(data);
+    }
+    return _constantConstructor;
+  }
+
+  @override
+  AsyncMarker get asyncMarker => _unsupported('asyncMarker');
+
+  @override
+  InterfaceType computeEffectiveTargetType(InterfaceType newType) {
+    return _unsupported('computeEffectiveTargetType');
+  }
+
+  @override
+  ConstructorElement get definingConstructor  {
+    return _unsupported('definingConstructor');
+  }
+
+  @override
+  ConstructorElement get effectiveTarget  {
+    return _unsupported('effectiveTarget');
+  }
+
+  @override
+  ConstructorElement get immediateRedirectionTarget  {
+    return _unsupported('immediateRedirectionTarget');
+  }
+
+  @override
+  bool get isRedirectingFactory => _unsupported('isRedirectingFactory');
+
+  @override
+  bool get isRedirectingGenerative => _unsupported('isRedirectingGenerative');
+
+  @override
+  bool get isCyclicRedirection => _unsupported('isCyclicRedirection');
+
+  @override
+  PrefixElement get redirectionDeferredPrefix  {
+    return _unsupported('redirectionDeferredPrefix');
+  }
+}
+
+class GenerativeConstructorElementZ extends ConstructorElementZ {
+  GenerativeConstructorElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.GENERATIVE_CONSTRUCTOR;
+}
+
+class FactoryConstructorElementZ extends ConstructorElementZ {
+
+  FactoryConstructorElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.FUNCTION;
+
+  @override
+  bool get isFactoryConstructor => true;
+}
+
+abstract class MemberElementMixin
+    implements DeserializedElementZ, MemberElement {
+
+  @override
+  MemberElement get memberContext => this;
+
+  @override
+  Name get memberName => new Name(name, library);
+
+  @override
+  List<FunctionElement> get nestedClosures => const <FunctionElement>[];
+
+}
+
+abstract class FieldElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         TypedElementMixin,
+         MemberElementMixin
+    implements FieldElement {
+  ConstantExpression _constant;
+
+  FieldElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.FIELD;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitFieldElement(this, arg);
+  }
+
+  @override
+  bool get isFinal => _decoder.getBool(Key.IS_FINAL);
+
+  @override
+  bool get isConst => _decoder.getBool(Key.IS_CONST);
+
+  @override
+  ConstantExpression get constant {
+    if (isConst && _constant == null) {
+      _constant = _decoder.getConstant(Key.CONSTANT);
+    }
+    return _constant;
+  }
+
+  @override
+  Expression get initializer => _unsupported('initializer');
+}
+
+
+class TopLevelFieldElementZ extends FieldElementZ with LibraryMemberMixin {
+  TopLevelFieldElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class StaticFieldElementZ extends FieldElementZ
+    with ClassMemberMixin, StaticMemberMixin {
+  StaticFieldElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class InstanceFieldElementZ extends FieldElementZ
+    with ClassMemberMixin, InstanceMemberMixin {
+  InstanceFieldElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+abstract class FunctionElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         ParametersMixin,
+         FunctionTypedElementMixin,
+         TypedElementMixin,
+         MemberElementMixin
+    implements MethodElement {
+  FunctionElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.FUNCTION;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitFunctionElement(this, arg);
+  }
+
+  @override
+  bool get isOperator => _decoder.getBool(Key.IS_OPERATOR);
+}
+
+class TopLevelFunctionElementZ extends FunctionElementZ
+    with LibraryMemberMixin {
+  TopLevelFunctionElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class StaticFunctionElementZ extends FunctionElementZ
+    with ClassMemberMixin, StaticMemberMixin {
+  StaticFunctionElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class InstanceFunctionElementZ extends FunctionElementZ
+    with ClassMemberMixin, InstanceMemberMixin {
+  InstanceFunctionElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+abstract class GetterElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         FunctionTypedElementMixin,
+         ParametersMixin,
+         TypedElementMixin,
+         MemberElementMixin
+    implements FunctionElement {
+
+  GetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.GETTER;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitFunctionElement(this, arg);
+  }
+}
+
+class TopLevelGetterElementZ extends GetterElementZ with LibraryMemberMixin {
+  TopLevelGetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class StaticGetterElementZ extends GetterElementZ
+    with ClassMemberMixin, StaticMemberMixin {
+  StaticGetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class InstanceGetterElementZ extends GetterElementZ
+    with ClassMemberMixin, InstanceMemberMixin {
+  InstanceGetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+abstract class SetterElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         FunctionTypedElementMixin,
+         ParametersMixin,
+         TypedElementMixin,
+         MemberElementMixin
+    implements FunctionElement {
+
+  SetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.SETTER;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitFunctionElement(this, arg);
+  }
+}
+
+class TopLevelSetterElementZ extends SetterElementZ with LibraryMemberMixin {
+  TopLevelSetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class StaticSetterElementZ extends SetterElementZ
+    with ClassMemberMixin, StaticMemberMixin {
+  StaticSetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+class InstanceSetterElementZ extends SetterElementZ
+    with ClassMemberMixin, InstanceMemberMixin {
+  InstanceSetterElementZ(ObjectDecoder decoder)
+      : super(decoder);
+}
+
+abstract class TypeDeclarationMixin<T extends GenericType>
+    implements DeserializedElementZ, TypeDeclarationElement {
+  List<DartType> _typeVariables;
+  T _rawType;
+  T _thisType;
+
+  void _ensureTypes() {
+    if (_typeVariables == null) {
+      _typeVariables = _decoder.getTypes(
+          Key.TYPE_VARIABLES, isOptional: true);
+      _rawType = _createType(new List<DartType>.filled(
+          _typeVariables.length, const DynamicType()));
+      _thisType = _createType(_typeVariables);
+    }
+  }
+
+  T _createType(List<DartType> typeArguments);
+
+  @override
+  List<DartType> get typeVariables {
+    _ensureTypes();
+    return _typeVariables;
+  }
+
+  @override
+  T get rawType {
+    _ensureTypes();
+    return _rawType;
+  }
+
+  @override
+  T get thisType {
+    _ensureTypes();
+    return _thisType;
+  }
+
+  @override
+  T computeType(Compiler compiler) => thisType;
+
+  @override
+  bool get isResolved => true;
+
+  @override
+  void ensureResolved(Compiler compiler) {}
+}
+
+class TypedefElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         LibraryMemberMixin,
+         ParametersMixin,
+         TypeDeclarationMixin<TypedefType>
+    implements TypedefElement {
+  DartType _alias;
+
+  TypedefElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  TypedefType _createType(List<DartType> typeArguments) {
+    return new TypedefType(this, typeArguments);
+  }
+
+  @override
+  ElementKind get kind => ElementKind.TYPEDEF;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitTypedefElement(this, arg);
+  }
+
+  @override
+  DartType get alias {
+    if (_alias == null) {
+      _alias = _decoder.getType(Key.ALIAS);
+    }
+    return _alias;
+  }
+
+  @override
+  void checkCyclicReference(Compiler compiler) {}
+}
+
+class TypeVariableElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         TypedElementMixin
+    implements TypeVariableElement {
+  TypeDeclarationElement _typeDeclaration;
+  TypeVariableType _type;
+  DartType _bound;
+
+  TypeVariableElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  ElementKind get kind => ElementKind.TYPE_VARIABLE;
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitTypeVariableElement(this, arg);
+  }
+
+  @override
+  CompilationUnitElement get compilationUnit {
+    return typeDeclaration.compilationUnit;
+  }
+
+  @override
+  Element get enclosingElement => typeDeclaration;
+
+  @override
+  Element get enclosingClass => typeDeclaration;
+
+  @override
+  int get index => _decoder.getInt(Key.INDEX);
+
+  @override
+  TypeDeclarationElement get typeDeclaration {
+    if (_typeDeclaration == null) {
+      _typeDeclaration =
+          _decoder.getElement(Key.TYPE_DECLARATION);
+    }
+    return _typeDeclaration;
+  }
+
+  DartType get bound {
+    if (_bound == null) {
+      _bound = _decoder.getType(Key.BOUND);
+    }
+    return _bound;
+  }
+
+  @override
+  LibraryElement get library => typeDeclaration.library;
+}
+
+class ParameterElementZ extends DeserializedElementZ
+    with AnalyzableElementMixin,
+         AstElementMixin,
+         TypedElementMixin
+    implements ParameterElement {
+  FunctionElement _functionDeclaration;
+  ConstantExpression _constant;
+  DartType _type;
+
+  ParameterElementZ(ObjectDecoder decoder) : super(decoder);
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitParameterElement(this, arg);
+  }
+
+  @override
+  ConstantExpression get constant {
+    if (isOptional) {
+      if (_constant == null) {
+        _constant = _decoder.getConstant(Key.CONSTANT);
+      }
+      return _constant;
+    }
+    return null;
+  }
+
+  @override
+  CompilationUnitElement get compilationUnit {
+    return functionDeclaration.compilationUnit;
+  }
+
+  @override
+  ExecutableElement get executableContext => functionDeclaration;
+
+  @override
+  Element get enclosingElement => functionDeclaration;
+
+  @override
+  FunctionElement get functionDeclaration {
+    if (_functionDeclaration == null) {
+      _functionDeclaration = _decoder.getElement(Key.FUNCTION);
+    }
+    return _functionDeclaration;
+  }
+
+  @override
+  FunctionSignature get functionSignature => _unsupported('functionSignature');
+
+  @override
+  Expression get initializer => _unsupported('initializer');
+
+  @override
+  bool get isNamed => _decoder.getBool(Key.IS_NAMED);
+
+  @override
+  bool get isOptional => _decoder.getBool(Key.IS_OPTIONAL);
+
+  @override
+  ElementKind get kind => ElementKind.PARAMETER;
+
+  @override
+  LibraryElement get library => executableContext.library;
+
+  @override
+  MemberElement get memberContext => executableContext.memberContext;
+}
+
+
+class InitializingFormalElementZ extends ParameterElementZ
+    implements InitializingFormalElement {
+  FieldElement _fieldElement;
+
+  InitializingFormalElementZ(ObjectDecoder decoder)
+      : super(decoder);
+
+  @override
+  FieldElement get fieldElement {
+    if (_fieldElement == null) {
+      _fieldElement = _decoder.getElement(Key.FIELD);
+    }
+    return _fieldElement;
+  }
+
+  @override
+  accept(ElementVisitor visitor, arg) {
+    return visitor.visitFieldParameterElement(this, arg);
+  }
+
+  @override
+  ElementKind get kind => ElementKind.INITIALIZING_FORMAL;
+
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
new file mode 100644
index 0000000..5a818ce
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -0,0 +1,864 @@
+// 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.serialization;
+
+import '../elements/elements.dart';
+import '../constants/expressions.dart';
+import '../dart_types.dart';
+
+import 'element_serialization.dart';
+import 'constant_serialization.dart';
+import 'type_serialization.dart';
+import 'keys.dart';
+import 'json_serializer.dart';
+import 'values.dart';
+
+/// An object that supports the encoding an [ObjectValue] for serialization.
+///
+/// The [ObjectEncoder] ensures that nominality and circularities of
+/// non-primitive values like [Element], [DartType] and [ConstantExpression] are
+/// handled.
+class ObjectEncoder extends AbstractEncoder<Key> {
+  /// Creates an [ObjectEncoder] in the scope of [serializer] that uses [map]
+  /// as its internal storage.
+  ObjectEncoder(Serializer serializer, Map<dynamic, Value> map)
+        : super(serializer, map);
+
+  String get _name => 'Object';
+}
+
+/// An object that supports the encoding a [MapValue] for serialization.
+///
+/// The [MapEncoder] ensures that nominality and circularities of
+/// non-primitive values like [Element], [DartType] and [ConstantExpression] are
+/// handled.
+class MapEncoder extends AbstractEncoder<String> {
+  /// Creates an [MapEncoder] in the scope of [serializer] that uses [map]
+  /// as its internal storage.
+  MapEncoder(Serializer serializer, Map<String, Value> map)
+      : super(serializer, map);
+
+  String get _name => 'Map';
+}
+
+/// An object that supports the encoding a [ListValue] containing [ObjectValue]s
+/// or [MapValue]s.
+///
+/// The [ListEncoder] ensures that nominality and circularities of
+/// non-primitive values like [Element], [DartType] and [ConstantExpression] are
+/// handled.
+class ListEncoder {
+  final Serializer _serializer;
+  final List<Value> _list;
+
+  /// Creates an [ListEncoder] in the scope of [_serializer] that uses [_list]
+  /// as its internal storage.
+  ListEncoder(this._serializer, this._list);
+
+  /// Creates an [ObjectEncoder] and adds it to the encoded list.
+  ObjectEncoder createObject() {
+    Map<Key, Value> map = <Key, Value>{};
+    _list.add(new ObjectValue(map));
+    return new ObjectEncoder(_serializer, map);
+  }
+
+  /// Creates an [ObjectEncoder] and adds it to the encoded list.
+  MapEncoder createMap() {
+    Map<String, Value> map = {};
+    _list.add(new MapValue(map));
+    return new MapEncoder(_serializer, map);
+  }
+}
+
+/// Abstract base implementation for [ObjectEncoder] and [MapEncoder].
+abstract class AbstractEncoder<K> {
+  final Serializer _serializer;
+  final Map<K, Value> _map;
+
+  AbstractEncoder(this._serializer, this._map);
+
+  /// The name of the encoder kind. Use for error reporting.
+  String get _name;
+
+  void _checkKey(K key) {
+    if (_map.containsKey(key)) {
+      throw new StateError("$_name value '$key' already in $_map.");
+    }
+  }
+
+  /// Maps the [key] entry to the enum [value] in the encoded object.
+  void setEnum(K key, var value) {
+    _checkKey(key);
+    _map[key] = new EnumValue(value);
+  }
+
+  /// Maps the [key] entry to the [element] in the encoded object.
+  void setElement(K key, Element element) {
+    _checkKey(key);
+    _map[key] = _serializer.createElementValue(element);
+  }
+
+  /// Maps the [key] entry to the [elements] in the encoded object.
+  ///
+  /// If [elements] is empty, it is skipped.
+  void setElements(K key, Iterable<Element> elements) {
+    _checkKey(key);
+    if (elements.isNotEmpty) {
+      _map[key] = new ListValue(
+          elements.map(_serializer.createElementValue).toList());
+    }
+  }
+
+  /// Maps the [key] entry to the [constant] in the encoded object.
+  void setConstant(K key, ConstantExpression constant) {
+    _checkKey(key);
+    _map[key] = _serializer.createConstantValue(constant);
+  }
+
+  /// Maps the [key] entry to the [constants] in the encoded object.
+  ///
+  /// If [constants] is empty, it is skipped.
+  void setConstants(K key, Iterable<ConstantExpression> constants) {
+    _checkKey(key);
+    if (constants.isNotEmpty) {
+      _map[key] = new ListValue(
+          constants.map(_serializer.createConstantValue).toList());
+    }
+  }
+
+  /// Maps the [key] entry to the [type] in the encoded object.
+  void setType(K key, DartType type) {
+    _checkKey(key);
+    _map[key] = _serializer.createTypeValue(type);
+  }
+
+  /// Maps the [key] entry to the [types] in the encoded object.
+  ///
+  /// If [types] is empty, it is skipped.
+  void setTypes(K key, Iterable<DartType> types) {
+    _checkKey(key);
+    if (types.isNotEmpty) {
+      _map[key] =
+          new ListValue(types.map(_serializer.createTypeValue).toList());
+    }
+  }
+
+  /// Maps the [key] entry to the [uri] in the encoded object using [baseUri] to
+  /// relatives the encoding.
+  ///
+  /// For instance, a source file like `sdk/lib/core/string.dart` should be
+  /// serialized relative to the library root.
+  void setUri(K key, Uri baseUri, Uri uri) {
+    _checkKey(key);
+    _map[key] = new UriValue(baseUri, uri);
+  }
+
+  /// Maps the [key] entry to the string [value] in the encoded object.
+  void setString(K key, String value) {
+    _checkKey(key);
+    _map[key] = new StringValue(value);
+  }
+
+  /// Maps the [key] entry to the string [values] in the encoded object.
+  ///
+  /// If [values] is empty, it is skipped.
+  void setStrings(K key, Iterable<String> values) {
+    _checkKey(key);
+    if (values.isNotEmpty) {
+      _map[key] = new ListValue(values.map((v) => new StringValue(v)).toList());
+    }
+  }
+
+  /// Maps the [key] entry to the bool [value] in the encoded object.
+  void setBool(K key, bool value) {
+    _checkKey(key);
+    _map[key] = new BoolValue(value);
+  }
+
+  /// Maps the [key] entry to the int [value] in the encoded object.
+  void setInt(K key, int value) {
+    _checkKey(key);
+    _map[key] = new IntValue(value);
+  }
+
+  /// Maps the [key] entry to the int [values] in this serializer.
+  ///
+  /// If [values] is empty, it is skipped.
+  void setInts(K key, Iterable<int> values) {
+    _checkKey(key);
+    if (values.isNotEmpty) {
+      _map[key] = new ListValue(values.map((v) => new IntValue(v)).toList());
+    }
+  }
+
+  /// Maps the [key] entry to the double [value] in the encoded object.
+  void setDouble(K key, double value) {
+    _checkKey(key);
+    _map[key] = new DoubleValue(value);
+  }
+
+  /// Creates and returns an [ObjectEncoder] that is mapped to the [key]
+  /// entry in the encoded object.
+  ObjectEncoder createObject(K key) {
+    Map<Key, Value> map = <Key, Value>{};
+    _map[key] = new ObjectValue(map);
+    return new ObjectEncoder(_serializer, map);
+  }
+
+  /// Creates and returns a [MapEncoder] that is mapped to the [key] entry
+  /// in the encoded object.
+  MapEncoder createMap(K key) {
+    Map<String, Value> map = <String, Value>{};
+    _map[key] = new MapValue(map);
+    return new MapEncoder(_serializer, map);
+  }
+
+  /// Creates and returns a [ListEncoder] that is mapped to the [key] entry
+  /// in the encoded object.
+  ListEncoder createList(K key) {
+    List<Value> list = <Value>[];
+    _map[key] = new ListValue(list);
+    return new ListEncoder(_serializer, list);
+  }
+
+  String toString() => _map.toString();
+}
+
+/// [ObjectDecoder] reads serialized values from a [Map] encoded from an
+/// [ObjectValue] where properties are stored using [Key] values as keys.
+class ObjectDecoder extends AbstractDecoder<Key> {
+  /// Creates an [ObjectDecoder] that decodes [map] into deserialized values
+  /// using [deserializer] to create canonicalized values.
+  ObjectDecoder(Deserializer deserializer, Map map)
+      : super(deserializer, map);
+
+  @override
+  _getKeyValue(Key key) => _deserializer.decoder.getObjectPropertyValue(key);
+}
+
+/// [MapDecoder] reads serialized values from a [Map] encoded from an
+/// [MapValue] where entries are stored using [String] values as keys.
+class MapDecoder extends AbstractDecoder<String> {
+  /// Creates an [MapDecoder] that decodes [map] into deserialized values
+  /// using [deserializer] to create canonicalized values.
+  MapDecoder(Deserializer deserializer, Map<String, dynamic> map)
+      : super(deserializer, map);
+
+  @override
+  _getKeyValue(String key) => key;
+
+  /// Applies [f] to every key in the decoded [Map].
+  void forEachKey(f(String key)) {
+    _map.keys.forEach(f);
+  }
+}
+
+/// [ListDecoder] reads serialized map or object values from a [List].
+class ListDecoder {
+  final Deserializer _deserializer;
+  final List _list;
+
+  /// Creates a [ListDecoder] that decodes [_list] using [_deserializer] to
+  /// create canonicalized values.
+  ListDecoder(this._deserializer, this._list);
+
+  /// The number of values in the decoded list.
+  int get length => _list.length;
+
+  /// Returns an [ObjectDecoder] for the [index]th object value in the decoded
+  /// list.
+  ObjectDecoder getObject(int index) {
+    return new ObjectDecoder(_deserializer, _list[index]);
+  }
+
+  /// Returns an [MapDecoder] for the [index]th map value in the decoded list.
+  MapDecoder getMap(int index) {
+    return new MapDecoder(_deserializer, _list[index]);
+  }
+}
+
+/// Abstract base implementation for [ObjectDecoder] and [MapDecoder].
+abstract class AbstractDecoder<K> {
+  final Deserializer _deserializer;
+  final Map<K, dynamic> _map;
+
+  AbstractDecoder(this._deserializer, this._map) {
+    assert(_deserializer != null);
+    assert(_map != null);
+  }
+
+  /// Returns the value for [key] defined by the [SerializationDecoder] in used
+  /// [_deserializer].
+  _getKeyValue(K key);
+
+  /// Returns `true` if [key] has an associated value in the decoded object.
+  bool containsKey(K key) => _map.containsKey(_getKeyValue(key));
+
+  /// Returns the enum value from the [enumValues] associated with [key] in the
+  /// decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  getEnum(K key, List enumValues, {bool isOptional: false, defaultValue}) {
+    int value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("enum value '$key' not found in $_map.");
+    }
+    return enumValues[value];
+  }
+
+  /// Returns the [Element] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  Element getElement(K key, {bool isOptional: false}) {
+    int id = _map[_getKeyValue(key)];
+    if (id == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("Element value '$key' not found in $_map.");
+    }
+    return _deserializer.deserializeElement(id);
+  }
+
+  /// Returns the list of [Element] values associated with [key] in the decoded
+  /// object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// and empty [List] is returned, otherwise an exception is thrown.
+  List<Element> getElements(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return const [];
+      }
+      throw new StateError("Elements value '$key' not found in $_map.");
+    }
+    return list.map(_deserializer.deserializeElement).toList();
+  }
+
+  /// Returns the [ConstantExpression] value associated with [key] in the
+  /// decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  ConstantExpression getConstant(K key, {bool isOptional: false}) {
+    int id = _map[_getKeyValue(key)];
+    if (id == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("Constant value '$key' not found in $_map.");
+    }
+    return _deserializer.deserializeConstant(id);
+  }
+
+  /// Returns the list of [ConstantExpression] values associated with [key] in
+  /// the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// and empty [List] is returned, otherwise an exception is thrown.
+  List<ConstantExpression> getConstants(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return const [];
+      }
+      throw new StateError("Constants value '$key' not found in $_map.");
+    }
+    return list.map(_deserializer.deserializeConstant).toList();
+  }
+
+  /// Returns the [DartType] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  DartType getType(K key, {bool isOptional: false}) {
+    int id = _map[_getKeyValue(key)];
+    if (id == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("Type value '$key' not found in $_map.");
+    }
+    return _deserializer.deserializeType(id);
+  }
+
+  /// Returns the list of [DartType] values associated with [key] in the decoded
+  /// object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// and empty [List] is returned, otherwise an exception is thrown.
+  List<DartType> getTypes(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return const [];
+      }
+      throw new StateError("Types value '$key' not found in $_map.");
+    }
+    return list.map(_deserializer.deserializeType).toList();
+  }
+
+  /// Returns the [Uri] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  Uri getUri(K key, {bool isOptional: false, Uri defaultValue}) {
+    String value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("Uri value '$key' not found in $_map.");
+    }
+    return Uri.parse(value);
+  }
+
+  /// Returns the [String] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  String getString(K key, {bool isOptional: false, String defaultValue}) {
+    String value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("String value '$key' not found in $_map.");
+    }
+    return value;
+  }
+
+  /// Returns the list of [String] values associated with [key] in the decoded
+  /// object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// and empty [List] is returned, otherwise an exception is thrown.
+  List<String> getStrings(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return const [];
+      }
+      throw new StateError("Strings value '$key' not found in $_map.");
+    }
+    return list;
+  }
+
+  /// Returns the [bool] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  bool getBool(K key, {bool isOptional: false, bool defaultValue}) {
+    bool value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("bool value '$key' not found in $_map.");
+    }
+    return value;
+  }
+
+  /// Returns the [int] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  int getInt(K key, {bool isOptional: false, int defaultValue}) {
+    int value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("int value '$key' not found in $_map.");
+    }
+    return value;
+  }
+
+  /// Returns the list of [int] values associated with [key] in the decoded
+  /// object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// and empty [List] is returned, otherwise an exception is thrown.
+  List<int> getInts(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return const [];
+      }
+      throw new StateError("Ints value '$key' not found in $_map.");
+    }
+    return list;
+  }
+
+  /// Returns the [double] value associated with [key] in the decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// [defaultValue] is returned, otherwise an exception is thrown.
+  double getDouble(K key, {bool isOptional: false, double defaultValue}) {
+    double value = _map[_getKeyValue(key)];
+    if (value == null) {
+      if (isOptional || defaultValue != null) {
+        return defaultValue;
+      }
+      throw new StateError("double value '$key' not found in $_map.");
+    }
+    return value;
+  }
+
+  /// Returns an [ObjectDecoder] for the map value associated with [key] in the
+  /// decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  ObjectDecoder getObject(K key, {bool isOptional: false}) {
+    Map map = _map[_getKeyValue(key)];
+    if (map == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("Object value '$key' not found in $_map.");
+    }
+    return new ObjectDecoder(_deserializer, map);
+  }
+
+  /// Returns an [MapDecoder] for the map value associated with [key] in the
+  /// decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  MapDecoder getMap(K key, {bool isOptional: false}) {
+    Map map = _map[_getKeyValue(key)];
+    if (map == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("Map value '$key' not found in $_map.");
+    }
+    return new MapDecoder(_deserializer, map);
+  }
+
+  /// Returns an [ListDecoder] for the list value associated with [key] in the
+  /// decoded object.
+  ///
+  /// If no value is associated with [key], then if [isOptional] is `true`,
+  /// `null` is returned, otherwise an exception is thrown.
+  ListDecoder getList(K key, {bool isOptional: false}) {
+    List list = _map[_getKeyValue(key)];
+    if (list == null) {
+      if (isOptional) {
+        return null;
+      }
+      throw new StateError("List value '$key' not found in $_map.");
+    }
+    return new ListDecoder(_deserializer, list);
+  }
+}
+
+/// A nominal object containing its serialized value.
+class DataObject {
+  /// The id for the object.
+  final Value id;
+
+  /// The serialized value of the object.
+  final ObjectValue objectValue;
+
+  DataObject(Value id, EnumValue kind)
+      : this.id = id,
+        this.objectValue =
+            new ObjectValue(<Key, Value>{Key.ID: id, Key.KIND: kind});
+
+  Map<Key, Value> get map => objectValue.map;
+}
+
+/// Serializer for the transitive closure of a collection of libraries.
+///
+/// The serializer creates an [ObjectValue] model of the [Element], [DartType]
+/// and [ConstantExpression] values in the transitive closure of the serialized
+/// libraries.
+///
+/// The model layout of the produced [objectValue] is:
+///
+///     { // Header object
+///       Key.ELEMENTS: [
+///         {...}, // [ObjectValue] of the 0th [Element].
+///         ...
+///         {...}, // [ObjectValue] of the n-th [Element].
+///       ],
+///       Key.TYPES: [
+///         {...}, // [ObjectValue] of the 0th [DartType].
+///         ...
+///         {...}, // [ObjectValue] of the n-th [DartType].
+///       ],
+///       Key.CONSTANTS: [
+///         {...}, // [ObjectValue] of the 0th [ConstantExpression].
+///         ...
+///         {...}, // [ObjectValue] of the n-th [ConstantExpression].
+///       ],
+///     }
+///
+// TODO(johnniwinther): Support per-library serialization and dependencies
+// between serialized subcomponent.
+class Serializer {
+  final SerializationEncoder _encoder;
+
+  Map<Element, DataObject> _elementMap = <Element, DataObject>{};
+  Map<ConstantExpression, DataObject> _constantMap =
+      <ConstantExpression, DataObject>{};
+  Map<DartType, DataObject> _typeMap = <DartType, DataObject>{};
+  List _pendingList = [];
+
+  Serializer(this._encoder);
+
+  /// Add the transitive closure of [library] to this serializer.
+  void serialize(LibraryElement library) {
+    // Call [_getElementDataObject] for its side-effect: To create a
+    // [DataObject] for [library]. If not already created, this will
+    // put the serialization of [library] in the work queue.
+    _getElementDataObject(library);
+    _emptyWorklist();
+  }
+
+  void _emptyWorklist() {
+    while (_pendingList.isNotEmpty) {
+      _pendingList.removeLast()();
+    }
+  }
+
+  /// Returns the [DataObject] for [element].
+  ///
+  /// If [constant] has no [DataObject], a new [DataObject] is created and
+  /// encoding the [ObjectValue] for [constant] is put into the work queue of
+  /// this serializer.
+  DataObject _getElementDataObject(Element element) {
+    if (element == null) {
+      throw new ArgumentError('Serializer._getElementDataObject(null)');
+    }
+    return _elementMap.putIfAbsent(element, () {
+      // Run through [ELEMENT_SERIALIZERS] sequentially to find the one that
+      // deals with [element].
+      for (ElementSerializer serializer in ELEMENT_SERIALIZERS) {
+        SerializedElementKind kind = serializer.getSerializedKind(element);
+        if (kind != null) {
+          DataObject dataObject = new DataObject(
+              new IntValue(_elementMap.length), new EnumValue(kind));
+          // Delay the serialization of the element itself to avoid loops, and
+          // to keep the call stack small.
+          _pendingList.add(() {
+            serializer.serialize(
+                element, new ObjectEncoder(this, dataObject.map), kind);
+          });
+          return dataObject;
+        }
+      }
+      throw new UnsupportedError(
+          'Unsupported element: $element (${element.kind})');
+    });
+  }
+
+  /// Creates the [ElementValue] for [element].
+  ///
+  /// If [element] has not already been serialized, it is added to the work
+  /// queue of this serializer.
+  ElementValue createElementValue(Element element) {
+    return new ElementValue(element, _getElementDataObject(element).id);
+  }
+
+  /// Returns the [DataObject] for [constant].
+  ///
+  /// If [constant] has no [DataObject], a new [DataObject] is created and
+  /// encoding the [ObjectValue] for [constant] is put into the work queue of
+  /// this serializer.
+  DataObject _getConstantDataObject(ConstantExpression constant) {
+    return _constantMap.putIfAbsent(constant, () {
+      DataObject dataObject = new DataObject(
+          new IntValue(_constantMap.length), new EnumValue(constant.kind));
+      // Delay the serialization of the constant itself to avoid loops, and to
+      // keep the call stack small.
+      _pendingList.add(() => _encodeConstant(constant, dataObject));
+      return dataObject;
+    });
+  }
+
+  /// Encodes [constant] into the [ObjectValue] of [dataObject].
+  void _encodeConstant(ConstantExpression constant, DataObject dataObject) {
+    const ConstantSerializer().visit(constant,
+        new ObjectEncoder(this, dataObject.map));
+  }
+
+  /// Creates the [ConstantValue] for [constant].
+  ///
+  /// If [constant] has not already been serialized, it is added to the work
+  /// queue of this serializer.
+  ConstantValue createConstantValue(ConstantExpression constant) {
+    return new ConstantValue(constant, _getConstantDataObject(constant).id);
+  }
+
+  /// Returns the [DataObject] for [type].
+  ///
+  /// If [type] has no [DataObject], a new [DataObject] is created and
+  /// encoding the [ObjectValue] for [type] is put into the work queue of this
+  /// serializer.
+  DataObject _getTypeDataObject(DartType type) {
+    return _typeMap.putIfAbsent(type, () {
+      DataObject dataObject = new DataObject(
+          new IntValue(_typeMap.length), new EnumValue(type.kind));
+      // Delay the serialization of the type itself to avoid loops, and to keep
+      // the call stack small.
+      _pendingList.add(() => _encodeType(type, dataObject));
+      return dataObject;
+    });
+  }
+
+  /// Encodes [type] into the [ObjectValue] of [dataObject].
+  void _encodeType(DartType type, DataObject dataObject) {
+    const TypeSerializer().visit(type, new ObjectEncoder(this, dataObject.map));
+  }
+
+  /// Creates the [TypeValue] for [type].
+  ///
+  /// If [type] has not already been serialized, it is added to the work
+  /// queue of this serializer.
+  TypeValue createTypeValue(DartType type) {
+    return new TypeValue(type, _getTypeDataObject(type).id);
+  }
+
+  ObjectValue get objectValue {
+    Map<Key, Value> map = <Key, Value>{};
+    map[Key.ELEMENTS] =
+        new ListValue(_elementMap.values.map((l) => l.objectValue).toList());
+    if (_typeMap.isNotEmpty) {
+      map[Key.TYPES] =
+          new ListValue(_typeMap.values.map((l) => l.objectValue).toList());
+    }
+    if (_constantMap.isNotEmpty) {
+      map[Key.CONSTANTS] =
+          new ListValue(_constantMap.values.map((l) => l.objectValue).toList());
+    }
+    return new ObjectValue(map);
+  }
+
+  String toText() {
+    return _encoder.encode(objectValue);
+  }
+
+  String prettyPrint() {
+    PrettyPrintEncoder encoder = new PrettyPrintEncoder();
+    return encoder.toText(objectValue);
+  }
+}
+
+/// Deserializer for a closed collection of libraries.
+// TODO(johnniwinther): Support per-library deserialization and dependencies
+// between deserialized subcomponent.
+class Deserializer {
+  final SerializationDecoder decoder;
+  ObjectDecoder _headerObject;
+  ListDecoder _elementList;
+  ListDecoder _typeList;
+  ListDecoder _constantList;
+  Map<int, Element> _elementMap = {};
+  Map<int, DartType> _typeMap = {};
+  Map<int, ConstantExpression> _constantMap = {};
+
+  Deserializer.fromText(String text, this.decoder) {
+    _headerObject = new ObjectDecoder(this, decoder.decode(text));
+  }
+
+  /// Returns the [ListDecoder] for the [Element]s in this deserializer.
+  ListDecoder get elements {
+    if (_elementList == null) {
+      _elementList = _headerObject.getList(Key.ELEMENTS);
+    }
+    return _elementList;
+  }
+
+  /// Returns the [ListDecoder] for the [DartType]s in this deserializer.
+  ListDecoder get types {
+    if (_typeList == null) {
+      _typeList = _headerObject.getList(Key.TYPES);
+    }
+    return _typeList;
+  }
+
+  /// Returns the [ListDecoder] for the [ConstantExpression]s in this
+  /// deserializer.
+  ListDecoder get constants {
+    if (_constantList == null) {
+      _constantList = _headerObject.getList(Key.CONSTANTS);
+    }
+    return _constantList;
+  }
+
+  /// Returns the [LibraryElement] for [uri] if part of the deserializer.
+  LibraryElement lookupLibrary(Uri uri) {
+    // TODO(johnniwinther): Libraries should be stored explicitly in the header.
+    ListDecoder list = elements;
+    for (int i = 0; i < list.length; i++) {
+      ObjectDecoder object = list.getObject(i);
+      SerializedElementKind kind =
+          object.getEnum(Key.KIND, SerializedElementKind.values);
+      if (kind == SerializedElementKind.LIBRARY) {
+        Uri libraryUri = object.getUri(Key.CANONICAL_URI);
+        if (libraryUri == uri) {
+          return deserializeElement(object.getInt(Key.ID));
+        }
+      }
+    }
+    return null;
+  }
+
+  /// Returns the deserialized [Element] for [id].
+  Element deserializeElement(int id) {
+    if (id == null) throw new ArgumentError('Deserializer.getElement(null)');
+    return _elementMap.putIfAbsent(id, () {
+      return ElementDeserializer.deserialize(elements.getObject(id));
+    });
+  }
+
+  /// Returns the deserialized [DartType] for [id].
+  DartType deserializeType(int id) {
+    if (id == null) throw new ArgumentError('Deserializer.getType(null)');
+    return _typeMap.putIfAbsent(id, () {
+      return TypeDeserializer.deserialize(types.getObject(id));
+    });
+  }
+
+  /// Returns the deserialized [ConstantExpression] for [id].
+  ConstantExpression deserializeConstant(int id) {
+    if (id == null) throw new ArgumentError('Deserializer.getConstant(null)');
+    return _constantMap.putIfAbsent(id, () {
+      return ConstantDeserializer.deserialize(constants.getObject(id));
+    });
+  }
+}
+
+/// Strategy used by [Serializer] to define the memory and output encoding.
+abstract class SerializationEncoder {
+  /// Encode [objectValue] into text.
+  String encode(ObjectValue objectValue);
+}
+
+/// Strategy used by [Deserializer] for decoding and reading data from a
+/// serialized output.
+abstract class SerializationDecoder {
+  /// Decode [text] into [Map] containing the data corresponding to an encoding
+  /// of the serializer header object.
+  Map decode(String text);
+
+  /// Returns the value used to store [key] as a property in the encoding an
+  /// [ObjectValue].
+  ///
+  /// Different encodings have different restrictions and capabilities as how
+  /// to store a [Key] value. For instance: A JSON encoding needs to convert
+  /// [Key] to a [String] to store it in a JSON object; a Dart encoding can
+  /// choose to store a [Key] as an [int] or as the [Key] itself.
+  getObjectPropertyValue(Key key);
+}
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
new file mode 100644
index 0000000..d82bb7e
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -0,0 +1,69 @@
+// 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.serialization.task;
+
+import '../dart2jslib.dart';
+import '../elements/elements.dart';
+
+/// Task that supports deserialization of elements.
+class SerializationTask extends CompilerTask {
+  SerializationTask(Compiler compiler) : super(compiler);
+
+  DeserializerSystem deserializer;
+
+  String get name => 'Serialization';
+
+  /// Returns the [LibraryElement] for [resolvedUri] if available from
+  /// serialization.
+  LibraryElement readLibrary(Uri resolvedUri) {
+    if (deserializer == null) return null;
+    return deserializer.readLibrary(resolvedUri);
+  }
+
+  /// Returns `true` if [element] has been deserialized.
+  bool isDeserialized(Element element) {
+    return deserializer != null && deserializer.isDeserialized(element);
+  }
+
+  /// Creates the [ResolutionWorkItem] for the deserialized [element].
+  ResolutionWorkItem createResolutionWorkItem(
+      Element element, ItemCompilationContext context) {
+    assert(deserializer != null);
+    assert(isDeserialized(element));
+    return new DeserializedResolutionWorkItem(
+        element, context, deserializer.computeWorldImpact(element));
+  }
+}
+
+/// A [ResolutionWorkItem] for a deserialized element.
+///
+/// This will not resolve the element but only compute the [WorldImpact].
+class DeserializedResolutionWorkItem implements ResolutionWorkItem {
+  final Element element;
+  final ItemCompilationContext compilationContext;
+  final WorldImpact worldImpact;
+  bool _isAnalyzed = false;
+
+  DeserializedResolutionWorkItem(
+      this.element, this.compilationContext, this.worldImpact);
+
+  @override
+  bool get isAnalyzed => _isAnalyzed;
+
+  @override
+  WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
+    _isAnalyzed = true;
+    world.registerResolvedElement(element);
+    return worldImpact;
+  }
+}
+
+/// The interface for a system that supports deserialization of libraries and
+/// elements.
+abstract class DeserializerSystem {
+  LibraryElement readLibrary(Uri resolvedUri);
+  bool isDeserialized(Element element);
+  WorldImpact computeWorldImpact(Element element);
+}
diff --git a/pkg/compiler/lib/src/serialization/type_serialization.dart b/pkg/compiler/lib/src/serialization/type_serialization.dart
new file mode 100644
index 0000000..7ea60ff
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/type_serialization.dart
@@ -0,0 +1,104 @@
+// 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.serialization.types;
+
+import '../dart_types.dart';
+import 'serialization.dart';
+import 'keys.dart';
+
+/// Visitor that serializes a [DartType] by encoding it into an [ObjectEncoder].
+///
+/// This class is called from the [Serializer] when a [DartType] needs
+/// serialization. The [ObjectEncoder] ensures that any [Element], and other
+/// [DartType] that the serialized [DartType] depends upon are also serialized.
+class TypeSerializer extends DartTypeVisitor<dynamic, ObjectEncoder> {
+  const TypeSerializer();
+
+  void visitType(DartType type, ObjectEncoder encoder) {
+    throw new UnsupportedError('Unsupported type: $type');
+  }
+
+  void visitVoidType(VoidType type, ObjectEncoder encoder) {}
+
+  void visitTypeVariableType(TypeVariableType type,
+                             ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, type.element);
+  }
+
+  void visitFunctionType(FunctionType type,
+                         ObjectEncoder encoder) {
+    // TODO(johnniwinther): Support encoding of `type.element`.
+    encoder.setType(Key.RETURN_TYPE, type.returnType);
+    encoder.setTypes(Key.PARAMETER_TYPES, type.parameterTypes);
+    encoder.setTypes(
+        Key.OPTIONAL_PARAMETER_TYPES, type.optionalParameterTypes);
+    encoder.setStrings(Key.NAMED_PARAMETERS, type.namedParameters);
+    encoder.setTypes(Key.NAMED_PARAMETER_TYPES, type.namedParameterTypes);
+  }
+
+  void visitMalformedType(MalformedType type, ObjectEncoder encoder) {
+
+  }
+
+  void visitInterfaceType(InterfaceType type, ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, type.element);
+    encoder.setTypes(Key.TYPE_ARGUMENTS, type.typeArguments);
+  }
+
+  void visitTypedefType(TypedefType type, ObjectEncoder encoder) {
+    encoder.setElement(Key.ELEMENT, type.element);
+    encoder.setTypes(Key.TYPE_ARGUMENTS, type.typeArguments);
+  }
+
+  void visitDynamicType(DynamicType type, ObjectEncoder encoder) {}
+}
+
+
+/// Utility class for deserializing [DartType]s.
+///
+/// This is used by the [Deserializer].
+class TypeDeserializer {
+
+  /// Deserializes a [DartType] from an [ObjectDecoder].
+  ///
+  /// The class is called from the [Deserializer] when a [DartType] needs
+  /// deserialization. The [ObjectDecoder] ensures that any [Element], other
+  /// [DartType] that the deserialized [DartType] depends upon are available.
+  static DartType deserialize(ObjectDecoder decoder) {
+    TypeKind typeKind = decoder.getEnum(Key.KIND, TypeKind.values);
+    switch (typeKind) {
+      case TypeKind.INTERFACE:
+        return new InterfaceType(
+            decoder.getElement(Key.ELEMENT),
+            decoder.getTypes(Key.TYPE_ARGUMENTS, isOptional: true));
+      case TypeKind.FUNCTION:
+        // TODO(johnniwinther): Support decoding of `type.element`.
+        return new FunctionType.synthesized(
+            decoder.getType(Key.RETURN_TYPE),
+            decoder.getTypes(Key.PARAMETER_TYPES, isOptional: true),
+            decoder.getTypes(
+                Key.OPTIONAL_PARAMETER_TYPES, isOptional: true),
+            decoder.getStrings(
+                Key.NAMED_PARAMETERS, isOptional: true),
+            decoder.getTypes(
+                Key.NAMED_PARAMETER_TYPES, isOptional: true));
+      case TypeKind.TYPE_VARIABLE:
+        return new TypeVariableType(
+            decoder.getElement(Key.ELEMENT));
+      case TypeKind.TYPEDEF:
+        return new TypedefType(
+            decoder.getElement(Key.ELEMENT),
+            decoder.getTypes(Key.TYPE_ARGUMENTS, isOptional: true));
+      case TypeKind.STATEMENT:
+      case TypeKind.MALFORMED_TYPE:
+        throw new UnsupportedError("Unexpected type kind '${typeKind}.");
+      case TypeKind.DYNAMIC:
+        return const DynamicType();
+      case TypeKind.VOID:
+        return const VoidType();
+    }
+  }
+}
+
diff --git a/pkg/compiler/lib/src/serialization/values.dart b/pkg/compiler/lib/src/serialization/values.dart
new file mode 100644
index 0000000..4e49de4
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/values.dart
@@ -0,0 +1,178 @@
+// 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.
+
+/// Class hiarchy for semantic wrapping of serializable values.
+
+library dart2js.serialization.values;
+
+import '../constants/expressions.dart';
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import 'keys.dart';
+
+/// Intermediate representation of a serializable value.
+///
+/// Serializable values are
+///    * [bool],
+///    * [int],
+///    * [double],
+///    * [String],
+///    * enum values,
+///    * [ConstantExpression],
+///    * [DartType],
+///    * [Element],
+///    * [Uri],
+///    * lists of serializeable values,
+///    * maps from arbitrary strings to serializable values; these are called
+///         `Map` values, and
+///    * maps from [Key] to serializable values; these are called `Object`
+///         values.
+///
+/// The distinction between map and object values is chosen to provide a more
+/// robust and checkable implementation of the latter; since the keys are drawn
+/// from a fixed typed set of values, consistency between serialization and
+/// deserialization is easierly maintained.
+abstract class Value {
+  accept(ValueVisitor visitor, arg);
+}
+
+class ElementValue implements Value {
+  final Element element;
+  final Value id;
+
+  ElementValue(this.element, this.id);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitElement(this, arg);
+
+  String toString() => element.toString();
+}
+
+class TypeValue implements Value  {
+  final DartType type;
+  final Value id;
+
+  TypeValue(this.type, this.id);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitType(this, arg);
+
+  String toString() => type.toString();
+}
+
+class ConstantValue implements Value  {
+  final ConstantExpression constant;
+  final Value id;
+
+  ConstantValue(this.constant, this.id);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitConstant(this, arg);
+
+  String toString() => constant.getText();
+}
+
+abstract class PrimitiveValue implements Value {
+  get value;
+
+  String toString() => value.toString();
+}
+
+class BoolValue extends PrimitiveValue {
+  final bool value;
+
+  BoolValue(this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitBool(this, arg);
+}
+
+class IntValue extends PrimitiveValue {
+  final int value;
+
+  IntValue(this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitInt(this, arg);
+}
+
+class DoubleValue extends PrimitiveValue {
+  final double value;
+
+  DoubleValue(this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitDouble(this, arg);
+}
+
+class StringValue extends PrimitiveValue {
+  final String value;
+
+  StringValue(this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitString(this, arg);
+}
+
+class ObjectValue implements Value {
+  final Map<Key, Value> map;
+
+  ObjectValue(this.map);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitObject(this, arg);
+
+  String toString() => map.toString();
+}
+
+class MapValue implements Value {
+  final Map<String, Value> map;
+
+  MapValue(this.map);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitMap(this, arg);
+
+  String toString() => map.toString();
+}
+
+class ListValue implements Value {
+  final List<Value> values;
+
+  ListValue(this.values);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitList(this, arg);
+
+  String toString() => values.toString();
+}
+
+class EnumValue implements Value {
+  final value;
+
+  EnumValue(this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitEnum(this, arg);
+
+  String toString() => value.toString();
+}
+
+class UriValue implements Value {
+  final Uri baseUri;
+  final Uri value;
+
+  UriValue(this.baseUri, this.value);
+
+  accept(ValueVisitor visitor, arg) => visitor.visitUri(this, arg);
+
+  String toString() => value.toString();
+}
+
+/// Visitor for the [Value] class hierarchy.
+abstract class ValueVisitor<R, A> {
+  R visit(Value value, A arg);
+
+  R visitElement(ElementValue value, A arg);
+  R visitType(TypeValue value, A arg);
+  R visitConstant(ConstantValue value, A arg);
+  R visitBool(BoolValue value, A arg);
+  R visitInt(IntValue value, A arg);
+  R visitDouble(DoubleValue value, A arg);
+  R visitString(StringValue value, A arg);
+  R visitObject(ObjectValue value, A arg);
+  R visitMap(MapValue value, A arg);
+  R visitList(ListValue value, A arg);
+  R visitEnum(EnumValue value, A arg);
+  R visitUri(UriValue value, A arg);
+}
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index b47fc64..cbc6ff3 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -103,6 +103,10 @@
   Future/*<List<int> | String>*/ call(Uri resourceUri);
 
   relativizeUri(Uri uri) => relativize(cwd, uri, isWindows);
+
+  SourceFile getSourceFile(Uri resourceUri) {
+    return sourceFiles[resourceUri];
+  }
 }
 
 class CompilerSourceFileProvider extends SourceFileProvider {
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 07e7793..f866a0f 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -10,7 +10,7 @@
   SsaOptimizerTask optimizer;
 
   SsaFunctionCompiler(JavaScriptBackend backend,
-                      SourceInformationFactory sourceInformationFactory)
+                      SourceInformationStrategy sourceInformationFactory)
       : generator = new SsaCodeGeneratorTask(backend, sourceInformationFactory),
         builder = new SsaBuilderTask(backend, sourceInformationFactory),
         optimizer = new SsaOptimizerTask(backend);
@@ -97,7 +97,7 @@
 class SsaBuilderTask extends CompilerTask {
   final CodeEmitterTask emitter;
   final JavaScriptBackend backend;
-  final SourceInformationFactory sourceInformationFactory;
+  final SourceInformationStrategy sourceInformationFactory;
 
   String get name => 'SSA builder';
 
@@ -480,7 +480,8 @@
    * boxed or stored in a closure then the method generates code to retrieve
    * the value.
    */
-  HInstruction readLocal(Local local) {
+  HInstruction readLocal(Local local,
+                         {SourceInformation sourceInformation}) {
     if (isAccessedDirectly(local)) {
       if (directLocals[local] == null) {
         if (local is TypeVariableElement) {
@@ -500,7 +501,7 @@
           : builder.getTypeOfCapturedVariable(redirect);
       HInstruction fieldGet = new HFieldGet(redirect, receiver, type);
       builder.add(fieldGet);
-      return fieldGet;
+      return fieldGet..sourceInformation = sourceInformation;
     } else if (isBoxed(local)) {
       BoxFieldElement redirect = redirectionMapping[local];
       // In the function that declares the captured variable the box is
@@ -512,14 +513,14 @@
       HInstruction lookup = new HFieldGet(
           redirect, box, builder.getTypeOfCapturedVariable(redirect));
       builder.add(lookup);
-      return lookup;
+      return lookup..sourceInformation = sourceInformation;
     } else {
       assert(isUsedInTryOrGenerator(local));
       HLocalValue localValue = getLocal(local);
       HInstruction instruction = new HLocalGet(
           local, localValue, builder.backend.dynamicType);
       builder.add(instruction);
-      return instruction;
+      return instruction..sourceInformation = sourceInformation;
     }
   }
 
@@ -531,7 +532,8 @@
     return res;
   }
 
-  HLocalValue getLocal(Local local) {
+  HLocalValue getLocal(Local local,
+                       {SourceInformation sourceInformation}) {
     // If the element is a parameter, we already have a
     // HParameterValue for it. We cannot create another one because
     // it could then have another name than the real parameter. And
@@ -541,7 +543,8 @@
 
     return builder.activationVariables.putIfAbsent(local, () {
       JavaScriptBackend backend = builder.backend;
-      HLocalValue localValue = new HLocalValue(local, backend.nonNullType);
+      HLocalValue localValue = new HLocalValue(local, backend.nonNullType)
+          ..sourceInformation = sourceInformation;
       builder.graph.entry.addAtExit(localValue);
       return localValue;
     });
@@ -557,7 +560,8 @@
    * Sets the [element] to [value]. If the element is boxed or stored in a
    * closure then the method generates code to set the value.
    */
-  void updateLocal(Local local, HInstruction value) {
+  void updateLocal(Local local, HInstruction value,
+                   {SourceInformation sourceInformation}) {
     assert(!isStoredInClosureField(local));
     if (isAccessedDirectly(local)) {
       directLocals[local] = value;
@@ -568,11 +572,13 @@
       // Inside the closure the box is stored in a closure-field and cannot
       // be accessed directly.
       HInstruction box = readLocal(redirect.box);
-      builder.add(new HFieldSet(redirect, box, value));
+      builder.add(new HFieldSet(redirect, box, value)
+          ..sourceInformation = sourceInformation);
     } else {
       assert(isUsedInTryOrGenerator(local));
       HLocalValue localValue = getLocal(local);
-      builder.add(new HLocalSet(local, localValue, value));
+      builder.add(new HLocalSet(local, localValue, value)
+          ..sourceInformation = sourceInformation);
     }
   }
 
@@ -1119,7 +1125,7 @@
   SsaBuilder(JavaScriptBackend backend,
              CodegenWorkItem work,
              this.nativeEmitter,
-             SourceInformationFactory sourceInformationFactory)
+             SourceInformationStrategy sourceInformationFactory)
     : this.compiler = backend.compiler,
       this.backend = backend,
       this.constantSystem = backend.constantSystem,
@@ -1129,7 +1135,8 @@
     localsHandler = new LocalsHandler(this, work.element, null);
     sourceElementStack.add(work.element);
     sourceInformationBuilder =
-        sourceInformationFactory.forContext(work.element.implementation);
+        sourceInformationFactory.createBuilderForContext(
+            work.element.implementation);
   }
 
   @override
@@ -1635,17 +1642,19 @@
       if (!backend.operatorEqHandlesNullArgument(functionElement)) {
         handleIf(
             function,
-            () {
+            visitCondition: () {
               HParameterValue parameter = parameters.values.first;
               push(new HIdentity(
                   parameter, graph.addConstantNull(compiler), null,
                   backend.boolType));
             },
-            () {
+            visitThen: () {
+              // TODO(johnniwinther): Add source information.
               closeAndGotoExit(new HReturn(
-                  graph.addConstantBool(false, compiler)));
+                  graph.addConstantBool(false, compiler),
+                  null));
             },
-            null);
+            visitElse: null);
       }
     }
     function.body.accept(this);
@@ -1669,14 +1678,16 @@
 
   HGraph buildLazyInitializer(VariableElement variable) {
     inLazyInitializerExpression = true;
-    ast.Node node = variable.node;
+    ast.VariableDefinitions node = variable.node;
     openFunction(variable, node);
     assert(invariant(variable, variable.initializer != null,
         message: "Non-constant variable $variable has no initializer."));
     visit(variable.initializer);
     HInstruction value = pop();
     value = potentiallyCheckOrTrustType(value, variable.type);
-    closeAndGotoExit(new HReturn(value));
+    ast.SendSet sendSet = node.definitions.nodes.head;
+    closeAndGotoExit(new HReturn(value,
+        sourceInformationBuilder.buildReturn(sendSet.assignmentOperator)));
     return closeFunction();
   }
 
@@ -2179,6 +2190,10 @@
           ssaType,
           constructorArguments,
           instantiatedTypes);
+      if (function != null) {
+        newObject.sourceInformation =
+            sourceInformationBuilder.buildGeneric(function);
+      }
       add(newObject);
     } else {
       // Bulk assign to the initialized fields.
@@ -2332,7 +2347,8 @@
       }
     }
     if (inliningStack.isEmpty) {
-      closeAndGotoExit(new HReturn(newObject));
+      closeAndGotoExit(new HReturn(newObject,
+          sourceInformationBuilder.buildImplicitReturn(functionElement)));
       return closeFunction();
     } else {
       localsHandler.updateLocal(returnLocal, newObject);
@@ -2634,7 +2650,8 @@
     if (throwExpression != null && inliningStack.isEmpty) {
       visitThrowExpression(throwExpression.expression);
       handleInTryStatement();
-      closeAndGotoExit(new HThrow(pop()));
+      closeAndGotoExit(
+          new HThrow(pop(), sourceInformationBuilder.buildThrow(node)));
     } else {
       visit(node.expression);
       pop();
@@ -3129,7 +3146,8 @@
 
     TypeMask type =
         new TypeMask.nonNullExact(compiler.functionClass, compiler.world);
-    push(new HForeignNew(closureClassElement, type, capturedVariables));
+    push(new HForeignNew(closureClassElement, type, capturedVariables)
+        ..sourceInformation = sourceInformationBuilder.buildGeneric(node));
 
     Element methodElement = nestedClosureData.closureElement;
     registry.registerInstantiatedClosure(methodElement);
@@ -3159,16 +3177,23 @@
 
   visitIf(ast.If node) {
     assert(isReachable);
-    handleIf(node,
-             () => visit(node.condition),
-             () => visit(node.thenPart),
-             node.elsePart != null ? () => visit(node.elsePart) : null);
+    handleIf(
+        node,
+        visitCondition: () => visit(node.condition),
+        visitThen: () => visit(node.thenPart),
+        visitElse: node.elsePart != null ? () => visit(node.elsePart) : null,
+        sourceInformation: sourceInformationBuilder.buildIf(node));
   }
 
   void handleIf(ast.Node diagnosticNode,
-                void visitCondition(), void visitThen(), void visitElse()) {
+                {void visitCondition(),
+                 void visitThen(),
+                 void visitElse(),
+                 SourceInformation sourceInformation}) {
     SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode);
-    branchBuilder.handleIf(visitCondition, visitThen, visitElse);
+    branchBuilder.handleIf(
+        visitCondition, visitThen, visitElse,
+        sourceInformation: sourceInformation);
   }
 
   @override
@@ -3199,8 +3224,10 @@
   void visitNot(ast.Send node, ast.Node expression, _) {
     assert(node.argumentsNode is ast.Prefix);
     visit(expression);
-    HNot not = new HNot(popBoolified(), backend.boolType);
-    pushWithPosition(not, node);
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGeneric(node);
+    push(new HNot(popBoolified(), backend.boolType)
+        ..sourceInformation = sourceInformation);
   }
 
   @override
@@ -3225,7 +3252,8 @@
         node,
         elements.getSelector(node),
         elements.getTypeMask(node),
-        [operand]);
+        [operand],
+        sourceInformation: sourceInformationBuilder.buildGeneric(node));
   }
 
   @override
@@ -3259,7 +3287,8 @@
         elements.getSelector(node),
         elements.getTypeMask(node),
         node,
-        location: node.selector);
+        sourceInformation:
+            sourceInformationBuilder.buildGeneric(node.selector));
   }
 
   /// TODO(johnniwinther): Merge [visitBinarySend] with [handleBinary] and
@@ -3269,8 +3298,9 @@
                        Selector selector,
                        TypeMask mask,
                        ast.Send send,
-                       {ast.Node location}) {
-    pushInvokeDynamic(send, selector, mask, [left, right], location: location);
+                       {SourceInformation sourceInformation}) {
+    pushInvokeDynamic(send, selector, mask, [left, right],
+        sourceInformation: sourceInformation);
   }
 
   HInstruction generateInstanceSendReceiver(ast.Send send) {
@@ -3299,7 +3329,8 @@
       HInstruction receiver) {
     assert(Elements.isInstanceSend(send, elements));
     assert(selector.isGetter);
-    pushInvokeDynamic(send, selector, mask, [receiver]);
+    pushInvokeDynamic(send, selector, mask, [receiver],
+        sourceInformation: sourceInformationBuilder.buildGet(send));
   }
 
   /// Inserts a call to checkDeferredIsLoaded for [prefixElement].
@@ -3326,15 +3357,20 @@
   }
 
   void handleInvalidStaticGet(ast.Send node, Element element) {
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGet(node);
     generateThrowNoSuchMethod(
         node,
         noSuchMethodTargetSymbolString(element, 'get'),
-        argumentNodes: const Link<ast.Node>());
+        argumentNodes: const Link<ast.Node>(),
+        sourceInformation: sourceInformation);
   }
 
   /// Generate read access of an unresolved static or top level entity.
   void generateStaticUnresolvedGet(ast.Send node, Element element) {
     if (element is ErroneousElement) {
+      SourceInformation sourceInformation =
+          sourceInformationBuilder.buildGet(node);
       // An erroneous element indicates an unresolved static getter.
       handleInvalidStaticGet(node, element);
     } else {
@@ -3350,7 +3386,8 @@
   void generateStaticConstGet(
       ast.Send node,
       FieldElement field,
-      ConstantExpression constant) {
+      ConstantExpression constant,
+      SourceInformation sourceInformation) {
     ConstantValue value = backend.constants.getConstantValue(constant);
     HConstant instruction;
     // Constants that are referred via a deferred prefix should be referred
@@ -3358,9 +3395,11 @@
     PrefixElement prefix = compiler.deferredLoadTask
         .deferredPrefixElement(node, elements);
     if (prefix != null) {
-      instruction = graph.addDeferredConstant(value, prefix, compiler);
+      instruction =
+          graph.addDeferredConstant(value, prefix, sourceInformation, compiler);
     } else {
-      instruction = graph.addConstant(value, compiler);
+      instruction = graph.addConstant(
+          value, compiler, sourceInformation: sourceInformation);
     }
     stack.add(instruction);
     // The inferrer may have found a better type than the constant
@@ -3382,34 +3421,41 @@
 
     ConstantExpression constant =
         backend.constants.getConstantForVariable(field);
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGet(node);
     if (constant != null) {
       if (!field.isAssignable) {
         // A static final or const. Get its constant value and inline it if
         // the value can be compiled eagerly.
-        generateStaticConstGet(node, field, constant);
+        generateStaticConstGet(node, field, constant, sourceInformation);
       } else {
         // TODO(5346): Try to avoid the need for calling [declaration] before
         // creating an [HStatic].
         HInstruction instruction = new HStatic(
             field.declaration,
-            TypeMaskFactory.inferredTypeForElement(field, compiler));
+            TypeMaskFactory.inferredTypeForElement(field, compiler))
+                ..sourceInformation = sourceInformation;
         push(instruction);
       }
     } else {
       HInstruction instruction = new HLazyStatic(
           field,
-          TypeMaskFactory.inferredTypeForElement(field, compiler));
+          TypeMaskFactory.inferredTypeForElement(field, compiler))
+              ..sourceInformation = sourceInformation;
       push(instruction);
     }
   }
 
   /// Generate a getter invocation of the static or top level [getter].
   void generateStaticGetterGet(ast.Send node, MethodElement getter) {
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGet(node);
     if (getter.isDeferredLoaderGetter) {
-      generateDeferredLoaderGet(node, getter);
+      generateDeferredLoaderGet(node, getter, sourceInformation);
     } else {
       generateIsDeferredLoadedCheckOfSend(node);
-      pushInvokeStatic(node, getter, <HInstruction>[]);
+      pushInvokeStatic(node, getter, <HInstruction>[],
+                       sourceInformation: sourceInformation);
     }
   }
 
@@ -3425,12 +3471,20 @@
     generateIsDeferredLoadedCheckOfSend(node);
     // TODO(5346): Try to avoid the need for calling [declaration] before
     // creating an [HStatic].
-    push(new HStatic(function.declaration, backend.nonNullType));
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGet(node);
+    push(new HStatic(function.declaration, backend.nonNullType)
+        ..sourceInformation = sourceInformation);
   }
 
   /// Read a local variable, function or parameter.
-  void handleLocalGet(LocalElement local) {
-    stack.add(localsHandler.readLocal(local));
+  void buildLocalGet(LocalElement local, SourceInformation sourceInformation) {
+    stack.add(localsHandler.readLocal(
+              local, sourceInformation: sourceInformation));
+  }
+
+  void handleLocalGet(ast.Send node, LocalElement local) {
+    buildLocalGet(local, sourceInformationBuilder.buildGet(node));
   }
 
   @override
@@ -3479,17 +3533,17 @@
 
   @override
   void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
-    handleLocalGet(variable);
+    handleLocalGet(node, variable);
   }
 
   @override
   void visitParameterGet(ast.Send node, ParameterElement parameter, _) {
-    handleLocalGet(parameter);
+    handleLocalGet(node, parameter);
   }
 
   @override
   void visitLocalFunctionGet(ast.Send node, LocalFunctionElement function, _) {
-    handleLocalGet(function);
+    handleLocalGet(node, function);
   }
 
   @override
@@ -3567,7 +3621,8 @@
       location = send;
     }
     assert(selector.isSetter);
-    pushInvokeDynamic(location, selector, mask, [receiver, value]);
+    pushInvokeDynamic(location, selector, mask, [receiver, value],
+        sourceInformation: sourceInformationBuilder.buildAssignment(location));
     pop();
     stack.add(value);
   }
@@ -3617,7 +3672,9 @@
         stack.add(checkedOrTrusted);
       }
 
-      localsHandler.updateLocal(local, checkedOrTrusted);
+      localsHandler.updateLocal(local, checkedOrTrusted,
+          sourceInformation:
+              sourceInformationBuilder.buildAssignment(location));
     }
   }
 
@@ -3827,12 +3884,15 @@
   void _generateDynamicSend(ast.Send node, HInstruction receiver) {
     Selector selector = elements.getSelector(node);
     TypeMask mask = elements.getTypeMask(node);
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildCall(node, node.selector);
 
     List<HInstruction> inputs = <HInstruction>[];
     inputs.add(receiver);
     addDynamicSendArgumentsToList(node, inputs);
 
-    pushInvokeDynamic(node, selector, mask, inputs);
+    pushInvokeDynamic(node, selector, mask, inputs,
+                      sourceInformation: sourceInformation);
     if (selector.isSetter || selector.isIndexSet) {
       pop();
       stack.add(inputs.last);
@@ -3884,7 +3944,10 @@
       ast.NodeList arguments,
       Selector selector,
       _) {
-    generateCallInvoke(node, visitAndPop(expression));
+    generateCallInvoke(
+        node,
+        visitAndPop(expression),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -3893,7 +3956,10 @@
       ast.NodeList arguments,
       CallStructure callStructure,
       _) {
-    generateCallInvoke(node, localsHandler.readThis());
+    generateCallInvoke(
+        node,
+        localsHandler.readThis(),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -3903,7 +3969,10 @@
       ast.NodeList arguments,
       CallStructure callStructure,
       _) {
-    generateCallInvoke(node, localsHandler.readLocal(parameter));
+    generateCallInvoke(
+        node,
+            localsHandler.readLocal(parameter),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -3913,7 +3982,10 @@
       ast.NodeList arguments,
       CallStructure callStructure,
       _) {
-    generateCallInvoke(node, localsHandler.readLocal(variable));
+    generateCallInvoke(
+        node,
+        localsHandler.readLocal(variable),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -3923,7 +3995,10 @@
       ast.NodeList arguments,
       CallStructure callStructure,
       _) {
-    generateCallInvoke(node, localsHandler.readLocal(function));
+    generateCallInvoke(
+        node,
+        localsHandler.readLocal(function),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -3933,7 +4008,8 @@
       ast.NodeList arguments,
       CallStructure callStructure,
       _) {
-    generateCallInvoke(node, localsHandler.readLocal(function));
+    generateCallInvoke(node, localsHandler.readLocal(function),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   void handleForeignJs(ast.Send node) {
@@ -3953,17 +4029,21 @@
     TypeMask ssaType =
         TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler);
 
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildCall(node, node.argumentsNode);
     if (nativeBehavior.codeTemplate.isExpression) {
       push(new HForeignCode(
           nativeBehavior.codeTemplate, ssaType, inputs,
           effects: nativeBehavior.sideEffects,
-          nativeBehavior: nativeBehavior));
+          nativeBehavior: nativeBehavior)
+              ..sourceInformation = sourceInformation);
     } else {
       push(new HForeignCode(
           nativeBehavior.codeTemplate, ssaType, inputs,
           isStatement: true,
           effects: nativeBehavior.sideEffects,
-          nativeBehavior: nativeBehavior));
+          nativeBehavior: nativeBehavior)
+              ..sourceInformation = sourceInformation);
     }
   }
 
@@ -4312,7 +4392,9 @@
     }
   }
 
-  generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader) {
+  generateDeferredLoaderGet(ast.Send node,
+                            FunctionElement deferredLoader,
+                            SourceInformation sourceInformation) {
     // Until now we only handle these as getters.
     invariant(node, deferredLoader.isDeferredLoaderGetter);
     Element loadFunction = compiler.loadLibraryFunction;
@@ -4322,7 +4404,8 @@
     var inputs = [graph.addConstantString(
         new ast.DartString.literal(loadId), compiler)];
     push(new HInvokeStatic(loadFunction, inputs, backend.nonNullType,
-                           targetCanThrow: false));
+                           targetCanThrow: false)
+        ..sourceInformation = sourceInformation);
   }
 
   generateSuperNoSuchMethodSend(ast.Send node,
@@ -4371,14 +4454,16 @@
                       graph.addConstant(kindConstant, compiler),
                       argumentsInstruction,
                       argumentNamesInstruction],
-                      typeMask: backend.dynamicType);
+                     typeMask: backend.dynamicType);
 
     var inputs = <HInstruction>[pop()];
     push(buildInvokeSuper(compiler.noSuchMethodSelector, element, inputs));
   }
 
   /// Generate a call to a super method or constructor.
-  void generateSuperInvoke(ast.Send node, FunctionElement function) {
+  void generateSuperInvoke(ast.Send node,
+                           FunctionElement function,
+                           SourceInformation sourceInformation) {
     // TODO(5347): Try to avoid the need for calling [implementation] before
     // calling [makeStaticArgumentList].
     Selector selector = elements.getSelector(node);
@@ -4389,29 +4474,37 @@
         makeStaticArgumentList(selector.callStructure,
                                node.arguments,
                                function.implementation);
-    push(buildInvokeSuper(selector, function, inputs));
+    push(buildInvokeSuper(selector, function, inputs, sourceInformation));
   }
 
   /// Access the value from the super [element].
   void handleSuperGet(ast.Send node, Element element) {
     Selector selector = elements.getSelector(node);
-    push(buildInvokeSuper(selector, element, const <HInstruction>[]));
+    SourceInformation sourceInformation =
+        sourceInformationBuilder.buildGet(node);
+    push(buildInvokeSuper(
+        selector, element, const <HInstruction>[], sourceInformation));
   }
 
   /// Invoke .call on the value retrieved from the super [element].
   void handleSuperCallInvoke(ast.Send node, Element element) {
     Selector selector = elements.getSelector(node);
-    HInstruction target =
-        buildInvokeSuper(selector, element, const <HInstruction>[]);
+    HInstruction target = buildInvokeSuper(
+        selector, element, const <HInstruction>[],
+        sourceInformationBuilder.buildGet(node));
     add(target);
-    generateCallInvoke(node, target);
+    generateCallInvoke(
+        node,
+        target,
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   /// Invoke super [method].
   void handleSuperMethodInvoke(
       ast.Send node,
       MethodElement method) {
-    generateSuperInvoke(node, method);
+    generateSuperInvoke(node, method,
+        sourceInformationBuilder.buildCall(node, node.selector));
   }
 
   /// Access an unresolved super property.
@@ -4622,8 +4715,10 @@
    * extract the type argument by the index of the variable in the list of type
    * variables for that class.
    */
-  HInstruction readTypeVariable(ClassElement cls,
-                                TypeVariableElement variable) {
+  HInstruction readTypeVariable(
+      ClassElement cls,
+      TypeVariableElement variable,
+      {SourceInformation sourceInformation}) {
     assert(sourceElement.isInstanceMember);
 
     HInstruction target = localsHandler.readThis();
@@ -4641,11 +4736,15 @@
       pushInvokeStatic(null,
                        backend.getGetRuntimeTypeArgument(),
                        [target, substitutionNameInstr, index],
-                       typeMask: backend.dynamicType);
+                       typeMask: backend.dynamicType,
+                       sourceInformation: sourceInformation);
     } else {
-      pushInvokeStatic(null, backend.getGetTypeArgumentByIndex(),
+      pushInvokeStatic(
+          null,
+          backend.getGetTypeArgumentByIndex(),
           [target, index],
-          typeMask: backend.dynamicType);
+          typeMask: backend.dynamicType,
+          sourceInformation: sourceInformation);
     }
     return pop();
   }
@@ -4661,7 +4760,10 @@
   /**
    * Helper to create an instruction that gets the value of a type variable.
    */
-  HInstruction addTypeVariableReference(TypeVariableType type) {
+  HInstruction addTypeVariableReference(
+      TypeVariableType type,
+      {SourceInformation sourceInformation}) {
+
     assert(assertTypeInContext(type));
     Element member = sourceElement;
     bool isClosure = member.enclosingElement.isClosure;
@@ -4679,14 +4781,18 @@
         // The type variable is used from a closure in a factory constructor.
         // The value of the type argument is stored as a local on the closure
         // itself.
-        return localsHandler.readLocal(typeVariableLocal);
+        return localsHandler.readLocal(
+            typeVariableLocal, sourceInformation: sourceInformation);
       } else if (member.isFunction ||
                  member.isGetter ||
                  member.isSetter ||
                  isInConstructorContext) {
         // The type variable is stored on the "enclosing object" and needs to be
         // accessed using the this-reference in the closure.
-        return readTypeVariable(member.enclosingClass, type.element);
+        return readTypeVariable(
+            member.enclosingClass,
+            type.element,
+            sourceInformation: sourceInformation);
       } else {
         assert(member.isField);
         // The type variable is stored in a parameter of the method.
@@ -4700,11 +4806,14 @@
                // always return true when seeing one.
                (member.isField && !isBuildingFor(member))) {
       // The type variable is stored in a parameter of the method.
-      return localsHandler.readLocal(typeVariableLocal);
+      return localsHandler.readLocal(
+          typeVariableLocal, sourceInformation: sourceInformation);
     } else if (member.isInstanceMember) {
       // The type variable is stored on the object.
-      return readTypeVariable(member.enclosingClass,
-                              type.element);
+      return readTypeVariable(
+          member.enclosingClass,
+          type.element,
+          sourceInformation: sourceInformation);
     } else {
       compiler.internalError(type.element,
           'Unexpected type variable in static context.');
@@ -4712,7 +4821,10 @@
     }
   }
 
-  HInstruction analyzeTypeArgument(DartType argument) {
+  HInstruction analyzeTypeArgument(
+      DartType argument,
+      {SourceInformation sourceInformation}) {
+
     assert(assertTypeInContext(argument));
     if (argument.treatAsDynamic) {
       // Represent [dynamic] as [null].
@@ -4720,7 +4832,8 @@
     }
 
     if (argument.isTypeVariable) {
-      return addTypeVariableReference(argument);
+      return addTypeVariableReference(
+          argument, sourceInformation: sourceInformation);
     }
 
     List<HInstruction> inputs = <HInstruction>[];
@@ -4755,7 +4868,8 @@
 
   void copyRuntimeTypeInfo(HInstruction source, HInstruction target) {
     Element copyHelper = backend.getCopyTypeArguments();
-    pushInvokeStatic(null, copyHelper, [source, target]);
+    pushInvokeStatic(null, copyHelper, [source, target],
+        sourceInformation: target.sourceInformation);
     pop();
   }
 
@@ -4775,7 +4889,8 @@
         null,
         typeInfoSetterElement,
         <HInstruction>[newObject, typeInfo],
-        typeMask: backend.dynamicType);
+        typeMask: backend.dynamicType,
+        sourceInformation: newObject.sourceInformation);
 
     // The new object will now be referenced through the
     // `setRuntimeTypeInfo` call. We therefore set the type of that
@@ -4933,6 +5048,8 @@
       push(buildLiteralList(<HInstruction>[]));
       stack.last.instructionType = elementType;
     } else {
+      SourceInformation sourceInformation =
+          sourceInformationBuilder.buildNew(send);
       ClassElement cls = constructor.enclosingClass;
       if (cls.isAbstract && constructor.isGenerativeConstructor) {
         generateAbstractClassInstantiationError(send, cls.name);
@@ -4942,7 +5059,9 @@
 
       addInlinedInstantiation(expectedType);
       pushInvokeStatic(node, constructor, inputs,
-          typeMask: elementType, instanceType: expectedType);
+          typeMask: elementType,
+          instanceType: expectedType,
+          sourceInformation: sourceInformation);
       removeInlinedInstantiation(expectedType);
     }
     HInstruction newInstance = stack.last;
@@ -4976,12 +5095,14 @@
   }
 
   void potentiallyAddTypeArguments(List<HInstruction> inputs, ClassElement cls,
-                                   InterfaceType expectedType) {
+                                   InterfaceType expectedType,
+                                   {SourceInformation sourceInformation}) {
     if (!backend.classNeedsRti(cls)) return;
     assert(expectedType.typeArguments.isEmpty ||
         cls.typeVariables.length == expectedType.typeArguments.length);
     expectedType.typeArguments.forEach((DartType argument) {
-      inputs.add(analyzeTypeArgument(argument));
+      inputs.add(analyzeTypeArgument(
+          argument, sourceInformation: sourceInformation));
     });
   }
 
@@ -5074,7 +5195,9 @@
           new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
       return;
     } else {
-      pushInvokeStatic(node, function, inputs);
+      pushInvokeStatic(node, function, inputs,
+          sourceInformation: sourceInformationBuilder.buildCall(
+              node, node.selector));
     }
   }
 
@@ -5093,7 +5216,10 @@
       CallStructure callStructure,
       _) {
     generateStaticFieldGet(node, field);
-    generateCallInvoke(node, pop());
+    generateCallInvoke(
+        node,
+        pop(),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -5124,7 +5250,10 @@
       CallStructure callStructure,
       _) {
     generateStaticGetterGet(node, getter);
-    generateCallInvoke(node, pop());
+    generateCallInvoke(
+        node,
+        pop(),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -5135,7 +5264,10 @@
       CallStructure callStructure,
       _) {
     generateStaticFieldGet(node, field);
-    generateCallInvoke(node, pop());
+    generateCallInvoke(
+        node,
+        pop(),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -5170,7 +5302,10 @@
       CallStructure callStructure,
       _) {
     generateStaticGetterGet(node, getter);
-    generateCallInvoke(node, pop());
+    generateCallInvoke(
+        node,
+        pop(),
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   @override
@@ -5335,7 +5470,8 @@
   void generateTypeVariableLiteral(ast.Send node,
                                    TypeVariableType typeVariable) {
     DartType type = localsHandler.substInContext(typeVariable);
-    HInstruction value = analyzeTypeArgument(type);
+    HInstruction value = analyzeTypeArgument(type,
+        sourceInformation: sourceInformationBuilder.buildGet(node));
     pushInvokeStatic(node,
                      backend.getRuntimeTypeToString(),
                      [value],
@@ -5352,19 +5488,21 @@
     // reference instead of creating a NoSuchMethodError to avoid pulling it
     // in if it is not used (e.g., in a try/catch).
     HInstruction target = pop();
-    generateCallInvoke(node, target);
+    generateCallInvoke(node, target,
+        sourceInformationBuilder.buildCall(node, node.argumentsNode));
   }
 
   /// Generate a '.call' invocation on [target].
-  void generateCallInvoke(ast.Send node, HInstruction target) {
+  void generateCallInvoke(ast.Send node,
+                          HInstruction target,
+                          SourceInformation sourceInformation) {
     Selector selector = elements.getSelector(node);
     List<HInstruction> inputs = <HInstruction>[target];
     addDynamicSendArgumentsToList(node, inputs);
-    pushWithPosition(
-        new HInvokeClosure(
+    push(new HInvokeClosure(
             new Selector.callClosureFrom(selector),
-            inputs, backend.dynamicType),
-        node);
+            inputs, backend.dynamicType)
+        ..sourceInformation = sourceInformation);
   }
 
   visitGetterSend(ast.Send node) {
@@ -5399,7 +5537,8 @@
                                  String methodName,
                                  {Link<ast.Node> argumentNodes,
                                   List<HInstruction> argumentValues,
-                                  List<String> existingArguments}) {
+                                  List<String> existingArguments,
+                                  SourceInformation sourceInformation}) {
     Element helper = backend.getThrowNoSuchMethod();
     ConstantValue receiverConstant =
         constantSystem.createString(new ast.DartString.empty());
@@ -5432,7 +5571,8 @@
     }
     pushInvokeStatic(diagnosticNode,
                      helper,
-                     [receiver, name, arguments, existingNamesList]);
+                     [receiver, name, arguments, existingNamesList],
+                     sourceInformation: sourceInformation);
   }
 
   /**
@@ -5511,8 +5651,7 @@
                          Selector selector,
                          TypeMask mask,
                          List<HInstruction> arguments,
-                         {ast.Node location}) {
-    if (location == null) location = node;
+                         {SourceInformation sourceInformation}) {
 
     // We prefer to not inline certain operations on indexables,
     // because the constant folder will handle them better and turn
@@ -5571,17 +5710,17 @@
     TypeMask type =
         TypeMaskFactory.inferredTypeForSelector(selector, mask, compiler);
     if (selector.isGetter) {
-      pushWithPosition(
-          new HInvokeDynamicGetter(selector, mask, null, inputs, type),
-          location);
+      push(
+          new HInvokeDynamicGetter(selector, mask, null, inputs, type)
+              ..sourceInformation = sourceInformation);
     } else if (selector.isSetter) {
-      pushWithPosition(
-          new HInvokeDynamicSetter(selector, mask, null, inputs, type),
-          location);
+      push(
+          new HInvokeDynamicSetter(selector, mask, null, inputs, type)
+              ..sourceInformation = sourceInformation);
     } else {
-      pushWithPosition(
-          new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted),
-          location);
+      push(
+          new HInvokeDynamicMethod(selector, mask, inputs, type, isIntercepted)
+              ..sourceInformation = sourceInformation);
     }
   }
 
@@ -5589,7 +5728,9 @@
                         Element element,
                         List<HInstruction> arguments,
                         {TypeMask typeMask,
-                         InterfaceType instanceType}) {
+                         InterfaceType instanceType,
+                         SourceInformation sourceInformation}) {
+    // TODO(johnniwinther): Use [sourceInformation] instead of [location].
     if (tryInlineMethod(element, null, null, arguments, location,
                         instanceType: instanceType)) {
       return;
@@ -5604,7 +5745,8 @@
     // creating an [HInvokeStatic].
     HInvokeStatic instruction = new HInvokeStatic(
         element.declaration, arguments, typeMask,
-        targetCanThrow: targetCanThrow);
+        targetCanThrow: targetCanThrow)
+            ..sourceInformation = sourceInformation;
     if (!currentInlinedInstantiations.isEmpty) {
       instruction.instantiatedTypes = new List<DartType>.from(
           currentInlinedInstantiations);
@@ -5619,7 +5761,8 @@
 
   HInstruction buildInvokeSuper(Selector selector,
                                 Element element,
-                                List<HInstruction> arguments) {
+                                List<HInstruction> arguments,
+                                [SourceInformation sourceInformation]) {
     HInstruction receiver = localsHandler.readThis();
     // TODO(5346): Try to avoid the need for calling [declaration] before
     // creating an [HStatic].
@@ -5644,6 +5787,7 @@
         selector,
         inputs,
         type,
+        sourceInformation,
         isSetter: selector.isSetter || selector.isIndexSet);
     instruction.sideEffects =
         compiler.world.getSideEffectsOfSelector(selector, null);
@@ -5661,11 +5805,14 @@
       assert(arguments.tail.isEmpty);
       rhs = pop();
     }
-    visitBinarySend(receiver, rhs,
-                    elements.getOperatorSelectorInComplexSendSet(node),
-                    elements.getOperatorTypeMaskInComplexSendSet(node),
-                    node,
-                    location: node.assignmentOperator);
+    visitBinarySend(
+        receiver,
+        rhs,
+        elements.getOperatorSelectorInComplexSendSet(node),
+        elements.getOperatorTypeMaskInComplexSendSet(node),
+        node,
+        sourceInformation:
+          sourceInformationBuilder.buildGeneric(node.assignmentOperator));
   }
 
   void handleSuperSendSet(ast.SendSet node) {
@@ -6525,7 +6672,7 @@
     } else if (getter.isFunction) {
       generateStaticFunctionGet(node, getter);
     } else if (getter.isLocal) {
-      handleLocalGet(getter);
+      handleLocalGet(node, getter);
     } else {
       internalError(node, "Unexpected getter: $getter");
     }
@@ -6665,7 +6812,10 @@
           'rethrowableException should not be null.');
     }
     handleInTryStatement();
-    closeAndGotoExit(new HThrow(exception, isRethrow: true));
+    closeAndGotoExit(
+        new HThrow(exception,
+                   sourceInformationBuilder.buildThrow(node),
+                   isRethrow: true));
   }
 
   visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
@@ -6762,7 +6912,8 @@
     visitThrowExpression(node.expression);
     if (isReachable) {
       handleInTryStatement();
-      push(new HThrowExpression(pop()));
+      push(new HThrowExpression(
+          pop(), sourceInformationBuilder.buildThrow(node)));
       isReachable = false;
     }
   }
@@ -7536,7 +7687,10 @@
             [localsHandler.readLocal(switchTarget)],
             nativeBehavior: native.NativeBehavior.PURE));
       }
-      handleIf(node, buildCondition, buildLoop, () => {});
+      handleIf(node,
+          visitCondition: buildCondition,
+          visitThen: buildLoop,
+          visitElse: () => {});
     }
   }
 
@@ -7599,7 +7753,7 @@
         if (caseIterator.hasNext) {
           pushInvokeStatic(switchCase, getFallThroughErrorElement, []);
           HInstruction error = pop();
-          closeAndGotoExit(new HThrow(error));
+          closeAndGotoExit(new HThrow(error, error.sourceInformation));
         } else if (!isDefaultCase(switchCase)) {
           // If there is no default, we will add one later to avoid
           // the critical edge. So we generate a break statement to make
@@ -7875,17 +8029,24 @@
 
       void visitElse() {
         if (link.isEmpty) {
-          closeAndGotoExit(new HThrow(exception, isRethrow: true));
+          closeAndGotoExit(
+              new HThrow(exception,
+                         exception.sourceInformation,
+                         isRethrow: true));
         } else {
           ast.CatchBlock newBlock = link.head;
           handleIf(node,
-                   () { pushCondition(newBlock); },
-                   visitThen, visitElse);
+                   visitCondition: () { pushCondition(newBlock); },
+                   visitThen: visitThen,
+                   visitElse: visitElse);
         }
       }
 
       ast.CatchBlock firstBlock = link.head;
-      handleIf(node, () { pushCondition(firstBlock); }, visitThen, visitElse);
+      handleIf(node,
+          visitCondition: () { pushCondition(firstBlock); },
+          visitThen: visitThen,
+          visitElse: visitElse);
       if (!isAborted()) endCatchBlock = close(new HGoto());
 
       rethrowableException = oldRethrowableException;
@@ -8016,7 +8177,8 @@
 
   void emitReturn(HInstruction value, ast.Node node) {
     if (inliningStack.isEmpty) {
-      closeAndGotoExit(attachPosition(new HReturn(value), node));
+      closeAndGotoExit(new HReturn(value,
+          sourceInformationBuilder.buildReturn(node)));
     } else {
       localsHandler.updateLocal(returnLocal, value);
     }
@@ -8375,13 +8537,14 @@
   void buildCondition(void visitCondition(),
                       SsaBranch conditionBranch,
                       SsaBranch thenBranch,
-                      SsaBranch elseBranch) {
+                      SsaBranch elseBranch,
+                      SourceInformation sourceInformation) {
     startBranch(conditionBranch);
     visitCondition();
     checkNotAborted();
     assert(identical(builder.current, builder.lastOpenedBlock));
     HInstruction conditionValue = builder.popBoolified();
-    HIf branch = new HIf(conditionValue);
+    HIf branch = new HIf(conditionValue)..sourceInformation = sourceInformation;
     HBasicBlock conditionExitBlock = builder.current;
     builder.close(branch);
     conditionBranch.exitLocals = builder.localsHandler;
@@ -8442,7 +8605,10 @@
     return null;
   }
 
-  handleIf(void visitCondition(), void visitThen(), void visitElse()) {
+  handleIf(void visitCondition(),
+           void visitThen(),
+           void visitElse(),
+           {SourceInformation sourceInformation}) {
     if (visitElse == null) {
       // Make sure to have an else part to avoid a critical edge. A
       // critical edge is an edge that connects a block with multiple
@@ -8452,12 +8618,17 @@
       visitElse = () {};
     }
 
-    _handleDiamondBranch(visitCondition, visitThen, visitElse, false);
+    _handleDiamondBranch(
+        visitCondition, visitThen, visitElse, isExpression: false,
+        sourceInformation: sourceInformation);
   }
 
-  handleConditional(void visitCondition(), void visitThen(), void visitElse()) {
+  handleConditional(void visitCondition(),
+                    void visitThen(),
+                    void visitElse()) {
     assert(visitElse != null);
-    _handleDiamondBranch(visitCondition, visitThen, visitElse, true);
+    _handleDiamondBranch(
+        visitCondition, visitThen, visitElse, isExpression: true);
   }
 
   handleIfNull(void left(), void right()) {
@@ -8552,7 +8723,8 @@
   void _handleDiamondBranch(void visitCondition(),
                             void visitThen(),
                             void visitElse(),
-                            bool isExpression) {
+                            {bool isExpression,
+                             SourceInformation sourceInformation}) {
     SsaBranch conditionBranch = new SsaBranch(this);
     SsaBranch thenBranch = new SsaBranch(this);
     SsaBranch elseBranch = new SsaBranch(this);
@@ -8561,7 +8733,8 @@
     conditionBranch.startLocals = builder.localsHandler;
     builder.goto(builder.current, conditionBranch.block);
 
-    buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch);
+    buildCondition(visitCondition, conditionBranch, thenBranch, elseBranch,
+                   sourceInformation);
     HInstruction thenValue =
         buildBranch(thenBranch, visitThen, joinBranch, isExpression);
     HInstruction elseValue =
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 2524fdf..6057d6f 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -7,7 +7,7 @@
 class SsaCodeGeneratorTask extends CompilerTask {
 
   final JavaScriptBackend backend;
-  final SourceInformationFactory sourceInformationFactory;
+  final SourceInformationStrategy sourceInformationFactory;
 
   SsaCodeGeneratorTask(JavaScriptBackend backend,
                        this.sourceInformationFactory)
@@ -17,12 +17,6 @@
   String get name => 'SSA code generator';
   NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
 
-
-  js.Node attachPosition(js.Node node, AstElement element) {
-    return node.withSourceInformation(
-        StartEndSourceInformation.computeSourceInformation(element));
-  }
-
   js.Fun buildJavaScriptFunction(FunctionElement element,
                                  List<js.Parameter> parameters,
                                  js.Block body) {
@@ -35,8 +29,9 @@
             : const js.AsyncModifier.sync());
 
     return new js.Fun(parameters, body, asyncModifier: asyncModifier)
-        .withSourceInformation(sourceInformationFactory.forContext(element)
-            .buildDeclaration(element));
+        .withSourceInformation(
+            sourceInformationFactory.createBuilderForContext(element)
+                .buildDeclaration(element));
   }
 
   js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
@@ -51,7 +46,7 @@
     return measure(() {
       compiler.tracer.traceGraph("codegen", graph);
       SourceInformation sourceInformation =
-          sourceInformationFactory.forContext(work.element)
+          sourceInformationFactory.createBuilderForContext(work.element)
               .buildDeclaration(work.element);
       SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
       codegen.visitGraph(graph);
@@ -189,11 +184,8 @@
    * If the [instruction] is not `null` it will be used to attach the position
    * to the [statement].
    */
-  void pushStatement(js.Statement statement, [HInstruction instruction]) {
+  void pushStatement(js.Statement statement) {
     assert(expressionStack.isEmpty);
-    if (instruction != null) {
-      statement = attachLocation(statement, instruction);
-    }
     currentContainer.statements.add(statement);
   }
 
@@ -206,18 +198,16 @@
    * to the [expression].
    */
   pushExpressionAsStatement(js.Expression expression,
-                            [HInstruction instruction]) {
-    pushStatement(new js.ExpressionStatement(expression), instruction);
+                            SourceInformation sourceInformation) {
+    pushStatement(new js.ExpressionStatement(expression)
+        .withSourceInformation(sourceInformation));
   }
 
   /**
    * If the [instruction] is not `null` it will be used to attach the position
    * to the [expression].
    */
-  push(js.Expression expression, [HInstruction instruction]) {
-    if (instruction != null) {
-      expression = attachLocation(expression, instruction);
-    }
+  push(js.Expression expression) {
     expressionStack.add(expression);
   }
 
@@ -225,21 +215,6 @@
     return expressionStack.removeLast();
   }
 
-  attachLocationToLast(HInstruction instruction) {
-    int index = expressionStack.length - 1;
-    expressionStack[index] =
-        attachLocation(expressionStack[index], instruction);
-  }
-
-  js.Node attachLocation(js.Node jsNode, HInstruction instruction) {
-    return attachSourceInformation(jsNode, instruction.sourceInformation);
-  }
-
-  js.Node attachSourceInformation(js.Node jsNode,
-                                  SourceInformation sourceInformation) {
-    return jsNode.withSourceInformation(sourceInformation);
-  }
-
   void preGenerateMethod(HGraph graph) {
     new SsaInstructionSelection(compiler).visitGraph(graph);
     new SsaTypeKnownRemover().visitGraph(graph);
@@ -499,10 +474,13 @@
         }
       }
     }
-    return new js.Assignment(new js.VariableUse(variableName), value);
+    return new js.Assignment(new js.VariableUse(variableName), value)
+        .withSourceInformation(value.sourceInformation);
   }
 
-  void assignVariable(String variableName, js.Expression value) {
+  void assignVariable(String variableName,
+                      js.Expression value,
+                      SourceInformation sourceInformation) {
     if (isGeneratingExpression) {
       // If we are in an expression then we can't declare the variable here.
       // We have no choice, but to use it and then declare it separately.
@@ -522,7 +500,8 @@
           new js.VariableInitialization(decl, value);
 
       pushExpressionAsStatement(new js.VariableDeclarationList(
-          <js.VariableInitialization>[initialization]));
+          <js.VariableInitialization>[initialization]),
+          sourceInformation);
     } else {
       // Otherwise we are just going to use it.  If we have not already declared
       // it then we make sure we will declare it later.
@@ -530,7 +509,8 @@
         collectedVariableDeclarations.add(variableName);
       }
       pushExpressionAsStatement(
-          generateExpressionAssignment(variableName, value));
+          generateExpressionAssignment(variableName, value),
+          sourceInformation);
     }
   }
 
@@ -553,7 +533,8 @@
     if (needsAssignment &&
         !instruction.isControlFlow() && variableNames.hasName(instruction)) {
       visitExpression(instruction);
-      assignVariable(variableNames.getName(instruction), pop());
+      assignVariable(variableNames.getName(instruction), pop(),
+                     instruction.sourceInformation);
       return;
     }
 
@@ -594,7 +575,8 @@
     visit(node);
     if (!expressionStack.isEmpty) {
       assert(expressionStack.length == 1);
-      pushExpressionAsStatement(pop());
+      js.Expression expression = pop();
+      pushExpressionAsStatement(expression, node.sourceInformation);
     }
   }
 
@@ -611,7 +593,8 @@
     pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target)));
   }
 
-  js.Statement wrapIntoLabels(js.Statement result, List<LabelDefinition> labels) {
+  js.Statement wrapIntoLabels(js.Statement result,
+                              List<LabelDefinition> labels) {
     for (LabelDefinition label in labels) {
       if (label.isTarget) {
         String breakLabelString = backend.namer.breakLabelName(label);
@@ -834,7 +817,8 @@
           visitBodyIgnoreLabels(info);
           currentContainer = oldContainer;
           body = unwrapStatement(body);
-          loop = new js.For(jsInitialization, jsCondition, jsUpdates, body);
+          loop = new js.For(jsInitialization, jsCondition, jsUpdates, body)
+              .withSourceInformation(info.sourceInformation);
         } else {
           // We have either no update graph, or it's too complex to
           // put in an expression.
@@ -848,7 +832,7 @@
             jsCondition = generateExpression(condition);
             currentContainer = body;
           } else {
-            jsCondition = newLiteralBool(true);
+            jsCondition = newLiteralBool(true, info.sourceInformation);
             currentContainer = body;
             generateStatements(condition);
             use(condition.conditionExpression);
@@ -871,7 +855,8 @@
           }
           currentContainer = oldContainer;
           body = unwrapStatement(body);
-          loop = new js.While(jsCondition, body);
+          loop = new js.While(jsCondition, body)
+              .withSourceInformation(info.sourceInformation);
         }
         break;
       case HLoopBlockInformation.DO_WHILE_LOOP:
@@ -922,7 +907,10 @@
           // If the condition is dead code, we turn the do-while into
           // a simpler while because we will never reach the condition
           // at the end of the loop anyway.
-          loop = new js.While(newLiteralBool(true), unwrapStatement(body));
+          loop = new js.While(
+              newLiteralBool(true, info.sourceInformation),
+              unwrapStatement(body))
+                  .withSourceInformation(info.sourceInformation);
         } else {
           if (hasPhiUpdates || hasExitPhiUpdates) {
             updateBody.statements.add(new js.Continue(null));
@@ -936,9 +924,10 @@
             }
             body.statements.add(
                 new js.If(jsCondition, updateBody, exitLoop));
-            jsCondition = newLiteralBool(true);
+            jsCondition = newLiteralBool(true, info.sourceInformation);
           }
-          loop = new js.Do(unwrapStatement(body), jsCondition);
+          loop = new js.Do(unwrapStatement(body), jsCondition)
+              .withSourceInformation(info.sourceInformation);
         }
         currentContainer = oldContainer;
         break;
@@ -946,7 +935,7 @@
         compiler.internalError(condition.conditionExpression,
             'Unexpected loop kind: ${info.kind}.');
     }
-    js.Statement result = attachSourceInformation(loop, info.sourceInformation);
+    js.Statement result = loop;
     if (info.kind == HLoopBlockInformation.SWITCH_CONTINUE_LOOP) {
       String continueLabelString =
           backend.namer.implicitContinueLabelName(info.target);
@@ -1093,7 +1082,7 @@
   }
 
   void emitAssignment(String destination, String source) {
-    assignVariable(destination, new js.VariableUse(source));
+    assignVariable(destination, new js.VariableUse(source), null);
   }
 
   /**
@@ -1193,7 +1182,7 @@
     for (Copy copy in handler.assignments) {
       String name = variableNames.getName(copy.destination);
       use(copy.source);
-      assignVariable(name, pop());
+      assignVariable(name, pop(), null);
     }
   }
 
@@ -1209,27 +1198,38 @@
     visit(instruction);
   }
 
-  visitInvokeBinary(HInvokeBinary node, String op) {
+  void handleInvokeBinary(HInvokeBinary node,
+                          String op,
+                          SourceInformation sourceInformation) {
     use(node.left);
     js.Expression jsLeft = pop();
     use(node.right);
-    push(new js.Binary(op, jsLeft, pop()), node);
+    push(new js.Binary(op, jsLeft, pop())
+        .withSourceInformation(sourceInformation));
   }
 
-  visitRelational(HRelational node, String op) => visitInvokeBinary(node, op);
+  visitInvokeBinary(HInvokeBinary node, String op) {
+    handleInvokeBinary(node, op, node.sourceInformation);
+  }
+
+  visitRelational(HRelational node, String op) {
+    handleInvokeBinary(node, op, node.sourceInformation);
+  }
 
   // We want the outcome of bit-operations to be positive. We use the unsigned
   // shift operator to achieve this.
   visitBitInvokeBinary(HBinaryBitOp node, String op) {
     visitInvokeBinary(node, op);
     if (op != '>>>' && requiresUintConversion(node)) {
-      push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node);
+      push(new js.Binary(">>>", pop(), new js.LiteralNumber("0"))
+              .withSourceInformation(node.sourceInformation));
     }
   }
 
   visitInvokeUnary(HInvokeUnary node, String op) {
     use(node.operand);
-    push(new js.Prefix(op, pop()), node);
+    push(new js.Prefix(op, pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   // We want the outcome of bit-operations to be positive. We use the unsigned
@@ -1237,11 +1237,14 @@
   visitBitInvokeUnary(HInvokeUnary node, String op) {
     visitInvokeUnary(node, op);
     if (requiresUintConversion(node)) {
-      push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")), node);
+      push(new js.Binary(">>>", pop(), new js.LiteralNumber("0"))
+          .withSourceInformation(node.sourceInformation));
     }
   }
 
-  void emitIdentityComparison(HIdentity instruction, bool inverse) {
+  void emitIdentityComparison(HIdentity instruction,
+                              SourceInformation sourceInformation,
+                              {bool inverse: false}) {
     String op = instruction.singleComparisonOp;
     HInstruction left = instruction.left;
     HInstruction right = instruction.right;
@@ -1249,7 +1252,8 @@
       use(left);
       js.Expression jsLeft = pop();
       use(right);
-      push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop()));
+      push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop())
+         .withSourceInformation(sourceInformation));
     } else {
       assert(NullConstantValue.JsNull == 'null');
       use(left);
@@ -1264,12 +1268,13 @@
       js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse),
                                          pop(), pop());
 
-      push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq));
+      push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)
+          .withSourceInformation(sourceInformation));
     }
   }
 
   visitIdentity(HIdentity node) {
-    emitIdentityComparison(node, false);
+    emitIdentityComparison(node, node.sourceInformation, inverse: false);
   }
 
   visitAdd(HAdd node)               => visitInvokeBinary(node, '+');
@@ -1292,11 +1297,13 @@
     use(node.left);
     js.Expression jsLeft = pop();
     use(node.right);
-    push(new js.Binary('/', jsLeft, pop()), node);
-    push(new js.Binary('|', pop(), new js.LiteralNumber("0")), node);
+    push(new js.Binary('/', jsLeft, pop())
+        .withSourceInformation(node.sourceInformation));
+    push(new js.Binary('|', pop(), new js.LiteralNumber("0"))
+        .withSourceInformation(node.sourceInformation));
   }
 
-  visitNegate(HNegate node)         => visitInvokeUnary(node, '-');
+  visitNegate(HNegate node)             => visitInvokeUnary(node, '-');
 
   visitLess(HLess node)                 => visitRelational(node, '<');
   visitLessEqual(HLessEqual node)       => visitRelational(node, '<=');
@@ -1306,7 +1313,9 @@
   visitBoolify(HBoolify node) {
     assert(node.inputs.length == 1);
     use(node.inputs[0]);
-    push(new js.Binary('===', pop(), newLiteralBool(true)), node);
+    push(new js.Binary('===', pop(),
+                       newLiteralBool(true, node.sourceInformation))
+        .withSourceInformation(node.sourceInformation));
   }
 
   visitExit(HExit node) {
@@ -1362,16 +1371,20 @@
     if (node.label != null) {
       LabelDefinition label = node.label;
       if (!tryCallAction(breakAction, label)) {
-        pushStatement(new js.Break(backend.namer.breakLabelName(label)), node);
+        pushStatement(
+            new js.Break(backend.namer.breakLabelName(label))
+                .withSourceInformation(node.sourceInformation));
       }
     } else {
       JumpTarget target = node.target;
       if (!tryCallAction(breakAction, target)) {
         if (node.breakSwitchContinueLoop) {
-          pushStatement(new js.Break(
-              backend.namer.implicitContinueLabelName(target)), node);
+          pushStatement(
+              new js.Break(backend.namer.implicitContinueLabelName(target))
+                  .withSourceInformation(node.sourceInformation));
         } else {
-          pushStatement(new js.Break(null), node);
+          pushStatement(new js.Break(null)
+              .withSourceInformation(node.sourceInformation));
         }
       }
     }
@@ -1383,17 +1396,20 @@
       LabelDefinition label = node.label;
       if (!tryCallAction(continueAction, label)) {
         // TODO(floitsch): should this really be the breakLabelName?
-        pushStatement(new js.Continue(backend.namer.breakLabelName(label)),
-                      node);
+        pushStatement(
+            new js.Continue(backend.namer.breakLabelName(label))
+                .withSourceInformation(node.sourceInformation));
       }
     } else {
       JumpTarget target = node.target;
       if (!tryCallAction(continueAction, target)) {
         if (target.statement is ast.SwitchStatement) {
-          pushStatement(new js.Continue(
-              backend.namer.implicitContinueLabelName(target)), node);
+          pushStatement(
+              new js.Continue(backend.namer.implicitContinueLabelName(target))
+                  .withSourceInformation(node.sourceInformation));
         } else {
-          pushStatement(new js.Continue(null), node);
+          pushStatement(new js.Continue(null)
+              .withSourceInformation(node.sourceInformation));
         }
       }
     }
@@ -1444,7 +1460,8 @@
     js.Statement elsePart =
         unwrapStatement(generateStatementsInNewBlock(elseGraph));
 
-    pushStatement(new js.If(test, thenPart, elsePart), node);
+    pushStatement(new js.If(test, thenPart, elsePart)
+        .withSourceInformation(node.sourceInformation));
   }
 
   visitIf(HIf node) {
@@ -1499,7 +1516,8 @@
           backend.namer.globalObjectFor(backend.interceptorsLibrary));
       use(node.receiver);
       List<js.Expression> arguments = <js.Expression>[pop()];
-      push(js.propertyCall(isolate, name, arguments), node);
+      push(js.propertyCall(isolate, name, arguments)
+           .withSourceInformation(node.sourceInformation));
       registry.registerUseInterceptor();
     }
   }
@@ -1538,7 +1556,8 @@
     } else {
       methodLiteral = backend.namer.asName(methodName);
     }
-    push(js.propertyCall(object, methodLiteral, arguments), node);
+    push(js.propertyCall(object, methodLiteral, arguments)
+         .withSourceInformation(node.sourceInformation));
   }
 
   void visitInvokeConstructorBody(HInvokeConstructorBody node) {
@@ -1546,7 +1565,8 @@
     js.Expression object = pop();
     js.Name methodName = backend.namer.instanceMethodName(node.element);
     List<js.Expression> arguments = visitArguments(node.inputs);
-    push(js.propertyCall(object, methodName, arguments), node);
+    push(js.propertyCall(object, methodName, arguments)
+         .withSourceInformation(node.sourceInformation));
     registry.registerStaticUse(node.element);
   }
 
@@ -1557,7 +1577,8 @@
     Selector selector = node.selector;
     TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
     js.Name methodName = backend.registerOneShotInterceptor(selector);
-    push(js.propertyCall(isolate, methodName, arguments), node);
+    push(js.propertyCall(isolate, methodName, arguments)
+        .withSourceInformation(node.sourceInformation));
     if (selector.isGetter) {
       registerGetter(node);
     } else if (selector.isSetter) {
@@ -1622,14 +1643,16 @@
   visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
     use(node.receiver);
     js.Name name = backend.namer.invocationName(node.selector);
-    push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node);
+    push(js.propertyCall(pop(), name, visitArguments(node.inputs))
+         .withSourceInformation(node.sourceInformation));
     registerSetter(node);
   }
 
   visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
     use(node.receiver);
     js.Name name = backend.namer.invocationName(node.selector);
-    push(js.propertyCall(pop(), name, visitArguments(node.inputs)), node);
+    push(js.propertyCall(pop(), name, visitArguments(node.inputs))
+         .withSourceInformation(node.sourceInformation));
     registerGetter(node);
   }
 
@@ -1638,8 +1661,8 @@
     use(node.receiver);
     push(js.propertyCall(pop(),
                          backend.namer.invocationName(call),
-                         visitArguments(node.inputs)),
-         node);
+                         visitArguments(node.inputs))
+            .withSourceInformation(node.sourceInformation));
     registry.registerDynamicInvocation(
         new UniverseSelector(call, null));
   }
@@ -1681,7 +1704,8 @@
     } else {
       registry.registerStaticInvocation(element);
       push(backend.emitter.staticFunctionAccess(element));
-      push(new js.Call(pop(), arguments), node);
+      push(new js.Call(pop(), arguments,
+          sourceInformation: node.sourceInformation));
     }
 
   }
@@ -1694,12 +1718,15 @@
       js.Name fieldName =
           backend.namer.instanceFieldPropertyName(superMethod);
       use(node.inputs[0]);
-      js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName);
+      js.PropertyAccess access =
+          new js.PropertyAccess(pop(), fieldName)
+              .withSourceInformation(node.sourceInformation);
       if (node.isSetter) {
         use(node.value);
-        push(new js.Assignment(access, pop()), node);
+        push(new js.Assignment(access, pop())
+            .withSourceInformation(node.sourceInformation));
       } else {
-        push(access, node);
+        push(access);
       }
     } else {
       Selector selector = node.selector;
@@ -1725,15 +1752,15 @@
         push(js.js('#.#.call(#)',
                    [backend.emitter.prototypeAccess(superClass,
                                                     hasBeenInstantiated: true),
-                    methodName, visitArguments(node.inputs, start: 0)]),
-             node);
+                    methodName, visitArguments(node.inputs, start: 0)])
+                .withSourceInformation(node.sourceInformation));
       } else {
         use(node.receiver);
         push(
           js.js('#.#(#)', [
             pop(), backend.namer.aliasedSuperMemberPropertyName(superMethod),
-            visitArguments(node.inputs, start: 1)]), // Skip receiver argument.
-          node);
+            visitArguments(node.inputs, start: 1)]) // Skip receiver argument.
+              .withSourceInformation(node.sourceInformation));
       }
     }
   }
@@ -1745,15 +1772,18 @@
       // We access a JavaScript member we know all objects besides
       // null and undefined have: V8 does not like accessing a member
       // that does not exist.
-      push(new js.PropertyAccess.field(pop(), 'toString'), node);
+      push(new js.PropertyAccess.field(pop(), 'toString')
+          .withSourceInformation(node.sourceInformation));
     } else if (element == backend.jsIndexableLength) {
       // We're accessing a native JavaScript property called 'length'
       // on a JS String or a JS array. Therefore, the name of that
       // property should not be mangled.
-      push(new js.PropertyAccess.field(pop(), 'length'), node);
+      push(new js.PropertyAccess.field(pop(), 'length')
+          .withSourceInformation(node.sourceInformation));
     } else {
       js.Name name = backend.namer.instanceFieldPropertyName(element);
-      push(new js.PropertyAccess(pop(), name), node);
+      push(new js.PropertyAccess(pop(), name)
+          .withSourceInformation(node.sourceInformation));
       registry.registerFieldGetter(element);
     }
   }
@@ -1765,8 +1795,8 @@
     use(node.receiver);
     js.Expression receiver = pop();
     use(node.value);
-    push(new js.Assignment(new js.PropertyAccess(receiver, name), pop()),
-        node);
+    push(new js.Assignment(new js.PropertyAccess(receiver, name), pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   visitReadModifyWrite(HReadModifyWrite node) {
@@ -1776,12 +1806,15 @@
     use(node.receiver);
     js.Expression fieldReference = new js.PropertyAccess(pop(), name);
     if (node.isPreOp) {
-      push(new js.Prefix(node.jsOp, fieldReference), node);
+      push(new js.Prefix(node.jsOp, fieldReference)
+          .withSourceInformation(node.sourceInformation));
     } else if (node.isPostOp) {
-      push(new js.Postfix(node.jsOp, fieldReference), node);
+      push(new js.Postfix(node.jsOp, fieldReference)
+          .withSourceInformation(node.sourceInformation));
     } else {
       use(node.value);
-      push(new js.Assignment.compound(fieldReference, node.jsOp, pop()), node);
+      push(new js.Assignment.compound(fieldReference, node.jsOp, pop())
+          .withSourceInformation(node.sourceInformation));
     }
   }
 
@@ -1791,7 +1824,9 @@
 
   visitLocalSet(HLocalSet node) {
     use(node.value);
-    assignVariable(variableNames.getName(node.receiver), pop());
+    assignVariable(variableNames.getName(node.receiver),
+                   pop(),
+                   node.sourceInformation);
   }
 
   void registerForeignTypes(HForeign node) {
@@ -1812,14 +1847,16 @@
         use(inputs[i]);
         interpolatedExpressions.add(pop());
       }
-      pushStatement(node.codeTemplate.instantiate(interpolatedExpressions));
+      pushStatement(node.codeTemplate.instantiate(interpolatedExpressions)
+          .withSourceInformation(node.sourceInformation));
     } else {
       List<js.Expression> interpolatedExpressions = <js.Expression>[];
       for (int i = 0; i < inputs.length; i++) {
         use(inputs[i]);
         interpolatedExpressions.add(pop());
       }
-      push(node.codeTemplate.instantiate(interpolatedExpressions));
+      push(node.codeTemplate.instantiate(interpolatedExpressions)
+          .withSourceInformation(node.sourceInformation));
     }
 
     // TODO(sra): Tell world.nativeEnqueuer about the types created here.
@@ -1830,7 +1867,8 @@
     js.Expression jsClassReference =
         backend.emitter.constructorAccess(node.element);
     List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
-    push(new js.New(jsClassReference, arguments), node);
+    push(new js.New(jsClassReference, arguments)
+        .withSourceInformation(node.sourceInformation));
     registerForeignTypes(node);
     // We also use ForeignNew to instantiate closure classes that belong to
     // function expressions. We have to register their use here, as otherwise
@@ -1846,16 +1884,20 @@
     });
   }
 
-  js.Expression newLiteralBool(bool value) {
+  js.Expression newLiteralBool(bool value,
+                               SourceInformation sourceInformation) {
     if (compiler.enableMinification) {
       // Use !0 for true, !1 for false.
-      return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1"));
+      return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1"))
+          .withSourceInformation(sourceInformation);
     } else {
-      return new js.LiteralBool(value);
+      return new js.LiteralBool(value)
+          .withSourceInformation(sourceInformation);
     }
   }
 
-  void generateConstant(ConstantValue constant) {
+  void generateConstant(ConstantValue constant,
+                        SourceInformation sourceInformation) {
     if (constant.isFunction) {
       FunctionConstantValue function = constant;
       registry.registerStaticUse(function.element);
@@ -1869,12 +1911,13 @@
         registry.registerTypeConstant(element);
       }
     }
-    push(backend.emitter.constantReference(constant));
+    push(backend.emitter.constantReference(constant)
+            .withSourceInformation(sourceInformation));
   }
 
   visitConstant(HConstant node) {
     assert(isGenerateAtUseSite(node));
-    generateConstant(node.constant);
+    generateConstant(node.constant, node.sourceInformation);
 
     registry.registerCompileTimeConstant(node.constant);
     backend.constants.addCompileTimeConstantForEmission(node.constant);
@@ -1882,8 +1925,7 @@
 
   visitNot(HNot node) {
     assert(node.inputs.length == 1);
-    generateNot(node.inputs[0]);
-    attachLocationToLast(node);
+    generateNot(node.inputs[0], node.sourceInformation);
   }
 
   static String mapRelationalOperator(String op, bool inverse) {
@@ -1900,7 +1942,7 @@
     return inverse ? inverseOperator[op] : op;
   }
 
-  void generateNot(HInstruction input) {
+  void generateNot(HInstruction input, SourceInformation sourceInformation) {
     bool canGenerateOptimizedComparison(HInstruction instruction) {
       if (instruction is !HRelational) return false;
 
@@ -1921,29 +1963,31 @@
     if (isGenerateAtUseSite(input)) {
       handledBySpecialCase = true;
       if (input is HIs) {
-        emitIs(input, '!==');
+        emitIs(input, '!==', sourceInformation);
       } else if (input is HIsViaInterceptor) {
-        emitIsViaInterceptor(input, true);
+        emitIsViaInterceptor(input, sourceInformation, negative: true);
       } else if (input is HNot) {
         use(input.inputs[0]);
       } else if (input is HIdentity) {
-        emitIdentityComparison(input, true);
+        emitIdentityComparison(input, sourceInformation, inverse: true);
       } else if (input is HBoolify) {
         use(input.inputs[0]);
-        push(new js.Binary("!==", pop(), newLiteralBool(true)), input);
+        push(new js.Binary("!==", pop(),
+                           newLiteralBool(true, input.sourceInformation))
+            .withSourceInformation(sourceInformation));
       } else if (canGenerateOptimizedComparison(input)) {
         HRelational relational = input;
         BinaryOperation operation =
             relational.operation(backend.constantSystem);
         String op = mapRelationalOperator(operation.name, true);
-        visitRelational(input, op);
+        handleInvokeBinary(input, op, sourceInformation);
       } else {
         handledBySpecialCase = false;
       }
     }
     if (!handledBySpecialCase) {
       use(input);
-      push(new js.Prefix("!", pop()));
+      push(new js.Prefix("!", pop()).withSourceInformation(sourceInformation));
     }
   }
 
@@ -1974,7 +2018,7 @@
     } else if (node.inputs[1].isConstantBoolean()) {
       String operation = node.inputs[1].isConstantFalse() ? '&&' : '||';
       if (operation == '||') {
-        generateNot(input);
+        generateNot(input, input.sourceInformation);
       } else {
         use(input);
       }
@@ -1995,10 +2039,12 @@
     assert(node.inputs.length == 1);
     HInstruction input = node.inputs[0];
     if (input.isConstantNull()) {
-      pushStatement(new js.Return(null), node);
+      pushStatement(new js.Return()
+          .withSourceInformation(node.sourceInformation));
     } else {
       use(node.inputs[0]);
-      pushStatement(new js.Return(pop()), node);
+      pushStatement(new js.Return(pop())
+          .withSourceInformation(node.sourceInformation));
     }
   }
 
@@ -2009,20 +2055,24 @@
   visitThrow(HThrow node) {
     if (node.isRethrow) {
       use(node.inputs[0]);
-      pushStatement(new js.Throw(pop()), node);
+      pushStatement(new js.Throw(pop())
+          .withSourceInformation(node.sourceInformation));
     } else {
-      generateThrowWithHelper('wrapException', node.inputs[0]);
+      generateThrowWithHelper('wrapException', node.inputs[0],
+          sourceInformation: node.sourceInformation);
     }
   }
 
   visitAwait(HAwait node) {
     use(node.inputs[0]);
-    push(new js.Await(pop()), node);
+    push(new js.Await(pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   visitYield(HYield node) {
     use(node.inputs[0]);
-    pushStatement(new js.DartYield(pop(), node.hasStar), node);
+    pushStatement(new js.DartYield(pop(), node.hasStar)
+        .withSourceInformation(node.sourceInformation));
   }
 
   visitRangeConversion(HRangeConversion node) {
@@ -2072,13 +2122,15 @@
       generateThrowWithHelper('ioore', [node.array, node.index]);
       currentContainer = oldContainer;
       thenBody = unwrapStatement(thenBody);
-      pushStatement(new js.If.noElse(underOver, thenBody), node);
+      pushStatement(new js.If.noElse(underOver, thenBody)
+          .withSourceInformation(node.sourceInformation));
     } else {
       generateThrowWithHelper('ioore', [node.array, node.index]);
     }
   }
 
-  void generateThrowWithHelper(String helperName, argument) {
+  void generateThrowWithHelper(String helperName, argument,
+                               {SourceInformation sourceInformation}) {
     Element helper = backend.findHelper(helperName);
     registry.registerStaticUse(helper);
     js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper);
@@ -2095,22 +2147,25 @@
       use(argument);
       arguments.add(pop());
     }
-    js.Call value = new js.Call(jsHelper, arguments.toList(growable: false));
-    value = attachLocation(value, location);
+    js.Call value = new js.Call(jsHelper, arguments.toList(growable: false),
+        sourceInformation: sourceInformation);
     // BUG(4906): Using throw/return here adds to the size of the generated code
     // but it has the advantage of explicitly telling the JS engine that
     // this code path will terminate abruptly. Needs more work.
     if (helperName == 'wrapException') {
-      pushStatement(new js.Throw(value));
+      pushStatement(new js.Throw(value)
+          .withSourceInformation(sourceInformation));
     } else {
       Element element = work.element;
       if (element is FunctionElement && element.asyncMarker.isYielding) {
         // `return <expr>;` is illegal in a sync* or async* function.
         // To have the the async-translator working, we avoid introducing
         // `return` nodes.
-        pushStatement(new js.ExpressionStatement(value));
+        pushStatement(new js.ExpressionStatement(value)
+            .withSourceInformation(sourceInformation));
       } else {
-        pushStatement(new js.Return(value));
+        pushStatement(new js.Return(value)
+            .withSourceInformation(sourceInformation));
       }
     }
   }
@@ -2123,9 +2178,9 @@
     registry.registerStaticUse(helper);
 
     js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper);
-    js.Call value = new js.Call(jsHelper, [pop()]);
-    value = attachLocation(value, argument);
-    push(value, node);
+    js.Call value = new js.Call(jsHelper, [pop()])
+        .withSourceInformation(node.sourceInformation);
+    push(value);
   }
 
   void visitSwitch(HSwitch node) {
@@ -2136,10 +2191,12 @@
     Element element = node.element;
     assert(element.isFunction || element.isField);
     if (element.isFunction) {
-      push(backend.emitter.isolateStaticClosureAccess(element));
+      push(backend.emitter.isolateStaticClosureAccess(element)
+           .withSourceInformation(node.sourceInformation));
       registry.registerGetOfStaticFunction(element);
     } else {
-      push(backend.emitter.staticFieldAccess(element));
+      push(backend.emitter.staticFieldAccess(element)
+           .withSourceInformation(node.sourceInformation));
     }
     registry.registerStaticUse(element);
   }
@@ -2149,22 +2206,25 @@
     registry.registerStaticUse(element);
     js.Expression lazyGetter =
         backend.emitter.isolateLazyInitializerAccess(element);
-    js.Call call = new js.Call(lazyGetter, <js.Expression>[]);
-    push(call, node);
+    js.Call call = new js.Call(lazyGetter, <js.Expression>[],
+        sourceInformation: node.sourceInformation);
+    push(call);
   }
 
   void visitStaticStore(HStaticStore node) {
     registry.registerStaticUse(node.element);
     js.Node variable = backend.emitter.staticFieldAccess(node.element);
     use(node.inputs[0]);
-    push(new js.Assignment(variable, pop()), node);
+    push(new js.Assignment(variable, pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   void visitStringConcat(HStringConcat node) {
     use(node.left);
     js.Expression jsLeft = pop();
     use(node.right);
-    push(new js.Binary('+', jsLeft, pop()), node);
+    push(new js.Binary('+', jsLeft, pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   void visitStringify(HStringify node) {
@@ -2181,7 +2241,8 @@
         // The context is already <string> + value.
       } else {
         // Force an empty string for the first operand.
-        push(new js.Binary('+', js.string(""), pop()), node);
+        push(new js.Binary('+', js.string(""), pop())
+            .withSourceInformation(node.sourceInformation));
       }
     } else {
       Element convertToString = backend.getStringInterpolationHelper();
@@ -2189,7 +2250,8 @@
       js.Expression jsHelper =
           backend.emitter.staticFunctionAccess(convertToString);
       use(input);
-      push(new js.Call(jsHelper, <js.Expression>[pop()]), node);
+      push(new js.Call(jsHelper, <js.Expression>[pop()],
+                       sourceInformation: node.sourceInformation));
     }
   }
 
@@ -2203,14 +2265,16 @@
       use(input);
       return pop();
     }).toList();
-    push(new js.ArrayInitializer(elements), node);
+    push(new js.ArrayInitializer(elements)
+        .withSourceInformation(node.sourceInformation));
   }
 
   void visitIndex(HIndex node) {
     use(node.receiver);
     js.Expression receiver = pop();
     use(node.index);
-    push(new js.PropertyAccess(receiver, pop()), node);
+    push(new js.PropertyAccess(receiver, pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   void visitIndexAssign(HIndexAssign node) {
@@ -2219,8 +2283,8 @@
     use(node.index);
     js.Expression index = pop();
     use(node.value);
-    push(new js.Assignment(new js.PropertyAccess(receiver, index), pop()),
-         node);
+    push(new js.Assignment(new js.PropertyAccess(receiver, index), pop())
+        .withSourceInformation(node.sourceInformation));
   }
 
   void checkInt(HInstruction input, String cmp) {
@@ -2231,47 +2295,62 @@
     push(new js.Binary(cmp, left, or0));
   }
 
-  void checkBigInt(HInstruction input, String cmp) {
+  void checkBigInt(HInstruction input, String cmp,
+                   SourceInformation sourceInformation) {
     use(input);
     js.Expression left = pop();
     use(input);
     js.Expression right = pop();
     // TODO(4984): Deal with infinity and -0.0.
-    push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right]));
+    push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right])
+            .withSourceInformation(sourceInformation));
   }
 
-  void checkTypeOf(HInstruction input, String cmp, String typeName) {
+  void checkTypeOf(HInstruction input, String cmp, String typeName,
+                   SourceInformation sourceInformation) {
     use(input);
     js.Expression typeOf = new js.Prefix("typeof", pop());
     push(new js.Binary(cmp, typeOf, js.string(typeName)));
   }
 
-  void checkNum(HInstruction input, String cmp)
-      => checkTypeOf(input, cmp, 'number');
+  void checkNum(HInstruction input, String cmp,
+                SourceInformation sourceInformation) {
+    return checkTypeOf(input, cmp, 'number', sourceInformation);
+  }
 
-  void checkDouble(HInstruction input, String cmp)  => checkNum(input, cmp);
+  void checkDouble(HInstruction input, String cmp,
+                   SourceInformation sourceInformation) {
+    return checkNum(input, cmp, sourceInformation);
+  }
 
-  void checkString(HInstruction input, String cmp)
-      => checkTypeOf(input, cmp, 'string');
+  void checkString(HInstruction input, String cmp,
+                   SourceInformation sourceInformation) {
+    return checkTypeOf(input, cmp, 'string', sourceInformation);
+  }
 
-  void checkBool(HInstruction input, String cmp)
-      => checkTypeOf(input, cmp, 'boolean');
+  void checkBool(HInstruction input, String cmp,
+                 SourceInformation sourceInformation) {
+    return checkTypeOf(input, cmp, 'boolean', sourceInformation);
+  }
 
-  void checkObject(HInstruction input, String cmp) {
+  void checkObject(HInstruction input, String cmp,
+                   SourceInformation sourceInformation) {
     assert(NullConstantValue.JsNull == 'null');
     if (cmp == "===") {
-      checkTypeOf(input, '===', 'object');
+      checkTypeOf(input, '===', 'object', sourceInformation);
       js.Expression left = pop();
       use(input);
       js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull());
-      push(new js.Binary("&&", left, notNull));
+      push(new js.Binary("&&", left, notNull)
+          .withSourceInformation(sourceInformation));
     } else {
       assert(cmp == "!==");
-      checkTypeOf(input, '!==', 'object');
+      checkTypeOf(input, '!==', 'object', sourceInformation);
       js.Expression left = pop();
       use(input);
       js.Expression eqNull = new js.Binary("===", pop(), new js.LiteralNull());
-      push(new js.Binary("||", left, eqNull));
+      push(new js.Binary("||", left, eqNull)
+          .withSourceInformation(sourceInformation));
     }
   }
 
@@ -2322,7 +2401,9 @@
   }
 
   void checkType(HInstruction input, HInstruction interceptor,
-                 DartType type, {bool negative: false}) {
+                 DartType type,
+                 SourceInformation sourceInformation,
+                 {bool negative: false}) {
     Element element = type.element;
     if (element == backend.jsArrayClass) {
       checkArray(input, negative ? '!==': '===');
@@ -2357,73 +2438,92 @@
       return;
     }
     if (interceptor != null) {
-      checkTypeViaProperty(interceptor, type, negative);
+      checkTypeViaProperty(interceptor, type, sourceInformation,
+                           negative: negative);
     } else {
-      checkTypeViaProperty(input, type, negative);
+      checkTypeViaProperty(input, type, sourceInformation, negative: negative);
     }
   }
 
-  void checkTypeViaProperty(HInstruction input, DartType type, bool negative) {
+  void checkTypeViaProperty(HInstruction input, DartType type,
+                            SourceInformation sourceInformation,
+                            {bool negative: false}) {
     registry.registerIsCheck(type);
 
     use(input);
 
     js.PropertyAccess field =
-        new js.PropertyAccess(pop(), backend.namer.operatorIsType(type));
+        new js.PropertyAccess(pop(), backend.namer.operatorIsType(type))
+            .withSourceInformation(sourceInformation);
     // We always negate at least once so that the result is boolified.
-    push(new js.Prefix('!', field));
+    push(new js.Prefix('!', field)
+        .withSourceInformation(sourceInformation));
     // If the result is not negated, put another '!' in front.
-    if (!negative) push(new js.Prefix('!', pop()));
+    if (!negative) {
+      push(new js.Prefix('!', pop())
+          .withSourceInformation(sourceInformation));
+    }
   }
 
   void checkTypeViaInstanceof(
-      HInstruction input, DartType type, bool negative) {
+      HInstruction input, DartType type,
+      SourceInformation sourceInformation,
+      {bool negative: false}) {
     registry.registerIsCheck(type);
 
     use(input);
 
     js.Expression jsClassReference =
         backend.emitter.constructorAccess(type.element);
-    push(js.js('# instanceof #', [pop(), jsClassReference]));
-    if (negative) push(new js.Prefix('!', pop()));
+    push(js.js('# instanceof #', [pop(), jsClassReference])
+            .withSourceInformation(sourceInformation));
+    if (negative) {
+      push(new js.Prefix('!', pop())
+          .withSourceInformation(sourceInformation));
+    }
     registry.registerInstantiatedType(type);
   }
 
   void handleNumberOrStringSupertypeCheck(HInstruction input,
                                           HInstruction interceptor,
                                           DartType type,
-                                          { bool negative: false }) {
-    assert(!identical(type.element, compiler.listClass)
-           && !Elements.isListSupertype(type.element, compiler)
-           && !Elements.isStringOnlySupertype(type.element, compiler));
+                                          SourceInformation sourceInformation,
+                                          {bool negative: false}) {
+    assert(!identical(type.element, compiler.listClass) &&
+           !Elements.isListSupertype(type.element, compiler) &&
+           !Elements.isStringOnlySupertype(type.element, compiler));
     String relation = negative ? '!==' : '===';
-    checkNum(input, relation);
+    checkNum(input, relation, sourceInformation);
     js.Expression numberTest = pop();
-    checkString(input, relation);
+    checkString(input, relation, sourceInformation);
     js.Expression stringTest = pop();
-    checkObject(input, relation);
+    checkObject(input, relation, sourceInformation);
     js.Expression objectTest = pop();
-    checkType(input, interceptor, type, negative: negative);
+    checkType(input, interceptor, type, sourceInformation, negative: negative);
     String combiner = negative ? '&&' : '||';
     String combiner2 = negative ? '||' : '&&';
     push(new js.Binary(combiner,
-                       new js.Binary(combiner, numberTest, stringTest),
-                       new js.Binary(combiner2, objectTest, pop())));
+                       new js.Binary(combiner, numberTest, stringTest)
+                          .withSourceInformation(sourceInformation),
+                       new js.Binary(combiner2, objectTest, pop())
+                          .withSourceInformation(sourceInformation))
+        .withSourceInformation(sourceInformation));
   }
 
   void handleStringSupertypeCheck(HInstruction input,
                                   HInstruction interceptor,
                                   DartType type,
-                                  { bool negative: false }) {
+                                  SourceInformation sourceInformation,
+                                  {bool negative: false}) {
     assert(!identical(type.element, compiler.listClass)
            && !Elements.isListSupertype(type.element, compiler)
            && !Elements.isNumberOrStringSupertype(type.element, compiler));
     String relation = negative ? '!==' : '===';
-    checkString(input, relation);
+    checkString(input, relation, sourceInformation);
     js.Expression stringTest = pop();
-    checkObject(input, relation);
+    checkObject(input, relation, sourceInformation);
     js.Expression objectTest = pop();
-    checkType(input, interceptor, type, negative: negative);
+    checkType(input, interceptor, type, sourceInformation, negative: negative);
     String combiner = negative ? '||' : '&&';
     push(new js.Binary(negative ? '&&' : '||',
                        stringTest,
@@ -2433,31 +2533,33 @@
   void handleListOrSupertypeCheck(HInstruction input,
                                   HInstruction interceptor,
                                   DartType type,
+                                  SourceInformation sourceInformation,
                                   { bool negative: false }) {
     assert(!identical(type.element, compiler.stringClass)
            && !Elements.isStringOnlySupertype(type.element, compiler)
            && !Elements.isNumberOrStringSupertype(type.element, compiler));
     String relation = negative ? '!==' : '===';
-    checkObject(input, relation);
+    checkObject(input, relation, sourceInformation);
     js.Expression objectTest = pop();
     checkArray(input, relation);
     js.Expression arrayTest = pop();
-    checkType(input, interceptor, type, negative: negative);
+    checkType(input, interceptor, type, sourceInformation, negative: negative);
     String combiner = negative ? '&&' : '||';
     push(new js.Binary(negative ? '||' : '&&',
                        objectTest,
-                       new js.Binary(combiner, arrayTest, pop())));
+                       new js.Binary(combiner, arrayTest, pop()))
+        .withSourceInformation(sourceInformation));
   }
 
   void visitIs(HIs node) {
-    emitIs(node, "===");
+    emitIs(node, "===", node.sourceInformation);
   }
 
   void visitIsViaInterceptor(HIsViaInterceptor node) {
-    emitIsViaInterceptor(node, false);
+    emitIsViaInterceptor(node, node.sourceInformation, negative: false);
   }
 
-  void emitIs(HIs node, String relation)  {
+  void emitIs(HIs node, String relation, SourceInformation sourceInformation)  {
     DartType type = node.typeExpression;
     registry.registerIsCheck(type);
     HInstruction input = node.expression;
@@ -2484,64 +2586,73 @@
       } else if (identical(element, objectClass) || type.treatAsDynamic) {
         // The constant folder also does this optimization, but we make
         // it safe by assuming it may have not run.
-        push(newLiteralBool(!negative), node);
+        push(newLiteralBool(!negative, sourceInformation));
       } else if (element == compiler.stringClass) {
-        checkString(input, relation);
-        attachLocationToLast(node);
+        checkString(input, relation, sourceInformation);
       } else if (element == compiler.doubleClass) {
-        checkDouble(input, relation);
-        attachLocationToLast(node);
+        checkDouble(input, relation, sourceInformation);
       } else if (element == compiler.numClass) {
-        checkNum(input, relation);
-        attachLocationToLast(node);
+        checkNum(input, relation, sourceInformation);
       } else if (element == compiler.boolClass) {
-        checkBool(input, relation);
-        attachLocationToLast(node);
+        checkBool(input, relation, sourceInformation);
       } else if (element == compiler.intClass) {
         // The is check in the code tells us that it might not be an
         // int. So we do a typeof first to avoid possible
         // deoptimizations on the JS engine due to the Math.floor check.
-        checkNum(input, relation);
+        checkNum(input, relation, sourceInformation);
         js.Expression numTest = pop();
-        checkBigInt(input, relation);
-        push(new js.Binary(negative ? '||' : '&&', numTest, pop()), node);
+        checkBigInt(input, relation, sourceInformation);
+        push(new js.Binary(negative ? '||' : '&&', numTest, pop())
+            .withSourceInformation(sourceInformation));
       } else if (node.useInstanceOf) {
         assert(interceptor == null);
-        checkTypeViaInstanceof(input, type, negative);
-        attachLocationToLast(node);
+        checkTypeViaInstanceof(input, type,
+                               sourceInformation,
+                               negative: negative);
       } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
         handleNumberOrStringSupertypeCheck(
-            input, interceptor, type, negative: negative);
-        attachLocationToLast(node);
+            input, interceptor, type,
+            sourceInformation,
+            negative: negative);
       } else if (Elements.isStringOnlySupertype(element, compiler)) {
         handleStringSupertypeCheck(
-            input, interceptor, type, negative: negative);
-        attachLocationToLast(node);
-      } else if (identical(element, compiler.listClass)
-                 || Elements.isListSupertype(element, compiler)) {
+            input, interceptor, type,
+            sourceInformation,
+            negative: negative);
+      } else if (identical(element, compiler.listClass) ||
+                 Elements.isListSupertype(element, compiler)) {
         handleListOrSupertypeCheck(
-            input, interceptor, type, negative: negative);
-        attachLocationToLast(node);
+            input, interceptor, type,
+            sourceInformation,
+            negative: negative);
       } else if (type.isFunctionType) {
-        checkType(input, interceptor, type, negative: negative);
-        attachLocationToLast(node);
+        checkType(input, interceptor, type,
+                  sourceInformation,
+                  negative: negative);
       } else if ((input.canBePrimitive(compiler)
                   && !input.canBePrimitiveArray(compiler))
                  || input.canBeNull()) {
-        checkObject(input, relation);
+        checkObject(input, relation, node.sourceInformation);
         js.Expression objectTest = pop();
-        checkType(input, interceptor, type, negative: negative);
-        push(new js.Binary(negative ? '||' : '&&', objectTest, pop()), node);
+        checkType(input, interceptor, type,
+                  sourceInformation,
+                  negative: negative);
+        push(new js.Binary(negative ? '||' : '&&', objectTest, pop())
+            .withSourceInformation(sourceInformation));
       } else {
-        checkType(input, interceptor, type, negative: negative);
-        attachLocationToLast(node);
+        checkType(input, interceptor, type,
+                  sourceInformation,
+                  negative: negative);
       }
     }
   }
 
-  void emitIsViaInterceptor(HIsViaInterceptor node, bool negative) {
-    checkTypeViaProperty(node.interceptor, node.typeExpression, negative);
-    attachLocationToLast(node);
+  void emitIsViaInterceptor(HIsViaInterceptor node,
+                            SourceInformation sourceInformation,
+                            {bool negative: false}) {
+    checkTypeViaProperty(node.interceptor, node.typeExpression,
+                         sourceInformation,
+                         negative: negative);
   }
 
   js.Expression generateReceiverOrArgumentTypeTest(
@@ -2561,22 +2672,23 @@
 
     if (turnIntoNullCheck) {
       use(input);
-      return new js.Binary("==", pop(), new js.LiteralNull());
+      return new js.Binary("==", pop(), new js.LiteralNull())
+          .withSourceInformation(input.sourceInformation);
     } else if (isIntCheck && !turnIntoNumCheck) {
       // input is !int
-      checkBigInt(input, '!==');
+      checkBigInt(input, '!==', input.sourceInformation);
       return pop();
     } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) {
       // input is !num
-      checkNum(input, '!==');
+      checkNum(input, '!==', input.sourceInformation);
       return pop();
     } else if (checkedType.containsOnlyBool(classWorld)) {
       // input is !bool
-      checkBool(input, '!==');
+      checkBool(input, '!==', input.sourceInformation);
       return pop();
     } else if (checkedType.containsOnlyString(classWorld)) {
       // input is !string
-      checkString(input, '!==');
+      checkString(input, '!==', input.sourceInformation);
       return pop();
     }
     compiler.internalError(input, 'Unexpected check.');
@@ -2607,7 +2719,8 @@
       }
       currentContainer = oldContainer;
       body = unwrapStatement(body);
-      pushStatement(new js.If.noElse(test, body), node);
+      pushStatement(new js.If.noElse(test, body)
+          .withSourceInformation(node.sourceInformation));
       return;
     }
 
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 765ce05..0adc6e3 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -172,11 +172,14 @@
     return result;
   }
 
-  HConstant addConstant(ConstantValue constant, Compiler compiler) {
+  HConstant addConstant(ConstantValue constant, Compiler compiler,
+                        {SourceInformation sourceInformation}) {
     HConstant result = constants[constant];
+    // TODO(johnniwinther): Support source information per constant reference.
     if (result == null) {
       TypeMask type = computeTypeMask(compiler, constant);
-      result = new HConstant.internal(constant, type);
+      result = new HConstant.internal(constant, type)
+          ..sourceInformation = sourceInformation;
       entry.addAtExit(result);
       constants[constant] = result;
     } else if (result.block == null) {
@@ -187,12 +190,13 @@
   }
 
   HConstant addDeferredConstant(ConstantValue constant, PrefixElement prefix,
+                                SourceInformation sourceInformation,
                                 Compiler compiler) {
     // TODO(sigurdm,johnniwinter): These deferred constants should be created
     // by the constant evaluator.
     ConstantValue wrapper = new DeferredConstantValue(constant, prefix);
     compiler.deferredLoadTask.registerConstantDeferredUse(wrapper, prefix);
-    return addConstant(wrapper, compiler);
+    return addConstant(wrapper, compiler, sourceInformation: sourceInformation);
   }
 
   HConstant addConstantInt(int i, Compiler compiler) {
@@ -1316,6 +1320,7 @@
   HBoolify(HInstruction value, TypeMask type)
       : super(<HInstruction>[value], type) {
     setUseGvn();
+    sourceInformation = value.sourceInformation;
   }
 
   accept(HVisitor visitor) => visitor.visitBoolify(this);
@@ -1528,8 +1533,11 @@
                this.selector,
                inputs,
                type,
+               SourceInformation sourceInformation,
                {this.isSetter})
-      : super(element, inputs, type);
+      : super(element, inputs, type) {
+    this.sourceInformation = sourceInformation;
+  }
 
   HInstruction get receiver => inputs[0];
   HInstruction getDartReceiver(Compiler compiler) {
@@ -2302,14 +2310,19 @@
 }
 
 class HReturn extends HControlFlow {
-  HReturn(value) : super(<HInstruction>[value]);
+  HReturn(HInstruction value, SourceInformation sourceInformation)
+      : super(<HInstruction>[value]) {
+    this.sourceInformation = sourceInformation;
+  }
   toString() => 'return';
   accept(HVisitor visitor) => visitor.visitReturn(this);
 }
 
 class HThrowExpression extends HInstruction {
-  HThrowExpression(value)
-      : super(<HInstruction>[value], const TypeMask.nonNullEmpty());
+  HThrowExpression(HInstruction value, SourceInformation sourceInformation)
+      : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) {
+    this.sourceInformation = sourceInformation;
+  }
   toString() => 'throw expression';
   accept(HVisitor visitor) => visitor.visitThrowExpression(this);
   bool canThrow() => true;
@@ -2337,7 +2350,12 @@
 
 class HThrow extends HControlFlow {
   final bool isRethrow;
-  HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]);
+  HThrow(HInstruction value,
+         SourceInformation sourceInformation,
+         {this.isRethrow: false})
+      : super(<HInstruction>[value]) {
+    this.sourceInformation = sourceInformation;
+  }
   toString() => 'throw';
   accept(HVisitor visitor) => visitor.visitThrow(this);
 }
diff --git a/pkg/compiler/lib/src/tree/prettyprint.dart b/pkg/compiler/lib/src/tree/prettyprint.dart
index f01963b..ab4c87c 100644
--- a/pkg/compiler/lib/src/tree/prettyprint.dart
+++ b/pkg/compiler/lib/src/tree/prettyprint.dart
@@ -10,100 +10,18 @@
  * TODO(smok): Add main() to run from command-line to print out tree for given
  * .dart file.
  */
-class PrettyPrinter extends Indentation implements Visitor {
-
-  StringBuffer sb;
-  Link<String> tagStack;
-
-  PrettyPrinter() :
-      sb = new StringBuffer(),
-      tagStack = const Link<String>();
-
-  void pushTag(String tag) {
-    tagStack = tagStack.prepend(tag);
-    indentMore();
-  }
-
-  String popTag() {
-    assert(!tagStack.isEmpty);
-    String tag = tagStack.head;
-    tagStack = tagStack.tail;
-    indentLess();
-    return tag;
-  }
-
-  /**
-   * Adds given string to result string.
-   */
-  void add(String string) {
-    sb.write(string);
-  }
-
-  void addBeginAndEndTokensToParams(Node node, Map params) {
+class PrettyPrinter extends Indentation with Tagging<Node> implements Visitor {
+  @override
+  void addDefaultParameters(Node node, Map params) {
     params['getBeginToken'] = tokenToStringOrNull(node.getBeginToken());
     params['getEndToken'] = tokenToStringOrNull(node.getEndToken());
   }
 
-  /**
-   * Adds given node type to result string.
-   * The method "opens" the node, meaning that all output after calling
-   * this method and before calling closeNode() will represent contents
-   * of given node.
-   */
-  void openNode(Node node, String type, [Map params]) {
-    if (params == null) params = new Map();
-    addCurrentIndent();
-    sb.write("<");
-    addBeginAndEndTokensToParams(node, params);
-    addTypeWithParams(type, params);
-    sb.write(">\n");
-    pushTag(type);
-  }
-
-  /**
-   * Adds given node to result string.
-   */
-  void openAndCloseNode(Node node, String type, [Map params]) {
-    if (params == null) params = new Map();
-    addCurrentIndent();
-    sb.write("<");
-    addBeginAndEndTokensToParams(node, params);
-    addTypeWithParams(type, params);
-    sb.write("/>\n");
-  }
-
-  /**
-   * Closes current node type.
-   */
-  void closeNode() {
-    String tag = popTag();
-    addCurrentIndent();
-    sb.write("</");
-    addTypeWithParams(tag);
-    sb.write(">\n");
-  }
-
-  void addTypeWithParams(String type, [Map params]) {
-    if (params == null) params = new Map();
-    sb.write("${type}");
-    params.forEach((k, v) {
-      String value;
-      if (v != null) {
-        var str = v;
-        if (v is Token) str = v.value;
-        value = str
-            .replaceAll("<", "&lt;")
-            .replaceAll(">", "&gt;")
-            .replaceAll('"', "'");
-      } else {
-        value = "[null]";
-      }
-      sb.write(' $k="$value"');
-    });
-  }
-
-  void addCurrentIndent() {
-    sb.write(indentation);
+  String valueToString(var value) {
+    if (value is Token) {
+      return value.value;
+    }
+    return value;
   }
 
   /**
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index bad7690..be59dc9 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -8,7 +8,35 @@
 import '../tree_ir_nodes.dart';
 
 /**
- * Performs the following transformations on the tree:
+ * Translates to direct-style.
+ *
+ * In addition to the general IR constraints (see [CheckTreeIntegrity]),
+ * the input is assumed to satisfy the following criteria:
+ *
+ * All expressions other than those nested in [Assign] or [ExpressionStatement]
+ * must be simple. A [VariableUse] and [This] is a simple expression.
+ * The right-hand of an [Assign] may not be an [Assign].
+ *
+ * Moreover, every variable must either be an SSA variable or a mutable
+ * variable, and must satisfy the corresponding criteria:
+ *
+ * SSA VARIABLE:
+ * An SSA variable must have a unique definition site, which is either an
+ * assignment or label. In case of a label, its target must act as the unique
+ * reaching definition of that variable at all uses of the variable and at
+ * all other label targets where the variable is in scope.
+ *
+ * (The second criterion is to ensure that we can move a use of an SSA variable
+ * across a label without changing its reaching definition).
+ *
+ * MUTABLE VARIABLE:
+ * Uses of mutable variables are considered complex expressions, and hence must
+ * not be nested in other expressions. Assignments to mutable variables must
+ * have simple right-hand sides.
+ *
+ * ----
+ *
+ * This pass performs the following transformations on the tree:
  * - Assignment inlining
  * - Assignment expression propagation
  * - If-to-conditional conversion
@@ -113,7 +141,9 @@
 
   @override
   void rewrite(FunctionDefinition node) {
+    node.parameters.forEach(pushDominatingAssignment);
     node.body = visitStatement(node.body);
+    node.parameters.forEach(popDominatingAssignment);
   }
 
   /// The most recently evaluated impure expressions, with the most recent
@@ -145,6 +175,14 @@
   /// traversal, the first use is the last one seen).
   Map<Variable, int> unseenUses = <Variable, int>{};
 
+  /// Number of assignments to a given variable that dominate the current
+  /// position.
+  ///
+  /// Pure expressions will not be inlined if it uses a variable with more than
+  /// one dominating assignment, because the reaching definition of the used
+  /// variable might have changed since it was put in the environment.
+  final Map<Variable, int> dominatingAssignments = <Variable, int>{};
+
   /// Rewriter for methods.
   StatementRewriter() : constantEnvironment = <Variable, Expression>{};
 
@@ -196,6 +234,31 @@
     return value is VariableUse ? value.variable : null;
   }
 
+  /// True if the given expression (taken from [constantEnvironment]) uses a
+  /// variable that might have been reassigned since [node] was evaluated.
+  bool hasUnsafeVariableUse(Expression node) {
+    bool wasFound = false;
+    VariableUseVisitor.visit(node, (VariableUse use) {
+      if (dominatingAssignments[use.variable] > 1) {
+        wasFound = true;
+      }
+    });
+    return wasFound;
+  }
+
+  void pushDominatingAssignment(Variable variable) {
+    if (variable != null) {
+      dominatingAssignments.putIfAbsent(variable, () => 0);
+      ++dominatingAssignments[variable];
+    }
+  }
+
+  void popDominatingAssignment(Variable variable) {
+    if (variable != null) {
+      --dominatingAssignments[variable];
+    }
+  }
+
   @override
   Expression visitVariableUse(VariableUse node) {
     // Count of number of unseen uses remaining.
@@ -210,7 +273,7 @@
 
     // Propagate constant to use site.
     Expression constant = constantEnvironment[node.variable];
-    if (constant != null) {
+    if (constant != null && !hasUnsafeVariableUse(constant)) {
       --node.variable.readCount;
       return visitExpression(constant);
     }
@@ -287,7 +350,6 @@
     return exp is Constant ||
            exp is This ||
            exp is CreateInvocationMirror ||
-           exp is InvokeStatic && exp.isEffectivelyConstant ||
            exp is Interceptor ||
            exp is ApplyBuiltinOperator ||
            exp is VariableUse && constantEnvironment.containsKey(exp.variable);
@@ -301,6 +363,8 @@
   }
 
   Statement visitExpressionStatement(ExpressionStatement stmt) {
+    Variable leftHand = getLeftHand(stmt.expression);
+    pushDominatingAssignment(leftHand);
     if (isEffectivelyConstantAssignment(stmt.expression) &&
         !usesRecentlyAssignedVariable(stmt.expression)) {
       Assign assign = stmt.expression;
@@ -308,15 +372,29 @@
       // They are always safe to propagate (though we should avoid duplication).
       // Moreover, they should not prevent other expressions from propagating.
       if (assign.variable.readCount == 1) {
-        // A single-use constant should always be propagted to its use site.
+        // A single-use constant should always be propagated to its use site.
         constantEnvironment[assign.variable] = assign.value;
-        --assign.variable.writeCount;
-        return visitStatement(stmt.next);
+        Statement next = visitStatement(stmt.next);
+        popDominatingAssignment(leftHand);
+        if (assign.variable.readCount > 0) {
+          // The assignment could not be propagated into the successor, either
+          // because it has an unsafe variable use (see [hasUnsafeVariableUse])
+          // or because the use is outside the current try block, and we do
+          // not currently support constant propagation out of a try block.
+          constantEnvironment.remove(assign.variable);
+          assign.value = visitExpression(assign.value);
+          stmt.next = next;
+          return stmt;
+        } else {
+          --assign.variable.writeCount;
+          return next;
+        }
       } else {
         // With more than one use, we cannot propagate the constant.
         // Visit the following statement without polluting [environment] so
         // that any preceding non-constant assignments might still propagate.
         stmt.next = visitStatement(stmt.next);
+        popDominatingAssignment(leftHand);
         assign.value = visitExpression(assign.value);
         return stmt;
       }
@@ -325,6 +403,7 @@
     // until this has propagated.
     environment.add(stmt.expression);
     stmt.next = visitStatement(stmt.next);
+    popDominatingAssignment(leftHand);
     if (!environment.isEmpty && environment.last == stmt.expression) {
       // Retain the expression statement.
       environment.removeLast();
@@ -549,7 +628,9 @@
       safeForInlining = new Set<Label>();
       node.tryBody = visitStatement(node.tryBody);
       safeForInlining = saved;
+      node.catchParameters.forEach(pushDominatingAssignment);
       node.catchBody = visitStatement(node.catchBody);
+      node.catchParameters.forEach(popDominatingAssignment);
     });
     return node;
   }
@@ -755,7 +836,11 @@
       // We are not in risk of reprocessing the original subexpressions because
       // the combined expression will always hide them inside a Conditional.
       environment.add(values.combined);
+
+      Variable leftHand = getLeftHand(values.combined);
+      pushDominatingAssignment(leftHand);
       Statement next = combineStatements(s.next, t.next);
+      popDominatingAssignment(leftHand);
 
       if (next == null) {
         // Statements could not be combined.
@@ -830,7 +915,10 @@
           combineExpressions(s.expression, t.expression);
       if (values == null) return null;
       environment.add(values.combined);
+      Variable leftHand = getLeftHand(values.combined);
+      pushDominatingAssignment(leftHand);
       Statement next = combineStatements(s.next, t.next);
+      popDominatingAssignment(leftHand);
       if (next == null) {
         // The successors could not be combined.
         // Restore the environment and uncombine the values again.
@@ -1046,3 +1134,19 @@
 
   visitInnerFunction(FunctionDefinition node) {}
 }
+
+typedef VariableUseCallback(VariableUse use);
+
+class VariableUseVisitor extends RecursiveVisitor {
+  VariableUseCallback callback;
+
+  VariableUseVisitor(this.callback);
+
+  visitVariableUse(VariableUse use) => callback(use);
+
+  visitInnerFunction(FunctionDefinition node) {}
+
+  static void visit(Expression node, VariableUseCallback callback) {
+    new VariableUseVisitor(callback).visitExpression(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 6e39aae..6ca4430 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -54,15 +54,6 @@
   // is the mapping from continuations to labels.
   final Map<cps_ir.Continuation, Label> labels = <cps_ir.Continuation, Label>{};
 
-  /// A stack of singly-used labels that can be safely inlined at their use
-  /// site.
-  ///
-  /// Code for continuations with exactly one use is inlined at the use site.
-  /// This is not safe if the code is moved inside the scope of an exception
-  /// handler (i.e., into a try block).  We keep a stack of singly-referenced
-  /// continuations that are in scope without crossing a binding for a handler.
-  List<cps_ir.Continuation> safeForInlining = <cps_ir.Continuation>[];
-
   ExecutableElement currentElement;
   /// The 'this' Parameter for currentElement or the enclosing method.
   cps_ir.Parameter thisParameter;
@@ -318,16 +309,12 @@
 
   Statement visitLetCont(cps_ir.LetCont node) {
     // Introduce labels for continuations that need them.
-    int safeForInliningLengthOnEntry = safeForInlining.length;
     for (cps_ir.Continuation continuation in node.continuations) {
       if (continuation.hasMultipleUses || continuation.isRecursive) {
         labels[continuation] = new Label();
-      } else {
-        safeForInlining.add(continuation);
       }
     }
     Statement body = visit(node.body);
-    safeForInlining.length = safeForInliningLengthOnEntry;
     // Continuations are bound at the same level, but they have to be
     // translated as if nested.  This is because the body can invoke any
     // of them from anywhere, so it must be nested inside all of them.
@@ -352,10 +339,7 @@
   }
 
   Statement visitLetHandler(cps_ir.LetHandler node) {
-    List<cps_ir.Continuation> saved = safeForInlining;
-    safeForInlining = <cps_ir.Continuation>[];
     Statement tryBody = visit(node.body);
-    safeForInlining = saved;
     List<Variable> catchParameters =
         node.handler.parameters.map(getVariable).toList();
     Statement catchBody = visit(node.handler.body);
@@ -366,7 +350,7 @@
     // Calls are translated to direct style.
     List<Expression> arguments = translateArguments(node.arguments);
     Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
-        sourceInformation: node.sourceInformation);
+                                         node.sourceInformation);
     return continueWithExpression(node.continuation, invoke);
   }
 
@@ -490,7 +474,7 @@
                   : new WhileTrue(labels[cont], visit(cont.body));
             } else {
               if (cont.hasExactlyOneUse) {
-                if (safeForInlining.contains(cont)) {
+                if (!node.isEscapingTry) {
                   return visit(cont.body);
                 }
                 labels[cont] = new Label();
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index ab549e2..b30c368 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -181,16 +181,8 @@
   final Selector selector;
   final SourceInformation sourceInformation;
 
-  /// True if the [target] is known not to diverge or read or write any
-  /// mutable state.
-  ///
-  /// This is set for calls to `getInterceptor` and `identical` to indicate
-  /// that they can be safely be moved across an impure expression
-  /// (assuming the [arguments] are not affected by the impure expression).
-  bool isEffectivelyConstant = false;
-
   InvokeStatic(this.target, this.selector, this.arguments,
-               {this.sourceInformation});
+               [this.sourceInformation]);
 
   accept(ExpressionVisitor visitor) => visitor.visitInvokeStatic(this);
   accept1(ExpressionVisitor1 visitor, arg) {
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 215bfa5..3e90be4 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -26,13 +26,14 @@
 import 'filenames.dart' as filenames;
 import 'inferrer/concrete_types_inferrer.dart' as concrete_types_inferrer;
 import 'inferrer/type_graph_inferrer.dart' as type_graph_inferrer;
-import 'io/code_output.dart' as io;
+import 'io/line_column_provider.dart' as io;
 import 'io/source_map_builder.dart' as io;
 import 'js/js.dart' as js;
 import 'js_backend/js_backend.dart' as js_backend;
 import 'js_emitter/js_emitter.dart' as js_emitter;
-import 'js_emitter/program_builder.dart' as program_builder;
+import 'js_emitter/program_builder/program_builder.dart' as program_builder;
 import 'resolution/semantic_visitor.dart' as semantic_visitor;
+import 'resolution/operators.dart' as operators;
 import 'source_file_provider.dart' as source_file_provider;
 import 'ssa/ssa.dart' as ssa;
 import 'tree/tree.dart' as tree;
@@ -50,7 +51,7 @@
   useApi(null);
   dart2js.main(arguments);
   dart2jslib.isPublicName(null);
-  useConstant(null, null, null, null, null);
+  useConstant();
   useNode(null);
   useUtil(null);
   useSetlet(null);
@@ -65,7 +66,7 @@
   useColor();
   useFilenames();
   useSsa(null);
-  useIo(null, null);
+  useIo();
   usedByTests();
   useElements();
   useIr(null);
@@ -81,16 +82,38 @@
 useApi(api.ReadStringFromUri uri) {
 }
 
-void useConstant(constants.ConstantValue constant,
-                 constants.ConstantExpression expression,
-                 constants.ConstructedConstantExpression constructedConstant,
-                 constants.ConstantSystem cs,
-                 constants.Environment env) {
+class NullConstantConstructorVisitor extends constants.ConstantConstructorVisitor {
+  @override
+  visitGenerative(constants.GenerativeConstantConstructor constructor, arg) {
+  }
+
+  @override
+  visitRedirectingFactory(
+      constants.RedirectingFactoryConstantConstructor constructor, arg) {
+  }
+
+  @override
+  visitRedirectingGenerative(
+      constants.RedirectingGenerativeConstantConstructor constructor, arg) {
+  }
+}
+
+void useConstant([constants.ConstantValue constant,
+                  constants.ConstantExpression expression,
+                  constants.ConstructedConstantExpression constructedConstant,
+                  constants.ConstantSystem cs,
+                  constants.Environment env]) {
   constant.isObject;
   cs.isBool(constant);
   constructedConstant.computeInstanceType();
   constructedConstant.computeInstanceFields();
   expression.evaluate(null, null);
+  new NullConstantConstructorVisitor()
+      ..visit(null, null)
+      ..visitGenerative(null, null)
+      ..visitRedirectingFactory(null, null)
+      ..visitRedirectingGenerative(null, null);
+
 }
 
 void useNode(tree.Node node) {
@@ -217,11 +240,13 @@
   new ssa.HStatementSequenceInformation(null);
 }
 
-useIo(io.CodeBuffer buffer, io.LineColumnMap map) {
+useIo([io.LineColumnMap map,
+       io.LineColumnProvider provider]) {
   map..addFirst(null, null, null)
      ..forEachLine(null)
      ..getFirstElementsInLine(null)
      ..forEachColumn(null, null);
+  provider.getOffset(null, null);
 }
 
 usedByTests() {
@@ -232,6 +257,7 @@
   compiler.currentlyInUserCode();
   type_graph_inferrer.TypeGraphInferrer typeGraphInferrer = null;
   source_file_provider.SourceFileProvider sourceFileProvider = null;
+  sourceFileProvider.getSourceFile(null);
   world.hasAnyUserDefinedGetter(null, null);
   typeGraphInferrer.getCallersOf(null);
   dart_types.Types.sorted(null);
@@ -290,6 +316,8 @@
 }
 
 useSemanticVisitor() {
+  operators.UnaryOperator.fromKind(null);
+  operators.BinaryOperator.fromKind(null);
   new semantic_visitor.BulkSendVisitor()
       ..apply(null, null)
       ..visitSuperFieldFieldCompound(null, null, null, null, null, null);
diff --git a/pkg/compiler/lib/src/util/indentation.dart b/pkg/compiler/lib/src/util/indentation.dart
index 6206bd6..ddbeafa 100644
--- a/pkg/compiler/lib/src/util/indentation.dart
+++ b/pkg/compiler/lib/src/util/indentation.dart
@@ -51,3 +51,96 @@
     return result;
   }
 }
+
+abstract class Tagging<N> implements Indentation {
+
+  StringBuffer sb = new StringBuffer();
+  Link<String> tagStack = const Link<String>();
+
+  void pushTag(String tag) {
+    tagStack = tagStack.prepend(tag);
+    indentMore();
+  }
+
+  String popTag() {
+    assert(!tagStack.isEmpty);
+    String tag = tagStack.head;
+    tagStack = tagStack.tail;
+    indentLess();
+    return tag;
+  }
+
+  /**
+   * Adds given string to result string.
+   */
+  void add(String string) {
+    sb.write(string);
+  }
+
+  /// Adds default parameters for [node] into [params].
+  void addDefaultParameters(N node, Map params) {}
+
+  /**
+   * Adds given node type to result string.
+   * The method "opens" the node, meaning that all output after calling
+   * this method and before calling closeNode() will represent contents
+   * of given node.
+   */
+  void openNode(N node, String type, [Map params]) {
+    if (params == null) params = new Map();
+    addCurrentIndent();
+    sb.write("<");
+    addDefaultParameters(node, params);
+    addTypeWithParams(type, params);
+    sb.write(">\n");
+    pushTag(type);
+  }
+
+  /**
+   * Adds given node to result string.
+   */
+  void openAndCloseNode(N node, String type, [Map params]) {
+    if (params == null) params = {};
+    addCurrentIndent();
+    sb.write("<");
+    addDefaultParameters(node, params);
+    addTypeWithParams(type, params);
+    sb.write("/>\n");
+  }
+
+  /**
+   * Closes current node type.
+   */
+  void closeNode() {
+    String tag = popTag();
+    addCurrentIndent();
+    sb.write("</");
+    addTypeWithParams(tag);
+    sb.write(">\n");
+  }
+
+  void addTypeWithParams(String type, [Map params]) {
+    if (params == null) params = new Map();
+    sb.write("${type}");
+    params.forEach((k, v) {
+      String value;
+      if (v != null) {
+        String str = valueToString(v);
+        value = str
+            .replaceAll("<", "&lt;")
+            .replaceAll(">", "&gt;")
+            .replaceAll('"', "'");
+      } else {
+        value = "[null]";
+      }
+      sb.write(' $k="$value"');
+    });
+  }
+
+  void addCurrentIndent() {
+    sb.write(indentation);
+  }
+
+  /// Converts a parameter value into a string.
+  String valueToString(var value) => value;
+}
diff --git a/pkg/compiler/lib/src/util/link.dart b/pkg/compiler/lib/src/util/link.dart
index b45ea6c..31316e9 100644
--- a/pkg/compiler/lib/src/util/link.dart
+++ b/pkg/compiler/lib/src/util/link.dart
@@ -132,7 +132,7 @@
 
   List<T> toList();
 
-  void addLast(T t);
+  Link<T> addLast(T t);
 
   final int length;
   final bool isEmpty;
diff --git a/pkg/compiler/lib/src/util/link_implementation.dart b/pkg/compiler/lib/src/util/link_implementation.dart
index 5359102..7cea7d9 100644
--- a/pkg/compiler/lib/src/util/link_implementation.dart
+++ b/pkg/compiler/lib/src/util/link_implementation.dart
@@ -180,7 +180,7 @@
     return list;
   }
 
-  void addLast(T t) {
+  Link<T> addLast(T t) {
     length++;
     LinkEntry<T> entry = new LinkEntry<T>(t, null);
     if (head == null) {
@@ -189,6 +189,7 @@
       lastLink.tail = entry;
     }
     lastLink = entry;
+    return entry;
   }
 
   bool get isEmpty => length == 0;
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index a078492..d1f45c5 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -3,7 +3,7 @@
 name: compiler
 #version: do-not-upload
 dependencies:
-  package_config: ^0.0.4
+  package_config: ^0.1.1
   js_ast:
     path: ../js_ast
   js_runtime:
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 924f2f4..f111d4a 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -70,8 +70,8 @@
     Class,
     Method;
 
-import 'package:compiler/src/js_emitter/program_builder.dart' show
-    ProgramBuilder;
+import 'package:compiler/src/js_emitter/program_builder/program_builder.dart'
+    show ProgramBuilder;
 
 import 'package:js_runtime/shared/embedded_names.dart'
     as embeddedNames;
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 33b5c58..95c8819 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -588,6 +588,12 @@
     implements Declaration, Parameter, Comparable {
   accept(NodeVisitor visitor) => visitor.visitName(this);
 
+  /// Returns a unique [key] for this name.
+  ///
+  /// The key is unrelated to the actual name and is not intended for human
+  /// consumption. As such, it might be long or cryptic.
+  String get key;
+
   bool get allowRename => false;
 }
 
@@ -597,6 +603,10 @@
   LiteralStringFromName(this.name) : super(null);
 
   String get value => '"${name.name}"';
+
+  void visitChildren(NodeVisitor visitor) {
+    name.accept(visitor);
+  }
 }
 
 class LiteralExpression extends Expression {
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index ff757b4..8523916 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -5,15 +5,21 @@
 part of js_ast;
 
 
+typedef String Renamer(Name);
+
 class JavaScriptPrintingOptions {
   final bool shouldCompressOutput;
   final bool minifyLocalVariables;
   final bool preferSemicolonToNewlineInMinifiedOutput;
+  final Renamer renamerForNames;
 
   JavaScriptPrintingOptions(
       {this.shouldCompressOutput: false,
        this.minifyLocalVariables: false,
-       this.preferSemicolonToNewlineInMinifiedOutput: false});
+       this.preferSemicolonToNewlineInMinifiedOutput: false,
+       this.renamerForNames: identityRenamer});
+
+  static String identityRenamer(Name name) => name.name;
 }
 
 
@@ -360,7 +366,9 @@
       out("else");
       if (elsePart is If) {
         pendingSpace = true;
+        startNode(elsePart);
         ifOut(elsePart, false);
+        endNode(elsePart);
       } else {
         blockBody(unwrapBlockIfSingleStatement(elsePart),
                   needsSeparation: true, needsNewline: true);
@@ -628,7 +636,10 @@
     VarCollector vars = new VarCollector();
     vars.visitFunctionDeclaration(declaration);
     indent();
-    functionOut(declaration.function, declaration.name, vars);
+    startNode(declaration.function);
+    currentNode.closingPosition =
+        functionOut(declaration.function, declaration.name, vars);
+    endNode(declaration.function);
     lineOut();
   }
 
@@ -924,13 +935,17 @@
       if (isValidJavaScriptId(fieldWithQuotes)) {
         if (access.receiver is LiteralNumber) out(" ", isWhitespace: true);
         out(".");
+        startNode(selector);
         out(fieldWithQuotes.substring(1, fieldWithQuotes.length - 1));
+        endNode(selector);
         return;
       }
     } else if (selector is Name) {
       if (access.receiver is LiteralNumber) out(" ", isWhitespace: true);
       out(".");
-      out(selector.name);
+      startNode(selector);
+      selector.accept(this);
+      endNode(selector);
       return;
     }
     out("[");
@@ -998,7 +1013,7 @@
 
   @override
   visitName(Name node) {
-    out(node.name);
+    out(options.renamerForNames(node));
   }
 
   @override
@@ -1022,7 +1037,9 @@
         // in last position. Otherwise `[,]` (having length 1) would become
         // equal to `[]` (the empty array)
         // and [1,,] (array with 1 and a hole) would become [1,] = [1].
+        startNode(element);
         out(",");
+        endNode(element);
         continue;
       }
       if (i != 0) spaceOut();
@@ -1069,6 +1086,7 @@
 
   @override
   void visitProperty(Property node) {
+    startNode(node.name);
     if (node.name is LiteralString) {
       LiteralString nameString = node.name;
       String name = nameString.value;
@@ -1084,6 +1102,7 @@
       LiteralNumber nameNumber = node.name;
       out(nameNumber.value);
     }
+    endNode(node.name);
     out(":");
     spaceOut();
     visitNestedExpression(node.value, ASSIGNMENT,
diff --git a/pkg/js_ast/test/printer_callback_test.dart b/pkg/js_ast/test/printer_callback_test.dart
index b4ff074..dbd248b 100644
--- a/pkg/js_ast/test/printer_callback_test.dart
+++ b/pkg/js_ast/test/printer_callback_test.dart
@@ -12,14 +12,26 @@
 import 'package:unittest/unittest.dart';
 
 enum TestMode {
+  INPUT,
   NONE,
   ENTER,
   DELIMITER,
   EXIT,
 }
 
-const DATA = const [
-  const {
+class TestCase {
+  final Map<TestMode, String> data;
+
+  /// Map from template names to the inserted values.
+  final Map<String, String> environment;
+
+  const TestCase(
+      this.data,
+      [this.environment = const {}]);
+}
+
+const List<TestCase> DATA = const <TestCase>[
+  const TestCase(const {
     TestMode.NONE: """
 function(a, b) {
   return null;
@@ -36,15 +48,15 @@
 function(a@1, b@2) {
   return null@5;
 @4}@3@0"""
-  },
+  }),
 
-  const {
+  const TestCase(const {
     TestMode.NONE: """
 function() {
   if (true) {
     foo1();
     foo2();
-  } else {
+  } else if (false) {
     bar1();
     bar2();
   }
@@ -58,13 +70,13 @@
   @2if (@3true) @4{
     @5@6@7foo1();
     @8@9@10foo2();
-  } else @11{
-    @12@13@14bar1();
-    @15@16@17bar2();
+  } else @11if (@12false) @13{
+    @14@15@16bar1();
+    @17@18@19bar2();
   }
-  @18while (@19false) @20{
-    @21@22@23baz3();
-    @24@25@26baz4();
+  @20while (@21false) @22{
+    @23@24@25baz3();
+    @26@27@28baz4();
   }
 }""",
     TestMode.DELIMITER: """
@@ -72,7 +84,7 @@
   if (true) {
     foo1();
     foo2();
-  } else {
+  } else if (false) {
     bar1();
     bar2();
   }
@@ -86,26 +98,107 @@
   if (true@3) {
     foo1@7()@6;
 @5    foo2@10()@9;
-@8  }@4 else {
-    bar1@14()@13;
-@12    bar2@17()@16;
-@15  }@11
-@2  while (false@19) {
-    baz3@23()@22;
-@21    baz4@26()@25;
-@24  }@20
-@18}@1@0""",
-  },
+@8  }@4 else if (false@12) {
+    bar1@16()@15;
+@14    bar2@19()@18;
+@17  }@13
+@11@2  while (false@21) {
+    baz3@25()@24;
+@23    baz4@28()@27;
+@26  }@22
+@20}@1@0""",
+  }),
+
+  const TestCase(const {
+    TestMode.NONE: """
+function() {
+  function foo() {
+  }
+}""",
+    TestMode.ENTER: """
+@0function() @1{
+  @2@3function @4foo() @5{
+  }
+}""",
+    TestMode.DELIMITER: """
+function() {
+  function foo() {
+  @3}
+@0}""",
+   TestMode.EXIT: """
+function() {
+  function foo@4() {
+  }@5@3
+@2}@1@0"""
+  }),
+
+  const TestCase(const {
+    TestMode.INPUT: """
+function() {
+  a['b'];
+  [1,, 2];
+}""",
+    TestMode.NONE: """
+function() {
+  a.b;
+  [1,, 2];
+}""",
+    TestMode.ENTER: """
+@0function() @1{
+  @2@3@4a.@5b;
+  @6@7[@81,@9, @102];
+}""",
+    TestMode.DELIMITER: """
+function() {
+  a.b;
+  [1,, 2];
+@0}""",
+   TestMode.EXIT: """
+function() {
+  a@4.b@5@3;
+@2  [1@8,,@9 2@10]@7;
+@6}@1@0""",
+  }),
+
+  const TestCase(const {
+    TestMode.INPUT: "a.#nameTemplate",
+    TestMode.NONE: "a.nameValue",
+    TestMode.ENTER: "@0@1a.@2nameValue",
+    TestMode.DELIMITER: "a.nameValue",
+    TestMode.EXIT: "a@1.nameValue@2@0",
+  }, const {'nameTemplate': 'nameValue'}),
 ];
 
-void check(Map<TestMode, String> map) {
-  String code = map[TestMode.NONE];
+class FixedName extends Name {
+  final String name;
+  String get key => name;
+
+  FixedName(this.name);
+
+  @override
+  int compareTo(other) => 0;
+}
+
+void check(TestCase testCase) {
+  Map<TestMode, String> map = testCase.data;
+  String code = map[TestMode.INPUT];
+  if (code == null) {
+    // Input is the same as output.
+    code = map[TestMode.NONE];
+  }
   JavaScriptPrintingOptions options = new JavaScriptPrintingOptions();
-  Node node = js.parseForeignJS(code).instantiate({});
+  Map arguments = {};
+  testCase.environment.forEach((String name, String value) {
+    arguments[name] = new FixedName(value);
+  });
+  Node node = js.parseForeignJS(code).instantiate(arguments);
   map.forEach((TestMode mode, String expectedOutput) {
+    if (mode == TestMode.INPUT) return;
     Context context = new Context(mode);
     new Printer(options, context).visit(node);
-    expect(context.getText(), equals(expectedOutput),
+    // TODO(johnniwinther): Remove `replaceAll(...)` when dart2js behaves as the
+    // VM on newline in multiline strings.
+    expect(context.getText(), equals(expectedOutput.replaceAll('\r\n', '\n')),
         reason: "Unexpected output for $code in $mode");
   });
 }
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 5bb70dc..f105670 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -150,47 +150,46 @@
 analyzer/test/*: PubGetError
 
 [ $compiler == dart2js && $cps_ir ]
-analyzer/test/cancelable_future_test: Crash # Invalid argument(s)
-analyzer/test/enum_test: Crash # Invalid argument(s)
-analyzer/test/file_system/memory_file_system_test: Crash # Invalid argument(s)
-analyzer/test/file_system/physical_resource_provider_test: Crash # Invalid argument(s)
-analyzer/test/file_system/resource_uri_resolver_test: Crash # Invalid argument(s)
-analyzer/test/generated/all_the_rest_test: Crash # Invalid argument(s)
-analyzer/test/generated/ast_test: Crash # Invalid argument(s)
-analyzer/test/generated/compile_time_error_code_test: Crash # Invalid argument(s)
-analyzer/test/generated/element_test: Crash # Invalid argument(s)
-analyzer/test/generated/incremental_resolver_test: Crash # Invalid argument(s)
-analyzer/test/generated/incremental_scanner_test: Crash # Invalid argument(s)
-analyzer/test/generated/java_core_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-analyzer/test/generated/non_error_resolver_test: Crash # Invalid argument(s)
-analyzer/test/generated/parser_test: Crash # Invalid argument(s)
-analyzer/test/generated/resolver_test: Crash # Invalid argument(s)
-analyzer/test/generated/scanner_test: Crash # Invalid argument(s)
-analyzer/test/generated/static_type_warning_code_test: Crash # Invalid argument(s)
-analyzer/test/generated/static_warning_code_test: Crash # Invalid argument(s)
-analyzer/test/generated/type_system_test: Crash # Invalid argument(s)
-analyzer/test/generated/utilities_test: Crash # Invalid argument(s)
-analyzer/test/instrumentation/instrumentation_test: Crash # Invalid argument(s)
-analyzer/test/parse_compilation_unit_test: Crash # Invalid argument(s)
-analyzer/test/source/package_map_provider_test: Crash # Invalid argument(s)
-analyzer/test/source/package_map_resolver_test: Crash # Invalid argument(s)
-analyzer/test/src/context/cache_test: Crash # Invalid argument(s)
-analyzer/test/src/context/context_test: Crash # Invalid argument(s)
-analyzer/test/src/task/dart_test: Crash # Invalid argument(s)
-analyzer/test/src/task/dart_work_manager_test: Crash # Invalid argument(s)
-analyzer/test/src/task/driver_test: Crash # Invalid argument(s)
-analyzer/test/src/task/general_test: Crash # Invalid argument(s)
-analyzer/test/src/task/html_test: Crash # Invalid argument(s)
-analyzer/test/src/task/html_work_manager_test: Crash # Invalid argument(s)
-analyzer/test/src/task/incremental_element_builder_test: Crash # Invalid argument(s)
-analyzer/test/src/task/inputs_test: Crash # Invalid argument(s)
-analyzer/test/src/task/manager_test: Crash # Invalid argument(s)
-analyzer/test/src/task/model_test: Crash # Invalid argument(s)
-analyzer/test/src/util/asserts_test: Crash # Invalid argument(s)
-analyzer/test/src/util/lru_map_test: Crash # Invalid argument(s)
-fixnum/test/int_32_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-fixnum/test/int_64_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-typed_data/test/typed_buffers_test/01: Crash # Invalid argument(s)
-typed_data/test/typed_buffers_test/none : RuntimeError # TypeError: receiver.get$_nums is not a function
-typed_mock/test/typed_mock_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-analyzer/test/generated/source_factory_test : Crash # Invalid argument(s)
+analyzer/test/cancelable_future_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/enum_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/file_system/memory_file_system_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/file_system/physical_resource_provider_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/file_system/resource_uri_resolver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/all_the_rest_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/ast_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/compile_time_error_code_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/element_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/incremental_resolver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/incremental_scanner_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/java_core_test: RuntimeError # receiver.get$_nums is not a function
+analyzer/test/generated/non_error_resolver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/parser_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/resolver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/scanner_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/source_factory_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/static_type_warning_code_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/static_warning_code_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/type_system_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/generated/utilities_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/instrumentation/instrumentation_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/parse_compilation_unit_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/source/package_map_provider_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/source/package_map_resolver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/context/cache_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/context/context_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/dart_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/dart_work_manager_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/driver_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/general_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/html_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/html_work_manager_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/incremental_element_builder_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/inputs_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/manager_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/task/model_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/util/asserts_test: Crash # The null object does not have a getter '_element'.
+analyzer/test/src/util/lru_map_test: Crash # The null object does not have a getter '_element'.
+fixnum/test/int_32_test: RuntimeError # receiver.get$_nums is not a function
+fixnum/test/int_64_test: RuntimeError # receiver.get$_nums is not a function
+typed_data/test/typed_buffers_test/none: RuntimeError # receiver.get$_nums is not a function
+typed_mock/test/typed_mock_test: RuntimeError # receiver.get$_nums is not a function
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index a2c33a4..3cf95f1 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -8,20 +8,17 @@
 
 [ $use_repository_packages ]
 pkg/analyzer: PubGetError
-pkg/compiler: PubGetError # Issue 23750
 samples/third_party/angular_todo: Fail # angular needs to be updated
 samples/third_party/todomvc_performance: Skip # dependencies are not in the repo
-third_party/pkg/package_config: PubGetError # Issue 23750
 
 [ $use_public_packages ]
-pkg/compiler: PubGetError # Issue 23750
+pkg/compiler: SkipByDesign # js_ast is not published
 samples/third_party/angular_todo: Pass, Slow
-third_party/pkg/async_await: Skip # Uses expect package.
 samples/third_party/todomvc_performance: Pass, Slow
 
 [ $builder_tag == russian ]
 samples/third_party/angular_todo: Fail # Issue 16356
-samples/third_party/dromaeo: Fail # Issue 23750
+samples/third_party/dromaeo: Fail # Issue 23760
 
 [ $use_public_packages && $system == windows ]
 samples/third_party/todomvc_performance: Fail # Issue 18086
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 2ee4114..bbc4d3e 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -143,8 +143,11 @@
 executable("gen_snapshot") {
   configs += ["..:dart_config"]
   deps = [
-    ":libdart_nosnapshot",
+    ":generate_builtin_cc_file",
+    ":generate_io_cc_file",
+    ":generate_io_patch_cc_file",
     ":libdart_builtin",
+    ":libdart_nosnapshot",
   ]
 
   sources = [
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index ce151cf..a278595 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -1222,7 +1222,7 @@
   // This method must support smi._toBigint()._shrFromInt(int).
   int _shrFromInt(int other) {
     if (_used == 0) return other;  // Shift amount is zero.
-    if (_neg) throw new RangeError(this);
+    if (_neg) throw new RangeError.range(this, 0, null);
     assert(_DIGIT_BITS == 32);  // Otherwise this code needs to be revised.
     var shift;
     if ((_used > 2) || ((_used == 2) && (_digits[1] > 0x10000000))) {
@@ -1241,7 +1241,7 @@
   // An out of memory exception is thrown if the result cannot be allocated.
   int _shlFromInt(int other) {
     if (_used == 0) return other;  // Shift amount is zero.
-    if (_neg) throw new RangeError(this);
+    if (_neg) throw new RangeError.range(this, 0, null);
     assert(_DIGIT_BITS == 32);  // Otherwise this code needs to be revised.
     var shift;
     if (_used > 2 || (_used == 2 && _digits[1] > 0x10000000)) {
@@ -1399,10 +1399,14 @@
 
   // Returns pow(this, e) % m, with e >= 0, m > 0.
   int modPow(int e, int m) {
-    if (e is! int) throw new ArgumentError(e);
-    if (m is! int) throw new ArgumentError(m);
-    if (e < 0) throw new RangeError(e);
-    if (m <= 0) throw new RangeError(m);
+    if (e is! int) {
+      throw new ArgumentError.value(e, "exponent", "not an integer");
+    }
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (e < 0) throw new RangeError.range(e, 0, null, "exponent");
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (e == 0) return 1;
     m = m._toBigint();
     final m_used = m._used;
@@ -1543,7 +1547,7 @@
 
   // If inv is false, returns gcd(x, y).
   // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
-  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
   static int _binaryGcd(_Bigint x, _Bigint y, bool inv) {
     var x_digits = x._digits;
     var y_digits = y._digits;
@@ -1557,10 +1561,15 @@
     if (inv) {
       if ((y_used == 1) && (y_digits[0] == 1)) return 1;
       if ((y_used == 0) || (y_digits[0].isEven && x_digits[0].isEven)) {
-        throw new RangeError("Not coprime");
+        throw new Exception("Not coprime");
       }
     } else {
-      if ((x_used == 0) || (y_used == 0)) throw new RangeError(0);
+      if (x_used == 0) {
+        throw new ArgumentError.value(0, "this", "must not be zero");
+      }
+      if (y_used == 0) {
+        throw new ArgumentError.value(0, "other", "must not be zero");
+      }
       if (((x_used == 1) && (x_digits[0] == 1)) ||
           ((y_used == 1) && (y_digits[0] == 1))) return 1;
       bool xy_cloned = false;
@@ -1756,7 +1765,9 @@
     // No inverse if v != 1.
     var i = m_used - 1;
     while ((i > 0) && (v_digits[i] == 0)) --i;
-    if ((i != 0) || (v_digits[0] != 1)) throw new RangeError("Not coprime");
+    if ((i != 0) || (v_digits[0] != 1)) {
+      throw new Exception("Not coprime");
+    }
 
     if (d_neg) {
       if ((d_digits[m_used] != 0) ||
@@ -1786,8 +1797,10 @@
 
   // Returns 1/this % m, with m > 0.
   int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (m == 1) return 0;
     m = m._toBigint();
     var t = this;
@@ -1798,9 +1811,14 @@
     return _binaryGcd(m, t, true);
   }
 
-  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  // Returns gcd of abs(this) and abs(other).
   int gcd(int other) {
-    if (other is! int) throw new ArgumentError(other);
+    if (other is! int) {
+      throw new ArgumentError.value(other, "other", "not an integer");
+    }
+    if (other == 0) {
+      return this.abs();
+    }
     return _binaryGcd(this, other._toBigint(), false);
   }
 }
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index be0cb8f..63f868b 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -175,21 +175,23 @@
   double truncateToDouble() { return this.toDouble(); }
 
   num clamp(num lowerLimit, num upperLimit) {
-    if (lowerLimit is! num) throw new ArgumentError(lowerLimit);
-    if (upperLimit is! num) throw new ArgumentError(upperLimit);
+    if (lowerLimit is! num) {
+      throw new ArgumentError.value(lowerLimit, "lowerLimit");
+    }
+    if (upperLimit is! num) {
+      throw new ArgumentError.value(upperLimit, "upperLimit");
+    }
 
     // Special case for integers.
-    if (lowerLimit is int && upperLimit is int) {
-      if (lowerLimit > upperLimit) {
-        throw new ArgumentError(lowerLimit);
-      }
+    if (lowerLimit is int && upperLimit is int &&
+        lowerLimit <= upperLimit) {
       if (this < lowerLimit) return lowerLimit;
       if (this > upperLimit) return upperLimit;
       return this;
     }
-    // Generic case involving doubles.
+    // Generic case involving doubles, and invalid integer ranges.
     if (lowerLimit.compareTo(upperLimit) > 0) {
-      throw new ArgumentError(lowerLimit);
+      throw new RangeError.range(upperLimit, lowerLimit, null, "upperLimit");
     }
     if (lowerLimit.isNaN) return lowerLimit;
     // Note that we don't need to care for -0.0 for the lower limit.
@@ -216,8 +218,8 @@
   static const _digits = "0123456789abcdefghijklmnopqrstuvwxyz";
 
   String toRadixString(int radix) {
-    if (radix is! int || radix < 2 || radix > 36) {
-      throw new ArgumentError(radix);
+    if (radix < 2 || 36 < radix) {
+      throw new RangeError.range(radix, 2, 36, "radix");
     }
     if (radix & (radix - 1) == 0) {
       return _toPow2String(radix);
@@ -267,10 +269,14 @@
 
   // Returns pow(this, e) % m.
   int modPow(int e, int m) {
-    if (e is! int) throw new ArgumentError(e);
-    if (m is! int) throw new ArgumentError(m);
-    if (e < 0) throw new RangeError(e);
-    if (m <= 0) throw new RangeError(m);
+    if (e is! int) {
+      throw new ArgumentError.value(e, "exponent", "not an integer");
+    }
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (e < 0) throw new RangeError.range(e, 0, null, "exponent");
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (e == 0) return 1;
     if (e is _Bigint || m is _Bigint) {
       return _toBigint().modPow(e, m);
@@ -292,7 +298,7 @@
 
   // If inv is false, returns gcd(x, y).
   // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
-  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
   static int _binaryGcd(int x, int y, bool inv) {
     int s = 0;
     if (!inv) {
@@ -352,7 +358,9 @@
       }
     } while (u != 0);
     if (!inv) return v << s;
-    if (v != 1) throw new RangeError("Not coprime");
+    if (v != 1) {
+      throw new Exception("Not coprime");
+    }
     if (d < 0) {
       d += x;
       if (d < 0) d += x;
@@ -365,8 +373,10 @@
 
   // Returns 1/this % m, with m > 0.
   int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (m == 1) return 0;
     if (m is _Bigint) {
       return _toBigint().modInverse(m);
@@ -374,16 +384,21 @@
     int t = this;
     if ((t < 0) || (t >= m)) t %= m;
     if (t == 1) return 1;
-    if ((t == 0) || (t.isEven && m.isEven)) throw new RangeError("Not coprime");
+    if ((t == 0) || (t.isEven && m.isEven)) {
+      throw new Exception("Not coprime");
+    }
     return _binaryGcd(m, t, true);
   }
 
-  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  // Returns gcd of abs(this) and abs(other).
   int gcd(int other) {
-    if (other is! int) throw new ArgumentError(other);
-    if ((this == 0) || (other == 0)) throw new RangeError(0);
+    if (other is! int) {
+      throw new ArgumentError.value(other, "other", "not an integer");
+    }
     int x = this.abs();
     int y = other.abs();
+    if (x == 0) return y;
+    if (y == 0) return x;
     if ((x == 1) || (y == 1)) return 1;
     if (other is _Bigint) {
       return _toBigint().gcd(other);
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3ffbff8..33af271 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -18,6 +18,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, lazy_dispatchers);
+
 #define PROPAGATE_IF_MALFORMED(type)                                           \
   if (type.IsMalformed()) {                                                    \
     Exceptions::PropagateError(Error::Handle(type.error()));                   \
@@ -739,37 +741,6 @@
 }
 
 
-static RawInstance* InvokeInstanceGetter(const Class& klass,
-                                         const Instance& reflectee,
-                                         const String& getter_name,
-                                         const bool throw_nsm_if_absent) {
-  const String& internal_getter_name = String::Handle(
-      Field::GetterName(getter_name));
-  Function& function = Function::Handle(
-      Resolver::ResolveDynamicAnyArgs(klass, internal_getter_name));
-
-  if (!function.IsNull() || throw_nsm_if_absent) {
-    const int kNumArgs = 1;
-    const Array& args = Array::Handle(Array::New(kNumArgs));
-    args.SetAt(0, reflectee);
-    const Array& args_descriptor =
-        Array::Handle(ArgumentsDescriptor::New(args.Length()));
-
-    // InvokeDynamic invokes NoSuchMethod if the provided function is null.
-    return InvokeDynamicFunction(reflectee,
-                                 function,
-                                 internal_getter_name,
-                                 args,
-                                 args_descriptor);
-  }
-
-  // Fall through case: Indicate that we didn't find any function or field using
-  // a special null instance. This is different from a field being null. Callers
-  // make sure that this null does not leak into Dartland.
-  return Object::sentinel().raw();
-}
-
-
 static RawAbstractType* InstantiateType(const AbstractType& type,
                                         const AbstractType& instantiator) {
   ASSERT(type.IsFinalized());
@@ -1389,7 +1360,34 @@
   GET_NATIVE_ARGUMENT(Instance, reflectee, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(String, getter_name, arguments->NativeArgAt(2));
   Class& klass = Class::Handle(reflectee.clazz());
-  return InvokeInstanceGetter(klass, reflectee, getter_name, true);
+
+  const String& internal_getter_name = String::Handle(
+      Field::GetterName(getter_name));
+  Function& function = Function::Handle(
+      Resolver::ResolveDynamicAnyArgs(klass, internal_getter_name));
+
+  // Check for method extraction when method extractors are not created.
+  if (function.IsNull() && !FLAG_lazy_dispatchers) {
+    function = Resolver::ResolveDynamicAnyArgs(klass, getter_name);
+    if (!function.IsNull()) {
+      const Function& closure_function =
+        Function::Handle(function.ImplicitClosureFunction());
+      return closure_function.ImplicitInstanceClosure(reflectee);
+    }
+  }
+
+  const int kNumArgs = 1;
+  const Array& args = Array::Handle(Array::New(kNumArgs));
+  args.SetAt(0, reflectee);
+  const Array& args_descriptor =
+      Array::Handle(ArgumentsDescriptor::New(args.Length()));
+
+  // InvokeDynamic invokes NoSuchMethod if the provided function is null.
+  return InvokeDynamicFunction(reflectee,
+                               function,
+                               internal_getter_name,
+                               args,
+                               args_descriptor);
 }
 
 
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index fe88b85..2c43d96 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -207,6 +207,66 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Object_instanceOfNum, 2) {
+  const Instance& instance =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Bool& negate = Bool::CheckedHandle(zone, arguments->NativeArgAt(1));
+  bool is_instance_of = instance.IsNumber();
+  if (negate.value()) {
+    is_instance_of = !is_instance_of;
+  }
+  return Bool::Get(is_instance_of).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(Object_instanceOfInt, 2) {
+  const Instance& instance =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Bool& negate = Bool::CheckedHandle(zone, arguments->NativeArgAt(1));
+  bool is_instance_of = instance.IsInteger();
+  if (negate.value()) {
+    is_instance_of = !is_instance_of;
+  }
+  return Bool::Get(is_instance_of).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(Object_instanceOfSmi, 2) {
+  const Instance& instance =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Bool& negate = Bool::CheckedHandle(zone, arguments->NativeArgAt(1));
+  bool is_instance_of = instance.IsSmi();
+  if (negate.value()) {
+    is_instance_of = !is_instance_of;
+  }
+  return Bool::Get(is_instance_of).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(Object_instanceOfDouble, 2) {
+  const Instance& instance =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Bool& negate = Bool::CheckedHandle(zone, arguments->NativeArgAt(1));
+  bool is_instance_of = instance.IsDouble();
+  if (negate.value()) {
+    is_instance_of = !is_instance_of;
+  }
+  return Bool::Get(is_instance_of).raw();
+}
+
+
+DEFINE_NATIVE_ENTRY(Object_instanceOfString, 2) {
+  const Instance& instance =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Bool& negate = Bool::CheckedHandle(zone, arguments->NativeArgAt(1));
+  bool is_instance_of = instance.IsString();
+  if (negate.value()) {
+    is_instance_of = !is_instance_of;
+  }
+  return Bool::Get(is_instance_of).raw();
+}
+
+
 DEFINE_NATIVE_ENTRY(Object_as, 4) {
   const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
   // Instantiator at position 1 is not used. It is passed along so that the call
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index 52d7546..be42a57 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -59,6 +59,12 @@
                    bool negate)
       native "Object_instanceOf";
 
+  bool _instanceOfDouble(bool negate) native "Object_instanceOfDouble";
+  bool _instanceOfNum(bool negate) native "Object_instanceOfNum";
+  bool _instanceOfInt(bool negate) native "Object_instanceOfInt";
+  bool _instanceOfSmi(bool negate) native "Object_instanceOfSmi";
+  bool _instanceOfString(bool negate) native "Object_instanceOfString";
+
   // Call this function instead of inlining 'as', thus collecting type
   // feedback. Returns receiver.
   _as(instantiator, instantiator_type_arguments, type) native "Object_as";
diff --git a/runtime/lib/regexp.cc b/runtime/lib/regexp.cc
index 6ffeb6d..6fd9d6f 100644
--- a/runtime/lib/regexp.cc
+++ b/runtime/lib/regexp.cc
@@ -8,11 +8,14 @@
 #include "vm/native_entry.h"
 #include "vm/object.h"
 #include "vm/regexp_parser.h"
+#include "vm/regexp_assembler_ir.h"
+#include "vm/regexp_assembler_bytecode.h"
 #include "vm/thread.h"
 
 namespace dart {
 
 DECLARE_FLAG(bool, trace_irregexp);
+DECLARE_FLAG(bool, interpret_irregexp);
 
 
 DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_factory, 4) {
@@ -82,18 +85,23 @@
 DEFINE_NATIVE_ENTRY(JSSyntaxRegExp_ExecuteMatch, 3) {
   const JSRegExp& regexp = JSRegExp::CheckedHandle(arguments->NativeArgAt(0));
   ASSERT(!regexp.IsNull());
-  GET_NON_NULL_NATIVE_ARGUMENT(String, str, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(String, subject, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
 
+  if (FLAG_interpret_irregexp) {
+    return BytecodeRegExpMacroAssembler::Interpret(regexp, subject, start_index,
+                                                   zone);
+  }
+
   // This function is intrinsified. See Intrinsifier::JSRegExp_ExecuteMatch.
-  const intptr_t cid = str.GetClassId();
+  const intptr_t cid = subject.GetClassId();
 
   // Retrieve the cached function.
   const Function& fn = Function::Handle(regexp.function(cid));
   ASSERT(!fn.IsNull());
 
   // And finally call the generated code.
-  return IRRegExpMacroAssembler::Execute(fn, str, start_index, zone);
+  return IRRegExpMacroAssembler::Execute(fn, subject, start_index, zone);
 }
 
 }  // namespace dart
diff --git a/runtime/observatory/.gitignore b/runtime/observatory/.gitignore
index c73eaff..06adbfb 100644
--- a/runtime/observatory/.gitignore
+++ b/runtime/observatory/.gitignore
@@ -3,3 +3,4 @@
 build
 .pub
 .idea
+.packages
\ No newline at end of file
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 6367d4d..28d2c56 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1563,7 +1563,10 @@
 }
 
 
-void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
+void Assembler::LoadObjectHelper(Register rd,
+                                 const Object& object,
+                                 Condition cond,
+                                 bool is_unique) {
   // Smis and VM heap objects are never relocated; do not use object pool.
   if (object.IsSmi()) {
     LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond);
@@ -1574,13 +1577,26 @@
   } else {
     // Make sure that class CallPattern is able to decode this load from the
     // object pool.
-    const int32_t offset =
-        ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
+    const int32_t offset = ObjectPool::element_offset(
+       is_unique ? object_pool_wrapper_.AddObject(object)
+                 : object_pool_wrapper_.FindObject(object));
     LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond);
   }
 }
 
 
+void Assembler::LoadObject(Register rd, const Object& object, Condition cond) {
+  LoadObjectHelper(rd, object, cond, false);
+}
+
+
+void Assembler::LoadUniqueObject(Register rd,
+                                 const Object& object,
+                                 Condition cond) {
+  LoadObjectHelper(rd, object, cond, true);
+}
+
+
 void Assembler::LoadExternalLabel(Register rd,
                                   const ExternalLabel* label,
                                   Patchability patchable,
@@ -1966,13 +1982,18 @@
 }
 
 
-void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
 
   LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
   tst(object, Operand(kSmiTagMask));
   mov(TMP, Operand(object), NE);
   LoadClassId(result, TMP);
+}
+
+
+void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+  LoadClassIdMayBeSmi(result, object);
   SmiTag(result);
 }
 
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 24e41b0..f3d9583 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -666,6 +666,7 @@
   void LoadIsolate(Register rd);
 
   void LoadObject(Register rd, const Object& object, Condition cond = AL);
+  void LoadUniqueObject(Register rd, const Object& object, Condition cond = AL);
   void LoadExternalLabel(Register dst,
                          const ExternalLabel* label,
                          Patchability patchable,
@@ -739,6 +740,7 @@
   void LoadClassById(Register result, Register class_id);
   void LoadClass(Register result, Register object, Register scratch);
   void CompareClassId(Register object, intptr_t class_id, Register scratch);
+  void LoadClassIdMayBeSmi(Register result, Register object);
   void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
   void ComputeRange(Register result,
@@ -1000,6 +1002,11 @@
 
   bool allow_constant_pool_;
 
+  void LoadObjectHelper(Register rd,
+                        const Object& object,
+                        Condition cond,
+                        bool is_unique);
+
   void EmitType01(Condition cond,
                   int type,
                   Opcode opcode,
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 7b71e57..4e39862 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -52,13 +52,6 @@
     } else {
       object_pool_wrapper_.AddObject(vacant);
     }
-
-    if (stub_code->CallToRuntime_entry() != NULL) {
-      object_pool_wrapper_.AddExternalLabel(
-          &stub_code->CallToRuntimeLabel(), kNotPatchable);
-    } else {
-      object_pool_wrapper_.AddObject(vacant);
-    }
   }
 }
 
@@ -464,10 +457,14 @@
 }
 
 
-void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
+void Assembler::LoadObjectHelper(Register dst,
+                                 const Object& object,
+                                 Register pp,
+                                 bool is_unique) {
   if (CanLoadObjectFromPool(object)) {
-    const int32_t offset =
-        ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
+    const int32_t offset = ObjectPool::element_offset(
+        is_unique ? object_pool_wrapper_.AddObject(object)
+                  : object_pool_wrapper_.FindObject(object));
     LoadWordFromPoolOffset(dst, pp, offset);
   } else {
     ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
@@ -478,6 +475,18 @@
 }
 
 
+void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
+  LoadObjectHelper(dst, object, pp, false);
+}
+
+
+void Assembler::LoadUniqueObject(Register dst,
+                                 const Object& object,
+                                 Register pp) {
+  LoadObjectHelper(dst, object, pp, true);
+}
+
+
 void Assembler::CompareObject(Register reg, const Object& object, Register pp) {
   if (CanLoadObjectFromPool(object)) {
     LoadObject(TMP, object, pp);
@@ -1016,7 +1025,7 @@
 }
 
 
-void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   // Load up a null object. We only need it so we can use LoadClassId on it in
   // the case that object is a Smi..
   LoadObject(TMP, Object::null_object(), PP);
@@ -1031,6 +1040,11 @@
   LoadImmediate(TMP, kSmiCid, PP);
   // If object is a Smi, move the Smi cid into result. o/w leave alone.
   csel(result, TMP, result, EQ);
+}
+
+
+void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+  LoadClassIdMayBeSmi(result, object);
   // Finally, tag the result.
   SmiTag(result);
 }
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index 0ac4a69..1da9605 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1321,6 +1321,7 @@
                               Register pp);
   void LoadIsolate(Register dst, Register pp);
   void LoadObject(Register dst, const Object& obj, Register pp);
+  void LoadUniqueObject(Register dst, const Object& obj, Register pp);
   void LoadDecodableImmediate(Register reg, int64_t imm, Register pp);
   void LoadImmediateFixed(Register reg, int64_t imm);
   void LoadImmediate(Register reg, int64_t imm, Register pp);
@@ -1336,6 +1337,7 @@
   void LoadClassById(Register result, Register class_id, Register pp);
   void LoadClass(Register result, Register object, Register pp);
   void CompareClassId(Register object, intptr_t class_id, Register pp);
+  void LoadClassIdMayBeSmi(Register result, Register object);
   void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
   void ComputeRange(Register result,
@@ -1443,6 +1445,11 @@
 
   bool allow_constant_pool_;
 
+  void LoadObjectHelper(Register dst,
+                        const Object& obj,
+                        Register pp,
+                        bool is_unique);
+
   void AddSubHelper(OperandSize os, bool set_flags, bool subtract,
                     Register rd, Register rn, Operand o) {
     ASSERT((rd != R31) && (rn != R31));
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index bb54355..249fba0 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -3017,7 +3017,7 @@
 }
 
 
-void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   ASSERT(result != object);
   static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
 
@@ -3031,7 +3031,11 @@
   // Otherwise, the dummy object is used, and the result is kSmiCid.
   cmovne(result, object);
   LoadClassId(result, result);
+}
 
+
+void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+  LoadClassIdMayBeSmi(result, object);
   // Tag the result.
   SmiTag(result);
 }
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 1b386a3..7ebea1d 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -742,8 +742,8 @@
 
   void CompareClassId(Register object, intptr_t class_id, Register scratch);
 
-  void LoadTaggedClassIdMayBeSmi(Register result,
-                                 Register object);
+  void LoadClassIdMayBeSmi(Register result, Register object);
+  void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
   void SmiUntagOrCheckClass(Register object,
                             intptr_t class_id,
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index 29644ab..b418fc8 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -456,7 +456,9 @@
 }
 
 
-void Assembler::LoadObject(Register rd, const Object& object) {
+void Assembler::LoadObjectHelper(Register rd,
+                                 const Object& object,
+                                 bool is_unique) {
   ASSERT(!in_delay_slot_);
   // Smis and VM heap objects are never relocated; do not use object pool.
   if (object.IsSmi()) {
@@ -471,13 +473,24 @@
   } else {
     // Make sure that class CallPattern is able to decode this load from the
     // object pool.
-    const int32_t offset =
-        ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
+    const int32_t offset = ObjectPool::element_offset(
+        is_unique ? object_pool_wrapper_.AddObject(object)
+                  : object_pool_wrapper_.FindObject(object));
     LoadWordFromPoolOffset(rd, offset - kHeapObjectTag);
   }
 }
 
 
+void Assembler::LoadObject(Register rd, const Object& object) {
+  LoadObjectHelper(rd, object, false);
+}
+
+
+void Assembler::LoadUniqueObject(Register rd, const Object& object) {
+  LoadObjectHelper(rd, object, true);
+}
+
+
 void Assembler::LoadExternalLabel(Register rd,
                                   const ExternalLabel* label,
                                   Patchability patchable) {
@@ -667,7 +680,7 @@
 }
 
 
-void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
 
   LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
@@ -677,6 +690,11 @@
   }
   movz(result, TMP, CMPRES1);
   LoadClassId(result, result);
+}
+
+
+void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+  LoadClassIdMayBeSmi(result, object);
   SmiTag(result);
 }
 
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 79e6539..a4c379b 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1539,6 +1539,7 @@
 
   void LoadWordFromPoolOffset(Register rd, int32_t offset);
   void LoadObject(Register rd, const Object& object);
+  void LoadUniqueObject(Register rd, const Object& object);
   void LoadExternalLabel(Register rd,
                          const ExternalLabel* label,
                          Patchability patchable);
@@ -1549,6 +1550,7 @@
   void LoadClassId(Register result, Register object);
   void LoadClassById(Register result, Register class_id);
   void LoadClass(Register result, Register object);
+  void LoadClassIdMayBeSmi(Register result, Register object);
   void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
   void ComputeRange(Register result,
@@ -1650,6 +1652,8 @@
 
   bool allow_constant_pool_;
 
+  void LoadObjectHelper(Register rd, const Object& object, bool is_unique);
+
   void Emit(int32_t value) {
     // Emitting an instruction clears the delay slot state.
     in_delay_slot_ = false;
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 02f85df..66b36d0 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -49,13 +49,6 @@
     } else {
       object_pool_wrapper_.AddObject(vacant);
     }
-
-    if (stub_code->CallToRuntime_entry() != NULL) {
-      object_pool_wrapper_.AddExternalLabel(
-          &stub_code->CallToRuntimeLabel(), kNotPatchable);
-    } else {
-      object_pool_wrapper_.AddObject(vacant);
-    }
   }
 }
 
@@ -2841,10 +2834,14 @@
 }
 
 
-void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
+void Assembler::LoadObjectHelper(Register dst,
+                                 const Object& object,
+                                 Register pp,
+                                 bool is_unique) {
   if (CanLoadFromObjectPool(object)) {
-    const int32_t offset =
-        ObjectPool::element_offset(object_pool_wrapper_.FindObject(object));
+    const int32_t offset = ObjectPool::element_offset(
+        is_unique ? object_pool_wrapper_.AddObject(object)
+                  : object_pool_wrapper_.FindObject(object));
     LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
   } else {
     ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
@@ -2855,6 +2852,18 @@
 }
 
 
+void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
+  LoadObjectHelper(dst, object, pp, false);
+}
+
+
+void Assembler::LoadUniqueObject(Register dst,
+                                 const Object& object,
+                                 Register pp) {
+  LoadObjectHelper(dst, object, pp, true);
+}
+
+
 void Assembler::StoreObject(const Address& dst, const Object& object,
                             Register pp) {
   if (CanLoadFromObjectPool(object)) {
@@ -3793,7 +3802,7 @@
 }
 
 
-void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+void Assembler::LoadClassIdMayBeSmi(Register result, Register object) {
   ASSERT(result != object);
 
   // Load up a null object. We only need it so we can use LoadClassId on it in
@@ -3810,6 +3819,11 @@
   movq(object, Immediate(kSmiCid));
   // If object is a Smi, move the Smi cid into result. o/w leave alone.
   cmoveq(result, object);
+}
+
+
+void Assembler::LoadTaggedClassIdMayBeSmi(Register result, Register object) {
+  LoadClassIdMayBeSmi(result, object);
   // Finally, tag the result.
   SmiTag(result);
 }
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index c3ea20d..d964931 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -762,6 +762,7 @@
   void LoadImmediate(Register reg, const Immediate& imm, Register pp);
   void LoadIsolate(Register dst);
   void LoadObject(Register dst, const Object& obj, Register pp);
+  void LoadUniqueObject(Register dst, const Object& obj, Register pp);
   void LoadExternalLabel(Register dst,
                          const ExternalLabel* label,
                          Patchability patchable,
@@ -859,6 +860,7 @@
 
   void CompareClassId(Register object, intptr_t class_id);
 
+  void LoadClassIdMayBeSmi(Register result, Register object);
   void LoadTaggedClassIdMayBeSmi(Register result, Register object);
 
   // CheckClassIs fused with optimistic SmiUntag.
@@ -1066,6 +1068,10 @@
 
   intptr_t FindImmediate(int64_t imm);
   bool CanLoadFromObjectPool(const Object& object);
+  void LoadObjectHelper(Register dst,
+                        const Object& obj,
+                        Register pp,
+                        bool is_unique);
   void LoadWordFromPoolOffset(Register dst, Register pp, int32_t offset);
 
   inline void EmitUint8(uint8_t value);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 227a32b..6784ece 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -21,6 +21,11 @@
   V(Object_noSuchMethod, 6)                                                    \
   V(Object_runtimeType, 1)                                                     \
   V(Object_instanceOf, 5)                                                      \
+  V(Object_instanceOfNum, 2)                                                   \
+  V(Object_instanceOfInt, 2)                                                   \
+  V(Object_instanceOfSmi, 2)                                                   \
+  V(Object_instanceOfDouble, 2)                                                \
+  V(Object_instanceOfString, 2)                                                \
   V(Object_as, 4)                                                              \
   V(Function_apply, 2)                                                         \
   V(FunctionImpl_equals, 2)                                                    \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 46f3f4d..4af6636 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -248,6 +248,18 @@
 #endif  // defined(DART_NO_SNAPSHOT).
 
 
+static bool IsLoaded(const Type& type) {
+  if (type.HasResolvedTypeClass()) {
+    return true;
+  }
+  const UnresolvedClass& unresolved_class =
+      UnresolvedClass::Handle(type.unresolved_class());
+  const LibraryPrefix& prefix =
+      LibraryPrefix::Handle(unresolved_class.library_prefix());
+  return prefix.IsNull() || prefix.is_loaded();
+}
+
+
 // Resolve unresolved_class in the library of cls, or return null.
 RawClass* ClassFinalizer::ResolveClass(
       const Class& cls,
@@ -275,7 +287,7 @@
   const Function& target = Function::Handle(factory.RedirectionTarget());
   if (target.IsNull()) {
     Type& type = Type::Handle(factory.RedirectionType());
-    if (!type.IsMalformed()) {
+    if (!type.IsMalformed() && IsLoaded(type)) {
       const GrowableObjectArray& visited_factories =
           GrowableObjectArray::Handle(GrowableObjectArray::New());
       ResolveRedirectingFactoryTarget(cls, factory, visited_factories);
@@ -1498,9 +1510,13 @@
         // The function may be a still unresolved redirecting factory. Do not
         // yet try to resolve it in order to avoid cycles in class finalization.
         // However, the redirection type should be finalized.
+        // If the redirection type is from a deferred library and is not
+        // yet loaded, do not attempt to resolve.
         Type& type = Type::Handle(I, function.RedirectionType());
-        type ^= FinalizeType(cls, type, kCanonicalize);
-        function.SetRedirectionType(type);
+        if (IsLoaded(type)) {
+          type ^= FinalizeType(cls, type, kCanonicalize);
+          function.SetRedirectionType(type);
+        }
       }
     } else if (function.IsGetterFunction() ||
                function.IsImplicitGetterFunction()) {
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index a4359a7..dd977b2 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -724,6 +724,7 @@
                                      const String& target_name,
                                      const Array& arguments_descriptor,
                                      Function* result) {
+  ASSERT(FLAG_lazy_dispatchers);
   // 1. Check if there is a getter with the same name.
   const String& getter_name = String::Handle(Field::GetterName(target_name));
   const int kNumArguments = 1;
@@ -764,6 +765,10 @@
 RawFunction* InlineCacheMissHelper(
     const Instance& receiver,
     const ICData& ic_data) {
+  if (!FLAG_lazy_dispatchers) {
+    return Function::null();  // We'll handle it in the runtime.
+  }
+
   const Array& args_descriptor = Array::Handle(ic_data.arguments_descriptor());
 
   const Class& receiver_class = Class::Handle(receiver.clazz());
@@ -775,9 +780,6 @@
                                 target_name,
                                 args_descriptor,
                                 &result)) {
-    if (!FLAG_lazy_dispatchers) {
-      return result.raw();  // Return null.
-    }
     ArgumentsDescriptor desc(args_descriptor);
     const Function& target_function =
         Function::Handle(receiver_class.GetInvocationDispatcher(
@@ -1042,6 +1044,78 @@
   const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(2));
   const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(3));
   const String& target_name = String::Handle(ic_data.target_name());
+
+  Class& cls = Class::Handle(receiver.clazz());
+  Function& function = Function::Handle();
+
+  // Dart distinguishes getters and regular methods and allows their calls
+  // to mix with conversions, and its selectors are independent of arity. So do
+  // a zigzagged lookup to see if this call failed because of an arity mismatch,
+  // need for conversion, or there really is no such method.
+
+  const bool is_getter = Field::IsGetterName(target_name);
+  if (is_getter) {
+    // o.foo failed, closurize o.foo() if it exists
+    const String& field_name =
+      String::Handle(Field::NameFromGetter(target_name));
+    while (!cls.IsNull()) {
+      function ^= cls.LookupDynamicFunction(field_name);
+      if (!function.IsNull()) {
+        const Function& closure_function =
+            Function::Handle(function.ImplicitClosureFunction());
+        const Object& result =
+            Object::Handle(closure_function.ImplicitInstanceClosure(receiver));
+        arguments.SetReturn(result);
+        return;
+      }
+      cls = cls.SuperClass();
+    }
+  } else {
+    // o.foo(...) failed, invoke noSuchMethod is foo exists but has the wrong
+    // number of arguments, or try (o.foo).call(...)
+
+    if ((target_name.raw() == Symbols::Call().raw()) && receiver.IsClosure()) {
+      // Special case: closures are implemented with a call getter instead of a
+      // call method and with lazy dispatchers the field-invocation-dispatcher
+      // would perform the closure call.
+      const Object& result =
+        Object::Handle(DartEntry::InvokeClosure(orig_arguments,
+                                                orig_arguments_desc));
+      CheckResultError(result);
+      arguments.SetReturn(result);
+      return;
+    }
+
+    const String& getter_name = String::Handle(Field::GetterName(target_name));
+    while (!cls.IsNull()) {
+      function ^= cls.LookupDynamicFunction(target_name);
+      if (!function.IsNull()) {
+        ArgumentsDescriptor args_desc(orig_arguments_desc);
+        ASSERT(!function.AreValidArguments(args_desc, NULL));
+        break;  // mismatch, invoke noSuchMethod
+      }
+      function ^= cls.LookupDynamicFunction(getter_name);
+      if (!function.IsNull()) {
+        const Array& getter_arguments = Array::Handle(Array::New(1));
+        getter_arguments.SetAt(0, receiver);
+        const Object& getter_result =
+          Object::Handle(DartEntry::InvokeFunction(function,
+                                                   getter_arguments));
+        CheckResultError(getter_result);
+        ASSERT(getter_result.IsNull() || getter_result.IsInstance());
+
+        orig_arguments.SetAt(0, getter_result);
+        const Object& call_result =
+          Object::Handle(DartEntry::InvokeClosure(orig_arguments,
+                                                  orig_arguments_desc));
+        CheckResultError(call_result);
+        arguments.SetReturn(call_result);
+        return;
+      }
+      cls = cls.SuperClass();
+    }
+  }
+
   // Handle noSuchMethod invocation.
   const Object& result = Object::Handle(
       DartEntry::InvokeNoSuchMethod(receiver,
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 885208b..0afc458 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -131,9 +131,9 @@
       intptr_t osr_id) {
     // Compile to the dart IR.
     RegExpEngine::CompilationResult result =
-        RegExpEngine::Compile(parsed_function->regexp_compile_data(),
-                              parsed_function,
-                              ic_data_array);
+        RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
+                                parsed_function,
+                                ic_data_array);
     backtrack_goto_ = result.backtrack_goto;
 
     // Allocate variables now that we know the number of locals.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 9868346..17406ea 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1522,7 +1522,7 @@
   isolate->heap()->CollectAllGarbage();
 #if defined(DEBUG)
   FunctionVisitor check_canonical(isolate);
-  isolate->heap()->VisitObjects(&check_canonical);
+  isolate->heap()->IterateObjects(&check_canonical);
 #endif  // #if defined(DEBUG).
 
   // Since this is only a snapshot the root library should not be set.
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 9a1ea76..817b7e9 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -151,7 +151,50 @@
       return InvokeFunction(function, arguments, arguments_descriptor);
     }
   }
-  // There is no compatible 'call' method, so invoke noSuchMethod.
+
+  // There is no compatible 'call' method, see if there's a getter.
+  if (instance.IsClosure()) {
+    // Special case: closures are implemented with a call getter instead of a
+    // call method. If the arguments didn't match, go to noSuchMethod instead
+    // of infinitely recursing on the getter.
+  } else {
+    const String& getter_name = String::Handle(Symbols::New("get:call"));
+    Class& cls = Class::Handle(instance.clazz());
+    while (!cls.IsNull()) {
+      function ^= cls.LookupDynamicFunction(getter_name);
+      if (!function.IsNull()) {
+        // Getters don't have a stack overflow check, so do one in C++.
+
+        Isolate* isolate = Isolate::Current();
+#if defined(USING_SIMULATOR)
+        uword stack_pos = Simulator::Current()->get_register(SPREG);
+#else
+        uword stack_pos = Isolate::GetCurrentStackPointer();
+#endif
+        if (stack_pos < isolate->saved_stack_limit()) {
+          const Instance& exception =
+            Instance::Handle(isolate->object_store()->stack_overflow());
+          return UnhandledException::New(exception, Stacktrace::Handle());
+        }
+
+        const Array& getter_arguments = Array::Handle(Array::New(1));
+        getter_arguments.SetAt(0, instance);
+        const Object& getter_result =
+              Object::Handle(DartEntry::InvokeFunction(function,
+                                                       getter_arguments));
+        if (getter_result.IsError()) {
+          return getter_result.raw();
+        }
+        ASSERT(getter_result.IsNull() || getter_result.IsInstance());
+
+        arguments.SetAt(0, getter_result);
+        return InvokeClosure(arguments, arguments_descriptor);
+      }
+      cls = cls.SuperClass();
+    }
+  }
+
+  // No compatible method or getter so invoke noSuchMethod.
   return InvokeNoSuchMethod(instance,
                             Symbols::Call(),
                             arguments,
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 0329ca3..abdd58e 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -1811,6 +1811,44 @@
   ValueGraphVisitor for_left_value(owner());
   node->left()->Visit(&for_left_value);
   Append(for_left_value);
+
+  if (!FLAG_warn_on_javascript_compatibility) {
+    if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType() ||
+        type.IsSmiType() || type.IsStringType()) {
+      String& method_name = String::ZoneHandle(Z);
+      if (type.IsNumberType()) {
+        method_name = Symbols::_instanceOfNum().raw();
+      } else if (type.IsIntType()) {
+        method_name = Symbols::_instanceOfInt().raw();
+      } else if (type.IsDoubleType()) {
+        method_name = Symbols::_instanceOfDouble().raw();
+      } else if (type.IsSmiType()) {
+        method_name = Symbols::_instanceOfSmi().raw();
+      } else if (type.IsStringType()) {
+        method_name = Symbols::_instanceOfString().raw();
+      }
+      ASSERT(!method_name.IsNull());
+      PushArgumentInstr* push_left = PushArgument(for_left_value.value());
+      ZoneGrowableArray<PushArgumentInstr*>* arguments =
+          new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+      arguments->Add(push_left);
+      const Bool& negate = Bool::Get(node->kind() == Token::kISNOT);
+      Value* negate_arg = Bind(new(Z) ConstantInstr(negate));
+      arguments->Add(PushArgument(negate_arg));
+      const intptr_t kNumArgsChecked = 1;
+      InstanceCallInstr* call = new(Z) InstanceCallInstr(
+          node->token_pos(),
+          Library::PrivateCoreLibName(method_name),
+          node->kind(),
+          arguments,
+          Object::null_array(),  // No argument names.
+          kNumArgsChecked,
+          owner()->ic_data_array());
+      ReturnDefinition(call);
+      return;
+    }
+  }
+
   PushArgumentInstr* push_left = PushArgument(for_left_value.value());
   PushArgumentInstr* push_instantiator = NULL;
   PushArgumentInstr* push_type_args = NULL;
@@ -1828,9 +1866,8 @@
   arguments->Add(push_instantiator);
   arguments->Add(push_type_args);
   ASSERT(!node->right()->AsTypeNode()->type().IsNull());
-  Value* type_arg = Bind(
-      new(Z) ConstantInstr(node->right()->AsTypeNode()->type()));
-  arguments->Add(PushArgument(type_arg));
+  Value* type_const = Bind(new(Z) ConstantInstr(type));
+  arguments->Add(PushArgument(type_const));
   const Bool& negate = Bool::Get(node->kind() == Token::kISNOT);
   Value* negate_arg = Bind(new(Z) ConstantInstr(negate));
   arguments->Add(PushArgument(negate_arg));
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 5fdb2d8..d169b8d 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -237,7 +237,7 @@
   const SubtypeTestCache& type_test_cache =
       SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
   StubCode* stub_code = isolate()->stub_code();
-  __ LoadObject(R2, type_test_cache);
+  __ LoadUniqueObject(R2, type_test_cache);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
     __ LoadImmediate(R1, reinterpret_cast<intptr_t>(Object::null()));
@@ -627,7 +627,7 @@
     __ PushObject(type);  // Push the type.
     // Push instantiator (R2) and its type arguments (R1).
     __ PushList((1 << R1) | (1 << R2));
-    __ LoadObject(R0, test_cache);
+    __ LoadUniqueObject(R0, test_cache);
     __ Push(R0);
     GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
     // Pop the parameters supplied to the runtime entry. The result of the
@@ -720,7 +720,7 @@
   // Push instantiator (R2) and its type arguments (R1).
   __ PushList((1 << R1) | (1 << R2));
   __ PushObject(dst_name);  // Push the name of the destination.
-  __ LoadObject(R0, test_cache);
+  __ LoadUniqueObject(R0, test_cache);
   __ Push(R0);
   GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
   // Pop the parameters supplied to the runtime entry. The result of the
@@ -1204,7 +1204,7 @@
   const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
   counter.SetAt(0, Smi::Handle(Smi::New(0)));
   __ Comment("Edge counter");
-  __ LoadObject(R0, counter);
+  __ LoadUniqueObject(R0, counter);
   intptr_t increment_start = assembler_->CodeSize();
 #if defined(DEBUG)
   bool old_use_far_branches = assembler_->use_far_branches();
@@ -1248,7 +1248,7 @@
   // Pass the function explicitly, it is used in IC stub.
 
   __ LoadObject(R6, parsed_function().function());
-  __ LoadObject(R5, ic_data);
+  __ LoadUniqueObject(R5, ic_data);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1265,7 +1265,7 @@
                                          intptr_t token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
-  __ LoadObject(R5, ic_data);
+  __ LoadUniqueObject(R5, ic_data);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index e2b8308..f951807 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -224,7 +224,7 @@
   const SubtypeTestCache& type_test_cache =
       SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
   StubCode* stub_code = isolate()->stub_code();
-  __ LoadObject(R2, type_test_cache, PP);
+  __ LoadUniqueObject(R2, type_test_cache, PP);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
     __ LoadObject(R1, Object::null_object(), PP);
@@ -617,7 +617,7 @@
     // Push instantiator (R2) and its type arguments (R1).
     __ Push(R2);
     __ Push(R1);
-    __ LoadObject(R0, test_cache, PP);
+    __ LoadUniqueObject(R0, test_cache, PP);
     __ Push(R0);
     GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
     // Pop the parameters supplied to the runtime entry. The result of the
@@ -714,7 +714,7 @@
   __ Push(R2);
   __ Push(R1);
   __ PushObject(dst_name, PP);  // Push the name of the destination.
-  __ LoadObject(R0, test_cache, PP);
+  __ LoadUniqueObject(R0, test_cache, PP);
   __ Push(R0);
   GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
   // Pop the parameters supplied to the runtime entry. The result of the
@@ -1207,7 +1207,7 @@
   const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
   counter.SetAt(0, Smi::Handle(Smi::New(0)));
   __ Comment("Edge counter");
-  __ LoadObject(R0, counter, PP);
+  __ LoadUniqueObject(R0, counter, PP);
   __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0), PP);
   __ add(TMP, TMP, Operand(Smi::RawValue(1)));
   __ StoreFieldToOffset(TMP, R0, Array::element_offset(0), PP);
@@ -1230,7 +1230,7 @@
   // Pass the function explicitly, it is used in IC stub.
 
   __ LoadObject(R6, parsed_function().function(), PP);
-  __ LoadObject(R5, ic_data, PP);
+  __ LoadUniqueObject(R5, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1247,7 +1247,7 @@
                                          intptr_t token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
-  __ LoadObject(R5, ic_data, PP);
+  __ LoadUniqueObject(R5, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 7a59b43..b65b62e 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -227,7 +227,7 @@
   const SubtypeTestCache& type_test_cache =
       SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
   StubCode* stub_code = isolate()->stub_code();
-  __ LoadObject(A2, type_test_cache);
+  __ LoadUniqueObject(A2, type_test_cache);
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
     __ LoadImmediate(A1, reinterpret_cast<int32_t>(Object::null()));
@@ -616,7 +616,7 @@
     __ sw(TMP, Address(SP, 3 * kWordSize));  // Push the type.
     __ sw(A2, Address(SP, 2 * kWordSize));  // Push instantiator.
     __ sw(A1, Address(SP, 1 * kWordSize));  // Push type arguments.
-    __ LoadObject(A0, test_cache);
+    __ LoadUniqueObject(A0, test_cache);
     __ sw(A0, Address(SP, 0 * kWordSize));
     GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs);
     // Pop the parameters supplied to the runtime entry. The result of the
@@ -726,7 +726,7 @@
   __ sw(A1, Address(SP, 2 * kWordSize));  // Push type arguments.
   __ LoadObject(TMP, dst_name);
   __ sw(TMP, Address(SP, 1 * kWordSize));  // Push the name of the destination.
-  __ LoadObject(T0, test_cache);
+  __ LoadUniqueObject(T0, test_cache);
   __ sw(T0, Address(SP, 0 * kWordSize));
 
   GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
@@ -1227,7 +1227,7 @@
   const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
   counter.SetAt(0, Smi::Handle(Smi::New(0)));
   __ Comment("Edge counter");
-  __ LoadObject(T0, counter);
+  __ LoadUniqueObject(T0, counter);
   __ lw(T1, FieldAddress(T0, Array::element_offset(0)));
   __ AddImmediate(T1, T1, Smi::RawValue(1));
   __ sw(T1, FieldAddress(T0, Array::element_offset(0)));
@@ -1250,7 +1250,7 @@
   // Pass the function explicitly, it is used in IC stub.
   __ Comment("OptimizedInstanceCall");
   __ LoadObject(T0, parsed_function().function());
-  __ LoadObject(S5, ic_data);
+  __ LoadUniqueObject(S5, ic_data);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1268,7 +1268,7 @@
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
   __ Comment("InstanceCall");
-  __ LoadObject(S5, ic_data);
+  __ LoadUniqueObject(S5, ic_data);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 649e919..3aa6f29 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -225,7 +225,7 @@
   const SubtypeTestCache& type_test_cache =
       SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
   StubCode* stub_code = isolate()->stub_code();
-  __ LoadObject(temp_reg, type_test_cache, PP);
+  __ LoadUniqueObject(temp_reg, type_test_cache, PP);
   __ pushq(temp_reg);  // Subtype test cache.
   __ pushq(instance_reg);  // Instance.
   if (test_kind == kTestTypeOneArg) {
@@ -623,7 +623,7 @@
     __ PushObject(type, PP);  // Push the type.
     __ pushq(RCX);  // TODO(srdjan): Pass instantiator instead of null.
     __ pushq(RDX);  // Instantiator type arguments.
-    __ LoadObject(RAX, test_cache, PP);
+    __ LoadUniqueObject(RAX, test_cache, PP);
     __ pushq(RAX);
     GenerateRuntimeCall(token_pos,
                         deopt_id,
@@ -720,7 +720,7 @@
   __ pushq(RCX);  // Instantiator.
   __ pushq(RDX);  // Instantiator type arguments.
   __ PushObject(dst_name, PP);  // Push the name of the destination.
-  __ LoadObject(RAX, test_cache, PP);
+  __ LoadUniqueObject(RAX, test_cache, PP);
   __ pushq(RAX);
   GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
   // Pop the parameters supplied to the runtime entry. The result of the
@@ -1244,7 +1244,7 @@
   const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld));
   counter.SetAt(0, Smi::Handle(Smi::New(0)));
   __ Comment("Edge counter");
-  __ LoadObject(RAX, counter, PP);
+  __ LoadUniqueObject(RAX, counter, PP);
   intptr_t increment_start = assembler_->CodeSize();
   __ IncrementSmiField(FieldAddress(RAX, Array::element_offset(0)), 1);
   int32_t size = assembler_->CodeSize() - increment_start;
@@ -1278,7 +1278,7 @@
   // reoptimized and which counter needs to be incremented.
   // Pass the function explicitly, it is used in IC stub.
   __ LoadObject(RDI, parsed_function().function(), PP);
-  __ LoadObject(RBX, ic_data, PP);
+  __ LoadUniqueObject(RBX, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1295,7 +1295,7 @@
                                          intptr_t token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
-  __ LoadObject(RBX, ic_data, PP);
+  __ LoadUniqueObject(RBX, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index abdb548..add12f5 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -4109,12 +4109,40 @@
 void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
   ASSERT(Token::IsTypeTestOperator(call->token_kind()));
   Definition* left = call->ArgumentAt(0);
-  Definition* instantiator = call->ArgumentAt(1);
-  Definition* type_args = call->ArgumentAt(2);
-  const AbstractType& type =
-      AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value());
-  const bool negate = Bool::Cast(
-      call->ArgumentAt(4)->OriginalDefinition()->AsConstant()->value()).value();
+  Definition* instantiator = NULL;
+  Definition* type_args = NULL;
+  AbstractType& type = AbstractType::ZoneHandle(Z);
+  bool negate = false;
+  if (call->ArgumentCount() == 2) {
+    instantiator = flow_graph()->constant_null();
+    type_args = flow_graph()->constant_null();
+    if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
+      type = Type::Number();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
+      type = Type::IntType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
+      type = Type::SmiType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
+      type = Type::Double();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
+      type = Type::StringType();
+    } else {
+      UNIMPLEMENTED();
+    }
+    negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  } else {
+    instantiator = call->ArgumentAt(1);
+    type_args = call->ArgumentAt(2);
+    type = AbstractType::Cast(call->ArgumentAt(3)->AsConstant()->value()).raw();
+    negate = Bool::Cast(call->ArgumentAt(4)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  }
   const ICData& unary_checks =
       ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
   if (FLAG_warn_on_javascript_compatibility &&
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 27d39d3..e66d6db 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -219,6 +219,50 @@
 }
 
 
+HeapIterationScope::HeapIterationScope()
+    : StackResource(Thread::Current()->isolate()),
+      old_space_(isolate()->heap()->old_space()) {
+  // It's not yet safe to iterate over a paged space while it's concurrently
+  // sweeping, so wait for any such task to complete first.
+  MonitorLocker ml(old_space_->tasks_lock());
+#if defined(DEBUG)
+  // We currently don't support nesting of HeapIterationScopes.
+  ASSERT(!old_space_->is_iterating_);
+  old_space_->is_iterating_ = true;
+#endif
+  while (old_space_->tasks() > 0) {
+    ml.Wait();
+  }
+  old_space_->set_tasks(1);
+}
+
+
+HeapIterationScope::~HeapIterationScope() {
+  MonitorLocker ml(old_space_->tasks_lock());
+#if defined(DEBUG)
+  ASSERT(old_space_->is_iterating_);
+  old_space_->is_iterating_ = false;
+#endif
+  ASSERT(old_space_->tasks() == 1);
+  old_space_->set_tasks(0);
+  ml.Notify();
+}
+
+
+void Heap::IterateObjects(ObjectVisitor* visitor) const {
+  // The visitor must not allocate from the heap.
+  NoSafepointScope no_safepoint_scope_;
+  new_space_->VisitObjects(visitor);
+  IterateOldObjects(visitor);
+}
+
+
+void Heap::IterateOldObjects(ObjectVisitor* visitor) const {
+  HeapIterationScope heap_iteration_scope;
+  old_space_->VisitObjects(visitor);
+}
+
+
 void Heap::VisitObjectPointers(ObjectPointerVisitor* visitor) const {
   new_space_->VisitObjectPointers(visitor);
   old_space_->VisitObjectPointers(visitor);
@@ -235,11 +279,7 @@
 
 
 RawObject* Heap::FindOldObject(FindObjectVisitor* visitor) const {
-  // Wait for any concurrent GC tasks to finish before walking.
-  MonitorLocker ml(old_space_->tasks_lock());
-  while (old_space_->tasks() > 0) {
-    ml.Wait();
-  }
+  HeapIterationScope heap_iteration_scope;
   return old_space_->FindObject(visitor, HeapPage::kData);
 }
 
@@ -250,7 +290,8 @@
 
 
 RawObject* Heap::FindObject(FindObjectVisitor* visitor) const {
-  ASSERT(isolate()->no_safepoint_scope_depth() != 0);
+  // The visitor must not allocate from the heap.
+  NoSafepointScope no_safepoint_scope;
   RawObject* raw_obj = FindNewObject(visitor);
   if (raw_obj != Object::null()) {
     return raw_obj;
@@ -489,6 +530,12 @@
 
 
 bool Heap::Verify(MarkExpectation mark_expectation) const {
+  HeapIterationScope heap_iteration_scope;
+  return VerifyGC(mark_expectation);
+}
+
+
+bool Heap::VerifyGC(MarkExpectation mark_expectation) const {
   ObjectSet* allocated_set = CreateAllocatedObjectSet(mark_expectation);
   VerifyPointersVisitor visitor(isolate(), allocated_set);
   VisitObjectPointers(&visitor);
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 6d8752c..4385883 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -105,14 +105,9 @@
   bool CodeContains(uword addr) const;
   bool StubCodeContains(uword addr) const;
 
-  // Visit all pointers. Caller must ensure concurrent sweeper is not running,
-  // and the visitor must not allocate (see issue 21620).
-  void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
-
-  // Visit all objects, including FreeListElement "objects". Caller must ensure
-  // concurrent sweeper is not running, and the visitor must not allocate (see
-  // issue 21620).
-  void VisitObjects(ObjectVisitor* visitor) const;
+  void IterateObjects(ObjectVisitor* visitor) const;
+  void IterateOldObjects(ObjectVisitor* visitor) const;
+  void IterateObjectPointers(ObjectVisitor* visitor) const;
 
   // Find an object by visiting all pointers in the specified heap space,
   // the 'visitor' is used to determine if an object is found or not.
@@ -121,8 +116,7 @@
   // point.
   // The 'visitor' function should return false if the object is not found,
   // traversal through the heap space continues.
-  // Returns null object if nothing is found. Must be called within a
-  // NoSafepointScope.
+  // Returns null object if nothing is found.
   RawInstructions* FindObjectInCodeSpace(FindObjectVisitor* visitor) const;
   RawObject* FindOldObject(FindObjectVisitor* visitor) const;
   RawObject* FindNewObject(FindObjectVisitor* visitor) const;
@@ -284,6 +278,18 @@
   uword AllocateOld(intptr_t size, HeapPage::PageType type);
   uword AllocatePretenured(intptr_t size);
 
+  // Visit all pointers. Caller must ensure concurrent sweeper is not running,
+  // and the visitor must not allocate.
+  void VisitObjectPointers(ObjectPointerVisitor* visitor) const;
+
+  // Visit all objects, including FreeListElement "objects". Caller must ensure
+  // concurrent sweeper is not running, and the visitor must not allocate.
+  void VisitObjects(ObjectVisitor* visitor) const;
+
+  // Like Verify, but does not wait for concurrent sweeper, so caller must
+  // ensure thread-safety.
+  bool VerifyGC(MarkExpectation mark_expectation = kForbidMarked) const;
+
   // GC stats collection.
   void RecordBeforeGC(Space space, GCReason reason);
   void RecordAfterGC();
@@ -318,6 +324,7 @@
 
   friend class ServiceEvent;
   friend class GCTestHelper;
+  friend class PageSpace;  // VerifyGC
   DISALLOW_COPY_AND_ASSIGN(Heap);
 };
 
@@ -342,6 +349,18 @@
 #endif  // defined(DEBUG)
 
 
+class HeapIterationScope : public StackResource {
+ public:
+  HeapIterationScope();
+  ~HeapIterationScope();
+ private:
+  NoSafepointScope no_safepoint_scope_;
+  PageSpace* old_space_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeapIterationScope);
+};
+
+
 class NoHeapGrowthControlScope : public StackResource {
  public:
   NoHeapGrowthControlScope();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index cc17570..a5e7f5e 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -18,7 +18,7 @@
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/os.h"
-#include "vm/regexp_assembler.h"
+#include "vm/regexp_assembler_ir.h"
 #include "vm/resolver.h"
 #include "vm/scopes.h"
 #include "vm/stub_code.h"
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 4ba8fed..6238014 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -18,6 +18,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, interpret_irregexp);
+
 // When entering intrinsics code:
 // R5: IC Data
 // R4: Arguments descriptor
@@ -1570,6 +1572,35 @@
 }
 
 
+// Return type quickly for simple types (not parameterized and not signature).
+void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
+  Label fall_through;
+  static const intptr_t kSmiCidSource = kSmiCid << RawObject::kClassIdTagPos;
+  __ ldr(R0, Address(SP, 0 * kWordSize));
+
+  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(&kSmiCidSource) + 1);
+  __ tst(R0, Operand(kSmiTagMask));
+  __ mov(TMP, Operand(R0), NE);
+  __ LoadClassId(R1, TMP);
+  __ LoadClassById(R2, R1);
+  // R2: class of instance (R0).
+  __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
+  __ CompareImmediate(R3, reinterpret_cast<int32_t>(Object::null()));
+  __ b(&fall_through, NE);
+
+  __ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
+  __ CompareImmediate(R3, 0);
+  __ b(&fall_through, NE);
+
+  __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+  __ CompareImmediate(R0, reinterpret_cast<int32_t>(Object::null()));
+  __ b(&fall_through, EQ);
+  __ Ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ ldr(R0, FieldAddress(R0, String::hash_offset()));
@@ -1962,6 +1993,8 @@
 
 
 void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
+  if (FLAG_interpret_irregexp) return;
+
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
   static const intptr_t kStringParamOffset = 1 * kWordSize;
   // start_index smi is located at offset 0.
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index fedbe17..dd46bcc 100644
--- a/runtime/vm/intrinsifier_arm64.cc
+++ b/runtime/vm/intrinsifier_arm64.cc
@@ -17,6 +17,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, interpret_irregexp);
+
 // When entering intrinsics code:
 // R5: IC Data
 // R4: Arguments descriptor
@@ -1646,6 +1648,30 @@
 }
 
 
+// Return type quickly for simple types (not parameterized and not signature).
+void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
+  Label fall_through;
+  __ ldr(R0, Address(SP, 0 * kWordSize));
+  __ LoadClassIdMayBeSmi(R1, R0);
+  __ LoadClassById(R2, R1, PP);
+  // R2: class of instance (R0).
+  __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
+  __ CompareObject(R3, Object::null_object(), PP);
+  __ b(&fall_through, NE);
+
+  __ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
+  __ CompareImmediate(R3, 0, kNoPP);
+  __ b(&fall_through, NE);
+
+  __ ldr(R0, FieldAddress(R2, Class::canonical_types_offset()));
+  __ CompareObject(R0, Object::null_object(), PP);
+  __ b(&fall_through, EQ);
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ ldr(R0, Address(SP, 0 * kWordSize));
@@ -2043,6 +2069,8 @@
 
 
 void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
+  if (FLAG_interpret_irregexp) return;
+
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
   static const intptr_t kStringParamOffset = 1 * kWordSize;
   // start_index smi is located at offset 0.
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 93290ed..2b15a71 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -24,6 +24,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, interpret_irregexp);
+
 // When entering intrinsics code:
 // ECX: IC Data
 // EDX: Arguments descriptor
@@ -1666,6 +1668,31 @@
 }
 
 
+// Return type quickly for simple types (not parameterized and not signature).
+void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
+  Label fall_through;
+  __ movl(EAX, Address(ESP, + 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(EDI, EAX);
+  __ LoadClassById(EBX, EDI);
+  // EBX: class of instance (EAX).
+  const Immediate& raw_null =
+      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+  __ movl(EDI, FieldAddress(EBX, Class::signature_function_offset()));
+  __ cmpl(EDI, raw_null);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
+  __ cmpl(EDI, Immediate(0));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+  __ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
+  __ cmpl(EAX, raw_null);
+  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Not yet set.
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));  // String object.
@@ -2052,6 +2079,8 @@
 
 
 void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
+  if (FLAG_interpret_irregexp) return;
+
   static const intptr_t kRegExpParamOffset = 3 * kWordSize;
   static const intptr_t kStringParamOffset = 2 * kWordSize;
   // start_index smi is located at offset 1.
@@ -2073,7 +2102,7 @@
   // Registers are now set up for the lazy compile stub. It expects the function
   // in EAX, the argument descriptor in EDX, and IC-Data in ECX.
   static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
-  __ LoadObject(EDX, Array::Handle(ArgumentsDescriptor::New(arg_count)));
+  __ LoadObject(EDX, Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)));
   __ xorl(ECX, ECX);
 
   // Tail-call the function.
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index ecf07e6..e20cbd0 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -17,6 +17,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, interpret_irregexp);
+
 // When entering intrinsics code:
 // S5: IC Data
 // S4: Arguments descriptor
@@ -1675,6 +1677,28 @@
 }
 
 
+// Return type quickly for simple types (not parameterized and not signature).
+void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
+  Label fall_through;
+  __ lw(T0, Address(SP, 0 * kWordSize));
+  __ LoadClassIdMayBeSmi(T1, T0);
+  __ LoadClassById(T2, T1);
+  // T2: class of instance (T0).
+
+  __ lw(T1, FieldAddress(T2, Class::signature_function_offset()));
+  __ BranchNotEqual(T1, Object::null_object(), &fall_through);
+
+  __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
+  __ BranchNotEqual(T1, Immediate(0), &fall_through);
+
+  __ lw(V0, FieldAddress(T2, Class::canonical_types_offset()));
+  __ BranchEqual(V0, Object::null_object(), &fall_through);
+  __ Ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ lw(T0, Address(SP, 0 * kWordSize));
@@ -2075,6 +2099,8 @@
 
 
 void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
+  if (FLAG_interpret_irregexp) return;
+
   static const intptr_t kRegExpParamOffset = 2 * kWordSize;
   static const intptr_t kStringParamOffset = 1 * kWordSize;
   // start_index smi is located at 0.
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 14eb3cf..96fe7bc 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -17,6 +17,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, interpret_irregexp);
+
 // When entering intrinsics code:
 // RBX: IC Data
 // R10: Arguments descriptor
@@ -1524,6 +1526,31 @@
 }
 
 
+// Return type quickly for simple types (not parameterized and not signature).
+void Intrinsifier::ObjectRuntimeType(Assembler* assembler) {
+  Label fall_through;
+  __ movq(RAX, Address(RSP, + 1 * kWordSize));
+  __ LoadClassIdMayBeSmi(RCX, RAX);
+
+  // RCX: untagged cid of instance (RAX).
+  __ LoadClassById(RDI, RCX, PP);
+  // RDI: class of instance (RAX).
+  __ movq(RCX, FieldAddress(RDI, Class::signature_function_offset()));
+  __ CompareObject(RCX, Object::null_object(), PP);
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+
+  __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
+  __ cmpq(RCX, Immediate(0));
+  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
+  __ movq(RAX, FieldAddress(RDI, Class::canonical_types_offset()));
+  __ CompareObject(RAX, Object::null_object(), PP);
+  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Not yet set.
+  __ ret();
+
+  __ Bind(&fall_through);
+}
+
+
 void Intrinsifier::String_getHashCode(Assembler* assembler) {
   Label fall_through;
   __ movq(RAX, Address(RSP, + 1 * kWordSize));  // String object.
@@ -1911,6 +1938,8 @@
 
 
 void Intrinsifier::JSRegExp_ExecuteMatch(Assembler* assembler) {
+  if (FLAG_interpret_irregexp) return;
+
   static const intptr_t kRegExpParamOffset = 3 * kWordSize;
   static const intptr_t kStringParamOffset = 2 * kWordSize;
   // start_index smi is located at offset 1.
@@ -1932,7 +1961,8 @@
   // Registers are now set up for the lazy compile stub. It expects the function
   // in RAX, the argument descriptor in R10, and IC-Data in RCX.
   static const intptr_t arg_count = RegExpMacroAssembler::kParamCount;
-  __ LoadObject(R10, Array::Handle(ArgumentsDescriptor::New(arg_count)), PP);
+  __ LoadObject(R10,
+      Array::ZoneHandle(ArgumentsDescriptor::New(arg_count)), PP);
   __ xorq(RCX, RCX);
 
   // Tail-call the function.
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 195623b..50df955 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1426,12 +1426,6 @@
   ASSERT(top_resource() == NULL);
 #if defined(DEBUG)
   if (heap_ != NULL) {
-    // Wait for concurrent GC tasks to finish before final verification.
-    PageSpace* old_space = heap_->old_space();
-    MonitorLocker ml(old_space->tasks_lock());
-    while (old_space->tasks() > 0) {
-      ml.Wait();
-    }
     // The VM isolate keeps all objects marked.
     heap_->Verify(this == Dart::vm_isolate() ? kRequireMarked : kForbidMarked);
   }
@@ -1513,6 +1507,14 @@
 Isolate* Isolate::isolates_list_head_ = NULL;
 
 
+void Isolate::IterateObjectPointers(ObjectPointerVisitor* visitor,
+                                    bool visit_prologue_weak_handles,
+                                    bool validate_frames) {
+  HeapIterationScope heap_iteration_scope;
+  VisitObjectPointers(visitor, visit_prologue_weak_handles, validate_frames);
+}
+
+
 void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
                                   bool visit_prologue_weak_handles,
                                   bool validate_frames) {
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 2b1256f..447afac 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -133,9 +133,9 @@
   void ValidateClassTable();
 
   // Visit all object pointers.
-  void VisitObjectPointers(ObjectPointerVisitor* visitor,
-                           bool visit_prologue_weak_persistent_handles,
-                           bool validate_frames);
+  void IterateObjectPointers(ObjectPointerVisitor* visitor,
+                             bool visit_prologue_weak_persistent_handles,
+                             bool validate_frames);
 
   // Visits weak object pointers.
   void VisitWeakPersistentHandles(HandleVisitor* visitor,
@@ -727,6 +727,12 @@
 
   void ProfileIdle();
 
+  // Visit all object pointers. Caller must ensure concurrent sweeper is not
+  // running, and the visitor must not allocate.
+  void VisitObjectPointers(ObjectPointerVisitor* visitor,
+                           bool visit_prologue_weak_persistent_handles,
+                           bool validate_frames);
+
   void set_user_tag(uword tag) {
     user_tag_ = tag;
   }
@@ -882,6 +888,8 @@
 REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)
 #undef REUSABLE_FRIEND_DECLARATION
 
+  friend class GCMarker;  // VisitObjectPointers
+  friend class Scavenger;  // VisitObjectPointers
   friend class ServiceIsolate;
   friend class Thread;
 
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index cc3ef7d..eb752f9 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -190,6 +190,7 @@
   V(_GrowableList, add, GrowableArray_add, 1675959698)                         \
   V(_JSSyntaxRegExp, _ExecuteMatch, JSRegExp_ExecuteMatch, 1711509198)         \
   V(Object, ==, ObjectEquals, 409406570)                                       \
+  V(Object, get:runtimeType, ObjectRuntimeType, 2076963579)                    \
   V(_StringBase, get:hashCode, String_getHashCode, 2103025405)                 \
   V(_StringBase, get:isEmpty, StringBaseIsEmpty, 780870414)                    \
   V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 397735324)                  \
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 150be3e..907156f 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -876,7 +876,7 @@
   PremarkingVisitor premarker(isolate);
   isolate->heap()->WriteProtect(false);
   ASSERT(isolate->heap()->UsedInWords(Heap::kNew) == 0);
-  isolate->heap()->old_space()->VisitObjects(&premarker);
+  isolate->heap()->IterateOldObjects(&premarker);
   isolate->heap()->WriteProtect(true);
 }
 
@@ -3551,6 +3551,7 @@
   return raw_ptr()->canonical_types_;
 }
 
+
 void Class::set_canonical_types(const Object& value) const {
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->canonical_types_, value.raw());
@@ -6511,6 +6512,21 @@
 }
 
 
+RawInstance* Function::ImplicitInstanceClosure(const Instance& receiver) const {
+  ASSERT(IsImplicitClosureFunction());
+  const Class& cls = Class::Handle(signature_class());
+  const Context& context = Context::Handle(Context::New(1));
+  context.SetAt(0, receiver);
+  const Instance& result = Instance::Handle(Closure::New(*this, context));
+  if (cls.NumTypeArguments() > 0) {
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(receiver.GetTypeArguments());
+    result.SetTypeArguments(type_arguments);
+  }
+  return result.raw();
+}
+
+
 RawString* Function::BuildSignature(bool instantiate,
                                     NameVisibility name_visibility,
                                     const TypeArguments& instantiator) const {
@@ -14882,6 +14898,12 @@
 }
 
 
+bool AbstractType::IsSmiType() const {
+  return HasResolvedTypeClass() &&
+      (type_class() == Type::Handle(Type::SmiType()).type_class());
+}
+
+
 bool AbstractType::IsStringType() const {
   return HasResolvedTypeClass() &&
       (type_class() == Type::Handle(Type::StringType()).type_class());
@@ -20820,6 +20842,15 @@
 }
 
 
+void JSRegExp::set_bytecode(bool is_one_byte, const TypedData& bytecode) const {
+  if (is_one_byte) {
+    StorePointer(&raw_ptr()->one_byte_bytecode_, bytecode.raw());
+  } else {
+    StorePointer(&raw_ptr()->two_byte_bytecode_, bytecode.raw());
+  }
+}
+
+
 void JSRegExp::set_num_bracket_expressions(intptr_t value) const {
   StoreSmi(&raw_ptr()->num_bracket_expressions_, Smi::New(value));
 }
@@ -20835,6 +20866,7 @@
     result ^= raw;
     result.set_type(kUnitialized);
     result.set_flags(0);
+    result.set_num_registers(-1);
   }
   return result.raw();
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ad21c1a..b259aac 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1049,6 +1049,9 @@
     }
     return reinterpret_cast<RawType*>(Object::null());
   }
+  static intptr_t canonical_types_offset() {
+    return OFFSET_OF(RawClass, canonical_types_);
+  }
 
   // The super type of this class, Object type if not explicitly specified.
   // Note that the super type may be bounded, as in this example:
@@ -1442,6 +1445,9 @@
     return raw_ptr()->num_type_arguments_;
   }
   void set_num_type_arguments(intptr_t value) const;
+  static intptr_t num_type_arguments_offset() {
+    return OFFSET_OF(RawClass, num_type_arguments_);
+  }
 
   int16_t num_own_type_arguments() const {
     return raw_ptr()->num_own_type_arguments_;
@@ -1484,6 +1490,7 @@
   friend class Instance;
   friend class Object;
   friend class Type;
+  friend class Intrinsifier;
 };
 
 
@@ -2190,6 +2197,8 @@
   // If none exists yet, create one and remember it.
   RawInstance* ImplicitStaticClosure() const;
 
+  RawInstance* ImplicitInstanceClosure(const Instance& receiver) const;
+
   // Redirection information for a redirecting factory.
   bool IsRedirectingFactory() const;
   RawType* RedirectionType() const;
@@ -5030,6 +5039,9 @@
   // Check if this type represents the 'num' type.
   bool IsNumberType() const;
 
+  // Check if this type represents the '_Smi' type.
+  bool IsSmiType() const;
+
   // Check if this type represents the 'String' type.
   bool IsStringType() const;
 
@@ -7658,11 +7670,18 @@
   bool is_ignore_case() const { return (flags() & kIgnoreCase); }
   bool is_multi_line() const { return (flags() & kMultiLine); }
 
+  intptr_t num_registers() const { return raw_ptr()->num_registers_; }
+
   RawString* pattern() const { return raw_ptr()->pattern_; }
   RawSmi* num_bracket_expressions() const {
     return raw_ptr()->num_bracket_expressions_;
   }
 
+  RawTypedData* bytecode(bool is_one_byte) const {
+    return is_one_byte ? raw_ptr()->one_byte_bytecode_
+                       : raw_ptr()->two_byte_bytecode_;
+  }
+
   static intptr_t function_offset(intptr_t cid) {
     switch (cid) {
       case kOneByteStringCid:
@@ -7690,6 +7709,7 @@
 
   void set_pattern(const String& pattern) const;
   void set_function(intptr_t cid, const Function& value) const;
+  void set_bytecode(bool is_one_byte, const TypedData& bytecode) const;
 
   void set_num_bracket_expressions(intptr_t value) const;
   void set_is_global() const { set_flags(flags() | kGlobal); }
@@ -7697,6 +7717,9 @@
   void set_is_multi_line() const { set_flags(flags() | kMultiLine); }
   void set_is_simple() const { set_type(kSimple); }
   void set_is_complex() const { set_type(kComplex); }
+  void set_num_registers(intptr_t value) const {
+    StoreNonPointer(&raw_ptr()->num_registers_, value);
+  }
 
   void* GetDataStartAddress() const;
   static RawJSRegExp* FromDataStartAddress(void* data);
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index b07fe0a..2e30f25 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -148,7 +148,7 @@
 
   static void UnmarkAll(Isolate* isolate) {
     Unmarker unmarker(isolate);
-    isolate->heap()->VisitObjects(&unmarker);
+    isolate->heap()->IterateObjects(&unmarker);
   }
 
  private:
@@ -172,13 +172,8 @@
 
 void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) {
   NoSafepointScope no_safepoint_scope_;
-  PageSpace* old_space = isolate()->heap()->old_space();
-  MonitorLocker ml(old_space->tasks_lock());
-  while (old_space->tasks() > 0) {
-    ml.Wait();
-  }
   Stack stack(isolate());
-  isolate()->VisitObjectPointers(&stack, false, false);
+  isolate()->IterateObjectPointers(&stack, false, false);
   stack.TraverseGraph(visitor);
   Unmarker::UnmarkAll(isolate());
 }
@@ -187,11 +182,6 @@
 void ObjectGraph::IterateObjectsFrom(const Object& root,
                                      ObjectGraph::Visitor* visitor) {
   NoSafepointScope no_safepoint_scope_;
-  PageSpace* old_space = isolate()->heap()->old_space();
-  MonitorLocker ml(old_space->tasks_lock());
-  while (old_space->tasks() > 0) {
-    ml.Wait();
-  }
   Stack stack(isolate());
   RawObject* root_raw = root.raw();
   stack.VisitPointer(&root_raw);
@@ -377,7 +367,7 @@
   Object& scratch = Object::Handle();
   NoSafepointScope no_safepoint_scope_;
   InboundReferencesVisitor visitor(isolate(), obj->raw(), references, &scratch);
-  isolate()->heap()->VisitObjects(&visitor);
+  isolate()->heap()->IterateObjects(&visitor);
   return visitor.length();
 }
 
@@ -466,7 +456,7 @@
   stream->WriteUnsigned(0);
   {
     WritePointerVisitor ptr_writer(isolate(), stream);
-    isolate()->VisitObjectPointers(&ptr_writer, false, false);
+    isolate()->IterateObjectPointers(&ptr_writer, false, false);
   }
   stream->WriteUnsigned(0);
   IterateObjects(&visitor);
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 028455d..156fb48 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -4248,19 +4248,9 @@
 TEST_CASE(PrintJSON) {
   Heap* heap = Isolate::Current()->heap();
   heap->CollectAllGarbage();
-  // We don't want to print garbage objects, so wait for concurrent sweeper.
-  // TODO(21620): Add heap iteration interface that excludes garbage (or
-  // use ObjectGraph).
-  PageSpace* old_space = heap->old_space();
-  {
-    MonitorLocker ml(old_space->tasks_lock());
-    while (old_space->tasks() > 0) {
-      ml.Wait();
-    }
-  }
   GrowableArray<Object*> objects;
   ObjectAccumulator acc(&objects);
-  heap->VisitObjects(&acc);
+  heap->IterateObjects(&acc);
   for (intptr_t i = 0; i < objects.length(); ++i) {
     JSONStream js;
     objects[i]->PrintJSON(&js, false);
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index 18eec36..109df50 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -160,6 +160,9 @@
       max_external_in_words_(max_external_in_words),
       tasks_lock_(new Monitor()),
       tasks_(0),
+#if defined(DEBUG)
+      is_iterating_(false),
+#endif
       page_space_controller_(heap,
                              FLAG_old_gen_growth_space_ratio,
                              FLAG_old_gen_growth_rate,
@@ -778,7 +781,7 @@
 
   if (FLAG_verify_before_gc) {
     OS::PrintErr("Verifying before marking...");
-    heap_->Verify();
+    heap_->VerifyGC();
     OS::PrintErr(" done.\n");
   }
 
@@ -810,7 +813,7 @@
   {
     if (FLAG_verify_before_gc) {
       OS::PrintErr("Verifying before sweeping...");
-      heap_->Verify(kAllowMarked);
+      heap_->VerifyGC(kAllowMarked);
       OS::PrintErr(" done.\n");
     }
     GCSweeper sweeper;
@@ -871,7 +874,7 @@
       }
       if (FLAG_verify_after_gc) {
         OS::PrintErr("Verifying after sweeping...");
-        heap_->Verify(kForbidMarked);
+        heap_->VerifyGC(kForbidMarked);
         OS::PrintErr(" done.\n");
       }
     } else {
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 0d0d4dd..cd2b8cb 100644
--- a/runtime/vm/pages.h
+++ b/runtime/vm/pages.h
@@ -424,7 +424,9 @@
   // Keep track of running MarkSweep tasks.
   Monitor* tasks_lock_;
   intptr_t tasks_;
-
+#if defined(DEBUG)
+  bool is_iterating_;
+#endif
   PageSpaceController page_space_controller_;
 
   int64_t gc_time_micros_;
@@ -433,6 +435,7 @@
   friend class ExclusivePageIterator;
   friend class ExclusiveCodePageIterator;
   friend class ExclusiveLargePageIterator;
+  friend class HeapIterationScope;
   friend class PageSpaceController;
   friend class SweeperTask;
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 6cc8e54..a966b40 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -46,6 +46,7 @@
 DECLARE_FLAG(bool, warn_on_javascript_compatibility);
 DEFINE_FLAG(bool, enable_mirrors, true,
     "Disable to make importing dart:mirrors an error.");
+DECLARE_FLAG(bool, lazy_dispatchers);
 
 // Quick access to the current isolate and zone.
 #define I (isolate())
@@ -1330,6 +1331,8 @@
 
 SequenceNode* Parser::ParseMethodExtractor(const Function& func) {
   TRACE_PARSER("ParseMethodExtractor");
+  ASSERT(FLAG_lazy_dispatchers);
+
   ParamList params;
 
   const intptr_t ident_pos = func.token_pos();
@@ -1402,6 +1405,7 @@
 SequenceNode* Parser::ParseNoSuchMethodDispatcher(const Function& func,
                                                   Array* default_values) {
   TRACE_PARSER("ParseNoSuchMethodDispatcher");
+  ASSERT(FLAG_lazy_dispatchers);
 
   ASSERT(func.IsNoSuchMethodDispatcher());
   intptr_t token_pos = func.token_pos();
@@ -1459,6 +1463,7 @@
 SequenceNode* Parser::ParseInvokeFieldDispatcher(const Function& func,
                                                  Array* default_values) {
   TRACE_PARSER("ParseInvokeFieldDispatcher");
+  ASSERT(FLAG_lazy_dispatchers);
 
   ASSERT(func.IsInvokeFieldDispatcher());
   intptr_t token_pos = func.token_pos();
@@ -3573,7 +3578,7 @@
         (LookaheadToken(3) == Token::kPERIOD);
     const AbstractType& type = AbstractType::Handle(Z,
         ParseType(ClassFinalizer::kResolveTypeParameters,
-                  false,  // Deferred types not allowed.
+                  true,
                   consume_unresolved_prefix));
     if (!type.IsMalformed() && type.IsTypeParameter()) {
       // Replace the type with a malformed type and compile a throw when called.
@@ -12019,13 +12024,16 @@
       // If deferred prefixes are allowed but it is not yet loaded,
       // remember that this function depends on the prefix.
       if (allow_deferred_type && !prefix.is_loaded()) {
-        ASSERT(parsed_function() != NULL);
-        parsed_function()->AddDeferredPrefix(prefix);
+        if (parsed_function() != NULL) {
+          parsed_function()->AddDeferredPrefix(prefix);
+        }
       }
-      // If the deferred prefixes are not allowed, or if the prefix
-      // is not yet loaded, return a malformed type. Otherwise, handle
-      // resolution below, as needed.
-      if (!prefix.is_loaded() || !allow_deferred_type) {
+      // If the deferred prefixes are not allowed, or if the prefix is not yet
+      // loaded when finalization is requested, return a malformed type.
+      // Otherwise, handle resolution below, as needed.
+      if (!allow_deferred_type ||
+          (!prefix.is_loaded()
+              && (finalization > ClassFinalizer::kResolveTypeParameters))) {
         ParseTypeArguments(ClassFinalizer::kIgnore);
         return ClassFinalizer::NewFinalizedMalformedType(
             Error::Handle(Z),  // No previous error.
@@ -12702,6 +12710,28 @@
               String::Handle(Z, redirect_type.UserVisibleName()).ToCString());
         }
       }
+      if (!redirect_type.HasResolvedTypeClass()) {
+        // If the redirection type is unresolved, we convert the allocation
+        // into throwing a type error.
+        const UnresolvedClass& cls =
+            UnresolvedClass::Handle(Z, redirect_type.unresolved_class());
+        const LibraryPrefix& prefix =
+            LibraryPrefix::Handle(Z, cls.library_prefix());
+        if (!prefix.IsNull() && !prefix.is_loaded()) {
+          // If the redirection type is unresolved because it refers to
+          // an unloaded deferred prefix, mark this function as depending
+          // on the library prefix. It will then get invalidated when the
+          // prefix is loaded.
+          parsed_function()->AddDeferredPrefix(prefix);
+        }
+        redirect_type = ClassFinalizer::NewFinalizedMalformedType(
+            Error::Handle(Z),
+            script_,
+            call_pos,
+            "redirection type '%s' is not loaded",
+            String::Handle(Z, redirect_type.UserVisibleName()).ToCString());
+      }
+
       if (redirect_type.IsMalformedOrMalbounded()) {
         if (is_const) {
           ReportError(Error::Handle(Z, redirect_type.error()));
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3be710b..cc967e7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -638,7 +638,7 @@
   int32_t type_arguments_field_offset_in_words_;  // Offset of type args fld.
   int32_t next_field_offset_in_words_;  // Offset of the next instance field.
   classid_t id_;  // Class Id, also index in the class table.
-  int16_t num_type_arguments_;  // Number of type arguments in flatten vector.
+  int16_t num_type_arguments_;  // Number of type arguments in flattened vector.
   int16_t num_own_type_arguments_;  // Number of non-overlapping type arguments.
   uint16_t num_native_fields_;  // Number of native fields in class.
   uint16_t state_bits_;
@@ -1904,10 +1904,14 @@
   RawFunction* two_byte_function_;
   RawFunction* external_one_byte_function_;
   RawFunction* external_two_byte_function_;
+  RawTypedData* one_byte_bytecode_;
+  RawTypedData* two_byte_bytecode_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->external_two_byte_function_);
+    return reinterpret_cast<RawObject**>(&ptr()->two_byte_bytecode_);
   }
 
+  intptr_t num_registers_;
+
   // A bitfield with two fields:
   // type: Uninitialized, simple or complex.
   // flags: Represents global/local, case insensitive, multiline.
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 092ddcd..057f8e9 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -2980,6 +2980,8 @@
                  reader->ReadAsSmi());
   *reader->StringHandle() ^= reader->ReadObjectImpl();
   regex.set_pattern(*reader->StringHandle());
+  regex.StoreNonPointer(&regex.raw_ptr()->num_registers_,
+                        reader->Read<int32_t>());
   regex.StoreNonPointer(&regex.raw_ptr()->type_flags_,
                         reader->Read<int8_t>());
 
@@ -3004,6 +3006,7 @@
   // Write out all the other fields.
   writer->Write<RawObject*>(ptr()->num_bracket_expressions_);
   writer->WriteObjectImpl(ptr()->pattern_);
+  writer->Write<int32_t>(ptr()->num_registers_);
   writer->Write<int8_t>(ptr()->type_flags_);
 }
 
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index fcfa02c..db115a5 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -6,6 +6,8 @@
 
 #include "vm/dart_entry.h"
 #include "vm/regexp_assembler.h"
+#include "vm/regexp_assembler_bytecode.h"
+#include "vm/regexp_assembler_ir.h"
 #include "vm/regexp_ast.h"
 #include "vm/unibrow-inl.h"
 #include "vm/unicode.h"
@@ -17,6 +19,8 @@
 namespace dart {
 
 DECLARE_FLAG(bool, trace_irregexp);
+DEFINE_FLAG(bool, interpret_irregexp, false,
+            "Use irregexp bytecode interpreter");
 
 // Default to generating optimized regexp code.
 static const bool kRegexpOptimization = true;
@@ -294,16 +298,23 @@
  public:
   RegExpCompiler(intptr_t capture_count,
                  bool ignore_case,
-                 intptr_t specialization_cid);
+                 bool is_one_byte);
 
   intptr_t AllocateRegister() {
     return next_register_++;
   }
 
-  RegExpEngine::CompilationResult Assemble(IRRegExpMacroAssembler* assembler,
-                                           RegExpNode* start,
-                                           intptr_t capture_count,
-                                           const String& pattern);
+  RegExpEngine::CompilationResult Assemble(
+      IRRegExpMacroAssembler* assembler,
+      RegExpNode* start,
+      intptr_t capture_count,
+      const String& pattern);
+
+  RegExpEngine::CompilationResult Assemble(
+      BytecodeRegExpMacroAssembler* assembler,
+      RegExpNode* start,
+      intptr_t capture_count,
+      const String& pattern);
 
   inline void AddWork(RegExpNode* node) { work_list_->Add(node); }
 
@@ -311,7 +322,7 @@
   static const intptr_t kNumberOfRegistersOffset = 0;
   static const intptr_t kCodeOffset = 1;
 
-  IRRegExpMacroAssembler* macro_assembler() { return macro_assembler_; }
+  RegExpMacroAssembler* macro_assembler() { return macro_assembler_; }
   EndNode* accept() { return accept_; }
 
   static const intptr_t kMaxRecursion = 100;
@@ -322,11 +333,7 @@
   void SetRegExpTooBig() { reg_exp_too_big_ = true; }
 
   inline bool ignore_case() { return ignore_case_; }
-  inline bool one_byte() const {
-    return (specialization_cid_ == kOneByteStringCid ||
-            specialization_cid_ == kExternalOneByteStringCid);
-  }
-  inline intptr_t specialization_cid() { return specialization_cid_; }
+  inline bool one_byte() const { return is_one_byte_; }
   FrequencyCollator* frequency_collator() { return &frequency_collator_; }
 
   intptr_t current_expansion_factor() { return current_expansion_factor_; }
@@ -343,9 +350,9 @@
   intptr_t next_register_;
   ZoneGrowableArray<RegExpNode*>* work_list_;
   intptr_t recursion_depth_;
-  IRRegExpMacroAssembler* macro_assembler_;
+  RegExpMacroAssembler* macro_assembler_;
   bool ignore_case_;
-  intptr_t specialization_cid_;
+  bool is_one_byte_;
   bool reg_exp_too_big_;
   intptr_t current_expansion_factor_;
   FrequencyCollator frequency_collator_;
@@ -371,13 +378,14 @@
 
 // Attempts to compile the regexp using an Irregexp code generator.  Returns
 // a fixed array or a null handle depending on whether it succeeded.
-RegExpCompiler::RegExpCompiler(intptr_t capture_count, bool ignore_case,
-                               intptr_t specialization_cid)
+RegExpCompiler::RegExpCompiler(intptr_t capture_count,
+                               bool ignore_case,
+                               bool is_one_byte)
     : next_register_(2 * (capture_count + 1)),
       work_list_(NULL),
       recursion_depth_(0),
       ignore_case_(ignore_case),
-      specialization_cid_(specialization_cid),
+      is_one_byte_(is_one_byte),
       reg_exp_too_big_(false),
       current_expansion_factor_(1),
       zone_(Thread::Current()->zone()) {
@@ -390,9 +398,7 @@
     RegExpNode* start,
     intptr_t capture_count,
     const String& pattern) {
-  static const bool use_slow_safe_regexp_compiler = false;
-
-  macro_assembler->set_slow_safe(use_slow_safe_regexp_compiler);
+  macro_assembler->set_slow_safe(false /* use_slow_safe_regexp_compiler */);
   macro_assembler_ = macro_assembler;
 
   ZoneGrowableArray<RegExpNode*> work_list(0);
@@ -414,7 +420,34 @@
   return RegExpEngine::CompilationResult(macro_assembler->backtrack_goto(),
                                          macro_assembler->graph_entry(),
                                          macro_assembler->num_blocks(),
-                                         macro_assembler->num_stack_locals());
+                                         macro_assembler->num_stack_locals(),
+                                         next_register_);
+}
+
+
+RegExpEngine::CompilationResult RegExpCompiler::Assemble(
+    BytecodeRegExpMacroAssembler* macro_assembler,
+    RegExpNode* start,
+    intptr_t capture_count,
+    const String& pattern) {
+  macro_assembler->set_slow_safe(false /* use_slow_safe_regexp_compiler */);
+  macro_assembler_ = macro_assembler;
+
+  ZoneGrowableArray<RegExpNode*> work_list(0);
+  work_list_ = &work_list;
+  BlockLabel fail;
+  macro_assembler_->PushBacktrack(&fail);
+  Trace new_trace;
+  start->Emit(this, &new_trace);
+  macro_assembler_->BindBlock(&fail);
+  macro_assembler_->Fail();
+  while (!work_list.is_empty()) {
+    work_list.RemoveLast()->Emit(this, &new_trace);
+  }
+  if (reg_exp_too_big_) return IrregexpRegExpTooBig();
+
+  TypedData& bytecode = TypedData::ZoneHandle(macro_assembler->GetBytecode());
+  return RegExpEngine::CompilationResult(&bytecode, next_register_);
 }
 
 
@@ -4976,10 +5009,11 @@
 }
 
 
-RegExpEngine::CompilationResult RegExpEngine::Compile(
+RegExpEngine::CompilationResult RegExpEngine::CompileIR(
     RegExpCompileData* data,
     const ParsedFunction* parsed_function,
     const ZoneGrowableArray<const ICData*>& ic_data_array) {
+  ASSERT(!FLAG_interpret_irregexp);
   Zone* zone = Thread::Current()->zone();
 
   const Function& function = parsed_function->function();
@@ -4995,7 +5029,7 @@
   const bool ignore_case = regexp.is_ignore_case();
   const bool is_global = regexp.is_global();
 
-  RegExpCompiler compiler(data->capture_count, ignore_case, specialization_cid);
+  RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte);
 
   // TODO(zerny): Frequency sampling is currently disabled because of several
   // issues. We do not want to store subject strings in the regexp object since
@@ -5098,6 +5132,120 @@
 }
 
 
+RegExpEngine::CompilationResult RegExpEngine::CompileBytecode(
+    RegExpCompileData* data,
+    const JSRegExp& regexp,
+    bool is_one_byte,
+    Zone* zone) {
+  ASSERT(FLAG_interpret_irregexp);
+  const String& pattern = String::Handle(zone, regexp.pattern());
+
+  ASSERT(!regexp.IsNull());
+  ASSERT(!pattern.IsNull());
+
+  const bool ignore_case = regexp.is_ignore_case();
+  const bool is_global = regexp.is_global();
+
+  RegExpCompiler compiler(data->capture_count, ignore_case, is_one_byte);
+
+  // TODO(zerny): Frequency sampling is currently disabled because of several
+  // issues. We do not want to store subject strings in the regexp object since
+  // they might be long and we should not prevent their garbage collection.
+  // Passing them to this function explicitly does not help, since we must
+  // generate exactly the same IR for both the unoptimizing and optimizing
+  // pipelines (otherwise it gets confused when i.e. deopt id's differ).
+  // An option would be to store sampling results in the regexp object, but
+  // I'm not sure the performance gains are relevant enough.
+
+  // Wrap the body of the regexp in capture #0.
+  RegExpNode* captured_body = RegExpCapture::ToNode(data->tree,
+                                                    0,
+                                                    &compiler,
+                                                    compiler.accept());
+
+  RegExpNode* node = captured_body;
+  bool is_end_anchored = data->tree->IsAnchoredAtEnd();
+  bool is_start_anchored = data->tree->IsAnchoredAtStart();
+  intptr_t max_length = data->tree->max_match();
+  if (!is_start_anchored) {
+    // Add a .*? at the beginning, outside the body capture, unless
+    // this expression is anchored at the beginning.
+    RegExpNode* loop_node =
+        RegExpQuantifier::ToNode(0,
+                                 RegExpTree::kInfinity,
+                                 false,
+                                 new(zone) RegExpCharacterClass('*'),
+                                 &compiler,
+                                 captured_body,
+                                 data->contains_anchor);
+
+    if (data->contains_anchor) {
+      // Unroll loop once, to take care of the case that might start
+      // at the start of input.
+      ChoiceNode* first_step_node = new(zone) ChoiceNode(2, zone);
+      first_step_node->AddAlternative(GuardedAlternative(captured_body));
+      first_step_node->AddAlternative(GuardedAlternative(
+          new(zone) TextNode(
+              new(zone) RegExpCharacterClass('*'), loop_node)));
+      node = first_step_node;
+    } else {
+      node = loop_node;
+    }
+  }
+  if (is_one_byte) {
+    node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case);
+    // Do it again to propagate the new nodes to places where they were not
+    // put because they had not been calculated yet.
+    if (node != NULL) {
+      node = node->FilterOneByte(RegExpCompiler::kMaxRecursion, ignore_case);
+    }
+  }
+
+  if (node == NULL) node = new(zone) EndNode(EndNode::BACKTRACK, zone);
+  data->node = node;
+  Analysis analysis(ignore_case, is_one_byte);
+  analysis.EnsureAnalyzed(node);
+  if (analysis.has_failed()) {
+    const char* error_message = analysis.error_message();
+    return CompilationResult(error_message);
+  }
+
+  // Bytecode regexp implementation.
+
+  ZoneGrowableArray<uint8_t> buffer(zone, 1024);
+  BytecodeRegExpMacroAssembler* macro_assembler =
+      new(zone) BytecodeRegExpMacroAssembler(&buffer, zone);
+
+  // Inserted here, instead of in Assembler, because it depends on information
+  // in the AST that isn't replicated in the Node structure.
+  static const intptr_t kMaxBacksearchLimit = 1024;
+  if (is_end_anchored &&
+      !is_start_anchored &&
+      max_length < kMaxBacksearchLimit) {
+    macro_assembler->SetCurrentPositionFromEnd(max_length);
+  }
+
+  if (is_global) {
+    macro_assembler->set_global_mode(
+        (data->tree->min_match() > 0)
+            ? RegExpMacroAssembler::GLOBAL_NO_ZERO_LENGTH_CHECK
+            : RegExpMacroAssembler::GLOBAL);
+  }
+
+  RegExpEngine::CompilationResult result =
+      compiler.Assemble(macro_assembler,
+                        node,
+                        data->capture_count,
+                        pattern);
+
+  if (FLAG_trace_irregexp) {
+    macro_assembler->PrintBlocks();
+  }
+
+  return result;
+}
+
+
 static void CreateSpecializedFunction(Zone* zone,
                                       const JSRegExp& regexp,
                                       intptr_t specialization_cid,
diff --git a/runtime/vm/regexp.h b/runtime/vm/regexp.h
index e0808d6..394279d 100644
--- a/runtime/vm/regexp.h
+++ b/runtime/vm/regexp.h
@@ -1377,16 +1377,30 @@
           graph_entry(NULL),
           num_blocks(-1),
           num_stack_locals(-1),
-          error_message(error_message) {}
+          error_message(error_message),
+          bytecode(NULL),
+          num_registers(-1) {}
+
+    CompilationResult(TypedData* bytecode, intptr_t num_registers)
+        : backtrack_goto(NULL),
+          graph_entry(NULL),
+          num_blocks(-1),
+          num_stack_locals(-1),
+          error_message(NULL),
+          bytecode(bytecode),
+          num_registers(num_registers) {}
+
     CompilationResult(IndirectGotoInstr* backtrack_goto,
                       GraphEntryInstr* graph_entry,
                       intptr_t num_blocks,
-                      intptr_t num_stack_locals)
+                      intptr_t num_stack_locals,
+                      intptr_t num_registers)
       : backtrack_goto(backtrack_goto),
         graph_entry(graph_entry),
         num_blocks(num_blocks),
         num_stack_locals(num_stack_locals),
-        error_message(NULL) {}
+        error_message(NULL),
+        bytecode(NULL) {}
 
     IndirectGotoInstr* backtrack_goto;
     GraphEntryInstr* graph_entry;
@@ -1394,13 +1408,22 @@
     const intptr_t num_stack_locals;
 
     const char* error_message;
+
+    TypedData* bytecode;
+    intptr_t num_registers;
   };
 
-  static CompilationResult Compile(
+  static CompilationResult CompileIR(
       RegExpCompileData* input,
       const ParsedFunction* parsed_function,
       const ZoneGrowableArray<const ICData*>& ic_data_array);
 
+  static CompilationResult CompileBytecode(
+      RegExpCompileData* data,
+      const JSRegExp& regexp,
+      bool is_one_byte,
+      Zone* zone);
+
   static RawJSRegExp* CreateJSRegExp(
       Zone* zone,
       const String& pattern,
diff --git a/runtime/vm/regexp_assembler.cc b/runtime/vm/regexp_assembler.cc
index e4e3247..9e01f35 100644
--- a/runtime/vm/regexp_assembler.cc
+++ b/runtime/vm/regexp_assembler.cc
@@ -4,70 +4,10 @@
 
 #include "vm/regexp_assembler.h"
 
-#include "vm/bit_vector.h"
-#include "vm/compiler.h"
-#include "vm/dart_entry.h"
-#include "vm/flow_graph_builder.h"
-#include "vm/il_printer.h"
-#include "vm/object_store.h"
 #include "vm/regexp.h"
-#include "vm/resolver.h"
-#include "vm/stack_frame.h"
-#include "vm/unibrow-inl.h"
-#include "vm/unicode.h"
-
-#define Z zone()
-
-// Debugging output macros. TAG() is called at the head of each interesting
-// function and prints its name during execution if irregexp tracing is enabled.
-#define TAG() if (FLAG_trace_irregexp) { TAG_(); }
-#define TAG_() \
-  Print(PushArgument( \
-    Bind(new(Z) ConstantInstr(String::ZoneHandle(Z, String::Concat( \
-        String::Handle(String::New("TAG: ")), \
-        String::Handle(String::New(__FUNCTION__)), Heap::kOld))))));
-
-#define PRINT(arg) if (FLAG_trace_irregexp) { Print(arg); }
 
 namespace dart {
 
-DEFINE_FLAG(bool, trace_irregexp, false, "Trace irregexps");
-
-
-static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex;
-static const intptr_t kNoSourcePos = Scanner::kNoSourcePos;
-static const intptr_t kMinStackSize = 512;
-
-
-void PrintUtf16(uint16_t c) {
-  const char* format = (0x20 <= c && c <= 0x7F) ?
-        "%c" : (c <= 0xff) ? "\\x%02x" : "\\u%04x";
-  OS::Print(format, c);
-}
-
-
-/*
- * This assembler uses the following main local variables:
- * - stack_: A pointer to a growable list which we use as an all-purpose stack
- *           storing backtracking offsets, positions & stored register values.
- * - current_character_: Stores the currently loaded characters (possibly more
- *                       than one).
- * - current_position_: The current position within the string, stored as a
- *                      negative offset from the end of the string (i.e. the
- *                      position corresponding to str[0] is -str.length).
- *                      Note that current_position_ is *not* byte-based, unlike
- *                      original V8 code.
- *
- * Results are returned though an array of capture indices, stored at
- * matches_param_. A null array specifies a failure to match. The match indices
- * [start_inclusive, end_exclusive] for capture group i are stored at positions
- * matches_param_[i * 2] and matches_param_[i * 2 + 1], respectively. Match
- * indices of -1 denote non-matched groups. Note that we store these indices
- * as a negative offset from the end of the string in registers_array_
- * during processing, and convert them to standard indexes when copying them
- * to matches_param_ on successful match.
- */
-
 RegExpMacroAssembler::RegExpMacroAssembler(Zone* zone)
   : slow_safe_compiler_(false),
     global_mode_(NOT_GLOBAL),
@@ -78,1858 +18,4 @@
 RegExpMacroAssembler::~RegExpMacroAssembler() {
 }
 
-
-IRRegExpMacroAssembler::IRRegExpMacroAssembler(
-    intptr_t specialization_cid,
-    intptr_t capture_count,
-    const ParsedFunction* parsed_function,
-    const ZoneGrowableArray<const ICData*>& ic_data_array,
-    Zone* zone)
-    : RegExpMacroAssembler(zone),
-      specialization_cid_(specialization_cid),
-      parsed_function_(parsed_function),
-      ic_data_array_(ic_data_array),
-      current_instruction_(NULL),
-      stack_(NULL),
-      stack_pointer_(NULL),
-      current_character_(NULL),
-      current_position_(NULL),
-      string_param_(NULL),
-      string_param_length_(NULL),
-      start_index_param_(NULL),
-      registers_count_(0),
-      saved_registers_count_((capture_count + 1) * 2),
-      stack_array_cell_(Array::ZoneHandle(zone, Array::New(1, Heap::kOld))),
-      // The registers array is allocated at a fixed size after assembly.
-      registers_array_(TypedData::ZoneHandle(zone, TypedData::null())) {
-  switch (specialization_cid) {
-    case kOneByteStringCid:
-    case kExternalOneByteStringCid: mode_ = ASCII; break;
-    case kTwoByteStringCid:
-    case kExternalTwoByteStringCid: mode_ = UC16; break;
-    default: UNREACHABLE();
-  }
-
-  InitializeLocals();
-
-  // Allocate an initial stack backing of the minimum stack size. The stack
-  // backing is indirectly referred to so we can reuse it on subsequent matches
-  // even in the case where the backing has been enlarged and thus reallocated.
-  stack_array_cell_.SetAt(0, TypedData::Handle(zone,
-    TypedData::New(kTypedDataInt32ArrayCid, kMinStackSize / 4, Heap::kOld)));
-
-  // Create and generate all preset blocks.
-  entry_block_ =
-      new(zone) GraphEntryInstr(
-        *parsed_function_,
-        new(zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex),
-        Isolate::kNoDeoptId);
-  start_block_ =
-      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
-  success_block_ =
-      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
-  backtrack_block_ =
-      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
-  exit_block_ =
-      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
-
-  GenerateEntryBlock();
-  GenerateSuccessBlock();
-  GenerateExitBlock();
-
-  blocks_.Add(entry_block_);
-  blocks_.Add(entry_block_->normal_entry());
-  blocks_.Add(start_block_);
-  blocks_.Add(success_block_);
-  blocks_.Add(backtrack_block_);
-  blocks_.Add(exit_block_);
-
-  // Begin emission at the start_block_.
-  set_current_instruction(start_block_);
-}
-
-
-IRRegExpMacroAssembler::~IRRegExpMacroAssembler() { }
-
-
-void IRRegExpMacroAssembler::InitializeLocals() {
-  // All generated functions are expected to have a current-context variable.
-  // This variable is unused in irregexp functions.
-  parsed_function_->current_context_var()->set_index(GetNextLocalIndex());
-
-  // Create local variables and parameters.
-  stack_ = Local(Symbols::stack());
-  stack_pointer_ = Local(Symbols::stack_pointer());
-  registers_ = Local(Symbols::position_registers());
-  current_character_ = Local(Symbols::current_character());
-  current_position_ = Local(Symbols::current_position());
-  string_param_length_ = Local(Symbols::string_param_length());
-  capture_length_ = Local(Symbols::capture_length());
-  match_start_index_ = Local(Symbols::match_start_index());
-  capture_start_index_ = Local(Symbols::capture_start_index());
-  match_end_index_ = Local(Symbols::match_end_index());
-  char_in_capture_ = Local(Symbols::char_in_capture());
-  char_in_match_ = Local(Symbols::char_in_match());
-  index_temp_ = Local(Symbols::index_temp());
-  result_ = Local(Symbols::result());
-
-  string_param_ = Parameter(Symbols::string_param(), 0);
-  start_index_param_ = Parameter(Symbols::start_index_param(), 1);
-}
-
-
-void IRRegExpMacroAssembler::GenerateEntryBlock() {
-  set_current_instruction(entry_block_->normal_entry());
-  TAG();
-
-  // Store string.length.
-  PushArgumentInstr* string_push = PushLocal(string_param_);
-
-  StoreLocal(
-      string_param_length_,
-      Bind(InstanceCall(
-          InstanceCallDescriptor(
-              String::ZoneHandle(Field::GetterSymbol(Symbols::Length()))),
-          string_push)));
-
-  // Store (start_index - string.length) as the current position (since it's a
-  // negative offset from the end of the string).
-  PushArgumentInstr* start_index_push = PushLocal(start_index_param_);
-  PushArgumentInstr* length_push = PushLocal(string_param_length_);
-
-  StoreLocal(current_position_, Bind(Sub(start_index_push, length_push)));
-
-  // Generate a local list variable to represent "registers" and
-  // initialize capture registers (others remain garbage).
-  StoreLocal(registers_, Bind(new(Z) ConstantInstr(registers_array_)));
-  ClearRegisters(0, saved_registers_count_ - 1);
-
-  // Generate a local list variable to represent the backtracking stack.
-  PushArgumentInstr* stack_cell_push =
-      PushArgument(Bind(new(Z) ConstantInstr(stack_array_cell_)));
-  StoreLocal(stack_, Bind(InstanceCall(
-      InstanceCallDescriptor::FromToken(Token::kINDEX),
-      stack_cell_push,
-      PushArgument(Bind(Uint64Constant(0))))));
-  StoreLocal(stack_pointer_, Bind(Int64Constant(-1)));
-
-  // Jump to the start block.
-  current_instruction_->Goto(start_block_);
-}
-
-
-void IRRegExpMacroAssembler::GenerateBacktrackBlock() {
-  set_current_instruction(backtrack_block_);
-  TAG();
-  CheckPreemption();
-
-  const intptr_t entries_count = entry_block_->indirect_entries().length();
-
-  TypedData& offsets = TypedData::ZoneHandle(Z,
-      TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld));
-
-  PushArgumentInstr* block_offsets_push =
-      PushArgument(Bind(new(Z) ConstantInstr(offsets)));
-  PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack()));
-
-  Value* offset_value =
-      Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                        block_offsets_push,
-                        block_id_push));
-
-  backtrack_goto_ = new(Z) IndirectGotoInstr(&offsets, offset_value);
-  CloseBlockWith(backtrack_goto_);
-
-  // Add an edge from the "indirect" goto to each of the targets.
-  for (intptr_t j = 0; j < entries_count; j++) {
-    backtrack_goto_->AddSuccessor(
-        TargetWithJoinGoto(entry_block_->indirect_entries().At(j)));
-  }
-}
-
-
-void IRRegExpMacroAssembler::GenerateSuccessBlock() {
-  set_current_instruction(success_block_);
-  TAG();
-
-  Value* type = Bind(new(Z) ConstantInstr(
-      TypeArguments::ZoneHandle(Z, TypeArguments::null())));
-  Value* length = Bind(Uint64Constant(saved_registers_count_));
-  Value* array = Bind(new(Z) CreateArrayInstr(kNoSourcePos, type, length));
-  StoreLocal(result_, array);
-
-  // Store captured offsets in the `matches` parameter.
-  for (intptr_t i = 0; i < saved_registers_count_; i++) {
-    PushArgumentInstr* matches_push = PushLocal(result_);
-    PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i)));
-
-    // Convert negative offsets from the end of the string to string indices.
-    // TODO(zerny): use positive offsets from the get-go.
-    PushArgumentInstr* offset_push = PushArgument(LoadRegister(i));
-    PushArgumentInstr* len_push = PushLocal(string_param_length_);
-    PushArgumentInstr* value_push =
-        PushArgument(Bind(Add(offset_push, len_push)));
-
-    Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
-                    matches_push,
-                    index_push,
-                    value_push));
-  }
-
-  // Print the result if tracing.
-  PRINT(PushLocal(result_));
-
-  // Return true on success.
-  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
-}
-
-
-void IRRegExpMacroAssembler::GenerateExitBlock() {
-  set_current_instruction(exit_block_);
-  TAG();
-
-  // Return false on failure.
-  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
-}
-
-
-void IRRegExpMacroAssembler::FinalizeRegistersArray() {
-  ASSERT(registers_count_ >= saved_registers_count_);
-  registers_array_ =
-      TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld);
-}
-
-
-#if defined(TARGET_ARCH_ARM64) ||                                              \
-    defined(TARGET_ARCH_ARM) ||                                                \
-    defined(TARGET_ARCH_MIPS)
-// Disabling unaligned accesses forces the regexp engine to load characters one
-// by one instead of up to 4 at once, along with the associated performance hit.
-// TODO(zerny): Be less conservative about disabling unaligned accesses.
-// For instance, ARMv6 supports unaligned accesses. Once it is enabled here,
-// update LoadCodeUnitsInstr methods for the appropriate architectures.
-static const bool kEnableUnalignedAccesses = false;
-#else
-static const bool kEnableUnalignedAccesses = true;
-#endif
-bool IRRegExpMacroAssembler::CanReadUnaligned() {
-  return kEnableUnalignedAccesses && !slow_safe();
-}
-
-
-RawArray* IRRegExpMacroAssembler::Execute(
-    const Function& function,
-    const String& input,
-    const Smi& start_offset,
-    Zone* zone) {
-  // Create the argument list.
-  const Array& args = Array::Handle(Array::New(2));
-  args.SetAt(0, input);
-  args.SetAt(1, start_offset);
-
-  // And finally call the generated code.
-
-  const Object& retval =
-      Object::Handle(zone, DartEntry::InvokeFunction(function, args));
-  if (retval.IsError()) {
-    const Error& error = Error::Cast(retval);
-    OS::Print("%s\n", error.ToErrorCString());
-    // Should never happen.
-    UNREACHABLE();
-  }
-
-  if (retval.IsNull()) {
-    return Array::null();
-  }
-
-  ASSERT(retval.IsArray());
-  return Array::Cast(retval).raw();
-}
-
-
-RawBool* IRRegExpMacroAssembler::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);
-  const Smi& length = Smi::Handle(length_raw);
-
-  // TODO(zerny): Optimize as single instance. V8 has this as an
-  // isolate member.
-  unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
-
-  for (intptr_t i = 0; i < length.Value(); i++) {
-    int32_t c1 = str.CharAt(lhs_index.Value() + i);
-    int32_t c2 = str.CharAt(rhs_index.Value() + i);
-    if (c1 != c2) {
-      int32_t s1[1] = { c1 };
-      canonicalize.get(c1, '\0', s1);
-      if (s1[0] != c2) {
-        int32_t s2[1] = { c2 };
-        canonicalize.get(c2, '\0', s2);
-        if (s1[0] != s2[0]) {
-          return Bool::False().raw();
-        }
-      }
-    }
-  }
-  return Bool::True().raw();
-}
-
-
-LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
-                                                 intptr_t index) const {
-  const Type& local_type = Type::ZoneHandle(Z, Type::DynamicType());
-  LocalVariable* local =
-      new(Z) LocalVariable(kNoSourcePos, name, local_type);
-
-  intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index;
-  local->set_index(param_frame_index);
-
-  return local;
-}
-
-
-LocalVariable* IRRegExpMacroAssembler::Local(const String& name) {
-  const Type& local_type = Type::ZoneHandle(Z, Type::DynamicType());
-  LocalVariable* local =
-      new(Z) LocalVariable(kNoSourcePos, name, local_type);
-  local->set_index(GetNextLocalIndex());
-
-  return local;
-}
-
-
-ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const {
-  return new(Z) ConstantInstr(
-        Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
-}
-
-
-ConstantInstr* IRRegExpMacroAssembler::Uint64Constant(uint64_t value) const {
-  return new(Z) ConstantInstr(
-        Integer::ZoneHandle(Z, Integer::NewFromUint64(value, Heap::kOld)));
-}
-
-
-ConstantInstr* IRRegExpMacroAssembler::BoolConstant(bool value) const {
-  return new(Z) ConstantInstr(value ? Bool::True() : Bool::False());
-}
-
-
-ConstantInstr* IRRegExpMacroAssembler::StringConstant(const char* value) const {
-  return new(Z) ConstantInstr(
-        String::ZoneHandle(Z, String::New(value, Heap::kOld)));
-}
-
-
-ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const {
-  const Library& lib = Library::Handle(Z, Library::CoreLibrary());
-  const Class& regexp_class = Class::Handle(Z,
-        lib.LookupClassAllowPrivate(Symbols::JSSyntaxRegExp()));
-  const Field& word_character_field = Field::ZoneHandle(Z,
-      regexp_class.LookupStaticField(Symbols::_wordCharacterMap()));
-  ASSERT(!word_character_field.IsNull());
-
-  if (word_character_field.IsUninitialized()) {
-    word_character_field.EvaluateInitializer();
-  }
-  ASSERT(!word_character_field.IsUninitialized());
-
-  return new(Z) ConstantInstr(
-        Instance::ZoneHandle(Z, word_character_field.value()));
-}
-
-
-ComparisonInstr* IRRegExpMacroAssembler::Comparison(
-    ComparisonKind kind, PushArgumentInstr* lhs, PushArgumentInstr* rhs) {
-  Token::Kind strict_comparison = Token::kEQ_STRICT;
-  Token::Kind intermediate_operator = Token::kILLEGAL;
-  switch (kind) {
-  case kEQ:
-    intermediate_operator = Token::kEQ;
-    break;
-  case kNE:
-    intermediate_operator = Token::kEQ;
-    strict_comparison = Token::kNE_STRICT;
-    break;
-  case kLT:
-    intermediate_operator = Token::kLT;
-    break;
-  case kGT:
-    intermediate_operator = Token::kGT;
-    break;
-  case kLTE:
-    intermediate_operator = Token::kLTE;
-    break;
-  case kGTE:
-    intermediate_operator = Token::kGTE;
-    break;
-  default:
-    UNREACHABLE();
-  }
-
-  ASSERT(intermediate_operator != Token::kILLEGAL);
-
-  Value* lhs_value =
-      Bind(InstanceCall(
-             InstanceCallDescriptor::FromToken(intermediate_operator),
-             lhs,
-             rhs));
-  Value* rhs_value = Bind(BoolConstant(true));
-
-  return new(Z) StrictCompareInstr(
-      kNoSourcePos, strict_comparison, lhs_value, rhs_value, true);
-}
-
-ComparisonInstr* IRRegExpMacroAssembler::Comparison(
-    ComparisonKind kind, Definition* lhs, Definition* rhs) {
-  PushArgumentInstr* lhs_push = PushArgument(Bind(lhs));
-  PushArgumentInstr* rhs_push = PushArgument(Bind(rhs));
-  return Comparison(kind, lhs_push, rhs_push);
-}
-
-
-StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
-    const Function& function) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(0);
-  return StaticCall(function, arguments);
-}
-
-
-StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
-    const Function& function,
-    PushArgumentInstr* arg1) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
-  arguments->Add(arg1);
-
-  return StaticCall(function, arguments);
-}
-
-
-StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
-    const Function& function,
-    PushArgumentInstr* arg1,
-    PushArgumentInstr* arg2) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
-  arguments->Add(arg1);
-  arguments->Add(arg2);
-
-  return StaticCall(function, arguments);
-}
-
-
-StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
-    const Function& function,
-    ZoneGrowableArray<PushArgumentInstr*>* arguments) const {
-  return new(Z) StaticCallInstr(kNoSourcePos,
-                                function,
-                                Object::null_array(),
-                                arguments,
-                                ic_data_array_);
-}
-
-
-InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
-    const InstanceCallDescriptor& desc,
-    PushArgumentInstr* arg1) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
-  arguments->Add(arg1);
-
-  return InstanceCall(desc, arguments);
-}
-
-
-InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
-    const InstanceCallDescriptor& desc,
-    PushArgumentInstr* arg1,
-    PushArgumentInstr* arg2) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
-  arguments->Add(arg1);
-  arguments->Add(arg2);
-
-  return InstanceCall(desc, arguments);
-}
-
-
-InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
-    const InstanceCallDescriptor& desc,
-    PushArgumentInstr* arg1,
-    PushArgumentInstr* arg2,
-    PushArgumentInstr* arg3) const {
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(3);
-  arguments->Add(arg1);
-  arguments->Add(arg2);
-  arguments->Add(arg3);
-
-  return InstanceCall(desc, arguments);
-}
-
-
-InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
-    const InstanceCallDescriptor& desc,
-    ZoneGrowableArray<PushArgumentInstr*> *arguments) const {
-  return
-    new(Z) InstanceCallInstr(kNoSourcePos,
-                             desc.name,
-                             desc.token_kind,
-                             arguments,
-                             Object::null_array(),
-                             desc.checked_argument_count,
-                             ic_data_array_);
-}
-
-
-LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const {
-  return new(Z) LoadLocalInstr(*local);
-}
-
-
-void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local,
-                                        Value* value) {
-  Do(new(Z) StoreLocalInstr(*local, value));
-}
-
-
-void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) {
-  current_instruction_ = instruction;
-}
-
-
-Value* IRRegExpMacroAssembler::Bind(Definition* definition) {
-  AppendInstruction(definition);
-  definition->set_temp_index(temp_id_.Alloc());
-
-  return new(Z) Value(definition);
-}
-
-
-void IRRegExpMacroAssembler::Do(Definition* definition) {
-  AppendInstruction(definition);
-}
-
-
-Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) {
-  if (local.IsConst()) {
-    return Bind(new(Z) ConstantInstr(*local.ConstValue()));
-  }
-  ASSERT(!local.is_captured());
-  return Bind(new(Z) LoadLocalInstr(local));
-}
-
-
-// In some cases, the V8 irregexp engine generates unreachable code by emitting
-// a jmp not followed by a bind. We cannot do the same, since it is impossible
-// to append to a block following a jmp. In such cases, assume that we are doing
-// the correct thing, but output a warning when tracing.
-#define HANDLE_DEAD_CODE_EMISSION() \
-  if (current_instruction_ == NULL) { \
-    if (FLAG_trace_irregexp) { \
-      OS::Print("WARNING: Attempting to append to a closed assembler. " \
-                "This could be either a bug or generation of dead code " \
-                "inherited from V8.\n"); \
-    } \
-    BlockLabel dummy; \
-    BindBlock(&dummy); \
-  }
-
-void IRRegExpMacroAssembler::AppendInstruction(Instruction* instruction) {
-  HANDLE_DEAD_CODE_EMISSION();
-
-  ASSERT(current_instruction_ != NULL);
-  ASSERT(current_instruction_->next() == NULL);
-
-  temp_id_.Dealloc(instruction->InputCount());
-  arg_id_.Dealloc(instruction->ArgumentCount());
-
-  current_instruction_->LinkTo(instruction);
-  set_current_instruction(instruction);
-}
-
-
-void IRRegExpMacroAssembler::CloseBlockWith(Instruction* instruction) {
-  HANDLE_DEAD_CODE_EMISSION();
-
-  ASSERT(current_instruction_ != NULL);
-  ASSERT(current_instruction_->next() == NULL);
-
-  temp_id_.Dealloc(instruction->InputCount());
-  arg_id_.Dealloc(instruction->ArgumentCount());
-
-  current_instruction_->LinkTo(instruction);
-  set_current_instruction(NULL);
-}
-
-
-void IRRegExpMacroAssembler::GoTo(BlockLabel* to) {
-  if (to == NULL) {
-    Backtrack();
-  } else {
-    to->SetLinked();
-    GoTo(to->block());
-  }
-}
-
-
-// Closes the current block with a goto, and unsets current_instruction_.
-// BindBlock() must be called before emission can continue.
-void IRRegExpMacroAssembler::GoTo(JoinEntryInstr* to) {
-  HANDLE_DEAD_CODE_EMISSION();
-
-  ASSERT(current_instruction_ != NULL);
-  ASSERT(current_instruction_->next() == NULL);
-  current_instruction_->Goto(to);
-  set_current_instruction(NULL);
-}
-
-
-PushArgumentInstr* IRRegExpMacroAssembler::PushArgument(Value* value) {
-  arg_id_.Alloc();
-  PushArgumentInstr* push = new(Z) PushArgumentInstr(value);
-  // Do *not* use Do() for push argument instructions.
-  AppendInstruction(push);
-  return push;
-}
-
-
-PushArgumentInstr* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) {
-  return PushArgument(Bind(LoadLocal(local)));
-}
-
-
-void IRRegExpMacroAssembler::Print(const char* str) {
-  Print(PushArgument(
-    Bind(new(Z) ConstantInstr(
-           String::ZoneHandle(Z, String::New(str, Heap::kOld))))));
-}
-
-
-void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) {
-  const Library& lib = Library::Handle(Library::CoreLibrary());
-  const Function& print_fn = Function::ZoneHandle(
-        Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
-  Do(StaticCall(print_fn, argument));
-}
-
-
-void IRRegExpMacroAssembler::PrintBlocks() {
-  for (intptr_t i = 0; i < blocks_.length(); i++) {
-    FlowGraphPrinter::PrintBlock(blocks_[i], false);
-  }
-}
-
-
-intptr_t IRRegExpMacroAssembler::stack_limit_slack()  {
-  return 32;
-}
-
-
-void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) {
-  TAG();
-  if (by != 0) {
-    PushArgumentInstr* cur_pos_push = PushLocal(current_position_);
-    PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by)));
-
-    Value* new_pos_value = Bind(Add(cur_pos_push, by_push));
-    StoreLocal(current_position_, new_pos_value);
-  }
-}
-
-
-void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) {
-  TAG();
-  ASSERT(reg >= 0);
-  ASSERT(reg < registers_count_);
-
-  if (by != 0) {
-    PushArgumentInstr* registers_push = PushLocal(registers_);
-    PushArgumentInstr* index_push = PushRegisterIndex(reg);
-    PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
-    PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by)));
-    PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push)));
-    StoreRegister(registers_push, index_push, value_push);
-  }
-}
-
-
-void IRRegExpMacroAssembler::Backtrack() {
-  TAG();
-  GoTo(backtrack_block_);
-}
-
-
-// A BindBlock is analogous to assigning a label to a basic block.
-// If the BlockLabel does not yet contain a block, it is created.
-// If there is a current instruction, append a goto to the bound block.
-void IRRegExpMacroAssembler::BindBlock(BlockLabel* label) {
-  ASSERT(!label->IsBound());
-  ASSERT(label->block()->next() == NULL);
-
-  label->SetBound(block_id_.Alloc());
-  blocks_.Add(label->block());
-
-  if (current_instruction_ != NULL) {
-    GoTo(label);
-  }
-  set_current_instruction(label->block());
-
-  // Print the id of the current block if tracing.
-  PRINT(PushArgument(Bind(Uint64Constant(label->block()->block_id()))));
-}
-
-
-intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() {
-  intptr_t id = local_id_.Alloc();
-  return kFirstLocalSlotFromFp - id;
-}
-
-
-Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) {
-  PushArgumentInstr* registers_push = PushLocal(registers_);
-  PushArgumentInstr* index_push = PushRegisterIndex(index);
-  return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                           registers_push,
-                           index_push));
-}
-
-void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) {
-  PushArgumentInstr* registers_push = PushLocal(registers_);
-  PushArgumentInstr* index_push = PushRegisterIndex(index);
-  PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value)));
-  StoreRegister(registers_push, index_push, value_push);
-}
-
-
-void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers,
-                                           PushArgumentInstr* index,
-                                           PushArgumentInstr* value) {
-  TAG();
-  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
-                  registers,
-                  index,
-                  value));
-}
-
-PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) {
-  if (registers_count_ <= index) {
-    registers_count_ = index + 1;
-  }
-  return PushArgument(Bind(Uint64Constant(index)));
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacter(uint32_t c, BlockLabel* on_equal) {
-  TAG();
-  Definition* cur_char_def = LoadLocal(current_character_);
-  Definition* char_def = Uint64Constant(c);
-
-  BranchOrBacktrack(Comparison(kEQ, cur_char_def, char_def), on_equal);
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacterGT(uint16_t limit,
-                                              BlockLabel* on_greater) {
-  TAG();
-  BranchOrBacktrack(Comparison(kGT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(limit)),
-                    on_greater);
-}
-
-
-void IRRegExpMacroAssembler::CheckAtStart(BlockLabel* on_at_start) {
-  TAG();
-
-  BlockLabel not_at_start;
-
-  // Did we start the match at the start of the string at all?
-  BranchOrBacktrack(Comparison(kNE,
-                               LoadLocal(start_index_param_),
-                               Uint64Constant(0)),
-                    &not_at_start);
-
-  // If we did, are we still at the start of the input, i.e. is
-  // (offset == string_length * -1)?
-  Definition* neg_len_def =
-      InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE),
-                   PushLocal(string_param_length_));
-  Definition* offset_def = LoadLocal(current_position_);
-  BranchOrBacktrack(Comparison(kEQ, neg_len_def, offset_def),
-                    on_at_start);
-
-  BindBlock(&not_at_start);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotAtStart(BlockLabel* on_not_at_start) {
-  TAG();
-
-  // Did we start the match at the start of the string at all?
-  BranchOrBacktrack(Comparison(kNE,
-                               LoadLocal(start_index_param_),
-                               Uint64Constant(0)),
-                    on_not_at_start);
-
-  // If we did, are we still at the start of the input, i.e. is
-  // (offset == string_length * -1)?
-  Definition* neg_len_def =
-      InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE),
-                   PushLocal(string_param_length_));
-  Definition* offset_def = LoadLocal(current_position_);
-  BranchOrBacktrack(Comparison(kNE, neg_len_def, offset_def),
-                    on_not_at_start);
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacterLT(uint16_t limit,
-                                              BlockLabel* on_less) {
-  TAG();
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(limit)),
-                    on_less);
-}
-
-
-void IRRegExpMacroAssembler::CheckGreedyLoop(BlockLabel* on_equal) {
-  TAG();
-
-  BlockLabel fallthrough;
-
-  Definition* head = PeekStack();
-  Definition* cur_pos_def = LoadLocal(current_position_);
-  BranchOrBacktrack(Comparison(kNE, head, cur_pos_def),
-                    &fallthrough);
-
-  // Pop, throwing away the value.
-  Do(PopStack());
-
-  BranchOrBacktrack(NULL, on_equal);
-
-  BindBlock(&fallthrough);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(
-    intptr_t start_reg,
-    BlockLabel* on_no_match) {
-  TAG();
-  ASSERT(start_reg + 1 <= registers_count_);
-
-  BlockLabel fallthrough;
-
-  PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1));
-  PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg));
-  StoreLocal(capture_length_, Bind(Sub(end_push, start_push)));
-
-  // The length of a capture should not be negative. This can only happen
-  // if the end of the capture is unrecorded, or at a point earlier than
-  // the start of the capture.
-  // BranchOrBacktrack(less, on_no_match);
-
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(capture_length_),
-                               Uint64Constant(0)),
-                    on_no_match);
-
-  // If length is zero, either the capture is empty or it is completely
-  // uncaptured. In either case succeed immediately.
-  BranchOrBacktrack(Comparison(kEQ,
-                               LoadLocal(capture_length_),
-                               Uint64Constant(0)),
-                    &fallthrough);
-
-
-  // Check that there are sufficient characters left in the input.
-  PushArgumentInstr* pos_push = PushLocal(current_position_);
-  PushArgumentInstr* len_push = PushLocal(capture_length_);
-  BranchOrBacktrack(
-        Comparison(kGT,
-                   InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD),
-                                pos_push,
-                                len_push),
-                   Uint64Constant(0)),
-        on_no_match);
-
-  pos_push = PushLocal(current_position_);
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(match_start_index_, Bind(Add(pos_push, len_push)));
-
-  pos_push = PushArgument(LoadRegister(start_reg));
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push)));
-
-  pos_push = PushLocal(match_start_index_);
-  len_push = PushLocal(capture_length_);
-  StoreLocal(match_end_index_, Bind(Add(pos_push, len_push)));
-
-  BlockLabel success;
-  if (mode_ == ASCII) {
-    BlockLabel loop_increment;
-    BlockLabel loop;
-    BindBlock(&loop);
-
-    StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
-    StoreLocal(char_in_match_, CharacterAt(match_start_index_));
-
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(char_in_capture_),
-                                 LoadLocal(char_in_match_)),
-                      &loop_increment);
-
-    // Mismatch, try case-insensitive match (converting letters to lower-case).
-    PushArgumentInstr* match_char_push = PushLocal(char_in_match_);
-    PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(0x20)));
-    StoreLocal(char_in_match_,
-               Bind(InstanceCall(
-                      InstanceCallDescriptor::FromToken(Token::kBIT_OR),
-                      match_char_push,
-                      mask_push)));
-
-    BlockLabel convert_capture;
-    BlockLabel on_not_in_range;
-    BranchOrBacktrack(Comparison(kLT,
-                                 LoadLocal(char_in_match_),
-                                 Uint64Constant('a')),
-                      &on_not_in_range);
-    BranchOrBacktrack(Comparison(kGT,
-                                 LoadLocal(char_in_match_),
-                                 Uint64Constant('z')),
-                      &on_not_in_range);
-    GoTo(&convert_capture);
-    BindBlock(&on_not_in_range);
-
-    // Latin-1: Check for values in range [224,254] but not 247.
-    BranchOrBacktrack(Comparison(kLT,
-                                 LoadLocal(char_in_match_),
-                                 Uint64Constant(224)),
-                      on_no_match);
-    BranchOrBacktrack(Comparison(kGT,
-                                 LoadLocal(char_in_match_),
-                                 Uint64Constant(254)),
-                      on_no_match);
-
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(char_in_match_),
-                                 Uint64Constant(247)),
-                      on_no_match);
-
-    // Also convert capture character.
-    BindBlock(&convert_capture);
-
-    PushArgumentInstr* capture_char_push = PushLocal(char_in_capture_);
-    mask_push = PushArgument(Bind(Uint64Constant(0x20)));
-    StoreLocal(char_in_capture_,
-               Bind(InstanceCall(
-                      InstanceCallDescriptor::FromToken(Token::kBIT_OR),
-                      capture_char_push,
-                      mask_push)));
-
-    BranchOrBacktrack(Comparison(kNE,
-                                 LoadLocal(char_in_match_),
-                                 LoadLocal(char_in_capture_)),
-                      on_no_match);
-
-    BindBlock(&loop_increment);
-
-    // Increment indexes into capture and match strings.
-    PushArgumentInstr* index_push = PushLocal(capture_start_index_);
-    PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1)));
-    StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push)));
-
-    index_push = PushLocal(match_start_index_);
-    inc_push = PushArgument(Bind(Uint64Constant(1)));
-    StoreLocal(match_start_index_, Bind(Add(index_push, inc_push)));
-
-    // Compare to end of match, and loop if not done.
-    BranchOrBacktrack(Comparison(kLT,
-                                 LoadLocal(match_start_index_),
-                                 LoadLocal(match_end_index_)),
-                      &loop);
-  } else {
-    ASSERT(mode_ == UC16);
-
-    Value* string_value = Bind(LoadLocal(string_param_));
-    Value* lhs_index_value = Bind(LoadLocal(match_start_index_));
-    Value* rhs_index_value = Bind(LoadLocal(capture_start_index_));
-    Value* length_value = Bind(LoadLocal(capture_length_));
-
-    Definition* is_match_def =
-        new(Z) CaseInsensitiveCompareUC16Instr(
-                            string_value,
-                            lhs_index_value,
-                            rhs_index_value,
-                            length_value,
-                            specialization_cid_);
-
-    BranchOrBacktrack(Comparison(kNE, is_match_def, BoolConstant(true)),
-                      on_no_match);
-  }
-
-  BindBlock(&success);
-
-  // Move current character position to position after match.
-  PushArgumentInstr* match_end_push = PushLocal(match_end_index_);
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(current_position_, Bind(Sub(match_end_push, len_push)));
-
-  BindBlock(&fallthrough);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotBackReference(
-    intptr_t start_reg,
-    BlockLabel* on_no_match) {
-  TAG();
-  ASSERT(start_reg + 1 <= registers_count_);
-
-  BlockLabel fallthrough;
-  BlockLabel success;
-
-  // Find length of back-referenced capture.
-  PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1));
-  PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg));
-  StoreLocal(capture_length_, Bind(Sub(end_push, start_push)));
-
-  // Fail on partial or illegal capture (start of capture after end of capture).
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(capture_length_),
-                               Uint64Constant(0)),
-                    on_no_match);
-
-  // Succeed on empty capture (including no capture)
-  BranchOrBacktrack(Comparison(kEQ,
-                               LoadLocal(capture_length_),
-                               Uint64Constant(0)),
-                    &fallthrough);
-
-  // Check that there are sufficient characters left in the input.
-  PushArgumentInstr* pos_push = PushLocal(current_position_);
-  PushArgumentInstr* len_push = PushLocal(capture_length_);
-  BranchOrBacktrack(
-        Comparison(kGT,
-                   InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD),
-                                pos_push,
-                                len_push),
-                   Uint64Constant(0)),
-        on_no_match);
-
-  // Compute pointers to match string and capture string.
-  pos_push = PushLocal(current_position_);
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(match_start_index_, Bind(Add(pos_push, len_push)));
-
-  pos_push = PushArgument(LoadRegister(start_reg));
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push)));
-
-  pos_push = PushLocal(match_start_index_);
-  len_push = PushLocal(capture_length_);
-  StoreLocal(match_end_index_, Bind(Add(pos_push, len_push)));
-
-  BlockLabel loop;
-  BindBlock(&loop);
-
-  StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
-  StoreLocal(char_in_match_, CharacterAt(match_start_index_));
-
-  BranchOrBacktrack(Comparison(kNE,
-                               LoadLocal(char_in_capture_),
-                               LoadLocal(char_in_match_)),
-                    on_no_match);
-
-  // Increment indexes into capture and match strings.
-  PushArgumentInstr* index_push = PushLocal(capture_start_index_);
-  PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1)));
-  StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push)));
-
-  index_push = PushLocal(match_start_index_);
-  inc_push = PushArgument(Bind(Uint64Constant(1)));
-  StoreLocal(match_start_index_, Bind(Add(index_push, inc_push)));
-
-  // Check if we have reached end of match area.
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(match_start_index_),
-                               LoadLocal(match_end_index_)),
-                    &loop);
-
-  BindBlock(&success);
-
-  // Move current character position to position after match.
-  PushArgumentInstr* match_end_push = PushLocal(match_end_index_);
-  len_push = PushLocal(string_param_length_);
-  StoreLocal(current_position_, Bind(Sub(match_end_push, len_push)));
-
-  BindBlock(&fallthrough);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotCharacter(uint32_t c,
-                                               BlockLabel* on_not_equal) {
-  TAG();
-  BranchOrBacktrack(Comparison(kNE,
-                               LoadLocal(current_character_),
-                               Uint64Constant(c)),
-                    on_not_equal);
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacterAfterAnd(uint32_t c,
-                                                    uint32_t mask,
-                                                    BlockLabel* on_equal) {
-  TAG();
-
-  Definition* actual_def = LoadLocal(current_character_);
-  Definition* expected_def = Uint64Constant(c);
-
-  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
-  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
-  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
-                            actual_push,
-                            mask_push);
-
-  BranchOrBacktrack(Comparison(kEQ, actual_def, expected_def), on_equal);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotCharacterAfterAnd(
-    uint32_t c,
-    uint32_t mask,
-    BlockLabel* on_not_equal) {
-  TAG();
-
-  Definition* actual_def = LoadLocal(current_character_);
-  Definition* expected_def = Uint64Constant(c);
-
-  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
-  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
-  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
-                            actual_push,
-                            mask_push);
-
-  BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal);
-}
-
-
-void IRRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(
-    uint16_t c,
-    uint16_t minus,
-    uint16_t mask,
-    BlockLabel* on_not_equal) {
-  TAG();
-  ASSERT(minus < Utf16::kMaxCodeUnit);  // NOLINT
-
-  Definition* actual_def = LoadLocal(current_character_);
-  Definition* expected_def = Uint64Constant(c);
-
-  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
-  PushArgumentInstr* minus_push = PushArgument(Bind(Uint64Constant(minus)));
-
-  actual_push = PushArgument(Bind(Sub(actual_push, minus_push)));
-  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
-  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
-                            actual_push,
-                            mask_push);
-
-  BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal);
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacterInRange(
-    uint16_t from,
-    uint16_t to,
-    BlockLabel* on_in_range) {
-  TAG();
-  ASSERT(from <= to);
-
-  // TODO(zerny): All range comparisons could be done cheaper with unsigned
-  // compares. This pattern repeats in various places.
-
-  BlockLabel on_not_in_range;
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(from)),
-                    &on_not_in_range);
-  BranchOrBacktrack(Comparison(kGT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(to)),
-                    &on_not_in_range);
-  BranchOrBacktrack(NULL, on_in_range);
-
-  BindBlock(&on_not_in_range);
-}
-
-
-void IRRegExpMacroAssembler::CheckCharacterNotInRange(
-    uint16_t from,
-    uint16_t to,
-    BlockLabel* on_not_in_range) {
-  TAG();
-  ASSERT(from <= to);
-
-  BranchOrBacktrack(Comparison(kLT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(from)),
-                    on_not_in_range);
-
-  BranchOrBacktrack(Comparison(kGT,
-                               LoadLocal(current_character_),
-                               Uint64Constant(to)),
-                    on_not_in_range);
-}
-
-
-void IRRegExpMacroAssembler::CheckBitInTable(
-    const TypedData& table,
-    BlockLabel* on_bit_set) {
-  TAG();
-
-  PushArgumentInstr* table_push =
-      PushArgument(Bind(new(Z) ConstantInstr(table)));
-  PushArgumentInstr* index_push = PushLocal(current_character_);
-
-  if (mode_ != ASCII || kTableMask != Symbols::kMaxOneCharCodeSymbol) {
-    PushArgumentInstr* mask_push =
-        PushArgument(Bind(Uint64Constant(kTableSize - 1)));
-    index_push = PushArgument(
-          Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
-                            index_push,
-                            mask_push)));
-  }
-
-  Definition* byte_def =
-      InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                   table_push,
-                   index_push);
-  Definition* zero_def = Int64Constant(0);
-
-  BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_bit_set);
-}
-
-
-bool IRRegExpMacroAssembler::CheckSpecialCharacterClass(
-    uint16_t type,
-    BlockLabel* on_no_match) {
-  TAG();
-
-  // Range checks (c in min..max) are generally implemented by an unsigned
-  // (c - min) <= (max - min) check
-  switch (type) {
-  case 's':
-    // Match space-characters
-    if (mode_ == ASCII) {
-      // One byte space characters are '\t'..'\r', ' ' and \u00a0.
-      BlockLabel success;
-      // Space (' ').
-      BranchOrBacktrack(Comparison(kEQ,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(' ')),
-                        &success);
-      // Check range 0x09..0x0d.
-      CheckCharacterInRange('\t', '\r', &success);
-      // \u00a0 (NBSP).
-      BranchOrBacktrack(Comparison(kNE,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(0x00a0)),
-                        on_no_match);
-      BindBlock(&success);
-      return true;
-    }
-    return false;
-  case 'S':
-    // The emitted code for generic character classes is good enough.
-    return false;
-  case 'd':
-    // Match ASCII digits ('0'..'9')
-    CheckCharacterNotInRange('0', '9', on_no_match);
-    return true;
-  case 'D':
-    // Match non ASCII-digits
-    CheckCharacterInRange('0', '9', on_no_match);
-    return true;
-  case '.': {
-    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(current_character_),
-                                 Uint64Constant('\n')),
-                      on_no_match);
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(current_character_),
-                                 Uint64Constant('\r')),
-                      on_no_match);
-    if (mode_ == UC16) {
-      BranchOrBacktrack(Comparison(kEQ,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(0x2028)),
-                        on_no_match);
-      BranchOrBacktrack(Comparison(kEQ,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(0x2029)),
-                        on_no_match);
-    }
-    return true;
-  }
-  case 'w': {
-    if (mode_ != ASCII) {
-      // Table is 128 entries, so all ASCII characters can be tested.
-      BranchOrBacktrack(Comparison(kGT,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant('z')),
-                        on_no_match);
-    }
-
-    PushArgumentInstr* table_push =
-        PushArgument(Bind(WordCharacterMapConstant()));
-    PushArgumentInstr* index_push = PushLocal(current_character_);
-
-    Definition* byte_def =
-        InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                     table_push,
-                     index_push);
-    Definition* zero_def = Int64Constant(0);
-
-    BranchOrBacktrack(Comparison(kEQ, byte_def, zero_def), on_no_match);
-
-    return true;
-  }
-  case 'W': {
-    BlockLabel done;
-    if (mode_ != ASCII) {
-      // Table is 128 entries, so all ASCII characters can be tested.
-      BranchOrBacktrack(Comparison(kGT,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant('z')),
-                        &done);
-    }
-
-    // TODO(zerny): Refactor to use CheckBitInTable if possible.
-
-    PushArgumentInstr* table_push =
-        PushArgument(Bind(WordCharacterMapConstant()));
-    PushArgumentInstr* index_push = PushLocal(current_character_);
-
-    Definition* byte_def =
-        InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                     table_push,
-                     index_push);
-    Definition* zero_def = Int64Constant(0);
-
-    BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_no_match);
-
-    if (mode_ != ASCII) {
-      BindBlock(&done);
-    }
-    return true;
-  }
-  // Non-standard classes (with no syntactic shorthand) used internally.
-  case '*':
-    // Match any character.
-    return true;
-  case 'n': {
-    // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
-    // The opposite of '.'.
-    BlockLabel success;
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(current_character_),
-                                 Uint64Constant('\n')),
-                      &success);
-    BranchOrBacktrack(Comparison(kEQ,
-                                 LoadLocal(current_character_),
-                                 Uint64Constant('\r')),
-                      &success);
-    if (mode_ == UC16) {
-      BranchOrBacktrack(Comparison(kEQ,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(0x2028)),
-                        &success);
-      BranchOrBacktrack(Comparison(kEQ,
-                                   LoadLocal(current_character_),
-                                   Uint64Constant(0x2029)),
-                        &success);
-    }
-    BranchOrBacktrack(NULL, on_no_match);
-    BindBlock(&success);
-    return true;
-  }
-  // No custom implementation (yet): s(uint16_t), S(uint16_t).
-  default:
-    return false;
-  }
-}
-
-
-void IRRegExpMacroAssembler::Fail() {
-  TAG();
-  ASSERT(FAILURE == 0);  // Return value for failure is zero.
-  if (!global()) {
-    UNREACHABLE();  // Dart regexps are always global.
-  }
-  GoTo(exit_block_);
-}
-
-
-void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg,
-                                          intptr_t comparand,
-                                          BlockLabel* if_ge) {
-  TAG();
-  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
-  PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand)));
-  BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge);
-}
-
-
-void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg,
-                                          intptr_t comparand,
-                                          BlockLabel* if_lt) {
-  TAG();
-  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
-  PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand)));
-  BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt);
-}
-
-
-void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg,
-                                             BlockLabel* if_eq) {
-  TAG();
-  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
-  PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_)));
-  BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq);
-}
-
-
-RegExpMacroAssembler::IrregexpImplementation
-    IRRegExpMacroAssembler::Implementation() {
-  return kIRImplementation;
-}
-
-
-void IRRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset,
-                                                  BlockLabel* on_end_of_input,
-                                                  bool check_bounds,
-                                                  intptr_t characters) {
-  TAG();
-  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
-  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
-  if (check_bounds) {
-    CheckPosition(cp_offset + characters - 1, on_end_of_input);
-  }
-  LoadCurrentCharacterUnchecked(cp_offset, characters);
-}
-
-
-void IRRegExpMacroAssembler::PopCurrentPosition() {
-  TAG();
-  StoreLocal(current_position_, Bind(PopStack()));
-}
-
-
-void IRRegExpMacroAssembler::PopRegister(intptr_t reg) {
-  TAG();
-  ASSERT(reg < registers_count_);
-  PushArgumentInstr* registers_push = PushLocal(registers_);
-  PushArgumentInstr* index_push = PushRegisterIndex(reg);
-  PushArgumentInstr* pop_push = PushArgument(Bind(PopStack()));
-  StoreRegister(registers_push, index_push, pop_push);
-}
-
-
-void IRRegExpMacroAssembler::PushStack(Definition *definition) {
-  PushArgumentInstr* stack_push = PushLocal(stack_);
-  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
-  StoreLocal(stack_pointer_,
-             Bind(Add(stack_pointer_push,
-                      PushArgument(Bind(Uint64Constant(1))))));
-  stack_pointer_push = PushLocal(stack_pointer_);
-  // TODO(zerny): bind value and push could break stack discipline.
-  PushArgumentInstr* value_push = PushArgument(Bind(definition));
-  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
-                  stack_push,
-                  stack_pointer_push,
-                  value_push));
-}
-
-
-Definition* IRRegExpMacroAssembler::PopStack() {
-  PushArgumentInstr* stack_push = PushLocal(stack_);
-  PushArgumentInstr* stack_pointer_push1 = PushLocal(stack_pointer_);
-  PushArgumentInstr* stack_pointer_push2 = PushLocal(stack_pointer_);
-  StoreLocal(stack_pointer_,
-             Bind(Sub(stack_pointer_push2,
-                      PushArgument(Bind(Uint64Constant(1))))));
-  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                      stack_push,
-                      stack_pointer_push1);
-}
-
-
-Definition* IRRegExpMacroAssembler::PeekStack() {
-  PushArgumentInstr* stack_push = PushLocal(stack_);
-  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
-  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
-                      stack_push,
-                      stack_pointer_push);
-}
-
-
-// Pushes the location corresponding to label to the backtracking stack.
-void IRRegExpMacroAssembler::PushBacktrack(BlockLabel* label) {
-  TAG();
-
-  // Ensure that targets of indirect jumps are never accessed through a
-  // normal control flow instructions by creating a new block for each backtrack
-  // target.
-  IndirectEntryInstr* indirect_target = IndirectWithJoinGoto(label->block());
-
-  // Add a fake edge from the graph entry for data flow analysis.
-  entry_block_->AddIndirectEntry(indirect_target);
-
-  ConstantInstr* offset = Uint64Constant(indirect_target->indirect_id());
-  PushStack(offset);
-  CheckStackLimit();
-}
-
-
-void IRRegExpMacroAssembler::PushCurrentPosition() {
-  TAG();
-  PushStack(LoadLocal(current_position_));
-}
-
-
-void IRRegExpMacroAssembler::PushRegister(intptr_t reg) {
-  TAG();
-  // TODO(zerny): Refactor PushStack so it can be reused here.
-  PushArgumentInstr* stack_push = PushLocal(stack_);
-  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
-  StoreLocal(stack_pointer_,
-             Bind(Add(stack_pointer_push,
-                      PushArgument(Bind(Uint64Constant(1))))));
-  stack_pointer_push = PushLocal(stack_pointer_);
-  // TODO(zerny): bind value and push could break stack discipline.
-  PushArgumentInstr* value_push = PushArgument(LoadRegister(reg));
-  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
-                  stack_push,
-                  stack_pointer_push,
-                  value_push));
-  CheckStackLimit();
-}
-
-
-// Checks that (stack.capacity - stack_limit_slack) > stack_pointer.
-// This ensures that up to stack_limit_slack stack pushes can be
-// done without exhausting the stack space. If the check fails the
-// stack will be grown.
-void IRRegExpMacroAssembler::CheckStackLimit() {
-  TAG();
-  PushArgumentInstr* stack_push = PushLocal(stack_);
-  PushArgumentInstr* length_push = PushArgument(Bind(InstanceCall(
-      InstanceCallDescriptor(
-          String::ZoneHandle(Field::GetterSymbol(Symbols::Length()))),
-      stack_push)));
-  PushArgumentInstr* capacity_push = PushArgument(Bind(Sub(
-      length_push,
-      PushArgument(Bind(Uint64Constant(stack_limit_slack()))))));
-  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
-  BranchInstr* branch = new(Z) BranchInstr(
-      Comparison(kGT, capacity_push, stack_pointer_push));
-  CloseBlockWith(branch);
-
-  BlockLabel grow_stack;
-  BlockLabel fallthrough;
-  *branch->true_successor_address() =
-      TargetWithJoinGoto(fallthrough.block());
-  *branch->false_successor_address() =
-      TargetWithJoinGoto(grow_stack.block());
-
-  BindBlock(&grow_stack);
-  GrowStack();
-
-  BindBlock(&fallthrough);
-}
-
-
-void IRRegExpMacroAssembler::GrowStack() {
-  TAG();
-  Value* cell = Bind(new(Z) ConstantInstr(stack_array_cell_));
-  StoreLocal(stack_, Bind(new(Z) GrowRegExpStackInstr(cell)));
-}
-
-
-void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) {
-  TAG();
-  StoreLocal(current_position_, LoadRegister(reg));
-}
-
-// Resets the tip of the stack to the value stored in reg.
-void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) {
-  TAG();
-  ASSERT(reg < registers_count_);
-  StoreLocal(stack_pointer_, LoadRegister(reg));
-}
-
-void IRRegExpMacroAssembler::SetCurrentPositionFromEnd(intptr_t by)  {
-  TAG();
-
-  BlockLabel after_position;
-
-  Definition* cur_pos_def = LoadLocal(current_position_);
-  Definition* by_value_def = Int64Constant(-by);
-
-  BranchOrBacktrack(Comparison(kGTE, cur_pos_def, by_value_def),
-                    &after_position);
-
-  StoreLocal(current_position_, Bind(Int64Constant(-by)));
-
-  // On RegExp code entry (where this operation is used), the character before
-  // the current position is expected to be already loaded.
-  // We have advanced the position, so it's safe to read backwards.
-  LoadCurrentCharacterUnchecked(-1, 1);
-
-  BindBlock(&after_position);
-}
-
-
-void IRRegExpMacroAssembler::SetRegister(intptr_t reg, intptr_t to) {
-  TAG();
-  // Reserved for positions!
-  ASSERT(reg >= saved_registers_count_);
-  StoreRegister(reg, to);
-}
-
-
-bool IRRegExpMacroAssembler::Succeed() {
-  TAG();
-  GoTo(success_block_);
-  return global();
-}
-
-
-void IRRegExpMacroAssembler::WriteCurrentPositionToRegister(
-    intptr_t reg, intptr_t cp_offset) {
-  TAG();
-
-  PushArgumentInstr* registers_push = PushLocal(registers_);
-  PushArgumentInstr* index_push = PushRegisterIndex(reg);
-  PushArgumentInstr* pos_push = PushLocal(current_position_);
-  PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset)));
-  PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push)));
-  // Push the negative offset; these are converted to positive string positions
-  // within the success block.
-  StoreRegister(registers_push, index_push, neg_off_push);
-}
-
-
-void IRRegExpMacroAssembler::ClearRegisters(
-    intptr_t reg_from, intptr_t reg_to) {
-  TAG();
-
-  ASSERT(reg_from <= reg_to);
-
-  // In order to clear registers to a final result value of -1, set them to
-  // (-1 - string length), the offset of -1 from the end of the string.
-
-  for (intptr_t reg = reg_from; reg <= reg_to; reg++) {
-    PushArgumentInstr* registers_push = PushLocal(registers_);
-    PushArgumentInstr* index_push = PushRegisterIndex(reg);
-    PushArgumentInstr* minus_one_push =
-        PushArgument(Bind(Int64Constant(-1)));
-    PushArgumentInstr* length_push = PushLocal(string_param_length_);
-    PushArgumentInstr* value_push =
-        PushArgument(Bind(Sub(minus_one_push, length_push)));
-    StoreRegister(registers_push, index_push, value_push);
-  }
-}
-
-
-void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) {
-  TAG();
-
-  PushArgumentInstr* registers_push = PushLocal(registers_);
-  PushArgumentInstr* index_push = PushRegisterIndex(reg);
-  PushArgumentInstr* tip_push = PushLocal(stack_pointer_);
-  StoreRegister(registers_push, index_push, tip_push);
-}
-
-
-// Private methods:
-
-
-void IRRegExpMacroAssembler::CheckPosition(intptr_t cp_offset,
-                                           BlockLabel* on_outside_input) {
-  TAG();
-  Definition* curpos_def = LoadLocal(current_position_);
-  Definition* cp_off_def = Int64Constant(-cp_offset);
-
-  // If (current_position_ < -cp_offset), we are in bounds.
-  // Remember, current_position_ is a negative offset from the string end.
-
-  BranchOrBacktrack(Comparison(kGTE, curpos_def, cp_off_def),
-                    on_outside_input);
-}
-
-
-void IRRegExpMacroAssembler::BranchOrBacktrack(
-    ComparisonInstr* comparison,
-    BlockLabel* true_successor) {
-  if (comparison == NULL) {  // No condition
-    if (true_successor == NULL) {
-      Backtrack();
-      return;
-    }
-    GoTo(true_successor);
-    return;
-  }
-
-  // If no successor block has been passed in, backtrack.
-  JoinEntryInstr* true_successor_block = backtrack_block_;
-  if (true_successor != NULL) {
-    true_successor->SetLinked();
-    true_successor_block = true_successor->block();
-  }
-  ASSERT(true_successor_block != NULL);
-
-  // If the condition is not true, fall through to a new block.
-  BlockLabel fallthrough;
-
-  BranchInstr* branch = new(Z) BranchInstr(comparison);
-  *branch->true_successor_address() =
-      TargetWithJoinGoto(true_successor_block);
-  *branch->false_successor_address() =
-      TargetWithJoinGoto(fallthrough.block());
-
-  CloseBlockWith(branch);
-  BindBlock(&fallthrough);
-}
-
-
-TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto(
-    JoinEntryInstr* dst) {
-  TargetEntryInstr* target = new(Z) TargetEntryInstr(
-          block_id_.Alloc(), kInvalidTryIndex);
-  blocks_.Add(target);
-
-  target->AppendInstruction(new(Z) GotoInstr(dst));
-
-  return target;
-}
-
-
-IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto(
-    JoinEntryInstr* dst) {
-  IndirectEntryInstr* target = new(Z) IndirectEntryInstr(
-          block_id_.Alloc(), indirect_id_.Alloc(), kInvalidTryIndex);
-  blocks_.Add(target);
-
-  target->AppendInstruction(new(Z) GotoInstr(dst));
-
-  return target;
-}
-
-
-void IRRegExpMacroAssembler::CheckPreemption() {
-  TAG();
-  AppendInstruction(new(Z) CheckStackOverflowInstr(kNoSourcePos, 0));
-}
-
-
-Definition* IRRegExpMacroAssembler::Add(
-    PushArgumentInstr* lhs,
-    PushArgumentInstr* rhs) {
-  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs);
-}
-
-
-Definition* IRRegExpMacroAssembler::Sub(
-    PushArgumentInstr* lhs,
-    PushArgumentInstr* rhs) {
-  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kSUB), lhs, rhs);
-}
-
-
-void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked(
-    intptr_t cp_offset, intptr_t characters) {
-  TAG();
-
-  ASSERT(characters == 1 || CanReadUnaligned());
-  if (mode_ == ASCII) {
-    ASSERT(characters == 1 || characters == 2 || characters == 4);
-  } else {
-    ASSERT(mode_ == UC16);
-    ASSERT(characters == 1 || characters == 2);
-  }
-
-  // Calculate the addressed string index as:
-  //    cp_offset + current_position_ + string_param_length_
-  // TODO(zerny): Avoid generating 'add' instance-calls here.
-  PushArgumentInstr* off_arg =
-      PushArgument(Bind(Int64Constant(cp_offset)));
-  PushArgumentInstr* pos_arg =
-      PushArgument(BindLoadLocal(*current_position_));
-  PushArgumentInstr* off_pos_arg =
-      PushArgument(Bind(Add(off_arg, pos_arg)));
-  PushArgumentInstr* len_arg =
-      PushArgument(BindLoadLocal(*string_param_length_));
-  // Index is stored in a temporary local so that we can later load it safely.
-  StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg)));
-
-  // Load and store the code units.
-  Value* code_unit_value = LoadCodeUnitsAt(index_temp_, characters);
-  StoreLocal(current_character_, code_unit_value);
-  PRINT(PushLocal(current_character_));
-}
-
-
-Value* IRRegExpMacroAssembler::CharacterAt(LocalVariable* index) {
-  return LoadCodeUnitsAt(index, 1);
-}
-
-
-Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index,
-                                               intptr_t characters) {
-  // Bind the pattern as the load receiver.
-  Value* pattern_val = BindLoadLocal(*string_param_);
-  if (RawObject::IsExternalStringClassId(specialization_cid_)) {
-    // The data of an external string is stored through two indirections.
-    intptr_t external_offset = 0;
-    intptr_t data_offset = 0;
-    if (specialization_cid_ == kExternalOneByteStringCid) {
-      external_offset = ExternalOneByteString::external_data_offset();
-      data_offset = RawExternalOneByteString::ExternalData::data_offset();
-    } else if (specialization_cid_ == kExternalTwoByteStringCid) {
-      external_offset = ExternalTwoByteString::external_data_offset();
-      data_offset = RawExternalTwoByteString::ExternalData::data_offset();
-    } else {
-      UNREACHABLE();
-    }
-    // This pushes untagged values on the stack which are immediately consumed:
-    // the first value is consumed to obtain the second value which is consumed
-    // by LoadCodeUnitsAtInstr below.
-    Value* external_val =
-        Bind(new(Z) LoadUntaggedInstr(pattern_val, external_offset));
-    pattern_val =
-        Bind(new(Z) LoadUntaggedInstr(external_val, data_offset));
-  }
-
-  // Here pattern_val might be untagged so this must not trigger a GC.
-  Value* index_val = BindLoadLocal(*index);
-
-  return Bind(new(Z) LoadCodeUnitsInstr(
-      pattern_val,
-      index_val,
-      characters,
-      specialization_cid_,
-      Scanner::kNoSourcePos));
-}
-
-
-#undef __
-
 }  // namespace dart
diff --git a/runtime/vm/regexp_assembler.h b/runtime/vm/regexp_assembler.h
index 88aa06b..821f054 100644
--- a/runtime/vm/regexp_assembler.h
+++ b/runtime/vm/regexp_assembler.h
@@ -17,24 +17,13 @@
 
 /// Convenience wrapper around a BlockEntryInstr pointer.
 class BlockLabel : public ValueObject {
+  // Used by the IR assembler.
  public:
   BlockLabel()
     : block_(new JoinEntryInstr(-1, -1)),
       is_bound_(false),
-      is_linked_(false) { }
-
-  BlockLabel(const BlockLabel& that)
-    : ValueObject(),
-      block_(that.block_),
-      is_bound_(that.is_bound_),
-      is_linked_(that.is_linked_) { }
-
-  BlockLabel& operator=(const BlockLabel& that) {
-    block_ = that.block_;
-    is_bound_ = that.is_bound_;
-    is_linked_ = that.is_linked_;
-    return *this;
-  }
+      is_linked_(false),
+      pos_(-1) { }
 
   JoinEntryInstr* block() const { return block_; }
 
@@ -60,6 +49,41 @@
 
   bool is_bound_;
   bool is_linked_;
+
+  // Used by the bytecode assembler.
+ public:
+  ~BlockLabel() {
+    ASSERT(!is_linked());
+  }
+
+  intptr_t pos() const {
+    return pos_;
+  }
+  bool is_bound() const { return IsBound(); }
+  bool is_linked() const { return IsLinked(); }
+
+  void Unuse() {
+    pos_ = 0;
+    is_bound_ = false;
+    is_linked_ = false;
+  }
+
+  void bind_to(intptr_t pos) {
+    pos_ = pos;
+    is_bound_ = true;
+    is_linked_ = false;
+    ASSERT(is_bound());
+  }
+
+  void link_to(intptr_t pos) {
+    pos_ = pos;
+    is_bound_ = false;
+    is_linked_ = true;
+    ASSERT(is_linked());
+  }
+
+ private:
+  intptr_t pos_;
 };
 
 
@@ -81,6 +105,7 @@
   };
 
   enum IrregexpImplementation {
+    kBytecodeImplementation,
     kIRImplementation
   };
 
@@ -217,433 +242,6 @@
   Zone* zone_;
 };
 
-
-class IRRegExpMacroAssembler : public RegExpMacroAssembler {
- public:
-  // Type of input string to generate code for.
-  enum Mode { ASCII = 1, UC16 = 2 };
-
-  // Result of calling generated native RegExp code.
-  // RETRY: Something significant changed during execution, and the matching
-  //        should be retried from scratch.
-  // EXCEPTION: Something failed during execution. If no exception has been
-  //        thrown, it's an internal out-of-memory, and the caller should
-  //        throw the exception.
-  // FAILURE: Matching failed.
-  // SUCCESS: Matching succeeded, and the output array has been filled with
-  //        capture positions.
-  enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
-
-  IRRegExpMacroAssembler(intptr_t specialization_cid,
-                         intptr_t capture_count,
-                         const ParsedFunction* parsed_function,
-                         const ZoneGrowableArray<const ICData*>& ic_data_array,
-                         Zone* zone);
-  virtual ~IRRegExpMacroAssembler();
-
-  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,
-                           Zone* zone);
-
-  virtual bool IsClosed() const { return (current_instruction_ == NULL); }
-
-  virtual intptr_t stack_limit_slack();
-  virtual void AdvanceCurrentPosition(intptr_t by);
-  virtual void AdvanceRegister(intptr_t reg, intptr_t by);
-  virtual void Backtrack();
-  virtual void BindBlock(BlockLabel* label);
-  virtual void CheckAtStart(BlockLabel* on_at_start);
-  virtual void CheckCharacter(uint32_t c, BlockLabel* on_equal);
-  virtual void CheckCharacterAfterAnd(uint32_t c,
-                                      uint32_t mask,
-                                      BlockLabel* on_equal);
-  virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater);
-  virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less);
-  // A "greedy loop" is a loop that is both greedy and with a simple
-  // body. It has a particularly simple implementation.
-  virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position);
-  virtual void CheckNotAtStart(BlockLabel* on_not_at_start);
-  virtual void CheckNotBackReference(intptr_t start_reg,
-                                     BlockLabel* on_no_match);
-  virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg,
-                                               BlockLabel* on_no_match);
-  virtual void CheckNotCharacter(uint32_t c, BlockLabel* on_not_equal);
-  virtual void CheckNotCharacterAfterAnd(uint32_t c,
-                                         uint32_t mask,
-                                         BlockLabel* on_not_equal);
-  virtual void CheckNotCharacterAfterMinusAnd(uint16_t c,
-                                              uint16_t minus,
-                                              uint16_t mask,
-                                              BlockLabel* on_not_equal);
-  virtual void CheckCharacterInRange(uint16_t from,
-                                     uint16_t to,
-                                     BlockLabel* on_in_range);
-  virtual void CheckCharacterNotInRange(uint16_t from,
-                                        uint16_t to,
-                                        BlockLabel* on_not_in_range);
-  virtual void CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set);
-
-  // Checks whether the given offset from the current position is before
-  // the end of the string.
-  virtual void CheckPosition(intptr_t cp_offset, BlockLabel* on_outside_input);
-  virtual bool CheckSpecialCharacterClass(
-      uint16_t type, BlockLabel* on_no_match);
-  virtual void Fail();
-  virtual void IfRegisterGE(intptr_t reg,
-                            intptr_t comparand, BlockLabel* if_ge);
-  virtual void IfRegisterLT(intptr_t reg,
-                            intptr_t comparand, BlockLabel* if_lt);
-  virtual void IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq);
-  virtual IrregexpImplementation Implementation();
-  virtual void GoTo(BlockLabel* to);
-  virtual void LoadCurrentCharacter(intptr_t cp_offset,
-                                    BlockLabel* on_end_of_input,
-                                    bool check_bounds = true,
-                                    intptr_t characters = 1);
-  virtual void PopCurrentPosition();
-  virtual void PopRegister(intptr_t register_index);
-  virtual void Print(const char* str);
-  virtual void PushBacktrack(BlockLabel* label);
-  virtual void PushCurrentPosition();
-  virtual void PushRegister(intptr_t register_index);
-  virtual void ReadCurrentPositionFromRegister(intptr_t reg);
-  virtual void ReadStackPointerFromRegister(intptr_t reg);
-  virtual void SetCurrentPositionFromEnd(intptr_t by);
-  virtual void SetRegister(intptr_t register_index, intptr_t to);
-  virtual bool Succeed();
-  virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset);
-  virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to);
-  virtual void WriteStackPointerToRegister(intptr_t reg);
-
-  virtual void PrintBlocks();
-
-  IndirectGotoInstr* backtrack_goto() const { return backtrack_goto_; }
-  GraphEntryInstr* graph_entry() const { return entry_block_; }
-
-  intptr_t num_stack_locals() const { return local_id_.Count(); }
-  intptr_t num_blocks() const { return block_id_.Count(); }
-
-  // Generate a dispatch block implementing backtracking. Must be done after
-  // graph construction.
-  void GenerateBacktrackBlock();
-
-  // Allocate the actual registers array once its size is known. Must be done
-  // after graph construction.
-  void FinalizeRegistersArray();
-
- private:
-  // Generate the contents of preset blocks. The entry block is the entry point
-  // of the generated code.
-  void GenerateEntryBlock();
-  // Copies capture indices into the result area and returns true.
-  void GenerateSuccessBlock();
-  // Returns false.
-  void GenerateExitBlock();
-
-  enum ComparisonKind {
-    kEQ,
-    kNE,
-    kLT,
-    kGT,
-    kLTE,
-    kGTE,
-  };
-
-  struct InstanceCallDescriptor {
-    // Standard (i.e. most non-Smi) functions.
-    explicit InstanceCallDescriptor(const String& name)
-      : name(name),
-        token_kind(Token::kILLEGAL),
-        checked_argument_count(1) { }
-
-    InstanceCallDescriptor(const String& name,
-                           Token::Kind token_kind,
-                           intptr_t checked_argument_count)
-      : name(name),
-        token_kind(token_kind),
-        checked_argument_count(checked_argument_count) { }
-
-    // Special cases for Smi and indexing functions.
-    static InstanceCallDescriptor FromToken(Token::Kind token_kind) {
-      switch (token_kind) {
-        case Token::kEQ: return InstanceCallDescriptor(
-                  Symbols::EqualOperator(), token_kind, 2);
-        case Token::kADD: return InstanceCallDescriptor(
-                Symbols::Plus(), token_kind, 2);
-        case Token::kSUB: return InstanceCallDescriptor(
-                Symbols::Minus(), token_kind, 2);
-        case Token::kBIT_OR: return InstanceCallDescriptor(
-                Symbols::BitOr(), token_kind, 2);
-        case Token::kBIT_AND: return InstanceCallDescriptor(
-                Symbols::BitAnd(), token_kind, 2);
-        case Token::kLT: return InstanceCallDescriptor(
-                Symbols::LAngleBracket(), token_kind, 2);
-        case Token::kLTE: return InstanceCallDescriptor(
-                Symbols::LessEqualOperator(), token_kind, 2);
-        case Token::kGT: return InstanceCallDescriptor(
-                Symbols::RAngleBracket(), token_kind, 2);
-        case Token::kGTE: return InstanceCallDescriptor(
-                Symbols::GreaterEqualOperator(), token_kind, 2);
-        case Token::kNEGATE: return InstanceCallDescriptor(
-                Symbols::UnaryMinus(), token_kind, 1);
-        case Token::kINDEX: return InstanceCallDescriptor(
-                Symbols::IndexToken(), token_kind, 2);
-        case Token::kASSIGN_INDEX: return InstanceCallDescriptor(
-                Symbols::AssignIndexToken(), token_kind, 2);
-        default:
-          UNREACHABLE();
-      }
-      UNREACHABLE();
-      return InstanceCallDescriptor(Symbols::Empty());
-    }
-
-    const String& name;
-    Token::Kind token_kind;
-    intptr_t checked_argument_count;
-  };
-
-  LocalVariable* Local(const String& name);
-  LocalVariable* Parameter(const String& name, intptr_t index) const;
-
-  ConstantInstr* Int64Constant(int64_t value) const;
-  ConstantInstr* Uint64Constant(uint64_t value) const;
-  ConstantInstr* BoolConstant(bool value) const;
-  ConstantInstr* StringConstant(const char* value) const;
-
-  // The word character map static member of the RegExp class.
-  // Byte map of one byte characters with a 0xff if the character is a word
-  // character (digit, letter or underscore) and 0x00 otherwise.
-  // Used by generated RegExp code.
-  ConstantInstr* WordCharacterMapConstant() const;
-
-  ComparisonInstr* Comparison(ComparisonKind kind,
-                              PushArgumentInstr* lhs,
-                              PushArgumentInstr* rhs);
-  ComparisonInstr* Comparison(ComparisonKind kind,
-                              Definition* lhs,
-                              Definition* rhs);
-
-  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
-                                  PushArgumentInstr* arg1) const;
-  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
-                                  PushArgumentInstr* arg1,
-                                  PushArgumentInstr* arg2) const;
-  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
-                                  PushArgumentInstr* arg1,
-                                  PushArgumentInstr* arg2,
-                                  PushArgumentInstr* arg3) const;
-  InstanceCallInstr* InstanceCall(
-      const InstanceCallDescriptor& desc,
-      ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
-
-  StaticCallInstr* StaticCall(const Function& function) const;
-  StaticCallInstr* StaticCall(const Function& function,
-                              PushArgumentInstr* arg1) const;
-  StaticCallInstr* StaticCall(const Function& function,
-                              PushArgumentInstr* arg1,
-                              PushArgumentInstr* arg2) const;
-  StaticCallInstr* StaticCall(
-      const Function& function,
-      ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
-
-  // Creates a new block consisting simply of a goto to dst.
-  TargetEntryInstr* TargetWithJoinGoto(JoinEntryInstr* dst);
-  IndirectEntryInstr* IndirectWithJoinGoto(JoinEntryInstr* dst);
-
-  // Adds, respectively subtracts lhs and rhs and returns the result.
-  Definition* Add(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
-  Definition* Sub(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
-
-  LoadLocalInstr* LoadLocal(LocalVariable* local) const;
-  void StoreLocal(LocalVariable* local, Value* value);
-
-  PushArgumentInstr* PushArgument(Value* value);
-  PushArgumentInstr* PushLocal(LocalVariable* local);
-
-  PushArgumentInstr* PushRegisterIndex(intptr_t reg);
-  Value* LoadRegister(intptr_t reg);
-  void StoreRegister(intptr_t reg, intptr_t value);
-  void StoreRegister(PushArgumentInstr* registers,
-                     PushArgumentInstr* index,
-                     PushArgumentInstr* value);
-
-  // Load a number of characters at the given offset from the
-  // current position, into the current-character register.
-  void LoadCurrentCharacterUnchecked(intptr_t cp_offset,
-                                     intptr_t character_count);
-
-  // Returns the character within the passed string at the specified index.
-  Value* CharacterAt(LocalVariable* index);
-
-  // Load a number of characters starting from index in the pattern string.
-  Value* LoadCodeUnitsAt(LocalVariable* index, intptr_t character_count);
-
-  // Check whether preemption has been requested.
-  void CheckPreemption();
-
-  // Byte size of chars in the string to match (decided by the Mode argument)
-  inline intptr_t char_size() { return static_cast<int>(mode_); }
-
-  // Equivalent to a conditional branch to the label, unless the label
-  // is NULL, in which case it is a conditional Backtrack.
-  void BranchOrBacktrack(ComparisonInstr* comparison,
-                         BlockLabel* true_successor);
-
-  // Set up all local variables and parameters.
-  void InitializeLocals();
-
-  // Allocates a new local, and returns the appropriate id for placing it
-  // on the stack.
-  intptr_t GetNextLocalIndex();
-
-  // We never have any copied parameters.
-  intptr_t num_copied_params() const {
-    return 0;
-  }
-
-  // Return the position register at the specified index, creating it if
-  // necessary. Note that the number of such registers can exceed the amount
-  // required by the number of output captures.
-  LocalVariable* position_register(intptr_t index);
-
-  void set_current_instruction(Instruction* instruction);
-
-  // The following functions are responsible for appending instructions
-  // to the current instruction in various ways. The most simple one
-  // is AppendInstruction, which simply appends an instruction and performs
-  // bookkeeping.
-  void AppendInstruction(Instruction* instruction);
-  // Similar to AppendInstruction, but closes the current block by
-  // setting current_instruction_ to NULL.
-  void CloseBlockWith(Instruction* instruction);
-  // Appends definition and allocates a temp index for the result.
-  Value* Bind(Definition* definition);
-  // Loads and binds a local variable.
-  Value* BindLoadLocal(const LocalVariable& local);
-
-  // Appends the definition.
-  void Do(Definition* definition);
-  // Closes the current block with a jump to the specified block.
-  void GoTo(JoinEntryInstr* to);
-
-  // Accessors for our local stack_.
-  void PushStack(Definition* definition);
-  Definition* PopStack();
-  Definition* PeekStack();
-  void CheckStackLimit();
-  void GrowStack();
-
-  // Prints the specified argument. Used for debugging.
-  void Print(PushArgumentInstr* argument);
-
-  // A utility class tracking ids of various objects such as blocks, temps, etc.
-  class IdAllocator : public ValueObject {
-   public:
-    IdAllocator() : next_id(0) { }
-
-    intptr_t Count() const { return next_id; }
-    intptr_t Alloc(intptr_t count = 1) {
-      ASSERT(count >= 0);
-      intptr_t current_id = next_id;
-      next_id += count;
-      return current_id;
-    }
-    void Dealloc(intptr_t count = 1) {
-      ASSERT(count <= next_id);
-      next_id -= count;
-    }
-
-   private:
-    intptr_t next_id;
-  };
-
-  // Which mode to generate code for (ASCII or UC16).
-  Mode mode_;
-
-  // Which specific string class to generate code for.
-  intptr_t specialization_cid_;
-
-  // Block entries used internally.
-  GraphEntryInstr* entry_block_;
-  JoinEntryInstr* start_block_;
-  JoinEntryInstr* success_block_;
-  JoinEntryInstr* exit_block_;
-
-  // Shared backtracking block.
-  JoinEntryInstr* backtrack_block_;
-  // Single indirect goto instruction which performs all backtracking.
-  IndirectGotoInstr* backtrack_goto_;
-
-  const ParsedFunction* parsed_function_;
-  const ZoneGrowableArray<const ICData*>& ic_data_array_;
-
-  // All created blocks are contained within this set. Used for printing
-  // the generated code.
-  GrowableArray<BlockEntryInstr*> blocks_;
-
-  // The current instruction to link to when new code is emitted.
-  Instruction* current_instruction_;
-
-  // A list, acting as the runtime stack for both backtrack locations and
-  // stored positions within the string.
-  LocalVariable* stack_;
-  LocalVariable* stack_pointer_;
-
-  // Stores the current character within the string.
-  LocalVariable* current_character_;
-
-  // Stores the current location within the string as a negative offset
-  // from the end of the string.
-  LocalVariable* current_position_;
-
-  // The string being processed, passed as a function parameter.
-  LocalVariable* string_param_;
-
-  // Stores the length of string_param_.
-  LocalVariable* string_param_length_;
-
-  // The start index within the string, passed as a function parameter.
-  LocalVariable* start_index_param_;
-
-  // An assortment of utility variables.
-  LocalVariable* capture_length_;
-  LocalVariable* match_start_index_;
-  LocalVariable* capture_start_index_;
-  LocalVariable* match_end_index_;
-  LocalVariable* char_in_capture_;
-  LocalVariable* char_in_match_;
-  LocalVariable* index_temp_;
-
-  LocalVariable* result_;
-
-  // Stored positions containing group bounds. Generated as needed.
-  LocalVariable* registers_;
-  intptr_t registers_count_;
-  const intptr_t saved_registers_count_;
-
-  // The actual array objects used for the stack and registers.
-  Array& stack_array_cell_;
-  TypedData& registers_array_;
-
-  IdAllocator block_id_;
-  IdAllocator temp_id_;
-  IdAllocator arg_id_;
-  IdAllocator local_id_;
-  IdAllocator indirect_id_;
-};
-
-
 }  // namespace dart
 
 #endif  // VM_REGEXP_ASSEMBLER_H_
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
new file mode 100644
index 0000000..193616c
--- /dev/null
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -0,0 +1,594 @@
+// 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.
+
+#include "vm/regexp_assembler_bytecode.h"
+
+#include "vm/regexp_assembler_bytecode_inl.h"
+#include "vm/exceptions.h"
+#include "vm/object_store.h"
+#include "vm/regexp_bytecodes.h"
+#include "vm/regexp_assembler.h"
+#include "vm/regexp.h"
+#include "vm/regexp_parser.h"
+#include "vm/regexp_interpreter.h"
+
+namespace dart {
+
+BytecodeRegExpMacroAssembler::BytecodeRegExpMacroAssembler(
+    ZoneGrowableArray<uint8_t>* buffer,
+    Zone* zone)
+    : RegExpMacroAssembler(zone),
+      buffer_(buffer),
+      pc_(0),
+      advance_current_end_(kInvalidPC) { }
+
+
+BytecodeRegExpMacroAssembler::~BytecodeRegExpMacroAssembler() {
+  if (backtrack_.is_linked()) backtrack_.Unuse();
+}
+
+
+BytecodeRegExpMacroAssembler::IrregexpImplementation
+BytecodeRegExpMacroAssembler::Implementation() {
+  return kBytecodeImplementation;
+}
+
+
+void BytecodeRegExpMacroAssembler::BindBlock(BlockLabel* l) {
+  advance_current_end_ = kInvalidPC;
+  ASSERT(!l->is_bound());
+  if (l->is_linked()) {
+    intptr_t pos = l->pos();
+    while (pos != 0) {
+      intptr_t fixup = pos;
+      pos = *reinterpret_cast<int32_t*>(buffer_->data() + fixup);
+      *reinterpret_cast<uint32_t*>(buffer_->data() + fixup) = pc_;
+    }
+  }
+  l->bind_to(pc_);
+}
+
+
+void BytecodeRegExpMacroAssembler::EmitOrLink(BlockLabel* l) {
+  if (l == NULL) l = &backtrack_;
+  if (l->is_bound()) {
+    Emit32(l->pos());
+  } else {
+    int pos = 0;
+    if (l->is_linked()) {
+      pos = l->pos();
+    }
+    l->link_to(pc_);
+    Emit32(pos);
+  }
+}
+
+
+void BytecodeRegExpMacroAssembler::PopRegister(intptr_t register_index) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_POP_REGISTER, register_index);
+}
+
+
+void BytecodeRegExpMacroAssembler::PushRegister(intptr_t register_index) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_PUSH_REGISTER, register_index);
+}
+
+
+void BytecodeRegExpMacroAssembler::WriteCurrentPositionToRegister(
+    intptr_t register_index, intptr_t cp_offset) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER_TO_CP, register_index);
+  Emit32(cp_offset);  // Current position offset.
+}
+
+
+void BytecodeRegExpMacroAssembler::ClearRegisters(intptr_t reg_from,
+                                                  intptr_t reg_to) {
+  ASSERT(reg_from <= reg_to);
+  for (int reg = reg_from; reg <= reg_to; reg++) {
+    SetRegister(reg, -1);
+  }
+}
+
+
+void BytecodeRegExpMacroAssembler::ReadCurrentPositionFromRegister(
+    intptr_t register_index) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_CP_TO_REGISTER, register_index);
+}
+
+
+void BytecodeRegExpMacroAssembler::WriteStackPointerToRegister(
+    intptr_t register_index) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER_TO_SP, register_index);
+}
+
+
+void BytecodeRegExpMacroAssembler::ReadStackPointerFromRegister(
+    intptr_t register_index) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_SP_TO_REGISTER, register_index);
+}
+
+
+void BytecodeRegExpMacroAssembler::SetCurrentPositionFromEnd(intptr_t by) {
+  ASSERT(Utils::IsUint(24, by));
+  Emit(BC_SET_CURRENT_POSITION_FROM_END, by);
+}
+
+
+void BytecodeRegExpMacroAssembler::SetRegister(intptr_t register_index,
+                                               intptr_t to) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_SET_REGISTER, register_index);
+  Emit32(to);
+}
+
+
+void BytecodeRegExpMacroAssembler::AdvanceRegister(intptr_t register_index,
+                                                   intptr_t by) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_ADVANCE_REGISTER, register_index);
+  Emit32(by);
+}
+
+
+void BytecodeRegExpMacroAssembler::PopCurrentPosition() {
+  Emit(BC_POP_CP, 0);
+}
+
+
+void BytecodeRegExpMacroAssembler::PushCurrentPosition() {
+  Emit(BC_PUSH_CP, 0);
+}
+
+
+void BytecodeRegExpMacroAssembler::Backtrack() {
+  Emit(BC_POP_BT, 0);
+}
+
+
+void BytecodeRegExpMacroAssembler::GoTo(BlockLabel* l) {
+  if (advance_current_end_ == pc_) {
+    // Combine advance current and goto.
+    pc_ = advance_current_start_;
+    Emit(BC_ADVANCE_CP_AND_GOTO, advance_current_offset_);
+    EmitOrLink(l);
+    advance_current_end_ = kInvalidPC;
+  } else {
+    // Regular goto.
+    Emit(BC_GOTO, 0);
+    EmitOrLink(l);
+  }
+}
+
+
+void BytecodeRegExpMacroAssembler::PushBacktrack(BlockLabel* l) {
+  Emit(BC_PUSH_BT, 0);
+  EmitOrLink(l);
+}
+
+
+bool BytecodeRegExpMacroAssembler::Succeed() {
+  Emit(BC_SUCCEED, 0);
+  return false;  // Restart matching for global regexp not supported.
+}
+
+
+void BytecodeRegExpMacroAssembler::Fail() {
+  Emit(BC_FAIL, 0);
+}
+
+
+void BytecodeRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) {
+  ASSERT(by >= kMinCPOffset);
+  ASSERT(by <= kMaxCPOffset);
+  advance_current_start_ = pc_;
+  advance_current_offset_ = by;
+  Emit(BC_ADVANCE_CP, by);
+  advance_current_end_ = pc_;
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckGreedyLoop(
+      BlockLabel* on_tos_equals_current_position) {
+  Emit(BC_CHECK_GREEDY, 0);
+  EmitOrLink(on_tos_equals_current_position);
+}
+
+
+void BytecodeRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset,
+                                                        BlockLabel* on_failure,
+                                                        bool check_bounds,
+                                                        intptr_t characters) {
+  ASSERT(cp_offset >= kMinCPOffset);
+  ASSERT(cp_offset <= kMaxCPOffset);
+  int bytecode;
+  if (check_bounds) {
+    if (characters == 4) {
+      bytecode = BC_LOAD_4_CURRENT_CHARS;
+    } else if (characters == 2) {
+      bytecode = BC_LOAD_2_CURRENT_CHARS;
+    } else {
+      ASSERT(characters == 1);
+      bytecode = BC_LOAD_CURRENT_CHAR;
+    }
+  } else {
+    if (characters == 4) {
+      bytecode = BC_LOAD_4_CURRENT_CHARS_UNCHECKED;
+    } else if (characters == 2) {
+      bytecode = BC_LOAD_2_CURRENT_CHARS_UNCHECKED;
+    } else {
+      ASSERT(characters == 1);
+      bytecode = BC_LOAD_CURRENT_CHAR_UNCHECKED;
+    }
+  }
+  Emit(bytecode, cp_offset);
+  if (check_bounds) EmitOrLink(on_failure);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacterLT(uint16_t limit,
+                                                    BlockLabel* on_less) {
+  Emit(BC_CHECK_LT, limit);
+  EmitOrLink(on_less);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacterGT(uint16_t limit,
+                                                    BlockLabel* on_greater) {
+  Emit(BC_CHECK_GT, limit);
+  EmitOrLink(on_greater);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacter(uint32_t c,
+                                                  BlockLabel* on_equal) {
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_CHECK_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_CHECK_CHAR, c);
+  }
+  EmitOrLink(on_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckAtStart(BlockLabel* on_at_start) {
+  Emit(BC_CHECK_AT_START, 0);
+  EmitOrLink(on_at_start);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotAtStart(
+    BlockLabel* on_not_at_start) {
+  Emit(BC_CHECK_NOT_AT_START, 0);
+  EmitOrLink(on_not_at_start);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotCharacter(uint32_t c,
+                                                     BlockLabel* on_not_equal) {
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_CHECK_NOT_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_CHECK_NOT_CHAR, c);
+  }
+  EmitOrLink(on_not_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacterAfterAnd(
+    uint32_t c,
+    uint32_t mask,
+    BlockLabel* on_equal) {
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_AND_CHECK_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_AND_CHECK_CHAR, c);
+  }
+  Emit32(mask);
+  EmitOrLink(on_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotCharacterAfterAnd(
+    uint32_t c,
+    uint32_t mask,
+    BlockLabel* on_not_equal) {
+  if (c > MAX_FIRST_ARG) {
+    Emit(BC_AND_CHECK_NOT_4_CHARS, 0);
+    Emit32(c);
+  } else {
+    Emit(BC_AND_CHECK_NOT_CHAR, c);
+  }
+  Emit32(mask);
+  EmitOrLink(on_not_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(
+    uint16_t c,
+    uint16_t minus,
+    uint16_t mask,
+    BlockLabel* on_not_equal) {
+  Emit(BC_MINUS_AND_CHECK_NOT_CHAR, c);
+  Emit16(minus);
+  Emit16(mask);
+  EmitOrLink(on_not_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacterInRange(
+    uint16_t from,
+    uint16_t to,
+    BlockLabel* on_in_range) {
+  Emit(BC_CHECK_CHAR_IN_RANGE, 0);
+  Emit16(from);
+  Emit16(to);
+  EmitOrLink(on_in_range);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckCharacterNotInRange(
+    uint16_t from,
+    uint16_t to,
+    BlockLabel* on_not_in_range) {
+  Emit(BC_CHECK_CHAR_NOT_IN_RANGE, 0);
+  Emit16(from);
+  Emit16(to);
+  EmitOrLink(on_not_in_range);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckBitInTable(
+    const TypedData& table, BlockLabel* on_bit_set) {
+  Emit(BC_CHECK_BIT_IN_TABLE, 0);
+  EmitOrLink(on_bit_set);
+  for (int i = 0; i < kTableSize; i += kBitsPerByte) {
+    int byte = 0;
+    for (int j = 0; j < kBitsPerByte; j++) {
+      if (table.GetUint8(i + j) != 0) byte |= 1 << j;
+    }
+    Emit8(byte);
+  }
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotBackReference(
+    intptr_t start_reg,
+    BlockLabel* on_not_equal) {
+  ASSERT(start_reg >= 0);
+  ASSERT(start_reg <= kMaxRegister);
+  Emit(BC_CHECK_NOT_BACK_REF, start_reg);
+  EmitOrLink(on_not_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(
+    intptr_t start_reg,
+    BlockLabel* on_not_equal) {
+  ASSERT(start_reg >= 0);
+  ASSERT(start_reg <= kMaxRegister);
+  Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg);
+  EmitOrLink(on_not_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::IfRegisterLT(intptr_t register_index,
+                                                intptr_t comparand,
+                                                BlockLabel* on_less_than) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_LT, register_index);
+  Emit32(comparand);
+  EmitOrLink(on_less_than);
+}
+
+
+void BytecodeRegExpMacroAssembler::IfRegisterGE(
+    intptr_t register_index,
+    intptr_t comparand,
+    BlockLabel* on_greater_or_equal) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_GE, register_index);
+  Emit32(comparand);
+  EmitOrLink(on_greater_or_equal);
+}
+
+
+void BytecodeRegExpMacroAssembler::IfRegisterEqPos(intptr_t register_index,
+                                                   BlockLabel* on_eq) {
+  ASSERT(register_index >= 0);
+  ASSERT(register_index <= kMaxRegister);
+  Emit(BC_CHECK_REGISTER_EQ_POS, register_index);
+  EmitOrLink(on_eq);
+}
+
+
+RawTypedData* BytecodeRegExpMacroAssembler::GetBytecode() {
+  BindBlock(&backtrack_);
+  Emit(BC_POP_BT, 0);
+
+  intptr_t len = length();
+  const TypedData& bytecode =
+      TypedData::Handle(TypedData::New(kTypedDataUint8ArrayCid, len));
+
+  NoSafepointScope no_safepoint;
+  memmove(bytecode.DataAddr(0), buffer_->data(), len);
+
+  return bytecode.raw();
+}
+
+
+intptr_t BytecodeRegExpMacroAssembler::length() {
+  return pc_;
+}
+
+
+void BytecodeRegExpMacroAssembler::Expand() {
+  // BOGUS
+  buffer_->Add(0);
+  buffer_->Add(0);
+  buffer_->Add(0);
+  buffer_->Add(0);
+  intptr_t x = buffer_->length();
+  for (intptr_t i = 0; i < x; i++) buffer_->Add(0);
+}
+
+
+static intptr_t Prepare(const JSRegExp& regexp,
+                        const String& subject,
+                        Zone* zone) {
+  bool is_one_byte = subject.IsOneByteString() ||
+                     subject.IsExternalOneByteString();
+
+  if (regexp.bytecode(is_one_byte) == TypedData::null()) {
+    const String& pattern = String::Handle(zone, regexp.pattern());
+
+    const bool multiline = regexp.is_multi_line();
+    RegExpCompileData* compile_data = new(zone) RegExpCompileData();
+    if (!RegExpParser::ParseRegExp(pattern, multiline, compile_data)) {
+      // Parsing failures are handled in the JSRegExp factory constructor.
+      UNREACHABLE();
+    }
+
+    regexp.set_num_bracket_expressions(compile_data->capture_count);
+    if (compile_data->simple) {
+      regexp.set_is_simple();
+    } else {
+      regexp.set_is_complex();
+    }
+
+    RegExpEngine::CompilationResult result =
+        RegExpEngine::CompileBytecode(compile_data, regexp, is_one_byte, zone);
+    ASSERT(result.bytecode != NULL);
+    ASSERT((regexp.num_registers() == -1) ||
+           (regexp.num_registers() == result.num_registers));
+    regexp.set_num_registers(result.num_registers);
+    regexp.set_bytecode(is_one_byte, *(result.bytecode));
+  }
+
+  ASSERT(regexp.num_registers() != -1);
+
+  return regexp.num_registers() +
+         (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2;
+}
+
+
+static IrregexpInterpreter::IrregexpResult ExecRaw(const JSRegExp& regexp,
+                                                   const String& subject,
+                                                   intptr_t index,
+                                                   int32_t* output,
+                                                   intptr_t output_size,
+                                                   Zone* zone) {
+  bool is_one_byte = subject.IsOneByteString() ||
+                     subject.IsExternalOneByteString();
+
+  ASSERT(regexp.num_bracket_expressions() != Smi::null());
+
+  // We must have done EnsureCompiledIrregexp, so we can get the number of
+  // registers.
+  int number_of_capture_registers =
+     (Smi::Value(regexp.num_bracket_expressions()) + 1) * 2;
+  int32_t* raw_output = &output[number_of_capture_registers];
+
+  // We do not touch the actual capture result registers until we know there
+  // has been a match so that we can use those capture results to set the
+  // last match info.
+  for (int i = number_of_capture_registers - 1; i >= 0; i--) {
+    raw_output[i] = -1;
+  }
+
+  const TypedData& bytecode =
+      TypedData::Handle(zone, regexp.bytecode(is_one_byte));
+  ASSERT(!bytecode.IsNull());
+  IrregexpInterpreter::IrregexpResult result =
+      IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone);
+
+  if (result == IrregexpInterpreter::RE_SUCCESS) {
+    // Copy capture results to the start of the registers array.
+    memmove(output, raw_output, number_of_capture_registers * sizeof(int32_t));
+  }
+  if (result == IrregexpInterpreter::RE_EXCEPTION) {
+    Thread* thread = Thread::Current();
+    Isolate* isolate = thread->isolate();
+    const Instance& exception =
+        Instance::Handle(isolate->object_store()->stack_overflow());
+    Exceptions::Throw(thread, exception);
+    UNREACHABLE();
+  }
+  return result;
+}
+
+
+RawInstance* BytecodeRegExpMacroAssembler::Interpret(const JSRegExp& regexp,
+                                                     const String& subject,
+                                                     const Smi& start_index,
+                                                     Zone* zone) {
+  intptr_t required_registers = Prepare(regexp, subject, zone);
+  if (required_registers < 0) {
+    // Compiling failed with an exception.
+    UNREACHABLE();
+  }
+
+  // V8 uses a shared copy on the isolate when smaller than some threshold.
+  int32_t* output_registers = zone->Alloc<int32_t>(required_registers);
+
+  IrregexpInterpreter::IrregexpResult result = ExecRaw(regexp,
+                                                       subject,
+                                                       start_index.Value(),
+                                                       output_registers,
+                                                       required_registers,
+                                                       zone);
+
+  if (result == IrregexpInterpreter::RE_SUCCESS) {
+    intptr_t capture_count = Smi::Value(regexp.num_bracket_expressions());
+    intptr_t capture_register_count = (capture_count + 1) * 2;
+    ASSERT(required_registers >= capture_register_count);
+
+    const TypedData& result =
+        TypedData::Handle(TypedData::New(kTypedDataInt32ArrayCid,
+                                         capture_register_count));
+    {
+#ifdef DEBUG
+      // These indices will be used with substring operations that don't check
+      // bounds, so sanity check them here.
+      for (intptr_t i = 0; i < capture_register_count; i++) {
+        int32_t val = output_registers[i];
+        ASSERT(val == -1 || (val >= 0 && val <= subject.Length()));
+      }
+#endif
+
+      NoSafepointScope no_safepoint;
+      memmove(result.DataAddr(0),
+              output_registers,
+              capture_register_count * sizeof(int32_t));
+    }
+
+    return result.raw();
+  }
+  if (result == IrregexpInterpreter::RE_EXCEPTION) {
+    UNREACHABLE();
+  }
+  ASSERT(result == IrregexpInterpreter::RE_FAILURE);
+  return Instance::null();
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/regexp_assembler_bytecode.h b/runtime/vm/regexp_assembler_bytecode.h
new file mode 100644
index 0000000..2de00d0
--- /dev/null
+++ b/runtime/vm/regexp_assembler_bytecode.h
@@ -0,0 +1,144 @@
+// 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.
+
+#ifndef VM_REGEXP_ASSEMBLER_BYTECODE_H_
+#define VM_REGEXP_ASSEMBLER_BYTECODE_H_
+
+#include "vm/object.h"
+#include "vm/regexp_assembler.h"
+
+namespace dart {
+
+class BytecodeRegExpMacroAssembler: public RegExpMacroAssembler {
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  BytecodeRegExpMacroAssembler(ZoneGrowableArray<uint8_t>* buffer,
+                               Zone* zone);
+  virtual ~BytecodeRegExpMacroAssembler();
+
+  // The byte-code interpreter checks on each push anyway.
+  virtual intptr_t stack_limit_slack() { return 1; }
+  virtual bool CanReadUnaligned() { return false; }
+  virtual void BindBlock(BlockLabel* label);
+  virtual void AdvanceCurrentPosition(intptr_t by);  // Signed cp change.
+  virtual void PopCurrentPosition();
+  virtual void PushCurrentPosition();
+  virtual void Backtrack();
+  virtual void GoTo(BlockLabel* label);
+  virtual void PushBacktrack(BlockLabel* label);
+  virtual bool Succeed();
+  virtual void Fail();
+  virtual void PopRegister(intptr_t register_index);
+  virtual void PushRegister(intptr_t register_index);
+  virtual void AdvanceRegister(intptr_t reg, intptr_t by);  // r[reg] += by.
+  virtual void SetCurrentPositionFromEnd(intptr_t by);
+  virtual void SetRegister(intptr_t register_index, intptr_t to);
+  virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset);
+  virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to);
+  virtual void ReadCurrentPositionFromRegister(intptr_t reg);
+  virtual void WriteStackPointerToRegister(intptr_t reg);
+  virtual void ReadStackPointerFromRegister(intptr_t reg);
+  virtual void LoadCurrentCharacter(intptr_t cp_offset,
+                                    BlockLabel* on_end_of_input,
+                                    bool check_bounds = true,
+                                    intptr_t characters = 1);
+  virtual void CheckCharacter(unsigned c, BlockLabel* on_equal);
+  virtual void CheckCharacterAfterAnd(unsigned c,
+                                      unsigned mask,
+                                      BlockLabel* on_equal);
+  virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater);
+  virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less);
+  virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position);
+  virtual void CheckAtStart(BlockLabel* on_at_start);
+  virtual void CheckNotAtStart(BlockLabel* on_not_at_start);
+  virtual void CheckNotCharacter(unsigned c, BlockLabel* on_not_equal);
+  virtual void CheckNotCharacterAfterAnd(unsigned c,
+                                         unsigned mask,
+                                         BlockLabel* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusAnd(uint16_t c,
+                                              uint16_t minus,
+                                              uint16_t mask,
+                                              BlockLabel* on_not_equal);
+  virtual void CheckCharacterInRange(uint16_t from,
+                                     uint16_t to,
+                                     BlockLabel* on_in_range);
+  virtual void CheckCharacterNotInRange(uint16_t from,
+                                        uint16_t to,
+                                        BlockLabel* on_not_in_range);
+  virtual void CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set);
+  virtual void CheckNotBackReference(intptr_t start_reg,
+                                     BlockLabel* on_no_match);
+  virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg,
+                                               BlockLabel* on_no_match);
+  virtual void IfRegisterLT(intptr_t register_index,
+                            intptr_t comparand,
+                            BlockLabel* if_lt);
+  virtual void IfRegisterGE(intptr_t register_index,
+                            intptr_t comparand,
+                            BlockLabel* if_ge);
+  virtual void IfRegisterEqPos(intptr_t register_index, BlockLabel* if_eq);
+
+  virtual IrregexpImplementation Implementation();
+  // virtual Handle<HeapObject> GetCode(Handle<String> source);
+  RawTypedData* GetBytecode();
+
+  // New
+  virtual bool IsClosed() const {
+    // Added by Dart for the IR version. Bytecode version should never need an
+    // extra goto.
+    return true;
+  }
+  virtual void Print(const char* str)  { UNIMPLEMENTED(); }
+  virtual void PrintBlocks() { UNIMPLEMENTED(); }
+  /////
+
+  static RawInstance* Interpret(const JSRegExp& regexp,
+                                const String& str,
+                                const Smi& start_index,
+                                Zone* zone);
+
+ private:
+  void Expand();
+  // Code and bitmap emission.
+  inline void EmitOrLink(BlockLabel* label);
+  inline void Emit32(uint32_t x);
+  inline void Emit16(uint32_t x);
+  inline void Emit8(uint32_t x);
+  inline void Emit(uint32_t bc, uint32_t arg);
+  // Bytecode buffer.
+  intptr_t length();
+
+  // The buffer into which code and relocation info are generated.
+  ZoneGrowableArray<uint8_t>* buffer_;
+
+  // The program counter.
+  intptr_t pc_;
+
+  BlockLabel backtrack_;
+
+  intptr_t advance_current_start_;
+  intptr_t advance_current_offset_;
+  intptr_t advance_current_end_;
+
+  static const int kInvalidPC = -1;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeRegExpMacroAssembler);
+};
+
+
+}  // namespace dart
+
+#endif  // VM_REGEXP_ASSEMBLER_BYTECODE_H_
diff --git a/runtime/vm/regexp_assembler_bytecode_inl.h b/runtime/vm/regexp_assembler_bytecode_inl.h
new file mode 100644
index 0000000..2b370db
--- /dev/null
+++ b/runtime/vm/regexp_assembler_bytecode_inl.h
@@ -0,0 +1,57 @@
+// 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.
+
+// A light-weight assembler for the Irregexp byte code.
+
+#include "vm/regexp_bytecodes.h"
+
+#ifndef VM_REGEXP_ASSEMBLER_BYTECODE_INL_H_
+#define VM_REGEXP_ASSEMBLER_BYTECODE_INL_H_
+
+namespace dart {
+
+void BytecodeRegExpMacroAssembler::Emit(uint32_t byte,
+                                        uint32_t twenty_four_bits) {
+  uint32_t word = ((twenty_four_bits << BYTECODE_SHIFT) | byte);
+  ASSERT(pc_ <= buffer_->length());
+  if (pc_  + 3 >= buffer_->length()) {
+    Expand();
+  }
+  *reinterpret_cast<uint32_t*>(buffer_->data() + pc_) = word;
+  pc_ += 4;
+}
+
+
+void BytecodeRegExpMacroAssembler::Emit16(uint32_t word) {
+  ASSERT(pc_ <= buffer_->length());
+  if (pc_ + 1 >= buffer_->length()) {
+    Expand();
+  }
+  *reinterpret_cast<uint16_t*>(buffer_->data() + pc_) = word;
+  pc_ += 2;
+}
+
+
+void BytecodeRegExpMacroAssembler::Emit8(uint32_t word) {
+  ASSERT(pc_ <= buffer_->length());
+  if (pc_ == buffer_->length()) {
+    Expand();
+  }
+  *reinterpret_cast<unsigned char*>(buffer_->data() + pc_) = word;
+  pc_ += 1;
+}
+
+
+void BytecodeRegExpMacroAssembler::Emit32(uint32_t word) {
+  ASSERT(pc_ <= buffer_->length());
+  if (pc_ + 3 >= buffer_->length()) {
+    Expand();
+  }
+  *reinterpret_cast<uint32_t*>(buffer_->data() + pc_) = word;
+  pc_ += 4;
+}
+
+}  // namespace dart
+
+#endif  // VM_REGEXP_ASSEMBLER_BYTECODE_INL_H_
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
new file mode 100644
index 0000000..6851926
--- /dev/null
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -0,0 +1,1923 @@
+// 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.
+
+#include "vm/regexp_assembler_ir.h"
+
+#include "vm/bit_vector.h"
+#include "vm/compiler.h"
+#include "vm/dart_entry.h"
+#include "vm/flow_graph_builder.h"
+#include "vm/il_printer.h"
+#include "vm/object_store.h"
+#include "vm/regexp.h"
+#include "vm/resolver.h"
+#include "vm/stack_frame.h"
+#include "vm/unibrow-inl.h"
+#include "vm/unicode.h"
+
+#define Z zone()
+
+// Debugging output macros. TAG() is called at the head of each interesting
+// function and prints its name during execution if irregexp tracing is enabled.
+#define TAG() if (FLAG_trace_irregexp) { TAG_(); }
+#define TAG_() \
+  Print(PushArgument( \
+    Bind(new(Z) ConstantInstr(String::ZoneHandle(Z, String::Concat( \
+        String::Handle(String::New("TAG: ")), \
+        String::Handle(String::New(__FUNCTION__)), Heap::kOld))))));
+
+#define PRINT(arg) if (FLAG_trace_irregexp) { Print(arg); }
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_irregexp, false, "Trace irregexps");
+
+
+static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex;
+static const intptr_t kNoSourcePos = Scanner::kNoSourcePos;
+static const intptr_t kMinStackSize = 512;
+
+
+void PrintUtf16(uint16_t c) {
+  const char* format = (0x20 <= c && c <= 0x7F) ?
+        "%c" : (c <= 0xff) ? "\\x%02x" : "\\u%04x";
+  OS::Print(format, c);
+}
+
+
+/*
+ * This assembler uses the following main local variables:
+ * - stack_: A pointer to a growable list which we use as an all-purpose stack
+ *           storing backtracking offsets, positions & stored register values.
+ * - current_character_: Stores the currently loaded characters (possibly more
+ *                       than one).
+ * - current_position_: The current position within the string, stored as a
+ *                      negative offset from the end of the string (i.e. the
+ *                      position corresponding to str[0] is -str.length).
+ *                      Note that current_position_ is *not* byte-based, unlike
+ *                      original V8 code.
+ *
+ * Results are returned though an array of capture indices, stored at
+ * matches_param_. A null array specifies a failure to match. The match indices
+ * [start_inclusive, end_exclusive] for capture group i are stored at positions
+ * matches_param_[i * 2] and matches_param_[i * 2 + 1], respectively. Match
+ * indices of -1 denote non-matched groups. Note that we store these indices
+ * as a negative offset from the end of the string in registers_array_
+ * during processing, and convert them to standard indexes when copying them
+ * to matches_param_ on successful match.
+ */
+IRRegExpMacroAssembler::IRRegExpMacroAssembler(
+    intptr_t specialization_cid,
+    intptr_t capture_count,
+    const ParsedFunction* parsed_function,
+    const ZoneGrowableArray<const ICData*>& ic_data_array,
+    Zone* zone)
+    : RegExpMacroAssembler(zone),
+      specialization_cid_(specialization_cid),
+      parsed_function_(parsed_function),
+      ic_data_array_(ic_data_array),
+      current_instruction_(NULL),
+      stack_(NULL),
+      stack_pointer_(NULL),
+      current_character_(NULL),
+      current_position_(NULL),
+      string_param_(NULL),
+      string_param_length_(NULL),
+      start_index_param_(NULL),
+      registers_count_(0),
+      saved_registers_count_((capture_count + 1) * 2),
+      stack_array_cell_(Array::ZoneHandle(zone, Array::New(1, Heap::kOld))),
+      // The registers array is allocated at a fixed size after assembly.
+      registers_array_(TypedData::ZoneHandle(zone, TypedData::null())) {
+  switch (specialization_cid) {
+    case kOneByteStringCid:
+    case kExternalOneByteStringCid: mode_ = ASCII; break;
+    case kTwoByteStringCid:
+    case kExternalTwoByteStringCid: mode_ = UC16; break;
+    default: UNREACHABLE();
+  }
+
+  InitializeLocals();
+
+  // Allocate an initial stack backing of the minimum stack size. The stack
+  // backing is indirectly referred to so we can reuse it on subsequent matches
+  // even in the case where the backing has been enlarged and thus reallocated.
+  stack_array_cell_.SetAt(0, TypedData::Handle(zone,
+    TypedData::New(kTypedDataInt32ArrayCid, kMinStackSize / 4, Heap::kOld)));
+
+  // Create and generate all preset blocks.
+  entry_block_ =
+      new(zone) GraphEntryInstr(
+        *parsed_function_,
+        new(zone) TargetEntryInstr(block_id_.Alloc(), kInvalidTryIndex),
+        Isolate::kNoDeoptId);
+  start_block_ =
+      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
+  success_block_ =
+      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
+  backtrack_block_ =
+      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
+  exit_block_ =
+      new(zone) JoinEntryInstr(block_id_.Alloc(), kInvalidTryIndex);
+
+  GenerateEntryBlock();
+  GenerateSuccessBlock();
+  GenerateExitBlock();
+
+  blocks_.Add(entry_block_);
+  blocks_.Add(entry_block_->normal_entry());
+  blocks_.Add(start_block_);
+  blocks_.Add(success_block_);
+  blocks_.Add(backtrack_block_);
+  blocks_.Add(exit_block_);
+
+  // Begin emission at the start_block_.
+  set_current_instruction(start_block_);
+}
+
+
+IRRegExpMacroAssembler::~IRRegExpMacroAssembler() { }
+
+
+void IRRegExpMacroAssembler::InitializeLocals() {
+  // All generated functions are expected to have a current-context variable.
+  // This variable is unused in irregexp functions.
+  parsed_function_->current_context_var()->set_index(GetNextLocalIndex());
+
+  // Create local variables and parameters.
+  stack_ = Local(Symbols::stack());
+  stack_pointer_ = Local(Symbols::stack_pointer());
+  registers_ = Local(Symbols::position_registers());
+  current_character_ = Local(Symbols::current_character());
+  current_position_ = Local(Symbols::current_position());
+  string_param_length_ = Local(Symbols::string_param_length());
+  capture_length_ = Local(Symbols::capture_length());
+  match_start_index_ = Local(Symbols::match_start_index());
+  capture_start_index_ = Local(Symbols::capture_start_index());
+  match_end_index_ = Local(Symbols::match_end_index());
+  char_in_capture_ = Local(Symbols::char_in_capture());
+  char_in_match_ = Local(Symbols::char_in_match());
+  index_temp_ = Local(Symbols::index_temp());
+  result_ = Local(Symbols::result());
+
+  string_param_ = Parameter(Symbols::string_param(), 0);
+  start_index_param_ = Parameter(Symbols::start_index_param(), 1);
+}
+
+
+void IRRegExpMacroAssembler::GenerateEntryBlock() {
+  set_current_instruction(entry_block_->normal_entry());
+  TAG();
+
+  // Store string.length.
+  PushArgumentInstr* string_push = PushLocal(string_param_);
+
+  StoreLocal(
+      string_param_length_,
+      Bind(InstanceCall(
+          InstanceCallDescriptor(
+              String::ZoneHandle(Field::GetterSymbol(Symbols::Length()))),
+          string_push)));
+
+  // Store (start_index - string.length) as the current position (since it's a
+  // negative offset from the end of the string).
+  PushArgumentInstr* start_index_push = PushLocal(start_index_param_);
+  PushArgumentInstr* length_push = PushLocal(string_param_length_);
+
+  StoreLocal(current_position_, Bind(Sub(start_index_push, length_push)));
+
+  // Generate a local list variable to represent "registers" and
+  // initialize capture registers (others remain garbage).
+  StoreLocal(registers_, Bind(new(Z) ConstantInstr(registers_array_)));
+  ClearRegisters(0, saved_registers_count_ - 1);
+
+  // Generate a local list variable to represent the backtracking stack.
+  PushArgumentInstr* stack_cell_push =
+      PushArgument(Bind(new(Z) ConstantInstr(stack_array_cell_)));
+  StoreLocal(stack_, Bind(InstanceCall(
+      InstanceCallDescriptor::FromToken(Token::kINDEX),
+      stack_cell_push,
+      PushArgument(Bind(Uint64Constant(0))))));
+  StoreLocal(stack_pointer_, Bind(Int64Constant(-1)));
+
+  // Jump to the start block.
+  current_instruction_->Goto(start_block_);
+}
+
+
+void IRRegExpMacroAssembler::GenerateBacktrackBlock() {
+  set_current_instruction(backtrack_block_);
+  TAG();
+  CheckPreemption();
+
+  const intptr_t entries_count = entry_block_->indirect_entries().length();
+
+  TypedData& offsets = TypedData::ZoneHandle(Z,
+      TypedData::New(kTypedDataInt32ArrayCid, entries_count, Heap::kOld));
+
+  PushArgumentInstr* block_offsets_push =
+      PushArgument(Bind(new(Z) ConstantInstr(offsets)));
+  PushArgumentInstr* block_id_push = PushArgument(Bind(PopStack()));
+
+  Value* offset_value =
+      Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                        block_offsets_push,
+                        block_id_push));
+
+  backtrack_goto_ = new(Z) IndirectGotoInstr(&offsets, offset_value);
+  CloseBlockWith(backtrack_goto_);
+
+  // Add an edge from the "indirect" goto to each of the targets.
+  for (intptr_t j = 0; j < entries_count; j++) {
+    backtrack_goto_->AddSuccessor(
+        TargetWithJoinGoto(entry_block_->indirect_entries().At(j)));
+  }
+}
+
+
+void IRRegExpMacroAssembler::GenerateSuccessBlock() {
+  set_current_instruction(success_block_);
+  TAG();
+
+  Value* type = Bind(new(Z) ConstantInstr(
+      TypeArguments::ZoneHandle(Z, TypeArguments::null())));
+  Value* length = Bind(Uint64Constant(saved_registers_count_));
+  Value* array = Bind(new(Z) CreateArrayInstr(kNoSourcePos, type, length));
+  StoreLocal(result_, array);
+
+  // Store captured offsets in the `matches` parameter.
+  for (intptr_t i = 0; i < saved_registers_count_; i++) {
+    PushArgumentInstr* matches_push = PushLocal(result_);
+    PushArgumentInstr* index_push = PushArgument(Bind(Uint64Constant(i)));
+
+    // Convert negative offsets from the end of the string to string indices.
+    // TODO(zerny): use positive offsets from the get-go.
+    PushArgumentInstr* offset_push = PushArgument(LoadRegister(i));
+    PushArgumentInstr* len_push = PushLocal(string_param_length_);
+    PushArgumentInstr* value_push =
+        PushArgument(Bind(Add(offset_push, len_push)));
+
+    Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
+                    matches_push,
+                    index_push,
+                    value_push));
+  }
+
+  // Print the result if tracing.
+  PRINT(PushLocal(result_));
+
+  // Return true on success.
+  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
+}
+
+
+void IRRegExpMacroAssembler::GenerateExitBlock() {
+  set_current_instruction(exit_block_);
+  TAG();
+
+  // Return false on failure.
+  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
+}
+
+
+void IRRegExpMacroAssembler::FinalizeRegistersArray() {
+  ASSERT(registers_count_ >= saved_registers_count_);
+  registers_array_ =
+      TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld);
+}
+
+
+#if defined(TARGET_ARCH_ARM64) ||                                              \
+    defined(TARGET_ARCH_ARM) ||                                                \
+    defined(TARGET_ARCH_MIPS)
+// Disabling unaligned accesses forces the regexp engine to load characters one
+// by one instead of up to 4 at once, along with the associated performance hit.
+// TODO(zerny): Be less conservative about disabling unaligned accesses.
+// For instance, ARMv6 supports unaligned accesses. Once it is enabled here,
+// update LoadCodeUnitsInstr methods for the appropriate architectures.
+static const bool kEnableUnalignedAccesses = false;
+#else
+static const bool kEnableUnalignedAccesses = true;
+#endif
+bool IRRegExpMacroAssembler::CanReadUnaligned() {
+  return kEnableUnalignedAccesses && !slow_safe();
+}
+
+
+RawArray* IRRegExpMacroAssembler::Execute(
+    const Function& function,
+    const String& input,
+    const Smi& start_offset,
+    Zone* zone) {
+  // Create the argument list.
+  const Array& args = Array::Handle(Array::New(2));
+  args.SetAt(0, input);
+  args.SetAt(1, start_offset);
+
+  // And finally call the generated code.
+
+  const Object& retval =
+      Object::Handle(zone, DartEntry::InvokeFunction(function, args));
+  if (retval.IsError()) {
+    const Error& error = Error::Cast(retval);
+    OS::Print("%s\n", error.ToErrorCString());
+    // Should never happen.
+    UNREACHABLE();
+  }
+
+  if (retval.IsNull()) {
+    return Array::null();
+  }
+
+  ASSERT(retval.IsArray());
+  return Array::Cast(retval).raw();
+}
+
+
+RawBool* IRRegExpMacroAssembler::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);
+  const Smi& length = Smi::Handle(length_raw);
+
+  // TODO(zerny): Optimize as single instance. V8 has this as an
+  // isolate member.
+  unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
+
+  for (intptr_t i = 0; i < length.Value(); i++) {
+    int32_t c1 = str.CharAt(lhs_index.Value() + i);
+    int32_t c2 = str.CharAt(rhs_index.Value() + i);
+    if (c1 != c2) {
+      int32_t s1[1] = { c1 };
+      canonicalize.get(c1, '\0', s1);
+      if (s1[0] != c2) {
+        int32_t s2[1] = { c2 };
+        canonicalize.get(c2, '\0', s2);
+        if (s1[0] != s2[0]) {
+          return Bool::False().raw();
+        }
+      }
+    }
+  }
+  return Bool::True().raw();
+}
+
+
+LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
+                                                 intptr_t index) const {
+  const Type& local_type = Type::ZoneHandle(Z, Type::DynamicType());
+  LocalVariable* local =
+      new(Z) LocalVariable(kNoSourcePos, name, local_type);
+
+  intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index;
+  local->set_index(param_frame_index);
+
+  return local;
+}
+
+
+LocalVariable* IRRegExpMacroAssembler::Local(const String& name) {
+  const Type& local_type = Type::ZoneHandle(Z, Type::DynamicType());
+  LocalVariable* local =
+      new(Z) LocalVariable(kNoSourcePos, name, local_type);
+  local->set_index(GetNextLocalIndex());
+
+  return local;
+}
+
+
+ConstantInstr* IRRegExpMacroAssembler::Int64Constant(int64_t value) const {
+  return new(Z) ConstantInstr(
+        Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
+}
+
+
+ConstantInstr* IRRegExpMacroAssembler::Uint64Constant(uint64_t value) const {
+  return new(Z) ConstantInstr(
+        Integer::ZoneHandle(Z, Integer::NewFromUint64(value, Heap::kOld)));
+}
+
+
+ConstantInstr* IRRegExpMacroAssembler::BoolConstant(bool value) const {
+  return new(Z) ConstantInstr(value ? Bool::True() : Bool::False());
+}
+
+
+ConstantInstr* IRRegExpMacroAssembler::StringConstant(const char* value) const {
+  return new(Z) ConstantInstr(
+        String::ZoneHandle(Z, String::New(value, Heap::kOld)));
+}
+
+
+ConstantInstr* IRRegExpMacroAssembler::WordCharacterMapConstant() const {
+  const Library& lib = Library::Handle(Z, Library::CoreLibrary());
+  const Class& regexp_class = Class::Handle(Z,
+        lib.LookupClassAllowPrivate(Symbols::JSSyntaxRegExp()));
+  const Field& word_character_field = Field::ZoneHandle(Z,
+      regexp_class.LookupStaticField(Symbols::_wordCharacterMap()));
+  ASSERT(!word_character_field.IsNull());
+
+  if (word_character_field.IsUninitialized()) {
+    word_character_field.EvaluateInitializer();
+  }
+  ASSERT(!word_character_field.IsUninitialized());
+
+  return new(Z) ConstantInstr(
+        Instance::ZoneHandle(Z, word_character_field.value()));
+}
+
+
+ComparisonInstr* IRRegExpMacroAssembler::Comparison(
+    ComparisonKind kind, PushArgumentInstr* lhs, PushArgumentInstr* rhs) {
+  Token::Kind strict_comparison = Token::kEQ_STRICT;
+  Token::Kind intermediate_operator = Token::kILLEGAL;
+  switch (kind) {
+  case kEQ:
+    intermediate_operator = Token::kEQ;
+    break;
+  case kNE:
+    intermediate_operator = Token::kEQ;
+    strict_comparison = Token::kNE_STRICT;
+    break;
+  case kLT:
+    intermediate_operator = Token::kLT;
+    break;
+  case kGT:
+    intermediate_operator = Token::kGT;
+    break;
+  case kLTE:
+    intermediate_operator = Token::kLTE;
+    break;
+  case kGTE:
+    intermediate_operator = Token::kGTE;
+    break;
+  default:
+    UNREACHABLE();
+  }
+
+  ASSERT(intermediate_operator != Token::kILLEGAL);
+
+  Value* lhs_value =
+      Bind(InstanceCall(
+             InstanceCallDescriptor::FromToken(intermediate_operator),
+             lhs,
+             rhs));
+  Value* rhs_value = Bind(BoolConstant(true));
+
+  return new(Z) StrictCompareInstr(
+      kNoSourcePos, strict_comparison, lhs_value, rhs_value, true);
+}
+
+ComparisonInstr* IRRegExpMacroAssembler::Comparison(
+    ComparisonKind kind, Definition* lhs, Definition* rhs) {
+  PushArgumentInstr* lhs_push = PushArgument(Bind(lhs));
+  PushArgumentInstr* rhs_push = PushArgument(Bind(rhs));
+  return Comparison(kind, lhs_push, rhs_push);
+}
+
+
+StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
+    const Function& function) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(0);
+  return StaticCall(function, arguments);
+}
+
+
+StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
+    const Function& function,
+    PushArgumentInstr* arg1) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
+  arguments->Add(arg1);
+
+  return StaticCall(function, arguments);
+}
+
+
+StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
+    const Function& function,
+    PushArgumentInstr* arg1,
+    PushArgumentInstr* arg2) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+  arguments->Add(arg1);
+  arguments->Add(arg2);
+
+  return StaticCall(function, arguments);
+}
+
+
+StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
+    const Function& function,
+    ZoneGrowableArray<PushArgumentInstr*>* arguments) const {
+  return new(Z) StaticCallInstr(kNoSourcePos,
+                                function,
+                                Object::null_array(),
+                                arguments,
+                                ic_data_array_);
+}
+
+
+InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
+    const InstanceCallDescriptor& desc,
+    PushArgumentInstr* arg1) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
+  arguments->Add(arg1);
+
+  return InstanceCall(desc, arguments);
+}
+
+
+InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
+    const InstanceCallDescriptor& desc,
+    PushArgumentInstr* arg1,
+    PushArgumentInstr* arg2) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+  arguments->Add(arg1);
+  arguments->Add(arg2);
+
+  return InstanceCall(desc, arguments);
+}
+
+
+InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
+    const InstanceCallDescriptor& desc,
+    PushArgumentInstr* arg1,
+    PushArgumentInstr* arg2,
+    PushArgumentInstr* arg3) const {
+  ZoneGrowableArray<PushArgumentInstr*>* arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(3);
+  arguments->Add(arg1);
+  arguments->Add(arg2);
+  arguments->Add(arg3);
+
+  return InstanceCall(desc, arguments);
+}
+
+
+InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
+    const InstanceCallDescriptor& desc,
+    ZoneGrowableArray<PushArgumentInstr*> *arguments) const {
+  return
+    new(Z) InstanceCallInstr(kNoSourcePos,
+                             desc.name,
+                             desc.token_kind,
+                             arguments,
+                             Object::null_array(),
+                             desc.checked_argument_count,
+                             ic_data_array_);
+}
+
+
+LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const {
+  return new(Z) LoadLocalInstr(*local);
+}
+
+
+void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local,
+                                        Value* value) {
+  Do(new(Z) StoreLocalInstr(*local, value));
+}
+
+
+void IRRegExpMacroAssembler::set_current_instruction(Instruction* instruction) {
+  current_instruction_ = instruction;
+}
+
+
+Value* IRRegExpMacroAssembler::Bind(Definition* definition) {
+  AppendInstruction(definition);
+  definition->set_temp_index(temp_id_.Alloc());
+
+  return new(Z) Value(definition);
+}
+
+
+void IRRegExpMacroAssembler::Do(Definition* definition) {
+  AppendInstruction(definition);
+}
+
+
+Value* IRRegExpMacroAssembler::BindLoadLocal(const LocalVariable& local) {
+  if (local.IsConst()) {
+    return Bind(new(Z) ConstantInstr(*local.ConstValue()));
+  }
+  ASSERT(!local.is_captured());
+  return Bind(new(Z) LoadLocalInstr(local));
+}
+
+
+// In some cases, the V8 irregexp engine generates unreachable code by emitting
+// a jmp not followed by a bind. We cannot do the same, since it is impossible
+// to append to a block following a jmp. In such cases, assume that we are doing
+// the correct thing, but output a warning when tracing.
+#define HANDLE_DEAD_CODE_EMISSION() \
+  if (current_instruction_ == NULL) { \
+    if (FLAG_trace_irregexp) { \
+      OS::Print("WARNING: Attempting to append to a closed assembler. " \
+                "This could be either a bug or generation of dead code " \
+                "inherited from V8.\n"); \
+    } \
+    BlockLabel dummy; \
+    BindBlock(&dummy); \
+  }
+
+void IRRegExpMacroAssembler::AppendInstruction(Instruction* instruction) {
+  HANDLE_DEAD_CODE_EMISSION();
+
+  ASSERT(current_instruction_ != NULL);
+  ASSERT(current_instruction_->next() == NULL);
+
+  temp_id_.Dealloc(instruction->InputCount());
+  arg_id_.Dealloc(instruction->ArgumentCount());
+
+  current_instruction_->LinkTo(instruction);
+  set_current_instruction(instruction);
+}
+
+
+void IRRegExpMacroAssembler::CloseBlockWith(Instruction* instruction) {
+  HANDLE_DEAD_CODE_EMISSION();
+
+  ASSERT(current_instruction_ != NULL);
+  ASSERT(current_instruction_->next() == NULL);
+
+  temp_id_.Dealloc(instruction->InputCount());
+  arg_id_.Dealloc(instruction->ArgumentCount());
+
+  current_instruction_->LinkTo(instruction);
+  set_current_instruction(NULL);
+}
+
+
+void IRRegExpMacroAssembler::GoTo(BlockLabel* to) {
+  if (to == NULL) {
+    Backtrack();
+  } else {
+    to->SetLinked();
+    GoTo(to->block());
+  }
+}
+
+
+// Closes the current block with a goto, and unsets current_instruction_.
+// BindBlock() must be called before emission can continue.
+void IRRegExpMacroAssembler::GoTo(JoinEntryInstr* to) {
+  HANDLE_DEAD_CODE_EMISSION();
+
+  ASSERT(current_instruction_ != NULL);
+  ASSERT(current_instruction_->next() == NULL);
+  current_instruction_->Goto(to);
+  set_current_instruction(NULL);
+}
+
+
+PushArgumentInstr* IRRegExpMacroAssembler::PushArgument(Value* value) {
+  arg_id_.Alloc();
+  PushArgumentInstr* push = new(Z) PushArgumentInstr(value);
+  // Do *not* use Do() for push argument instructions.
+  AppendInstruction(push);
+  return push;
+}
+
+
+PushArgumentInstr* IRRegExpMacroAssembler::PushLocal(LocalVariable* local) {
+  return PushArgument(Bind(LoadLocal(local)));
+}
+
+
+void IRRegExpMacroAssembler::Print(const char* str) {
+  Print(PushArgument(
+    Bind(new(Z) ConstantInstr(
+           String::ZoneHandle(Z, String::New(str, Heap::kOld))))));
+}
+
+
+void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) {
+  const Library& lib = Library::Handle(Library::CoreLibrary());
+  const Function& print_fn = Function::ZoneHandle(
+        Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
+  Do(StaticCall(print_fn, argument));
+}
+
+
+void IRRegExpMacroAssembler::PrintBlocks() {
+  for (intptr_t i = 0; i < blocks_.length(); i++) {
+    FlowGraphPrinter::PrintBlock(blocks_[i], false);
+  }
+}
+
+
+intptr_t IRRegExpMacroAssembler::stack_limit_slack()  {
+  return 32;
+}
+
+
+void IRRegExpMacroAssembler::AdvanceCurrentPosition(intptr_t by) {
+  TAG();
+  if (by != 0) {
+    PushArgumentInstr* cur_pos_push = PushLocal(current_position_);
+    PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by)));
+
+    Value* new_pos_value = Bind(Add(cur_pos_push, by_push));
+    StoreLocal(current_position_, new_pos_value);
+  }
+}
+
+
+void IRRegExpMacroAssembler::AdvanceRegister(intptr_t reg, intptr_t by) {
+  TAG();
+  ASSERT(reg >= 0);
+  ASSERT(reg < registers_count_);
+
+  if (by != 0) {
+    PushArgumentInstr* registers_push = PushLocal(registers_);
+    PushArgumentInstr* index_push = PushRegisterIndex(reg);
+    PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
+    PushArgumentInstr* by_push = PushArgument(Bind(Int64Constant(by)));
+    PushArgumentInstr* value_push = PushArgument(Bind(Add(reg_push, by_push)));
+    StoreRegister(registers_push, index_push, value_push);
+  }
+}
+
+
+void IRRegExpMacroAssembler::Backtrack() {
+  TAG();
+  GoTo(backtrack_block_);
+}
+
+
+// A BindBlock is analogous to assigning a label to a basic block.
+// If the BlockLabel does not yet contain a block, it is created.
+// If there is a current instruction, append a goto to the bound block.
+void IRRegExpMacroAssembler::BindBlock(BlockLabel* label) {
+  ASSERT(!label->IsBound());
+  ASSERT(label->block()->next() == NULL);
+
+  label->SetBound(block_id_.Alloc());
+  blocks_.Add(label->block());
+
+  if (current_instruction_ != NULL) {
+    GoTo(label);
+  }
+  set_current_instruction(label->block());
+
+  // Print the id of the current block if tracing.
+  PRINT(PushArgument(Bind(Uint64Constant(label->block()->block_id()))));
+}
+
+
+intptr_t IRRegExpMacroAssembler::GetNextLocalIndex() {
+  intptr_t id = local_id_.Alloc();
+  return kFirstLocalSlotFromFp - id;
+}
+
+
+Value* IRRegExpMacroAssembler::LoadRegister(intptr_t index) {
+  PushArgumentInstr* registers_push = PushLocal(registers_);
+  PushArgumentInstr* index_push = PushRegisterIndex(index);
+  return Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                           registers_push,
+                           index_push));
+}
+
+void IRRegExpMacroAssembler::StoreRegister(intptr_t index, intptr_t value) {
+  PushArgumentInstr* registers_push = PushLocal(registers_);
+  PushArgumentInstr* index_push = PushRegisterIndex(index);
+  PushArgumentInstr* value_push = PushArgument(Bind(Uint64Constant(value)));
+  StoreRegister(registers_push, index_push, value_push);
+}
+
+
+void IRRegExpMacroAssembler::StoreRegister(PushArgumentInstr* registers,
+                                           PushArgumentInstr* index,
+                                           PushArgumentInstr* value) {
+  TAG();
+  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
+                  registers,
+                  index,
+                  value));
+}
+
+PushArgumentInstr* IRRegExpMacroAssembler::PushRegisterIndex(intptr_t index) {
+  if (registers_count_ <= index) {
+    registers_count_ = index + 1;
+  }
+  return PushArgument(Bind(Uint64Constant(index)));
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacter(uint32_t c, BlockLabel* on_equal) {
+  TAG();
+  Definition* cur_char_def = LoadLocal(current_character_);
+  Definition* char_def = Uint64Constant(c);
+
+  BranchOrBacktrack(Comparison(kEQ, cur_char_def, char_def), on_equal);
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacterGT(uint16_t limit,
+                                              BlockLabel* on_greater) {
+  TAG();
+  BranchOrBacktrack(Comparison(kGT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(limit)),
+                    on_greater);
+}
+
+
+void IRRegExpMacroAssembler::CheckAtStart(BlockLabel* on_at_start) {
+  TAG();
+
+  BlockLabel not_at_start;
+
+  // Did we start the match at the start of the string at all?
+  BranchOrBacktrack(Comparison(kNE,
+                               LoadLocal(start_index_param_),
+                               Uint64Constant(0)),
+                    &not_at_start);
+
+  // If we did, are we still at the start of the input, i.e. is
+  // (offset == string_length * -1)?
+  Definition* neg_len_def =
+      InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE),
+                   PushLocal(string_param_length_));
+  Definition* offset_def = LoadLocal(current_position_);
+  BranchOrBacktrack(Comparison(kEQ, neg_len_def, offset_def),
+                    on_at_start);
+
+  BindBlock(&not_at_start);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotAtStart(BlockLabel* on_not_at_start) {
+  TAG();
+
+  // Did we start the match at the start of the string at all?
+  BranchOrBacktrack(Comparison(kNE,
+                               LoadLocal(start_index_param_),
+                               Uint64Constant(0)),
+                    on_not_at_start);
+
+  // If we did, are we still at the start of the input, i.e. is
+  // (offset == string_length * -1)?
+  Definition* neg_len_def =
+      InstanceCall(InstanceCallDescriptor::FromToken(Token::kNEGATE),
+                   PushLocal(string_param_length_));
+  Definition* offset_def = LoadLocal(current_position_);
+  BranchOrBacktrack(Comparison(kNE, neg_len_def, offset_def),
+                    on_not_at_start);
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacterLT(uint16_t limit,
+                                              BlockLabel* on_less) {
+  TAG();
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(limit)),
+                    on_less);
+}
+
+
+void IRRegExpMacroAssembler::CheckGreedyLoop(BlockLabel* on_equal) {
+  TAG();
+
+  BlockLabel fallthrough;
+
+  Definition* head = PeekStack();
+  Definition* cur_pos_def = LoadLocal(current_position_);
+  BranchOrBacktrack(Comparison(kNE, head, cur_pos_def),
+                    &fallthrough);
+
+  // Pop, throwing away the value.
+  Do(PopStack());
+
+  BranchOrBacktrack(NULL, on_equal);
+
+  BindBlock(&fallthrough);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(
+    intptr_t start_reg,
+    BlockLabel* on_no_match) {
+  TAG();
+  ASSERT(start_reg + 1 <= registers_count_);
+
+  BlockLabel fallthrough;
+
+  PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1));
+  PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg));
+  StoreLocal(capture_length_, Bind(Sub(end_push, start_push)));
+
+  // The length of a capture should not be negative. This can only happen
+  // if the end of the capture is unrecorded, or at a point earlier than
+  // the start of the capture.
+  // BranchOrBacktrack(less, on_no_match);
+
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(capture_length_),
+                               Uint64Constant(0)),
+                    on_no_match);
+
+  // If length is zero, either the capture is empty or it is completely
+  // uncaptured. In either case succeed immediately.
+  BranchOrBacktrack(Comparison(kEQ,
+                               LoadLocal(capture_length_),
+                               Uint64Constant(0)),
+                    &fallthrough);
+
+
+  // Check that there are sufficient characters left in the input.
+  PushArgumentInstr* pos_push = PushLocal(current_position_);
+  PushArgumentInstr* len_push = PushLocal(capture_length_);
+  BranchOrBacktrack(
+        Comparison(kGT,
+                   InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD),
+                                pos_push,
+                                len_push),
+                   Uint64Constant(0)),
+        on_no_match);
+
+  pos_push = PushLocal(current_position_);
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(match_start_index_, Bind(Add(pos_push, len_push)));
+
+  pos_push = PushArgument(LoadRegister(start_reg));
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push)));
+
+  pos_push = PushLocal(match_start_index_);
+  len_push = PushLocal(capture_length_);
+  StoreLocal(match_end_index_, Bind(Add(pos_push, len_push)));
+
+  BlockLabel success;
+  if (mode_ == ASCII) {
+    BlockLabel loop_increment;
+    BlockLabel loop;
+    BindBlock(&loop);
+
+    StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
+    StoreLocal(char_in_match_, CharacterAt(match_start_index_));
+
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(char_in_capture_),
+                                 LoadLocal(char_in_match_)),
+                      &loop_increment);
+
+    // Mismatch, try case-insensitive match (converting letters to lower-case).
+    PushArgumentInstr* match_char_push = PushLocal(char_in_match_);
+    PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(0x20)));
+    StoreLocal(char_in_match_,
+               Bind(InstanceCall(
+                      InstanceCallDescriptor::FromToken(Token::kBIT_OR),
+                      match_char_push,
+                      mask_push)));
+
+    BlockLabel convert_capture;
+    BlockLabel on_not_in_range;
+    BranchOrBacktrack(Comparison(kLT,
+                                 LoadLocal(char_in_match_),
+                                 Uint64Constant('a')),
+                      &on_not_in_range);
+    BranchOrBacktrack(Comparison(kGT,
+                                 LoadLocal(char_in_match_),
+                                 Uint64Constant('z')),
+                      &on_not_in_range);
+    GoTo(&convert_capture);
+    BindBlock(&on_not_in_range);
+
+    // Latin-1: Check for values in range [224,254] but not 247.
+    BranchOrBacktrack(Comparison(kLT,
+                                 LoadLocal(char_in_match_),
+                                 Uint64Constant(224)),
+                      on_no_match);
+    BranchOrBacktrack(Comparison(kGT,
+                                 LoadLocal(char_in_match_),
+                                 Uint64Constant(254)),
+                      on_no_match);
+
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(char_in_match_),
+                                 Uint64Constant(247)),
+                      on_no_match);
+
+    // Also convert capture character.
+    BindBlock(&convert_capture);
+
+    PushArgumentInstr* capture_char_push = PushLocal(char_in_capture_);
+    mask_push = PushArgument(Bind(Uint64Constant(0x20)));
+    StoreLocal(char_in_capture_,
+               Bind(InstanceCall(
+                      InstanceCallDescriptor::FromToken(Token::kBIT_OR),
+                      capture_char_push,
+                      mask_push)));
+
+    BranchOrBacktrack(Comparison(kNE,
+                                 LoadLocal(char_in_match_),
+                                 LoadLocal(char_in_capture_)),
+                      on_no_match);
+
+    BindBlock(&loop_increment);
+
+    // Increment indexes into capture and match strings.
+    PushArgumentInstr* index_push = PushLocal(capture_start_index_);
+    PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1)));
+    StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push)));
+
+    index_push = PushLocal(match_start_index_);
+    inc_push = PushArgument(Bind(Uint64Constant(1)));
+    StoreLocal(match_start_index_, Bind(Add(index_push, inc_push)));
+
+    // Compare to end of match, and loop if not done.
+    BranchOrBacktrack(Comparison(kLT,
+                                 LoadLocal(match_start_index_),
+                                 LoadLocal(match_end_index_)),
+                      &loop);
+  } else {
+    ASSERT(mode_ == UC16);
+
+    Value* string_value = Bind(LoadLocal(string_param_));
+    Value* lhs_index_value = Bind(LoadLocal(match_start_index_));
+    Value* rhs_index_value = Bind(LoadLocal(capture_start_index_));
+    Value* length_value = Bind(LoadLocal(capture_length_));
+
+    Definition* is_match_def =
+        new(Z) CaseInsensitiveCompareUC16Instr(
+                            string_value,
+                            lhs_index_value,
+                            rhs_index_value,
+                            length_value,
+                            specialization_cid_);
+
+    BranchOrBacktrack(Comparison(kNE, is_match_def, BoolConstant(true)),
+                      on_no_match);
+  }
+
+  BindBlock(&success);
+
+  // Move current character position to position after match.
+  PushArgumentInstr* match_end_push = PushLocal(match_end_index_);
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(current_position_, Bind(Sub(match_end_push, len_push)));
+
+  BindBlock(&fallthrough);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotBackReference(
+    intptr_t start_reg,
+    BlockLabel* on_no_match) {
+  TAG();
+  ASSERT(start_reg + 1 <= registers_count_);
+
+  BlockLabel fallthrough;
+  BlockLabel success;
+
+  // Find length of back-referenced capture.
+  PushArgumentInstr* end_push = PushArgument(LoadRegister(start_reg + 1));
+  PushArgumentInstr* start_push = PushArgument(LoadRegister(start_reg));
+  StoreLocal(capture_length_, Bind(Sub(end_push, start_push)));
+
+  // Fail on partial or illegal capture (start of capture after end of capture).
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(capture_length_),
+                               Uint64Constant(0)),
+                    on_no_match);
+
+  // Succeed on empty capture (including no capture)
+  BranchOrBacktrack(Comparison(kEQ,
+                               LoadLocal(capture_length_),
+                               Uint64Constant(0)),
+                    &fallthrough);
+
+  // Check that there are sufficient characters left in the input.
+  PushArgumentInstr* pos_push = PushLocal(current_position_);
+  PushArgumentInstr* len_push = PushLocal(capture_length_);
+  BranchOrBacktrack(
+        Comparison(kGT,
+                   InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD),
+                                pos_push,
+                                len_push),
+                   Uint64Constant(0)),
+        on_no_match);
+
+  // Compute pointers to match string and capture string.
+  pos_push = PushLocal(current_position_);
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(match_start_index_, Bind(Add(pos_push, len_push)));
+
+  pos_push = PushArgument(LoadRegister(start_reg));
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(capture_start_index_, Bind(Add(pos_push, len_push)));
+
+  pos_push = PushLocal(match_start_index_);
+  len_push = PushLocal(capture_length_);
+  StoreLocal(match_end_index_, Bind(Add(pos_push, len_push)));
+
+  BlockLabel loop;
+  BindBlock(&loop);
+
+  StoreLocal(char_in_capture_, CharacterAt(capture_start_index_));
+  StoreLocal(char_in_match_, CharacterAt(match_start_index_));
+
+  BranchOrBacktrack(Comparison(kNE,
+                               LoadLocal(char_in_capture_),
+                               LoadLocal(char_in_match_)),
+                    on_no_match);
+
+  // Increment indexes into capture and match strings.
+  PushArgumentInstr* index_push = PushLocal(capture_start_index_);
+  PushArgumentInstr* inc_push = PushArgument(Bind(Uint64Constant(1)));
+  StoreLocal(capture_start_index_, Bind(Add(index_push, inc_push)));
+
+  index_push = PushLocal(match_start_index_);
+  inc_push = PushArgument(Bind(Uint64Constant(1)));
+  StoreLocal(match_start_index_, Bind(Add(index_push, inc_push)));
+
+  // Check if we have reached end of match area.
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(match_start_index_),
+                               LoadLocal(match_end_index_)),
+                    &loop);
+
+  BindBlock(&success);
+
+  // Move current character position to position after match.
+  PushArgumentInstr* match_end_push = PushLocal(match_end_index_);
+  len_push = PushLocal(string_param_length_);
+  StoreLocal(current_position_, Bind(Sub(match_end_push, len_push)));
+
+  BindBlock(&fallthrough);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotCharacter(uint32_t c,
+                                               BlockLabel* on_not_equal) {
+  TAG();
+  BranchOrBacktrack(Comparison(kNE,
+                               LoadLocal(current_character_),
+                               Uint64Constant(c)),
+                    on_not_equal);
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacterAfterAnd(uint32_t c,
+                                                    uint32_t mask,
+                                                    BlockLabel* on_equal) {
+  TAG();
+
+  Definition* actual_def = LoadLocal(current_character_);
+  Definition* expected_def = Uint64Constant(c);
+
+  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
+  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
+  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
+                            actual_push,
+                            mask_push);
+
+  BranchOrBacktrack(Comparison(kEQ, actual_def, expected_def), on_equal);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotCharacterAfterAnd(
+    uint32_t c,
+    uint32_t mask,
+    BlockLabel* on_not_equal) {
+  TAG();
+
+  Definition* actual_def = LoadLocal(current_character_);
+  Definition* expected_def = Uint64Constant(c);
+
+  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
+  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
+  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
+                            actual_push,
+                            mask_push);
+
+  BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal);
+}
+
+
+void IRRegExpMacroAssembler::CheckNotCharacterAfterMinusAnd(
+    uint16_t c,
+    uint16_t minus,
+    uint16_t mask,
+    BlockLabel* on_not_equal) {
+  TAG();
+  ASSERT(minus < Utf16::kMaxCodeUnit);  // NOLINT
+
+  Definition* actual_def = LoadLocal(current_character_);
+  Definition* expected_def = Uint64Constant(c);
+
+  PushArgumentInstr* actual_push = PushArgument(Bind(actual_def));
+  PushArgumentInstr* minus_push = PushArgument(Bind(Uint64Constant(minus)));
+
+  actual_push = PushArgument(Bind(Sub(actual_push, minus_push)));
+  PushArgumentInstr* mask_push = PushArgument(Bind(Uint64Constant(mask)));
+  actual_def = InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
+                            actual_push,
+                            mask_push);
+
+  BranchOrBacktrack(Comparison(kNE, actual_def, expected_def), on_not_equal);
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacterInRange(
+    uint16_t from,
+    uint16_t to,
+    BlockLabel* on_in_range) {
+  TAG();
+  ASSERT(from <= to);
+
+  // TODO(zerny): All range comparisons could be done cheaper with unsigned
+  // compares. This pattern repeats in various places.
+
+  BlockLabel on_not_in_range;
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(from)),
+                    &on_not_in_range);
+  BranchOrBacktrack(Comparison(kGT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(to)),
+                    &on_not_in_range);
+  BranchOrBacktrack(NULL, on_in_range);
+
+  BindBlock(&on_not_in_range);
+}
+
+
+void IRRegExpMacroAssembler::CheckCharacterNotInRange(
+    uint16_t from,
+    uint16_t to,
+    BlockLabel* on_not_in_range) {
+  TAG();
+  ASSERT(from <= to);
+
+  BranchOrBacktrack(Comparison(kLT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(from)),
+                    on_not_in_range);
+
+  BranchOrBacktrack(Comparison(kGT,
+                               LoadLocal(current_character_),
+                               Uint64Constant(to)),
+                    on_not_in_range);
+}
+
+
+void IRRegExpMacroAssembler::CheckBitInTable(
+    const TypedData& table,
+    BlockLabel* on_bit_set) {
+  TAG();
+
+  PushArgumentInstr* table_push =
+      PushArgument(Bind(new(Z) ConstantInstr(table)));
+  PushArgumentInstr* index_push = PushLocal(current_character_);
+
+  if (mode_ != ASCII || kTableMask != Symbols::kMaxOneCharCodeSymbol) {
+    PushArgumentInstr* mask_push =
+        PushArgument(Bind(Uint64Constant(kTableSize - 1)));
+    index_push = PushArgument(
+          Bind(InstanceCall(InstanceCallDescriptor::FromToken(Token::kBIT_AND),
+                            index_push,
+                            mask_push)));
+  }
+
+  Definition* byte_def =
+      InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                   table_push,
+                   index_push);
+  Definition* zero_def = Int64Constant(0);
+
+  BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_bit_set);
+}
+
+
+bool IRRegExpMacroAssembler::CheckSpecialCharacterClass(
+    uint16_t type,
+    BlockLabel* on_no_match) {
+  TAG();
+
+  // Range checks (c in min..max) are generally implemented by an unsigned
+  // (c - min) <= (max - min) check
+  switch (type) {
+  case 's':
+    // Match space-characters
+    if (mode_ == ASCII) {
+      // One byte space characters are '\t'..'\r', ' ' and \u00a0.
+      BlockLabel success;
+      // Space (' ').
+      BranchOrBacktrack(Comparison(kEQ,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(' ')),
+                        &success);
+      // Check range 0x09..0x0d.
+      CheckCharacterInRange('\t', '\r', &success);
+      // \u00a0 (NBSP).
+      BranchOrBacktrack(Comparison(kNE,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(0x00a0)),
+                        on_no_match);
+      BindBlock(&success);
+      return true;
+    }
+    return false;
+  case 'S':
+    // The emitted code for generic character classes is good enough.
+    return false;
+  case 'd':
+    // Match ASCII digits ('0'..'9')
+    CheckCharacterNotInRange('0', '9', on_no_match);
+    return true;
+  case 'D':
+    // Match non ASCII-digits
+    CheckCharacterInRange('0', '9', on_no_match);
+    return true;
+  case '.': {
+    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(current_character_),
+                                 Uint64Constant('\n')),
+                      on_no_match);
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(current_character_),
+                                 Uint64Constant('\r')),
+                      on_no_match);
+    if (mode_ == UC16) {
+      BranchOrBacktrack(Comparison(kEQ,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(0x2028)),
+                        on_no_match);
+      BranchOrBacktrack(Comparison(kEQ,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(0x2029)),
+                        on_no_match);
+    }
+    return true;
+  }
+  case 'w': {
+    if (mode_ != ASCII) {
+      // Table is 128 entries, so all ASCII characters can be tested.
+      BranchOrBacktrack(Comparison(kGT,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant('z')),
+                        on_no_match);
+    }
+
+    PushArgumentInstr* table_push =
+        PushArgument(Bind(WordCharacterMapConstant()));
+    PushArgumentInstr* index_push = PushLocal(current_character_);
+
+    Definition* byte_def =
+        InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                     table_push,
+                     index_push);
+    Definition* zero_def = Int64Constant(0);
+
+    BranchOrBacktrack(Comparison(kEQ, byte_def, zero_def), on_no_match);
+
+    return true;
+  }
+  case 'W': {
+    BlockLabel done;
+    if (mode_ != ASCII) {
+      // Table is 128 entries, so all ASCII characters can be tested.
+      BranchOrBacktrack(Comparison(kGT,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant('z')),
+                        &done);
+    }
+
+    // TODO(zerny): Refactor to use CheckBitInTable if possible.
+
+    PushArgumentInstr* table_push =
+        PushArgument(Bind(WordCharacterMapConstant()));
+    PushArgumentInstr* index_push = PushLocal(current_character_);
+
+    Definition* byte_def =
+        InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                     table_push,
+                     index_push);
+    Definition* zero_def = Int64Constant(0);
+
+    BranchOrBacktrack(Comparison(kNE, byte_def, zero_def), on_no_match);
+
+    if (mode_ != ASCII) {
+      BindBlock(&done);
+    }
+    return true;
+  }
+  // Non-standard classes (with no syntactic shorthand) used internally.
+  case '*':
+    // Match any character.
+    return true;
+  case 'n': {
+    // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 or 0x2029).
+    // The opposite of '.'.
+    BlockLabel success;
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(current_character_),
+                                 Uint64Constant('\n')),
+                      &success);
+    BranchOrBacktrack(Comparison(kEQ,
+                                 LoadLocal(current_character_),
+                                 Uint64Constant('\r')),
+                      &success);
+    if (mode_ == UC16) {
+      BranchOrBacktrack(Comparison(kEQ,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(0x2028)),
+                        &success);
+      BranchOrBacktrack(Comparison(kEQ,
+                                   LoadLocal(current_character_),
+                                   Uint64Constant(0x2029)),
+                        &success);
+    }
+    BranchOrBacktrack(NULL, on_no_match);
+    BindBlock(&success);
+    return true;
+  }
+  // No custom implementation (yet): s(uint16_t), S(uint16_t).
+  default:
+    return false;
+  }
+}
+
+
+void IRRegExpMacroAssembler::Fail() {
+  TAG();
+  ASSERT(FAILURE == 0);  // Return value for failure is zero.
+  if (!global()) {
+    UNREACHABLE();  // Dart regexps are always global.
+  }
+  GoTo(exit_block_);
+}
+
+
+void IRRegExpMacroAssembler::IfRegisterGE(intptr_t reg,
+                                          intptr_t comparand,
+                                          BlockLabel* if_ge) {
+  TAG();
+  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
+  PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand)));
+  BranchOrBacktrack(Comparison(kGTE, reg_push, pos), if_ge);
+}
+
+
+void IRRegExpMacroAssembler::IfRegisterLT(intptr_t reg,
+                                          intptr_t comparand,
+                                          BlockLabel* if_lt) {
+  TAG();
+  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
+  PushArgumentInstr* pos = PushArgument(Bind(Int64Constant(comparand)));
+  BranchOrBacktrack(Comparison(kLT, reg_push, pos), if_lt);
+}
+
+
+void IRRegExpMacroAssembler::IfRegisterEqPos(intptr_t reg,
+                                             BlockLabel* if_eq) {
+  TAG();
+  PushArgumentInstr* reg_push = PushArgument(LoadRegister(reg));
+  PushArgumentInstr* pos = PushArgument(Bind(LoadLocal(current_position_)));
+  BranchOrBacktrack(Comparison(kEQ, reg_push, pos), if_eq);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+    IRRegExpMacroAssembler::Implementation() {
+  return kIRImplementation;
+}
+
+
+void IRRegExpMacroAssembler::LoadCurrentCharacter(intptr_t cp_offset,
+                                                  BlockLabel* on_end_of_input,
+                                                  bool check_bounds,
+                                                  intptr_t characters) {
+  TAG();
+  ASSERT(cp_offset >= -1);      // ^ and \b can look behind one character.
+  ASSERT(cp_offset < (1<<30));  // Be sane! (And ensure negation works)
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
+  LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+
+void IRRegExpMacroAssembler::PopCurrentPosition() {
+  TAG();
+  StoreLocal(current_position_, Bind(PopStack()));
+}
+
+
+void IRRegExpMacroAssembler::PopRegister(intptr_t reg) {
+  TAG();
+  ASSERT(reg < registers_count_);
+  PushArgumentInstr* registers_push = PushLocal(registers_);
+  PushArgumentInstr* index_push = PushRegisterIndex(reg);
+  PushArgumentInstr* pop_push = PushArgument(Bind(PopStack()));
+  StoreRegister(registers_push, index_push, pop_push);
+}
+
+
+void IRRegExpMacroAssembler::PushStack(Definition *definition) {
+  PushArgumentInstr* stack_push = PushLocal(stack_);
+  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
+  StoreLocal(stack_pointer_,
+             Bind(Add(stack_pointer_push,
+                      PushArgument(Bind(Uint64Constant(1))))));
+  stack_pointer_push = PushLocal(stack_pointer_);
+  // TODO(zerny): bind value and push could break stack discipline.
+  PushArgumentInstr* value_push = PushArgument(Bind(definition));
+  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
+                  stack_push,
+                  stack_pointer_push,
+                  value_push));
+}
+
+
+Definition* IRRegExpMacroAssembler::PopStack() {
+  PushArgumentInstr* stack_push = PushLocal(stack_);
+  PushArgumentInstr* stack_pointer_push1 = PushLocal(stack_pointer_);
+  PushArgumentInstr* stack_pointer_push2 = PushLocal(stack_pointer_);
+  StoreLocal(stack_pointer_,
+             Bind(Sub(stack_pointer_push2,
+                      PushArgument(Bind(Uint64Constant(1))))));
+  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                      stack_push,
+                      stack_pointer_push1);
+}
+
+
+Definition* IRRegExpMacroAssembler::PeekStack() {
+  PushArgumentInstr* stack_push = PushLocal(stack_);
+  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
+  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kINDEX),
+                      stack_push,
+                      stack_pointer_push);
+}
+
+
+// Pushes the location corresponding to label to the backtracking stack.
+void IRRegExpMacroAssembler::PushBacktrack(BlockLabel* label) {
+  TAG();
+
+  // Ensure that targets of indirect jumps are never accessed through a
+  // normal control flow instructions by creating a new block for each backtrack
+  // target.
+  IndirectEntryInstr* indirect_target = IndirectWithJoinGoto(label->block());
+
+  // Add a fake edge from the graph entry for data flow analysis.
+  entry_block_->AddIndirectEntry(indirect_target);
+
+  ConstantInstr* offset = Uint64Constant(indirect_target->indirect_id());
+  PushStack(offset);
+  CheckStackLimit();
+}
+
+
+void IRRegExpMacroAssembler::PushCurrentPosition() {
+  TAG();
+  PushStack(LoadLocal(current_position_));
+}
+
+
+void IRRegExpMacroAssembler::PushRegister(intptr_t reg) {
+  TAG();
+  // TODO(zerny): Refactor PushStack so it can be reused here.
+  PushArgumentInstr* stack_push = PushLocal(stack_);
+  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
+  StoreLocal(stack_pointer_,
+             Bind(Add(stack_pointer_push,
+                      PushArgument(Bind(Uint64Constant(1))))));
+  stack_pointer_push = PushLocal(stack_pointer_);
+  // TODO(zerny): bind value and push could break stack discipline.
+  PushArgumentInstr* value_push = PushArgument(LoadRegister(reg));
+  Do(InstanceCall(InstanceCallDescriptor::FromToken(Token::kASSIGN_INDEX),
+                  stack_push,
+                  stack_pointer_push,
+                  value_push));
+  CheckStackLimit();
+}
+
+
+// Checks that (stack.capacity - stack_limit_slack) > stack_pointer.
+// This ensures that up to stack_limit_slack stack pushes can be
+// done without exhausting the stack space. If the check fails the
+// stack will be grown.
+void IRRegExpMacroAssembler::CheckStackLimit() {
+  TAG();
+  PushArgumentInstr* stack_push = PushLocal(stack_);
+  PushArgumentInstr* length_push = PushArgument(Bind(InstanceCall(
+      InstanceCallDescriptor(
+          String::ZoneHandle(Field::GetterSymbol(Symbols::Length()))),
+      stack_push)));
+  PushArgumentInstr* capacity_push = PushArgument(Bind(Sub(
+      length_push,
+      PushArgument(Bind(Uint64Constant(stack_limit_slack()))))));
+  PushArgumentInstr* stack_pointer_push = PushLocal(stack_pointer_);
+  BranchInstr* branch = new(Z) BranchInstr(
+      Comparison(kGT, capacity_push, stack_pointer_push));
+  CloseBlockWith(branch);
+
+  BlockLabel grow_stack;
+  BlockLabel fallthrough;
+  *branch->true_successor_address() =
+      TargetWithJoinGoto(fallthrough.block());
+  *branch->false_successor_address() =
+      TargetWithJoinGoto(grow_stack.block());
+
+  BindBlock(&grow_stack);
+  GrowStack();
+
+  BindBlock(&fallthrough);
+}
+
+
+void IRRegExpMacroAssembler::GrowStack() {
+  TAG();
+  Value* cell = Bind(new(Z) ConstantInstr(stack_array_cell_));
+  StoreLocal(stack_, Bind(new(Z) GrowRegExpStackInstr(cell)));
+}
+
+
+void IRRegExpMacroAssembler::ReadCurrentPositionFromRegister(intptr_t reg) {
+  TAG();
+  StoreLocal(current_position_, LoadRegister(reg));
+}
+
+// Resets the tip of the stack to the value stored in reg.
+void IRRegExpMacroAssembler::ReadStackPointerFromRegister(intptr_t reg) {
+  TAG();
+  ASSERT(reg < registers_count_);
+  StoreLocal(stack_pointer_, LoadRegister(reg));
+}
+
+void IRRegExpMacroAssembler::SetCurrentPositionFromEnd(intptr_t by)  {
+  TAG();
+
+  BlockLabel after_position;
+
+  Definition* cur_pos_def = LoadLocal(current_position_);
+  Definition* by_value_def = Int64Constant(-by);
+
+  BranchOrBacktrack(Comparison(kGTE, cur_pos_def, by_value_def),
+                    &after_position);
+
+  StoreLocal(current_position_, Bind(Int64Constant(-by)));
+
+  // On RegExp code entry (where this operation is used), the character before
+  // the current position is expected to be already loaded.
+  // We have advanced the position, so it's safe to read backwards.
+  LoadCurrentCharacterUnchecked(-1, 1);
+
+  BindBlock(&after_position);
+}
+
+
+void IRRegExpMacroAssembler::SetRegister(intptr_t reg, intptr_t to) {
+  TAG();
+  // Reserved for positions!
+  ASSERT(reg >= saved_registers_count_);
+  StoreRegister(reg, to);
+}
+
+
+bool IRRegExpMacroAssembler::Succeed() {
+  TAG();
+  GoTo(success_block_);
+  return global();
+}
+
+
+void IRRegExpMacroAssembler::WriteCurrentPositionToRegister(
+    intptr_t reg, intptr_t cp_offset) {
+  TAG();
+
+  PushArgumentInstr* registers_push = PushLocal(registers_);
+  PushArgumentInstr* index_push = PushRegisterIndex(reg);
+  PushArgumentInstr* pos_push = PushLocal(current_position_);
+  PushArgumentInstr* off_push = PushArgument(Bind(Int64Constant(cp_offset)));
+  PushArgumentInstr* neg_off_push = PushArgument(Bind(Add(pos_push, off_push)));
+  // Push the negative offset; these are converted to positive string positions
+  // within the success block.
+  StoreRegister(registers_push, index_push, neg_off_push);
+}
+
+
+void IRRegExpMacroAssembler::ClearRegisters(
+    intptr_t reg_from, intptr_t reg_to) {
+  TAG();
+
+  ASSERT(reg_from <= reg_to);
+
+  // In order to clear registers to a final result value of -1, set them to
+  // (-1 - string length), the offset of -1 from the end of the string.
+
+  for (intptr_t reg = reg_from; reg <= reg_to; reg++) {
+    PushArgumentInstr* registers_push = PushLocal(registers_);
+    PushArgumentInstr* index_push = PushRegisterIndex(reg);
+    PushArgumentInstr* minus_one_push =
+        PushArgument(Bind(Int64Constant(-1)));
+    PushArgumentInstr* length_push = PushLocal(string_param_length_);
+    PushArgumentInstr* value_push =
+        PushArgument(Bind(Sub(minus_one_push, length_push)));
+    StoreRegister(registers_push, index_push, value_push);
+  }
+}
+
+
+void IRRegExpMacroAssembler::WriteStackPointerToRegister(intptr_t reg) {
+  TAG();
+
+  PushArgumentInstr* registers_push = PushLocal(registers_);
+  PushArgumentInstr* index_push = PushRegisterIndex(reg);
+  PushArgumentInstr* tip_push = PushLocal(stack_pointer_);
+  StoreRegister(registers_push, index_push, tip_push);
+}
+
+
+// Private methods:
+
+
+void IRRegExpMacroAssembler::CheckPosition(intptr_t cp_offset,
+                                           BlockLabel* on_outside_input) {
+  TAG();
+  Definition* curpos_def = LoadLocal(current_position_);
+  Definition* cp_off_def = Int64Constant(-cp_offset);
+
+  // If (current_position_ < -cp_offset), we are in bounds.
+  // Remember, current_position_ is a negative offset from the string end.
+
+  BranchOrBacktrack(Comparison(kGTE, curpos_def, cp_off_def),
+                    on_outside_input);
+}
+
+
+void IRRegExpMacroAssembler::BranchOrBacktrack(
+    ComparisonInstr* comparison,
+    BlockLabel* true_successor) {
+  if (comparison == NULL) {  // No condition
+    if (true_successor == NULL) {
+      Backtrack();
+      return;
+    }
+    GoTo(true_successor);
+    return;
+  }
+
+  // If no successor block has been passed in, backtrack.
+  JoinEntryInstr* true_successor_block = backtrack_block_;
+  if (true_successor != NULL) {
+    true_successor->SetLinked();
+    true_successor_block = true_successor->block();
+  }
+  ASSERT(true_successor_block != NULL);
+
+  // If the condition is not true, fall through to a new block.
+  BlockLabel fallthrough;
+
+  BranchInstr* branch = new(Z) BranchInstr(comparison);
+  *branch->true_successor_address() =
+      TargetWithJoinGoto(true_successor_block);
+  *branch->false_successor_address() =
+      TargetWithJoinGoto(fallthrough.block());
+
+  CloseBlockWith(branch);
+  BindBlock(&fallthrough);
+}
+
+
+TargetEntryInstr* IRRegExpMacroAssembler::TargetWithJoinGoto(
+    JoinEntryInstr* dst) {
+  TargetEntryInstr* target = new(Z) TargetEntryInstr(
+          block_id_.Alloc(), kInvalidTryIndex);
+  blocks_.Add(target);
+
+  target->AppendInstruction(new(Z) GotoInstr(dst));
+
+  return target;
+}
+
+
+IndirectEntryInstr* IRRegExpMacroAssembler::IndirectWithJoinGoto(
+    JoinEntryInstr* dst) {
+  IndirectEntryInstr* target = new(Z) IndirectEntryInstr(
+          block_id_.Alloc(), indirect_id_.Alloc(), kInvalidTryIndex);
+  blocks_.Add(target);
+
+  target->AppendInstruction(new(Z) GotoInstr(dst));
+
+  return target;
+}
+
+
+void IRRegExpMacroAssembler::CheckPreemption() {
+  TAG();
+  AppendInstruction(new(Z) CheckStackOverflowInstr(kNoSourcePos, 0));
+}
+
+
+Definition* IRRegExpMacroAssembler::Add(
+    PushArgumentInstr* lhs,
+    PushArgumentInstr* rhs) {
+  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kADD), lhs, rhs);
+}
+
+
+Definition* IRRegExpMacroAssembler::Sub(
+    PushArgumentInstr* lhs,
+    PushArgumentInstr* rhs) {
+  return InstanceCall(InstanceCallDescriptor::FromToken(Token::kSUB), lhs, rhs);
+}
+
+
+void IRRegExpMacroAssembler::LoadCurrentCharacterUnchecked(
+    intptr_t cp_offset, intptr_t characters) {
+  TAG();
+
+  ASSERT(characters == 1 || CanReadUnaligned());
+  if (mode_ == ASCII) {
+    ASSERT(characters == 1 || characters == 2 || characters == 4);
+  } else {
+    ASSERT(mode_ == UC16);
+    ASSERT(characters == 1 || characters == 2);
+  }
+
+  // Calculate the addressed string index as:
+  //    cp_offset + current_position_ + string_param_length_
+  // TODO(zerny): Avoid generating 'add' instance-calls here.
+  PushArgumentInstr* off_arg =
+      PushArgument(Bind(Int64Constant(cp_offset)));
+  PushArgumentInstr* pos_arg =
+      PushArgument(BindLoadLocal(*current_position_));
+  PushArgumentInstr* off_pos_arg =
+      PushArgument(Bind(Add(off_arg, pos_arg)));
+  PushArgumentInstr* len_arg =
+      PushArgument(BindLoadLocal(*string_param_length_));
+  // Index is stored in a temporary local so that we can later load it safely.
+  StoreLocal(index_temp_, Bind(Add(off_pos_arg, len_arg)));
+
+  // Load and store the code units.
+  Value* code_unit_value = LoadCodeUnitsAt(index_temp_, characters);
+  StoreLocal(current_character_, code_unit_value);
+  PRINT(PushLocal(current_character_));
+}
+
+
+Value* IRRegExpMacroAssembler::CharacterAt(LocalVariable* index) {
+  return LoadCodeUnitsAt(index, 1);
+}
+
+
+Value* IRRegExpMacroAssembler::LoadCodeUnitsAt(LocalVariable* index,
+                                               intptr_t characters) {
+  // Bind the pattern as the load receiver.
+  Value* pattern_val = BindLoadLocal(*string_param_);
+  if (RawObject::IsExternalStringClassId(specialization_cid_)) {
+    // The data of an external string is stored through two indirections.
+    intptr_t external_offset = 0;
+    intptr_t data_offset = 0;
+    if (specialization_cid_ == kExternalOneByteStringCid) {
+      external_offset = ExternalOneByteString::external_data_offset();
+      data_offset = RawExternalOneByteString::ExternalData::data_offset();
+    } else if (specialization_cid_ == kExternalTwoByteStringCid) {
+      external_offset = ExternalTwoByteString::external_data_offset();
+      data_offset = RawExternalTwoByteString::ExternalData::data_offset();
+    } else {
+      UNREACHABLE();
+    }
+    // This pushes untagged values on the stack which are immediately consumed:
+    // the first value is consumed to obtain the second value which is consumed
+    // by LoadCodeUnitsAtInstr below.
+    Value* external_val =
+        Bind(new(Z) LoadUntaggedInstr(pattern_val, external_offset));
+    pattern_val =
+        Bind(new(Z) LoadUntaggedInstr(external_val, data_offset));
+  }
+
+  // Here pattern_val might be untagged so this must not trigger a GC.
+  Value* index_val = BindLoadLocal(*index);
+
+  return Bind(new(Z) LoadCodeUnitsInstr(
+      pattern_val,
+      index_val,
+      characters,
+      specialization_cid_,
+      Scanner::kNoSourcePos));
+}
+
+
+#undef __
+
+}  // namespace dart
diff --git a/runtime/vm/regexp_assembler_ir.h b/runtime/vm/regexp_assembler_ir.h
new file mode 100644
index 0000000..77d09d5
--- /dev/null
+++ b/runtime/vm/regexp_assembler_ir.h
@@ -0,0 +1,443 @@
+// 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.
+
+#ifndef VM_REGEXP_ASSEMBLER_IR_H_
+#define VM_REGEXP_ASSEMBLER_IR_H_
+
+#include "vm/assembler.h"
+#include "vm/intermediate_language.h"
+#include "vm/object.h"
+#include "vm/regexp_assembler.h"
+
+namespace dart {
+
+class IRRegExpMacroAssembler : public RegExpMacroAssembler {
+ public:
+  // Type of input string to generate code for.
+  enum Mode { ASCII = 1, UC16 = 2 };
+
+  // Result of calling generated native RegExp code.
+  // RETRY: Something significant changed during execution, and the matching
+  //        should be retried from scratch.
+  // EXCEPTION: Something failed during execution. If no exception has been
+  //        thrown, it's an internal out-of-memory, and the caller should
+  //        throw the exception.
+  // FAILURE: Matching failed.
+  // SUCCESS: Matching succeeded, and the output array has been filled with
+  //        capture positions.
+  enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
+
+  IRRegExpMacroAssembler(intptr_t specialization_cid,
+                         intptr_t capture_count,
+                         const ParsedFunction* parsed_function,
+                         const ZoneGrowableArray<const ICData*>& ic_data_array,
+                         Zone* zone);
+  virtual ~IRRegExpMacroAssembler();
+
+  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,
+                           Zone* zone);
+
+  virtual bool IsClosed() const { return (current_instruction_ == NULL); }
+
+  virtual intptr_t stack_limit_slack();
+  virtual void AdvanceCurrentPosition(intptr_t by);
+  virtual void AdvanceRegister(intptr_t reg, intptr_t by);
+  virtual void Backtrack();
+  virtual void BindBlock(BlockLabel* label);
+  virtual void CheckAtStart(BlockLabel* on_at_start);
+  virtual void CheckCharacter(uint32_t c, BlockLabel* on_equal);
+  virtual void CheckCharacterAfterAnd(uint32_t c,
+                                      uint32_t mask,
+                                      BlockLabel* on_equal);
+  virtual void CheckCharacterGT(uint16_t limit, BlockLabel* on_greater);
+  virtual void CheckCharacterLT(uint16_t limit, BlockLabel* on_less);
+  // A "greedy loop" is a loop that is both greedy and with a simple
+  // body. It has a particularly simple implementation.
+  virtual void CheckGreedyLoop(BlockLabel* on_tos_equals_current_position);
+  virtual void CheckNotAtStart(BlockLabel* on_not_at_start);
+  virtual void CheckNotBackReference(intptr_t start_reg,
+                                     BlockLabel* on_no_match);
+  virtual void CheckNotBackReferenceIgnoreCase(intptr_t start_reg,
+                                               BlockLabel* on_no_match);
+  virtual void CheckNotCharacter(uint32_t c, BlockLabel* on_not_equal);
+  virtual void CheckNotCharacterAfterAnd(uint32_t c,
+                                         uint32_t mask,
+                                         BlockLabel* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusAnd(uint16_t c,
+                                              uint16_t minus,
+                                              uint16_t mask,
+                                              BlockLabel* on_not_equal);
+  virtual void CheckCharacterInRange(uint16_t from,
+                                     uint16_t to,
+                                     BlockLabel* on_in_range);
+  virtual void CheckCharacterNotInRange(uint16_t from,
+                                        uint16_t to,
+                                        BlockLabel* on_not_in_range);
+  virtual void CheckBitInTable(const TypedData& table, BlockLabel* on_bit_set);
+
+  // Checks whether the given offset from the current position is before
+  // the end of the string.
+  virtual void CheckPosition(intptr_t cp_offset, BlockLabel* on_outside_input);
+  virtual bool CheckSpecialCharacterClass(
+      uint16_t type, BlockLabel* on_no_match);
+  virtual void Fail();
+  virtual void IfRegisterGE(intptr_t reg,
+                            intptr_t comparand, BlockLabel* if_ge);
+  virtual void IfRegisterLT(intptr_t reg,
+                            intptr_t comparand, BlockLabel* if_lt);
+  virtual void IfRegisterEqPos(intptr_t reg, BlockLabel* if_eq);
+  virtual IrregexpImplementation Implementation();
+  virtual void GoTo(BlockLabel* to);
+  virtual void LoadCurrentCharacter(intptr_t cp_offset,
+                                    BlockLabel* on_end_of_input,
+                                    bool check_bounds = true,
+                                    intptr_t characters = 1);
+  virtual void PopCurrentPosition();
+  virtual void PopRegister(intptr_t register_index);
+  virtual void Print(const char* str);
+  virtual void PushBacktrack(BlockLabel* label);
+  virtual void PushCurrentPosition();
+  virtual void PushRegister(intptr_t register_index);
+  virtual void ReadCurrentPositionFromRegister(intptr_t reg);
+  virtual void ReadStackPointerFromRegister(intptr_t reg);
+  virtual void SetCurrentPositionFromEnd(intptr_t by);
+  virtual void SetRegister(intptr_t register_index, intptr_t to);
+  virtual bool Succeed();
+  virtual void WriteCurrentPositionToRegister(intptr_t reg, intptr_t cp_offset);
+  virtual void ClearRegisters(intptr_t reg_from, intptr_t reg_to);
+  virtual void WriteStackPointerToRegister(intptr_t reg);
+
+  virtual void PrintBlocks();
+
+  IndirectGotoInstr* backtrack_goto() const { return backtrack_goto_; }
+  GraphEntryInstr* graph_entry() const { return entry_block_; }
+
+  intptr_t num_stack_locals() const { return local_id_.Count(); }
+  intptr_t num_blocks() const { return block_id_.Count(); }
+
+  // Generate a dispatch block implementing backtracking. Must be done after
+  // graph construction.
+  void GenerateBacktrackBlock();
+
+  // Allocate the actual registers array once its size is known. Must be done
+  // after graph construction.
+  void FinalizeRegistersArray();
+
+ private:
+  // Generate the contents of preset blocks. The entry block is the entry point
+  // of the generated code.
+  void GenerateEntryBlock();
+  // Copies capture indices into the result area and returns true.
+  void GenerateSuccessBlock();
+  // Returns false.
+  void GenerateExitBlock();
+
+  enum ComparisonKind {
+    kEQ,
+    kNE,
+    kLT,
+    kGT,
+    kLTE,
+    kGTE,
+  };
+
+  struct InstanceCallDescriptor {
+    // Standard (i.e. most non-Smi) functions.
+    explicit InstanceCallDescriptor(const String& name)
+      : name(name),
+        token_kind(Token::kILLEGAL),
+        checked_argument_count(1) { }
+
+    InstanceCallDescriptor(const String& name,
+                           Token::Kind token_kind,
+                           intptr_t checked_argument_count)
+      : name(name),
+        token_kind(token_kind),
+        checked_argument_count(checked_argument_count) { }
+
+    // Special cases for Smi and indexing functions.
+    static InstanceCallDescriptor FromToken(Token::Kind token_kind) {
+      switch (token_kind) {
+        case Token::kEQ: return InstanceCallDescriptor(
+                  Symbols::EqualOperator(), token_kind, 2);
+        case Token::kADD: return InstanceCallDescriptor(
+                Symbols::Plus(), token_kind, 2);
+        case Token::kSUB: return InstanceCallDescriptor(
+                Symbols::Minus(), token_kind, 2);
+        case Token::kBIT_OR: return InstanceCallDescriptor(
+                Symbols::BitOr(), token_kind, 2);
+        case Token::kBIT_AND: return InstanceCallDescriptor(
+                Symbols::BitAnd(), token_kind, 2);
+        case Token::kLT: return InstanceCallDescriptor(
+                Symbols::LAngleBracket(), token_kind, 2);
+        case Token::kLTE: return InstanceCallDescriptor(
+                Symbols::LessEqualOperator(), token_kind, 2);
+        case Token::kGT: return InstanceCallDescriptor(
+                Symbols::RAngleBracket(), token_kind, 2);
+        case Token::kGTE: return InstanceCallDescriptor(
+                Symbols::GreaterEqualOperator(), token_kind, 2);
+        case Token::kNEGATE: return InstanceCallDescriptor(
+                Symbols::UnaryMinus(), token_kind, 1);
+        case Token::kINDEX: return InstanceCallDescriptor(
+                Symbols::IndexToken(), token_kind, 2);
+        case Token::kASSIGN_INDEX: return InstanceCallDescriptor(
+                Symbols::AssignIndexToken(), token_kind, 2);
+        default:
+          UNREACHABLE();
+      }
+      UNREACHABLE();
+      return InstanceCallDescriptor(Symbols::Empty());
+    }
+
+    const String& name;
+    Token::Kind token_kind;
+    intptr_t checked_argument_count;
+  };
+
+  LocalVariable* Local(const String& name);
+  LocalVariable* Parameter(const String& name, intptr_t index) const;
+
+  ConstantInstr* Int64Constant(int64_t value) const;
+  ConstantInstr* Uint64Constant(uint64_t value) const;
+  ConstantInstr* BoolConstant(bool value) const;
+  ConstantInstr* StringConstant(const char* value) const;
+
+  // The word character map static member of the RegExp class.
+  // Byte map of one byte characters with a 0xff if the character is a word
+  // character (digit, letter or underscore) and 0x00 otherwise.
+  // Used by generated RegExp code.
+  ConstantInstr* WordCharacterMapConstant() const;
+
+  ComparisonInstr* Comparison(ComparisonKind kind,
+                              PushArgumentInstr* lhs,
+                              PushArgumentInstr* rhs);
+  ComparisonInstr* Comparison(ComparisonKind kind,
+                              Definition* lhs,
+                              Definition* rhs);
+
+  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
+                                  PushArgumentInstr* arg1) const;
+  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
+                                  PushArgumentInstr* arg1,
+                                  PushArgumentInstr* arg2) const;
+  InstanceCallInstr* InstanceCall(const InstanceCallDescriptor& desc,
+                                  PushArgumentInstr* arg1,
+                                  PushArgumentInstr* arg2,
+                                  PushArgumentInstr* arg3) const;
+  InstanceCallInstr* InstanceCall(
+      const InstanceCallDescriptor& desc,
+      ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
+
+  StaticCallInstr* StaticCall(const Function& function) const;
+  StaticCallInstr* StaticCall(const Function& function,
+                              PushArgumentInstr* arg1) const;
+  StaticCallInstr* StaticCall(const Function& function,
+                              PushArgumentInstr* arg1,
+                              PushArgumentInstr* arg2) const;
+  StaticCallInstr* StaticCall(
+      const Function& function,
+      ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
+
+  // Creates a new block consisting simply of a goto to dst.
+  TargetEntryInstr* TargetWithJoinGoto(JoinEntryInstr* dst);
+  IndirectEntryInstr* IndirectWithJoinGoto(JoinEntryInstr* dst);
+
+  // Adds, respectively subtracts lhs and rhs and returns the result.
+  Definition* Add(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
+  Definition* Sub(PushArgumentInstr* lhs, PushArgumentInstr* rhs);
+
+  LoadLocalInstr* LoadLocal(LocalVariable* local) const;
+  void StoreLocal(LocalVariable* local, Value* value);
+
+  PushArgumentInstr* PushArgument(Value* value);
+  PushArgumentInstr* PushLocal(LocalVariable* local);
+
+  PushArgumentInstr* PushRegisterIndex(intptr_t reg);
+  Value* LoadRegister(intptr_t reg);
+  void StoreRegister(intptr_t reg, intptr_t value);
+  void StoreRegister(PushArgumentInstr* registers,
+                     PushArgumentInstr* index,
+                     PushArgumentInstr* value);
+
+  // Load a number of characters at the given offset from the
+  // current position, into the current-character register.
+  void LoadCurrentCharacterUnchecked(intptr_t cp_offset,
+                                     intptr_t character_count);
+
+  // Returns the character within the passed string at the specified index.
+  Value* CharacterAt(LocalVariable* index);
+
+  // Load a number of characters starting from index in the pattern string.
+  Value* LoadCodeUnitsAt(LocalVariable* index, intptr_t character_count);
+
+  // Check whether preemption has been requested.
+  void CheckPreemption();
+
+  // Byte size of chars in the string to match (decided by the Mode argument)
+  inline intptr_t char_size() { return static_cast<int>(mode_); }
+
+  // Equivalent to a conditional branch to the label, unless the label
+  // is NULL, in which case it is a conditional Backtrack.
+  void BranchOrBacktrack(ComparisonInstr* comparison,
+                         BlockLabel* true_successor);
+
+  // Set up all local variables and parameters.
+  void InitializeLocals();
+
+  // Allocates a new local, and returns the appropriate id for placing it
+  // on the stack.
+  intptr_t GetNextLocalIndex();
+
+  // We never have any copied parameters.
+  intptr_t num_copied_params() const {
+    return 0;
+  }
+
+  // Return the position register at the specified index, creating it if
+  // necessary. Note that the number of such registers can exceed the amount
+  // required by the number of output captures.
+  LocalVariable* position_register(intptr_t index);
+
+  void set_current_instruction(Instruction* instruction);
+
+  // The following functions are responsible for appending instructions
+  // to the current instruction in various ways. The most simple one
+  // is AppendInstruction, which simply appends an instruction and performs
+  // bookkeeping.
+  void AppendInstruction(Instruction* instruction);
+  // Similar to AppendInstruction, but closes the current block by
+  // setting current_instruction_ to NULL.
+  void CloseBlockWith(Instruction* instruction);
+  // Appends definition and allocates a temp index for the result.
+  Value* Bind(Definition* definition);
+  // Loads and binds a local variable.
+  Value* BindLoadLocal(const LocalVariable& local);
+
+  // Appends the definition.
+  void Do(Definition* definition);
+  // Closes the current block with a jump to the specified block.
+  void GoTo(JoinEntryInstr* to);
+
+  // Accessors for our local stack_.
+  void PushStack(Definition* definition);
+  Definition* PopStack();
+  Definition* PeekStack();
+  void CheckStackLimit();
+  void GrowStack();
+
+  // Prints the specified argument. Used for debugging.
+  void Print(PushArgumentInstr* argument);
+
+  // A utility class tracking ids of various objects such as blocks, temps, etc.
+  class IdAllocator : public ValueObject {
+   public:
+    IdAllocator() : next_id(0) { }
+
+    intptr_t Count() const { return next_id; }
+    intptr_t Alloc(intptr_t count = 1) {
+      ASSERT(count >= 0);
+      intptr_t current_id = next_id;
+      next_id += count;
+      return current_id;
+    }
+    void Dealloc(intptr_t count = 1) {
+      ASSERT(count <= next_id);
+      next_id -= count;
+    }
+
+   private:
+    intptr_t next_id;
+  };
+
+  // Which mode to generate code for (ASCII or UC16).
+  Mode mode_;
+
+  // Which specific string class to generate code for.
+  intptr_t specialization_cid_;
+
+  // Block entries used internally.
+  GraphEntryInstr* entry_block_;
+  JoinEntryInstr* start_block_;
+  JoinEntryInstr* success_block_;
+  JoinEntryInstr* exit_block_;
+
+  // Shared backtracking block.
+  JoinEntryInstr* backtrack_block_;
+  // Single indirect goto instruction which performs all backtracking.
+  IndirectGotoInstr* backtrack_goto_;
+
+  const ParsedFunction* parsed_function_;
+  const ZoneGrowableArray<const ICData*>& ic_data_array_;
+
+  // All created blocks are contained within this set. Used for printing
+  // the generated code.
+  GrowableArray<BlockEntryInstr*> blocks_;
+
+  // The current instruction to link to when new code is emitted.
+  Instruction* current_instruction_;
+
+  // A list, acting as the runtime stack for both backtrack locations and
+  // stored positions within the string.
+  LocalVariable* stack_;
+  LocalVariable* stack_pointer_;
+
+  // Stores the current character within the string.
+  LocalVariable* current_character_;
+
+  // Stores the current location within the string as a negative offset
+  // from the end of the string.
+  LocalVariable* current_position_;
+
+  // The string being processed, passed as a function parameter.
+  LocalVariable* string_param_;
+
+  // Stores the length of string_param_.
+  LocalVariable* string_param_length_;
+
+  // The start index within the string, passed as a function parameter.
+  LocalVariable* start_index_param_;
+
+  // An assortment of utility variables.
+  LocalVariable* capture_length_;
+  LocalVariable* match_start_index_;
+  LocalVariable* capture_start_index_;
+  LocalVariable* match_end_index_;
+  LocalVariable* char_in_capture_;
+  LocalVariable* char_in_match_;
+  LocalVariable* index_temp_;
+
+  LocalVariable* result_;
+
+  // Stored positions containing group bounds. Generated as needed.
+  LocalVariable* registers_;
+  intptr_t registers_count_;
+  const intptr_t saved_registers_count_;
+
+  // The actual array objects used for the stack and registers.
+  Array& stack_array_cell_;
+  TypedData& registers_array_;
+
+  IdAllocator block_id_;
+  IdAllocator temp_id_;
+  IdAllocator arg_id_;
+  IdAllocator local_id_;
+  IdAllocator indirect_id_;
+};
+
+
+}  // namespace dart
+
+#endif  // VM_REGEXP_ASSEMBLER_IR_H_
diff --git a/runtime/vm/regexp_bytecodes.h b/runtime/vm/regexp_bytecodes.h
new file mode 100644
index 0000000..8d1cddb
--- /dev/null
+++ b/runtime/vm/regexp_bytecodes.h
@@ -0,0 +1,79 @@
+// 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.
+
+#ifndef VM_REGEXP_BYTECODES_H_
+#define VM_REGEXP_BYTECODES_H_
+
+namespace dart {
+
+const int BYTECODE_MASK = 0xff;
+// The first argument is packed in with the byte code in one word, but so it
+// has 24 bits, but it can be positive and negative so only use 23 bits for
+// positive values.
+const unsigned int MAX_FIRST_ARG = 0x7fffffu;
+const int BYTECODE_SHIFT = 8;
+
+#define BYTECODE_ITERATOR(V)                                                   \
+V(BREAK,              0, 4)   /* bc8                                        */ \
+V(PUSH_CP,            1, 4)   /* bc8 pad24                                  */ \
+V(PUSH_BT,            2, 8)   /* bc8 pad24 offset32                         */ \
+V(PUSH_REGISTER,      3, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_CP, 4, 8)   /* bc8 reg_idx24 offset32                     */ \
+V(SET_CP_TO_REGISTER, 5, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER_TO_SP, 6, 4)   /* bc8 reg_idx24                              */ \
+V(SET_SP_TO_REGISTER, 7, 4)   /* bc8 reg_idx24                              */ \
+V(SET_REGISTER,       8, 8)   /* bc8 reg_idx24 value32                      */ \
+V(ADVANCE_REGISTER,   9, 8)   /* bc8 reg_idx24 value32                      */ \
+V(POP_CP,            10, 4)   /* bc8 pad24                                  */ \
+V(POP_BT,            11, 4)   /* bc8 pad24                                  */ \
+V(POP_REGISTER,      12, 4)   /* bc8 reg_idx24                              */ \
+V(FAIL,              13, 4)   /* bc8 pad24                                  */ \
+V(SUCCEED,           14, 4)   /* bc8 pad24                                  */ \
+V(ADVANCE_CP,        15, 4)   /* bc8 offset24                               */ \
+V(GOTO,              16, 8)   /* bc8 pad24 addr32                           */ \
+V(LOAD_CURRENT_CHAR, 17, 8)   /* bc8 offset24 addr32                        */ \
+V(LOAD_CURRENT_CHAR_UNCHECKED, 18, 4) /* bc8 offset24                       */ \
+V(LOAD_2_CURRENT_CHARS, 19, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_2_CURRENT_CHARS_UNCHECKED, 20, 4) /* bc8 offset24                    */ \
+V(LOAD_4_CURRENT_CHARS, 21, 8) /* bc8 offset24 addr32                       */ \
+V(LOAD_4_CURRENT_CHARS_UNCHECKED, 22, 4) /* bc8 offset24                    */ \
+V(CHECK_4_CHARS,     23, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_CHAR,        24, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(CHECK_NOT_4_CHARS, 25, 12)  /* bc8 pad24 uint32 addr32                    */ \
+V(CHECK_NOT_CHAR,    26, 8)   /* bc8 pad8 uint16 addr32                     */ \
+V(AND_CHECK_4_CHARS, 27, 16)  /* bc8 pad24 uint32 uint32 addr32             */ \
+V(AND_CHECK_CHAR,    28, 12)  /* bc8 pad8 uint16 uint32 addr32              */ \
+V(AND_CHECK_NOT_4_CHARS, 29, 16) /* bc8 pad24 uint32 uint32 addr32          */ \
+V(AND_CHECK_NOT_CHAR, 30, 12) /* bc8 pad8 uint16 uint32 addr32              */ \
+V(MINUS_AND_CHECK_NOT_CHAR, 31, 12) /* bc8 pad8 uc16 uc16 uc16 addr32       */ \
+V(CHECK_CHAR_IN_RANGE, 32, 12) /* bc8 pad24 uc16 uc16 addr32                */ \
+V(CHECK_CHAR_NOT_IN_RANGE, 33, 12) /* bc8 pad24 uc16 uc16 addr32            */ \
+V(CHECK_BIT_IN_TABLE, 34, 24) /* bc8 pad24 addr32 bits128                   */ \
+V(CHECK_LT,          35, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_GT,          36, 8)   /* bc8 pad8 uc16 addr32                       */ \
+V(CHECK_NOT_BACK_REF, 37, 8)  /* bc8 reg_idx24 addr32                       */ \
+V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32                */ \
+V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32            */ \
+V(CHECK_REGISTER_LT, 40, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_GE, 41, 12)  /* bc8 reg_idx24 value32 addr32               */ \
+V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32                     */ \
+V(CHECK_AT_START,    43, 8)   /* bc8 pad24 addr32                           */ \
+V(CHECK_NOT_AT_START, 44, 8)  /* bc8 pad24 addr32                           */ \
+V(CHECK_GREEDY,      45, 8)   /* bc8 pad24 addr32                           */ \
+V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32                        */ \
+V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24                        */
+
+#define DECLARE_BYTECODES(name, code, length) \
+  static const int BC_##name = code;
+BYTECODE_ITERATOR(DECLARE_BYTECODES)
+#undef DECLARE_BYTECODES
+
+#define DECLARE_BYTECODE_LENGTH(name, code, length) \
+  static const int BC_##name##_LENGTH = length;
+BYTECODE_ITERATOR(DECLARE_BYTECODE_LENGTH)
+#undef DECLARE_BYTECODE_LENGTH
+
+}  // namespace dart
+
+#endif  // VM_REGEXP_BYTECODES_H_
diff --git a/runtime/vm/regexp_interpreter.cc b/runtime/vm/regexp_interpreter.cc
new file mode 100644
index 0000000..b036ec8
--- /dev/null
+++ b/runtime/vm/regexp_interpreter.cc
@@ -0,0 +1,621 @@
+// 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.
+
+// A simple interpreter for the Irregexp byte code.
+
+#include "vm/regexp_interpreter.h"
+
+#include "vm/regexp_bytecodes.h"
+#include "vm/regexp_assembler.h"
+#include "vm/object.h"
+#include "vm/unicode.h"
+#include "vm/unibrow.h"
+#include "vm/unibrow-inl.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_regexp_bytecodes, false, "trace_regexp_bytecodes");
+
+typedef unibrow::Mapping<unibrow::Ecma262Canonicalize> Canonicalize;
+
+template<typename Char>
+static bool BackRefMatchesNoCase(Canonicalize* interp_canonicalize,
+                                 intptr_t from,
+                                 intptr_t current,
+                                 intptr_t len,
+                                 const String& subject);
+
+template <>
+bool BackRefMatchesNoCase<uint16_t>(Canonicalize* interp_canonicalize,
+                                    intptr_t from,
+                                    intptr_t current,
+                                    intptr_t len,
+                                    const String& subject) {
+  for (int i = 0; i < len; i++) {
+    int32_t old_char = subject.CharAt(from++);
+    int32_t new_char = subject.CharAt(current++);
+    if (old_char == new_char) continue;
+    int32_t old_string[1] = { old_char };
+    int32_t new_string[1] = { new_char };
+    interp_canonicalize->get(old_char, '\0', old_string);
+    interp_canonicalize->get(new_char, '\0', new_string);
+    if (old_string[0] != new_string[0]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <>
+bool BackRefMatchesNoCase<uint8_t>(Canonicalize* interp_canonicalize,
+                                   intptr_t from,
+                                   intptr_t current,
+                                   intptr_t len,
+                                   const String& subject) {
+  for (int i = 0; i < len; i++) {
+    unsigned int old_char = subject.CharAt(from++);
+    unsigned int new_char = subject.CharAt(current++);
+    if (old_char == new_char) continue;
+    // Convert both characters to lower case.
+    old_char |= 0x20;
+    new_char |= 0x20;
+    if (old_char != new_char) return false;
+    // Not letters in the ASCII range and Latin-1 range.
+    if (!(old_char - 'a' <= 'z' - 'a') &&
+        !(old_char - 224 <= 254 - 224 && old_char != 247)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+#ifdef DEBUG
+static void TraceInterpreter(const uint8_t* code_base,
+                             const uint8_t* pc,
+                             int stack_depth,
+                             int current_position,
+                             uint32_t current_char,
+                             int bytecode_length,
+                             const char* bytecode_name) {
+  if (FLAG_trace_regexp_bytecodes) {
+    bool printable = (current_char < 127 && current_char >= 32);
+    const char* format =
+        printable ?
+        "pc = %02x, sp = %d, curpos = %d, curchar = %08x (%c), bc = %s" :
+        "pc = %02x, sp = %d, curpos = %d, curchar = %08x .%c., bc = %s";
+    OS::Print(format,
+              pc - code_base,
+              stack_depth,
+              current_position,
+              current_char,
+              printable ? current_char : '.',
+              bytecode_name);
+    for (int i = 0; i < bytecode_length; i++) {
+      OS::Print(", %02x", pc[i]);
+    }
+    OS::Print(" ");
+    for (int i = 1; i < bytecode_length; i++) {
+      unsigned char b = pc[i];
+      if (b < 127 && b >= 32) {
+        OS::Print("%c", b);
+      } else {
+        OS::Print(".");
+      }
+    }
+    OS::Print("\n");
+  }
+}
+
+
+#define BYTECODE(name)                                                      \
+  case BC_##name:                                                           \
+    TraceInterpreter(code_base,                                             \
+                     pc,                                                    \
+                     static_cast<int>(backtrack_sp - backtrack_stack_base), \
+                     current,                                               \
+                     current_char,                                          \
+                     BC_##name##_LENGTH,                                    \
+                     #name);
+#else
+#define BYTECODE(name)                                                      \
+  case BC_##name:
+#endif
+
+
+static int32_t Load32Aligned(const uint8_t* pc) {
+  ASSERT((reinterpret_cast<intptr_t>(pc) & 3) == 0);
+  return *reinterpret_cast<const int32_t *>(pc);
+}
+
+
+static int32_t Load16Aligned(const uint8_t* pc) {
+  ASSERT((reinterpret_cast<intptr_t>(pc) & 1) == 0);
+  return *reinterpret_cast<const uint16_t *>(pc);
+}
+
+
+// A simple abstraction over the backtracking stack used by the interpreter.
+// This backtracking stack does not grow automatically, but it ensures that the
+// the memory held by the stack is released or remembered in a cache if the
+// matching terminates.
+class BacktrackStack {
+ public:
+  explicit BacktrackStack(Zone* zone) {
+    data_ = zone->Alloc<intptr_t>(kBacktrackStackSize);
+  }
+
+  intptr_t* data() const { return data_; }
+
+  intptr_t max_size() const { return kBacktrackStackSize; }
+
+ private:
+  static const intptr_t kBacktrackStackSize = 10000;
+
+  intptr_t* data_;
+
+  DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
+};
+
+
+template <typename Char>
+static IrregexpInterpreter::IrregexpResult RawMatch(const uint8_t* code_base,
+                                                    const String& subject,
+                                                    int32_t* registers,
+                                                    intptr_t current,
+                                                    uint32_t current_char,
+                                                    Zone* zone) {
+  const uint8_t* pc = code_base;
+  // BacktrackStack ensures that the memory allocated for the backtracking stack
+  // is returned to the system or cached if there is no stack being cached at
+  // the moment.
+  BacktrackStack backtrack_stack(zone);
+  intptr_t* backtrack_stack_base = backtrack_stack.data();
+  intptr_t* backtrack_sp = backtrack_stack_base;
+  intptr_t backtrack_stack_space = backtrack_stack.max_size();
+
+  // TODO(zerny): Optimize as single instance. V8 has this as an
+  // isolate member.
+  unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
+
+  intptr_t subject_length = subject.Length();
+
+#ifdef DEBUG
+  if (FLAG_trace_regexp_bytecodes) {
+    OS::Print("Start irregexp bytecode interpreter\n");
+  }
+#endif
+  while (true) {
+    int32_t insn = Load32Aligned(pc);
+    switch (insn & BYTECODE_MASK) {
+      BYTECODE(BREAK)
+        UNREACHABLE();
+        return IrregexpInterpreter::RE_FAILURE;
+      BYTECODE(PUSH_CP)
+        if (--backtrack_stack_space < 0) {
+          return IrregexpInterpreter::RE_EXCEPTION;
+        }
+        *backtrack_sp++ = current;
+        pc += BC_PUSH_CP_LENGTH;
+        break;
+      BYTECODE(PUSH_BT)
+        if (--backtrack_stack_space < 0) {
+          return IrregexpInterpreter::RE_EXCEPTION;
+        }
+        *backtrack_sp++ = Load32Aligned(pc + 4);
+        pc += BC_PUSH_BT_LENGTH;
+        break;
+      BYTECODE(PUSH_REGISTER)
+        if (--backtrack_stack_space < 0) {
+          return IrregexpInterpreter::RE_EXCEPTION;
+        }
+        *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
+        pc += BC_PUSH_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER)
+        registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
+        pc += BC_SET_REGISTER_LENGTH;
+        break;
+      BYTECODE(ADVANCE_REGISTER)
+        registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
+        pc += BC_ADVANCE_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER_TO_CP)
+        registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
+        pc += BC_SET_REGISTER_TO_CP_LENGTH;
+        break;
+      BYTECODE(SET_CP_TO_REGISTER)
+        current = registers[insn >> BYTECODE_SHIFT];
+        pc += BC_SET_CP_TO_REGISTER_LENGTH;
+        break;
+      BYTECODE(SET_REGISTER_TO_SP)
+        registers[insn >> BYTECODE_SHIFT] =
+            static_cast<int>(backtrack_sp - backtrack_stack_base);
+        pc += BC_SET_REGISTER_TO_SP_LENGTH;
+        break;
+      BYTECODE(SET_SP_TO_REGISTER)
+        backtrack_sp = backtrack_stack_base + registers[insn >> BYTECODE_SHIFT];
+        backtrack_stack_space = backtrack_stack.max_size() -
+            static_cast<int>(backtrack_sp - backtrack_stack_base);
+        pc += BC_SET_SP_TO_REGISTER_LENGTH;
+        break;
+      BYTECODE(POP_CP)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        current = *backtrack_sp;
+        pc += BC_POP_CP_LENGTH;
+        break;
+      BYTECODE(POP_BT)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        pc = code_base + *backtrack_sp;
+        break;
+      BYTECODE(POP_REGISTER)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
+        pc += BC_POP_REGISTER_LENGTH;
+        break;
+      BYTECODE(FAIL)
+        return IrregexpInterpreter::RE_FAILURE;
+      BYTECODE(SUCCEED)
+        return IrregexpInterpreter::RE_SUCCESS;
+      BYTECODE(ADVANCE_CP)
+        current += insn >> BYTECODE_SHIFT;
+        pc += BC_ADVANCE_CP_LENGTH;
+        break;
+      BYTECODE(GOTO)
+        pc = code_base + Load32Aligned(pc + 4);
+        break;
+      BYTECODE(ADVANCE_CP_AND_GOTO)
+        current += insn >> BYTECODE_SHIFT;
+        pc = code_base + Load32Aligned(pc + 4);
+        break;
+      BYTECODE(CHECK_GREEDY)
+        if (current == backtrack_sp[-1]) {
+          backtrack_sp--;
+          backtrack_stack_space++;
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_GREEDY_LENGTH;
+        }
+        break;
+      BYTECODE(LOAD_CURRENT_CHAR) {
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        if (pos >= subject_length) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          current_char = subject.CharAt(pos);
+          pc += BC_LOAD_CURRENT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        current_char = subject.CharAt(pos);
+        pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
+        break;
+      }
+      BYTECODE(LOAD_2_CURRENT_CHARS) {
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        if (pos + 2 > subject_length) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          Char next = subject.CharAt(pos + 1);
+          current_char = subject.CharAt(pos) |
+                         (next << (kBitsPerByte * sizeof(Char)));
+          pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        Char next = subject.CharAt(pos + 1);
+        current_char = subject.CharAt(pos) |
+                       (next << (kBitsPerByte * sizeof(Char)));
+        pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
+        break;
+      }
+      BYTECODE(LOAD_4_CURRENT_CHARS) {
+        ASSERT(sizeof(Char) == 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        if (pos + 4 > subject_length) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          Char next1 = subject.CharAt(pos + 1);
+          Char next2 = subject.CharAt(pos + 2);
+          Char next3 = subject.CharAt(pos + 3);
+          current_char = (subject.CharAt(pos) |
+                          (next1 << 8) |
+                          (next2 << 16) |
+                          (next3 << 24));
+          pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
+        ASSERT(sizeof(Char) == 1);
+        int pos = current + (insn >> BYTECODE_SHIFT);
+        Char next1 = subject.CharAt(pos + 1);
+        Char next2 = subject.CharAt(pos + 2);
+        Char next3 = subject.CharAt(pos + 3);
+        current_char = (subject.CharAt(pos) |
+                        (next1 << 8) |
+                        (next2 << 16) |
+                        (next3 << 24));
+        pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
+        break;
+      }
+      BYTECODE(CHECK_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c == current_char) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c == current_char) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_NOT_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c != current_char) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_NOT_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_NOT_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c != current_char) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(AND_CHECK_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c == (current_char & Load32Aligned(pc + 8))) {
+          pc = code_base + Load32Aligned(pc + 12);
+        } else {
+          pc += BC_AND_CHECK_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(AND_CHECK_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c == (current_char & Load32Aligned(pc + 4))) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_AND_CHECK_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(AND_CHECK_NOT_4_CHARS) {
+        uint32_t c = Load32Aligned(pc + 4);
+        if (c != (current_char & Load32Aligned(pc + 8))) {
+          pc = code_base + Load32Aligned(pc + 12);
+        } else {
+          pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(AND_CHECK_NOT_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        if (c != (current_char & Load32Aligned(pc + 4))) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
+        uint32_t c = (insn >> BYTECODE_SHIFT);
+        uint32_t minus = Load16Aligned(pc + 4);
+        uint32_t mask = Load16Aligned(pc + 6);
+        if (c != ((current_char - minus) & mask)) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_CHAR_IN_RANGE) {
+        uint32_t from = Load16Aligned(pc + 4);
+        uint32_t to = Load16Aligned(pc + 6);
+        if (from <= current_char && current_char <= to) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
+        uint32_t from = Load16Aligned(pc + 4);
+        uint32_t to = Load16Aligned(pc + 6);
+        if (from > current_char || current_char > to) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_BIT_IN_TABLE) {
+        int mask = RegExpMacroAssembler::kTableMask;
+        uint8_t b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
+        int bit = (current_char & (kBitsPerByte - 1));
+        if ((b & (1 << bit)) != 0) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_LT) {
+        uint32_t limit = (insn >> BYTECODE_SHIFT);
+        if (current_char < limit) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_LT_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_GT) {
+        uint32_t limit = (insn >> BYTECODE_SHIFT);
+        if (current_char > limit) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_GT_LENGTH;
+        }
+        break;
+      }
+      BYTECODE(CHECK_REGISTER_LT)
+        if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_REGISTER_LT_LENGTH;
+        }
+        break;
+      BYTECODE(CHECK_REGISTER_GE)
+        if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_REGISTER_GE_LENGTH;
+        }
+        break;
+      BYTECODE(CHECK_REGISTER_EQ_POS)
+        if (registers[insn >> BYTECODE_SHIFT] == current) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
+        }
+        break;
+      BYTECODE(CHECK_NOT_REGS_EQUAL)
+        if (registers[insn >> BYTECODE_SHIFT] ==
+            registers[Load32Aligned(pc + 4)]) {
+          pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
+        } else {
+          pc = code_base + Load32Aligned(pc + 8);
+        }
+        break;
+      BYTECODE(CHECK_NOT_BACK_REF) {
+        int from = registers[insn >> BYTECODE_SHIFT];
+        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+        if (from < 0 || len <= 0) {
+          pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+          break;
+        }
+        if (current + len > subject_length) {
+          pc = code_base + Load32Aligned(pc + 4);
+          break;
+        } else {
+          int i;
+          for (i = 0; i < len; i++) {
+            if (subject.CharAt(from + i) != subject.CharAt(current + i)) {
+              pc = code_base + Load32Aligned(pc + 4);
+              break;
+            }
+          }
+          if (i < len) break;
+          current += len;
+        }
+        pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+        break;
+      }
+      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
+        int from = registers[insn >> BYTECODE_SHIFT];
+        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+        if (from < 0 || len <= 0) {
+          pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+          break;
+        }
+        if (current + len > subject_length) {
+          pc = code_base + Load32Aligned(pc + 4);
+          break;
+        } else {
+          if (BackRefMatchesNoCase<Char>(&canonicalize,
+                                         from, current, len, subject)) {
+            current += len;
+            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+          } else {
+            pc = code_base + Load32Aligned(pc + 4);
+          }
+        }
+        break;
+      }
+      BYTECODE(CHECK_AT_START)
+        if (current == 0) {
+          pc = code_base + Load32Aligned(pc + 4);
+        } else {
+          pc += BC_CHECK_AT_START_LENGTH;
+        }
+        break;
+      BYTECODE(CHECK_NOT_AT_START)
+        if (current == 0) {
+          pc += BC_CHECK_NOT_AT_START_LENGTH;
+        } else {
+          pc = code_base + Load32Aligned(pc + 4);
+        }
+        break;
+      BYTECODE(SET_CURRENT_POSITION_FROM_END) {
+        int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
+        if (subject_length - current > by) {
+          current = subject_length - by;
+          current_char = subject.CharAt(current - 1);
+        }
+        pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
+        break;
+      }
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+IrregexpInterpreter::IrregexpResult IrregexpInterpreter::Match(
+    const TypedData& bytecode,
+    const String& subject,
+    int32_t* registers,
+    intptr_t start_position,
+    Zone* zone) {
+  NoSafepointScope no_safepoint;
+  const uint8_t* code_base = reinterpret_cast<uint8_t*>(bytecode.DataAddr(0));
+
+  uint16_t previous_char = '\n';
+  if (start_position != 0) {
+    previous_char = subject.CharAt(start_position - 1);
+  }
+
+  if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
+    return RawMatch<uint8_t>(code_base,
+                             subject,
+                             registers,
+                             start_position,
+                             previous_char,
+                             zone);
+  } else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
+    return RawMatch<uint16_t>(code_base,
+                              subject,
+                              registers,
+                              start_position,
+                              previous_char,
+                              zone);
+  } else {
+    UNREACHABLE();
+    return IrregexpInterpreter::RE_FAILURE;
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/vm/regexp_interpreter.h b/runtime/vm/regexp_interpreter.h
new file mode 100644
index 0000000..eab89cb
--- /dev/null
+++ b/runtime/vm/regexp_interpreter.h
@@ -0,0 +1,33 @@
+// 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.
+
+// A simple interpreter for the Irregexp byte code.
+
+#ifndef VM_REGEXP_INTERPRETER_H_
+#define VM_REGEXP_INTERPRETER_H_
+
+#include "vm/allocation.h"
+#include "vm/object.h"
+#include "vm/zone.h"
+
+namespace dart {
+
+class IrregexpInterpreter : public AllStatic {
+ public:
+  enum IrregexpResult {
+    RE_FAILURE = 0,
+    RE_SUCCESS = 1,
+    RE_EXCEPTION = -1
+  };
+
+  static IrregexpResult Match(const TypedData& bytecode,
+                              const String& subject,
+                              int32_t* captures,
+                              intptr_t start_position,
+                              Zone* zone);
+};
+
+}  // namespace dart
+
+#endif  // VM_REGEXP_INTERPRETER_H_
diff --git a/runtime/vm/regexp_test.cc b/runtime/vm/regexp_test.cc
index 4796279..7b33982 100644
--- a/runtime/vm/regexp_test.cc
+++ b/runtime/vm/regexp_test.cc
@@ -7,6 +7,7 @@
 #include "vm/isolate.h"
 #include "vm/object.h"
 #include "vm/regexp.h"
+#include "vm/regexp_assembler_ir.h"
 #include "vm/unit_test.h"
 
 namespace dart {
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 89d9ff6..954f340 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -14,7 +14,7 @@
 namespace dart {
 
 DEFINE_FLAG(bool, trace_resolving, false, "Trace resolving.");
-
+DECLARE_FLAG(bool, lazy_dispatchers);
 
 // The actual names of named arguments are not checked by the dynamic resolver,
 // but by the method entry code. It is important that the dynamic resolver
@@ -66,6 +66,7 @@
 // owning method M.
 static RawFunction* CreateMethodExtractor(const String& getter_name,
                                           const Function& method) {
+  ASSERT(FLAG_lazy_dispatchers);
   const Function& closure_function =
       Function::Handle(method.ImplicitClosureFunction());
 
@@ -124,13 +125,15 @@
       return function.raw();
     }
     // Getter invocation might actually be a method extraction.
-    if (is_getter && function.IsNull()) {
-      function ^= cls.LookupDynamicFunction(field_name);
-      if (!function.IsNull()) {
-        // We were looking for the getter but found a method with the same name.
-        // Create a method extractor and return it.
-        function ^= CreateMethodExtractor(function_name, function);
-        return function.raw();
+    if (FLAG_lazy_dispatchers) {
+      if (is_getter && function.IsNull()) {
+        function ^= cls.LookupDynamicFunction(field_name);
+        if (!function.IsNull()) {
+          // We were looking for the getter but found a method with the same
+          // name. Create a method extractor and return it.
+          function ^= CreateMethodExtractor(function_name, function);
+          return function.raw();
+        }
       }
     }
     cls = cls.SuperClass();
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 135c559..5bcf2ff 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1567,11 +1567,11 @@
   // and then fill it up with the script objects.
   ASSERT(isolate_ != NULL);
   ScriptVisitor scripts_counter(isolate_);
-  heap->old_space()->VisitObjects(&scripts_counter);
+  heap->IterateOldObjects(&scripts_counter);
   intptr_t count = scripts_counter.count();
   scripts_ = Array::New(count, Heap::kOld);
   ScriptVisitor script_visitor(isolate_, &scripts_);
-  heap->old_space()->VisitObjects(&script_visitor);
+  heap->IterateOldObjects(&script_visitor);
 
   // Stash the symbol table away for writing and reading into the vm isolate,
   // and reset the symbol table for the regular isolate so that we do not
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 68f4751..ee38d31 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -311,6 +311,11 @@
   V(TwoNewlines, "\n\n")                                                       \
   V(TwoSpaces, "  ")                                                           \
   V(_instanceOf, "_instanceOf")                                                \
+  V(_instanceOfSmi, "_instanceOfSmi")                                          \
+  V(_instanceOfNum, "_instanceOfNum")                                          \
+  V(_instanceOfInt, "_instanceOfInt")                                          \
+  V(_instanceOfDouble, "_instanceOfDouble")                                    \
+  V(_instanceOfString, "_instanceOfString")                                    \
   V(_as, "_as")                                                                \
   V(GetterPrefix, "get:")                                                      \
   V(SetterPrefix, "set:")                                                      \
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index 3c9fa66..556a738 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -78,9 +78,9 @@
       isolate->heap()->CreateAllocatedObjectSet(mark_expectation);
   VerifyPointersVisitor visitor(isolate, allocated_set);
   // Visit all strongly reachable objects.
-  isolate->VisitObjectPointers(&visitor,
-                               false,  // skip prologue weak handles
-                               StackFrameIterator::kValidateFrames);
+  isolate->IterateObjectPointers(&visitor,
+                                 false,  // skip prologue weak handles
+                                 StackFrameIterator::kValidateFrames);
   VerifyWeakPointersVisitor weak_visitor(&visitor);
   // Visit weak handles and prologue weak handles.
   isolate->VisitWeakPersistentHandles(&weak_visitor,
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index a8fb214..886e14c 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -351,8 +351,16 @@
     'regexp.h',
     'regexp_assembler.cc',
     'regexp_assembler.h',
+    'regexp_assembler_bytecode.cc',
+    'regexp_assembler_bytecode.h',
+    'regexp_assembler_bytecode_inl.h',
+    'regexp_assembler_ir.cc',
+    'regexp_assembler_ir.h',
     'regexp_ast.cc',
     'regexp_ast.h',
+    'regexp_bytecodes.h',
+    'regexp_interpreter.cc',
+    'regexp_interpreter.h',
     'regexp_parser.cc',
     'regexp_parser.h',
     'regexp_test.cc',
diff --git a/samples/samples.status b/samples/samples.status
index 224e573..81d9654 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -24,4 +24,3 @@
 [ $arch == simarm64 ]
 *: Skip
 
-[ $compiler == dart2js && $cps_ir ]
diff --git a/sdk/api_readme.md b/sdk/api_readme.md
index 68b662c..250c823 100644
--- a/sdk/api_readme.md
+++ b/sdk/api_readme.md
@@ -1,38 +1,31 @@
-Welcome to the Dart API reference documentation,
-covering the official Dart API libraries.
-
-Some of the most fundamental Dart libraries include:
+Welcome to the Dart API reference documentation, covering the official Dart API
+libraries. Some of the most fundamental Dart libraries include:
    
-  * [dart:core](./dart_core/index.html):
-    Core functionality such as strings, numbers, collections, errors,
-    dates, and URIs.
-  * [dart:html](./dart_html/index.html):
-    DOM manipulation for web apps.
-  * [dart:io](./dart_io/index.html):
-    I/O for command-line apps.
+  * [dart:core](dart-core/index.html): Core functionality such as strings, numbers, collections, errors, dates, and URIs.
+  * [dart:html](dart-html/index.html): DOM manipulation for web apps.
+  * [dart:io](dart-io/index.html): I/O for command-line apps.
   
-Except for dart:core, you must import a library before you can use it.
-Here's an example of importing dart:html and dart:math:
-  
-    import 'dart:html';
-    import 'dart:math';
-  
-You can install more libraries
-using the _pub package manager_.
-For information on finding, using, and publishing libraries (and more)
-with pub, see [pub.dartlang.org](https://pub.dartlang.org).
+Except for `dart:core`, you must import a library before you can use it. Here's
+an example of importing `dart:html` and `dart:math`:
+
+```dart
+import 'dart:html';
+import 'dart:math';
+```
+
+You can install more libraries using the pub package manager. For information
+on finding, using, and publishing libraries with pub, see 
+[pub.dartlang.org](https://pub.dartlang.org).
   
 The main site for learning and using Dart is
-[www.dartlang.org](https://www.dartlang.org).
-Check out these pages:
+[www.dartlang.org](https://www.dartlang.org). Check out these additional pages:
   
-  * [Dart homepage](https://www.dartlang.org)
   * [Tutorials](https://www.dartlang.org/docs/tutorials/)
   * [Programmer's Guide](https://www.dartlang.org/docs/)
   * [Samples](https://www.dartlang.org/samples/)
   * [A Tour of the Dart Libraries](https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html)
   
 This API reference is automatically generated from the source code in the
-[Dart project](https://github.com/dart-lang/sdk).
-If you'd like to contribute to this documentation, see
+[Dart project](https://github.com/dart-lang/sdk). If you'd like to contribute to
+this documentation, see
 [Contributing](https://github.com/dart-lang/sdk/wiki/Contributing).
diff --git a/sdk/lib/_internal/js_runtime/lib/annotations.dart b/sdk/lib/_internal/js_runtime/lib/annotations.dart
index 0ade221..ee33493 100644
--- a/sdk/lib/_internal/js_runtime/lib/annotations.dart
+++ b/sdk/lib/_internal/js_runtime/lib/annotations.dart
@@ -51,8 +51,8 @@
 /// Annotation that marks the declaration as a patch.
 const _Patch patch = const _Patch(null);
 
-/// Annotation that marks the declaration as a patch for the old emitter.
-const _Patch patch_old = const _Patch('old');
+/// Annotation that marks the declaration as a patch for the full emitter.
+const _Patch patch_full = const _Patch('full');
 
-/// Annotation that marks the declaration as a patch for the new emitter.
-const _Patch patch_new = const _Patch('new');
+/// Annotation that marks the declaration as a patch for the lazy emitter.
+const _Patch patch_lazy = const _Patch('lazy');
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 4e2e714..2ec85f0 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -6,8 +6,8 @@
 import "dart:_internal" as _symbol_dev;
 import 'dart:_interceptors';
 import 'dart:_js_helper' show patch,
-                              patch_new,
-                              patch_old,
+                              patch_full,
+                              patch_lazy,
                               checkInt,
                               getRuntimeType,
                               jsonEncodeNative,
@@ -60,7 +60,7 @@
 // Patch for Function implementation.
 @patch
 class Function {
-  @patch_old
+  @patch_full
   static apply(Function function,
                List positionalArguments,
                [Map<Symbol, dynamic> namedArguments]) {
@@ -69,7 +69,7 @@
         namedArguments == null ? null : _toMangledNames(namedArguments));
   }
 
-  @patch_new
+  @patch_lazy
   static apply(Function function,
                List positionalArguments,
                [Map<Symbol, dynamic> namedArguments]) {
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_serialization.dart b/sdk/lib/_internal/js_runtime/lib/isolate_serialization.dart
index 9230bba..ba8f66b 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_serialization.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_serialization.dart
@@ -61,6 +61,7 @@
     if (x is _WorkerSendPort) return serializeWorkerSendPort(x);
 
     if (x is Closure) return serializeClosure(x);
+    if (x is CapabilityImpl) return serializeCapability(x);
 
     return serializeDartObject(x);
   }
@@ -204,6 +205,7 @@
       case "raw sendport": return deserializeRawSendPort(x);
       case "js-object": return deserializeJSObject(x);
       case "function": return deserializeClosure(x);
+      case "capability": return deserializeCapability(x);
       case "dart": return deserializeDartObject(x);
       default: throw "couldn't deserialize: $x";
     }
@@ -345,6 +347,12 @@
     return result;
   }
 
+  // ['capability', <id>].
+  Capability deserializeCapability(x) {
+    assert(x[0] == 'capability');
+    return new CapabilityImpl._internal(x[1]);
+  }
+
   // ['dart', <class-id>, <field-list>].
   deserializeDartObject(x) {
     assert(x[0] == 'dart');
diff --git a/sdk/lib/_internal/js_runtime/lib/js_number.dart b/sdk/lib/_internal/js_runtime/lib/js_number.dart
index b340247..907da4e 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_number.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_number.dart
@@ -132,7 +132,7 @@
   String toStringAsFixed(int fractionDigits) {
     checkInt(fractionDigits);
     if (fractionDigits < 0 || fractionDigits > 20) {
-      throw new RangeError(fractionDigits);
+      throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
     }
     String result = JS('String', r'#.toFixed(#)', this, fractionDigits);
     if (this == 0 && isNegative) return "-$result";
@@ -144,7 +144,7 @@
     if (fractionDigits != null) {
       checkInt(fractionDigits);
       if (fractionDigits < 0 || fractionDigits > 20) {
-        throw new RangeError(fractionDigits);
+        throw new RangeError.range(fractionDigits, 0, 20, "fractionDigits");
       }
       result = JS('String', r'#.toExponential(#)', this, fractionDigits);
     } else {
@@ -157,7 +157,7 @@
   String toStringAsPrecision(int precision) {
     checkInt(precision);
     if (precision < 1 || precision > 21) {
-      throw new RangeError(precision);
+      throw new RangeError.range(precision, 1, 21, "precision");
     }
     String result = JS('String', r'#.toPrecision(#)',
                        this, precision);
@@ -390,10 +390,14 @@
 
   // Returns pow(this, e) % m.
   int modPow(int e, int m) {
-    if (e is! int) throw argumentErrorValue(e);
-    if (m is! int) throw argumentErrorValue(m);
-    if (e < 0) throw new RangeError(e);
-    if (m <= 0) throw new RangeError(m);
+    if (e is! int) {
+      throw new ArgumentError.value(e, "exponent", "not an integer");
+    }
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (e < 0) throw new RangeError.range(e, 0, null, "exponent");
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (e == 0) return 1;
     int b = this;
     if (b < 0 || b > m) {
@@ -412,7 +416,7 @@
 
   // If inv is false, returns gcd(x, y).
   // If inv is true and gcd(x, y) = 1, returns d, so that c*x + d*y = 1.
-  // If inv is true and gcd(x, y) != 1, throws RangeError("Not coprime").
+  // If inv is true and gcd(x, y) != 1, throws Exception("Not coprime").
   static int _binaryGcd(int x, int y, bool inv) {
     int s = 1;
     if (!inv) {
@@ -472,7 +476,7 @@
       }
     } while (u != 0);
     if (!inv) return s*v;
-    if (v != 1) throw new RangeError("Not coprime");
+    if (v != 1) throw new Exception("Not coprime");
     if (d < 0) {
       d += x;
       if (d < 0) d += x;
@@ -485,22 +489,29 @@
 
   // Returns 1/this % m, with m > 0.
   int modInverse(int m) {
-    if (m is! int) throw new ArgumentError(m);
-    if (m <= 0) throw new RangeError(m);
+    if (m is! int) {
+      throw new ArgumentError.value(m, "modulus", "not an integer");
+    }
+    if (m <= 0) throw new RangeError.range(m, 1, null, "modulus");
     if (m == 1) return 0;
     int t = this;
     if ((t < 0) || (t >= m)) t %= m;
     if (t == 1) return 1;
-    if ((t == 0) || (t.isEven && m.isEven)) throw new RangeError("Not coprime");
+    if ((t == 0) || (t.isEven && m.isEven)) {
+      throw new Exception("Not coprime");
+    }
     return _binaryGcd(m, t, true);
   }
 
-  // Returns gcd of abs(this) and abs(other), with this != 0 and other !=0.
+  // Returns gcd of abs(this) and abs(other).
   int gcd(int other) {
-    if (other is! int) throw new ArgumentError(other);
-    if ((this == 0) || (other == 0)) throw new RangeError(0);
+    if (other is! int) {
+      throw new ArgumentError.value(other, "other", "not an integer");
+    }
     int x = this.abs();
     int y = other.abs();
+    if (x == 0) return y;
+    if (y == 0) return x;
     if ((x == 1) || (y == 1)) return 1;
     return _binaryGcd(x, y, false);
   }
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 7256445..428e878 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -1664,7 +1664,7 @@
 }
 
 /**
- * An [Iterable] like interface for the values of a [Stream].
+ * An [Iterator] like interface for the values of a [Stream].
  *
  * This wraps a [Stream] and a subscription on the stream. It listens
  * on the stream, and completes the future returned by [moveNext] when the
@@ -1681,19 +1681,30 @@
   /**
    * Wait for the next stream value to be available.
    *
-   * It is not allowed to call this function again until the future has
-   * completed. If the returned future completes with anything except `true`,
-   * the iterator is done, and no new value will ever be available.
+   * Returns a future which will complete with either `true` or `false`.
+   * Completing with `true` means that another event has been received and
+   * can be read as [current].
+   * Completing with `false` means that the stream itearation is done and
+   * no further events will ever be available.
+   * The future may complete with an error, if the stream produces an error,
+   * which also ends iteration.
    *
-   * The future may complete with an error, if the stream produces an error.
+   * The function must not be called again until the future returned by a
+   * previous call is completed.
    */
   Future<bool> moveNext();
 
   /**
    * The current value of the stream.
    *
-   * Only valid when the future returned by [moveNext] completes with `true`
-   * as value, and only until the next call to [moveNext].
+   * Is `null` before the first call to [moveNext] and after a call to
+   * `moveNext` completes with a `false` result or an error.
+   *
+   * When a `moveNext` call completes with `true`, the `current` field holds
+   * the most recent event of the stream, and it stays like that until the next
+   * call to `moveNext`.
+   * Between a call to `moveNext` and when its returned future completes,
+   * the value is unspecified.
    */
   T get current;
 
@@ -1703,13 +1714,14 @@
    * The stream iterator is automatically canceled if the [moveNext] future
    * completes with either `false` or an error.
    *
-   * If a [moveNext] call has been made, it will complete with `false` as value,
-   * as will all further calls to [moveNext].
-   *
    * If you need to stop listening for values before the stream iterator is
    * automatically closed, you must call [cancel] to ensure that the stream
    * is properly closed.
    *
+   * If [moveNext] has been called when the iterator is cancelled,
+   * its returned future will complete with `false` as value,
+   * as will all further calls to [moveNext].
+   *
    * Returns a future if the cancel-operation is not completed synchronously.
    * Otherwise returns `null`.
    */
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 38af7af..7484ed5 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -18,15 +18,15 @@
  * until the actual exceptions used by a library are done.
  */
 abstract class Exception {
-  factory Exception([var message]) => new _ExceptionImplementation(message);
+  factory Exception([var message]) => new _Exception(message);
 }
 
 
 /** Default implementation of [Exception] which carries a message. */
-class _ExceptionImplementation implements Exception {
+class _Exception implements Exception {
   final message;
 
-  _ExceptionImplementation([this.message]);
+  _Exception([this.message]);
 
   String toString() {
     if (message == null) return "Exception";
@@ -174,6 +174,7 @@
   }
 }
 
+// Exception thrown when doing integer division with a zero divisor.
 class IntegerDivisionByZeroException implements Exception {
   const IntegerDivisionByZeroException();
   String toString() => "IntegerDivisionByZeroException";
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 16a1e07..98f7da8 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -88,7 +88,7 @@
    * limit intermediate values by using the "and" operator with a suitable
    * mask.
    *
-   * It is an error of [shiftAmount] is negative.
+   * It is an error if [shiftAmount] is negative.
    */
   int operator <<(int shiftAmount);
 
@@ -99,7 +99,7 @@
    * significant bits, effectively doing an integer division by
    *`pow(2, shiftIndex)`.
    *
-   * It is an error of [shiftAmount] is negative.
+   * It is an error if [shiftAmount] is negative.
    */
   int operator >>(int shiftAmount);
 
@@ -116,15 +116,23 @@
    * modulo [modulus].
    *
    * The [modulus] must be positive.
-   * Throws if no modular inverse exists.
+   *
+   * It is an error if no modular inverse exists.
    */
   int modInverse(int modulus);
 
   /**
-   * Returns the greatest common divisor of the absolute value of
-   * this integer and the absolute value of [other].
+   * Returns the greatest common divisor of this integer and [other].
    *
-   * Both this and [other] must be non-zero.
+   * If either number is non-zero, the result is the numerically greatest
+   * integer dividing both `this` and `other`.
+   *
+   * The greatest common divisor is independent of the order,
+   * so `x.gcd(y)` is  always the same as `y.gcd(x)`.
+   *
+   * For any integer `x`, `x.gcd(x)` is `x.abs()`.
+   *
+   * If both `this` and `other` is zero, the result is also zero.
    */
   int gcd(int other);
 
@@ -266,27 +274,29 @@
    * Converts [this] to a string representation in the given [radix].
    *
    * In the string representation, lower-case letters are used for digits above
-   * '9'.
+   * '9', with 'a' being 10 an 'z' being 35.
    *
    * The [radix] argument must be an integer in the range 2 to 36.
    */
   String toRadixString(int radix);
 
   /**
-   * Parse [source] as an integer literal and return its value.
-   *
-   * The [radix] must be in the range 2..36. The digits used are
-   * first the decimal digits 0..9, and then the letters 'a'..'z'.
-   * Accepts capital letters as well.
-   *
-   * If no [radix] is given then it defaults to 10, unless the string starts
-   * with "0x", "-0x" or "+0x", in which case the radix is set to 16 and the
-   * "0x" is ignored.
+   * Parse [source] as a, possibly signed, integer literal and return its value.
    *
    * The [source] must be a non-empty sequence of base-[radix] digits,
    * optionally prefixed with a minus or plus sign ('-' or '+').
    *
-   * It must always be the case for an int [:n:] and radix [:r:] that
+   * The [radix] must be in the range 2..36. The digits used are
+   * first the decimal digits 0..9, and then the letters 'a'..'z' with
+   * values 10 through 35. Also accepts upper-case letters with the same
+   * values as the lower-case ones.
+   *
+   * If no [radix] is given then it defaults to 10. In this case, the [source]
+   * digits may also start with `0x`, in which case the number is interpreted
+   * as a hexadecimal literal, which effectively means that the `0x` is ignored
+   * and the radix is instead set to 16.
+   *
+   * For any int [:n:] and radix [:r:], it is guaranteed that
    * [:n == int.parse(n.toRadixString(r), radix: r):].
    *
    * If the [source] is not a valid integer literal, optionally prefixed by a
diff --git a/tests/benchmark_smoke/benchmark_smoke.status b/tests/benchmark_smoke/benchmark_smoke.status
index fea516e0..d3fe9a3 100644
--- a/tests/benchmark_smoke/benchmark_smoke.status
+++ b/tests/benchmark_smoke/benchmark_smoke.status
@@ -8,4 +8,3 @@
 [ $compiler == dart2js && $runtime == none ]
 *: Fail, Pass # TODO(ahe): Triage these tests.
 
-[ $compiler == dart2js && $cps_ir ]
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index de69117..97a467e 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -2649,7 +2649,6 @@
 LayoutTests/fast/table/border-changes_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/caption-orthogonal-writing-mode-sizing_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/css-table-max-width_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/table/incorrect-colgroup-span-values_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/large-shrink-wrapped-width_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/min-width-css-block-table_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/min-width-css-inline-table_t01: RuntimeError # Please triage this failure
@@ -3124,6 +3123,7 @@
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/MutationObserver/observe-options-attributes_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/MutationObserver/observe-options-character-data_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/table/incorrect-colgroup-span-values_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xmlhttprequest/xmlhttprequest-responsetype-before-open_t01: RuntimeError # Please triage this failure
 LibTest/html/HttpRequest/responseType_A01_t02: RuntimeError # Please triage this failure
 
@@ -9602,236 +9602,189 @@
 WebPlatformTest/webstorage/storage_session_setitem_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $cps_ir ]
-Language/12_Expressions/05_Strings/1_String_Interpolation_A01_t12: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/05_Strings/1_String_Interpolation_A02_t02: RuntimeError # Cannot read property 'prototype' of undefined
 Language/12_Expressions/12_Instance_Creation/1_New_A06_t12: RuntimeError # Please triage this failure.
-Language/12_Expressions/13_Property_Extraction_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/13_Property_Extraction_A01_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/13_Property_Extraction_A01_t03: RuntimeError # Cannot read property 'prototype' of undefined
 Language/12_Expressions/13_Property_Extraction_A03_t01: RuntimeError # Cannot read property 'call' of undefined
 Language/12_Expressions/13_Property_Extraction_A03_t02: RuntimeError # Cannot read property 'call' of undefined
 Language/12_Expressions/13_Property_Extraction_A03_t03: RuntimeError # Cannot read property 'call' of undefined
 Language/12_Expressions/13_Spawning_an_Isolate_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-Language/12_Expressions/15_Method_Invocation/1_Ordinary_Invocation_A05_t04: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t05: RuntimeError # Cannot read property 'prototype' of undefined
 Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A01_t01: RuntimeError # Cannot read property 'call' of undefined
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A03_t04: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/29_Assignable_Expressions_A01_t08: RuntimeError # receiver.get$_first is not a function
 Language/12_Expressions/30_Identifier_Reference_A09_t03: Crash # (i=0): For-loop variable captured in loop header
-Language/12_Expressions/30_Identifier_Reference_A10_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/12_Expressions/30_Identifier_Reference_A10_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/13_Statements/02_Expression_Statements_A01_t06: RuntimeError # Cannot read property 'prototype' of undefined
 Language/13_Statements/06_For_A01_t07: Crash # unsupported operation on erroneous element
 Language/13_Statements/12_Labels_A03_t04: Crash # (switch (i){L:case 0:flag=true;break;case 2:continue L;}): continue to a labeled switch case
 Language/13_Statements/14_Continue_A02_t12: Crash # (switch (2){L:case 1:flag=true;break;case 2:continue L;}): continue to a labeled switch case
 Language/13_Statements/14_Continue_A02_t13: Crash # (switch (2){case 2:continue L;L:case 1:flag=true;}): continue to a labeled switch case
-Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-Language/15_Types/3_Type_Declarations/1_Typedef_A02_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/3_Type_Declarations/1_Typedef_A02_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/3_Type_Declarations/1_Typedef_A02_t03: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/3_Type_Declarations/1_Typedef_A03_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/3_Type_Declarations/1_Typedef_A04_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/4_Interface_Types_A12_t18: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t03: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t04: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t05: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t06: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t08: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t09: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A01_t11: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t03: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t04: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t05: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t09: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A02_t10: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t01: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t03: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t04: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t06: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t08: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t09: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t10: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t11: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t12: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A03_t13: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A05_t02: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A05_t05: RuntimeError # Cannot read property 'prototype' of undefined
-Language/15_Types/5_Function_Types_A06_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/async/Completer/Completer.sync_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/completeError_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t05: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A01_t06: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/complete_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Completer/isCompleted_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.delayed_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.delayed_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.delayed_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.error_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.microtask_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.sync_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.value_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future.value_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/Future_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/asStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/asStream_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/asStream_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/asStream_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/Completer.sync_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/completeError_A03_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t05: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A01_t06: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/complete_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Completer/isCompleted_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.delayed_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.delayed_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.delayed_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.error_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.microtask_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.microtask_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.microtask_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.microtask_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.sync_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.sync_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.sync_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.sync_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.value_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future.value_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/Future_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/asStream_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/asStream_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/asStream_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/asStream_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/catchError_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/catchError_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/catchError_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/catchError_A03_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Future/catchError_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A03_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/catchError_A03_t04: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Future/catchError_A03_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/catchError_A03_t04: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Future/catchError_A03_t05: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/forEach_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/forEach_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Future/forEach_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/forEach_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Future/forEach_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Future/then_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A03_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A04_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Future/then_A05_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Future/then_A05_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/then_A05_t03: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Future/then_A05_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/then_A05_t03: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Future/wait_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Future/wait_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Future/wait_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Future/wait_A01_t05: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Future/wait_A01_t06: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Future/wait_A01_t07: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/wait_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/whenComplete_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/whenComplete_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/whenComplete_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/whenComplete_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Future/whenComplete_A04_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Future/wait_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/wait_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/whenComplete_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/whenComplete_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/whenComplete_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/whenComplete_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Future/whenComplete_A04_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/Stream.eventTransformed_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/Stream.eventTransformed_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromFuture_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.fromIterable_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A01_t01 : RuntimeError # TypeError: receiver.get$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream.periodic_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/Stream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/any_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/any_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/any_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/Stream.fromFuture_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.fromFuture_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.fromFuture_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.fromIterable_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.fromIterable_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.fromIterable_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.periodic_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.periodic_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream.periodic_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/Stream_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/any_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/any_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/any_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/asBroadcastStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A01_t04: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A03_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/asBroadcastStream_A03_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/asBroadcastStream_A03_t03: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/asBroadcastStream_A04_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/asBroadcastStream_A04_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/asBroadcastStream_A04_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/contains_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/contains_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/contains_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/distinct_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/distinct_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/drain_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/drain_A02_t01 : RuntimeError # TypeError: receiver.get$_nums is not a function
-LibTest/async/Stream/drain_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/elementAt_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/elementAt_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/elementAt_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/elementAt_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/every_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/every_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/contains_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/contains_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/contains_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/distinct_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/distinct_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/drain_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/drain_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/drain_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/elementAt_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/elementAt_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/elementAt_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/elementAt_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/every_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/every_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/expand_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/firstWhere_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/firstWhere_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/firstWhere_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/firstWhere_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/first_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/first_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/first_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/first_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/fold_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/fold_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/firstWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/firstWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/firstWhere_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/firstWhere_A03_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/first_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/first_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/first_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/first_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/fold_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/fold_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/forEach_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/forEach_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/forEach_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/forEach_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/handleError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/handleError_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/handleError_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A04_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/handleError_A04_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/isBroadcast_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/isBroadcast_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/isEmpty_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/join_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/join_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/join_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/join_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/lastWhere_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/lastWhere_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/lastWhere_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/lastWhere_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/last_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/last_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/last_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/length_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/handleError_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/handleError_A04_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/handleError_A04_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/isBroadcast_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/isBroadcast_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/isEmpty_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/join_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/join_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/join_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/join_A02_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/lastWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/lastWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/lastWhere_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/lastWhere_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/last_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/last_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/last_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/length_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/listen_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/listen_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/listen_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A05_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A05_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A05_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/listen_A06_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/listen_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/listen_A05_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/listen_A05_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/listen_A05_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/listen_A06_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/map_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/pipe_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/reduce_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/reduce_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/reduce_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/singleWhere_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/singleWhere_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/single_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/single_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/skipWhile_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/skip_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/takeWhile_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/take_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/take_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Stream/take_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Stream/reduce_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/reduce_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/reduce_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/singleWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/singleWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/single_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/single_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/skipWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/skip_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/takeWhile_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/take_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/take_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Stream/take_A01_t03: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/toList_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/Stream/toSet_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/transform_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
@@ -9839,77 +9792,77 @@
 LibTest/async/Stream/where_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Stream/where_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamController/StreamController.broadcast_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A05_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A06_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A07_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A07_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController.broadcast_A08_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A03_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A05_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A06_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A07_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A07_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController.broadcast_A08_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamController/StreamController_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A04_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A05_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A06_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/StreamController_A06_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/addError_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamController/StreamController_A04_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController_A05_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController_A06_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/StreamController_A06_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/addError_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/addError_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamController/addStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamController/addStream_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamController/addStream_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamController/addStream_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamController/addStream_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/add_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/close_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/close_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/done_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/done_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/done_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/hasListener_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/hasListener_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/isClosed_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/isClosed_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/isPaused_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/sink_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamController/stream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamIterator/StreamIterator_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamController/add_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/close_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/close_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/done_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/done_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/done_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/hasListener_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/hasListener_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/isClosed_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/isClosed_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/isPaused_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/isPaused_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/isPaused_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/sink_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamController/stream_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamIterator/StreamIterator_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamIterator/cancel_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamIterator/current_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamIterator/moveNext_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamIterator/moveNext_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/addError_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamIterator/current_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamIterator/moveNext_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamIterator/moveNext_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamSink/addError_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamSink/addStream_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamSink/addStream_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamSink/addStream_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamSink/addStream_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamSink/addStream_A01_t04: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamSink/addStream_A01_t05: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamSink/add_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamSink/close_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamSink/done_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t03: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamTransformer/StreamTransformer.fromHandlers_A01_t04: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamTransformer/StreamTransformer_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/StreamTransformer/StreamTransformer_A03_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/StreamTransformer/StreamTransformer_A03_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/StreamTransformer/StreamTransformer_A03_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/async/StreamTransformer/bind_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/Timer.periodic_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/Timer.periodic_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/Timer_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/Timer_A02_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/cancel_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/isActive_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/isActive_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/run_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/async/Timer/run_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Timer/Timer.periodic_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/Timer.periodic_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/Timer_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/Timer_A02_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/cancel_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/isActive_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/isActive_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/run_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/async/Timer/run_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/bindBinaryCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/bindBinaryCallback_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/bindCallback_A01_t01: RuntimeError # receiver.get$_nums is not a function
@@ -9941,55 +9894,41 @@
 LibTest/async/Zone/runUnaryGuarded_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/runUnary_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/run_A01_t01: RuntimeError # receiver.get$_nums is not a function
-LibTest/async/Zone/scheduleMicrotask_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/async/Zone/scheduleMicrotask_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/async/Zone/scheduleMicrotask_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/collection/ListBase/ListBase_class_A01_t02: Crash # Stack Overflow
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Crash # Stack Overflow
-LibTest/convert/JsonCodec/encode_A01_t01: Crash # Internal Error: No default constructor available.
-LibTest/convert/JsonCodec/encode_A01_t02: Crash # Internal Error: No default constructor available.
-LibTest/convert/JsonDecoder/fuse_A01_t01: Crash # Internal Error: No default constructor available.
-LibTest/convert/JsonEncoder/convert_A01_t01: Crash # Internal Error: No default constructor available.
-LibTest/core/DateTime/parse_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/DateTime/parse_A01_t02: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/DateTime/parse_A03_t01: Pass # Please triage this failure.
-LibTest/core/DateTime/timeZoneName_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
 LibTest/core/Invocation/isAccessor_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-LibTest/core/Invocation/isGetter_A01_t01 : RuntimeError # 
-LibTest/core/Invocation/isGetter_A01_t02 : RuntimeError # 
+LibTest/core/Invocation/isGetter_A01_t01: RuntimeError # Please triage this failure.
+LibTest/core/Invocation/isGetter_A01_t02: RuntimeError # Please triage this failure.
 LibTest/core/Invocation/isMethod_A01_t02: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
 LibTest/core/Invocation/isSetter_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-LibTest/core/Invocation/isSetter_A01_t02 : RuntimeError # 
+LibTest/core/Invocation/isSetter_A01_t02: RuntimeError # Please triage this failure.
 LibTest/core/Invocation/memberName_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-LibTest/core/Invocation/positionalArguments_A01_t01 : RuntimeError # 
+LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError # Please triage this failure.
+LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # Please triage this failure.
 LibTest/core/List/List_class_A01_t02: Crash # Stack Overflow
-LibTest/core/Match/end_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/Match/groupCount_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/NoSuchMethodError/toString_A01_t01: RuntimeError # receiver.get$_first is not a function
-LibTest/core/RegExp/stringMatch_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/Stopwatch/Stopwatch_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/frequency_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
-LibTest/core/Stopwatch/start_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/start_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/start_A01_t03: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/start_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/start_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # receiver.get$_nums is not a function
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Please triage this failure.
 LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Please triage this failure.
 LibTest/core/double/INFINITY_A01_t04: Pass # Please triage this failure.
 LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Pass # Please triage this failure.
-LibTest/core/int/parse_A01_t01: RuntimeError # Cannot read property 'prototype' of undefined
 LibTest/isolate/Isolate/spawnUri_A02_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/isolate/Isolate/spawnUri_A02_t03: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/isolate/Isolate/spawnUri_A02_t04: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/isolate/Isolate/spawn_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/Isolate/spawn_A01_t02: RuntimeError # receiver.get$_nums is not a function
+LibTest/isolate/Isolate/spawn_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
 LibTest/isolate/Isolate/spawn_A01_t03: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # receiver.get$_nums is not a function
@@ -10019,7 +9958,7 @@
 LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/drain_A02_t01 : RuntimeError # TypeError: receiver.get$_nums is not a function
+LibTest/isolate/ReceivePort/drain_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/drain_A02_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/elementAt_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/elementAt_A03_t01: RuntimeError # receiver.get$_nums is not a function
@@ -10034,12 +9973,12 @@
 LibTest/isolate/ReceivePort/fold_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/fold_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/forEach_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/isBroadcast_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
-LibTest/isolate/ReceivePort/isBroadcast_A01_t02: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/isolate/ReceivePort/isBroadcast_A01_t01: RuntimeError # receiver.get$_nums is not a function
+LibTest/isolate/ReceivePort/isBroadcast_A01_t02: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/isEmpty_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/join_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/join_A01_t02: RuntimeError # receiver.get$_nums is not a function
-LibTest/isolate/ReceivePort/lastWhere_A01_t01: RuntimeError # receiver.get$_collection$_nums is not a function
+LibTest/isolate/ReceivePort/lastWhere_A01_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/lastWhere_A02_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/lastWhere_A04_t01: RuntimeError # receiver.get$_nums is not a function
 LibTest/isolate/ReceivePort/last_A01_t01: RuntimeError # receiver.get$_nums is not a function
@@ -10098,4 +10037,3 @@
 LibTest/typed_data/Uint8List/setAll_A01_t01: RuntimeError # this.get$length is not a function
 LibTest/typed_data/Uint8List/setRange_A01_t01: RuntimeError # this.get$length is not a function
 LibTest/typed_data/Uint8List/setRange_A02_t01: RuntimeError # this.get$length is not a function
-LibTest/core/Invocation/namedArguments_A01_t01 : RuntimeError # 
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
index 07f049c..db3923a 100644
--- a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -38,6 +38,10 @@
   "lib/src/constants/expressions.dart": const [
       "The method 'readFromEnvironment' is never called"],
 
+  // Serialization code is only used in test.
+  "lib/src/serialization/": const [
+      "is never"],
+
   // Nested functions are currently kept alive in the IR.
   "lib/src/tree_ir/": const [
     "accept", "FunctionExpression", "CreateFunction"
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index fa809e3..82511ce 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -42,6 +42,10 @@
 backend_dart/opt_shrinking_test: Skip
 backend_dart/opt_redundant_phi_test: Skip
 
+# These tests run the compiler multiple times.
+js_backend_cps_ir_basic_test: Pass, Slow
+js_backend_cps_ir_closures_test: Pass, Slow
+
 [ $unchecked ]
 exit_code_test: Skip # This tests requires checked mode.
 
@@ -70,8 +74,6 @@
 exit_code_test: Pass, Slow
 import_mirrors_test: Pass, Slow
 in_user_code_test: Pass, Slow
-js_backend_cps_ir_basic_test: Pass, Slow
-js_backend_cps_ir_closures_test: Pass, Slow
 message_kind_test: Pass, Slow
 show_package_warnings_test: Pass, Slow
 source_map_pub_build_validity_test: Pass, Slow
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 97b53e7..42d4e5a 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
@@ -106,6 +106,86 @@
 function() {
   return new V.A_b_closure(this);
 }"""),
+
+  const TestEntry("""
+staticMethod(x) => x;
+main(x) {
+  var tearOff = staticMethod;
+  print(tearOff(123));
+}
+""",
+r"""
+function(x) {
+  P.print(V.staticMethod(123));
+}"""),
+
+  const TestEntry("""
+class Foo {
+  instanceMethod(x) => x;
+}
+main(x) {
+  var tearOff = new Foo().instanceMethod;
+  print(tearOff(123));
+}
+""",
+r"""
+function(x) {
+  P.print(V.Foo$().instanceMethod$1(123));
+}"""),
+
+  const TestEntry("""
+class Foo {
+  instanceMethod(x) => x;
+}
+main(x) {
+  var tearOff = new Foo().instanceMethod;
+  print(tearOff(123));
+  print(tearOff(321));
+}
+""",
+r"""
+function(x) {
+  var v0 = V.Foo$();
+  P.print(v0.instanceMethod$1(123));
+  P.print(v0.instanceMethod$1(321));
+}"""),
+
+  const TestEntry("""
+class Foo {
+  get getter {
+    print('getter');
+    return (x) => x;
+  }
+}
+main(x) {
+  var notTearOff = new Foo().getter;
+  print(notTearOff(123));
+  print(notTearOff(321));
+}
+""",
+r"""
+function(x) {
+  var notTearOff = V.Foo$().get$getter();
+  P.print(notTearOff.call$1(123));
+  P.print(notTearOff.call$1(321));
+}"""),
+
+  const TestEntry("""
+class Foo {
+  get getter {
+    print('getter');
+    return (x) => x;
+  }
+}
+main(x) {
+  var notTearOff = new Foo().getter;
+  print(notTearOff(123));
+}
+""",
+r"""
+function(x) {
+  P.print(V.Foo$().getter$1(123));
+}"""),
 ];
 
 void main() {
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
index b6fc9ad..b16a1a8 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart
@@ -57,11 +57,11 @@
 }""", """
 function() {
   var i = 0;
-  L1:
+  L2:
     while (P.identical(V.foo(true), true)) {
       P.print(1);
       if (P.identical(V.foo(false), true))
-        break L1;
+        break L2;
       i = V.foo(i);
     }
   P.print(2);
diff --git a/tests/compiler/dart2js/memory_source_file_helper.dart b/tests/compiler/dart2js/memory_source_file_helper.dart
index 4efb8ad..0a0428b 100644
--- a/tests/compiler/dart2js/memory_source_file_helper.dart
+++ b/tests/compiler/dart2js/memory_source_file_helper.dart
@@ -14,7 +14,7 @@
        show currentDirectory;
 
 import 'package:compiler/src/io/source_file.dart'
-       show StringSourceFile;
+       show StringSourceFile, SourceFile;
 
 import 'package:compiler/src/source_file_provider.dart'
        show SourceFileProvider;
@@ -41,4 +41,15 @@
   }
 
   Future<String> call(Uri resourceUri) => readStringFromUri(resourceUri);
+
+  SourceFile getSourceFile(Uri resourceUri) {
+    if (resourceUri.scheme != 'memory') {
+      return super.getSourceFile(resourceUri);
+    }
+    String source = memorySourceFiles[resourceUri.path];
+    if (source == null) {
+      throw new Exception('No such file $resourceUri');
+    }
+    return new StringSourceFile.fromUri(resourceUri, source);
+  }
 }
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 296e18b..a9f96ef 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -194,8 +194,8 @@
   'numTypeCheck': 'numTypeCheck(value) {}',
   '_Patch': 'class _Patch { final tag; const _Patch(this.tag); }',
   'patch': 'const patch = const _Patch(null);',
-  'patch_new': 'const patch_new = const _Patch("new");',
-  'patch_old': 'const patch_old = const _Patch("old");',
+  'patch_full': 'const patch_full = const _Patch("full");',
+  'patch_lazy': 'const patch_lazy = const _Patch("lazy");',
   'propertyTypeCast': 'propertyTypeCast(x) {}',
   'propertyTypeCheck': 'propertyTypeCheck(value, property) {}',
   'requiresPreamble': 'requiresPreamble() {}',
diff --git a/tests/compiler/dart2js/output_collector.dart b/tests/compiler/dart2js/output_collector.dart
index c6bc101..d2d3af4 100644
--- a/tests/compiler/dart2js/output_collector.dart
+++ b/tests/compiler/dart2js/output_collector.dart
@@ -26,6 +26,29 @@
   }
 }
 
+class CloningEventSink implements EventSink<String> {
+  final List<EventSink<String>> sinks;
+
+  CloningEventSink(this.sinks);
+
+  @override
+  void add(String event) {
+    sinks.forEach((EventSink<String> sink) => sink.add(event));
+  }
+
+  @override
+  void addError(errorEvent, [StackTrace stackTrace]) {
+    sinks.forEach((EventSink<String> sink) {
+      sink.addError(errorEvent, stackTrace);
+    });
+  }
+
+  @override
+  void close() {
+    sinks.forEach((EventSink<String> sink) => sink.close());
+  }
+}
+
 class OutputCollector {
   Map<String, Map<String, BufferedEventSink>> outputMap = {};
 
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 6f59878..c198012 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -136,13 +136,13 @@
 
 
 testPatchVersioned() {
-  String oldPatch = "test(){return 'string';}";
-  String newPatch = "test(){return 'new and improved string';}";
+  String fullPatch = "test(){return 'string';}";
+  String lazyPatch = "test(){return 'new and improved string';}";
 
   String patchSource =
       """
-      @patch_old $oldPatch 
-      @patch_new $newPatch 
+      @patch_full $fullPatch
+      @patch_lazy $lazyPatch
       """;
 
   test(String patchVersion,
@@ -192,11 +192,11 @@
     }));
   }
 
-  test('old', patchText: oldPatch);
-  test('new', patchText: newPatch);
+  test('full', patchText: fullPatch);
+  test('lazy', patchText: lazyPatch);
   test('unknown', expectIsPatched: false,
        expectedError: 'External method without an implementation.');
-  test('old',
+  test('full',
        defaultPatch: "@patch test(){}",
        expectedInternalError: "Trying to patch a function more than once.");
 }
diff --git a/tests/compiler/dart2js/serialization_analysis_test.dart b/tests/compiler/dart2js/serialization_analysis_test.dart
new file mode 100644
index 0000000..775f6741
--- /dev/null
+++ b/tests/compiler/dart2js/serialization_analysis_test.dart
@@ -0,0 +1,237 @@
+// 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.serialization_analysis_test;
+
+import 'dart:async';
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/serialization/serialization.dart';
+import 'package:compiler/src/serialization/json_serializer.dart';
+import 'package:compiler/src/serialization/task.dart';
+import 'package:compiler/src/dart2jslib.dart';
+import 'package:compiler/src/filenames.dart';
+import 'memory_compiler.dart';
+
+const List<Test> TESTS = const <Test>[
+  const Test(const {
+    'main.dart': 'main() => print("Hello World");'
+  }),
+
+  const Test(const {
+    'main.dart': 'main() => print("Hello World", 0);'
+  },
+  expectedWarningCount: 1,
+  expectedInfoCount: 1),
+
+  const Test(const {
+    'main.dart': r'''
+main() {
+  String text = "Hello World";
+  print('$text');
+}'''
+  }),
+
+  const Test(const {
+    'main.dart': r'''
+main() {
+  String text = "Hello World";
+  print('$text', text);
+}'''
+  },
+  expectedWarningCount: 1,
+  expectedInfoCount: 1),
+
+  const Test(const {
+    'main.dart': r'''
+main(List<String> arguments) {
+  print(arguments);
+}'''
+  }),
+
+  const Test(const {
+      'main.dart': r'''
+main(List<String> arguments) {
+  for (int i = 0; i < arguments.length; i++) {
+    print(arguments[i]);
+  }
+}'''
+    }),
+
+  const Test(const {
+    'main.dart': r'''
+main(List<String> arguments) {
+  for (String argument in arguments) {
+    print(argument);
+  }
+}'''
+  }),
+
+  const Test(const {
+    'main.dart': r'''
+class Class {}
+main() {
+  print(new Class());
+}'''
+  }),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Function {}
+main() {
+  print(new Class());
+}'''
+  },
+  expectedWarningCount: 1),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Function {
+  call() {}
+}
+main() {
+  print(new Class()());
+}'''
+  }),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Comparable<Class> {
+  int compareTo(Class other) => 0;
+}
+main() {
+  print(new Class());
+}'''
+  }),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Comparable<Class, Class> {
+  int compareTo(other) => 0;
+}
+main() {
+  print(new Class());
+}'''
+  },
+  expectedWarningCount: 1),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Comparable<Class> {
+  int compareTo(String other) => 0;
+}
+main() {
+  print(new Class().compareTo(null));
+}'''
+  },
+  expectedWarningCount: 1,
+  expectedInfoCount: 1),
+
+  const Test(const {
+    'main.dart': r'''
+class Class implements Comparable {
+  bool compareTo(a, b) => true;
+}
+main() {
+  print(new Class().compareTo(null, null));
+}'''
+  },
+  expectedWarningCount: 1,
+  expectedInfoCount: 1),
+];
+
+main(List<String> arguments) {
+  asyncTest(() async {
+    String serializedData = await serializeDartCore();
+
+    if (arguments.isNotEmpty) {
+      Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.last));
+      await analyze(serializedData, entryPoint, null);
+    } else {
+      Uri entryPoint = Uri.parse('memory:main.dart');
+      for (Test test in TESTS) {
+        await analyze(serializedData, entryPoint, test);
+      }
+    }
+  });
+}
+
+class Test {
+  final Map sourceFiles;
+  final int expectedErrorCount;
+  final int expectedWarningCount;
+  final int expectedHintCount;
+  final int expectedInfoCount;
+
+  const Test(this.sourceFiles, {
+    this.expectedErrorCount: 0,
+    this.expectedWarningCount: 0,
+    this.expectedHintCount: 0,
+    this.expectedInfoCount: 0});
+}
+
+Future analyze(String serializedData, Uri entryPoint, Test test) async {
+  Deserializer deserializer = new Deserializer.fromText(
+      serializedData, const JsonSerializationDecoder());
+  DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
+  Compiler compiler = compilerFor(
+      test != null ? test.sourceFiles : const {},
+      options: ['--analyze-only', '--output-type=dart'],
+      diagnosticHandler: diagnosticCollector);
+  compiler.serialization.deserializer = new _DeserializerSystem(deserializer);
+  await compiler.runCompiler(entryPoint);
+  if (test != null) {
+    Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
+        "Unexpected error count.");
+    Expect.equals(
+        test.expectedWarningCount,
+        diagnosticCollector.warnings.length,
+        "Unexpected warning count.");
+    Expect.equals(test.expectedHintCount, diagnosticCollector.hints.length,
+        "Unexpected hint count.");
+    Expect.equals(test.expectedInfoCount, diagnosticCollector.infos.length,
+        "Unexpected info count.");
+  }
+}
+
+Future<String> serializeDartCore() async {
+  Compiler compiler = compilerFor({},
+      options: ['--analyze-all', '--output-type=dart']);
+  await compiler.runCompiler(Uri.parse('dart:core'));
+  return serialize(compiler.libraryLoader.libraries);
+}
+
+String serialize(Iterable<LibraryElement> libraries) {
+  Serializer serializer = new Serializer(const JsonSerializationEncoder());
+  for (LibraryElement library in libraries) {
+    serializer.serialize(library);
+  }
+  return serializer.toText();
+}
+
+class _DeserializerSystem extends DeserializerSystem {
+  final Deserializer _deserializer;
+  final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
+
+  _DeserializerSystem(this._deserializer);
+
+  LibraryElement readLibrary(Uri resolvedUri) {
+    LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
+    if (library != null) {
+      deserializedLibraries.add(library);
+    }
+    return library;
+  }
+
+  @override
+  WorldImpact computeWorldImpact(Element element) {
+    return const WorldImpact();
+  }
+
+  @override
+  bool isDeserialized(Element element) {
+    return deserializedLibraries.contains(element.library);
+  }
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/serialization_test.dart b/tests/compiler/dart2js/serialization_test.dart
new file mode 100644
index 0000000..a258c2d
--- /dev/null
+++ b/tests/compiler/dart2js/serialization_test.dart
@@ -0,0 +1,1049 @@
+// 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.serialization_test;
+
+import 'dart:io';
+import 'memory_compiler.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/constants/expressions.dart';
+import 'package:compiler/src/dart_types.dart';
+import 'package:compiler/src/dart2jslib.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/elements/visitor.dart';
+import 'package:compiler/src/ordered_typeset.dart';
+import 'package:compiler/src/serialization/serialization.dart';
+import 'package:compiler/src/serialization/json_serializer.dart';
+import 'package:compiler/src/tree/tree.dart';
+
+main(List<String> arguments) {
+  // Ensure that we can print out constant expressions.
+  DEBUG_MODE = true;
+
+  Uri entryPoint;
+  String outPath;
+  bool prettyPrint = false;
+  for (String arg in arguments) {
+    if (arg.startsWith('--')) {
+      if (arg.startsWith('--out=')) {
+        outPath = arg.substring('--out='.length);
+      } else if (arg == '--pretty-print') {
+        prettyPrint = true;
+      } else {
+        print("Unknown option $arg");
+      }
+    } else {
+      if (entryPoint != null) {
+        print("Multiple entrypoints is not supported.");
+      }
+      entryPoint = Uri.parse(arg);
+    }
+  }
+  if (entryPoint == null) {
+    entryPoint = Uri.parse('dart:core');
+  }
+  Compiler compiler = compilerFor({}, options: ['--analyze-all']);
+  asyncTest(() async {
+    await compiler.runCompiler(entryPoint);
+    testSerialization(compiler.libraryLoader.libraries,
+                      outPath: outPath,
+                      prettyPrint: prettyPrint);
+  });
+}
+
+void testSerialization(Iterable<LibraryElement> libraries1,
+                       {String outPath,
+                        bool prettyPrint}) {
+  Serializer serializer = new Serializer(const JsonSerializationEncoder());
+  for (LibraryElement library1 in libraries1) {
+    serializer.serialize(library1);
+  }
+  String text = serializer.toText();
+  String outText = text;
+  if (prettyPrint) {
+    outText = serializer.prettyPrint();
+  }
+  if (outPath != null) {
+    new File(outPath).writeAsStringSync(outText);
+  } else if (prettyPrint) {
+    print(outText);
+  }
+
+  Deserializer deserializer = new Deserializer.fromText(
+      text, const JsonSerializationDecoder());
+  List<LibraryElement> libraries2 = <LibraryElement>[];
+  for (LibraryElement library1 in libraries1) {
+    LibraryElement library2 =
+        deserializer.lookupLibrary(library1.canonicalUri);
+    if (library2 == null) {
+      throw new ArgumentError('No library ${library1.canonicalUri} found.');
+    }
+    checkLibraryContent('library1', 'library2', 'library', library1, library2);
+    libraries2.add(library2);
+  }
+
+  Serializer serializer2 = new Serializer(const JsonSerializationEncoder());
+  for (LibraryElement library2 in libraries2) {
+    serializer2.serialize(library2);
+  }
+  String text2 = serializer2.toText();
+
+  Deserializer deserializer3 = new Deserializer.fromText(
+      text2, const JsonSerializationDecoder());
+  for (LibraryElement library1 in libraries1) {
+    LibraryElement library2 =
+        deserializer.lookupLibrary(library1.canonicalUri);
+    if (library2 == null) {
+      throw new ArgumentError('No library ${library1.canonicalUri} found.');
+    }
+    LibraryElement library3 =
+        deserializer3.lookupLibrary(library1.canonicalUri);
+    if (library3 == null) {
+      throw new ArgumentError('No library ${library1.canonicalUri} found.');
+    }
+    checkLibraryContent('library1', 'library3', 'library', library1, library3);
+    checkLibraryContent('library2', 'library3', 'library', library2, library3);
+  }
+}
+
+/// Check the equivalence of [library1] and [library2] and their content.
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+checkLibraryContent(
+    Object object1, object2, String property,
+    LibraryElement library1, LibraryElement library2) {
+  checkElementProperties(object1, object2, property, library1, library2);
+}
+
+/// Check the equivalence of [element1] and [element2] and their properties.
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+checkElementProperties(
+    Object object1, object2, String property,
+    Element element1, Element element2) {
+  const ElementPropertyEquivalence().visit(element1, element2);
+}
+
+/// Check the equivalence of the two lists of elements, [list1] and [list2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+checkElementLists(Object object1, Object object2, String property,
+                  Iterable<Element> list1, Iterable<Element> list2) {
+  checkListEquivalence(object1, object2, property,
+                  list1, list2, checkElementProperties);
+}
+
+/// Check equivalence of the two lists, [list1] and [list2], using
+/// [checkEquivalence] to check the pair-wise equivalence.
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkListEquivalence(
+    Object object1, Object object2, String property,
+    Iterable list1, Iterable list2,
+    void checkEquivalence(o1, o2, property, a, b)) {
+  for (int i = 0; i < list1.length && i < list2.length; i++) {
+    checkEquivalence(
+        object1, object2, property,
+        list1.elementAt(i), list2.elementAt(i));
+  }
+  for (int i = list1.length; i < list2.length; i++) {
+    throw
+        'Missing equivalent for element '
+        '#$i ${list2.elementAt(i)} in `${property}` on $object2.\n'
+        '`${property}` on $object1:\n ${list1.join('\n ')}\n'
+        '`${property}` on $object2:\n ${list2.join('\n ')}';
+  }
+  for (int i = list2.length; i < list1.length; i++) {
+    throw
+        'Missing equivalent for element '
+        '#$i ${list1.elementAt(i)} in `${property}` on $object1.\n'
+        '`${property}` on $object1:\n ${list1.join('\n ')}\n'
+        '`${property}` on $object2:\n ${list2.join('\n ')}';
+  }
+}
+
+/// Checks the equivalence of the identity (but not properties) of [element1]
+/// and [element2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkElementIdentities(
+    Object object1, Object object2, String property,
+    Element element1, Element element2) {
+  if (identical(element1, element2)) return;
+  if (element1 == null || element2 == null) {
+    check(object1, object2, property, element1, element2);
+  }
+  const ElementIdentityEquivalence().visit(element1, element2);
+}
+
+/// Checks the pair-wise equivalence of the identity (but not properties) of the
+/// elements in [list] and [list2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkElementListIdentities(
+    Object object1, Object object2, String property,
+    Iterable<Element> list1, Iterable<Element> list2) {
+  checkListEquivalence(
+      object1, object2, property,
+      list1, list2, checkElementIdentities);
+}
+
+/// Checks the equivalence of [type1] and [type2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkTypes(
+    Object object1, Object object2, String property,
+    DartType type1, DartType type2) {
+  if (identical(type1, type2)) return;
+  if (type1 == null || type2 == null) {
+    check(object1, object2, property, type1, type2);
+  }
+  const TypeEquivalence().visit(type1, type2);
+}
+
+/// Checks the pair-wise equivalence of the types in [list1] and [list2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkTypeLists(
+    Object object1, Object object2, String property,
+    List<DartType> list1, List<DartType> list2) {
+  checkListEquivalence(object1, object2, property, list1, list2, checkTypes);
+}
+
+/// Checks the equivalence of [exp1] and [exp2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkConstants(
+    Object object1, Object object2, String property,
+    ConstantExpression exp1, ConstantExpression exp2) {
+  if (identical(exp1, exp2)) return;
+  if (exp1 == null || exp2 == null) {
+    check(object1, object2, property, exp1, exp2);
+  }
+  const ConstantEquivalence().visit(exp1, exp2);
+}
+
+/// Checks the pair-wise equivalence of the contants in [list1] and [list2].
+///
+/// Uses [object1], [object2] and [property] to provide context for failures.
+void checkConstantLists(
+    Object object1, Object object2, String property,
+    List<ConstantExpression> list1,
+    List<ConstantExpression> list2) {
+  checkListEquivalence(
+      object1, object2, property,
+      list1, list2, checkConstants);
+}
+
+/// Checks the equivalence of [constructor1] and [constructor2].
+void constantConstructorEquivalence(ConstantConstructor constructor1,
+                                    ConstantConstructor constructor2) {
+  const ConstantConstructorEquivalence().visit(constructor1, constructor2);
+}
+
+/// Visitor that checks the equivalence of [ConstantConstructor]s.
+class ConstantConstructorEquivalence
+    extends ConstantConstructorVisitor<dynamic, ConstantConstructor> {
+  const ConstantConstructorEquivalence();
+
+  @override
+  void visit(ConstantConstructor constructor1,
+             ConstantConstructor constructor2) {
+    if (identical(constructor1, constructor2)) return;
+    check(constructor1, constructor2, 'kind',
+          constructor1.kind, constructor2.kind);
+    constructor1.accept(this, constructor2);
+  }
+
+  @override
+  visitGenerative(
+      GenerativeConstantConstructor constructor1,
+      GenerativeConstantConstructor constructor2) {
+    checkTypes(
+        constructor1, constructor2, 'type',
+        constructor1.type, constructor2.type);
+    check(constructor1, constructor2, 'defaultValues.length',
+          constructor1.defaultValues.length,
+          constructor2.defaultValues.length);
+    constructor1.defaultValues.forEach((k, v) {
+      checkConstants(
+          constructor1, constructor2, 'defaultValue[$k]',
+          v, constructor2.defaultValues[k]);
+    });
+    check(constructor1, constructor2, 'fieldMap.length',
+          constructor1.fieldMap.length,
+          constructor2.fieldMap.length);
+    constructor1.fieldMap.forEach((k1, v1) {
+      bool matched = false;
+      constructor2.fieldMap.forEach((k2, v2) {
+        if (k1.name == k2.name &&
+            k1.library.canonicalUri == k2.library.canonicalUri) {
+          checkElementIdentities(
+              constructor1, constructor2, 'fieldMap[${k1.name}].key', k1, k2);
+          checkConstants(
+              constructor1, constructor2, 'fieldMap[${k1.name}].value', v1, v2);
+          matched = true;
+        }
+      });
+      if (!matched) {
+        throw 'Unmatched field $k1 = $v1';
+      }
+    });
+    checkConstants(
+        constructor1, constructor2, 'superConstructorInvocation',
+        constructor1.superConstructorInvocation,
+        constructor2.superConstructorInvocation);
+  }
+
+  @override
+  visitRedirectingFactory(
+      RedirectingFactoryConstantConstructor constructor1,
+      RedirectingFactoryConstantConstructor constructor2) {
+    checkConstants(
+        constructor1, constructor2, 'targetConstructorInvocation',
+        constructor1.targetConstructorInvocation,
+        constructor2.targetConstructorInvocation);
+  }
+
+  @override
+  visitRedirectingGenerative(
+      RedirectingGenerativeConstantConstructor constructor1,
+      RedirectingGenerativeConstantConstructor constructor2) {
+    check(constructor1, constructor2, 'defaultValues.length',
+          constructor1.defaultValues.length,
+          constructor2.defaultValues.length);
+    constructor1.defaultValues.forEach((k, v) {
+      checkConstants(
+          constructor1, constructor2, 'defaultValue[$k]',
+          v, constructor2.defaultValues[k]);
+    });
+    checkConstants(
+        constructor1, constructor2, 'thisConstructorInvocation',
+        constructor1.thisConstructorInvocation,
+        constructor2.thisConstructorInvocation);
+  }
+}
+
+/// Check that the values [property] of [object1] and [object2], [value1] and
+/// [value2] respectively, are equal and throw otherwise.
+void check(var object1, var object2, String property, var value1, value2) {
+  if (value1 != value2) {
+    throw "$object1.$property = '${value1}' <> "
+          "$object2.$property = '${value2}'";
+  }
+}
+
+/// Visitor that checks for equivalence of [Element] identities.
+class ElementIdentityEquivalence extends BaseElementVisitor<dynamic, Element> {
+  const ElementIdentityEquivalence();
+
+  void visit(Element element1, Element element2) {
+    check(element1, element2, 'kind', element1.kind, element2.kind);
+    element1.accept(this, element2);
+  }
+
+  @override
+  void visitElement(Element e, Element arg) {
+    throw new UnsupportedError("Unsupported element $e");
+  }
+
+  @override
+  void visitLibraryElement(LibraryElement element1, LibraryElement element2) {
+    check(element1, element2,
+          'canonicalUri',
+          element1.canonicalUri, element2.canonicalUri);
+  }
+
+  @override
+  void visitCompilationUnitElement(CompilationUnitElement element1,
+                                   CompilationUnitElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.library, element2.library);
+  }
+
+  @override
+  void visitClassElement(ClassElement element1, ClassElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.library, element2.library);
+  }
+
+  void checkMembers(Element element1, Element element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    if (element1.enclosingClass != null || element2.enclosingClass != null) {
+      visit(element1.enclosingClass, element2.enclosingClass);
+    } else {
+      visit(element1.library, element2.library);
+    }
+  }
+
+  @override
+  void visitFieldElement(FieldElement element1, FieldElement element2) {
+    checkMembers(element1, element2);
+  }
+
+  @override
+  void visitFunctionElement(FunctionElement element1,
+                            FunctionElement element2) {
+    checkMembers(element1, element2);
+  }
+
+  void visitAbstractFieldElement(AbstractFieldElement element1,
+                                 AbstractFieldElement element2) {
+    checkMembers(element1, element2);
+  }
+
+  @override
+  void visitTypeVariableElement(TypeVariableElement element1,
+                                TypeVariableElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.typeDeclaration, element2.typeDeclaration);
+  }
+
+  @override
+  void visitTypedefElement(TypedefElement element1, TypedefElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.library, element2.library);
+  }
+
+  @override
+  void visitParameterElement(ParameterElement element1,
+                             ParameterElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    visit(element1.functionDeclaration, element2.functionDeclaration);
+  }
+}
+
+/// Visitor that checks for equivalence of [Element] properties.
+class ElementPropertyEquivalence extends BaseElementVisitor<dynamic, Element> {
+  const ElementPropertyEquivalence();
+
+  void visit(Element element1, Element element2) {
+    if (element1 == element2) return;
+    check(element1, element2, 'kind', element1.kind, element2.kind);
+    element1.accept(this, element2);
+  }
+
+  @override
+  void visitElement(Element e, Element arg) {
+    throw new UnsupportedError("Unsupported element $e");
+  }
+
+  @override
+  void visitLibraryElement(LibraryElement element1, LibraryElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name', element1.name, element2.name);
+    check(element1, element2, 'getLibraryName',
+          element1.getLibraryName(), element2.getLibraryName());
+    visitMembers(element1, element2);
+    visit(element1.entryCompilationUnit, element2.entryCompilationUnit);
+    checkElementLists(
+        element1, element2, 'compilationUnits',
+        element1.compilationUnits.toList(),
+        element2.compilationUnits.toList());
+
+    bool filterTags(LibraryTag tag) => tag.asLibraryDependency() != null;
+
+    List<LibraryTag> tags1 = element1.tags.where(filterTags).toList();
+    List<LibraryTag> tags2 = element2.tags.where(filterTags).toList();
+    checkListEquivalence(element1, element2, 'tags', tags1, tags2,
+        (Object object1, Object object2, String property,
+         LibraryDependency tag1, LibraryDependency tag2) {
+      checkElementIdentities(
+          tag1, tag2, 'getLibraryFromTag',
+          element1.getLibraryFromTag(tag1),
+          element2.getLibraryFromTag(tag2));
+    });
+
+    List<Element> imports1 = <Element>[];
+    List<Element> imports2 = <Element>[];
+    element1.forEachImport((Element import) {
+      if (import.isAmbiguous) return;
+      imports1.add(import);
+    });
+    element2.forEachImport((Element import) {
+      if (import.isAmbiguous) return;
+      imports2.add(import);
+    });
+    checkElementListIdentities(
+        element1, element2, 'imports', imports1, imports2);
+
+    List<Element> exports1 = <Element>[];
+    List<Element> exports2 = <Element>[];
+    element1.forEachExport((Element export) {
+      if (export.isAmbiguous) return;
+      exports1.add(export);
+    });
+    element2.forEachExport((Element export) {
+      if (export.isAmbiguous) return;
+      exports2.add(export);
+    });
+    checkElementListIdentities(
+        element1, element2, 'exports', exports1, exports2);
+  }
+
+  @override
+  void visitCompilationUnitElement(CompilationUnitElement element1,
+                                   CompilationUnitElement element2) {
+    check(element1, element2,
+          'name',
+          element1.name, element2.name);
+    checkElementIdentities(
+        element1, element2, 'library',
+        element1.library, element2.library);
+    check(element1, element2,
+          'script.resourceUri',
+          element1.script.resourceUri, element2.script.resourceUri);
+    List<Element> members1 = <Element>[];
+    List<Element> members2 = <Element>[];
+    element1.forEachLocalMember((Element member) {
+      members1.add(member);
+    });
+    element2.forEachLocalMember((Element member) {
+      members2.add(member);
+    });
+    checkElementListIdentities(
+        element1, element2, 'localMembers', members1, members2);
+  }
+
+  void visitMembers(ScopeContainerElement element1,
+                    ScopeContainerElement element2) {
+    Set<String> names = new Set<String>();
+    element1.forEachLocalMember((Element member) {
+      names.add(member.name);
+    });
+    element2.forEachLocalMember((Element member) {
+      names.add(member.name);
+    });
+    for (String name in names) {
+      Element member1 = element1.localLookup(name);
+      Element member2 = element2.localLookup(name);
+      if (member1 == null) {
+        print('Missing member for $member2');
+        continue;
+      }
+      if (member2 == null) {
+        print('Missing member for $member1');
+        continue;
+      }
+      visit(member1, member2);
+    }
+  }
+
+  @override
+  void visitClassElement(ClassElement element1, ClassElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name',
+          element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkElementIdentities(
+        element1, element2, 'library',
+        element1.library, element2.library);
+    checkElementIdentities(
+        element1, element2, 'compilationUnit',
+        element1.compilationUnit, element2.compilationUnit);
+    check(element1, element2, 'isObject',
+        element1.isObject, element2.isObject);
+    checkTypeLists(element1, element2, 'typeVariables',
+        element1.typeVariables, element2.typeVariables);
+    check(element1, element2, 'isAbstract',
+        element1.isAbstract, element2.isAbstract);
+    if (!element1.isObject) {
+      checkTypes(element1, element2, 'supertype',
+          element1.supertype, element2.supertype);
+    }
+    check(element1, element2, 'hierarchyDepth',
+          element1.hierarchyDepth, element2.hierarchyDepth);
+    checkTypeLists(
+        element1, element2, 'allSupertypes',
+        element1.allSupertypes.toList(),
+        element2.allSupertypes.toList());
+    OrderedTypeSet typeSet1 = element1.allSupertypesAndSelf;
+    OrderedTypeSet typeSet2 = element1.allSupertypesAndSelf;
+    checkListEquivalence(
+        element1, element2, 'allSupertypes',
+        typeSet1.levelOffsets,
+        typeSet2.levelOffsets,
+        check);
+    check(element1, element2, 'allSupertypesAndSelf.levels',
+          typeSet1.levels, typeSet2.levels);
+    checkTypeLists(
+        element1, element2, 'supertypes',
+        typeSet1.supertypes.toList(),
+        typeSet2.supertypes.toList());
+    checkTypeLists(
+        element1, element2, 'types',
+        typeSet1.types.toList(),
+        typeSet2.types.toList());
+
+    checkTypeLists(
+        element1, element2, 'interfaces',
+        element1.interfaces.toList(),
+        element2.interfaces.toList());
+
+    visitMembers(element1, element2);
+  }
+
+  @override
+  void visitFieldElement(FieldElement element1, FieldElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name',
+          element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkTypes(
+        element1, element2, 'type',
+        element1.type, element2.type);
+    check(element1, element2, 'isConst',
+          element1.isConst, element2.isConst);
+    check(element1, element2, 'isFinal',
+          element1.isFinal, element2.isFinal);
+    if (element1.isConst) {
+      checkConstants(
+          element1, element2, 'constant',
+          element1.constant, element2.constant);
+    }
+    check(element1, element2, 'isTopLevel',
+          element1.isTopLevel, element2.isTopLevel);
+    check(element1, element2, 'isStatic',
+          element1.isStatic, element2.isStatic);
+    check(element1, element2, 'isInstanceMember',
+          element1.isInstanceMember, element2.isInstanceMember);
+
+    checkElementIdentities(
+        element1, element2, 'library',
+        element1.library, element2.library);
+    checkElementIdentities(
+        element1, element2, 'compilationUnit',
+        element1.compilationUnit, element2.compilationUnit);
+    checkElementIdentities(
+        element1, element2, 'enclosingClass',
+        element1.enclosingClass, element2.enclosingClass);
+  }
+
+  @override
+  void visitFunctionElement(FunctionElement element1,
+                            FunctionElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name',
+          element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkTypes(
+        element1, element2, 'type',
+        element1.type, element2.type);
+    checkListEquivalence(
+        element1, element2, 'parameters',
+        element1.parameters, element2.parameters,
+        checkElementProperties);
+    check(element1, element2, 'isOperator',
+          element1.isOperator, element2.isOperator);
+
+    checkElementIdentities(
+        element1, element2, 'library',
+        element1.library, element2.library);
+    checkElementIdentities(
+        element1, element2, 'compilationUnit',
+        element1.compilationUnit, element2.compilationUnit);
+    checkElementIdentities(
+        element1, element2, 'enclosingClass',
+        element1.enclosingClass, element2.enclosingClass);
+  }
+
+  @override
+  void visitConstructorElement(ConstructorElement element1,
+                               ConstructorElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    checkElementIdentities(
+        element1, element2, 'enclosingClass',
+        element1.enclosingClass, element2.enclosingClass);
+    check(
+        element1, element2, 'name',
+        element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkListEquivalence(
+        element1, element2, 'parameters',
+        element1.parameters, element2.parameters,
+        checkElementProperties);
+    checkTypes(
+        element1, element2, 'type',
+        element1.type, element2.type);
+    check(element1, element2, 'isConst',
+          element1.isConst, element2.isConst);
+    check(element1, element2, 'isExternal',
+          element1.isExternal, element2.isExternal);
+    if (element1.isConst && !element1.isExternal) {
+      constantConstructorEquivalence(
+          element1.constantConstructor,
+          element2.constantConstructor);
+    }
+  }
+
+  @override
+  void visitAbstractFieldElement(AbstractFieldElement element1,
+                                 AbstractFieldElement element2) {
+    visit(element1.getter, element2.getter);
+    visit(element1.setter, element2.setter);
+  }
+
+  @override
+  void visitTypeVariableElement(TypeVariableElement element1,
+                                TypeVariableElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name', element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    check(element1, element2, 'index', element1.index, element2.index);
+    checkTypes(
+        element1, element2, 'type',
+        element1.type, element2.type);
+    checkTypes(
+        element1, element2, 'bound',
+        element1.bound, element2.bound);
+  }
+
+  @override
+  void visitTypedefElement(TypedefElement element1,
+                           TypedefElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    check(element1, element2, 'name', element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkTypes(
+        element1, element2, 'alias',
+        element1.alias, element2.alias);
+    checkTypeLists(
+        element1, element2, 'typeVariables',
+        element1.typeVariables, element2.typeVariables);
+    checkElementIdentities(
+        element1, element2, 'library',
+        element1.library, element2.library);
+    checkElementIdentities(
+        element1, element2, 'compilationUnit',
+        element1.compilationUnit, element2.compilationUnit);
+    // TODO(johnniwinther): Check the equivalence of typedef parameters.
+  }
+
+  @override
+  void visitParameterElement(ParameterElement element1,
+                             ParameterElement element2) {
+    checkElementIdentities(null, null, null, element1, element2);
+    checkElementIdentities(
+        element1, element2, 'functionDeclaration',
+        element1.functionDeclaration, element2.functionDeclaration);
+    check(element1, element2, 'name', element1.name, element2.name);
+    check(element1, element2, 'sourcePosition',
+          element1.sourcePosition, element2.sourcePosition);
+    checkTypes(
+        element1, element2, 'type',
+        element1.type, element2.type);
+    check(
+        element1, element2, 'isOptional',
+        element1.isOptional, element2.isOptional);
+    check(
+        element1, element2, 'isNamed',
+        element1.isNamed, element2.isNamed);
+    check(element1, element2, 'name', element1.name, element2.name);
+    if (element1.isOptional) {
+      checkConstants(
+          element1, element2, 'constant',
+          element1.constant, element2.constant);
+    }
+    checkElementIdentities(
+        element1, element2, 'compilationUnit',
+        element1.compilationUnit, element2.compilationUnit);
+  }
+
+  @override
+  void visitFieldParameterElement(InitializingFormalElement element1,
+                                  InitializingFormalElement element2) {
+    visitParameterElement(element1, element2);
+    checkElementIdentities(
+        element1, element2, 'fieldElement',
+        element1.fieldElement, element2.fieldElement);
+  }
+}
+
+/// Visitor that checks for equivalence of [DartType]s.
+class TypeEquivalence implements DartTypeVisitor<dynamic, DartType> {
+  const TypeEquivalence();
+
+  void visit(DartType type1, DartType type2) {
+    check(type1, type2, 'kind', type1.kind, type2.kind);
+    type1.accept(this, type2);
+  }
+
+  @override
+  void visitDynamicType(DynamicType type, DynamicType other) {
+  }
+
+  @override
+  void visitFunctionType(FunctionType type, FunctionType other) {
+    checkTypeLists(
+        type, other, 'parameterTypes',
+        type.parameterTypes, other.parameterTypes);
+    checkTypeLists(
+        type, other, 'optionalParameterTypes',
+        type.optionalParameterTypes, other.optionalParameterTypes);
+    checkTypeLists(
+        type, other, 'namedParameterTypes',
+        type.namedParameterTypes, other.namedParameterTypes);
+    for (int i = 0; i < type.namedParameters.length; i++) {
+      if (type.namedParameters[i] != other.namedParameters[i]) {
+        throw "Named parameter '$type.namedParameters[i]' <> "
+              "'${other.namedParameters[i]}'";
+      }
+    }
+  }
+
+  void visitGenericType(GenericType type, GenericType other) {
+    checkElementIdentities(
+        type, other, 'element',
+        type.element, other.element);
+    checkTypeLists(
+        type, other, 'typeArguments',
+        type.typeArguments, other.typeArguments);
+  }
+
+  @override
+  void visitMalformedType(MalformedType type, MalformedType other) {
+  }
+
+  @override
+  void  visitStatementType(StatementType type, StatementType other) {
+    throw new UnsupportedError("Unsupported type: $type");
+  }
+
+  @override
+  void visitTypeVariableType(TypeVariableType type, TypeVariableType other) {
+    checkElementIdentities(
+        type, other, 'element',
+        type.element, other.element);
+  }
+
+  @override
+  void visitVoidType(VoidType type, VoidType argument) {
+  }
+
+  @override
+  void visitInterfaceType(InterfaceType type, InterfaceType other) {
+    visitGenericType(type, other);
+  }
+
+  @override
+  void visitTypedefType(TypedefType type, TypedefType other) {
+    visitGenericType(type, other);
+  }
+}
+
+/// Visitor that checks for structural equivalence of [ConstantExpression]s.
+class ConstantEquivalence
+    implements ConstantExpressionVisitor<dynamic, ConstantExpression> {
+  const ConstantEquivalence();
+
+  @override
+  visit(ConstantExpression exp1, ConstantExpression exp2) {
+    if (identical(exp1, exp2)) return;
+    check(exp1, exp2, 'kind', exp1.kind, exp2.kind);
+    exp1.accept(this, exp2);
+  }
+
+  @override
+  visitBinary(BinaryConstantExpression exp1, BinaryConstantExpression exp2) {
+    check(exp1, exp2, 'operator', exp1.operator, exp2.operator);
+    checkConstants(exp1, exp2, 'left', exp1.left, exp2.left);
+    checkConstants(exp1, exp2, 'right', exp1.right, exp2.right);
+  }
+
+  @override
+  visitConcatenate(ConcatenateConstantExpression exp1,
+                   ConcatenateConstantExpression exp2) {
+    checkConstantLists(
+        exp1, exp2, 'expressions',
+        exp1.expressions, exp2.expressions);
+  }
+
+  @override
+  visitConditional(ConditionalConstantExpression exp1,
+                   ConditionalConstantExpression exp2) {
+    checkConstants(
+        exp1, exp2, 'condition', exp1.condition, exp2.condition);
+    checkConstants(exp1, exp2, 'trueExp', exp1.trueExp, exp2.trueExp);
+    checkConstants(exp1, exp2, 'falseExp', exp1.falseExp, exp2.falseExp);
+  }
+
+  @override
+  visitConstructed(ConstructedConstantExpression exp1,
+                   ConstructedConstantExpression exp2) {
+    checkTypes(
+        exp1, exp2, 'type',
+        exp1.type, exp2.type);
+    checkElementIdentities(
+        exp1, exp2, 'target',
+        exp1.target, exp2.target);
+    checkConstantLists(
+        exp1, exp2, 'arguments',
+        exp1.arguments, exp2.arguments);
+    check(exp1, exp2, 'callStructure', exp1.callStructure, exp2.callStructure);
+  }
+
+  @override
+  visitFunction(FunctionConstantExpression exp1,
+                FunctionConstantExpression exp2) {
+    checkElementIdentities(
+        exp1, exp2, 'element',
+        exp1.element, exp2.element);
+  }
+
+  @override
+  visitIdentical(IdenticalConstantExpression exp1,
+                 IdenticalConstantExpression exp2) {
+    checkConstants(exp1, exp2, 'left', exp1.left, exp2.left);
+    checkConstants(exp1, exp2, 'right', exp1.right, exp2.right);
+  }
+
+  @override
+  visitList(ListConstantExpression exp1, ListConstantExpression exp2) {
+    checkTypes(
+        exp1, exp2, 'type',
+        exp1.type, exp2.type);
+    checkConstantLists(
+        exp1, exp2, 'values',
+        exp1.values, exp2.values);
+  }
+
+  @override
+  visitMap(MapConstantExpression exp1, MapConstantExpression exp2) {
+    checkTypes(
+        exp1, exp2, 'type',
+        exp1.type, exp2.type);
+    checkConstantLists(
+        exp1, exp2, 'keys',
+        exp1.keys, exp2.keys);
+    checkConstantLists(
+        exp1, exp2, 'values',
+        exp1.values, exp2.values);
+  }
+
+  @override
+  visitNamed(NamedArgumentReference exp1, NamedArgumentReference exp2) {
+    check(exp1, exp2, 'name', exp1.name, exp2.name);
+  }
+
+  @override
+  visitPositional(PositionalArgumentReference exp1,
+                  PositionalArgumentReference exp2) {
+    check(exp1, exp2, 'index', exp1.index, exp2.index);
+  }
+
+  @override
+  visitSymbol(SymbolConstantExpression exp1, SymbolConstantExpression exp2) {
+    // TODO: implement visitSymbol
+  }
+
+  @override
+  visitType(TypeConstantExpression exp1, TypeConstantExpression exp2) {
+    checkTypes(
+        exp1, exp2, 'type',
+        exp1.type, exp2.type);
+  }
+
+  @override
+  visitUnary(UnaryConstantExpression exp1, UnaryConstantExpression exp2) {
+    check(exp1, exp2, 'operator', exp1.operator, exp2.operator);
+    checkConstants(
+        exp1, exp2, 'expression', exp1.expression, exp2.expression);
+  }
+
+  @override
+  visitVariable(VariableConstantExpression exp1,
+                VariableConstantExpression exp2) {
+    checkElementIdentities(
+        exp1, exp2, 'element',
+        exp1.element, exp2.element);
+  }
+
+  @override
+  visitBool(BoolConstantExpression exp1, BoolConstantExpression exp2) {
+    check(exp1, exp2, 'primitiveValue',
+          exp1.primitiveValue, exp2.primitiveValue);
+  }
+
+  @override
+  visitDouble(DoubleConstantExpression exp1, DoubleConstantExpression exp2) {
+    check(exp1, exp2, 'primitiveValue',
+          exp1.primitiveValue, exp2.primitiveValue);
+  }
+
+  @override
+  visitInt(IntConstantExpression exp1, IntConstantExpression exp2) {
+    check(exp1, exp2, 'primitiveValue',
+          exp1.primitiveValue, exp2.primitiveValue);
+  }
+
+  @override
+  visitNull(NullConstantExpression exp1, NullConstantExpression exp2) {
+    // Do nothing.
+  }
+
+  @override
+  visitString(StringConstantExpression exp1, StringConstantExpression exp2) {
+    check(exp1, exp2, 'primitiveValue',
+          exp1.primitiveValue, exp2.primitiveValue);
+  }
+
+  @override
+  visitBoolFromEnvironment(BoolFromEnvironmentConstantExpression exp1,
+                           BoolFromEnvironmentConstantExpression exp2) {
+    checkConstants(exp1, exp2, 'name', exp1.name, exp2.name);
+    checkConstants(
+        exp1, exp2, 'defaultValue',
+        exp1.defaultValue, exp2.defaultValue);
+  }
+
+  @override
+  visitIntFromEnvironment(IntFromEnvironmentConstantExpression exp1,
+                          IntFromEnvironmentConstantExpression exp2) {
+    checkConstants(exp1, exp2, 'name', exp1.name, exp2.name);
+    checkConstants(
+        exp1, exp2, 'defaultValue',
+        exp1.defaultValue, exp2.defaultValue);
+  }
+
+  @override
+  visitStringFromEnvironment(StringFromEnvironmentConstantExpression exp1,
+                             StringFromEnvironmentConstantExpression exp2) {
+    checkConstants(exp1, exp2, 'name', exp1.name, exp2.name);
+    checkConstants(
+        exp1, exp2, 'defaultValue',
+        exp1.defaultValue, exp2.defaultValue);
+  }
+
+  @override
+  visitStringLength(StringLengthConstantExpression exp1,
+                    StringLengthConstantExpression exp2) {
+    checkConstants(
+        exp1, exp2, 'expression',
+        exp1.expression, exp2.expression);
+  }
+
+  @override
+  visitDeferred(DeferredConstantExpression exp1,
+                DeferredConstantExpression exp2) {
+    // TODO: implement visitDeferred
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/colors.dart b/tests/compiler/dart2js/sourcemaps/colors.dart
new file mode 100644
index 0000000..8241dd1
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/colors.dart
@@ -0,0 +1,89 @@
+// 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.
+
+/// Utility library for creating web colors.
+
+library colors;
+
+/// A web color.
+abstract class Color {
+  /// The hexadecimal code for the color, without the prefixed '#'.
+  String get toHex;
+}
+
+/// A web color defined as RGB.
+class RGB implements Color {
+  final double r;
+  final double g;
+  final double b;
+
+  /// Creates a color defined by the amount of red [r], green [g], and blue [b]
+  /// all in range 0..1.
+  const RGB(this.r, this.g, this.b);
+
+  String get toHex {
+    StringBuffer sb = new StringBuffer();
+
+    void writeHex(double value) {
+      int i = (value * 255.0).round();
+      if (i < 16) {
+        sb.write('0');
+      }
+      sb.write(i.toRadixString(16));
+    }
+
+    writeHex(r);
+    writeHex(g);
+    writeHex(b);
+
+    return sb.toString();
+  }
+
+  String toString() => 'rgb($r,$g,$b)';
+}
+
+/// A web color defined as HSV.
+class HSV implements Color {
+  final double h;
+  final double s;
+  final double v;
+
+  /// Creates a color defined by the hue [h] in range 0..360 (360 excluded),
+  /// saturation [s] in range 0..1, and value [v] in range 0..1.
+  const HSV(this.h, this.s, this.v);
+
+  String get toHex => toRGB(this).toHex;
+
+  static RGB toRGB(HSV hsv) {
+    double h = hsv.h;
+    double s = hsv.s;
+    double v = hsv.v;
+    if (s == 0.0) {
+      // Grey.
+      return new RGB(v, v, v);
+    }
+    h /= 60.0;  // Sector 0 to 5.
+    int i = h.floor();
+    double f = h - i; // Factorial part of [h].
+    double p = v * (1.0 - s);
+    double q = v * (1.0 - s * f);
+    double t = v * (1.0 - s * (1.0 - f ));
+    switch (i) {
+      case 0:
+        return new RGB(v, t, p);
+      case 1:
+        return new RGB(q, v, p);
+      case 2:
+        return new RGB(p, v, t);
+      case 3:
+        return new RGB(p, q, v);
+      case 4:
+        return new RGB(t, p, v);
+      default:    // case 5:
+        return new RGB(v, p, q);
+    }
+  }
+
+  String toString() => 'hsv($h,$s,$v)';
+}
diff --git a/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
new file mode 100644
index 0000000..9c06550
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/invokes_test_file.dart
@@ -0,0 +1,127 @@
+// 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.
+
+// Test file for testing source mappings of invocations.
+
+var counter = 0;
+var bucket;
+
+main(args) {
+  counter++;
+  invokes(args);
+  return counter;
+}
+
+invokes(parameter) {
+  counter++;
+  toplevelFunction();
+  toplevelField();
+  toplevelFinalField();
+  toplevelConstField();
+  toplevelGetter();
+  C.staticFunction();
+  C.staticField();
+  C.staticFinalField();
+  C.staticConstField();
+  C.staticGetter();
+
+  var localVariable = () {
+    counter++;
+  };
+  localFunction() {
+    counter++;
+  }
+
+  parameter();
+  localVariable();
+  localFunction();
+
+  parameter.dynamicInvoke();
+  new C(parameter).instanceInvokes();
+}
+
+toplevelFunction() {
+  counter++;
+}
+
+var toplevelField = () {
+  counter++;
+};
+
+final toplevelFinalField = toplevelFunction;
+
+const toplevelConstField = toplevelFunction;
+
+get toplevelGetter => () {
+  counter++;
+};
+
+typedef F();
+
+class B {
+  B(parameter);
+
+  superMethod() {
+    counter++;
+  }
+
+  var superField = () {
+    counter++;
+  };
+
+  get superGetter => () {
+    counter++;
+  };
+
+}
+
+class C<T> extends B {
+  C(parameter) : super(parameter);
+
+  static staticFunction() {
+    counter++;
+  }
+
+  static var staticField = () {
+    counter++;
+  };
+
+  static final staticFinalField = staticFunction;
+
+  static const staticConstField = staticFunction;
+
+  static get staticGetter => () {
+    counter++;
+  };
+
+  instanceMethod() {
+    counter++;
+  }
+
+  var instanceField = () {
+    counter++;
+  };
+
+  get instanceGetter => () {
+    counter++;
+  };
+
+  instanceInvokes() {
+    instanceMethod();
+    this.instanceMethod();
+    instanceField();
+    this.instanceField();
+    instanceGetter();
+    this.instanceGetter();
+
+    super.superMethod();
+    super.superField();
+    super.superGetter();
+
+    C();
+    dynamic();
+    F();
+    T();
+  }
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
new file mode 100644
index 0000000..831299f
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_test.dart
@@ -0,0 +1,51 @@
+// 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:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'sourcemap_helper.dart';
+import 'sourcemap_html_helper.dart';
+import 'package:compiler/src/filenames.dart';
+
+main(List<String> arguments) {
+  bool showAll = false;
+  Uri outputUri;
+  if (arguments.isNotEmpty) {
+    outputUri = Uri.base.resolve(nativeToUriPath(arguments.last));
+    showAll = arguments.contains('-a');
+  }
+  asyncTest(() async {
+    String filename =
+        'tests/compiler/dart2js/sourcemaps/invokes_test_file.dart';
+    SourceMapProcessor processor = new SourceMapProcessor(filename);
+    List<SourceMapInfo> infoList = await processor.process(
+        ['--use-new-source-info', '--csp', '--disable-inlining']);
+    List<SourceMapInfo> userInfoList = <SourceMapInfo>[];
+    List<SourceMapInfo> failureList = <SourceMapInfo>[];
+    for (SourceMapInfo info in infoList) {
+      if (info.element.library.isPlatformLibrary) continue;
+      userInfoList.add(info);
+      Iterable<CodePoint> missingCodePoints =
+          info.codePoints.where((c) => c.isMissing);
+      if (!missingCodePoints.isEmpty) {
+        print('Missing code points ${missingCodePoints} for '
+              '${info.element} in $filename');
+        failureList.add(info);
+      }
+    }
+    if (failureList.isNotEmpty) {
+      if (outputUri == null) {
+        Expect.fail(
+            "Missing code points found. "
+            "Run the test with a URI option, `source_mapping_test <uri>`, to "
+            "create a html visualization of the missing code points.");
+      } else {
+        createTraceSourceMapHtml(outputUri, processor,
+                                 showAll ? userInfoList : failureList);
+      }
+    } else if (outputUri != null) {
+      createTraceSourceMapHtml(outputUri, processor, userInfoList);
+    }
+  });
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
new file mode 100644
index 0000000..d7aa763
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -0,0 +1,331 @@
+// 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 sourcemap.helper;
+
+import 'dart:async';
+import 'package:compiler/src/apiimpl.dart' as api;
+import 'package:compiler/src/dart2jslib.dart' show NullSink;
+import "package:compiler/src/elements/elements.dart";
+import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/js/js.dart' as js;
+import 'package:compiler/src/js/js_debug.dart';
+import 'package:compiler/src/js/js_source_mapping.dart';
+import 'package:compiler/src/js_backend/js_backend.dart';
+import 'package:compiler/src/source_file_provider.dart';
+import '../memory_compiler.dart';
+import '../output_collector.dart';
+
+class OutputProvider {
+  BufferedEventSink jsMapOutput;
+
+  EventSink<String> call(String name, String extension) {
+    if (extension == 'js.map') {
+      return jsMapOutput = new BufferedEventSink();
+    }
+    return new NullSink('$name.$extension');
+  }
+}
+
+class CloningOutputProvider extends OutputProvider {
+  RandomAccessFileOutputProvider outputProvider;
+
+  CloningOutputProvider(Uri jsUri, Uri jsMapUri)
+    : outputProvider = new RandomAccessFileOutputProvider(jsUri, jsMapUri);
+
+  EventSink<String> call(String name, String extension) {
+    EventSink<String> output = outputProvider(name, extension);
+    if (extension == 'js.map') {
+      output = new CloningEventSink(
+          [output, jsMapOutput = new BufferedEventSink()]);
+    }
+    return output;
+  }
+}
+
+abstract class SourceFileManager {
+  SourceFile getSourceFile(var uri);
+}
+
+class ProviderSourceFileManager implements SourceFileManager {
+  final SourceFileProvider sourceFileProvider;
+
+  ProviderSourceFileManager(this.sourceFileProvider);
+
+  @override
+  SourceFile getSourceFile(uri) {
+    return sourceFileProvider.getSourceFile(uri);
+  }
+}
+
+class RecordingPrintingContext extends LenientPrintingContext {
+  CodePositionListener listener;
+
+  RecordingPrintingContext(this.listener);
+
+  @override
+  void exitNode(js.Node node,
+                int startPosition,
+                int endPosition,
+                int closingPosition) {
+    listener.onPositions(
+        node, startPosition, endPosition, closingPosition);
+  }
+}
+
+/// Processor that computes [SourceMapInfo] for the JavaScript compiled for a
+/// given Dart file.
+class SourceMapProcessor {
+  /// If `true` the output from the compilation is written to files.
+  final bool outputToFile;
+
+  /// The [Uri] of the Dart entrypoint.
+  Uri inputUri;
+
+  /// The name of the JavaScript output file.
+  String jsPath;
+
+  /// The [Uri] of the JavaScript output file.
+  Uri targetUri;
+
+  /// The [Uri] of the JavaScript source map file.
+  Uri sourceMapFileUri;
+
+  /// The [SourceFileManager] created for the processing.
+  SourceFileManager sourceFileManager;
+
+  /// Creates a processor for the Dart file [filename].
+  SourceMapProcessor(String filename, {this.outputToFile: false}) {
+    inputUri = Uri.base.resolve(nativeToUriPath(filename));
+    jsPath = 'out.js';
+    targetUri = Uri.base.resolve(jsPath);
+    sourceMapFileUri = Uri.base.resolve('${jsPath}.map');
+  }
+
+  /// Computes the [SourceMapInfo] for the compiled elements.
+  Future<List<SourceMapInfo>> process(List<String> options) async {
+    OutputProvider outputProvider = outputToFile
+        ? new OutputProvider()
+        : new CloningOutputProvider(targetUri, sourceMapFileUri);
+    if (options.contains('--use-new-source-info')) {
+      print('Using the new source information system.');
+      useNewSourceInfo = true;
+    }
+    api.Compiler compiler = await compilerFor({},
+        outputProvider: outputProvider,
+        options: ['--out=$targetUri', '--source-map=$sourceMapFileUri']
+            ..addAll(options));
+    if (options.contains('--disable-inlining')) {
+      print('Inlining disabled');
+      compiler.disableInlining = true;
+    }
+
+    JavaScriptBackend backend = compiler.backend;
+    var handler = compiler.handler;
+    SourceFileProvider sourceFileProvider = handler.provider;
+    sourceFileManager = new ProviderSourceFileManager(sourceFileProvider);
+    await compiler.runCompiler(inputUri);
+
+    List<SourceMapInfo> infoList = <SourceMapInfo>[];
+    backend.generatedCode.forEach((Element element, js.Expression node) {
+      js.JavaScriptPrintingOptions options =
+          new js.JavaScriptPrintingOptions();
+      JavaScriptSourceInformationStrategy sourceInformationStrategy =
+          compiler.backend.sourceInformationStrategy;
+      NodeToSourceLocationsMap nodeMap = new NodeToSourceLocationsMap();
+      SourceInformationProcessor sourceInformationProcessor =
+          sourceInformationStrategy.createProcessor(nodeMap);
+      RecordingPrintingContext printingContext =
+          new RecordingPrintingContext(sourceInformationProcessor);
+      new js.Printer(options, printingContext).visit(node);
+      sourceInformationProcessor.process(node);
+
+      String code = printingContext.getText();
+      CodePointComputer visitor =
+          new CodePointComputer(sourceFileManager, code, nodeMap);
+      visitor.apply(node);
+      List<CodePoint> codePoints = visitor.codePoints;
+      infoList.add(new SourceMapInfo(element, code, node, codePoints, nodeMap));
+    });
+
+    return infoList;
+  }
+}
+
+/// Source mapping information for the JavaScript code of an [Element].
+class SourceMapInfo {
+  final String name;
+  final Element element;
+  final String code;
+  final js.Expression node;
+  final List<CodePoint> codePoints;
+  final NodeToSourceLocationsMap nodeMap;
+
+  SourceMapInfo(
+      Element element, this.code, this.node, this.codePoints, this.nodeMap)
+      : this.name = computeElementNameForSourceMaps(element),
+        this.element = element;
+}
+
+/// Collection of JavaScript nodes with their source mapped target offsets
+/// and source locations.
+class NodeToSourceLocationsMap implements SourceMapper {
+  final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {};
+
+  @override
+  void register(js.Node node, int codeOffset, SourceLocation sourceLocation) {
+    _nodeMap.putIfAbsent(node, () => {})
+        .putIfAbsent(codeOffset, () => [])
+        .add(sourceLocation);
+  }
+
+  Iterable<js.Node> get nodes => _nodeMap.keys;
+
+  Map<int, List<SourceLocation>> operator[] (js.Node node) {
+    return _nodeMap[node];
+  }
+}
+
+/// Visitor that computes the [CodePoint]s for source mapping locations.
+class CodePointComputer extends js.BaseVisitor {
+  final SourceFileManager sourceFileManager;
+  final String code;
+  final NodeToSourceLocationsMap nodeMap;
+  List<CodePoint> codePoints = [];
+
+  CodePointComputer(this.sourceFileManager, this.code, this.nodeMap);
+
+  String nodeToString(js.Node node) {
+    js.JavaScriptPrintingOptions options = new js.JavaScriptPrintingOptions(
+        shouldCompressOutput: true,
+        preferSemicolonToNewlineInMinifiedOutput: true);
+    LenientPrintingContext printingContext = new LenientPrintingContext();
+    new js.Printer(options, printingContext).visit(node);
+    return printingContext.buffer.toString();
+  }
+
+  String positionToString(int position) {
+    String line = code.substring(position);
+    int nl = line.indexOf('\n');
+    if (nl != -1) {
+      line = line.substring(0, nl);
+    }
+    return line;
+  }
+
+  void register(String kind, js.Node node, {bool expectInfo: true}) {
+
+    String dartCodeFromSourceLocation(SourceLocation sourceLocation) {
+      SourceFile sourceFile =
+           sourceFileManager.getSourceFile(sourceLocation.sourceUri);
+      return sourceFile.getLineText(sourceLocation.line)
+          .substring(sourceLocation.column).trim();
+    }
+
+    void addLocation(SourceLocation sourceLocation, String jsCode) {
+      if (sourceLocation == null) {
+        if (expectInfo) {
+          SourceInformation sourceInformation = node.sourceInformation;
+          SourceLocation sourceLocation;
+          String dartCode;
+          if (sourceInformation != null) {
+            sourceLocation = sourceInformation.sourceLocations.first;
+            dartCode = dartCodeFromSourceLocation(sourceLocation);
+          }
+          codePoints.add(new CodePoint(
+              kind, jsCode, sourceLocation, dartCode, isMissing: true));
+        }
+      } else {
+         codePoints.add(new CodePoint(kind, jsCode, sourceLocation,
+             dartCodeFromSourceLocation(sourceLocation)));
+      }
+    }
+
+    Map<int, List<SourceLocation>> locationMap = nodeMap[node];
+    if (locationMap == null) {
+      addLocation(null, nodeToString(node));
+    } else {
+      locationMap.forEach((int targetOffset, List<SourceLocation> locations) {
+        String jsCode = positionToString(targetOffset);
+        for (SourceLocation location in locations) {
+          addLocation(location, jsCode);
+        }
+      });
+    }
+  }
+
+  void apply(js.Node node) {
+    node.accept(this);
+  }
+
+  void visitNode(js.Node node) {
+    register('${node.runtimeType}', node, expectInfo: false);
+    super.visitNode(node);
+  }
+
+  @override
+  void visitNew(js.New node) {
+    node.arguments.forEach(apply);
+    register('New', node);
+  }
+
+  @override
+  void visitReturn(js.Return node) {
+    if (node.value != null) {
+      apply(node.value);
+    }
+    register('Return', node);
+  }
+
+  @override
+  void visitCall(js.Call node) {
+    apply(node.target);
+    node.arguments.forEach(apply);
+    register('Call (${node.target.runtimeType})', node);
+  }
+
+  @override
+  void visitFun(js.Fun node) {
+    node.visitChildren(this);
+    register('Fun', node);
+  }
+
+  @override
+  visitExpressionStatement(js.ExpressionStatement node) {
+    node.visitChildren(this);
+  }
+
+  @override
+  visitBinary(js.Binary node) {
+    node.visitChildren(this);
+  }
+
+  @override
+  visitAccess(js.PropertyAccess node) {
+    node.visitChildren(this);
+  }
+}
+
+/// A JavaScript code point and its mapped dart source location.
+class CodePoint {
+  final String kind;
+  final String jsCode;
+  final SourceLocation sourceLocation;
+  final String dartCode;
+  final bool isMissing;
+
+  CodePoint(
+      this.kind,
+      this.jsCode,
+      this.sourceLocation,
+      this.dartCode,
+      {this.isMissing: false});
+
+  String toString() {
+    return 'CodePoint[kind=$kind,js=$jsCode,dart=$dartCode,'
+                     'location=$sourceLocation]';
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
new file mode 100644
index 0000000..eb1399a
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -0,0 +1,430 @@
+// 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.
+
+/// Helper for creating HTML visualization of the source map information
+/// generated by a [SourceMapProcessor].
+
+library sourcemap.html.helper;
+
+import 'dart:convert';
+
+import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/js/js.dart' as js;
+
+import 'colors.dart';
+import 'sourcemap_helper.dart';
+import 'sourcemap_html_templates.dart';
+
+/// Returns the [index]th color for visualization.
+String toColor(int index) {
+  int hueCount = 24;
+  double h = 360.0 * (index % hueCount) / hueCount;
+  double v = 1.0;
+  double s = 0.5;
+  HSV hsv = new HSV(h, s, v);
+  RGB rgb = HSV.toRGB(hsv);
+  return rgb.toHex;
+}
+
+/// Return the html for the [index] line number.
+String lineNumber(int index) {
+  return '<span class="lineNumber">${index + 1} </span>';
+}
+
+/// Return the html escaped [text].
+String escape(String text) {
+  return const HtmlEscape().convert(text);
+}
+
+/// Information needed to generate HTML for a single [SourceMapInfo].
+class SourceMapHtmlInfo {
+  final SourceMapInfo sourceMapInfo;
+  final CodeProcessor codeProcessor;
+  final SourceLocationCollection sourceLocationCollection;
+
+  SourceMapHtmlInfo(this.sourceMapInfo,
+                    this.codeProcessor,
+                    this.sourceLocationCollection);
+}
+
+/// A collection of source locations.
+///
+/// Used to index source locations for visualization and linking.
+class SourceLocationCollection {
+  List<SourceLocation> sourceLocations = [];
+  Map<SourceLocation, int> sourceLocationIndexMap;
+
+  SourceLocationCollection([SourceLocationCollection parent])
+      : sourceLocationIndexMap =
+            parent == null ? {} : parent.sourceLocationIndexMap;
+
+  int registerSourceLocation(SourceLocation sourceLocation) {
+    return sourceLocationIndexMap.putIfAbsent(sourceLocation, () {
+      sourceLocations.add(sourceLocation);
+      return sourceLocationIndexMap.length;
+    });
+  }
+
+  int getIndex(SourceLocation sourceLocation) {
+    return sourceLocationIndexMap[sourceLocation];
+  }
+}
+
+/// Processor that computes the HTML representation of a block of JavaScript
+/// code and collects the source locations mapped in the code.
+class CodeProcessor {
+  int lineIndex = 0;
+  final String onclick;
+  int currentJsSourceOffset = 0;
+  final SourceLocationCollection collection;
+  final Map<int, List<SourceLocation>> codeLocations = {};
+
+  CodeProcessor(this.onclick, this.collection);
+
+  void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
+    codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation);
+    collection.registerSourceLocation(sourceLocation);
+  }
+
+  String convertToHtml(String text) {
+    StringBuffer htmlBuffer = new StringBuffer();
+    int offset = 0;
+    int lineIndex = 0;
+    bool pendingSourceLocationsEnd = false;
+    htmlBuffer.write(lineNumber(lineIndex));
+    SourceLocation currentLocation;
+
+    void endCurrentLocation() {
+      if (currentLocation != null) {
+        htmlBuffer.write('</a>');
+      }
+      currentLocation = null;
+    }
+
+    void addSubstring(int until) {
+      if (until <= offset) return;
+
+      String substring = text.substring(offset, until);
+      offset = until;
+      bool first = true;
+      for (String line in substring.split('\n')) {
+        if (!first) {
+          endCurrentLocation();
+          htmlBuffer.write('\n');
+          lineIndex++;
+          htmlBuffer.write(lineNumber(lineIndex));
+        }
+        htmlBuffer.write(escape(line));
+        first = false;
+      }
+    }
+
+    void insertSourceLocations(List<SourceLocation> lastSourceLocations) {
+      endCurrentLocation();
+
+      String color;
+      int index;
+      String title;
+      if (lastSourceLocations.length == 1) {
+        SourceLocation sourceLocation = lastSourceLocations.single;
+        if (sourceLocation != null) {
+          index = collection.getIndex(sourceLocation);
+          color = "background:#${toColor(index)};";
+          title = sourceLocation.shortText;
+          currentLocation = sourceLocation;
+        }
+      } else {
+
+        index = collection.getIndex(lastSourceLocations.first);
+        StringBuffer sb = new StringBuffer();
+        double delta = 100.0 / (lastSourceLocations.length);
+        double position = 0.0;
+
+        void addColor(String color) {
+          sb.write(', ${color} ${position.toInt()}%');
+          position += delta;
+          sb.write(', ${color} ${position.toInt()}%');
+        }
+
+        for (SourceLocation sourceLocation in lastSourceLocations) {
+          if (sourceLocation == null) continue;
+          int colorIndex = collection.getIndex(sourceLocation);
+          addColor('#${toColor(colorIndex)}');
+          currentLocation = sourceLocation;
+        }
+        color = 'background: linear-gradient(to right${sb}); '
+                'background-size: 10px 10px;';
+        title = lastSourceLocations.map((l) => l.shortText).join(',');
+      }
+      if (index != null) {
+        Set<int> indices =
+            lastSourceLocations.map((l) => collection.getIndex(l)).toSet();
+        String onmouseover = indices.map((i) => '\'$i\'').join(',');
+        htmlBuffer.write(
+            '<a name="js$index" href="#${index}" style="$color" title="$title" '
+            'onclick="${onclick}" onmouseover="highlight([${onmouseover}]);"'
+            'onmouseout="highlight([]);">');
+        pendingSourceLocationsEnd = true;
+      }
+      if (lastSourceLocations.last == null) {
+        endCurrentLocation();
+      }
+    }
+
+    for (int targetOffset in codeLocations.keys.toList()..sort()) {
+      List<SourceLocation> sourceLocations = codeLocations[targetOffset];
+      addSubstring(targetOffset);
+      insertSourceLocations(sourceLocations);
+    }
+
+    addSubstring(text.length);
+    endCurrentLocation();
+    return htmlBuffer.toString();
+  }
+}
+
+/// Computes the HTML representation for a collection of JavaScript code blocks.
+String computeJsHtml(Iterable<SourceMapHtmlInfo> infoList) {
+
+  StringBuffer jsCodeBuffer = new StringBuffer();
+  for (SourceMapHtmlInfo info in infoList) {
+    String name = info.sourceMapInfo.name;
+    String html = info.codeProcessor.convertToHtml(info.sourceMapInfo.code);
+    String onclick = 'show(\'$name\');';
+    jsCodeBuffer.write(
+        '<h3 onclick="$onclick">JS code for: ${escape(name)}</h3>\n');
+    jsCodeBuffer.write('''
+<pre>
+$html
+</pre>
+''');
+  }
+  return jsCodeBuffer.toString();
+}
+
+/// Computes the HTML representation of the source mapping information for a
+/// collection of JavaScript code blocks.
+String computeJsTraceHtml(Iterable<SourceMapHtmlInfo> infoList) {
+  StringBuffer jsTraceBuffer = new StringBuffer();
+  for (SourceMapHtmlInfo info in infoList) {
+    String name = info.sourceMapInfo.name;
+    String jsTrace = computeJsTraceHtmlPart(
+        info.sourceMapInfo.codePoints, info.sourceLocationCollection);
+    jsTraceBuffer.write('''
+<div name="$name" class="js-trace-buffer" style="display:none;">
+<h3>Trace for: ${escape(name)}</h3>
+$jsTrace
+</div>
+''');
+  }
+  return jsTraceBuffer.toString();
+}
+
+/// Computes the HTML information for the [info].
+SourceMapHtmlInfo createHtmlInfo(SourceLocationCollection collection,
+                                 SourceMapInfo info) {
+  js.Node node = info.node;
+  String code = info.code;
+  String name = info.name;
+  String onclick = 'show(\'$name\');';
+  SourceLocationCollection subcollection =
+      new SourceLocationCollection(collection);
+  CodeProcessor codeProcessor = new CodeProcessor(onclick, subcollection);
+  for (js.Node node in info.nodeMap.nodes) {
+    info.nodeMap[node].forEach(
+        (int targetOffset, List<SourceLocation> sourceLocations) {
+      for (SourceLocation sourceLocation in sourceLocations) {
+        codeProcessor.addSourceLocation(targetOffset, sourceLocation);
+      }
+    });
+  }
+  return new SourceMapHtmlInfo(info, codeProcessor, subcollection);
+}
+
+/// Outputs a HTML file in [jsMapHtmlUri] containing an interactive
+/// visualization of the source mapping information in [infoList] computed
+/// with the [sourceMapProcessor].
+void createTraceSourceMapHtml(Uri jsMapHtmlUri,
+                              SourceMapProcessor sourceMapProcessor,
+                              Iterable<SourceMapInfo> infoList) {
+  SourceFileManager sourceFileManager = sourceMapProcessor.sourceFileManager;
+  SourceLocationCollection collection = new SourceLocationCollection();
+  List<SourceMapHtmlInfo> htmlInfoList = <SourceMapHtmlInfo>[];
+  for (SourceMapInfo info in infoList) {
+    htmlInfoList.add(createHtmlInfo(collection, info));
+  }
+
+  String jsCode = computeJsHtml(htmlInfoList);
+  String dartCode = computeDartHtml(sourceFileManager, htmlInfoList);
+
+  String jsTraceHtml = computeJsTraceHtml(htmlInfoList);
+  outputJsDartTrace(jsMapHtmlUri, jsCode, dartCode, jsTraceHtml);
+  print('Trace source map html generated: $jsMapHtmlUri');
+}
+
+/// Computes the HTML representation for the Dart code snippets referenced in
+/// [infoList].
+String computeDartHtml(
+    SourceFileManager sourceFileManager,
+    Iterable<SourceMapHtmlInfo> infoList) {
+
+  StringBuffer dartCodeBuffer = new StringBuffer();
+  for (SourceMapHtmlInfo info in infoList) {
+    dartCodeBuffer.write(computeDartHtmlPart(info.sourceMapInfo.name,
+         sourceFileManager, info.sourceLocationCollection));
+  }
+  return dartCodeBuffer.toString();
+
+}
+
+/// Computes the HTML representation for the Dart code snippets in [collection].
+String computeDartHtmlPart(String name,
+                           SourceFileManager sourceFileManager,
+                           SourceLocationCollection collection,
+                           {bool showAsBlock: false}) {
+  const int windowSize = 3;
+  StringBuffer dartCodeBuffer = new StringBuffer();
+  Map<Uri, Map<int, List<SourceLocation>>> sourceLocationMap = {};
+  collection.sourceLocations.forEach((SourceLocation sourceLocation) {
+    Map<int, List<SourceLocation>> uriMap =
+        sourceLocationMap.putIfAbsent(sourceLocation.sourceUri, () => {});
+    List<SourceLocation> lineList =
+        uriMap.putIfAbsent(sourceLocation.line, () => []);
+    lineList.add(sourceLocation);
+  });
+  sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) {
+    SourceFile sourceFile = sourceFileManager.getSourceFile(uri);
+    StringBuffer codeBuffer = new StringBuffer();
+
+    int firstLineIndex;
+    int lastLineIndex;
+
+    void flush() {
+      if (firstLineIndex != null && lastLineIndex != null) {
+        dartCodeBuffer.write(
+            '<h4>${uri.pathSegments.last}, '
+            '${firstLineIndex - windowSize + 1}-'
+            '${lastLineIndex + windowSize + 1}'
+            '</h4>\n');
+        dartCodeBuffer.write('<pre>\n');
+        for (int line = firstLineIndex - windowSize;
+             line < firstLineIndex;
+             line++) {
+          if (line >= 0) {
+            dartCodeBuffer.write(lineNumber(line));
+            dartCodeBuffer.write(sourceFile.getLineText(line));
+          }
+        }
+        dartCodeBuffer.write(codeBuffer);
+        for (int line = lastLineIndex + 1;
+             line <= lastLineIndex + windowSize;
+             line++) {
+          if (line < sourceFile.lines) {
+            dartCodeBuffer.write(lineNumber(line));
+            dartCodeBuffer.write(sourceFile.getLineText(line));
+          }
+        }
+        dartCodeBuffer.write('</pre>\n');
+        firstLineIndex = null;
+        lastLineIndex = null;
+      }
+      codeBuffer.clear();
+    }
+
+    List<int> lineIndices = uriMap.keys.toList()..sort();
+    lineIndices.forEach((int lineIndex) {
+      List<SourceLocation> locations = uriMap[lineIndex];
+      if (lastLineIndex != null &&
+          lastLineIndex + windowSize * 4 < lineIndex) {
+        flush();
+      }
+      if (firstLineIndex == null) {
+        firstLineIndex = lineIndex;
+      } else {
+        for (int line = lastLineIndex + 1; line < lineIndex; line++) {
+          codeBuffer.write(lineNumber(line));
+          codeBuffer.write(sourceFile.getLineText(line));
+        }
+      }
+      String line = sourceFile.getLineText(lineIndex);
+      locations.sort((a, b) => a.offset.compareTo(b.offset));
+      for (int i = 0; i < locations.length; i++) {
+        SourceLocation sourceLocation = locations[i];
+        int index = collection.getIndex(sourceLocation);
+        int start = sourceLocation.column;
+        int end = line.length;
+        if (i + 1 < locations.length) {
+          end = locations[i + 1].column;
+        }
+        if (i == 0) {
+          codeBuffer.write(lineNumber(lineIndex));
+          codeBuffer.write(line.substring(0, start));
+        }
+        codeBuffer.write(
+            '<a name="${index}" style="background:#${toColor(index)};" '
+            'title="[${lineIndex + 1},${start + 1}]" '
+            'onmouseover="highlight(\'$index\');" '
+            'onmouseout="highlight();">');
+        codeBuffer.write(line.substring(start, end));
+        codeBuffer.write('</a>');
+      }
+      lastLineIndex = lineIndex;
+    });
+
+    flush();
+  });
+  String display = showAsBlock ? 'block' : 'none';
+  return '''
+<div name="$name" class="dart-buffer" style="display:$display;">
+<h3>Dart code for: ${escape(name)}</h3>
+${dartCodeBuffer}
+</div>''';
+}
+
+/// Computes a HTML visualization of the [codePoints].
+String computeJsTraceHtmlPart(List<CodePoint> codePoints,
+                              SourceLocationCollection collection) {
+  StringBuffer buffer = new StringBuffer();
+  buffer.write('<table style="width:100%;">');
+  buffer.write(
+      '<tr><th>Node kind</th><th>JS code @ offset</th>'
+      '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>');
+  codePoints.forEach((CodePoint codePoint) {
+    String jsCode = codePoint.jsCode;
+    if (jsCode.length > 40) {
+      jsCode = jsCode.substring(0, 40);
+    }
+    if (codePoint.sourceLocation != null) {
+      int index = collection.getIndex(codePoint.sourceLocation);
+      if (index != null) {
+
+        buffer.write('<tr style="background:#${toColor(index)};" '
+                     'name="trace$index" '
+                     'onmouseover="highlight([${index}]);"'
+                     'onmouseout="highlight([]);">');
+      } else {
+        buffer.write('<tr>');
+        print('${codePoint.sourceLocation} not found in ');
+        collection.sourceLocationIndexMap.keys
+            .where((l) => l.sourceUri == codePoint.sourceLocation.sourceUri)
+            .forEach((l) => print(' $l'));
+      }
+    } else {
+      buffer.write('<tr>');
+    }
+    buffer.write('<td>${codePoint.kind}</td>');
+    buffer.write('<td class="code">${jsCode}</td>');
+    if (codePoint.sourceLocation == null) {
+      //buffer.write('<td></td>');
+    } else {
+      buffer.write('<td class="code">${codePoint.dartCode}</td>');
+      buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>');
+    }
+    buffer.write('</tr>');
+  });
+  buffer.write('</table>');
+
+  return buffer.toString();
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
new file mode 100644
index 0000000..573b902
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
@@ -0,0 +1,136 @@
+// 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.
+
+/// Templates used for the HTML visualization of source map information.
+
+library sourcemap.html.templates;
+
+import 'dart:io';
+
+/// Outputs JavaScript/Dart source mapping traces into [uri].
+void outputJsDartTrace(
+    Uri uri,
+    String jsCodeHtml,
+    String dartCodeHtml,
+    String jsTraceHtml) {
+  String html = '''
+<div class="js-buffer">
+${jsCodeHtml}
+</div>
+${dartCodeHtml}
+${jsTraceHtml}
+''';
+  String css = '''
+.js-buffer {
+  left:0%;
+  width:50%;
+  top:0%;
+  height:50%;
+}
+.dart-buffer {
+  right:0%;
+  width:50%;
+  top:0%;
+  height:50%;
+}
+.js-trace-buffer {
+  left:0%;
+  width:100%;
+  top:50%;
+  height:50%;
+}
+''';
+  outputInTemplate(uri, html, css);
+}
+
+/// Outputs [html] with customized [css] in [uri].
+void outputInTemplate(Uri uri,
+                      String html,
+                      String css) {
+  output(uri, '''
+<html>
+<head>
+<style>
+a, a:hover {
+  text-decoration: none;
+  color: #000;
+}
+h3 {
+  cursor: pointer;
+}
+.lineNumber {
+  font-size: smaller;
+  color: #888;
+}
+.buffer, .js-buffer, .dart-buffer, .js-trace-buffer {
+  position:fixed;
+  top:0px;
+  height:100%;
+  overflow:auto;
+}
+$css,
+.code {
+  font-family: monospace;
+}
+</style>
+</head>
+<body>
+<script>
+function setAll(name, property, value) {
+  var elements = document.getElementsByName(name);
+  for (var i = 0; i < elements.length; i++) {
+    elements[i].style[property] = value;
+  }
+}
+
+var shownName;
+function show(name) {
+  if (shownName != name) {
+    if (shownName) {
+      setAll(shownName, 'display', 'none');
+    }
+    shownName = name;
+    if (shownName) {
+      setAll(shownName, 'display', 'block');
+    }
+  }
+}
+var highlightNames = [];
+function highlight(names) {
+  var property = 'text-decoration';
+  var onValue = 'underline';
+  var offValue = 'none';
+  if (highlightNames != names) {
+    if (highlightNames && highlightNames.length > 0) {
+      for (var index in highlightNames) {
+        var highlightName = highlightNames[index];
+        setAll(highlightName, property, offValue);
+        setAll('js' + highlightName, property, offValue);
+        setAll('trace' + highlightName, property, offValue);
+      }
+    }
+    highlightNames = names;
+    if (highlightNames && highlightNames.length > 0) {
+      for (var index in highlightNames) {  
+        var highlightName = highlightNames[index];
+        setAll(highlightName, property, onValue);
+        setAll('js' + highlightName, property, onValue);
+        setAll('trace' + highlightName, property, onValue);
+      }
+    }
+  }
+}
+</script>
+$html
+</body>
+</html>
+''');
+}
+
+/// Outputs [html] in [uri].
+void output(Uri uri,
+            String html) {
+  File outputFile = new File.fromUri(uri);
+  outputFile.writeAsStringSync(html);
+}
diff --git a/tests/compiler/dart2js/token_naming_test.dart b/tests/compiler/dart2js/token_naming_test.dart
new file mode 100644
index 0000000..7f99d5e
--- /dev/null
+++ b/tests/compiler/dart2js/token_naming_test.dart
@@ -0,0 +1,63 @@
+// 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:compiler/src/js_backend/js_backend.dart" show TokenScope;
+
+import "package:expect/expect.dart";
+
+String forwardN(TokenScope scope, int N) {
+  for (int i = 1; i < N; ++i) {
+    scope.getNextName();
+  }
+
+  return scope.getNextName();
+}
+
+int main() {
+  // Test a normal scope.
+  TokenScope scope = new TokenScope();
+
+  // We start with 'a'.
+  Expect.equals("a", scope.getNextName());
+  // We have 24 lower case characters, as s and g are illegal.
+  Expect.equals("A", forwardN(scope, 24));
+  // Make it overflow by skipping all uppercase.
+  Expect.equals("a_", forwardN(scope, 26));
+  // Now numbers.
+  Expect.equals("a0", forwardN(scope, 1));
+  Expect.equals("a9", forwardN(scope, 9));
+  // Then lower case letters.
+  Expect.equals("aa", forwardN(scope, 1));
+  Expect.equals("az", forwardN(scope, 25));
+  // Then upper case letters
+  Expect.equals("aA", forwardN(scope, 1));
+  Expect.equals("aZ", forwardN(scope, 25));
+  // Overflow to first position.
+  Expect.equals("b_", forwardN(scope, 1));
+  // Make sure we skipe g. We have 1 + 10 + 26 + 26 = 63 digits.
+  Expect.equals("h_", forwardN(scope, 63 * 5));
+  // Likewise, ensure we skip s.
+  Expect.equals("t_", forwardN(scope, 63 * 11));
+  // And wrap around another digit. 
+  Expect.equals("a__", forwardN(scope, 63 * 33));
+
+  // Test a filtered scope.
+  Set<String> illegal = new Set.from(["b", "aa"]);
+  scope = new TokenScope(illegal);
+
+  // We start with 'a'.
+  Expect.equals("a", forwardN(scope, 1));
+  // Make sure 'b' is skipped.
+  Expect.equals("c", forwardN(scope, 1));
+  // We have 24 lower case characters, as s and g are illegal.
+  Expect.equals("A", forwardN(scope, 22));
+  // Make it overflow by skipping all uppercase.
+  Expect.equals("a_", forwardN(scope, 26));
+  // Now numbers.
+  Expect.equals("a0", forwardN(scope, 1));
+  Expect.equals("a9", forwardN(scope, 9));
+  // Make sure 'aa' is skipped on wrapping
+  Expect.equals("ab", forwardN(scope, 1));
+  Expect.equals("az", forwardN(scope, 24));
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index c398750..d3968e2 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -64,45 +64,28 @@
 21724_test: Crash # Please triage this failure.
 
 [ $compiler == dart2js && $cps_ir ]
-11673_test: RuntimeError # Cannot read property 'prototype' of undefined
-12320_test: RuntimeError # Cannot read property 'prototype' of undefined
 16407_test: Pass # Please triage this failure.
-22487_test: RuntimeError # Cannot read property 'prototype' of undefined
 22868_test: Crash # (main()async{var clo...  cannot handle async/sync*/async* functions
 22895_test: Crash # (main()async{var clo...  cannot handle async/sync*/async* functions
-23404_test: RuntimeError # Cannot read property 'prototype' of undefined
-23432_test : RuntimeError # 
-LayoutTests_fast_mediastream_getusermedia_t01_test/none: RuntimeError # Cannot read property 'prototype' of undefined
+23432_test: RuntimeError # Please triage this failure.
 async_stacktrace_test/asyncStar: Crash # (runTests()async{awa...  cannot handle async/sync*/async* functions
 async_stacktrace_test/none: Crash # (runTests()async{awa...  cannot handle async/sync*/async* functions
-closure5_test: RuntimeError # Cannot read property 'prototype' of undefined
 closure_capture5_test: Crash # (i=0): For-loop variable captured in loop header
-conditional_send_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_class_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_constant2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_constant3_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_constant4_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_function_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_mirrors1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred/deferred_mirrors2_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-deferred/deferred_overlapping_test: RuntimeError # receiver.get$_collection$_nums is not a function
-for_test: RuntimeError # Please triage this failure.
-if_null_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirror_invalid_field_access3_test: Crash # Internal Error: No default constructor available.
-mirror_invalid_field_access_test: Crash # Internal Error: No default constructor available.
-mirror_invalid_invoke3_test: Crash # Internal Error: No default constructor available.
-mirror_invalid_invoke_test: Crash # Internal Error: No default constructor available.
-mirror_printer_test: Crash # Internal Error: No default constructor available.
-mirror_test: Crash # Internal Error: No default constructor available.
-mirror_type_inference_field2_test: Crash # Internal Error: No default constructor available.
-mirror_type_inference_field_test: Crash # Internal Error: No default constructor available.
-mirror_type_inference_function_test: Crash # Internal Error: No default constructor available.
-mirrors_used_warning2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-mirrors_used_warning_test/minif : RuntimeError # TypeError: receiver.get$_nums is not a function
-mirrors_used_warning_test/none : RuntimeError # TypeError: receiver.get$_nums is not a function
-reflect_native_types_test: Crash # Internal Error: No default constructor available.
-runtime_type_test: RuntimeError # Cannot read property 'prototype' of undefined
+conditional_send_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_class_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_constant2_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_constant3_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_constant4_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_function_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_mirrors1_test: RuntimeError # receiver.get$_nums is not a function
+deferred/deferred_mirrors2_test: RuntimeError # receiver.get$_collection$_nums is not a function
+deferred/deferred_overlapping_test: RuntimeError # receiver.get$_nums is not a function
+if_null_test: RuntimeError # receiver.get$_nums is not a function
+mirror_printer_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors_used_warning2_test: RuntimeError # receiver.get$_nums is not a function
+mirrors_used_warning_test/minif: RuntimeError # receiver.get$_nums is not a function
+mirrors_used_warning_test/none: RuntimeError # receiver.get$_nums is not a function
+reflect_native_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
 switch_test/none: Crash # (switch (val){foo:ba...  continue to a labeled switch case
-timer_test: RuntimeError # receiver.get$_collection$_nums is not a function
-no_such_method_test : Crash # Internal Error: No default constructor available.
-mirrors_used_closure_test : Crash # Internal Error: No default constructor available.
+timer_test: RuntimeError # receiver.get$_nums is not a function
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index bb3bb85..2b3774c 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -21,16 +21,15 @@
 compute_this_script_test: Skip # Issue 17458
 
 [ $compiler == dart2js && $cps_ir ]
-compute_this_script_test: RuntimeError # receiver.get$_collection$_nums is not a function
-event_loop_test: RuntimeError # receiver.get$_collection$_nums is not a function
-internal_library_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mirror_intercepted_field_test: Crash # Internal Error: No default constructor available.
+compute_this_script_test: RuntimeError # receiver.get$_nums is not a function
+event_loop_test: RuntimeError # receiver.get$_nums is not a function
+internal_library_test: RuntimeError # receiver.get$_nums is not a function
+mirror_intercepted_field_test: Crash # (=_EmptyStream<T>;): Unhandled node
 native_closure_identity_frog_test: RuntimeError # invoke is not a function
 native_exception_test: RuntimeError # J.getInterceptor(...).toString$0 is not a function
 native_method_inlining_test: RuntimeError # Please triage this failure.
-native_mirror_test: Crash # Internal Error: No default constructor available.
-native_mixin_field_test: RuntimeError # Please triage this failure.
-native_no_such_method_exception3_frog_test : RuntimeError # 
+native_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+native_no_such_method_exception3_frog_test: RuntimeError # Please triage this failure.
 native_wrapping_function3_frog_test: RuntimeError # invoke is not a function
 native_wrapping_function_frog_test: RuntimeError # invoke is not a function
 optimization_hints_test: RuntimeError # Please triage this failure.
diff --git a/tests/corelib/big_integer_arith_vm_test.dart b/tests/corelib/big_integer_arith_vm_test.dart
index 8b76ba0..49e6e0d 100644
--- a/tests/corelib/big_integer_arith_vm_test.dart
+++ b/tests/corelib/big_integer_arith_vm_test.dart
@@ -231,7 +231,7 @@
   Expect.equals(0, x.modInverse(m));
   x = 0;
   m = 1000000001;
-  Expect.throws(() => x.modInverse(m), (e) => e is RangeError);  // Not coprime.
+  Expect.throws(() => x.modInverse(m), (e) => e is Exception);  // Not coprime.
   x = 1234567890;
   m = 19;
   Expect.equals(11, x.modInverse(m));
@@ -240,7 +240,7 @@
   Expect.equals(189108911, x.modInverse(m));
   x = 19;
   m = 1000000001;
-  Expect.throws(() => x.modInverse(m), (e) => e is RangeError);  // Not coprime.
+  Expect.throws(() => x.modInverse(m), (e) => e is Exception);  // Not coprime.
   x = 19;
   m = 1234567890;
   Expect.equals(519818059, x.modInverse(m));
@@ -249,7 +249,7 @@
   Expect.equals(1001100101, x.modInverse(m));
   x = 1000000001;
   m = 19;
-  Expect.throws(() => x.modInverse(m), (e) => e is RangeError);  // Not coprime.
+  Expect.throws(() => x.modInverse(m), (e) => e is Exception);  // Not coprime.
   x = 12345678901234567890;
   m = 19;
   Expect.equals(3, x.modInverse(m));
@@ -276,7 +276,7 @@
   Expect.equals(3, x.modInverse(m));
   x = 123456789012345678901234567890;
   m = 123456789012345678901234567899;
-  Expect.throws(() => x.modInverse(m), (e) => e is RangeError);  // Not coprime.
+  Expect.throws(() => x.modInverse(m), (e) => e is Exception);  // Not coprime.
   x = 123456789012345678901234567890;
   m = 123456789012345678901234567891;
   Expect.equals(123456789012345678901234567890, x.modInverse(m));
@@ -285,7 +285,7 @@
   Expect.equals(77160493132716049313271604932, x.modInverse(m));
   x = 123456789012345678901234567899;
   m = 123456789012345678901234567890;
-  Expect.throws(() => x.modInverse(m), (e) => e is RangeError);  // Not coprime.
+  Expect.throws(() => x.modInverse(m), (e) => e is Exception);  // Not coprime.
   x = 123456789012345678901234567891;
   m = 123456789012345678901234567890;
   Expect.equals(1, x.modInverse(m));
@@ -310,10 +310,31 @@
   Expect.equals(21 <<40, x.gcd(m));
   x = 0;
   m = 1000000001;
-  Expect.throws(() => x.gcd(m), (e) => e is RangeError);
+  Expect.equals(m, x.gcd(m));
   x = 1000000001;
   m = 0;
-  Expect.throws(() => x.gcd(m), (e) => e is RangeError);
+  Expect.equals(x, x.gcd(m));
+  x = 0;
+  m = -1000000001;
+  Expect.equals(-m, x.gcd(m));
+  x = -1000000001;
+  m = 0;
+  Expect.equals(-x, x.gcd(m));
+  x = 0;
+  m = 0;
+  Expect.equals(0, x.gcd(m));
+  x = 0;
+  m = 123456789012345678901234567890;
+  Expect.equals(m, x.gcd(m));
+  x = 123456789012345678901234567890;
+  m = 0;
+  Expect.equals(x, x.gcd(m));
+  x = 0;
+  m = -123456789012345678901234567890;
+  Expect.equals(-m, x.gcd(m));
+  x = -123456789012345678901234567890;
+  m = 0;
+  Expect.equals(-x, x.gcd(m));
   x = 1234567890;
   m = 19;
   Expect.equals(1, x.gcd(m));
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 693a690..4f9274e 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -213,47 +213,26 @@
 big_integer_parsed_mul_div_vm_test: Pass, Slow
 
 [ $compiler == dart2js && $cps_ir ]
-date_time2_test: RuntimeError # Cannot read property 'prototype' of undefined
-date_time3_test: RuntimeError # Cannot read property 'prototype' of undefined
-date_time4_test: RuntimeError # Cannot read property 'prototype' of undefined
-date_time7_test: RuntimeError # Cannot read property 'prototype' of undefined
-date_time_parse_test: RuntimeError # Cannot read property 'prototype' of undefined
 error_stack_trace1_test: Pass # H.unwrapException(...).get$stackTrace is not a function
 hashcode_test: RuntimeError # Please triage this failure.
-int_parse_radix_test/01: Crash # Invalid argument(s)
-int_parse_radix_test/02: Crash # Invalid argument(s)
 iterable_empty_test: RuntimeError # Please triage this failure.
 iterable_return_type_test/none: RuntimeError # Please triage this failure.
 iterable_to_list_test: RuntimeError # Please triage this failure.
 iterable_to_set_test: RuntimeError # Please triage this failure.
 list_test/01: RuntimeError # this.get$length is not a function
 list_test/none: RuntimeError # this.get$length is not a function
-main_test: RuntimeError # receiver.get$_collection$_nums is not a function
+main_test: RuntimeError # receiver.get$_nums is not a function
 map_values2_test: RuntimeError # Please triage this failure.
 map_values3_test: RuntimeError # Please triage this failure.
 map_values4_test: RuntimeError # Please triage this failure.
-null_test: RuntimeError # Cannot read property 'prototype' of undefined
-reg_exp_first_match_test: RuntimeError # Cannot read property 'prototype' of undefined
-reg_exp_group_test: RuntimeError # Cannot read property 'prototype' of undefined
-reg_exp_string_match_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/capture-3_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/extended-characters-match_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/non-bmp_test: RuntimeError # Cannot read property 'prototype' of undefined
 regexp/pcre_test: Crash # Stack Overflow
-regexp/regress-regexp-construct-result_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/results-cache_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/stack-overflow_test: RuntimeError # Cannot read property 'prototype' of undefined
-regexp/unicode-handling_test: RuntimeError # Cannot read property 'prototype' of undefined
-shuffle_test: RuntimeError # Please triage this failure.
-stacktrace_fromstring_test: RuntimeError # receiver.get$_collection$_nums is not a function
-stopwatch2_test: RuntimeError # Cannot read property 'prototype' of undefined
-stopwatch_test: RuntimeError # Cannot read property 'prototype' of undefined
-string_fromcharcodes_test: RuntimeError # Please triage this failure.
-string_replace_all_test: RuntimeError # Cannot read property 'prototype' of undefined
-symbol_operator_test/03 : RuntimeError # 
+shuffle_test: RuntimeError # this.get$length is not a function
+stacktrace_fromstring_test: RuntimeError # receiver.get$_nums is not a function
+string_fromcharcodes_test: RuntimeError # this.get$length is not a function
+symbol_operator_test/03: RuntimeError # Please triage this failure.
 symbol_reserved_word_test/03: Pass # Please triage this failure.
 symbol_reserved_word_test/06: RuntimeError # Please triage this failure.
 symbol_reserved_word_test/09: RuntimeError # Please triage this failure.
 symbol_reserved_word_test/12: RuntimeError # Please triage this failure.
 symbol_test/none: Crash # The null object does not have a getter '_element'.
-uri_test: Crash # Invalid argument(s)
+uri_test: Crash # The null object does not have a getter '_element'.
diff --git a/tests/corelib/int_modulo_arith_test.dart b/tests/corelib/int_modulo_arith_test.dart
index 87d253d..9d5b9eb 100644
--- a/tests/corelib/int_modulo_arith_test.dart
+++ b/tests/corelib/int_modulo_arith_test.dart
@@ -141,14 +141,15 @@
   // Test that gcd of value and other (non-negative) is expectedResult.
   // Tests all combinations of positive and negative values and order of
   // operands, so use positive values and order is not important.
-  test(value, other, [expectedResult]) {
-    assert(value % expectedResult == 0);  // Check for bug in test.
-    assert(other % expectedResult == 0);
+  test(value, other, expectedResult) {
+    // Check for bug in test.
+    assert(expectedResult == 0 || value % expectedResult == 0);
+    assert(expectedResult == 0 || other % expectedResult == 0);
     callCombos(value, other, (a, b) {
       var result = a.gcd(b);
       /// Check that the result is a divisor.
-      Expect.equals(0, a % result, "$result | $a");
-      Expect.equals(0, b % result, "$result | $b");
+      Expect.equals(0, result == 0 ? a : a % result, "$result | $a");
+      Expect.equals(0, result == 0 ? b : b % result, "$result | $b");
       // Check for bug in test. If assert fails, the expected value is too low,
       // and the gcd call has found a greater common divisor.
       assert(result >= expectedResult);
@@ -163,9 +164,8 @@
     });
   }
 
-  // Throws if either operand is zero, and if both operands are zero.
-  testThrows(0, 1000);
-  testThrows(0, 0);
+  testThrows(2.5, 5);  // Not a method on double.
+  testThrows(5, 2.5);  // Not accepting non-int arguments.
 
   // Format:
   //  test(value1, value2, expectedResult);
@@ -176,6 +176,9 @@
 
   test(9999, 7272, 909);  // Larger numbers
 
+  test(0, 1000, 1000);  // One operand is zero.
+  test(0, 0, 0);        // Both operands are zero.
+
   // Multiplying both operands by a number multiplies result by same number.
   test(693, 609, 21);
   test(693 << 5, 609 << 5, 21 << 5);
diff --git a/tests/html/html.status b/tests/html/html.status
index 1dd6339..27ea36a 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -416,4 +416,3 @@
 webgl_1_test: StaticWarning
 window_nosuchmethod_test: StaticWarning
 
-[ $compiler == dart2js && $cps_ir ]
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index e6b89b8..2472eb6 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -129,54 +129,52 @@
 bool_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
 capability_test: RuntimeError # receiver.get$_collection$_nums is not a function
 compile_time_error_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-count_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-cross_isolate_message_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-deferred_in_isolate2_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
+count_test: RuntimeError # receiver.get$_nums is not a function
+cross_isolate_message_test: RuntimeError # receiver.get$_nums is not a function
+deferred_in_isolate2_test: RuntimeError # receiver.get$_collection$_nums is not a function
 deferred_in_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
 function_send_test: RuntimeError # receiver.get$_nums is not a function
 handle_error2_test: RuntimeError # receiver.get$_collection$_nums is not a function
 handle_error3_test: RuntimeError # receiver.get$_collection$_nums is not a function
 handle_error_test: RuntimeError # receiver.get$_collection$_nums is not a function
-illegal_msg_function_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-illegal_msg_mirror_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+illegal_msg_function_test: RuntimeError # receiver.get$_nums is not a function
+illegal_msg_mirror_test: RuntimeError # receiver.get$_nums is not a function
 int_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-isolate_complex_messages_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+isolate_complex_messages_test: RuntimeError # receiver.get$_nums is not a function
 isolate_current_test: RuntimeError # receiver.get$_nums is not a function
 isolate_import_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
 issue_22778_test: RuntimeError # receiver.get$_collection$_nums is not a function
 kill2_test: RuntimeError # receiver.get$_collection$_nums is not a function
 kill_self_test: RuntimeError # receiver.get$_collection$_nums is not a function
 kill_test: RuntimeError # receiver.get$_collection$_nums is not a function
-mandel_isolate_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-message2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+mandel_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
+message2_test: RuntimeError # receiver.get$_nums is not a function
 message3_test/byteBuffer: RuntimeError # receiver.get$_collection$_nums is not a function
-message3_test/constInstance: Crash # Invalid argument(s)
 message3_test/fun: RuntimeError # receiver.get$_collection$_nums is not a function
 message3_test/int32x4: RuntimeError # receiver.get$_collection$_nums is not a function
 message3_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
 message_enum_test: RuntimeError # receiver.get$_collection$_nums is not a function
-message_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-mint_maker_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-nested_spawn2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-nested_spawn_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+message_test: RuntimeError # receiver.get$_nums is not a function
+mint_maker_test: RuntimeError # receiver.get$_nums is not a function
+nested_spawn2_test: RuntimeError # receiver.get$_nums is not a function
+nested_spawn_test: RuntimeError # receiver.get$_nums is not a function
 object_leak_test: RuntimeError # receiver.get$_collection$_nums is not a function
 ondone_test: RuntimeError # receiver.get$_nums is not a function
 pause_test: RuntimeError # receiver.get$_nums is not a function
 ping_pause_test: RuntimeError # receiver.get$_collection$_nums is not a function
 ping_test: RuntimeError # receiver.get$_collection$_nums is not a function
 port_test: RuntimeError # receiver.get$_collection$_nums is not a function
-raw_port_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-request_reply_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+raw_port_test: RuntimeError # receiver.get$_nums is not a function
+request_reply_test: RuntimeError # receiver.get$_nums is not a function
 simple_message_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-spawn_function_custom_class_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-spawn_function_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-spawn_uri_missing_from_isolate_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-spawn_uri_missing_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-spawn_uri_multi_test/none: Crash # Invalid argument(s)
-stacktrace_message_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+spawn_function_custom_class_test: RuntimeError # receiver.get$_nums is not a function
+spawn_function_test: RuntimeError # receiver.get$_nums is not a function
+spawn_uri_missing_from_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
+spawn_uri_missing_test: RuntimeError # receiver.get$_collection$_nums is not a function
+stacktrace_message_test: RuntimeError # receiver.get$_nums is not a function
 start_paused_test: RuntimeError # receiver.get$_nums is not a function
-static_function_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+static_function_test: RuntimeError # receiver.get$_nums is not a function
 string_from_environment_default_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-timer_isolate_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
+timer_isolate_test: RuntimeError # receiver.get$_collection$_nums is not a function
 typed_message_test: RuntimeError # receiver.get$_nums is not a function
-unresolved_ports_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+unresolved_ports_test: RuntimeError # receiver.get$_nums is not a function
diff --git a/tests/language/closure_self_reference_test.dart b/tests/language/closure_self_reference_test.dart
index 9ffc951..a47b1bf 100644
--- a/tests/language/closure_self_reference_test.dart
+++ b/tests/language/closure_self_reference_test.dart
@@ -18,6 +18,6 @@
     }
   }
 
-  Expect.equals(0, inner(499));
-  Expect.equals(499, counter);
+  Expect.equals(0, inner(199));
+  Expect.equals(199, counter);
 }
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 5ced80a..d000c34 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -12,6 +12,7 @@
 await_test: CompileTimeError # Issue 22052
 async_await_test/02: CompileTimeError # Issue 22052
 regress_17382_test: Skip # don't care about the static warning.
+regress_23408_test: Skip # don't care about the warning.
 regress_23038_test/01: Skip # Issue 23038
 getter_setter_in_lib_test: Fail # issue 23286
 
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index b35f11c..fbd47b1 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -14,6 +14,7 @@
 enum_syntax_test/06: Fail # 21649
 
 regress_17382_test: Skip # don't care about the static warning.
+regress_23408_test: Skip # don't care about the static warning.
 getter_setter_in_lib_test: Fail # issue 23286
 
 # Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 7b73b20..f728a01 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -259,6 +259,7 @@
 async_await_syntax_test/a04c: Crash # (a04c()sync*{}): cannot handle async/sync*/async* functions
 async_await_syntax_test/a05a: Crash # (a05a()async{await 0;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/a05b: Crash # (a05b()async{await (a){};await (0);}): cannot handle async/sync*/async* functions
+async_await_syntax_test/a05h: Crash # (a05h()async{yield*st;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/a06a: Crash # (a06a()async{await for(var o in st){}}): cannot handle async/sync*/async* functions
 async_await_syntax_test/a07a: Crash # (a07a()sync*{yield 0;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/a08a: Crash # (a08a()sync*{yield* [] ;}): cannot handle async/sync*/async* functions
@@ -292,6 +293,8 @@
 async_await_syntax_test/c08a: Crash # (c08a()sync*{yield* [] ;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/c09a: Crash # (c09a()async*{yield 0;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/c10a: Crash # (c10a()async*{yield* [] ;}): cannot handle async/sync*/async* functions
+async_await_syntax_test/c11a: Crash # (c11a()async{yield-5;}): cannot handle async/sync*/async* functions
+async_await_syntax_test/c11b: Crash # (c11b()async{yield*st;}): cannot handle async/sync*/async* functions
 async_await_syntax_test/d01a: Crash # (()async=>null): cannot handle async/sync*/async* functions
 async_await_syntax_test/d02a: Crash # (()async{}): cannot handle async/sync*/async* functions
 async_await_syntax_test/d03a: Crash # (()async*{}): cannot handle async/sync*/async* functions
@@ -357,72 +360,56 @@
 await_postfix_expr_test: Crash # (test()async{Expect....  cannot handle async/sync*/async* functions
 await_regression_test: Crash # (main()async{testNes...  cannot handle async/sync*/async* functions
 await_test: Crash # (others()async{var a...  cannot handle async/sync*/async* functions
-bind_test: RuntimeError # Cannot read property 'prototype' of undefined
-canonical_const3_test: RuntimeError # Cannot read property 'prototype' of undefined
-cascade_test/none: RuntimeError # Cannot read property 'prototype' of undefined
-cha_deopt1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-cha_deopt2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-cha_deopt3_test: RuntimeError # receiver.get$_collection$_nums is not a function
-closure7_test: RuntimeError # Cannot read property 'prototype' of undefined
-closure8_test: RuntimeError # Cannot read property 'prototype' of undefined
-closure_cycles_test: RuntimeError # receiver.get$_collection$_nums is not a function
+cha_deopt1_test: RuntimeError # receiver.get$_nums is not a function
+cha_deopt2_test: RuntimeError # receiver.get$_nums is not a function
+cha_deopt3_test: RuntimeError # receiver.get$_nums is not a function
+closure_cycles_test: RuntimeError # receiver.get$_nums is not a function
 closure_in_constructor_test: Crash # Invalid argument(s)
-closure_shared_state_test: RuntimeError # Cannot read property 'prototype' of undefined
 closure_type_variables_test: Crash # Invalid argument(s)
-closures_initializer2_test: RuntimeError # Cannot read property 'prototype' of undefined
-const_evaluation_test/01: Crash # Internal Error: No default constructor available.
+const_evaluation_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
 constructor12_test: RuntimeError # Please triage this failure.
 crash_6725_test/01: Crash # The null object does not have a getter '_element'.
 custom_await_stack_trace_test: Crash # (main()async{try {va...  cannot handle async/sync*/async* functions
-cyclic_type_test/00: RuntimeError # Cannot read property 'prototype' of undefined
-cyclic_type_test/01: RuntimeError # Cannot read property 'prototype' of undefined
-cyclic_type_test/02: RuntimeError # Cannot read property 'prototype' of undefined
-cyclic_type_test/03: RuntimeError # Cannot read property 'prototype' of undefined
-cyclic_type_test/04: RuntimeError # Cannot read property 'prototype' of undefined
-deferred_closurize_load_library_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constant_list_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_constants_test/none: Crash # Internal Error: No default constructor available.
-deferred_constraints_constants_test/reference_after_load: Crash # Internal Error: No default constructor available.
-deferred_constraints_type_annotation_test/as_operation: RuntimeError # receiver.get$_collection$_nums is not a function
+deferred_closurize_load_library_test: RuntimeError # receiver.get$_nums is not a function
+deferred_constant_list_test: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_constants_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+deferred_constraints_constants_test/reference_after_load: Crash # (=_EmptyStream<T>;): Unhandled node
+deferred_constraints_type_annotation_test/as_operation: RuntimeError # receiver.get$_nums is not a function
 deferred_constraints_type_annotation_test/catch_check: Crash # The null object does not have a getter '_element'.
-deferred_constraints_type_annotation_test/is_check: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/new: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/new_before_load: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic1: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic2: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/new_generic3: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/static_method: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation1: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic1: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic2: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic3: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_generic4: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_non_deferred: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_null: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_constraints_type_annotation_test/type_annotation_top_level: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_function_type_test: RuntimeError # receiver.get$_collection$_nums is not a function
+deferred_constraints_type_annotation_test/is_check: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/new: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/new_before_load: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/new_generic1: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/new_generic2: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/new_generic3: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/none: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/static_method: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation1: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic1: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic2: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic3: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_generic4: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_non_deferred: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_null: RuntimeError # receiver.get$_nums is not a function
+deferred_constraints_type_annotation_test/type_annotation_top_level: RuntimeError # receiver.get$_nums is not a function
+deferred_function_type_test: RuntimeError # receiver.get$_nums is not a function
 deferred_global_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_inlined_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_load_constants_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_load_inval_code_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_load_library_wrong_args_test/none: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_mixin_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_no_such_method_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+deferred_inlined_test: RuntimeError # receiver.get$_nums is not a function
+deferred_load_constants_test/none: RuntimeError # receiver.get$_nums is not a function
+deferred_load_inval_code_test: RuntimeError # receiver.get$_nums is not a function
+deferred_load_library_wrong_args_test/none: RuntimeError # receiver.get$_nums is not a function
+deferred_mixin_test: RuntimeError # receiver.get$_nums is not a function
+deferred_no_such_method_test: RuntimeError # receiver.get$_nums is not a function
 deferred_not_loaded_check_test: RuntimeError # Please triage this failure.
-deferred_only_constant_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_optimized_test: RuntimeError # receiver.get$_collection$_nums is not a function
+deferred_only_constant_test: RuntimeError # receiver.get$_nums is not a function
+deferred_optimized_test: RuntimeError # receiver.get$_nums is not a function
 deferred_redirecting_factory_test: Crash # (test()async{await t...  cannot handle async/sync*/async* functions
-deferred_regression_22995_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_shadow_load_library_test: RuntimeError # receiver.get$_collection$_nums is not a function
-deferred_shared_and_unshared_classes_test: RuntimeError # receiver.get$_collection$_nums is not a function
+deferred_regression_22995_test: RuntimeError # receiver.get$_nums is not a function
+deferred_shadow_load_library_test: RuntimeError # receiver.get$_nums is not a function
+deferred_shared_and_unshared_classes_test: RuntimeError # receiver.get$_nums is not a function
 deferred_static_seperate_test: RuntimeError # receiver.get$_collection$_nums is not a function
-enum_mirror_test: Crash # Internal Error: No default constructor available.
-f_bounded_equality_test: RuntimeError # Cannot read property 'prototype' of undefined
-final_super_field_set_test/01 : RuntimeError # 
-fixed_type_variable_test/02: RuntimeError # Cannot read property 'prototype' of undefined
-fixed_type_variable_test/04: RuntimeError # Cannot read property 'prototype' of undefined
-fixed_type_variable_test/06: RuntimeError # Cannot read property 'prototype' of undefined
+enum_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+final_super_field_set_test/01: RuntimeError # Please triage this failure.
 flatten_test/01: Crash # (test()async{int x=await new Derived<int>();}): cannot handle async/sync*/async* functions
 flatten_test/02: Crash # (test()async{Future<int> f()async=>new Derived<int>();}): cannot handle async/sync*/async* functions
 flatten_test/03: Crash # (test()async{Future<...  cannot handle async/sync*/async* functions
@@ -438,110 +425,63 @@
 flatten_test/none: Crash # (test()async{}): cannot handle async/sync*/async* functions
 for2_test: Crash # The null object does not have a getter 'field'.
 for_variable_capture_test: Crash # (i=0): For-loop variable captured in loop header
-function_getter_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_literals_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_bound_closure0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_bound_closure1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_call0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_factory1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_local0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_local1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_named1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_not0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_optional1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_simple0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_simple1_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_simple2_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_subtype_top_level0_test: RuntimeError # Cannot read property 'prototype' of undefined
-function_type_alias6_test/none: RuntimeError # Cannot read property 'prototype' of undefined
-generic_creation_test: RuntimeError # Cannot read property 'prototype' of undefined
 generic_field_mixin3_test: RuntimeError # Please triage this failure.
-identical_closure_test: RuntimeError # Cannot read property 'prototype' of undefined
-if_null_assignment_static_test/01: RuntimeError # Issue 23669
-if_null_assignment_static_test/03: RuntimeError # Issue 23669
-if_null_assignment_static_test/04: RuntimeError # Issue 23669
-if_null_assignment_static_test/05: RuntimeError # Issue 23669
-if_null_assignment_static_test/36: RuntimeError # Issue 23669
-if_null_assignment_static_test/38: RuntimeError # Issue 23669
-if_null_assignment_static_test/39: RuntimeError # Issue 23669
-if_null_assignment_static_test/40: RuntimeError # Issue 23669
-implicit_closure1_test: RuntimeError # Cannot read property 'prototype' of undefined
-implicit_closure2_test: RuntimeError # Cannot read property 'prototype' of undefined
-implicit_closure_test: RuntimeError # Cannot read property 'prototype' of undefined
+if_null_assignment_static_test/01: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/03: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/04: RuntimeError # v0.get$b is not a function
+if_null_assignment_static_test/05: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/36: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/38: RuntimeError # v0.get$a is not a function
+if_null_assignment_static_test/39: RuntimeError # v0.get$b is not a function
+if_null_assignment_static_test/40: RuntimeError # v0.get$a is not a function
 infinite_switch_label_test: Crash # (switch (target){l0:...  continue to a labeled switch case
-inlined_conditional_test: RuntimeError # Cannot read property 'prototype' of undefined
-instance_creation_in_function_annotation_test: Crash # Internal Error: No default constructor available.
+instance_creation_in_function_annotation_test: Crash # (=_EmptyStream<T>;): Unhandled node
 instanceof4_test/01: RuntimeError # Please triage this failure.
-invocation_mirror_invoke_on_test : RuntimeError # 
+invocation_mirror_invoke_on_test: RuntimeError # Please triage this failure.
 invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
-is_function_test: RuntimeError # Cannot read property 'prototype' of undefined
-issue13179_test: RuntimeError # Cannot read property 'prototype' of undefined
-issue_1751477_test: RuntimeError # receiver.get$_collection$_nums is not a function
+issue_1751477_test: RuntimeError # receiver.get$_nums is not a function
 large_class_declaration_test: Crash # Stack Overflow
 list_test: RuntimeError # Please triage this failure.
-main_test/01: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/02: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/04: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/05: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/20: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/21: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/22: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/41: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/42: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/43: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/44: RuntimeError # receiver.get$_collection$_nums is not a function
-main_test/45: RuntimeError # receiver.get$_collection$_nums is not a function
-many_overridden_no_such_method_test : RuntimeError # 
-method_binding_test: RuntimeError # Cannot read property 'prototype' of undefined
-methods_as_constants2_test: RuntimeError # Cannot read property 'prototype' of undefined
-mint_compares_test: RuntimeError # Cannot read property 'prototype' of undefined
-mixin_super_constructor_named_test/01: Crash # Internal Error: No default constructor available.
-mixin_super_constructor_positionals_test/01: Crash # Internal Error: No default constructor available.
+main_test/01: RuntimeError # receiver.get$_nums is not a function
+main_test/02: RuntimeError # receiver.get$_nums is not a function
+main_test/04: RuntimeError # receiver.get$_nums is not a function
+main_test/05: RuntimeError # receiver.get$_nums is not a function
+main_test/20: RuntimeError # receiver.get$_nums is not a function
+main_test/21: RuntimeError # receiver.get$_nums is not a function
+main_test/22: RuntimeError # receiver.get$_nums is not a function
+main_test/41: RuntimeError # receiver.get$_nums is not a function
+main_test/42: RuntimeError # receiver.get$_nums is not a function
+main_test/43: RuntimeError # receiver.get$_nums is not a function
+main_test/44: RuntimeError # receiver.get$_nums is not a function
+main_test/45: RuntimeError # receiver.get$_nums is not a function
+many_overridden_no_such_method_test: RuntimeError # Please triage this failure.
 mixin_type_parameters_mixin_extends_test: Crash # The null object does not have a getter '_element'.
 mixin_type_parameters_mixin_test: Crash # The null object does not have a getter '_element'.
 mixin_type_parameters_super_extends_test: Crash # The null object does not have a getter '_element'.
 mixin_type_parameters_super_test: Crash # The null object does not have a getter '_element'.
-named_parameters_with_conversions_test: RuntimeError # Cannot read property 'prototype' of undefined
 nested_switch_label_test: Crash # (switch (target){out...  continue to a labeled switch case
-no_such_method_test : RuntimeError # 
-null_test/none: Crash # Internal Error: No default constructor available.
-null_to_string2_test: RuntimeError # Cannot read property 'prototype' of undefined
-null_to_string_test: RuntimeError # Cannot read property 'prototype' of undefined
-overridden_no_such_method_test : RuntimeError # 
-override_method_with_field_test/02: RuntimeError # Cannot read property 'prototype' of undefined
-override_method_with_field_test/none: RuntimeError # Cannot read property 'prototype' of undefined
-prefix14_test: RuntimeError # Cannot read property 'prototype' of undefined
-prefix15_test: RuntimeError # Cannot read property 'prototype' of undefined
-prefix21_test: RuntimeError # Cannot read property 'prototype' of undefined
-range_analysis_test: RuntimeError # Cannot read property 'prototype' of undefined
-recursive_calls_test: RuntimeError # Cannot read property 'prototype' of undefined
-reg_ex2_test: RuntimeError # Cannot read property 'prototype' of undefined
-reg_exp2_test: RuntimeError # Cannot read property 'prototype' of undefined
-regress_18535_test: Crash # Internal Error: No default constructor available.
+no_such_method_test: RuntimeError # Please triage this failure.
+null_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+overridden_no_such_method_test: RuntimeError # Please triage this failure.
+regress_18535_test: Crash # (=_EmptyStream<T>;): Unhandled node
 regress_22438_test: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
-regress_22443_test: RuntimeError # receiver.get$_collection$_nums is not a function
+regress_22443_test: RuntimeError # receiver.get$_nums is not a function
 regress_22445_test: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
 regress_22579_test: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
 regress_22728_test: Crash # (main()async{bool fa...  cannot handle async/sync*/async* functions
 regress_22777_test: Crash # (test()async{try {te...  cannot handle async/sync*/async* functions
 regress_22936_test/01: Crash # The null object does not have a getter '_element'.
 regress_22936_test/none: Crash # The null object does not have a getter '_element'.
+regress_23408_test: RuntimeError # receiver.get$_nums is not a function
 regress_23498_test: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
 regress_23500_test/01: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
 regress_23500_test/02: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
 regress_23500_test/none: Crash # (main()async{var err...  cannot handle async/sync*/async* functions
-static_closure_identical_test: RuntimeError # Cannot read property 'prototype' of undefined
-static_field_test/none: RuntimeError # Cannot read property 'prototype' of undefined
-static_implicit_closure_test: RuntimeError # Cannot read property 'prototype' of undefined
-string_interpolation_test/01: RuntimeError # Cannot read property 'prototype' of undefined
-string_interpolation_test/none: RuntimeError # Cannot read property 'prototype' of undefined
 super_bound_closure_test/01: RuntimeError # Cannot read property 'call' of undefined
 super_bound_closure_test/none: RuntimeError # Cannot read property 'call' of undefined
-super_call4_test : RuntimeError # 
+super_call4_test: RuntimeError # Please triage this failure.
 super_getter_setter_test: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-super_implicit_closure_test: RuntimeError # Cannot read property 'prototype' of undefined
-super_operator_index2_test: RuntimeError # this.get$map is not a function
+super_implicit_closure_test: RuntimeError # Cannot read property 'call' of undefined
 super_operator_index5_test: Crash # (super[0]=42): visitUnresolvedSuperIndexSet
 super_operator_index7_test: Crash # (super[0]=42): visitUnresolvedSuperIndexSet
 super_operator_index8_test: Crash # (super[f()]=g()): visitUnresolvedSuperIndexSet
@@ -561,11 +501,7 @@
 syncstar_yield_test/copyParameters: Crash # (Iterable<int> foo3(...  cannot handle async/sync*/async* functions
 syncstar_yield_test/none: Crash # (Iterable<int> foo3(...  cannot handle async/sync*/async* functions
 syncstar_yieldstar_test: Crash # (main()async{Expect....  cannot handle async/sync*/async* functions
-top_level_in_initializer_test: RuntimeError # Cannot read property 'prototype' of undefined
 try_catch_test/none: Crash # The null object does not have a getter '_element'.
-type_check_const_function_typedef2_test/00: RuntimeError # Cannot read property 'prototype' of undefined
-type_check_const_function_typedef2_test/none: RuntimeError # Cannot read property 'prototype' of undefined
-type_check_const_function_typedef_test: RuntimeError # Cannot read property 'prototype' of undefined
 type_parameter_test/01: Crash # Invalid argument(s)
 type_parameter_test/02: Crash # Invalid argument(s)
 type_parameter_test/03: Crash # Invalid argument(s)
@@ -573,26 +509,5 @@
 type_parameter_test/05: Crash # Invalid argument(s)
 type_parameter_test/06: Crash # Invalid argument(s)
 type_parameter_test/none: Crash # Invalid argument(s)
-type_promotion_functions_test/01: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/02: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/03: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/04: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/05: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/06: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/07: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/08: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/09: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/10: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/11: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/12: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/13: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/14: RuntimeError # Cannot read property 'prototype' of undefined
-type_promotion_functions_test/none: RuntimeError # Cannot read property 'prototype' of undefined
 type_variable_closure2_test: RuntimeError # Please triage this failure.
 type_variable_closure_test: Crash # Invalid argument(s)
-typedef_is_test: RuntimeError # Cannot read property 'prototype' of undefined
-invocation_mirror2_test : Crash # Internal Error: No default constructor available.
-type_variable_conflict2_test/01 : Crash # Internal Error: No default constructor available.
-async_await_syntax_test/a05h : Crash # bailout: (a05h()async{yield*st;}): cannot handle async/sync*/async* functions
-async_await_syntax_test/c11a : Crash # bailout: (c11a()async{yield-5;}): cannot handle async/sync*/async* functions
-async_await_syntax_test/c11b : Crash # bailout: (c11b()async{yield*st;}): cannot handle async/sync*/async* functions
diff --git a/tests/language/regress_23408_lib.dart b/tests/language/regress_23408_lib.dart
new file mode 100644
index 0000000..64c4964
--- /dev/null
+++ b/tests/language/regress_23408_lib.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.
+
+library regress_23408_lib;
+
+import "regress_23408_test.dart" as main;
+
+class K extends main.C {
+  K();
+}
diff --git a/tests/language/regress_23408_test.dart b/tests/language/regress_23408_test.dart
new file mode 100644
index 0000000..f47f1cb
--- /dev/null
+++ b/tests/language/regress_23408_test.dart
@@ -0,0 +1,32 @@
+// 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 regress_23408_test;
+
+import 'package:expect/expect.dart';
+
+import 'regress_23408_lib.dart' deferred as lib;
+
+class A<T> extends C {
+  get t => "$T";
+}
+
+class C {
+  var v = 55;
+  C();
+  factory C.c() = lib.K;
+  factory C.l() = A<lib.K>;
+}
+
+void main() {
+  var a = new C.l(); // Redirects to A<dynamic>
+  Expect.equals("dynamic", a.t);
+  Expect.throws(() => new C.c());
+  lib.loadLibrary().then((_) {
+    var b = new C.l(); // Still redirects to A<dynamic>
+    Expect.equals("dynamic", b.t);
+    var z = new C.c();
+    Expect.equals(55, z.v);
+  });
+}
diff --git a/tests/language/runtime_type_test.dart b/tests/language/runtime_type_test.dart
index 03c4576..158f974 100644
--- a/tests/language/runtime_type_test.dart
+++ b/tests/language/runtime_type_test.dart
@@ -10,4 +10,6 @@
 
 main() {
   Expect.isTrue(new A().className is Type);
+  Expect.isTrue(null.runtimeType is Type);
+  Expect.equals(null.runtimeType, Null);
 }
diff --git a/tests/language/string_no_operator_test.dart b/tests/language/string_no_operator_test.dart
new file mode 100644
index 0000000..009442b
--- /dev/null
+++ b/tests/language/string_no_operator_test.dart
@@ -0,0 +1,26 @@
+// 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:expect/expect.dart';
+
+main() {
+	var x = "x";
+	var y = "y";
+	Expect.throws(() => x < y);
+	Expect.throws(() => x <= y);
+	Expect.throws(() => x > y);
+	Expect.throws(() => x >= y);
+	Expect.throws(() => x - y);
+	Expect.throws(() => x * y);
+	Expect.throws(() => x / y);
+	Expect.throws(() => x ~/ y);
+	Expect.throws(() => x % y);
+	Expect.throws(() => x >> y);
+	Expect.throws(() => x << y);
+	Expect.throws(() => x & y);
+	Expect.throws(() => x | y);
+	Expect.throws(() => x ^ y);
+	Expect.throws(() => -x);
+	Expect.throws(() => ~x);
+}
diff --git a/tests/lib/async/stream_iterator_test.dart b/tests/lib/async/stream_iterator_test.dart
index 57bd6cc..bbd7f71 100644
--- a/tests/lib/async/stream_iterator_test.dart
+++ b/tests/lib/async/stream_iterator_test.dart
@@ -6,89 +6,90 @@
 import "package:unittest/unittest.dart";
 
 main() {
-  test("stream iterator basic", () {
-    StreamController c = new StreamController();
-    Stream s = c.stream;
-    StreamIterator i = new StreamIterator(s);
-    i.moveNext().then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(42, i.current);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(37, i.current);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isFalse);
-    }));
-    c.add(42);
-    c.add(37);
-    c.close();
+  test("stream iterator basic", () async {
+    var stream = createStream();
+    StreamIterator iterator = new StreamIterator(stream);
+    expect(iterator.current, isNull);
+    expect(await iterator.moveNext(), isTrue);
+    expect(iterator.current, 42);
+    expect(await iterator.moveNext(), isTrue);
+    expect(iterator.current, 37);
+    expect(await iterator.moveNext(), isFalse);
+    expect(iterator.current, isNull);
+    expect(await iterator.moveNext(), isFalse);
   });
 
-  test("stream iterator prefilled", () {
-    StreamController c = new StreamController();
-    c.add(42);
-    c.add(37);
-    c.close();
-    Stream s = c.stream;
-    StreamIterator i = new StreamIterator(s);
-    i.moveNext().then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(42, i.current);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(37, i.current);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isFalse);
-    }));
+  test("stream iterator prefilled", () async {
+    Stream stream = createStream();
+    StreamIterator iterator = new StreamIterator(stream);
+    await new Future.delayed(Duration.ZERO);
+    expect(iterator.current, isNull);
+    expect(await iterator.moveNext(), isTrue);
+    expect(iterator.current, 42);
+    expect(await iterator.moveNext(), isTrue);
+    expect(iterator.current, 37);
+    expect(await iterator.moveNext(), isFalse);
+    expect(iterator.current, isNull);
+    expect(await iterator.moveNext(), isFalse);
   });
 
-  test("stream iterator error", () {
-    StreamController c = new StreamController();
-    Stream s = c.stream;
-    StreamIterator i = new StreamIterator(s);
-    i.moveNext().then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(42, i.current);
-      return i.moveNext();
-    })).then((bool b) {
-      fail("Result not expected");
-    }, onError: expectAsync((e) {
-      expect("BAD", e);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isFalse);
-    }));
-    c.add(42);
-    c.addError("BAD");
-    c.add(37);
-    c.close();
+  test("stream iterator error", () async {
+    Stream stream = createErrorStream();
+    StreamIterator iterator = new StreamIterator(stream);
+    expect(await iterator.moveNext(), isTrue);
+    expect(iterator.current, 42);
+    var hasNext = iterator.moveNext();
+    expect(hasNext, throwsA("BAD"));  // This is an async expectation,
+    await hasNext.catchError((_){});  // so we have to wait for the future too.
+    expect(iterator.current, isNull);
+    expect(await iterator.moveNext(), isFalse);
+    expect(iterator.current, isNull);
   });
 
-  test("stream iterator current/moveNext during move", () {
-    StreamController c = new StreamController();
-    Stream s = c.stream;
-    StreamIterator i = new StreamIterator(s);
-    i.moveNext().then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(42, i.current);
-      new Timer(const Duration(milliseconds:100), expectAsync(() {
-        expect(i.current, null);
-        expect(() { i.moveNext(); }, throws);
-        c.add(37);
-        c.close();
-      }));
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isTrue);
-      expect(37, i.current);
-      return i.moveNext();
-    })).then(expectAsync((bool b) {
-      expect(b, isFalse);
-    }));
-    c.add(42);
+  test("stream iterator current/moveNext during move", () async {
+    Stream stream = createStream();
+    StreamIterator iterator = new StreamIterator(stream);
+    var hasNext = iterator.moveNext();
+    expect(iterator.moveNext, throwsA(isStateError));
+    expect(await hasNext, isTrue);
+    expect(iterator.current, 42);
+    iterator.cancel();
   });
+
+  test("stream iterator error during cancel", () async {
+    Stream stream = createCancelErrorStream();
+    StreamIterator iterator = new StreamIterator(stream);
+    for (int i = 0; i < 10; i++) {
+      expect(await iterator.moveNext(), isTrue);
+      expect(iterator.current, i);
+    }
+    var hasNext = iterator.moveNext();  // active moveNext will be completed.
+    var cancel = iterator.cancel();
+    expect(cancel, throwsA("BAD"));
+    expect(await hasNext, isFalse);
+      expect(await iterator.moveNext(), isFalse);
+  });
+
+}
+
+Stream createStream() async* {
+  yield 42;
+  yield 37;
+}
+
+Stream createErrorStream() async* {
+  yield 42;
+  // Emit an error without stopping the generator.
+  yield* (new Future.error("BAD").asStream());
+  yield 37;
+}
+
+/// Create a stream that throws when cancelled.
+Stream createCancelErrorStream() async* {
+  int i = 0;
+  try {
+    while (true) yield i++;
+  } finally {
+    throw "BAD";
+  }
 }
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 015e3bd..e63fadf 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -151,7 +151,6 @@
 async/zone_empty_description2_test: RuntimeError # Timer interface not supported: Issue 7728.
 async/zone_create_timer2_test: RuntimeError # Timer interface not supported: Issue 7728.
 async/zone_create_periodic_timer_test: RuntimeError # Timer interface not supported: Issue 7728.
-async/stream_iterator_test: RuntimeError, OK # Timer interface not supported: Issue 7728.
 async/catch_errors12_test: Fail # Timer interface not supported: Issue 7728.
 async/catch_errors13_test: Fail # Timer interface not supported: Issue 7728.
 async/catch_errors14_test: Fail # Timer interface not supported: Issue 7728.
@@ -354,18 +353,18 @@
 async/catch_errors7_test: RuntimeError # receiver.get$_nums is not a function
 async/catch_errors8_test: RuntimeError # receiver.get$_nums is not a function
 async/catch_errors_test: RuntimeError # receiver.get$_nums is not a function
-async/first_regression_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/future_constructor_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/future_delayed_error_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/future_microtask_test: RuntimeError # receiver.get$_collection$_nums is not a function
+async/first_regression_test: RuntimeError # receiver.get$_nums is not a function
+async/future_constructor_test: RuntimeError # receiver.get$_nums is not a function
+async/future_delayed_error_test: RuntimeError # receiver.get$_nums is not a function
+async/future_microtask_test: RuntimeError # receiver.get$_nums is not a function
 async/future_test/01: Crash # (()async=>new Future.value(value)): cannot handle async/sync*/async* functions
 async/future_test/none: RuntimeError # receiver.get$_nums is not a function
-async/future_timeout_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/future_value_chain2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/future_value_chain3_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/future_value_chain4_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/future_value_chain_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/futures_test: RuntimeError # receiver.get$_collection$_nums is not a function
+async/future_timeout_test: RuntimeError # receiver.get$_nums is not a function
+async/future_value_chain2_test: RuntimeError # receiver.get$_nums is not a function
+async/future_value_chain3_test: RuntimeError # receiver.get$_nums is not a function
+async/future_value_chain4_test: RuntimeError # receiver.get$_nums is not a function
+async/future_value_chain_test: RuntimeError # receiver.get$_nums is not a function
+async/futures_test: RuntimeError # receiver.get$_nums is not a function
 async/intercept_print1_test: RuntimeError # receiver.get$_collection$_nums is not a function
 async/intercept_schedule_microtask1_test: RuntimeError # receiver.get$_nums is not a function
 async/intercept_schedule_microtask2_test: RuntimeError # receiver.get$_nums is not a function
@@ -373,7 +372,7 @@
 async/intercept_schedule_microtask4_test: RuntimeError # receiver.get$_nums is not a function
 async/intercept_schedule_microtask5_test: RuntimeError # receiver.get$_nums is not a function
 async/intercept_schedule_microtask6_test: RuntimeError # receiver.get$_nums is not a function
-async/multiple_timer_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+async/multiple_timer_test: RuntimeError # receiver.get$_nums is not a function
 async/print_test/none: RuntimeError # receiver.get$_nums is not a function
 async/run_zoned1_test: RuntimeError # receiver.get$_nums is not a function
 async/run_zoned4_test: RuntimeError # receiver.get$_nums is not a function
@@ -382,73 +381,73 @@
 async/run_zoned7_test: RuntimeError # receiver.get$_nums is not a function
 async/run_zoned8_test: RuntimeError # receiver.get$_nums is not a function
 async/run_zoned9_test/none: RuntimeError # receiver.get$_nums is not a function
-async/schedule_microtask2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/schedule_microtask3_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/schedule_microtask5_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/schedule_microtask_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/slow_consumer2_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/slow_consumer3_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/slow_consumer_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace01_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace02_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace03_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace04_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace05_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace06_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace07_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace08_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace09_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace10_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace11_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace12_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace13_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace14_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace15_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace16_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace17_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace18_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace19_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace20_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace21_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace22_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace23_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace24_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stack_trace25_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stream_controller_async_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_controller_test: RuntimeError # receiver.get$_collection$_nums is not a function
+async/schedule_microtask2_test: RuntimeError # receiver.get$_nums is not a function
+async/schedule_microtask3_test: RuntimeError # receiver.get$_nums is not a function
+async/schedule_microtask5_test: RuntimeError # receiver.get$_nums is not a function
+async/schedule_microtask_test: RuntimeError # receiver.get$_nums is not a function
+async/slow_consumer2_test: RuntimeError # receiver.get$_nums is not a function
+async/slow_consumer3_test: RuntimeError # receiver.get$_nums is not a function
+async/slow_consumer_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace01_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace02_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace03_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace04_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace05_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace06_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace07_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace08_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace09_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace10_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace11_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace12_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace13_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace14_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace15_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace16_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace17_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace18_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace19_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace20_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace21_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace22_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace23_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace24_test: RuntimeError # receiver.get$_nums is not a function
+async/stack_trace25_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_controller_async_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_controller_test: RuntimeError # receiver.get$_nums is not a function
 async/stream_empty_test: Crash # (Future runTest()asy...  cannot handle async/sync*/async* functions
 async/stream_event_transformed_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_first_where_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_from_iterable_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_iterator_double_cancel_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stream_iterator_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_join_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_last_where_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+async/stream_first_where_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_from_iterable_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_iterator_double_cancel_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_iterator_test: Crash # (()async{var stream=...  cannot handle async/sync*/async* functions
+async/stream_join_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_last_where_test: RuntimeError # receiver.get$_nums is not a function
 async/stream_listen_zone_test: RuntimeError # receiver.get$_nums is not a function
-async/stream_periodic2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_periodic3_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_periodic4_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_periodic5_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_periodic_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_single_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_single_to_multi_subscriber_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_state_nonzero_timer_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_state_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_subscription_as_future_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_subscription_cancel_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_timeout_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_transform_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_transformation_broadcast_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/stream_transformer_from_handlers_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/stream_transformer_test: RuntimeError # receiver.get$_collection$_nums is not a function
+async/stream_periodic2_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_periodic3_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_periodic4_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_periodic5_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_periodic_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_single_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_single_to_multi_subscriber_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_state_nonzero_timer_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_state_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_subscription_as_future_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_subscription_cancel_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_timeout_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_transform_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_transformation_broadcast_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_transformer_from_handlers_test: RuntimeError # receiver.get$_nums is not a function
+async/stream_transformer_test: RuntimeError # receiver.get$_nums is not a function
 async/stream_zones_test: RuntimeError # receiver.get$_nums is not a function
-async/timer_cancel1_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/timer_cancel2_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/timer_cancel_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/timer_isActive_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/timer_regress22626_test: RuntimeError # receiver.get$_collection$_nums is not a function
-async/timer_repeat_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-async/timer_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+async/timer_cancel1_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_cancel2_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_cancel_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_isActive_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_regress22626_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_repeat_test: RuntimeError # receiver.get$_nums is not a function
+async/timer_test: RuntimeError # receiver.get$_nums is not a function
 async/zone_bind_callback_test: RuntimeError # receiver.get$_nums is not a function
 async/zone_bind_callback_unary_test: RuntimeError # receiver.get$_nums is not a function
 async/zone_bind_test: RuntimeError # receiver.get$_nums is not a function
@@ -468,248 +467,240 @@
 async/zone_run_test: RuntimeError # receiver.get$_nums is not a function
 async/zone_run_unary_test: RuntimeError # receiver.get$_nums is not a function
 async/zone_value_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/ascii_test: RuntimeError # Please triage this failure.
-convert/chunked_conversion_utf88_test: RuntimeError # Please triage this failure.
-convert/codec1_test: RuntimeError # Cannot read property 'prototype' of undefined
-convert/encoding_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/html_escape_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/json_lib_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-convert/latin1_test: RuntimeError # Please triage this failure.
-convert/line_splitter_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+convert/ascii_test: RuntimeError # this.get$length is not a function
+convert/encoding_test: RuntimeError # receiver.get$_nums is not a function
+convert/html_escape_test: RuntimeError # receiver.get$_nums is not a function
+convert/json_lib_test: RuntimeError # receiver.get$_nums is not a function
+convert/latin1_test: RuntimeError # this.get$length is not a function
+convert/line_splitter_test: RuntimeError # receiver.get$_nums is not a function
 convert/streamed_conversion_json_decode1_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_json_encode1_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
+convert/streamed_conversion_json_encode1_test: RuntimeError # receiver.get$_collection$_nums is not a function
 convert/streamed_conversion_json_utf8_decode_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_json_utf8_encode_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_utf8_decode_test: RuntimeError # receiver.get$_collection$_nums is not a function
-convert/streamed_conversion_utf8_encode_test: RuntimeError # receiver.get$_collection$_nums is not a function
-math/pi_test: RuntimeError # receiver.get$_collection$_nums is not a function
-math/point_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-math/rectangle_test : RuntimeError # TypeError: receiver.get$_nums is not a function
-mirrors/abstract_class_test/00: Crash # Internal Error: No default constructor available.
-mirrors/abstract_class_test/none: Crash # Internal Error: No default constructor available.
-mirrors/abstract_test: Crash # Internal Error: No default constructor available.
-mirrors/accessor_cache_overflow_test: Crash # Internal Error: No default constructor available.
-mirrors/array_tracing2_test: Crash # Internal Error: No default constructor available.
-mirrors/array_tracing3_test: Crash # Internal Error: No default constructor available.
-mirrors/array_tracing_test: Crash # Internal Error: No default constructor available.
-mirrors/basic_types_in_dart_core_test: Crash # Internal Error: No default constructor available.
-mirrors/circular_factory_redirection_test/none: Crash # Internal Error: No default constructor available.
-mirrors/class_declarations_test/01: Crash # Internal Error: No default constructor available.
-mirrors/class_declarations_test/none: Crash # Internal Error: No default constructor available.
-mirrors/class_mirror_location_test: Crash # Internal Error: No default constructor available.
-mirrors/class_mirror_type_variables_test: Crash # Internal Error: No default constructor available.
-mirrors/closures_test: Crash # Internal Error: No default constructor available.
-mirrors/closurization_equivalence_test: Crash # Internal Error: No default constructor available.
-mirrors/constructor_kinds_test/01: Crash # Internal Error: No default constructor available.
-mirrors/constructor_kinds_test/none: Crash # Internal Error: No default constructor available.
-mirrors/constructors_test: Crash # Internal Error: No default constructor available.
-mirrors/dart2js_mirrors_test: Crash # Internal Error: No default constructor available.
-mirrors/declarations_type_test: Crash # Internal Error: No default constructor available.
-mirrors/deferred_mirrors_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/deferred_mirrors_metatarget_test: Crash # Internal Error: No default constructor available.
-mirrors/deferred_mirrors_update_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-mirrors/deferred_type_test: Crash # Internal Error: No default constructor available.
-mirrors/delegate_call_through_getter_test : RuntimeError # 
-mirrors/delegate_test : RuntimeError # 
-mirrors/disable_tree_shaking_test: Crash # Internal Error: No default constructor available.
-mirrors/empty_test: Crash # Internal Error: No default constructor available.
-mirrors/enum_test: Crash # Internal Error: No default constructor available.
-mirrors/equality_test: Crash # Internal Error: No default constructor available.
-mirrors/fake_function_with_call_test: Crash # Internal Error: No default constructor available.
-mirrors/fake_function_without_call_test: Crash # Internal Error: No default constructor available.
-mirrors/field_type_test: Crash # Internal Error: No default constructor available.
-mirrors/function_type_mirror_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_by_type_parameter_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_by_type_parameter_test/02: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_by_type_parameter_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_test/02: Crash # Internal Error: No default constructor available.
-mirrors/generic_bounded_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generic_class_declaration_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_f_bounded_mixin_application_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_f_bounded_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generic_f_bounded_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generic_function_typedef_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_interface_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generic_interface_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generic_list_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_local_function_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_mixin_applications_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_mixin_test: Crash # Internal Error: No default constructor available.
-mirrors/generic_superclass_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generic_superclass_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generic_type_mirror_test: Crash # Internal Error: No default constructor available.
-mirrors/generics_double_substitution_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generics_double_substitution_test/none: Crash # Internal Error: No default constructor available.
-mirrors/generics_dynamic_test: Crash # Internal Error: No default constructor available.
-mirrors/generics_special_types_test: Crash # Internal Error: No default constructor available.
-mirrors/generics_substitution_test: Crash # Internal Error: No default constructor available.
-mirrors/generics_test/01: Crash # Internal Error: No default constructor available.
-mirrors/generics_test/none: Crash # Internal Error: No default constructor available.
-mirrors/get_field_static_test/00: Crash # Internal Error: No default constructor available.
-mirrors/get_field_static_test/none: Crash # Internal Error: No default constructor available.
-mirrors/globalized_closures2_test/00: Crash # Internal Error: No default constructor available.
-mirrors/globalized_closures2_test/none: Crash # Internal Error: No default constructor available.
-mirrors/globalized_closures_test/00: Crash # Internal Error: No default constructor available.
-mirrors/globalized_closures_test/none: Crash # Internal Error: No default constructor available.
-mirrors/hierarchy_invariants_test: Crash # Internal Error: No default constructor available.
-mirrors/immutable_collections_test: Crash # Internal Error: No default constructor available.
-mirrors/inherit_field_test: Crash # Internal Error: No default constructor available.
-mirrors/initializing_formals_test/01: Crash # Internal Error: No default constructor available.
-mirrors/initializing_formals_test/none: Crash # Internal Error: No default constructor available.
-mirrors/instance_members_easier_test: Crash # Internal Error: No default constructor available.
-mirrors/instance_members_test: Crash # Internal Error: No default constructor available.
-mirrors/instance_members_unimplemented_interface_test: Crash # Internal Error: No default constructor available.
-mirrors/instance_members_with_override_test: Crash # Internal Error: No default constructor available.
-mirrors/instantiate_abstract_class_test: Crash # Internal Error: No default constructor available.
-mirrors/intercepted_cache_test: Crash # Internal Error: No default constructor available.
-mirrors/intercepted_class_test: Crash # Internal Error: No default constructor available.
-mirrors/intercepted_object_test: Crash # Internal Error: No default constructor available.
-mirrors/intercepted_superclass_test: Crash # Internal Error: No default constructor available.
-mirrors/invocation_fuzz_test/emptyarray: Crash # Internal Error: No default constructor available.
-mirrors/invocation_fuzz_test/false: Crash # Internal Error: No default constructor available.
-mirrors/invocation_fuzz_test/none: Crash # Internal Error: No default constructor available.
-mirrors/invocation_fuzz_test/smi: Crash # Internal Error: No default constructor available.
-mirrors/invocation_fuzz_test/string: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_on_closure_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_getter_previously_accessed_test/named: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_getter_previously_accessed_test/none: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_getter_test/named: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_getter_test/none: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_implicit_getter_previously_accessed_test/named: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_implicit_getter_previously_accessed_test/none: Crash # Internal Error: No default constructor available.
-mirrors/invoke_call_through_implicit_getter_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_closurization2_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_closurization_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_import_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_named_test/01: Crash # Internal Error: No default constructor available.
-mirrors/invoke_named_test/none: Crash # Internal Error: No default constructor available.
-mirrors/invoke_natives_malicious_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_test: Crash # Internal Error: No default constructor available.
-mirrors/invoke_throws_test: Crash # Internal Error: No default constructor available.
-mirrors/is_odd_test: Crash # Internal Error: No default constructor available.
-mirrors/lazy_static_test: Crash # Internal Error: No default constructor available.
-mirrors/libraries_test: Crash # Internal Error: No default constructor available.
-mirrors/library_declarations_test/01: Crash # Internal Error: No default constructor available.
-mirrors/library_declarations_test/none: Crash # Internal Error: No default constructor available.
-mirrors/library_enumeration_deferred_loading_test: Crash # Internal Error: No default constructor available.
-mirrors/library_exports_hidden_test: Crash # Internal Error: No default constructor available.
-mirrors/library_exports_shown_test: Crash # Internal Error: No default constructor available.
-mirrors/library_import_deferred_loading_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_bad_metadata_test/none: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_deferred_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_hidden_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_prefixed_show_hide_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_prefixed_test: Crash # Internal Error: No default constructor available.
-mirrors/library_imports_shown_test: Crash # Internal Error: No default constructor available.
-mirrors/library_metadata2_test/none: Crash # Internal Error: No default constructor available.
-mirrors/library_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/library_uri_package_test: Crash # Invalid argument(s)
-mirrors/list_constructor_test/01: Crash # Internal Error: No default constructor available.
-mirrors/list_constructor_test/none: Crash # Internal Error: No default constructor available.
-mirrors/load_library_test: Crash # Internal Error: No default constructor available.
-mirrors/local_function_is_static_test: Crash # Internal Error: No default constructor available.
-mirrors/local_isolate_test: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/01: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/05: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/10: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/11: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/13: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/14: Crash # Internal Error: No default constructor available.
-mirrors/metadata_allowed_values_test/none: Crash # Internal Error: No default constructor available.
-mirrors/metadata_class_mirror_test: Crash # Internal Error: No default constructor available.
-mirrors/metadata_constructed_constant_test: Crash # Internal Error: No default constructor available.
-mirrors/metadata_constructor_arguments_test/none: Crash # Internal Error: No default constructor available.
-mirrors/metadata_nested_constructor_call_test/none: Crash # Internal Error: No default constructor available.
-mirrors/metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_location_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_name_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_properties_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_returntype_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_source_line_ending_test: Crash # Internal Error: No default constructor available.
-mirrors/method_mirror_source_test: Crash # Internal Error: No default constructor available.
-mirrors/mirror_in_static_init_test/none: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_nsm_mismatch_test: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_nsm_test/dart2js: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_nsm_test/none: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_reader_test: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_resolve_fields_test: Crash # Internal Error: No default constructor available.
-mirrors/mirrors_test: Crash # Internal Error: No default constructor available.
-mirrors/mixin_application_test: Crash # Internal Error: No default constructor available.
-mirrors/mixin_members_test: Crash # Internal Error: No default constructor available.
-mirrors/mixin_test: Crash # Internal Error: No default constructor available.
-mirrors/native_class_test: Crash # Internal Error: No default constructor available.
-mirrors/new_instance_optional_arguments_test: Crash # Internal Error: No default constructor available.
-mirrors/new_instance_with_type_arguments_test: Crash # Internal Error: No default constructor available.
-mirrors/no_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/null2_test: Crash # Internal Error: No default constructor available.
-mirrors/null_test: Crash # Invalid argument(s)
-mirrors/operator_test: Crash # Internal Error: No default constructor available.
-mirrors/parameter_is_const_test/none: Crash # Internal Error: No default constructor available.
-mirrors/parameter_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/parameter_of_mixin_app_constructor_test: Crash # Internal Error: No default constructor available.
-mirrors/parameter_test/none: Crash # Internal Error: No default constructor available.
-mirrors/private_symbol_mangling_test: Crash # Internal Error: No default constructor available.
-mirrors/private_types_test: Crash # Internal Error: No default constructor available.
-mirrors/proxy_type_test: Crash # Internal Error: No default constructor available.
-mirrors/raw_type_test/01: Crash # Internal Error: No default constructor available.
-mirrors/raw_type_test/none: Crash # Internal Error: No default constructor available.
-mirrors/redirecting_factory_test/01: Crash # Internal Error: No default constructor available.
-mirrors/redirecting_factory_test/02: Crash # Internal Error: No default constructor available.
-mirrors/redirecting_factory_test/none: Crash # Internal Error: No default constructor available.
-mirrors/reflect_class_test/01: Crash # Internal Error: No default constructor available.
-mirrors/reflect_class_test/02: Crash # Internal Error: No default constructor available.
-mirrors/reflect_class_test/none: Crash # Internal Error: No default constructor available.
-mirrors/reflect_model_test: Crash # Internal Error: No default constructor available.
-mirrors/reflect_runtime_type_test: Crash # Internal Error: No default constructor available.
-mirrors/reflect_uninstantiated_class_test: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_classes_test/01: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_classes_test/02: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_classes_test/03: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_classes_test/none: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_function_type_test: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_special_types_test: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_test/01: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_test/02: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_test/03: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_test/none: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_typedefs_test: Crash # Internal Error: No default constructor available.
-mirrors/reflected_type_typevars_test: Crash # Internal Error: No default constructor available.
-mirrors/reflectively_instantiate_uninstantiated_class_test: Crash # Internal Error: No default constructor available.
-mirrors/regress_14304_test: Crash # Internal Error: No default constructor available.
-mirrors/regress_16321_test/01: Crash # Internal Error: No default constructor available.
-mirrors/regress_16321_test/none: Crash # Internal Error: No default constructor available.
-mirrors/regress_19731_test: Crash # Internal Error: No default constructor available.
-mirrors/relation_assignable_test: Crash # Internal Error: No default constructor available.
-mirrors/relation_subclass_test: Crash # Internal Error: No default constructor available.
-mirrors/relation_subtype_test: Crash # Internal Error: No default constructor available.
-mirrors/removed_api_test: Crash # Internal Error: No default constructor available.
-mirrors/repeated_private_anon_mixin_app_test: Crash # Internal Error: No default constructor available.
-mirrors/set_field_with_final_inheritance_test: Crash # Internal Error: No default constructor available.
-mirrors/set_field_with_final_test: Crash # Internal Error: No default constructor available.
-mirrors/spawn_function_root_library_test: Crash # Internal Error: No default constructor available.
-mirrors/static_members_easier_test: Crash # Internal Error: No default constructor available.
-mirrors/static_members_test: Crash # Internal Error: No default constructor available.
-mirrors/static_test: Crash # Internal Error: No default constructor available.
-mirrors/superclass2_test: Crash # Internal Error: No default constructor available.
-mirrors/superclass_test: Crash # Internal Error: No default constructor available.
-mirrors/symbol_validation_test/01: Crash # Internal Error: No default constructor available.
+convert/streamed_conversion_json_utf8_encode_test: RuntimeError # receiver.get$_collection$_nums is not a function
+convert/streamed_conversion_utf8_decode_test: RuntimeError # receiver.get$_nums is not a function
+convert/streamed_conversion_utf8_encode_test: RuntimeError # receiver.get$_nums is not a function
+math/pi_test: RuntimeError # receiver.get$_nums is not a function
+math/point_test: RuntimeError # receiver.get$_nums is not a function
+math/rectangle_test: RuntimeError # receiver.get$_nums is not a function
+mirrors/abstract_class_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/abstract_class_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/abstract_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/accessor_cache_overflow_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/array_tracing2_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/array_tracing_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/basic_types_in_dart_core_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/circular_factory_redirection_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/class_declarations_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/class_declarations_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/class_mirror_location_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/class_mirror_type_variables_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/closures_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/closurization_equivalence_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/constructor_kinds_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/constructor_kinds_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/constructors_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/dart2js_mirrors_test: Crash # (=Class.faktory;): Unhandled node
+mirrors/declarations_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/deferred_mirrors_metadata_test: RuntimeError # receiver.get$_collection$_nums is not a function
+mirrors/deferred_mirrors_metatarget_test: RuntimeError # receiver.get$_collection$_nums is not a function
+mirrors/deferred_mirrors_update_test: RuntimeError # receiver.get$_collection$_nums is not a function
+mirrors/deferred_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/delegate_call_through_getter_test: RuntimeError # Please triage this failure.
+mirrors/delegate_test: RuntimeError # Please triage this failure.
+mirrors/disable_tree_shaking_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/empty_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/enum_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/equality_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/fake_function_with_call_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/fake_function_without_call_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/field_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/function_type_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_by_type_parameter_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_by_type_parameter_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_by_type_parameter_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_bounded_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_class_declaration_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_f_bounded_mixin_application_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_f_bounded_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_f_bounded_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_function_typedef_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_interface_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_interface_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_list_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_local_function_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_mixin_applications_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_mixin_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_superclass_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_superclass_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generic_type_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_double_substitution_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_double_substitution_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_dynamic_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_special_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_substitution_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/generics_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/globalized_closures2_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/globalized_closures2_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/globalized_closures_test/00: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/globalized_closures_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/hierarchy_invariants_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/immutable_collections_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/inherit_field_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/initializing_formals_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/initializing_formals_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/instance_members_easier_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/instance_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/instance_members_unimplemented_interface_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/instance_members_with_override_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/instantiate_abstract_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/intercepted_cache_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/intercepted_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/intercepted_object_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/intercepted_superclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invocation_fuzz_test/emptyarray: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invocation_fuzz_test/false: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invocation_fuzz_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invocation_fuzz_test/smi: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invocation_fuzz_test/string: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_on_closure_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_getter_previously_accessed_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_getter_previously_accessed_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_getter_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_getter_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_implicit_getter_previously_accessed_test/named: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_implicit_getter_previously_accessed_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_call_through_implicit_getter_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_closurization2_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_closurization_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_import_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_named_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_named_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_natives_malicious_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/invoke_throws_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/is_odd_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/lazy_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/libraries_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_declarations_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_declarations_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_enumeration_deferred_loading_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_exports_hidden_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_exports_shown_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_import_deferred_loading_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_bad_metadata_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_deferred_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_hidden_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_prefixed_show_hide_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_prefixed_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_imports_shown_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_metadata2_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/library_uri_package_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/list_constructor_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/list_constructor_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/load_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/local_function_is_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/local_isolate_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/05: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/10: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/11: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/13: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/14: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_allowed_values_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_class_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_constructed_constant_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_constructor_arguments_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_nested_constructor_call_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_location_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_name_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_properties_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_returntype_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_source_line_ending_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/method_mirror_source_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirror_in_static_init_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_nsm_mismatch_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_nsm_test/dart2js: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_nsm_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_reader_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_resolve_fields_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mirrors_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mixin_application_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mixin_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/mixin_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/native_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/new_instance_with_type_arguments_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/no_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/null2_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/null_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/operator_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/parameter_is_const_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/parameter_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/parameter_of_mixin_app_constructor_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/private_symbol_mangling_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/private_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/proxy_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/raw_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/raw_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/redirecting_factory_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/redirecting_factory_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/redirecting_factory_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_class_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_class_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_class_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_model_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_runtime_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflect_uninstantiated_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_classes_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_classes_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_classes_test/03: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_classes_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_function_type_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_special_types_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_test/02: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_test/03: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_typedefs_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflected_type_typevars_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/reflectively_instantiate_uninstantiated_class_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/regress_14304_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/regress_16321_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/regress_16321_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/regress_19731_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/relation_assignable_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/relation_subclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/relation_subtype_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/removed_api_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/repeated_private_anon_mixin_app_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/set_field_with_final_inheritance_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/set_field_with_final_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/spawn_function_root_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/static_members_easier_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/static_members_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/static_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/superclass2_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/superclass_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/symbol_validation_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
 mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
-mirrors/syntax_error_test/none: Crash # Internal Error: No default constructor available.
-mirrors/synthetic_accessor_properties_test: Crash # Internal Error: No default constructor available.
-mirrors/to_string_test: Crash # Internal Error: No default constructor available.
-mirrors/top_level_accessors_test: Crash # Internal Error: No default constructor available.
-mirrors/type_argument_is_type_variable_test: Crash # Internal Error: No default constructor available.
-mirrors/type_variable_is_static_test: Crash # Internal Error: No default constructor available.
-mirrors/type_variable_owner_test/01: Crash # Internal Error: No default constructor available.
-mirrors/type_variable_owner_test/none: Crash # Internal Error: No default constructor available.
-mirrors/typearguments_mirror_test: Crash # Internal Error: No default constructor available.
-mirrors/typedef_deferred_library_test : RuntimeError # TypeError: receiver.get$_collection$_nums is not a function
-mirrors/typedef_metadata_test: Crash # Internal Error: No default constructor available.
-mirrors/typedef_reflected_type_test/01: Crash # Internal Error: No default constructor available.
-mirrors/typedef_reflected_type_test/none: Crash # Internal Error: No default constructor available.
-mirrors/typedef_test: Crash # Internal Error: No default constructor available.
-mirrors/unnamed_library_test: Crash # Internal Error: No default constructor available.
-mirrors/variable_is_const_test/none: Crash # Internal Error: No default constructor available.
-typed_data/typed_data_list_test: RuntimeError # Please triage this failure.
+mirrors/syntax_error_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/synthetic_accessor_properties_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/to_string_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/top_level_accessors_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/type_argument_is_type_variable_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/type_variable_is_static_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/type_variable_owner_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/type_variable_owner_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/typearguments_mirror_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/typedef_deferred_library_test: RuntimeError # receiver.get$_collection$_nums is not a function
+mirrors/typedef_metadata_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/typedef_reflected_type_test/01: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/typedef_reflected_type_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/unnamed_library_test: Crash # (=_EmptyStream<T>;): Unhandled node
+mirrors/variable_is_const_test/none: Crash # (=_EmptyStream<T>;): Unhandled node
+typed_data/typed_data_list_test: RuntimeError # this.get$length is not a function
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 9edc6cc..3dd8e64 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -170,16 +170,15 @@
 io/http_client_stays_alive_test: Skip  # Timeout.
 
 [ $compiler == dart2js && $cps_ir ]
-io/file_test: Crash # Invalid argument(s)
+io/file_test: Crash # (static testWriteFro...  cannot handle async/sync*/async* functions
 io/file_write_only_test: Crash # (main()async{asyncSt...  cannot handle async/sync*/async* functions
 io/http_bind_test: Crash # (testBindShared(Stri...  cannot handle async/sync*/async* functions
-io/http_parser_test : RuntimeError # TypeError: receiver.get$_nums is not a function
+io/http_parser_test: RuntimeError # receiver.get$_nums is not a function
 io/https_bad_certificate_test: Crash # (main()async{var cli...  cannot handle async/sync*/async* functions
 io/issue_22636_test: Crash # (test()async{server=...  cannot handle async/sync*/async* functions
 io/issue_22637_test: Crash # (test()async{server=...  cannot handle async/sync*/async* functions
-io/observatory_test: Crash # Invalid argument(s)
+io/observatory_test: Crash # (=_ByteCallbackSink;): Unhandled node
 io/socket_bind_test: Crash # (testListenCloseList...  cannot handle async/sync*/async* functions
 io/socket_source_address_test: Crash # (Future testConnect(...  cannot handle async/sync*/async* functions
-priority_queue_stress_test: RuntimeError # receiver.get$_collection$_nums is not a function
-slowpath_safepoints_test: RuntimeError # Cannot read property 'prototype' of undefined
+priority_queue_stress_test: RuntimeError # receiver.get$_nums is not a function
 typed_array_test: RuntimeError # receiver.get$_collection$_nums is not a function
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index 5bb2a3a..d690ff9 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -29,6 +29,6 @@
 source_mirrors_test: Pass, RuntimeError # Issue 17662
 
 [ $compiler == dart2js && $cps_ir ]
-dummy_compiler_test: Crash # Internal Error: No default constructor available.
-recursive_import_test: Crash # Internal Error: No default constructor available.
-source_mirrors_test: Crash # Internal Error: No default constructor available.
+dummy_compiler_test: Crash # The null object does not have a getter '_element'.
+recursive_import_test: Crash # The null object does not have a getter '_element'.
+source_mirrors_test: Crash # (Future<bool> run(Ur...  cannot handle async/sync*/async* functions
diff --git a/tools/VERSION b/tools/VERSION
index e552928..0d220d1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 12
 PATCH 0
-PRERELEASE 1
-PRERELEASE_PATCH 1
+PRERELEASE 2
+PRERELEASE_PATCH 0
diff --git a/tools/apps/update_homebrew/bin/update_homebrew.dart b/tools/apps/update_homebrew/bin/update_homebrew.dart
index a1e4586..d87631a 100644
--- a/tools/apps/update_homebrew/bin/update_homebrew.dart
+++ b/tools/apps/update_homebrew/bin/update_homebrew.dart
@@ -234,7 +234,7 @@
     bin.install_symlink "#{libexec}/bin/dart"
     bin.write_exec_script Dir["#{libexec}/bin/{pub,docgen,dart?*}"]
 
-    if build.with? 'content-shell'
+    if build.with? 'dartium'
       dartium_binary = 'Chromium.app/Contents/MacOS/Chromium'
       prefix.install resource('dartium')
       (bin+"dartium").write shim_script dartium_binary
@@ -260,7 +260,7 @@
 
     --with-dartium:
       To use with IntelliJ, set the Dartium execute home to:
-        #{prefix}/Chromium.app
+        #{opt_prefix}/Chromium.app
     EOS
   end
 
diff --git a/tools/bots/bot.py b/tools/bots/bot.py
index 0015f47..ed20c5d 100644
--- a/tools/bots/bot.py
+++ b/tools/bots/bot.py
@@ -15,7 +15,11 @@
 import subprocess
 import sys
 
-DART_PATH = dirname(dirname(dirname(abspath(__file__))))
+import bot_utils
+
+utils = bot_utils.GetUtils()
+
+BUILD_OS = utils.GuessOS()
 
 BUILDER_NAME = 'BUILDBOT_BUILDERNAME'
 BUILDER_CLOBBER = 'BUILDBOT_CLOBBER'
@@ -151,7 +155,7 @@
   build_info.PrintBuildInfo()
 
   # Make sure we are in the dart directory
-  os.chdir(DART_PATH)
+  os.chdir(bot_utils.DART_DIR)
 
   try:
     Clobber()
@@ -240,6 +244,32 @@
     RunProcess(cmd)
 
 
+def RunTestRunner(build_info, path):
+  """
+  Runs the test package's runner on the package at 'path'.
+  """
+  sdk_bin = os.path.join(
+      bot_utils.DART_DIR,
+      utils.GetBuildSdkBin(BUILD_OS, build_info.mode, build_info.arch))
+
+  build_root = utils.GetBuildRoot(
+      BUILD_OS, build_info.mode, build_info.arch)
+  package_root = os.path.abspath(os.path.join(build_root, 'packages'))
+
+  dart_name = 'dart.exe' if build_info.system == 'windows' else 'dart'
+  dart_bin = os.path.join(sdk_bin, dart_name)
+
+  test_bin = os.path.abspath(
+      os.path.join('third_party', 'pkg', 'test', 'bin', 'test.dart'))
+
+  with utils.ChangedWorkingDirectory(path):
+    args = [dart_bin, '--package-root=' + package_root, test_bin,
+            '--package-root', package_root, '--reporter', 'expanded',
+            '--no-color']
+    print("Running %s" % ' '.join(args))
+    RunProcess(args)
+
+
 def RunProcess(command):
   """
   Runs command.
diff --git a/tools/bots/dart_services.py b/tools/bots/dart_services.py
deleted file mode 100644
index dd0fe3f..0000000
--- a/tools/bots/dart_services.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/python
-
-# 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.
-
-"""
-Buildbot steps for stress testing analysis engine
-"""
-import os
-import shutil
-import sys
-import bot
-import bot_utils
-
-utils = bot_utils.GetUtils()
-
-def ServicesConfig(name, is_buildbot):
-  """Returns info for the current buildbot.
-  We only run this bot on linux, so all of this is just hard coded.
-  """
-  return bot.BuildInfo('none', 'none', 'release', 'linux')
-
-def Run(args):
-  print "Running: %s" % ' '.join(args)
-  sys.stdout.flush()
-  bot.RunProcess(args)
-
-def ServicesSteps(build_info):
-  build_root = utils.GetBuildRoot('linux')
-  sdk_bin = utils.GetBuildSdkBin('linux', mode='release', arch='ia32')
-  dart_services = os.path.join('third_party', 'dart-services')
-  dart_services_copy = os.path.join(build_root, 'dart-services')
-
-  with bot.BuildStep('Create copy of dart_services'):
-    print 'Removing existing copy of dart_services'
-    shutil.rmtree(dart_services_copy, ignore_errors=True)
-    args = ['cp', '-R', dart_services, dart_services_copy]
-    Run(args)
-
-  with bot.BuildStep('Fixing pubspec file'):
-    pubspec = os.path.join(dart_services_copy, 'pubspec.yaml')
-    # TODO(lukechurch): Actually provide the name of the alternative pubspec
-    testing_pubspec = os.path.join(dart_services_copy, 'pubspec.foobar.yaml')
-    print 'Fixing pubspec up for stress testing'
-    # TODO(lukechurch): change to do the mv of the testing pubspec
-    Run(['ls', pubspec])
-
-  with bot.BuildStep('Run pub'):
-    print 'Print running pub'
-    pub = os.path.join(sdk_bin, 'pub')
-    with utils.ChangedWorkingDirectory(dart_services_copy):
-      args = [pub, 'get']
-
-  with bot.BuildStep('Stress testing'):
-    # Consider doing something more useful here.
-    args = ['ls', 'third_party']
-    Run(args)
-
-
-if __name__ == '__main__':
-  bot.RunBot(ServicesConfig, ServicesSteps)
-
diff --git a/tools/bots/pkg.py b/tools/bots/pkg.py
index 1ba85bb..b3e22a7 100644
--- a/tools/bots/pkg.py
+++ b/tools/bots/pkg.py
@@ -11,6 +11,7 @@
 third_party/pkg_tested.
 """
 
+import os
 import re
 import sys
 
@@ -38,12 +39,6 @@
                        builder_tag=locale)
 
 def PkgSteps(build_info):
-  with bot.BuildStep('Build package-root'):
-    args = [sys.executable, './tools/build.py', '--mode=' + build_info.mode,
-            'packages']
-    print 'Building package-root: %s' % (' '.join(args))
-    bot.RunProcess(args)
-
   common_args = ['--write-test-outcome-log']
   if build_info.builder_tag:
     common_args.append('--builder-tag=%s' % build_info.builder_tag)
@@ -57,27 +52,31 @@
   # Experiment with not running concurrent calls.
   if build_info.system == 'windows':
     common_args.append('-j1')
-  if build_info.mode == 'release':
-    bot.RunTest('pkg ', build_info,
-                common_args + ['pkg', 'docs', 'pkg_tested'],
-                swallow_error=True)
-  else:
-    # Pkg tests currently have a lot of timeouts when run in debug mode.
-    # See issue 18479
-    bot.RunTest('pkg', build_info, common_args + ['pkg', 'docs'],
-                swallow_error=True)
 
-  if build_info.mode == 'release':
-    pkgbuild_build_info = bot.BuildInfo('none', 'vm', build_info.mode,
-                                        build_info.system, checked=False)
-    bot.RunTest('pkgbuild_repo_pkgs', pkgbuild_build_info,
-                common_args + ['--append_logs', '--use-repository-packages',
-                               'pkgbuild'],
-                swallow_error=True)
+  bot.RunTest('pkg ', build_info,
+              common_args + ['pkg', 'docs'],
+              swallow_error=True)
 
-    public_args = (common_args +
-                   ['--append_logs', '--use-public-packages', 'pkgbuild'])
-    bot.RunTest('pkgbuild_public_pkgs', pkgbuild_build_info, public_args)
+  # Pkg tests currently have a lot of timeouts when run in debug mode.
+  # See issue 18479
+  if build_info.mode != 'release': return
+
+  with bot.BuildStep('third_party pkg tests', swallow_error=True):
+    pkg_tested = os.path.join('third_party', 'pkg_tested')
+    for entry in os.listdir(pkg_tested):
+      path = os.path.join(pkg_tested, entry)
+      if os.path.isdir(path): bot.RunTestRunner(build_info, path)
+
+  pkgbuild_build_info = bot.BuildInfo('none', 'vm', build_info.mode,
+                                      build_info.system, checked=False)
+  bot.RunTest('pkgbuild_repo_pkgs', pkgbuild_build_info,
+              common_args + ['--append_logs', '--use-repository-packages',
+                             'pkgbuild'],
+              swallow_error=True)
+
+  public_args = (common_args +
+                 ['--append_logs', '--use-public-packages', 'pkgbuild'])
+  bot.RunTest('pkgbuild_public_pkgs', pkgbuild_build_info, public_args)
 
 if __name__ == '__main__':
   bot.RunBot(PkgConfig, PkgSteps)
diff --git a/tools/bots/pub.py b/tools/bots/pub.py
index ee3cd1e..cdd8a8b 100755
--- a/tools/bots/pub.py
+++ b/tools/bots/pub.py
@@ -12,15 +12,8 @@
 
 import os
 import re
-import shutil
-import sys
 
 import bot
-import bot_utils
-
-utils = bot_utils.GetUtils()
-
-BUILD_OS = utils.GuessOS()
 
 PUB_BUILDER = r'pub-(linux|mac|win)'
 
@@ -42,34 +35,11 @@
 
   return bot.BuildInfo('none', 'vm', mode, system, checked=True)
 
-def Run(command):
-  print "Running %s" % ' '.join(command)
-  return bot.RunProcess(command)
-
 def PubSteps(build_info):
-  sdk_bin = os.path.join(
-      bot_utils.DART_DIR,
-      utils.GetBuildSdkBin(BUILD_OS, build_info.mode, build_info.arch))
-  pub_script_name = 'pub.bat' if build_info.system == 'windows' else 'pub'
-  pub_bin = os.path.join(sdk_bin, pub_script_name)
-
-  pub_copy = os.path.join(utils.GetBuildRoot(BUILD_OS), 'pub_copy')
   pub_location = os.path.join('third_party', 'pkg', 'pub')
 
-  with bot.BuildStep('Make copy of pub for testing'):
-    print 'Removing old copy %s' % pub_copy
-    shutil.rmtree(pub_copy, ignore_errors=True)
-    print 'Copying %s to %s' % (pub_location, pub_copy)
-    shutil.copytree(pub_location, pub_copy)
-
-  # TODO(nweiz): add logic for testing pub.
-  with bot.BuildStep('Doing the magic ls'):
-    with utils.ChangedWorkingDirectory(pub_copy):
-      Run(['ls', '-l'])
-
-  with bot.BuildStep('Running pub'):
-    Run([pub_bin, '--version'])
-
+  with bot.BuildStep('Running pub tests'):
+    bot.RunTestRunner(build_info, pub_location)
 
 if __name__ == '__main__':
   bot.RunBot(PubConfig, PubSteps)
diff --git a/tools/clean_output_directory.py b/tools/clean_output_directory.py
index f94259b..e41671c 100755
--- a/tools/clean_output_directory.py
+++ b/tools/clean_output_directory.py
@@ -12,7 +12,13 @@
 def Main():
   build_root = utils.GetBuildRoot(utils.GuessOS())
   print 'Deleting %s' % build_root
-  shutil.rmtree(build_root, ignore_errors=True)
+  if sys.platform != 'win32':
+    shutil.rmtree(build_root, ignore_errors=True)
+  else:
+    # Intentionally ignore return value since a directory might be in use.
+    subprocess.call(['rmdir', '/Q', '/S', build_root],
+                    env=os.environ.copy(),
+                    shell=True)
   return 0
 
 if __name__ == '__main__':
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index f09f283..2304b5c 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -410,9 +410,9 @@
      * Layout of packages inside the dart repository:
      *  dart/
      *      pkg/PACKAGE_NAME
-     *      pkg/third_party/PACKAGE_NAME
      *      third_party/pkg/PACKAGE_NAME
      *      runtime/observatory/PACKAGE_NAME
+     *      sdk/lib/_internal/PACKAGE_NAME
      */
 
     // Directories containing "-" are not valid pub packages and we therefore
@@ -425,6 +425,7 @@
       listDir(dartDir.append('pkg'), isValid),
       listDir(dartDir.append('third_party').append('pkg'), isValid),
       listDir(dartDir.append('runtime').append('observatory'), isValid),
+      listDir(dartDir.append('sdk').append('lib').append('_internal'), isValid),
     ];
     return Future.wait(futures).then((results) {
       var packageDirectories = {};