Version 0.6.21.0

svn merge -r 26492:26574 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@26575 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index e8e9355..078c510 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -186,12 +186,11 @@
       _addPhase(_phases.last.addPhase(transformers[i]));
     }
 
-    if (transformers.length < _phases.length) {
-      for (var i = transformers.length; i < _phases.length; i++) {
-        // TODO(nweiz): actually remove phases rather than emptying them of
-        // transformers.
-        _phases[i].updateTransformers([]);
-      }
+    if (transformers.length == 0) {
+      _phases.last.updateTransformers([]);
+    } else if (transformers.length < _phases.length) {
+      _phases[transformers.length - 1].removeFollowing();
+      _phases.removeRange(transformers.length, _phases.length);
     }
   }
 
diff --git a/pkg/barback/lib/src/asset_forwarder.dart b/pkg/barback/lib/src/asset_forwarder.dart
index 7dc74dc..a2440e0 100644
--- a/pkg/barback/lib/src/asset_forwarder.dart
+++ b/pkg/barback/lib/src/asset_forwarder.dart
@@ -25,7 +25,9 @@
   AssetNode get node => _controller.node;
 
   AssetForwarder(AssetNode node)
-      : _controller = new AssetNodeController(node.id, node.transform) {
+      : _controller = new AssetNodeController.from(node) {
+    if (node.state.isRemoved) return;
+
     _subscription = node.onStateChange.listen((state) {
       if (state.isAvailable) {
         _controller.setAvailable(node.asset);
@@ -36,12 +38,6 @@
         close();
       }
     });
-
-    if (node.state.isAvailable) {
-      _controller.setAvailable(node.asset);
-    } else if (node.state.isRemoved) {
-      close();
-    }
   }
 
   /// Closes the forwarder and marks [node] as removed.
diff --git a/pkg/barback/lib/src/asset_id.dart b/pkg/barback/lib/src/asset_id.dart
index c4ed1d8..e091264 100644
--- a/pkg/barback/lib/src/asset_id.dart
+++ b/pkg/barback/lib/src/asset_id.dart
@@ -6,9 +6,6 @@
 
 import 'package:path/path.dart' as pathos;
 
-/// AssetIDs always use POSIX style paths regardless of the host platform.
-final _posix = new pathos.Builder(style: pathos.Style.posix);
-
 /// Identifies an asset within a package.
 class AssetId implements Comparable<AssetId> {
   /// The name of the package containing this asset.
@@ -29,10 +26,18 @@
   String get extension => pathos.extension(path);
 
   /// Creates a new AssetId at [path] within [package].
+  ///
+  /// The [path] will be normalized: any backslashes will be replaced with
+  /// forward slashes (regardless of host OS) and "." and ".." will be removed
+  /// where possible.
   AssetId(this.package, String path)
-      : path = _posix.normalize(path);
+      : path = _normalizePath(path);
 
   /// Parses an [AssetId] string of the form "package|path/to/asset.txt".
+  ///
+  /// The [path] will be normalized: any backslashes will be replaced with
+  /// forward slashes (regardless of host OS) and "." and ".." will be removed
+  /// where possible.
   factory AssetId.parse(String description) {
     var parts = description.split("|");
     if (parts.length != 2) {
@@ -92,3 +97,15 @@
   /// and passed to [deserialize].
   serialize() => [package, path];
 }
+
+String _normalizePath(String path) {
+  if (pathos.isAbsolute(path)) {
+    throw new ArgumentError('Asset paths must be relative, but got "$path".');
+  }
+
+  // Normalize path separators so that they are always "/" in the AssetID.
+  path = path.replaceAll(r"\", "/");
+
+  // Collapse "." and "..".
+  return pathos.posix.normalize(path);
+}
\ No newline at end of file
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index edc7408..db80a9f 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -23,8 +23,11 @@
 
   /// The transform that created this asset node.
   ///
-  /// This is `null` for source assets.
-  final TransformNode transform;
+  /// This is `null` for source assets. It can change if the upstream transform
+  /// that created this asset changes; this change will *not* cause an
+  /// [onStateChange] event.
+  TransformNode get transform => _transform;
+  TransformNode _transform;
 
   /// The current state of the asset node.
   AssetState get state => _state;
@@ -110,10 +113,10 @@
     return onStateChange.firstWhere(test);
   }
 
-  AssetNode._(this.id, this.transform)
+  AssetNode._(this.id, this._transform)
       : _state = AssetState.DIRTY;
 
-  AssetNode._available(Asset asset, this.transform)
+  AssetNode._available(Asset asset, this._transform)
       : id = asset.id,
         _asset = asset,
         _state = AssetState.AVAILABLE;
@@ -134,6 +137,17 @@
   AssetNodeController.available(Asset asset, [TransformNode transform])
       : node = new AssetNode._available(asset, transform);
 
+  /// Creates a controller for a node whose initial state matches the current
+  /// state of [node].
+  AssetNodeController.from(AssetNode node)
+      : node = new AssetNode._(node.id, node.transform) {
+    if (node.state.isAvailable) {
+      setAvailable(node.asset);
+    } else if (node.state.isRemoved) {
+      setRemoved();
+    }
+  }
+
   /// Marks the node as [AssetState.DIRTY].
   void setDirty() {
     assert(node._state != AssetState.REMOVED);
@@ -165,6 +179,14 @@
     node._asset = asset;
     node._stateChangeController.add(AssetState.AVAILABLE);
   }
+
+  /// Sets the node's [AssetNode.transform] property.
+  ///
+  /// This is used when resolving collisions, where a node will stick around but
+  /// a different transform will have created it.
+  void setTransform(TransformNode transform) {
+    node._transform = transform;
+  }
 }
 
 // TODO(nweiz): add an error state.
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 690126a..a73ee00 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -13,6 +13,7 @@
 import 'asset_set.dart';
 import 'errors.dart';
 import 'phase_input.dart';
+import 'phase_output.dart';
 import 'stream_pool.dart';
 import 'transformer.dart';
 import 'utils.dart';
@@ -44,15 +45,8 @@
   /// phases, they will be the outputs from the previous phase.
   final _inputs = new Map<AssetId, PhaseInput>();
 
-  /// A map of output ids to the asset node outputs for those ids and the
-  /// transforms that produced those asset nodes.
-  ///
-  /// Usually there's only one node for a given output id. However, it's
-  /// possible for multiple transformers to output an asset with the same id. In
-  /// that case, the chronologically first output emitted is passed forward. We
-  /// keep track of the other nodes so that if that output is removed, we know
-  /// which asset to replace it with.
-  final _outputs = new Map<AssetId, Queue<AssetNode>>();
+  /// The outputs for this phase.
+  final _outputs = new Map<AssetId, PhaseOutput>();
 
   /// A stream that emits an event whenever this phase becomes dirty and needs
   /// to be run.
@@ -77,7 +71,7 @@
   /// Returns all currently-available output assets for this phase.
   AssetSet get availableOutputs {
     return new AssetSet.from(_outputs.values
-        .map((queue) => queue.first)
+        .map((output) => output.output)
         .where((node) => node.state.isAvailable)
         .map((node) => node.asset));
   }
@@ -125,7 +119,7 @@
     return newFuture(() {
       if (id.package != cascade.package) return cascade.graph.getAssetNode(id);
       if (!_outputs.containsKey(id)) return null;
-      return _outputs[id].first;
+      return _outputs[id].output;
     });
   }
 
@@ -145,12 +139,38 @@
   Phase addPhase(Iterable<Transformer> transformers) {
     assert(_next == null);
     _next = new Phase(cascade, transformers);
-    for (var outputs in _outputs.values) {
-      _next.addInput(outputs.first);
+    for (var output in _outputs.values.toList()) {
+      // Remove [output]'s listeners because now they should get the asset from
+      // [_next], rather than this phase. Any transforms consuming [output] will
+      // be re-run and will consume the output from the new final phase.
+      output.removeListeners();
+
+      // Removing [output]'s listeners will cause it to be removed from
+      // [_outputs], so we have to put it back.
+      _outputs[output.output.id] = output;
+      _next.addInput(output.output);
     }
     return _next;
   }
 
+  /// Mark this phase as removed.
+  ///
+  /// This will remove all the phase's outputs and all following phases.
+  void remove() {
+    removeFollowing();
+    for (var input in _inputs.values.toList()) {
+      input.remove();
+    }
+    _onDirtyPool.close();
+  }
+
+  /// Remove all phases after this one.
+  Phase removeFollowing() {
+    if (_next == null) return;
+    _next.remove();
+    _next = null;
+  }
+
   /// Processes this phase.
   ///
   /// Returns a future that completes when processing is done. If there is
@@ -158,76 +178,32 @@
   Future process() {
     if (!_inputs.values.any((input) => input.isDirty)) return null;
 
+    var outputIds = new Set<AssetId>();
     return Future.wait(_inputs.values.map((input) {
       if (!input.isDirty) return new Future.value(new Set());
       return input.process().then((outputs) {
-        return outputs.where(_addOutput).map((output) => output.id).toSet();
+        for (var asset in outputs) {
+          outputIds.add(asset.id);
+          if (_outputs.containsKey(asset.id)) {
+            _outputs[asset.id].add(asset);
+          } else {
+            _outputs[asset.id] = new PhaseOutput(this, asset);
+            _outputs[asset.id].output.whenRemoved
+                .then((_) => _outputs.remove(asset.id));
+            if (_next != null) _next.addInput(_outputs[asset.id].output);
+          }
+        }
       });
-    })).then((collisionsList) {
+    })).then((_) {
       // Report collisions in a deterministic order.
-      var collisions = unionAll(collisionsList).toList();
-      collisions.sort((a, b) => a.compareTo(b));
-      for (var collision in collisions) {
-        // Ensure that there's still a collision. It's possible it was resolved
-        // while another transform was running.
-        if (_outputs[collision].length <= 1) continue;
-        cascade.reportError(new AssetCollisionException(
-            _outputs[collision].where((asset) => asset.transform != null)
-                .map((asset) => asset.transform.info),
-            collision));
-      }
-    });
-  }
-
-  /// Add [output] as an output of this phase, forwarding it to the next phase
-  /// if necessary.
-  ///
-  /// Returns whether or not [output] collides with another pre-existing output.
-  bool _addOutput(AssetNode output) {
-    _handleOutputRemoval(output);
-
-    if (_outputs.containsKey(output.id)) {
-      _outputs[output.id].add(output);
-      return true;
-    }
-
-    _outputs[output.id] = new Queue<AssetNode>.from([output]);
-    if (_next != null) _next.addInput(output);
-    return false;
-  }
-
-  /// Properly resolve collisions when [output] is removed.
-  void _handleOutputRemoval(AssetNode output) {
-    output.whenRemoved.then((_) {
-      var assets = _outputs[output.id];
-      if (assets.length == 1) {
-        assert(assets.single == output);
-        _outputs.remove(output.id);
-        return;
-      }
-
-      // If there was more than one asset, we're resolving a collision --
-      // possibly partially.
-      var wasFirst = assets.first == output;
-      assets.remove(output);
-
-      // If this was the first asset, we need to pass the next asset
-      // (chronologically) to the next phase. Pump the event queue first to give
-      // [_next] a chance to handle the removal of its input before getting a
-      // new input.
-      if (wasFirst && _next != null) {
-        newFuture(() => _next.addInput(assets.first));
-      }
-
-      // If there's still a collision, report it. This lets the user know
-      // if they've successfully resolved the collision or not.
-      if (assets.length > 1) {
-        // Pump the event queue to ensure that the removal of the input triggers
-        // a new build to which we can attach the error.
-        newFuture(() => cascade.reportError(new AssetCollisionException(
-            assets.where((asset) => asset.transform != null)
-                .map((asset) => asset.transform.info),
-            output.id)));
+      outputIds = outputIds.toList();
+      outputIds.sort((a, b) => a.compareTo(b));
+      for (var id in outputIds) {
+        // It's possible the output was removed before other transforms in this
+        // phase finished.
+        if (!_outputs.containsKey(id)) continue;
+        var exception = _outputs[id].collisionException;
+        if (exception != null) cascade.reportError(exception);
       }
     });
   }
diff --git a/pkg/barback/lib/src/phase_output.dart b/pkg/barback/lib/src/phase_output.dart
new file mode 100644
index 0000000..8082e54
--- /dev/null
+++ b/pkg/barback/lib/src/phase_output.dart
@@ -0,0 +1,129 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library barback.phase_output;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'asset_cascade.dart';
+import 'asset_id.dart';
+import 'asset_node.dart';
+import 'errors.dart';
+import 'phase_input.dart';
+import 'stream_pool.dart';
+import 'transformer.dart';
+import 'utils.dart';
+
+/// A class that handles a single output of a phase.
+///
+/// Normally there's only a single [AssetNode] for a phase's output, but it's
+/// possible that multiple transformers in the same phase emit assets with the
+/// same id, causing collisions. This handles those collisions by forwarding the
+/// chronologically first asset.
+class PhaseOutput {
+  /// The phase for which this is an output.
+  final Phase _phase;
+
+  /// The asset node for this output.
+  AssetNode get output => _outputController.node;
+  AssetNodeController _outputController;
+
+  /// The assets for this output.
+  ///
+  /// If there's no collision, this will only have one element. Otherwise, it
+  /// will be ordered by which asset was added first.
+  final _assets = new Queue<AssetNode>();
+
+  /// The [AssetCollisionException] for this output, or null if there is no
+  /// collision currently.
+  AssetCollisionException get collisionException {
+    if (_assets.length == 1) return null;
+    return new AssetCollisionException(
+        _assets.where((asset) => asset.transform != null)
+            .map((asset) => asset.transform.info),
+        output.id);
+  }
+
+  PhaseOutput(this._phase, AssetNode output)
+      : _outputController = new AssetNodeController.from(output) {
+    assert(!output.state.isRemoved);
+    add(output);
+  }
+
+  /// Adds an asset node as an output with this id.
+  void add(AssetNode node) {
+    assert(node.id == output.id);
+    _assets.add(node);
+    _watchAsset(node);
+  }
+
+  /// Removes all existing listeners on [output] without actually closing
+  /// [this].
+  ///
+  /// This marks [output] as removed, but immediately replaces it with a new
+  /// [AssetNode] in the same state as the old output. This is used when adding
+  /// a new [Phase] to cause consumers of the prior phase's outputs to be to
+  /// start consuming the new phase's outputs instead.
+  void removeListeners() {
+    _outputController.setRemoved();
+    _outputController = new AssetNodeController.from(_assets.first);
+  }
+
+  /// Watches [node] for state changes and adjusts [_assets] and [output]
+  /// appropriately when they occur.
+  void _watchAsset(AssetNode node) {
+    node.onStateChange.listen((state) {
+      if (state.isRemoved) {
+        _removeAsset(node);
+        return;
+      }
+      if (_assets.first != node) return;
+
+      if (state.isAvailable) {
+        _outputController.setAvailable(node.asset);
+      } else {
+        assert(state.isDirty);
+        _outputController.setDirty();
+      }
+    });
+  }
+
+  /// Removes [node] as an output.
+  void _removeAsset(AssetNode node) {
+    if (_assets.length == 1) {
+      assert(_assets.single == node);
+      _outputController.setRemoved();
+      return;
+    }
+
+    // If there was more than one asset, we're resolving a collision --
+    // possibly partially.
+    var wasFirst = _assets.first == node;
+    _assets.remove(node);
+
+    // If this was the first asset, we replace it with the next asset
+    // (chronologically).
+    if (wasFirst) {
+      var newOutput = _assets.first;
+      _outputController.setTransform(newOutput.transform);
+      if (newOutput.state.isAvailable) {
+        if (output.state.isAvailable) _outputController.setDirty();
+        _outputController.setAvailable(newOutput.asset);
+      } else {
+        assert(newOutput.isDirty);
+        if (!output.isDirty) _outputController.setDirty();
+      }
+    }
+
+    // If there's still a collision, report it. This lets the user know
+    // if they've successfully resolved the collision or not.
+    if (_assets.length > 1) {
+      // Pump the event queue to ensure that the removal of the input triggers
+      // a new build to which we can attach the error.
+      // TODO(nweiz): report this through the output asset.
+      newFuture(() => _phase.cascade.reportError(collisionException));
+    }
+  }
+}
diff --git a/pkg/barback/test/asset_id_test.dart b/pkg/barback/test/asset_id_test.dart
index a55bb18..16d29ae 100644
--- a/pkg/barback/test/asset_id_test.dart
+++ b/pkg/barback/test/asset_id_test.dart
@@ -11,6 +11,18 @@
 
 main() {
   initConfig();
+  group("constructor", () {
+    test("normalizes the path", () {
+      var id = new AssetId("app", r"path/././/to/drop/..//asset.txt");
+      expect(id.path, equals("path/to/asset.txt"));
+    });
+
+    test("normalizes backslashes to slashes in the path", () {
+      var id = new AssetId("app", r"path\to/asset.txt");
+      expect(id.path, equals("path/to/asset.txt"));
+    });
+  });
+
   group("parse", () {
     test("parses the package and path", () {
       var id = new AssetId.parse("package|path/to/asset.txt");
@@ -29,6 +41,16 @@
     test("throws if the path is empty '|'", () {
       expect(() => new AssetId.parse("app|"), throwsFormatException);
     });
+
+    test("normalizes the path", () {
+      var id = new AssetId.parse(r"app|path/././/to/drop/..//asset.txt");
+      expect(id.path, equals("path/to/asset.txt"));
+    });
+
+    test("normalizes backslashes to slashes in the path", () {
+      var id = new AssetId.parse(r"app|path\to/asset.txt");
+      expect(id.path, equals("path/to/asset.txt"));
+    });
   });
 
   test("equals another ID with the same package and path", () {
diff --git a/pkg/barback/test/package_graph/add_remove_transform_test.dart b/pkg/barback/test/package_graph/add_remove_transform_test.dart
index b79c69a..bd68f68 100644
--- a/pkg/barback/test/package_graph/add_remove_transform_test.dart
+++ b/pkg/barback/test/package_graph/add_remove_transform_test.dart
@@ -191,9 +191,6 @@
   });
 
   test("a cross-package transform sees a new transformer in a new phase", () {
-    // TODO(nweiz): make this work.
-    return;
-
     var rewrite = new RewriteTransformer("inc", "inc");
     initGraph({
       "pkg1|foo.txt": "pkg2|foo.inc",
@@ -204,7 +201,7 @@
     });
 
     updateSources(["pkg1|foo.txt", "pkg2|foo.inc"]);
-    expectAsset("pkg1|foo.out", "foo");
+    expectAsset("pkg1|foo.out", "foo.inc");
     buildShouldSucceed();
 
     updateTransformers("pkg2", [
diff --git a/pkg/fixnum/lib/fixnum.dart b/pkg/fixnum/lib/fixnum.dart
index 1f89dd4..fe21c47 100644
--- a/pkg/fixnum/lib/fixnum.dart
+++ b/pkg/fixnum/lib/fixnum.dart
@@ -8,7 +8,7 @@
  * The integer implementations in this library are designed to work
  * identically whether executed on the Dart VM or compiled to JavaScript.
  *
- * For information on getting this library, see the
+ * For information on installing and importing this library, see the
  * [fixnum package on pub.dartlang.org]
  * (http://pub.dartlang.org/packages/fixnum).
  */
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 6477023..5f9639f 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -159,7 +159,7 @@
   for (var locale in allLocales) {
     var baseFile = '${generatedFilePrefix}messages_$locale.dart';
     var file = importForGeneratedFile(baseFile);
-    output.write("@${_deferredName(locale)} ");
+    output.write("@${_deferredName(locale)}\n");
     output.write("import '$file' as ${_libraryName(locale)};\n");
   }
   output.write("\n");
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index a15abed..4f17a82 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -81,6 +81,11 @@
  * produce "I see 2 other people in Athens." as output in the default locale.
  *
  * To use a locale other than the default, use the `withLocale` function.
+ * You can set the default locale.
+ *       Intl.defaultLocale = "pt_BR";
+ *
+ * To temporarily use a locale other than the default, use the `withLocale`
+ * function.
  *       var todayString = new DateFormat("pt_BR").format(new DateTime.now());
  *       print(withLocale("pt_BR", () => today(todayString));
  *
@@ -99,7 +104,7 @@
    * can also be set explicitly, and will then apply to any new instances where
    * the locale isn't specified.
    */
-  static String _defaultLocale;
+  static String defaultLocale;
 
   /**
    * The system's locale, as obtained from the window.navigator.language
@@ -345,9 +350,9 @@
     // but must be a static variable in order to be visible to the Intl.message
     // invocation.
     var oldLocale = getCurrentLocale();
-    _defaultLocale = locale;
+    defaultLocale = locale;
     var result = message_function();
-    _defaultLocale = oldLocale;
+    defaultLocale = oldLocale;
     return result;
   }
 
@@ -357,8 +362,8 @@
    * locale.
    */
   static String getCurrentLocale() {
-    if (_defaultLocale == null) _defaultLocale = systemLocale;
-    return _defaultLocale;
+    if (defaultLocale == null) defaultLocale = systemLocale;
+    return defaultLocale;
   }
 
   toString() => "Intl($locale)";
diff --git a/pkg/intl/lib/message_lookup_by_library.dart b/pkg/intl/lib/message_lookup_by_library.dart
index 2e92dbd..c4107dc 100644
--- a/pkg/intl/lib/message_lookup_by_library.dart
+++ b/pkg/intl/lib/message_lookup_by_library.dart
@@ -97,23 +97,9 @@
   String lookupMessage(String message_str, [final String desc='',
       final Map examples=const {}, String locale,
       String name, List<String> args]) {
-    // If we don't have a name, return the original, and if we have
-    // been recursively invoked, also just return message_str. This
-    // happens because the replacement functions also call Intl.message,
-    // so we assume that when _lookupInProgress is true that we're
-    // already translated.
-    if (name == null || _lookupInProgress) return message_str;
-    _lookupInProgress = true;
-    // Try to apply the function holding the translated version. If there
-    // is an exception, use the original [message_str] as the result.
-    var result = message_str;
-    try {
-      var function = this[name];
-      if (function != null) result = Function.apply(function, args);
-    } finally {
-      _lookupInProgress = false;
-    }
-    return result;
+    if (name == null) return message_str;
+    var function = this[name];
+    return function == null ? message_str :  Function.apply(function, args);
   }
 
   /** Return our message with the given name */
diff --git a/pkg/intl/lib/src/intl_message.dart b/pkg/intl/lib/src/intl_message.dart
index 886c82d..ad88395 100644
--- a/pkg/intl/lib/src/intl_message.dart
+++ b/pkg/intl/lib/src/intl_message.dart
@@ -350,9 +350,9 @@
     var out = new StringBuffer()
       ..write('static $name(')
       ..write(arguments.join(", "))
-      ..write(') => Intl.$dartMessageName("')
+      ..write(') => "')
       ..write(translations[locale])
-      ..write('");');
+      ..write('";');
     return out.toString();
   }
 
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 28fbc2f..1eae910 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -3,25 +3,15 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * Provides APIs for debugging and error logging. This library introduces
- * abstractions similar to those used in other languages, such as the Closure JS
+ * Support for debugging and error logging.
+ *
+ * This library introduces abstractions similar to
+ * those used in other languages, such as the Closure JS
  * Logger and java.util.logging.Logger.
  *
- * ## Installing ##
- *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- *     dependencies:
- *       logging: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
- * [logging package on pub.dartlang.org][pkg].
- *
- * [pub]: http://pub.dartlang.org
- * [pkg]: http://pub.dartlang.org/packages/logging
+ * For information on installing and importing this library, see the
+ * [logging package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/logging).
  */
 library logging;
 
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 9960d59..e3e4a25 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -3,24 +3,21 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * This library contains the definitions of annotations that provide additional
- * semantic information about the program being annotated. These annotations are
- * intended to be used by tools to provide a better user experience.
+ * Constants for use in metadata annotations such as
+ * `@deprecated`, `@override`, and `@proxy`.
+ * 
+ * Annotations provide semantic information
+ * that tools can use to provide a better user experience.
+ * For example, an IDE might not autocomplete
+ * the name of a function that's been marked `@deprecated`,
+ * or it might display the function's name differently.
  *
- * ## Installing ##
- *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- *     dependencies:
- *       meta: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
- * [meta package on pub.dartlang.org](http://pub.dartlang.org/packages/meta).
- *
- * [pub]: http://pub.dartlang.org
+ * For information on installing and importing this library, see the
+ * [meta package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/meta).
+ * For examples of using annotations, see
+ * [Metadata](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-metadata)
+ * in the language tour.
  */
 library meta;
 
diff --git a/pkg/pkg.status b/pkg/pkg.status
index f41776a..4acfd1b 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -59,7 +59,7 @@
 
 [ $runtime == safari ]
 fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
-crypto/test/hmac_sha1_test: Fail # Issue 11407.
+crypto/test/hmac_sha1_test: Pass, Fail # Issue 11407.
 crypto/test/sha1_test: Fail # Issue 11407.
 stack_trace/test/trace_test: Fail # http://dartbug.com/12380
 crypto/test/sha256_test: Pass, Fail # Issue 12502
diff --git a/pkg/polymer/lib/src/emitters.dart b/pkg/polymer/lib/src/emitters.dart
index dbd6816..c5da7ba 100644
--- a/pkg/polymer/lib/src/emitters.dart
+++ b/pkg/polymer/lib/src/emitters.dart
@@ -79,11 +79,8 @@
   return printer
       ..indent -= 1
       ..addLine('],')
-      ..addLine(
-          "currentMirrorSystem().findLibrary(const Symbol('app_bootstrap'))")
-      ..indent += 2
-      ..addLine(".first.uri.toString());")
-      ..indent -= 4
+      ..addLine("currentMirrorSystem().isolate.rootLibrary.uri.toString());")
+      ..indent -= 2
       ..addLine('}');
 }
 
diff --git a/pkg/polymer/lib/src/transform.dart b/pkg/polymer/lib/src/transform.dart
new file mode 100644
index 0000000..ff5de2b
--- /dev/null
+++ b/pkg/polymer/lib/src/transform.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Transfomers used for pub-serve and pub-deploy. */
+// TODO(sigmund): move into a plugin directory when pub supports it.
+library polymer.src.transform;
+
+import 'package:observe/transform.dart';
+import 'transform/code_extractor.dart';
+import 'transform/import_inliner.dart';
+import 'transform/script_compactor.dart';
+
+export 'transform/code_extractor.dart';
+export 'transform/import_inliner.dart';
+export 'transform/script_compactor.dart';
+
+/** Phases to deploy a polymer application. */
+var phases = [
+  [new InlineCodeExtractor()],
+  [new ObservableTransformer()],
+  [new ImportedElementInliner()],
+  [new ScriptCompactor()]
+];
diff --git a/pkg/polymer/lib/src/transform/code_extractor.dart b/pkg/polymer/lib/src/transform/code_extractor.dart
new file mode 100644
index 0000000..0e6d4d5
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/code_extractor.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Transfomer that extracts inlined script code into separate assets. */
+library polymer.src.transformers;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+
+import 'common.dart';
+
+/**
+ * Transformer that extracts Dart code inlined in HTML script tags and outputs a
+ * separate file for each.
+ */
+class InlineCodeExtractor extends Transformer {
+  Future<bool> isPrimary(Asset input) =>
+      new Future.value(input.id.extension == ".html");
+
+  Future apply(Transform transform) {
+    var inputId = transform.primaryId;
+    return getPrimaryContent(transform).then((content) {
+      var document = parseHtml(content, inputId.path, transform.logger);
+      int count = 0;
+      bool htmlChanged = false;
+      for (var tag in document.queryAll('script')) {
+        // Only process tags that have inline Dart code
+        if (tag.attributes['type'] != 'application/dart' ||
+          tag.attributes.containsKey('src')) {
+          continue;
+        }
+        htmlChanged = true;
+
+        // Remove empty tags
+        if (tag.nodes.length == 0) {
+          tag.remove();
+          continue;
+        }
+
+        // TODO(sigmund): should we automatically include a library directive
+        // if it doesn't have one?
+        var filename = path.url.basename(inputId.path);
+        // TODO(sigmund): ensure this filename is unique (dartbug.com/12618).
+        tag.attributes['src'] = '$filename.$count.dart';
+        var textContent = tag.nodes.first;
+        var id = inputId.addExtension('.$count.dart');
+        transform.addOutput(new Asset.fromString(id, textContent.value));
+        textContent.remove();
+        count++;
+      }
+      transform.addOutput(new Asset.fromString(inputId,
+          htmlChanged ? document.outerHtml : content));
+    });
+  }
+}
diff --git a/pkg/polymer/lib/src/transform/common.dart b/pkg/polymer/lib/src/transform/common.dart
new file mode 100644
index 0000000..c72e8b1
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/common.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Common methods used by transfomers. */
+library polymer.src.transform.common;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/dom.dart' show Document;
+import 'package:html5lib/parser.dart' show HtmlParser;
+import 'package:path/path.dart' as path;
+import 'package:source_maps/span.dart' show Span;
+
+// TODO(sigmund): delete this function (see dartbug.com/12515 and
+// dartbug.com/12516)
+Future<String> getPrimaryContent(Transform transform) =>
+  transform.primaryInput.then((asset) => asset.readAsString());
+
+// TODO(sigmund): delete this function (see dartbug.com/12515)
+Future<String> getContent(Transform transform, AssetId id) =>
+  transform.getInput(id).then((asset) => asset.readAsString());
+
+/**
+ * Parses an HTML file [contents] and returns a DOM-like tree. Adds emitted
+ * error/warning to [logger].
+ */
+Document parseHtml(String contents, String sourcePath, TransformLogger logger,
+    {bool checkDocType: true}) {
+  // TODO(jmesserly): make HTTP encoding configurable
+  var parser = new HtmlParser(contents, encoding: 'utf8', generateSpans: true,
+      sourceUrl: sourcePath);
+  var document = parser.parse();
+
+  // Note: errors aren't fatal in HTML (unless strict mode is on).
+  // So just print them as warnings.
+  for (var e in parser.errors) {
+    if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') {
+      logger.warning(e.message, e.span);
+    }
+  }
+  return document;
+}
+
+/** Create an [AssetId] for a [url] seen in the [source] asset. */
+// TODO(sigmund): delete once this is part of barback (dartbug.com/12610)
+AssetId resolve(AssetId source, String url, TransformLogger logger, Span span) {
+  if (url == null || url == '') return null;
+  var uri = Uri.parse(url);
+  var urlBuilder = path.url;
+  if (uri.host != '' || uri.scheme != '' || urlBuilder.isAbsolute(url)) {
+    logger.error('absolute paths not allowed: "$url"', span);
+    return null;
+  }
+
+  var package;
+  var targetPath;
+  var segments = urlBuilder.split(url);
+  if (segments[0] == 'packages') {
+    if (segments.length < 3) {
+      logger.error("incomplete packages/ path. It should have at least 3 "
+          "segments packages/name/path-from-name's-lib-dir", span);
+      return null;
+    }
+    package = segments[1];
+    targetPath = urlBuilder.join('lib',
+        urlBuilder.joinAll(segments.sublist(2)));
+  } else if (segments[0] == 'assets') {
+    if (segments.length < 3) {
+      logger.error("incomplete assets/ path. It should have at least 3 "
+          "segments assets/name/path-from-name's-asset-dir", span);
+    }
+    package = segments[1];
+    targetPath = urlBuilder.join('asset',
+        urlBuilder.joinAll(segments.sublist(2)));
+  } else {
+    package = source.package;
+    targetPath = urlBuilder.normalize(
+        urlBuilder.join(urlBuilder.dirname(source.path), url));
+  }
+  return new AssetId(package, targetPath);
+}
diff --git a/pkg/polymer/lib/src/transform/import_inliner.dart b/pkg/polymer/lib/src/transform/import_inliner.dart
new file mode 100644
index 0000000..ac8ab7e
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/import_inliner.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Transfomer that inlines polymer-element definitions from html imports. */
+library polymer.src.transform.import_inliner;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/dom.dart' show Document, Node, DocumentFragment;
+import 'common.dart';
+
+/** Recursively inlines polymer-element definitions from html imports. */
+// TODO(sigmund): make sure we match semantics of html-imports for tags other
+// than polymer-element (see dartbug.com/12613).
+class ImportedElementInliner extends Transformer {
+  Future<bool> isPrimary(Asset input) =>
+      new Future.value(input.id.extension == ".html");
+
+  Future apply(Transform transform) {
+    var seen = new Set<AssetId>();
+    var elements = [];
+    var id = transform.primaryId;
+    seen.add(id);
+    return getPrimaryContent(transform).then((content) {
+      var document = parseHtml(content, id.path, transform.logger);
+      var future = _visitImports(document, id, transform, seen, elements);
+      return future.then((importsFound) {
+        if (!importsFound) {
+          transform.addOutput(new Asset.fromString(id, content));
+          return;
+        }
+
+        for (var tag in document.queryAll('link')) {
+          if (tag.attributes['rel'] == 'import') {
+            tag.remove();
+          }
+        }
+        var fragment = new DocumentFragment()..nodes.addAll(elements);
+        document.body.insertBefore(fragment,
+            //TODO(jmesserly): add Node.firstChild to html5lib
+            document.body.nodes.length == 0 ? null : document.body.nodes[0]);
+        transform.addOutput(new Asset.fromString(id, document.outerHtml));
+      });
+    });
+  }
+
+  /**
+   * Visits imports in [document] and add their polymer-element definitions to
+   * [elements], unless they have already been [seen]. Elements are added in the
+   * order they appear, transitive imports are added first.
+   */
+  Future<bool> _visitImports(Document document, AssetId sourceId,
+      Transform transform, Set<AssetId> seen, List<Node> elements) {
+    var importIds = [];
+    bool hasImports = false;
+    for (var tag in document.queryAll('link')) {
+      if (tag.attributes['rel'] != 'import') continue;
+      var href = tag.attributes['href'];
+      var id = resolve(sourceId, href, transform.logger, tag.sourceSpan);
+      hasImports = true;
+      if (id == null || seen.contains(id)) continue;
+      importIds.add(id);
+    }
+
+    if (importIds.isEmpty) return new Future.value(hasImports);
+
+    // Note: we need to preserve the import order in the generated output.
+    return Future.forEach(importIds, (id) {
+      if (seen.contains(id)) return new Future.value(null);
+      seen.add(id);
+      return _collectPolymerElements(id, transform, seen, elements);
+    }).then((_) => true);
+  }
+
+  /**
+   * Loads an asset identified by [id], visits its imports and collects it's
+   * polymer-element definitions.
+   */
+  Future _collectPolymerElements(
+      AssetId id, Transform transform, Set<AssetId> seen, List elements) {
+    return getContent(transform, id)
+        .then((content) => parseHtml(
+              content, id.path, transform.logger, checkDocType: false))
+        .then((document) {
+          return _visitImports(document, id, transform, seen, elements)
+            .then((_) => elements.addAll(document.queryAll('polymer-element')));
+        });
+  }
+}
diff --git a/pkg/polymer/lib/src/transform/script_compactor.dart b/pkg/polymer/lib/src/transform/script_compactor.dart
new file mode 100644
index 0000000..9c2550a
--- /dev/null
+++ b/pkg/polymer/lib/src/transform/script_compactor.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Transfomer that combines multiple dart script tags into a single one. */
+library polymer.src.transform.script_compactor;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:html5lib/parser.dart' show parseFragment;
+import 'package:path/path.dart' as path;
+
+import 'code_extractor.dart'; // import just for documentation.
+import 'common.dart';
+
+/**
+ * Combines Dart script tags into a single script tag, and creates a new Dart
+ * file that calls the main function of each of the original script tags.
+ *
+ * This transformer assumes that all script tags point to external files. To
+ * support script tags with inlined code, use this transformer after running
+ * [InlineCodeExtractor] on an earlier phase.
+ *
+ * Internally, this transformer will convert each script tag into an import
+ * statement to a library, and then uses `initPolymer` (see polymer.dart)  to
+ * invoke the main method on each of these libraries and register any polymer
+ * elements annotated with `@CustomTag`.
+ */
+class ScriptCompactor extends Transformer {
+  Future<bool> isPrimary(Asset input) =>
+      new Future.value(input.id.extension == ".html");
+
+  Future apply(Transform transform) {
+    var id = transform.primaryId;
+    var logger = transform.logger;
+    return getPrimaryContent(transform).then((content) {
+      var document = parseHtml(content, id.path, logger);
+      var libraries = [];
+      bool changed = false;
+      var dartLoaderTag = null;
+      for (var tag in document.queryAll('script')) {
+        var src = tag.attributes['src'];
+        if (src != null) {
+          if (src == 'packages/polymer/boot.js') {
+            tag.remove();
+            continue;
+          }
+          var last = src.split('/').last;
+          if (last == 'dart.js' || last == 'testing.js') {
+            dartLoaderTag = tag;
+          }
+        }
+        if (tag.attributes['type'] != 'application/dart') continue;
+        tag.remove();
+        changed = true;
+        if (src == null) {
+          logger.warning('unexpected script without a src url. The '
+            'ScriptCompactor transformer should run after running the '
+            'InlineCodeExtractor', tag.sourceSpan);
+          continue;
+        }
+        var libraryId = resolve(id, src, logger, tag.sourceSpan);
+
+        // TODO(sigmund): should we detect/remove duplicates?
+        if (libraryId == null) continue;
+        libraries.add(libraryId);
+      }
+
+      if (!changed) {
+        transform.addOutput(new Asset.fromString(id, content));
+        return;
+      }
+
+      var bootstrapId = id.addExtension('_bootstrap.dart');
+      var filename = path.url.basename(bootstrapId.path);
+
+      var bootstrapScript = parseFragment(
+            '<script type="application/dart" src="$filename"></script>');
+      if (dartLoaderTag == null) {
+        document.body.nodes.add(bootstrapScript);
+        document.body.nodes.add(parseFragment('<script type="text/javascript" '
+            'src="packages/browser/dart.js"></script>'));
+      } else if (dartLoaderTag.parent != document.body) {
+        document.body.nodes.add(bootstrapScript);
+      } else {
+        document.body.insertBefore(bootstrapScript, dartLoaderTag);
+      }
+
+      var urls = libraries.map((id) => importUrlFor(id, bootstrapId, logger))
+          .where((url) => url != null).toList();
+      var buffer = new StringBuffer()..write(_header);
+      for (int i = 0; i < urls.length; i++) {
+        buffer.writeln("import '${urls[i]}' as i$i;");
+      }
+      buffer..write(_mainPrefix)
+          ..writeAll(urls.map((url) => "      '$url',\n"))
+          ..write(_mainSuffix);
+
+      transform.addOutput(new Asset.fromString(bootstrapId, buffer.toString()));
+      transform.addOutput(new Asset.fromString(id, document.outerHtml));
+    });
+  }
+
+  /**
+   * Generate the import url for a file described by [id], referenced by a file
+   * with [sourceId].
+   */
+  String importUrlFor(AssetId id, AssetId sourceId, TransformLogger logger) {
+    // use package: urls if possible
+    if (id.path.startsWith('lib/')) {
+      return 'package:${id.package}/${id.path.substring(4)}';
+    }
+    
+    // Use relative urls only if it's possible.
+    if (id.package != sourceId.package) {
+      logger.error("don't know how to import $id from $sourceId");
+      return null;
+    }
+
+    var builder = path.url;
+    return builder.relative(builder.join('/', id.path),
+        from: builder.join('/', builder.dirname(sourceId.path)));
+  }
+}
+
+const _header = """
+library app_bootstrap;
+
+import 'package:polymer/polymer.dart';
+import 'dart:mirrors' show currentMirrorSystem;
+
+""";
+
+const _mainPrefix = """
+
+void main() {
+  initPolymer([
+""";
+
+// TODO(sigmund): investigate alternative to get the baseUri (dartbug.com/12612)
+const _mainSuffix = """
+    ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+}
+""";
diff --git a/pkg/polymer/test/run_all.dart b/pkg/polymer/test/run_all.dart
index b149502..cc666ed 100644
--- a/pkg/polymer/test/run_all.dart
+++ b/pkg/polymer/test/run_all.dart
@@ -17,6 +17,10 @@
 import 'compiler_test.dart' as compiler_test;
 import 'paths_test.dart' as paths_test;
 import 'utils_test.dart' as utils_test;
+import 'transform/code_extractor_test.dart' as code_extractor_test;
+import 'transform/import_inliner_test.dart' as import_inliner_test;
+import 'transform/script_compactor_test.dart' as script_compactor_test;
+import 'transform/all_phases_test.dart' as all_phases_test;
 
 main() {
   var args = new Options().arguments;
@@ -34,6 +38,10 @@
   addGroup('css_test.dart', css_test.main);
   addGroup('paths_test.dart', paths_test.main);
   addGroup('utils_test.dart', utils_test.main);
+  addGroup('transform/code_extractor_test.dart', code_extractor_test.main);
+  addGroup('transform/import_inliner_test.dart', import_inliner_test.main);
+  addGroup('transform/script_compactor_test.dart', script_compactor_test.main);
+  addGroup('transform/all_phases_test.dart', all_phases_test.main);
 
   endToEndTests('data/unit/', 'data/out');
 
diff --git a/pkg/polymer/test/transform/all_phases_test.dart b/pkg/polymer/test/transform/all_phases_test.dart
new file mode 100644
index 0000000..a644fe5
--- /dev/null
+++ b/pkg/polymer/test/transform/all_phases_test.dart
@@ -0,0 +1,206 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.transform.script_compactor_test;
+
+import 'package:polymer/src/transform.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+  useCompactVMConfiguration();
+
+  testPhases('no changes', phases, {
+      'a|web/test.html': '<!DOCTYPE html><html></html>',
+    }, {
+      'a|web/test.html': '<!DOCTYPE html><html></html>',
+    });
+
+  testPhases('observable changes', phases, {
+      'a|web/test.dart': _sampleObservable('A', 'foo'),
+      'a|web/test2.dart': _sampleObservableOutput('B', 'bar'),
+    }, {
+      'a|web/test.dart': _sampleObservableOutput('A', 'foo'),
+      'a|web/test2.dart': _sampleObservableOutput('B', 'bar'),
+    });
+
+  testPhases('single script', phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="a.dart"></script>',
+      'a|web/test.dart': _sampleObservable('A', 'foo'),
+    }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<script type="application/dart" '
+          'src="test.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+
+      'a|web/test.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'a.dart' as i0;
+
+          void main() {
+            initPolymer([
+                'a.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+      'a|web/test.dart': _sampleObservableOutput('A', 'foo'),
+    });
+
+  testPhases('single inline script', phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart">'
+          '${_sampleObservable("B", "bar")}</script>',
+    }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<script type="application/dart" '
+          'src="test.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+
+      'a|web/test.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'test.html.0.dart' as i0;
+
+          void main() {
+            initPolymer([
+                'test.html.0.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+      'a|web/test.html.0.dart': _sampleObservableOutput("B", "bar"),
+    });
+
+  testPhases('several scripts', phases, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="a.dart"></script>'
+          '<script type="application/dart">'
+          '${_sampleObservable("B", "bar")}</script>'
+          '</head><body><div>'
+          '<script type="application/dart">'
+          '${_sampleObservable("C", "car")}</script>'
+          '</div>'
+          '<script type="application/dart" src="d.dart"></script>',
+      'a|web/a.dart': _sampleObservable('A', 'foo'),
+    }, {
+      'a|web/test.html':
+          '<!DOCTYPE html><html><head></head><body><div></div>'
+          '<script type="application/dart" '
+          'src="test.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+
+      'a|web/test.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'a.dart' as i0;
+          import 'test.html.0.dart' as i1;
+          import 'test.html.1.dart' as i2;
+          import 'd.dart' as i3;
+
+          void main() {
+            initPolymer([
+                'a.dart',
+                'test.html.0.dart',
+                'test.html.1.dart',
+                'd.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+      'a|web/a.dart': _sampleObservableOutput('A', 'foo'),
+      'a|web/test.html.0.dart': _sampleObservableOutput("B", "bar"),
+      'a|web/test.html.1.dart': _sampleObservableOutput("C", "car"),
+    });
+
+  testPhases('with imports', phases, {
+      'a|web/index.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2.html">'
+          '</head><body>'
+          '<script type="application/dart" src="b.dart"></script>'
+          '<script type="application/dart">'
+          '${_sampleObservable("C", "car")}</script>',
+      'a|web/b.dart': _sampleObservable('B', 'bar'),
+      'a|web/test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>1'
+          '<script type="application/dart">'
+          '${_sampleObservable("A", "foo")}</script>'
+          '</polymer-element></html>',
+    }, {
+      'a|web/index.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<polymer-element>1</polymer-element>'
+          '<script type="application/dart" '
+          'src="index.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+      'a|web/index.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'test2.html.0.dart' as i0;
+          import 'b.dart' as i1;
+          import 'index.html.0.dart' as i2;
+
+          void main() {
+            initPolymer([
+                'test2.html.0.dart',
+                'b.dart',
+                'index.html.0.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+      'a|web/test2.html.0.dart': _sampleObservableOutput("A", "foo"),
+      'a|web/b.dart': _sampleObservableOutput('B', 'bar'),
+      'a|web/index.html.0.dart': _sampleObservableOutput("C", "car"),
+    });
+}
+
+String _sampleObservable(String className, String fieldName) => '''
+import 'package:observe/observe.dart';
+
+class $className extends ObservableBase {
+  @observable int $fieldName;
+  $className(this.$fieldName);
+}
+''';
+
+String _sampleObservableOutput(String className, String fieldName) => '''
+import 'package:observe/observe.dart';
+
+class $className extends ChangeNotifierBase {
+  int __\$$fieldName;
+  int get $fieldName => __\$$fieldName;
+  set $fieldName(int value) {
+    __\$$fieldName = notifyPropertyChange(const Symbol('$fieldName'), __\$$fieldName, value);
+  }
+  
+  $className($fieldName) : __\$$fieldName = $fieldName;
+}
+''';
diff --git a/pkg/polymer/test/transform/code_extractor_test.dart b/pkg/polymer/test/transform/code_extractor_test.dart
new file mode 100644
index 0000000..e62ec96
--- /dev/null
+++ b/pkg/polymer/test/transform/code_extractor_test.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.transform.code_extractor_test;
+
+import 'package:polymer/src/transform/code_extractor.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+  useCompactVMConfiguration();
+
+  testPhases('no changes', [[new InlineCodeExtractor()]], {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    }, {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    });
+
+  testPhases('single script', [[new InlineCodeExtractor()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart">main() { }</script>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="test.html.0.dart"></script>'
+          '</head><body></body></html>',
+
+      'a|test.html.0.dart':
+          'main() { }',
+    });
+
+  testPhases('multiple scripts', [[new InlineCodeExtractor()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart">main1() { }</script>'
+          '<script type="application/dart">main2() { }</script>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="test.html.0.dart"></script>'
+          '<script type="application/dart" src="test.html.1.dart"></script>'
+          '</head><body></body></html>',
+
+      'a|test.html.0.dart':
+          'main1() { }',
+
+      'a|test.html.1.dart':
+          'main2() { }',
+    });
+
+  testPhases('multiple deeper scripts', [[new InlineCodeExtractor()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart">main1() { }</script>'
+          '</head><body><div>'
+          '<script type="application/dart">main2() { }</script>'
+          '</div><div><div>'
+          '<script type="application/dart">main3() { }</script>'
+          '</div></div>'
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="test.html.0.dart"></script>'
+          '</head><body><div>'
+          '<script type="application/dart" src="test.html.1.dart"></script>'
+          '</div><div><div>'
+          '<script type="application/dart" src="test.html.2.dart"></script>'
+          '</div></div></body></html>',
+
+      'a|test.html.0.dart':
+          'main1() { }',
+
+      'a|test.html.1.dart':
+          'main2() { }',
+
+      'a|test.html.2.dart':
+          'main3() { }',
+    });
+}
diff --git a/pkg/polymer/test/transform/common.dart b/pkg/polymer/test/transform/common.dart
new file mode 100644
index 0000000..c0fd47e
--- /dev/null
+++ b/pkg/polymer/test/transform/common.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.transfom.common;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+import 'package:stack_trace/stack_trace.dart';
+import 'package:unittest/unittest.dart';
+
+String idToString(AssetId id) => '${id.package}|${id.path}';
+AssetId idFromString(String s) {
+  int index = s.indexOf('|');
+  return new AssetId(s.substring(0, index), s.substring(index + 1));
+}
+
+/**
+ * A helper package provider that has files stored in memory, also wraps
+ * [Barback] to simply our tests.
+ */
+class TestHelper implements PackageProvider {
+  /**
+   * Maps from an asset string identifier of the form 'package|path' to the
+   * file contents. 
+   */
+  final Map<String, String> files;
+  final Iterable<String> packages;
+
+  Barback barback;
+  var errorSubscription;
+  var resultSubscription;
+
+  Future<Asset> getAsset(AssetId id) =>
+      new Future.value(new Asset.fromString(id, files[idToString(id)]));
+  TestHelper(List<List<Transformer>> transformers, Map<String, String> files)
+      : files = files,
+        packages = files.keys.map((s) => idFromString(s).package) {
+    barback = new Barback(this);
+    for (var p in packages) {
+      barback.updateTransformers(p, transformers);
+    }
+    errorSubscription = barback.errors.listen((e) {
+      var trace = getAttachedStackTrace(e);
+      if (trace != null) {
+        print(Trace.format(trace));
+      }
+      fail('error running barback: $e');
+    });
+    resultSubscription = barback.results.listen((result) {
+      expect(result.succeeded, isTrue, reason: "${result.errors}");
+    });
+  }
+
+  void tearDown() {
+    errorSubscription.cancel();
+    resultSubscription.cancel();
+  }
+
+  /**
+   * Tells barback which files have changed, and thus anything that depends on
+   * it on should be computed. By default mark all the input files.
+   */
+  void run([Iterable<String> paths]) {
+    if (paths == null) paths = files.keys;
+    barback.updateSources(paths.map(idFromString));
+  }
+
+  Future<String> operator [](String assetString){
+    return barback.getAssetById(idFromString(assetString))
+        .then((asset) => asset.readAsString());
+  }
+
+  Future check(String assetIdString, String content) {
+    return this[assetIdString].then((value) {
+      expect(value, content, reason: 'Final output of $assetIdString differs.');
+    });
+  }
+
+  Future checkAll(Map<String, String> files) {
+    var futures = [];
+    files.forEach((k, v) {
+      futures.add(check(k, v));
+    });
+    return Future.wait(futures);
+  }
+}
+
+testPhases(String testName, List<List<Transformer>> phases,
+    Map<String, String> inputFiles, Map<String, String> expectedFiles) {
+  test(testName, () {
+    var helper = new TestHelper(phases, inputFiles)..run();
+    return helper.checkAll(expectedFiles).then((_) => helper.tearDown());
+  });
+}
+
diff --git a/pkg/polymer/test/transform/import_inliner_test.dart b/pkg/polymer/test/transform/import_inliner_test.dart
new file mode 100644
index 0000000..7776bbd
--- /dev/null
+++ b/pkg/polymer/test/transform/import_inliner_test.dart
@@ -0,0 +1,352 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.transform.import_inliner_test;
+
+import 'package:polymer/src/transform/import_inliner.dart';
+import 'package:unittest/compact_vm_config.dart';
+import 'package:unittest/unittest.dart';
+
+import 'common.dart';
+
+void main() {
+  useCompactVMConfiguration();
+  testPhases('no changes', [[new ImportedElementInliner()]], {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    }, {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    });
+
+  testPhases('empty import', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="">' // empty href
+          '</head></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import">'         // no href
+          '</head></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body></body></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body></body></html>',
+    });
+
+  testPhases('shallow, no elements', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2.html">'
+          '</head></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body></body></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head></html>',
+    });
+
+  testPhases('shallow, elements, one import', [[new ImportedElementInliner()]],
+    {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2.html">'
+          '</head></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>2</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>2</polymer-element>'
+          '</body></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>2</polymer-element></html>',
+    });
+
+  testPhases('shallow, elements, many', [[new ImportedElementInliner()]],
+    {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2.html">'
+          '<link rel="import" href="test3.html">'
+          '</head></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>2</polymer-element></html>',
+      'a|test3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>3</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>3</polymer-element>'
+          '</body></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>2</polymer-element></html>',
+      'a|test3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>3</polymer-element></html>',
+    });
+
+  testPhases('deep, elements, one per file', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2.html">'
+          '</head></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="assets/b/test3.html">'
+          '</head><body><polymer-element>2</polymer-element></html>',
+      'b|asset/test3.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="packages/c/test4.html">'
+          '</head><body><polymer-element>3</polymer-element></html>',
+      'c|lib/test4.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>4</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4</polymer-element>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+      'a|test2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4</polymer-element>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+      'b|asset/test3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4</polymer-element>'
+          '<polymer-element>3</polymer-element></body></html>',
+      'c|lib/test4.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>4</polymer-element></html>',
+    });
+
+  testPhases('deep, elements, many imports', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test2a.html">'
+          '<link rel="import" href="test2b.html">'
+          '</head></html>',
+      'a|test2a.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test3a.html">'
+          '<link rel="import" href="test3b.html">'
+          '</head><body><polymer-element>2a</polymer-element></body></html>',
+      'a|test2b.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test4a.html">'
+          '<link rel="import" href="test4b.html">'
+          '</head><body><polymer-element>2b</polymer-element></body></html>',
+      'a|test3a.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>3a</polymer-element></body></html>',
+      'a|test3b.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>3b</polymer-element></body></html>',
+      'a|test4a.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>4a</polymer-element></body></html>',
+      'a|test4b.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>4b</polymer-element></body></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3a</polymer-element>'
+          '<polymer-element>3b</polymer-element>'
+          '<polymer-element>2a</polymer-element>'
+          '<polymer-element>4a</polymer-element>'
+          '<polymer-element>4b</polymer-element>'
+          '<polymer-element>2b</polymer-element>'
+          '</body></html>',
+      'a|test2a.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3a</polymer-element>'
+          '<polymer-element>3b</polymer-element>'
+          '<polymer-element>2a</polymer-element>'
+          '</body></html>',
+      'a|test2b.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4a</polymer-element>'
+          '<polymer-element>4b</polymer-element>'
+          '<polymer-element>2b</polymer-element>'
+          '</body></html>',
+      'a|test3a.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3a</polymer-element>'
+          '</body></html>',
+      'a|test3b.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3b</polymer-element>'
+          '</body></html>',
+      'a|test4a.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4a</polymer-element>'
+          '</body></html>',
+      'a|test4b.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>4b</polymer-element>'
+          '</body></html>',
+    });
+
+  testPhases('imports cycle, 1-step lasso', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_2.html">'
+          '</head><body><polymer-element>1</polymer-element></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head><body><polymer-element>2</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>1</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+    });
+
+  testPhases('imports cycle, 2-step lasso', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_2.html">'
+          '</head><body><polymer-element>1</polymer-element></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_3.html">'
+          '</head><body><polymer-element>2</polymer-element></html>',
+      'a|test_3.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head><body><polymer-element>3</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>1</polymer-element>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+      'a|test_3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>2</polymer-element>'
+          '<polymer-element>1</polymer-element>'
+          '<polymer-element>3</polymer-element></body></html>',
+    });
+
+  testPhases('imports cycle, self cycle', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '</head><body><polymer-element>1</polymer-element></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>1</polymer-element></body></html>',
+    });
+
+  testPhases('imports DAG', [[new ImportedElementInliner()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_1.html">'
+          '<link rel="import" href="test_2.html">'
+          '</head></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_3.html">'
+          '</head><body><polymer-element>1</polymer-element></body></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '<link rel="import" href="test_3.html">'
+          '</head><body><polymer-element>2</polymer-element></body></html>',
+      'a|test_3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body><polymer-element>3</polymer-element></body></html>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>1</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+      'a|test_1.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>1</polymer-element></body></html>',
+      'a|test_2.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element>'
+          '<polymer-element>2</polymer-element></body></html>',
+      'a|test_3.html':
+          '<!DOCTYPE html><html><head>'
+          '</head><body>'
+          '<polymer-element>3</polymer-element></body></html>',
+    });
+}
diff --git a/pkg/polymer/test/transform/script_compactor_test.dart b/pkg/polymer/test/transform/script_compactor_test.dart
new file mode 100644
index 0000000..b271e3c
--- /dev/null
+++ b/pkg/polymer/test/transform/script_compactor_test.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.transform.script_compactor_test;
+
+import 'package:polymer/src/transform/script_compactor.dart';
+import 'package:unittest/compact_vm_config.dart';
+
+import 'common.dart';
+
+void main() {
+  useCompactVMConfiguration();
+
+  testPhases('no changes', [[new ScriptCompactor()]], {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    }, {
+      'a|test.html': '<!DOCTYPE html><html></html>',
+    });
+
+  testPhases('single script', [[new ScriptCompactor()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="a.dart"></script>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head></head><body>'
+          '<script type="application/dart" '
+          'src="test.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+
+      'a|test.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'a.dart' as i0;
+
+          void main() {
+            initPolymer([
+                'a.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+    });
+
+  testPhases('several scripts', [[new ScriptCompactor()]], {
+      'a|test.html':
+          '<!DOCTYPE html><html><head>'
+          '<script type="application/dart" src="a.dart"></script>'
+          '<script type="application/dart" src="b.dart"></script>'
+          '</head><body><div>'
+          '<script type="application/dart" src="c.dart"></script>'
+          '</div>'
+          '<script type="application/dart" src="d.dart"></script>',
+    }, {
+      'a|test.html':
+          '<!DOCTYPE html><html><head></head><body><div></div>'
+          '<script type="application/dart" '
+          'src="test.html_bootstrap.dart"></script>'
+          '<script type="text/javascript" '
+          'src="packages/browser/dart.js"></script>'
+          '</body></html>',
+
+      'a|test.html_bootstrap.dart':
+          '''library app_bootstrap;
+
+          import 'package:polymer/polymer.dart';
+          import 'dart:mirrors' show currentMirrorSystem;
+
+          import 'a.dart' as i0;
+          import 'b.dart' as i1;
+          import 'c.dart' as i2;
+          import 'd.dart' as i3;
+
+          void main() {
+            initPolymer([
+                'a.dart',
+                'b.dart',
+                'c.dart',
+                'd.dart',
+              ], currentMirrorSystem().isolate.rootLibrary.uri.toString());
+          }
+          '''.replaceAll('\n          ', '\n'),
+    });
+}
diff --git a/pkg/unittest/lib/html_config.dart b/pkg/unittest/lib/html_config.dart
index 2dde44b..b86b3fc 100644
--- a/pkg/unittest/lib/html_config.dart
+++ b/pkg/unittest/lib/html_config.dart
@@ -132,6 +132,11 @@
   }
 
   void onInit() {
+    // For Dart internal tests, we want to turn off stack frame
+    // filtering, which we do with this meta-header.
+    var meta = query('meta[name="dart.unittest"]');
+    filterStacks = meta == null ? true :
+       !meta.content.contains('full-stack-traces');
     _installHandlers();
     window.postMessage('unittest-suite-wait-for-done', '*');
   }
diff --git a/pkg/unittest/lib/src/simple_configuration.dart b/pkg/unittest/lib/src/simple_configuration.dart
index d4a0f6e..1056ad3 100644
--- a/pkg/unittest/lib/src/simple_configuration.dart
+++ b/pkg/unittest/lib/src/simple_configuration.dart
@@ -50,7 +50,7 @@
 
   // If stopTestOnExpectFailure is false, we need to capture failures, which
   // we do with this List.
-  final _testLogBuffer = <Pair<String, Trace>>[];
+  final _testLogBuffer = <Pair<String, StackTrace>>[];
 
   /**
    * The constructor sets up a failure handler for [expect] that redirects
@@ -61,6 +61,10 @@
   }
 
   void onInit() {
+    // For Dart internal tests, we don't want stack frame filtering.
+    // We turn it off here in the default config, but by default turn
+    // it back on in the vm and html configs.
+    filterStacks = false;
     _receivePort = new ReceivePort();
     _postMessage('unittest-suite-wait-for-done');
   }
@@ -135,8 +139,9 @@
       try {
         throw '';
       } catch (_, stack) {
-        _testLogBuffer.add(
-            new Pair<String, Trace>(reason, new Trace.from(stack)));
+        var trace = _getTrace(stack);
+        if (trace == null) trace = stack;
+        _testLogBuffer.add(new Pair<String, StackTrace>(reason, trace));
       }
     }
   }
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index d965082..c37b8a5 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -41,9 +41,9 @@
    */
   String get result => _result;
 
-  Trace _stackTrace;
+  StackTrace _stackTrace;
   /** Stack trace associated with this test, or [null] if it succeeded. */
-  Trace get stackTrace => _stackTrace;
+  StackTrace get stackTrace => _stackTrace;
 
   /** The group (or groups) under which this test is running. */
   final String currentGroup;
@@ -130,9 +130,10 @@
 
   // Set the results, notify the config, and return true if this
   // is the first time the result is being set.
-  void _setResult(String testResult, String messageText, stack) {
+  void _setResult(String testResult, String messageText, StackTrace stack) {
     _message = messageText;
     _stackTrace = _getTrace(stack);
+    if (_stackTrace == null) _stackTrace = stack;
     if (result == null) {
       _result = testResult;
       _config.onTestResult(this);
@@ -142,7 +143,8 @@
     }
   }
 
-  void _complete(String testResult, [String messageText = '', stack]) {
+  void _complete(String testResult, [String messageText = '',
+      StackTrace stack]) {
     if (runningTime == null) {
       // The startTime can be `null` if an error happened during setup. In this
       // case we simply report a running time of 0.
@@ -164,7 +166,7 @@
     _complete(PASS);
   }
 
-  void fail(String messageText, [stack]) {
+  void fail(String messageText, [StackTrace stack]) {
     if (result != null) {
       String newMessage = (result == PASS)
           ? 'Test failed after initially passing: $messageText'
@@ -176,7 +178,7 @@
     }
   }
 
-  void error(String messageText, [stack]) {
+  void error(String messageText, [StackTrace stack]) {
     _complete(ERROR, messageText, stack);
   }
 
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index eb186bd..f6e83c2 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -852,10 +852,19 @@
  */
 bool formatStacks = true;
 
-/** Returns a Trace object from a StackTrace object or a String. */
+/**
+ * A flag that controls whether we try to filter out irrelevant frames from 
+ * the stack trace. Requires formatStacks to be set.
+ */
+bool filterStacks = true;
+
+/**
+ * Returns a Trace object from a StackTrace object or a String, or the 
+ * unchanged input if formatStacks is false;
+ */
 Trace _getTrace(stack) {
   Trace trace;
-  if (stack == null) return null;
+  if (stack == null || !formatStacks) return null;
   if (stack is String) {
     trace = new Trace.parse(stack);
   } else if (stack is StackTrace) {
@@ -864,7 +873,7 @@
     throw new Exception('Invalid stack type ${stack.runtimeType} for $stack.');
   }
 
-  if (!formatStacks) return trace;
+  if (!filterStacks) return trace;
 
   // Format the stack trace by removing everything above TestCase._runTest,
   // which is usually going to be irrelevant. Also fold together unittest and
diff --git a/pkg/unittest/lib/vm_config.dart b/pkg/unittest/lib/vm_config.dart
index 0133186..962ca97 100644
--- a/pkg/unittest/lib/vm_config.dart
+++ b/pkg/unittest/lib/vm_config.dart
@@ -38,6 +38,11 @@
     return result;
   }
 
+  void onInit() {
+    super.onInit();
+    filterStacks = formatStacks = true;
+  }
+
   void onDone(bool success) {
     int status;
     try {
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index a07cf3d..c25a2fa 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -16,12 +16,6 @@
 static const intptr_t kTimerId = -1;
 static const intptr_t kInvalidId = -2;
 
-static EventHandler* event_handler = NULL;
-// TODO(ajohnsen): Consider removing mutex_ if we can enforce an invariant
-//    that eventhandler is kept alive untill all isolates are closed.
-static dart::Mutex* mutex_ = new dart::Mutex();
-
-
 void TimeoutQueue::UpdateTimeout(Dart_Port port, int64_t timeout) {
   // Find port if present.
   Timeout* last = NULL;
@@ -63,51 +57,40 @@
 }
 
 
+static EventHandler* event_handler = NULL;
+
+
+void EventHandler::Start() {
+  ASSERT(event_handler == NULL);
+  event_handler = new EventHandler();
+  event_handler->delegate_.Start(event_handler);
+}
+
+
 void EventHandler::Stop() {
-  MutexLocker locker(mutex_);
   if (event_handler == NULL) return;
-  event_handler->Shutdown();
+  event_handler->delegate_.Shutdown();
   event_handler = NULL;
 }
 
 
 /*
- * Starts the EventHandler thread and stores its reference in the dart
- * EventHandler object. args[0] holds the reference to the dart EventHandler
- * object.
- */
-void FUNCTION_NAME(EventHandler_Start)(Dart_NativeArguments args) {
-  MutexLocker locker(mutex_);
-  if (event_handler != NULL) return;
-  event_handler = EventHandler::Start();
-}
-
-
-/*
  * Send data to the EventHandler thread to register for a given instance
- * args[1] a ReceivePort args[2] with a notification event args[3]. args[0]
- * holds the reference to the dart EventHandler object.
+ * args[0] a ReceivePort args[1] with a notification event args[2].
  */
 void FUNCTION_NAME(EventHandler_SendData)(Dart_NativeArguments args) {
-  Dart_Handle sender = Dart_GetNativeArgument(args, 1);
+  Dart_Handle sender = Dart_GetNativeArgument(args, 0);
   intptr_t id = kInvalidId;
   if (Dart_IsNull(sender)) {
     id = kTimerId;
   } else {
     Socket::GetSocketIdNativeField(sender, &id);
   }
-  Dart_Handle handle = Dart_GetNativeArgument(args, 2);
+  Dart_Handle handle = Dart_GetNativeArgument(args, 1);
   Dart_Port dart_port =
       DartUtils::GetIntegerField(handle, DartUtils::kIdFieldName);
-  int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
-  {
-    MutexLocker locker(mutex_);
-    // Only send if the event_handler is not NULL. This means that the handler
-    // shut down, and a message is send later on.
-    if (event_handler != NULL) {
-      event_handler->SendData(id, dart_port, data);
-    }
-  }
+  int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
+  event_handler->SendData(id, dart_port, data);
 }
 
 }  // namespace bin
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 8a26043..a9b0bcd 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -108,16 +108,15 @@
     delegate_.SendData(id, dart_port, data);
   }
 
-  void Shutdown() {
-    delegate_.Shutdown();
-  }
+  /**
+   * Start the event-handler.
+   */
+  static void Start();
 
-  static EventHandler* Start() {
-    EventHandler* handler = new EventHandler();
-    handler->delegate_.Start(handler);
-    return handler;
-  }
-
+  /**
+   * Stop the event-handler. It's expected that there will be no further calls
+   * to SendData after a call to Stop.
+   */
   static void Stop();
 
  private:
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 90f94b4..975a6d1 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -160,6 +160,9 @@
   msg.id = id;
   msg.dart_port = dart_port;
   msg.data = data;
+  // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+  // is smaller than 512, we don't need a thread lock.
+  // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 6d15c9e..e95def6 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -165,6 +165,9 @@
   msg.id = id;
   msg.dart_port = dart_port;
   msg.data = data;
+  // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+  // is smaller than 512, we don't need a thread lock.
+  // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 419c93e..20c6b61 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -184,6 +184,9 @@
   msg.id = id;
   msg.dart_port = dart_port;
   msg.data = data;
+  // WriteToBlocking will write up to 512 bytes atomically, and since our msg
+  // is smaller than 512, we don't need a thread lock.
+  // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_patch.dart b/runtime/bin/eventhandler_patch.dart
index 46c1e3d..2038a57 100644
--- a/runtime/bin/eventhandler_patch.dart
+++ b/runtime/bin/eventhandler_patch.dart
@@ -5,28 +5,9 @@
 import 'dart:nativewrappers';
 
 patch class _EventHandler {
-  /* patch */ static void _start() {
-    if (_eventHandler == null) {
-      _eventHandler = new _EventHandlerImpl();
-      _eventHandler._start();
-    }
-  }
-
-  /* patch */ static _sendData(Object sender,
-                               ReceivePort receivePort,
-                               int data) {
-    if (_eventHandler != null) {
-      _eventHandler._sendData(sender, receivePort, data);
-    }
-  }
-
-  static _EventHandlerImpl _eventHandler;
-}
-
-
-class _EventHandlerImpl {
-  _EventHandlerImpl() { }
-  void _start() native "EventHandler_Start";
-  void _sendData(Object sender, ReceivePort receivePort, int data)
+  /* patch */ static void _sendData(Object sender,
+                                    ReceivePort receivePort,
+                                    int data)
       native "EventHandler_SendData";
 }
+
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 2948ce8..eb5b444 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -21,8 +21,7 @@
 // builtin_natives.cc instead.
 #define IO_NATIVE_LIST(V)                                                      \
   V(Crypto_GetRandomBytes, 1)                                                  \
-  V(EventHandler_Start, 1)                                                     \
-  V(EventHandler_SendData, 4)                                                  \
+  V(EventHandler_SendData, 3)                                                  \
   V(Filter_CreateZLibDeflate, 3)                                               \
   V(Filter_CreateZLibInflate, 1)                                               \
   V(Filter_End, 1)                                                             \
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 7e5138e..0e813eb 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -744,6 +744,9 @@
     }
   }
 
+  // Start event handler.
+  EventHandler::Start();
+
   // Start the VM service isolate, if necessary.
   if (start_vm_service) {
     ASSERT(vm_service_server_port >= 0);
@@ -860,7 +863,6 @@
   Dart_ShutdownIsolate();
   // Terminate process exit-code handler.
   Process::TerminateExitCodeHandler();
-  EventHandler::Stop();
 
   // Free copied argument strings if converted.
   if (argv_converted) {
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 55f9224e..512cdbe 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -358,17 +358,14 @@
 
   _NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET {
     eventHandlers = new List(EVENT_COUNT + 1);
-    _EventHandler._start();
   }
 
   _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET {
     eventHandlers = new List(EVENT_COUNT + 1);
-    _EventHandler._start();
   }
 
   _NativeSocket.pipe() : typeFlags = TYPE_PIPE {
     eventHandlers = new List(EVENT_COUNT + 1);
-    _EventHandler._start();
   }
 
   int available() {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4f35fab..80fc69b 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -1410,12 +1410,6 @@
                                                 intptr_t length);
 
 /**
- * Retrieves the peer pointer associated with an external String.
- */
-DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
-                                                   void** peer);
-
-/**
  * Returns a String which references an external array of
  * Latin-1 (ISO-8859-1) encoded characters.
  *
@@ -1536,8 +1530,9 @@
  * \return the converted ExternalString object if no error occurs.
  *   Otherwise returns an error handle.
  *   If the object is a valid string but if it cannot be externalized
- *   then Dart_Null() is returned and the string data is copied into
- *   the external space specified.
+ *   the string data is copied into the external space specified
+ *   and the passed in peer is setup as a peer for this string object.
+ *   In this case the function returns the original String object as is.
  *
  * For example:
  *  intptr_t size;
@@ -1562,7 +1557,8 @@
  * \param str A String.
  * \param char_size Returns the character size of the String.
  * \param str_len Returns the length of the String.
- * \param peer Returns the peer pointer if the String is an external String.
+ * \param peer Returns the peer pointer associated with the String or 0 if
+ *   there is no peer pointer for it.
  * \return Success if no error occurs. Otherwise returns
  *   an error handle.
  */
@@ -2001,9 +1997,10 @@
  * Gets a string native argument at some index.
  * \param args Native arguments structure.
  * \param arg_index Index of the desired argument in the structure above.
- * \param peer Returns the peer pointer if the String is an external String.
- * \return the String object if no error occurs. Otherwise returns
- *   an error handle.
+ * \param peer Returns the peer pointer if the string argument has one.
+ * \return Success if the string argument has a peer, if it does not
+ *   have a peer then the String object is returned. Otherwise returns
+ *   an error handle (argument is not a String object).
  */
 DART_EXPORT Dart_Handle Dart_GetNativeStringArgument(Dart_NativeArguments args,
                                                      int arg_index,
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index e0c8b23..ed78b7b 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -187,6 +187,8 @@
 static RawInstance* CreateClassMirror(const Class& cls,
                                       const AbstractType& type,
                                       const Instance& owner_mirror) {
+  ASSERT(!cls.IsDynamicClass() && !cls.IsVoidClass());
+
   if (cls.IsSignatureClass()) {
     if (cls.IsCanonicalSignatureClass()) {
       // We represent function types as canonical signature classes.
@@ -305,6 +307,12 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
   const Class& cls = Class::Handle(type.type_class());
   ASSERT(!cls.IsNull());
+  if (cls.IsDynamicClass() || cls.IsVoidClass()) {
+    const Array& args = Array::Handle(Array::New(1));
+    args.SetAt(0, type);
+    Exceptions::ThrowByType(Exceptions::kArgument, args);
+    UNREACHABLE();
+  }
   // Strip the type for generics only.
   if (cls.NumTypeParameters() == 0) {
     return CreateClassMirror(cls,
@@ -561,15 +569,15 @@
     entry = entries.GetNext();
     if (entry.IsClass()) {
       const Class& klass = Class::Cast(entry);
-      if (!klass.IsCanonicalSignatureClass()) {
-        // The various implementations of public classes don't always have the
-        // expected superinterfaces or other properties, so we filter them out.
-        if (!RawObject::IsImplementationClassId(klass.id())) {
-          member_mirror = CreateClassMirror(klass,
-                                            AbstractType::Handle(),
-                                            owner_mirror);
-          member_mirrors.Add(member_mirror);
-        }
+      // We filter out implementation classes like Smi, Mint, Bignum,
+      // OneByteString; function signature classes; and dynamic.
+      if (!klass.IsCanonicalSignatureClass() &&
+          !klass.IsDynamicClass() &&
+          !RawObject::IsImplementationClassId(klass.id())) {
+        member_mirror = CreateClassMirror(klass,
+                                          AbstractType::Handle(),
+                                          owner_mirror);
+        member_mirrors.Add(member_mirror);
       }
     } else if (entry.IsField()) {
       const Field& field = Field::Cast(entry);
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 2ca11fe..4cb8158 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -198,6 +198,8 @@
   // Create strings.
   uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
   int external_peer_data = 123;
+  intptr_t char_size;
+  intptr_t str_len;
   Dart_Handle external_string = Dart_NewExternalLatin1String(
       data8, ARRAY_SIZE(data8), &external_peer_data, NULL);
   Dart_Handle internal_string = NewString("two");
@@ -209,7 +211,12 @@
     EXPECT_VALID(external_string);
     EXPECT(Dart_IsExternalString(external_string));
     void* external_peer = NULL;
-    EXPECT_VALID(Dart_ExternalStringGetPeer(external_string, &external_peer));
+    EXPECT_VALID(Dart_StringGetProperties(external_string,
+                                          &char_size,
+                                          &str_len,
+                                          &external_peer));
+    EXPECT_EQ(1, char_size);
+    EXPECT_EQ(4, str_len);
     EXPECT_EQ(&external_peer_data, external_peer);
   }
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 4c082e8..b55b5b2 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -240,44 +240,33 @@
 }
 
 
-#define GET_PEER(type, ctype, raw_obj, peer)                                   \
-
-
-#define EXTERNAL_PEER_HELPER(cid, raw_obj, peer)                               \
-  switch (cid) {                                                               \
-    case kExternalOneByteStringCid: {                                          \
-      RawExternalOneByteString* raw_string =                                   \
-          reinterpret_cast<RawExternalOneByteString*>(raw_obj)->ptr();         \
-      ExternalStringData<uint8_t>* data = raw_string->external_data_;          \
-      *peer = data->peer();                                                    \
-      return true;                                                             \
-    }                                                                          \
-    case kExternalTwoByteStringCid: {                                          \
-      RawExternalTwoByteString* raw_string =                                   \
-          reinterpret_cast<RawExternalTwoByteString*>(raw_obj)->ptr();         \
-      ExternalStringData<uint16_t>* data = raw_string->external_data_;         \
-      *peer = data->peer();                                                    \
-      return true;                                                             \
-    }                                                                          \
-  }                                                                            \
-  return false;                                                                \
-
-
-bool Api::ExternalStringGetPeerHelper(Dart_NativeArguments args,
-                                      int arg_index,
-                                      void** peer) {
+bool Api::StringGetPeerHelper(Dart_NativeArguments args,
+                              int arg_index,
+                              void** peer) {
   NoGCScope no_gc_scope;
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
   RawObject* raw_obj = arguments->NativeArgAt(arg_index);
   intptr_t cid = raw_obj->GetClassId();
-  EXTERNAL_PEER_HELPER(cid, raw_obj, peer);
-}
-
-
-bool Api::ExternalStringGetPeerHelper(Dart_Handle object, void** peer) {
-  NoGCScope no_gc_scope;
-  RawObject* raw_obj = Api::UnwrapHandle(object);
-  EXTERNAL_PEER_HELPER(Api::ClassId(object), raw_obj, peer);
+  if (cid == kExternalOneByteStringCid) {
+    RawExternalOneByteString* raw_string =
+        reinterpret_cast<RawExternalOneByteString*>(raw_obj)->ptr();
+    ExternalStringData<uint8_t>* data = raw_string->external_data_;
+    *peer = data->peer();
+    return true;
+  }
+  if (cid == kOneByteStringCid || cid == kTwoByteStringCid) {
+    Isolate* isolate = arguments->isolate();
+    *peer = isolate->heap()->GetPeer(raw_obj);
+    return (*peer != 0);
+  }
+  if (cid == kExternalTwoByteStringCid) {
+    RawExternalTwoByteString* raw_string =
+        reinterpret_cast<RawExternalTwoByteString*>(raw_obj)->ptr();
+    ExternalStringData<uint16_t>* data = raw_string->external_data_;
+    *peer = data->peer();
+    return true;
+  }
+  return false;
 }
 
 
@@ -1647,28 +1636,6 @@
 }
 
 
-DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object,
-                                                   void** peer) {
-  if (peer == NULL) {
-    RETURN_NULL_ERROR(peer);
-  }
-
-  if (Api::ExternalStringGetPeerHelper(object, peer)) {
-    return Api::Success();
-  }
-
-  // It's not an external string, return appropriate error.
-  if (!RawObject::IsStringClassId(Api::ClassId(object))) {
-    RETURN_TYPE_ERROR(Isolate::Current(), object, String);
-  } else {
-    return
-        Api::NewError(
-            "%s expects argument 'object' to be an external String.",
-            CURRENT_FUNC);
-  }
-}
-
-
 DART_EXPORT Dart_Handle Dart_NewExternalLatin1String(
     const uint8_t* latin1_array,
     intptr_t length,
@@ -1842,9 +1809,9 @@
   if (str_obj.InVMHeap()) {
     // Since the string object is read only we do not externalize
     // the string but instead copy the contents of the string into the
-    // specified buffer and return a Null object.
-    // This ensures that the embedder does not have to call again
-    // to get at the contents.
+    // specified buffer add the specified peer/cback as a Peer object
+    // to this string. The Api::StringGetPeerHelper function picks up
+    // the peer from the Peer table.
     intptr_t copy_len = str_obj.Length();
     if (str_obj.IsOneByteString()) {
       ASSERT(length >= copy_len);
@@ -1852,6 +1819,7 @@
       for (intptr_t i = 0; i < copy_len; i++) {
         latin1_array[i] = static_cast<uint8_t>(str_obj.CharAt(i));
       }
+      OneByteString::SetPeer(str_obj, peer, cback);
     } else {
       ASSERT(str_obj.IsTwoByteString());
       ASSERT(length >= (copy_len * str_obj.CharSize()));
@@ -1859,8 +1827,9 @@
       for (intptr_t i = 0; i < copy_len; i++) {
         utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i));
       }
+      TwoByteString::SetPeer(str_obj, peer, cback);
     }
-    return Api::Null();
+    return str;
   }
   return Api::NewHandle(isolate,
                         str_obj.MakeExternal(array, length, peer, cback));
@@ -1881,7 +1850,8 @@
     *peer = str.GetPeer();
     ASSERT(*peer != NULL);
   } else {
-    *peer = NULL;
+    NoGCScope no_gc_scope;
+    *peer = isolate->heap()->GetPeer(str.raw());
   }
   *char_size = str.CharSize();
   *str_len = str.Length();
@@ -3704,7 +3674,7 @@
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
   Isolate* isolate = arguments->isolate();
   CHECK_ISOLATE(isolate);
-  if (Api::ExternalStringGetPeerHelper(args, arg_index, peer)) {
+  if (Api::StringGetPeerHelper(args, arg_index, peer)) {
     return Api::Success();
   }
   *peer = NULL;
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 322a265..6c05c98 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -191,10 +191,9 @@
   static void InitHandles();
 
   // Helper function to get the peer value of an external string object.
-  static bool ExternalStringGetPeerHelper(Dart_NativeArguments args,
-                                          int arg_index,
-                                          void** peer);
-  static bool ExternalStringGetPeerHelper(Dart_Handle object, void** peer);
+  static bool StringGetPeerHelper(Dart_NativeArguments args,
+                                  int arg_index,
+                                  void** peer);
 
   // Helper function to set the return value of native functions.
   static void SetReturnValue(NativeArguments* args, Dart_Handle retval) {
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index f92f29c..a9def3f 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -643,49 +643,6 @@
 }
 
 
-TEST_CASE(ExternalStringGetPeer) {
-  Dart_Handle result;
-
-  uint8_t data8[] = { 'o', 'n', 'e', 0xFF };
-  int peer_data = 123;
-  void* peer = NULL;
-
-  // Success.
-  Dart_Handle ext8 = Dart_NewExternalLatin1String(data8, ARRAY_SIZE(data8),
-                                                  &peer_data, NULL);
-  EXPECT_VALID(ext8);
-
-  result = Dart_ExternalStringGetPeer(ext8, &peer);
-  EXPECT_VALID(result);
-  EXPECT_EQ(&peer_data, peer);
-
-  // NULL peer.
-  result = Dart_ExternalStringGetPeer(ext8, NULL);
-  EXPECT(Dart_IsError(result));
-  EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'peer' to be "
-               "non-null.", Dart_GetError(result));
-
-  // String is not external.
-  peer = NULL;
-  uint8_t utf8_data8[] = { 'o', 'n', 'e', 0x7F };
-  Dart_Handle str8 = Dart_NewStringFromUTF8(utf8_data8, ARRAY_SIZE(data8));
-  EXPECT_VALID(str8);
-  result = Dart_ExternalStringGetPeer(str8, &peer);
-  EXPECT(Dart_IsError(result));
-  EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
-               "an external String.", Dart_GetError(result));
-  EXPECT(peer == NULL);
-
-  // Not a String.
-  peer = NULL;
-  result = Dart_ExternalStringGetPeer(Dart_True(), &peer);
-  EXPECT(Dart_IsError(result));
-  EXPECT_STREQ("Dart_ExternalStringGetPeer expects argument 'object' to be "
-               "of type String.", Dart_GetError(result));
-  EXPECT(peer == NULL);
-}
-
-
 static void ExternalStringCallbackFinalizer(void* peer) {
   *static_cast<int*>(peer) *= 2;
 }
@@ -705,9 +662,6 @@
         &peer8,
         ExternalStringCallbackFinalizer);
     EXPECT_VALID(obj8);
-    void* api_peer8 = NULL;
-    EXPECT_VALID(Dart_ExternalStringGetPeer(obj8, &api_peer8));
-    EXPECT_EQ(api_peer8, &peer8);
 
     uint16_t data16[] = { 'h', 'e', 'l', 'l', 'o' };
     Dart_Handle obj16 = Dart_NewExternalUTF16String(
@@ -716,9 +670,6 @@
         &peer16,
         ExternalStringCallbackFinalizer);
     EXPECT_VALID(obj16);
-    void* api_peer16 = NULL;
-    EXPECT_VALID(Dart_ExternalStringGetPeer(obj16, &api_peer16));
-    EXPECT_EQ(api_peer16, &peer16);
 
     Dart_ExitScope();
   }
@@ -6940,6 +6891,7 @@
 TEST_CASE(MakeExternalString) {
   int peer8 = 40;
   int peer16 = 41;
+  int canonical_str_peer = 42;
   intptr_t length = 0;
   intptr_t expected_length = 0;
   {
@@ -7001,6 +6953,29 @@
     EXPECT_VALID(Dart_StringLength(str, &length));
     EXPECT_EQ(0, length);
 
+    // Test with single character canonical string, it should not become
+    // external string but the peer should be setup for it.
+    Isolate* isolate = Isolate::Current();
+    Dart_Handle canonical_str = Api::NewHandle(isolate, Symbols::New("*"));
+    EXPECT(Dart_IsString(canonical_str));
+    EXPECT(!Dart_IsExternalString(canonical_str));
+    uint8_t ext_canonical_str[kLength];
+    str = Dart_MakeExternalString(canonical_str,
+                                  ext_canonical_str,
+                                  kLength,
+                                  &canonical_str_peer,
+                                  MakeExternalCback);
+    EXPECT(Dart_IsString(str));
+    EXPECT(!Dart_IsExternalString(canonical_str));
+    EXPECT_EQ(canonical_str, str);
+    EXPECT(Dart_IsString(canonical_str));
+    EXPECT(!Dart_IsExternalString(canonical_str));
+    void* peer;
+    EXPECT_VALID(Dart_StringGetProperties(str, &size, &length, &peer));
+    EXPECT_EQ(1, size);
+    EXPECT_EQ(1, length);
+    EXPECT_EQ(reinterpret_cast<void*>(&canonical_str_peer), peer);
+
     // Test with a one byte ascii string.
     const char* ascii = "string";
     expected_length = strlen(ascii);
@@ -7071,9 +7046,11 @@
   }
   EXPECT_EQ(40, peer8);
   EXPECT_EQ(41, peer16);
+  EXPECT_EQ(42, canonical_str_peer);
   Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
   EXPECT_EQ(80, peer8);
   EXPECT_EQ(82, peer16);
+  EXPECT_EQ(42, canonical_str_peer);  // "*" Symbol is not removed on GC.
 }
 
 
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 8affac2..ba9a4d9 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -408,31 +408,21 @@
         deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
     ASSERT(from != kTagged);
     ASSERT(to != kTagged);
-    Value* to_value = NULL;
+    Definition* boxed = NULL;
     if (from == kUnboxedDouble) {
-      BoxDoubleInstr* boxed = new BoxDoubleInstr(use->CopyWithType());
-      use->BindTo(boxed);
-      InsertBefore(insert_before, boxed, NULL, Definition::kValue);
-      to_value = new Value(boxed);
+      boxed = new BoxDoubleInstr(use->CopyWithType());
     } else if (from == kUnboxedUint32x4) {
-      BoxUint32x4Instr* boxed = new BoxUint32x4Instr(use->CopyWithType());
-      use->BindTo(boxed);
-      InsertBefore(insert_before, boxed, NULL, Definition::kValue);
-      to_value = new Value(boxed);
+      boxed = new BoxUint32x4Instr(use->CopyWithType());
     } else if (from == kUnboxedFloat32x4) {
-      BoxFloat32x4Instr* boxed = new BoxFloat32x4Instr(use->CopyWithType());
-      use->BindTo(boxed);
-      InsertBefore(insert_before, boxed, NULL, Definition::kValue);
-      to_value = new Value(boxed);
+      boxed = new BoxFloat32x4Instr(use->CopyWithType());
     } else if (from == kUnboxedMint) {
-      BoxIntegerInstr* boxed = new BoxIntegerInstr(use->CopyWithType());
-      use->BindTo(boxed);
-      InsertBefore(insert_before, boxed, NULL, Definition::kValue);
-      to_value = new Value(boxed);
+      boxed = new BoxIntegerInstr(use->CopyWithType());
     } else {
       UNIMPLEMENTED();
     }
-    ASSERT(to_value != NULL);
+    use->BindTo(boxed);
+    InsertBefore(insert_before, boxed, NULL, Definition::kValue);
+    Value* to_value = new Value(boxed);
     if (to == kUnboxedDouble) {
       converted = new UnboxDoubleInstr(to_value, deopt_id);
     } else if (to == kUnboxedUint32x4) {
@@ -6979,6 +6969,7 @@
                                  right,
                                  Object::null_array());
     new_equality_compare->set_ic_data(equality_compare->ic_data());
+    new_equality_compare->set_operation_cid(equality_compare->operation_cid());
     new_comparison = new_equality_compare;
   } else {
     ASSERT(comparison->IsRelationalOp());
@@ -6990,6 +6981,7 @@
                               right,
                               Object::null_array());
     new_relational_op->set_ic_data(relational_op->ic_data());
+    new_relational_op->set_operation_cid(relational_op->operation_cid());
     new_comparison = new_relational_op;
   }
   return new BranchInstr(new_comparison, branch->is_checked());
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 88ebbab..830ade1 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -3818,10 +3818,10 @@
       break;
     }
     case Token::kADD:
-      UNIMPLEMENTED();
+      __ vaddqi(kWord, result, left, right);
       break;
     case Token::kSUB:
-      UNIMPLEMENTED();
+      __ vsubqi(kWord, result, left, right);
       break;
     default: UNREACHABLE();
   }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index af1c5e6..6fcb9fa 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13427,6 +13427,24 @@
 }
 
 
+void OneByteString::SetPeer(const String& str,
+                            void* peer,
+                            Dart_PeerFinalizer cback) {
+  ASSERT(!str.IsNull() && str.IsOneByteString());
+  ASSERT(peer != NULL);
+  ExternalStringData<uint8_t>* ext_data =
+      new ExternalStringData<uint8_t>(NULL, peer, cback);
+  AddFinalizer(str, ext_data, OneByteString::Finalize);
+  Isolate::Current()->heap()->SetPeer(str.raw(), peer);
+}
+
+
+void OneByteString::Finalize(Dart_WeakPersistentHandle handle, void* peer) {
+  delete reinterpret_cast<ExternalStringData<uint8_t>*>(peer);
+  DeleteWeakPersistentHandle(handle);
+}
+
+
 RawTwoByteString* TwoByteString::EscapeSpecialCharacters(const String& str) {
   intptr_t len = str.Length();
   if (len > 0) {
@@ -13579,6 +13597,24 @@
 }
 
 
+void TwoByteString::SetPeer(const String& str,
+                            void* peer,
+                            Dart_PeerFinalizer cback) {
+  ASSERT(!str.IsNull() && str.IsTwoByteString());
+  ASSERT(peer != NULL);
+  ExternalStringData<uint16_t>* ext_data =
+      new ExternalStringData<uint16_t>(NULL, peer, cback);
+  AddFinalizer(str, ext_data, TwoByteString::Finalize);
+  Isolate::Current()->heap()->SetPeer(str.raw(), peer);
+}
+
+
+void TwoByteString::Finalize(Dart_WeakPersistentHandle handle, void* peer) {
+  delete reinterpret_cast<ExternalStringData<uint16_t>*>(peer);
+  DeleteWeakPersistentHandle(handle);
+}
+
+
 RawExternalOneByteString* ExternalOneByteString::New(
     const uint8_t* data,
     intptr_t len,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 20c508b..d591d4e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4608,7 +4608,6 @@
                           void* peer,
                           Dart_PeerFinalizer cback) const;
 
-
   // Creates a new String object from a C string that is assumed to contain
   // UTF-8 encoded characters and '\0' is considered a termination character.
   // TODO(7123) - Rename this to FromCString(....).
@@ -4808,6 +4807,12 @@
                                               intptr_t length,
                                               Heap::Space space);
 
+  static void SetPeer(const String& str,
+                      void* peer,
+                      Dart_PeerFinalizer cback);
+
+  static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
+
   static const ClassId kClassId = kOneByteStringCid;
 
   static RawOneByteString* null() {
@@ -4890,6 +4895,12 @@
                                      const String& str,
                                      Heap::Space space);
 
+  static void SetPeer(const String& str,
+                      void* peer,
+                      Dart_PeerFinalizer cback);
+
+  static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
+
   static RawTwoByteString* null() {
     return reinterpret_cast<RawTwoByteString*>(Object::null());
   }
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 1e96917..36e3deb 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -9287,10 +9287,11 @@
     ASSERT(key->IsLiteralNode());
     const Instance& new_key = key->AsLiteralNode()->literal();
     for (int i = 0; i < pairs->length(); i += 2) {
-      const Instance& key_i =
-          (*pairs)[i]->AsLiteralNode()->literal();
-      ASSERT(key_i.IsString());
-      if (new_key.Equals(key_i)) {
+      const Instance& key_i = (*pairs)[i]->AsLiteralNode()->literal();
+      // The keys of a compile time constant map are compile time
+      // constants, i.e. canonicalized values. Thus, we can compare
+      // raw pointers to check for equality.
+      if (new_key.raw() == key_i.raw()) {
         // Duplicate key found. The new value replaces the previously
         // defined value.
         (*pairs)[i + 1] = value;
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 4216317..80725b8 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -33,13 +33,9 @@
 }
 
 patch class _EventHandler {
-  patch static void _start() {
-    throw new UnsupportedError("EventHandler._start");
-  }
-
-  patch static _sendData(Object sender,
-                         ReceivePort receivePort,
-                         int data) {
+  patch static void _sendData(Object sender,
+                              ReceivePort receivePort,
+                              int data) {
     throw new UnsupportedError("EventHandler._sendData");
   }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index ad891dc..6393428 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -226,7 +226,8 @@
         var subdirectory = path.join(packageDir, name);
         var watcher = new DirectoryWatcher(subdirectory);
         watcher.events.listen((event) {
-          var id = pathToAssetId(package, packageDir, event.path);
+          var id = new AssetId(package,
+              path.relative(event.path, from: packageDir));
           if (event.type == ChangeType.REMOVE) {
             _barback.removeSources([id]);
           } else {
@@ -256,7 +257,8 @@
         // Skip directories.
         if (!fileExists(entry)) continue;
 
-        files.add(pathToAssetId(package, packageDir, entry));
+        var id = new AssetId(package, path.relative(entry, from: packageDir));
+        files.add(id);
       }
     }
 
@@ -270,14 +272,4 @@
     if (package == entrypoint.root.name) directories.add("web");
     return directories;
   }
-
-  /// Converts a local file path to an [AssetId].
-  AssetId pathToAssetId(String package, String packageDir, String filePath) {
-    var relative = path.relative(filePath, from: packageDir);
-
-    // AssetId paths use "/" on all platforms.
-    relative = path.toUri(relative).path;
-
-    return new AssetId(package, relative);
-  }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart
index 6da96ba..56b012b 100644
--- a/sdk/lib/_internal/pub/lib/src/pubspec.dart
+++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -121,7 +121,6 @@
 
 Pubspec _parseMap(String filePath, Map map, SourceRegistry sources) {
   var name = null;
-  var version = Version.none;
 
   if (map.containsKey('name')) {
     name = map['name'];
@@ -131,14 +130,14 @@
     }
   }
 
-  if (map.containsKey('version')) {
-    version = new Version.parse(map['version']);
-  }
+  var version = _parseVersion(map['version'], (v) =>
+      'The pubspec "version" field should be a semantic version number, '
+      'but was "$v".');
 
-  var dependencies = _parseDependencies(filePath, sources,
+  var dependencies = _parseDependencies(name, filePath, sources,
       map['dependencies']);
 
-  var devDependencies = _parseDependencies(filePath, sources,
+  var devDependencies = _parseDependencies(name, filePath, sources,
       map['dev_dependencies']);
 
   // Make sure the same package doesn't appear as both a regular and dev
@@ -183,14 +182,9 @@
           '"$environmentYaml".');
     }
 
-    var sdkYaml = environmentYaml['sdk'];
-    if (sdkYaml is! String) {
-      throw new FormatException(
-          'The "sdk" field of "environment" should be a string, but was '
-          '"$sdkYaml".');
-    }
-
-    sdkConstraint = new VersionConstraint.parse(sdkYaml);
+    sdkConstraint = _parseVersionConstraint(environmentYaml['sdk'], (v) =>
+        'The "sdk" field of "environment" should be a semantic version '
+        'constraint, but was "$v".');
   }
   var environment = new PubspecEnvironment(sdkConstraint);
 
@@ -241,8 +235,38 @@
       environment, map);
 }
 
-List<PackageDep> _parseDependencies(String pubspecPath, SourceRegistry sources,
-    yaml) {
+/// Parses [yaml] to a [Version] or throws a [FormatException] with the result
+/// of calling [message] if it isn't valid.
+///
+/// If [yaml] is `null`, returns [Version.none].
+Version _parseVersion(yaml, String message(yaml)) {
+  if (yaml == null) return Version.none;
+  if (yaml is! String) throw new FormatException(message(yaml));
+
+  try {
+    return new Version.parse(yaml);
+  } on FormatException catch(_) {
+    throw new FormatException(message(yaml));
+  }
+}
+
+/// Parses [yaml] to a [VersionConstraint] or throws a [FormatException] with
+/// the result of calling [message] if it isn't valid.
+///
+/// If [yaml] is `null`, returns [VersionConstraint.any].
+VersionConstraint _parseVersionConstraint(yaml, String getMessage(yaml)) {
+  if (yaml == null) return VersionConstraint.any;
+  if (yaml is! String) throw new FormatException(getMessage(yaml));
+
+  try {
+    return new VersionConstraint.parse(yaml);
+  } on FormatException catch(_) {
+    throw new FormatException(getMessage(yaml));
+  }
+}
+
+List<PackageDep> _parseDependencies(String packageName, String pubspecPath,
+    SourceRegistry sources, yaml) {
   var dependencies = <PackageDep>[];
 
   // Allow an empty dependencies key.
@@ -255,6 +279,10 @@
   }
 
   yaml.forEach((name, spec) {
+    if (name == packageName) {
+      throw new FormatException("Package '$name' cannot depend on itself.");
+    }
+
     var description;
     var sourceName;
 
@@ -268,7 +296,9 @@
       versionConstraint = new VersionConstraint.parse(spec);
     } else if (spec is Map) {
       if (spec.containsKey('version')) {
-        versionConstraint = new VersionConstraint.parse(spec.remove('version'));
+        versionConstraint = _parseVersionConstraint(spec.remove('version'),
+            (v) => 'The "version" field for $name should be a semantic '
+                   'version constraint, but was "$v".');
       }
 
       var sourceNames = spec.keys.toList();
diff --git a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
index 46e0015..1715240 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/dependency.dart
@@ -22,14 +22,6 @@
         return _warnAboutSource(dependency);
       }
 
-      if (dependency.name == entrypoint.root.name) {
-        warnings.add('You don\'t need to explicitly depend on your own '
-                'package.\n'
-            'Pub enables "package:${entrypoint.root.name}" imports '
-                'implicitly.');
-        return new Future.value();
-      }
-
       if (dependency.constraint.isAny) _warnAboutConstraint(dependency);
 
       return new Future.value();
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 951e99a..56f997a 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -6,6 +6,12 @@
 test/oauth2/with_an_expired_credentials_refreshes_and_saves_test: Pass, Fail # 12581
 test/hosted/remove_removed_dependency_test: Pass, Fail # 12582
 test/hosted/remove_removed_transitive_dependency_test: Pass, Fail # 12582
+test/install/hosted/cached_pubspec_test: Pass, Fail # 12678
+test/install/hosted/do_not_update_on_removed_constraints_test: Pass, Fail # 12680
+test/install/hosted/install_test: Pass, Fail # 12682
+test/install/hosted/install_transitive_test: Pass, Fail # 12683
+test/install/hosted/repair_cache_test: Pass, Fail # 12684
+pub/test/serve/serve_from_dependency_asset_test: Pass, Fail # 12686
 
 # Pub only runs on the VM, so just rule out all compilers.
 [ $compiler == dart2js || $compiler == dart2dart ]
diff --git a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
index f269126..06da50a 100644
--- a/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_install_and_update_test.dart
@@ -113,5 +113,30 @@
       pubCommand(command,
           error: new RegExp("^Incompatible dependencies on 'baz':\n"));
     });
+
+    integration('does not allow a dependency on itself', () {
+      d.dir(appPath, [
+        d.appPubspec({
+          "myapp": {"path": "."}
+        })
+      ]).create();
+
+      pubCommand(command,
+          error: new RegExp("Package 'myapp' cannot depend on itself."));
+    });
+
+    integration('does not allow a dev dependency on itself', () {
+      d.dir(appPath, [
+        d.pubspec({
+          "name": "myapp",
+          "dev_dependencies": {
+            "myapp": {"path": "."}
+          }
+        })
+      ]).create();
+
+      pubCommand(command,
+          error: new RegExp("Package 'myapp' cannot depend on itself."));
+    });
   });
 }
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart
index 47f838a..092611d 100644
--- a/sdk/lib/_internal/pub/test/pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -103,6 +103,24 @@
 ''');
     });
 
+    test("throws if it dependes on itself", () {
+      expectFormatError('''
+name: myapp
+dependencies:
+  myapp:
+    mock: ok
+''');
+    });
+
+    test("throws if it has a dev dependency on itself", () {
+      expectFormatError('''
+name: myapp
+dev_dependencies:
+  myapp:
+    mock: ok
+''');
+    });
+
     test("throws if the description isn't valid", () {
       expectFormatError('''
 dependencies:
@@ -111,10 +129,40 @@
 ''');
     });
 
+    test("throws if dependency version is not a string", () {
+      expectFormatError('''
+dependencies:
+  foo:
+    mock: ok
+    version: 1.2
+''');
+    });
+
+    test("throws if version is not a version constraint", () {
+      expectFormatError('''
+dependencies:
+  foo:
+    mock: ok
+    version: not constraint
+''');
+    });
+
     test("throws if 'name' is not a string", () {
       expectFormatError('name: [not, a, string]');
     });
 
+    test("throws if version is not a string", () {
+      expectFormatError('''
+version: 1.0
+''');
+    });
+
+    test("throws if version is not a version", () {
+      expectFormatError('''
+version: not version
+''');
+    });
+
     test("throws if 'homepage' is not a string", () {
       expectFormatError('homepage:');
       expectFormatError('homepage: [not, a, string]');
@@ -212,6 +260,13 @@
 ''');
       });
 
+    test("throws if the sdk is not a string", () {
+      expectFormatError('''
+environment:
+  sdk: 1.0
+''');
+    });
+
       test("throws if the sdk isn't a valid version constraint", () {
         expectFormatError('''
 environment:
diff --git a/sdk/lib/_internal/pub/test/validator/dependency_test.dart b/sdk/lib/_internal/pub/test/validator/dependency_test.dart
index ee38ee8..ba29373 100644
--- a/sdk/lib/_internal/pub/test/validator/dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/validator/dependency_test.dart
@@ -237,15 +237,5 @@
         });
       });
     });
-
-    integration('has a hosted dependency on itself', () {
-      d.dir(appPath, [
-        d.libPubspec("test_pkg", "1.0.0", deps: {
-          "test_pkg": ">=1.0.0"
-        })
-      ]).create();
-
-      expectValidationWarning(dependency);
-    });
   });
 }
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index ed8103f..6c15c4b 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -25,7 +25,8 @@
  *       var duration = milliseconds == null ? TIMEOUT : ms * milliseconds;
  *       return new Timer(duration, handleTimeout);
  *     }
- *     void handleTimeout(Timer _) {  // callback function
+ *     ...
+ *     void handleTimeout() {  // callback function
  *       ...
  *     }
  *
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
new file mode 100644
index 0000000..bea9680
--- /dev/null
+++ b/sdk/lib/convert/ascii.dart
@@ -0,0 +1,285 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/**
+ * An instance of the default implementation of the [AsciiCodec].
+ *
+ * This instance provides a convenient access to the most common ASCII
+ * use cases.
+ *
+ * Examples:
+ *
+ *     var encoded = ASCII.encode("This is ASCII!");
+ *     var decoded = ASCII.decode([0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+ *                                 0x20, 0x41, 0x53, 0x43, 0x49, 0x49, 0x21]);
+ */
+const ASCII = const AsciiCodec();
+
+const int _ASCII_MASK = 0x7F;
+
+/**
+ * An [AsciiCodec] allows encoding strings as ASCII bytes
+ * and decoding ASCII bytes to strings.
+ */
+class AsciiCodec extends _Encoding {
+  final bool _allowInvalid;
+  /**
+   * Instantiates a new [AsciiCodec].
+   *
+   * If [allowInvalid] is true, the [decode] method and the converter
+   * returned by [decoder] will default to allowing invalid values.
+   * If allowing invalid values, the values will be decoded into the Unicode
+   * Replacement character (U+FFFD). If not, an exception will be thrown.
+   * Calls to the [decode] method can choose to override this default.
+   *
+   * Encoders will not accept invalid (non Latin-1) characters.
+   */
+  const AsciiCodec({bool allowInvalid: false}) : _allowInvalid = allowInvalid;
+
+  /**
+   * Decodes the ASCII [bytes] (a list of unsigned 7-bit integers) to the
+   * corresponding string.
+   *
+   * If [bytes] contains values that are not in the range 0 .. 127, the decoder
+   * will eventually throw a [FormatException].
+   *
+   * If [allowInvalid] is not provided, it defaults to the value used to create
+   * this [AsciiCodec].
+   */
+  String decode(List<int> bytes, { bool allowInvalid }) {
+    if (allowInvalid == null) allowInvalid = _allowInvalid;
+    if (allowInvalid) {
+      return const AsciiDecoder(allowInvalid: true).convert(bytes);
+    } else {
+      return const AsciiDecoder(allowInvalid: false).convert(bytes);
+    }
+  }
+
+  Converter<String, List<int>> get encoder => const AsciiEncoder();
+
+  Converter<List<int>, String> get decoder =>
+      _allowInvalid ? const AsciiDecoder(allowInvalid: true)
+                    : const AsciiDecoder(allowInvalid: false);
+}
+
+// Superclass for [AsciiEncoder] and [Latin1Encoder].
+// Generalizes common operations that only differ by a mask;
+class _UnicodeSubsetEncoder extends Converter<String, List<int>> {
+  final int _subsetMask;
+
+  const _UnicodeSubsetEncoder(this._subsetMask);
+
+  List<int> convert(String string) {
+    // TODO(11971): Use Uint8List when possible.
+    List result = new List<int>(string.length);
+    for (int i = 0; i < string.length; i++) {
+      var codeUnit = string.codeUnitAt(i);
+      if ((codeUnit & ~_subsetMask) != 0) {
+        throw new ArgumentError("String contains invalid characters.");
+      }
+      result[i] = codeUnit;
+    }
+    return result;
+  }
+
+  /**
+   * Starts a chunked conversion.
+   *
+   * The converter works more efficiently if the given [sink] is a
+   * [ByteConversionSink].
+   */
+  StringConversionSink startChunkedConversion(
+      ChunkedConversionSink<List<int>> sink) {
+    if (sink is! ByteConversionSink) {
+      sink = new ByteConversionSink.from(sink);
+    }
+    return new _UnicodeSubsetEncoderSink(_subsetMask, sink);
+  }
+
+  // Override the base-class' bind, to provide a better type.
+  Stream<List<int>> bind(Stream<String> stream) => super.bind(stream);
+}
+
+/**
+ * This class converts strings of only ASCII characters to bytes.
+ */
+class AsciiEncoder extends _UnicodeSubsetEncoder {
+  const AsciiEncoder() : super(_ASCII_MASK);
+}
+
+/**
+ * This class encodes chunked strings to bytes (unsigned 8-bit
+ * integers).
+ */
+class _UnicodeSubsetEncoderSink extends StringConversionSinkBase {
+  final ByteConversionSink _sink;
+  final int _subsetMask;
+
+  _UnicodeSubsetEncoderSink(this._subsetMask, this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void addSlice(String source, int start, int end, bool isLast) {
+    if (start < 0 || start > source.length) {
+      throw new RangeError.range(start, 0, source.length);
+    }
+    if (end < start || end > source.length) {
+      throw new RangeError.range(end, start, source.length);
+    }
+    for (int i = start; i < end; i++) {
+      int codeUnit = source.codeUnitAt(i);
+      if ((codeUnit & ~_subsetMask) != 0) {
+        throw new ArgumentError(
+            "Source contains invalid character with code point: $codeUnit.");
+      }
+    }
+    _sink.add(source.codeUnits);
+    if (isLast) {
+      close();
+    }
+  }
+}
+
+/**
+ * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+ * to a string.
+ */
+abstract class _UnicodeSubsetDecoder extends Converter<List<int>, String> {
+  final bool _allowInvalid;
+  final int _subsetMask;
+
+  /**
+   * Instantiates a new decoder.
+   *
+   * The [_allowInvalid] argument defines how [convert] deals
+   * with invalid bytes.
+   *
+   * The [_subsetMask] argument is a bit mask used to define the subset
+   * of Unicode being decoded. Use [_LATIN1_MASK] for Latin-1 (8-bit) or
+   * [_ASCII_MASK] for ASCII (7-bit).
+   *
+   * If [_allowInvalid] is `true`, [convert] replaces invalid bytes with the
+   * Unicode Replacement character `U+FFFD` (�).
+   * Otherwise it throws a [FormatException].
+   */
+  const _UnicodeSubsetDecoder(this._allowInvalid, this._subsetMask);
+
+  /**
+   * Converts the [bytes] (a list of unsigned 7- or 8-bit integers) to the
+   * corresponding string.
+   */
+  String convert(List<int> bytes) {
+    for (int i = 0; i < bytes.length; i++) {
+      int byte = bytes[i];
+      if ((byte & ~_subsetMask) != 0) {
+        if (!_allowInvalid) {
+          throw new FormatException("Invalid value in input: $byte");
+        }
+        return _convertInvalid(bytes);
+      }
+    }
+    return new String.fromCharCodes(bytes);
+  }
+
+  String _convertInvalid(List<int> bytes) {
+    StringBuffer buffer = new StringBuffer();
+    for (int i = 0; i < bytes.length; i++) {
+      int value = bytes[i];
+      if ((value & ~_subsetMask) != 0) value = 0xFFFD;
+      buffer.writeCharCode(value);
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Starts a chunked conversion.
+   *
+   * The converter works more efficiently if the given [sink] is a
+   * [StringConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(
+      ChunkedConversionSink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = new StringConversionSink.from(sink);
+    }
+    // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+    return new _Latin1DecoderSink(_allowInvalid, stringSink);
+  }
+
+  // Override the base-class's bind, to provide a better type.
+  Stream<String> bind(Stream<List<int>> stream) => super.bind(stream);
+}
+
+class AsciiDecoder extends _UnicodeSubsetDecoder {
+  const AsciiDecoder({bool allowInvalid: false})
+      : super(allowInvalid, _ASCII_MASK);
+
+  /**
+   * Starts a chunked conversion.
+   *
+   * The converter works more efficiently if the given [sink] is a
+   * [StringConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(
+      ChunkedConversionSink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = new StringConversionSink.from(sink);
+    }
+    // TODO(lrn): Use asUtf16Sink when it becomes available. It
+    // works just as well, is likely to have less decoding overhead,
+    // and make adding U+FFFD easier.
+    // At that time, merge this with _Latin1DecoderSink;
+    return new _AsciiDecoderSink(_allowInvalid, stringSink.asUtf8Sink(false));
+  }
+}
+
+class _AsciiDecoderSink extends ByteConversionSinkBase {
+  final bool _allowInvalid;
+  ByteConversionSink _utf8Sink;
+  _AsciiDecoderSink(this._allowInvalid, this._utf8Sink);
+
+  void close() {
+    _utf8Sink.close();
+  }
+
+  void add(List<int> source) {
+    addSlice(source, 0, source.length, false);
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    if (start < 0 || start > source.length) {
+      throw new RangeError.range(start, 0, source.length);
+    }
+    if (end < start || end > source.length) {
+      throw new RangeError.range(end, start, source.length);
+    }
+    for (int i = start; i < end; i++) {
+      if ((source[i] & ~_ASCII_MASK) != 0) {
+        if (_allowInvalid) {
+          if (i > start) _utf8Sink.addSlice(source, start, i, false);
+          // Add UTF-8 encoding of U+FFFD.
+          _utf8Sink.add(const<int>[0xEF, 0xBF, 0xBD]);
+          start = i + 1;
+        } else {
+          throw new FormatException("Source contains non-ASCII bytes.");
+        }
+      }
+    }
+    if (start < end) {
+      _utf8Sink.addSlice(source, start, end, isLast);
+    } else if (isLast) {
+      close();
+    }
+  }
+}
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 3e9b6f5..5cca4d4 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * Converters for JSON and UTF-8, as well as support for creating additional 
+ * Converters for JSON and UTF-8, as well as support for creating additional
  * converters.
  */
 library dart.convert;
@@ -11,12 +11,14 @@
 import 'dart:async';
 import 'dart:json' as OLD_JSON_LIB;
 
+part 'ascii.dart';
 part 'byte_conversion.dart';
 part 'chunked_conversion.dart';
 part 'codec.dart';
 part 'converter.dart';
 part 'encoding.dart';
 part 'json.dart';
+part 'latin1.dart';
 part 'line_splitter.dart';
 part 'string_conversion.dart';
 part 'utf.dart';
diff --git a/sdk/lib/convert/convert_sources.gypi b/sdk/lib/convert/convert_sources.gypi
index eaf9952..35a825f 100644
--- a/sdk/lib/convert/convert_sources.gypi
+++ b/sdk/lib/convert/convert_sources.gypi
@@ -7,12 +7,14 @@
   'sources': [
     'convert.dart',
     # The above file needs to be first as it lists the parts below.
+    'ascii.dart',
     'byte_conversion.dart',
     'chunked_conversion.dart',
     'codec.dart',
     'converter.dart',
     'encoding.dart',
     'json.dart',
+    'latin1.dart',
     'line_splitter.dart',
     'string_conversion.dart',
     'utf.dart',
diff --git a/sdk/lib/convert/latin1.dart b/sdk/lib/convert/latin1.dart
new file mode 100644
index 0000000..3e9232f
--- /dev/null
+++ b/sdk/lib/convert/latin1.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.convert;
+
+/**
+ * An instance of the default implementation of the [Latin1Codec].
+ *
+ * This instance provides a convenient access to the most common ISO Latin 1
+ * use cases.
+ *
+ * Examples:
+ *
+ *     var encoded = LATIN1.encode("blåbærgrød");
+ *     var decoded = LATIN1.decode([0x62, 0x6c, 0xe5, 0x62, 0xe6,
+ *                                  0x72, 0x67, 0x72, 0xf8, 0x64]);
+ */
+const LATIN1 = const Latin1Codec();
+
+const int _LATIN1_MASK = 0xFF;
+
+/**
+ * A [LatinCodec] encodes strings to ISO Latin-1 (aka ISO-8859-1) bytes
+ * and decodes Latin-1 bytes to strings.
+ */
+class Latin1Codec extends _Encoding {
+  final bool _allowInvalid;
+  /**
+   * Instantiates a new [Latin1Codec].
+   *
+   * If [allowInvalid] is true, the [decode] method and the converter
+   * returned by [decoder] will default to allowing invalid values. Invalid
+   * values are decoded into the Unicode Replacement character (U+FFFD).
+   * Calls to the [decode] method can override this default.
+   *
+   * Encoders will not accept invalid (non Latin-1) characters.
+   */
+  const Latin1Codec({bool allowInvalid: false}) : _allowInvalid = allowInvalid;
+
+  /**
+   * Decodes the Latin-1 [bytes] (a list of unsigned 8-bit integers) to the
+   * corresponding string.
+   *
+   * If [bytes] contains values that are not in the range 0 .. 255, the decoder
+   * will eventually throw a [FormatException].
+   *
+   * If [allowInvalid] is not provided, it defaults to the value used to create
+   * this [Latin1Codec].
+   */
+  String decode(List<int> bytes, { bool allowInvalid }) {
+    if (allowInvalid == null) allowInvalid = _allowInvalid;
+    if (allowInvalid) {
+      return const Latin1Decoder(allowInvalid: true).convert(bytes);
+    } else {
+      return const Latin1Decoder(allowInvalid: false).convert(bytes);
+    }
+  }
+
+  Converter<String, List<int>> get encoder => const Latin1Encoder();
+
+  Converter<List<int>, String> get decoder =>
+      _allowInvalid ? const Latin1Decoder(allowInvalid: true)
+                    : const Latin1Decoder(allowInvalid: false);
+}
+
+/**
+ * This class converts strings of only ISO Latin-1 characters to bytes.
+ */
+class Latin1Encoder extends _UnicodeSubsetEncoder {
+  const Latin1Encoder() : super(_LATIN1_MASK);
+}
+
+/**
+ * This class converts Latin-1 bytes (lists of unsigned 8-bit integers)
+ * to a string.
+ */
+class Latin1Decoder extends _UnicodeSubsetDecoder {
+  /**
+   * Instantiates a new [Latin1Decoder].
+   *
+   * The optional [allowInvalid] argument defines how [convert] deals
+   * with invalid bytes.
+   *
+   * If it is `true`, [convert] replaces invalid bytes with the Unicode
+   * Replacement character `U+FFFD` (�).
+   * Otherwise it throws a [FormatException].
+   */
+  const Latin1Decoder({ bool allowInvalid: false })
+      : super(allowInvalid, _LATIN1_MASK);
+
+  /**
+   * Starts a chunked conversion.
+   *
+   * The converter works more efficiently if the given [sink] is a
+   * [StringConversionSink].
+   */
+  ByteConversionSink startChunkedConversion(
+      ChunkedConversionSink<String> sink) {
+    StringConversionSink stringSink;
+    if (sink is StringConversionSink) {
+      stringSink = sink;
+    } else {
+      stringSink = new StringConversionSink.from(sink);
+    }
+    // TODO(lrn): Use stringSink.asUtf16Sink() if it becomes available.
+    return new _Latin1DecoderSink(_allowInvalid, stringSink);
+  }
+}
+
+class _Latin1DecoderSink extends ByteConversionSinkBase {
+  final bool _allowInvalid;
+  StringConversionSink _sink;
+  _Latin1DecoderSink(this._allowInvalid, this._sink);
+
+  void close() {
+    _sink.close();
+  }
+
+  void add(List<int> source) {
+    addSlice(source, 0, source.length, false);
+  }
+
+  void _addSliceToSink(List<int> source, int start, int end, bool isLast) {
+    // If _sink was a UTF-16 conversion sink, just add the slice directly with
+    // _sink.addSlice(source, start, end, isLast).
+    // The code below is an incredibly stupid workaround until a real
+    // solution can be made.
+    _sink.add(new String.fromCharCodes(source.getRange(start, end)));
+    if (isLast) close();
+  }
+
+  void addSlice(List<int> source, int start, int end, bool isLast) {
+    if (start < 0 || start > source.length) {
+      throw new RangeError.range(start, 0, source.length);
+    }
+    if (end < start || end > source.length) {
+      throw new RangeError.range(end, start, source.length);
+    }
+    for (int i = start; i < end; i++) {
+      if ((source[i] & ~_LATIN1_MASK) != 0) {
+        if (_allowInvalid) {
+          if (i > start) _addSliceToSink(source, start, i, false);
+          // Add UTF-8 encoding of U+FFFD.
+          _addSliceToSink(const[0xFFFD], 0, 1, false);
+          start = i + 1;
+        } else {
+          throw new FormatException("Source contains non-Latin-1 characters.");
+        }
+      }
+    }
+    if (start < end) {
+      _addSliceToSink(source, start, end, isLast);
+    } else if (isLast) {
+      close();
+    }
+  }
+}
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index ee0d135..4a90cfa 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.dart
@@ -299,7 +299,6 @@
  */
 // TODO(floitsch): make this class public?
 class _Utf8ConversionSink extends ByteConversionSink {
-  static const _MIN_STRING_SIZE = 16;
 
   final _Utf8Decoder _decoder;
   final StringConversionSink _chunkedSink;
@@ -327,10 +326,9 @@
     addSlice(chunk, 0, chunk.length, false);
   }
 
-  void addSlice(List<int> chunk, int startIndex, int endIndex,
-                bool isLast) {
+  void addSlice(List<int> chunk, int startIndex, int endIndex, bool isLast) {
     _decoder.convert(chunk, startIndex, endIndex);
-    if (_buffer.length > _MIN_STRING_SIZE) {
+    if (_buffer.isNotEmpty) {
       String accumulated = _buffer.toString();
       _chunkedSink.addSlice(accumulated, 0, accumulated.length, isLast);
       _buffer.clear();
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 80f7a78..37f2335 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -455,7 +455,19 @@
 
       while (i < endIndex) {
         int unit = codeUnits[i++];
-        if (unit <= _ONE_BYTE_LIMIT) {
+        // TODO(floitsch): the way we test we could potentially allow
+        // units that are too large, if they happen to have the
+        // right bit-pattern. (Same is true for the multibyte loop above).
+        // TODO(floitsch): optimize this loop. See:
+        // https://codereview.chromium.org/22929022/diff/1/sdk/lib/convert/utf.dart?column_width=80
+        if (unit < 0) {
+          // TODO(floitsch): should this be unit <= 0 ?
+          if (!_allowMalformed) {
+            throw new FormatException(
+                "Negative UTF-8 code unit: -0x${(-unit).toRadixString(16)}");
+          }
+          _stringSink.writeCharCode(_REPLACEMENT_CHARACTER);
+        } else if (unit <= _ONE_BYTE_LIMIT) {
           _isFirstCharacter = false;
           _stringSink.writeCharCode(unit);
         } else {
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 6cfe998..a902226 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -7,62 +7,87 @@
  * Built-in types, collections,
  * and other core functionality for every Dart program.
  *
+ * This library is automatically imported.
+ *
  * Some classes in this library,
  * such as [String] and [num],
  * support Dart's built-in data types.
- * Other classes provide data structures
+ * Other classes, such as [List] and [Map], provide data structures
  * for managing collections of objects.
  * And still other classes represent commonly used types of data
- * such as URIs, dates, and times.
+ * such as URIs, dates and times, and errors.
  *
+ * ## Numbers and booleans
  *
- * ## Built-in types
+ * [int] and [double] provide support for Dart's built-in numerical data types:
+ * integers and double-precision floating point numbers, respectively.
+ * An object of type [bool] is either true or false.
+ * Variables of these types can be constructed from literals:
  *
- * [String], [int], [double], [bool], [List], and [Map]
- * provide support for Dart's built-in data types.
- * To declare and initialize variables of these types, write:
- *     String myString   = 'A sequence of characters.';
  *     int meaningOfLife = 42;
  *     double valueOfPi  = 3.141592;
  *     bool visible      = true;
- *     List superHeros   = [ 'Batman', 'Superman', 'Harry Potter' ];
- *     Map sidekicks     = { 'Batman': 'Robin',
- *                           'Superman': 'Lois Lane',
- *                           'Harry Potter': 'Ron and Hermione' };
  *
- * ## Strings
+ * ## Strings and regular expressions
  *
  * A [String] is immutable and represents a sequence of characters.
- * [StringBuffer] provides a way to construct strings efficiently.
- * 
- * The Dart language uses the [String] and [StringBuffer]
- * behind the scenes to implement string concatenation, interpolation,
- * and other features.
- *     String myString = 'Live on ';
- *     String get palindrome => myString + myString.split('').reversed.join();
  *
+ *     String shakespeareQuote = "All the world's a stage, ...";
+ *
+ * [StringBuffer] provides a way to construct strings efficiently.
+ *
+ *     StringBuffer moreShakespeare = new StringBuffer();
+ *     moreShakespeare.write('And all the men and women ');
+ *     moreShakespeare.write('merely players; ...');
+ * 
+ * The String and StringBuffer classes implement string concatenation,
+ * interpolation, and other string manipulation features.
+ *
+ *     String philosophy = 'Live on ';
+ *     String get palindrome => philosophy + philosophy.split('').reversed.join();
+ *
+ * [RegExp] implements Dart regular expressions,
+ * which provide a grammar for matching patterns within text.
+ * For example, here's a regular expression that matches
+ * a string of one or more digits:
+ *
+ *     var numbers = new RegExp(r'\d+');
+ *
+ * Dart regular expressions have the same syntax and semantics as
+ * JavaScript regular expressions. See
+ * <http://ecma-international.org/ecma-262/5.1/#sec-15.10>
+ * for the specification of JavaScript regular expressions.
  *
  * ## Collections
  *
  * The dart:core library provides basic collections,
  * such as [List], [Map], and [Set].
  *
- * * A [List] is an ordered collection of objects, with a length.
+ * A List is an ordered collection of objects, with a length.
  * Lists are sometimes called arrays.
  * Use a List when you need to access objects by index.
  *
- * * A [Set] is an unordered collection of unique objects.
+ *     List superheroes = [ 'Batman', 'Superman', 'Harry Potter' ];
+ *
+ * A Set is an unordered collection of unique objects.
  * You cannot get an item by index (position).
  * Adding a duplicate item has no effect.
- * Use a [Set] when you need to guarantee object uniqueness.
  *
- * * A [Map] is an unordered collection of key-value pairs.
+ *     Set villians = new Set();
+ *     villians.add('Joker');
+ *     villians.addAll( ['Lex Luther', 'Voldemort'] );
+ *
+ * A Map is an unordered collection of key-value pairs.
  * Maps are sometimes called associative arrays because
  * maps associate a key to some value for easy retrieval.
  * Keys are unique.
- * Use a [Map] when you need to access objects
+ * Use a Map when you need to access objects
  * by a unique identifier.
  *
+ *     Map sidekicks = { 'Batman': 'Robin',
+ *                       'Superman': 'Lois Lane',
+ *                       'Harry Potter': 'Ron and Hermione' };
+ *
  * In addition to these classes,
  * dart:core contains [Iterable],
  * an interface that defines functionality
@@ -72,30 +97,43 @@
  * to apply a test to each element, 
  * to retrieve an object, and to determine length.
  *
- * Iterable is implemented by [List] and [Set],
- * and used by [Map] for its lists of keys and values.
+ * Iterable is implemented by List and Set,
+ * and used by Map for its keys and values.
  * 
- * For other kinds of collections, check out the dart:collection library.
+ * For other kinds of collections, check out the
+ * [dart:collection](#dart-collection) library.
  * 
  * ## Date and time
  *
  * Use [DateTime] to represent a point in time
  * and [Duration] to represent a span of time.
  *
- * You can create [DateTime] objects with constructors
+ * You can create DateTime objects with constructors
  * or by parsing a correctly formatted string.
+ *
  *     DateTime now = new DateTime.now();
  *     DateTime berlinWallFell = new DateTime(1989, 11, 9);
  *     DateTime moonLanding = DateTime.parse("1969-07-20");
  *
- * Create a [Duration] object specifying the individual time units.
+ * Create a Duration object specifying the individual time units.
+ *
  *     Duration timeRemaining = new Duration(hours:56, minutes:14);
+ * 
+ * In addition to DateTime and Duration,
+ * dart:core contains the [Stopwatch] class for measuring elapsed time.
  *     
  * ## Uri
  *
  * A [Uri] object represents a uniform resource identifier,
  * which identifies a resource on the web.
+ *
  *     Uri dartlang = Uri.parse('http://dartlang.org/');
+ *     
+ * ## Errors
+ *
+ * The [Error] class represents the occurrence of an error
+ * during runtime.
+ * Subclasses of this class represent specific kinds of errors.
  *
  * ## Other documentation
  *
@@ -108,9 +146,10 @@
  * [dart:core - Numbers, Collections, Strings, and More](http://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-dartcore---strings-collections-and-more)
  * for more coverage of classes in this package.
  *
+ * The 
+ * [Dart Language Specification](https://www.dartlang.org/docs/spec/)
+ * provides technical details.
  */
-
-
 library dart.core;
 
 import "dart:collection";
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 39a5f2f..0b4a63a 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -506,7 +506,7 @@
    *
    *     DateTime moonLanding = DateTime.parse("1969-07-20 20:18:00");
    *     assert(moonLanding.month == 7);
-   *     assert(moonLanding.month == JULY);
+   *     assert(moonLanding.month == DateTime.JULY);
    */
   external int get month;
 
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index e74b936..e5ccb87 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -5,27 +5,32 @@
 part of dart.core;
 
 /**
- * A [Map] is an associative container, mapping a key to a value.
+ * An unordered collection of key-value pairs,
+ * from which you retrieve a value by using its associated key.
+ *
+ * Each key must be unique.
  * Null values are supported, but null keys are not.
  */
 abstract class Map<K, V> {
   /**
-   * Creates a map with the default implementation.
+   * Creates a Map instance with the default implementation.
    */
   factory Map() => new HashMap<K, V>();
 
   /**
-   * Creates a [Map] that contains all key value pairs of [other].
+   * Creates a Map instance that contains all key-value pairs of [other].
    */
   factory Map.from(Map<K, V> other) => new HashMap<K, V>.from(other);
 
   /**
-   * Creates a [Map] where the keys and values are computed from the [iterable].
+   * Creates a Map instance
+   * where the keys and values are computed from the [iterable].
    *
-   * For each element of the [iterable] this constructor computes a key/value
+   * For each element of the [iterable] this constructor computes a key-value
    * pair, by applying [key] and [value] respectively.
    *
-   * The keys of the key/value pairs do not need to be unique. The last
+   * The keys computed by the source [iterable] 
+   * do not need to be unique. The last
    * occurrence of a key will simply overwrite any previous value.
    *
    * If no values are specified for [key] and [value] the default is the
@@ -35,7 +40,7 @@
       {K key(element), V value(element)}) = HashMap<K, V>.fromIterable;
 
   /**
-   * Creates a [Map] associating the given [keys] to [values].
+   * Creates a Map instance associating the given [keys] to [values].
    *
    * This constructor iterates over [keys] and [values] and maps each element of
    * [keys] to the corresponding element of [values].
@@ -49,19 +54,19 @@
       = HashMap<K, V>.fromIterables;
 
   /**
-   * Returns whether this map contains the given [value].
+   * Returns true if this map contains the given value.
    */
   bool containsValue(Object value);
 
   /**
-   * Returns whether this map contains the given [key].
+   * Returns true if this map contains the given key.
    */
   bool containsKey(Object key);
 
   /**
    * Returns the value for the given [key] or null if [key] is not
    * in the map. Because null values are supported, one should either
-   * use containsKey to distinguish between an absent key and a null
+   * use [containsKey] to distinguish between an absent key and a null
    * value, or use the [putIfAbsent] method.
    */
   V operator [](Object key);
@@ -76,7 +81,7 @@
    * updates the map by mapping [key] to the value returned by
    * [ifAbsent]. Returns the value in the map.
    *
-   * It is an error to add or remove keys from map during the call to
+   * It is an error to add or remove keys from the map during the call to
    * [ifAbsent].
    */
   V putIfAbsent(K key, V ifAbsent());
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index b584d35..b527e44 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -7183,6 +7183,12 @@
   @DocsEditable()
   Event $dom_createEvent(String eventType) native;
 
+  @JSName('createNodeIterator')
+  @DomName('Document.createNodeIterator')
+  @DocsEditable()
+  @Unstable()
+  NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
+
   @JSName('createRange')
   @DomName('Document.createRange')
   @DocsEditable()
@@ -7216,6 +7222,11 @@
   @Experimental()
   TouchList $dom_createTouchList() native;
 
+  @JSName('createTreeWalker')
+  @DomName('Document.createTreeWalker')
+  @DocsEditable()
+  TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) native;
+
   @JSName('elementFromPoint')
   @DomName('Document.elementFromPoint')
   @DocsEditable()
@@ -17904,6 +17915,47 @@
   @DocsEditable()
   static const int SHOW_TEXT = 0x00000004;
 }
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DomName('NodeIterator')
+@Unstable()
+class NodeIterator extends Interceptor native "NodeIterator" {
+  factory NodeIterator(Node root, int whatToShow) {
+    return document.$dom_createNodeIterator(root, whatToShow, null, false);
+  }
+
+  @DomName('NodeIterator.pointerBeforeReferenceNode')
+  @DocsEditable()
+  final bool pointerBeforeReferenceNode;
+
+  @DomName('NodeIterator.referenceNode')
+  @DocsEditable()
+  final Node referenceNode;
+
+  @DomName('NodeIterator.root')
+  @DocsEditable()
+  final Node root;
+
+  @DomName('NodeIterator.whatToShow')
+  @DocsEditable()
+  final int whatToShow;
+
+  @DomName('NodeIterator.detach')
+  @DocsEditable()
+  void detach() native;
+
+  @DomName('NodeIterator.nextNode')
+  @DocsEditable()
+  Node nextNode() native;
+
+  @DomName('NodeIterator.previousNode')
+  @DocsEditable()
+  Node previousNode() native;
+
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -23609,6 +23661,69 @@
   @DocsEditable()
   final String pseudoElement;
 }
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DomName('TreeWalker')
+@Unstable()
+class TreeWalker extends Interceptor native "TreeWalker" {
+  factory TreeWalker(Node root, int whatToShow) {
+    return document.$dom_createTreeWalker(root, whatToShow, null, false);
+  }
+
+  @DomName('TreeWalker.currentNode')
+  @DocsEditable()
+  Node currentNode;
+
+  @DomName('TreeWalker.expandEntityReferences')
+  @DocsEditable()
+  // http://dom.spec.whatwg.org/#dom-traversal
+  @deprecated // deprecated
+  final bool expandEntityReferences;
+
+  @DomName('TreeWalker.filter')
+  @DocsEditable()
+  final NodeFilter filter;
+
+  @DomName('TreeWalker.root')
+  @DocsEditable()
+  final Node root;
+
+  @DomName('TreeWalker.whatToShow')
+  @DocsEditable()
+  final int whatToShow;
+
+  @DomName('TreeWalker.firstChild')
+  @DocsEditable()
+  Node firstChild() native;
+
+  @DomName('TreeWalker.lastChild')
+  @DocsEditable()
+  Node lastChild() native;
+
+  @DomName('TreeWalker.nextNode')
+  @DocsEditable()
+  Node nextNode() native;
+
+  @DomName('TreeWalker.nextSibling')
+  @DocsEditable()
+  Node nextSibling() native;
+
+  @DomName('TreeWalker.parentNode')
+  @DocsEditable()
+  Node parentNode() native;
+
+  @DomName('TreeWalker.previousNode')
+  @DocsEditable()
+  Node previousNode() native;
+
+  @DomName('TreeWalker.previousSibling')
+  @DocsEditable()
+  Node previousSibling() native;
+
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index dc81135..1fe8297 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -7724,6 +7724,27 @@
   @DocsEditable()
   Event $dom_createEvent(String eventType) native "Document_createEvent_Callback";
 
+  NodeIterator $dom_createNodeIterator(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
+    if (expandEntityReferences != null) {
+      return _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences);
+    }
+    if (filter != null) {
+      return _createNodeIterator_2(root, whatToShow, filter);
+    }
+    if (whatToShow != null) {
+      return _createNodeIterator_3(root, whatToShow);
+    }
+    return _createNodeIterator_4(root);
+  }
+
+  NodeIterator _createNodeIterator_1(root, whatToShow, filter, expandEntityReferences) native "Document__createNodeIterator_1_Callback";
+
+  NodeIterator _createNodeIterator_2(root, whatToShow, filter) native "Document__createNodeIterator_2_Callback";
+
+  NodeIterator _createNodeIterator_3(root, whatToShow) native "Document__createNodeIterator_3_Callback";
+
+  NodeIterator _createNodeIterator_4(root) native "Document__createNodeIterator_4_Callback";
+
   @DomName('Document.createRange')
   @DocsEditable()
   Range $dom_createRange() native "Document_createRange_Callback";
@@ -7745,6 +7766,27 @@
   @Experimental()
   TouchList $dom_createTouchList() native "Document_createTouchList_Callback";
 
+  TreeWalker $dom_createTreeWalker(Node root, [int whatToShow, NodeFilter filter, bool expandEntityReferences]) {
+    if (expandEntityReferences != null) {
+      return _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences);
+    }
+    if (filter != null) {
+      return _createTreeWalker_2(root, whatToShow, filter);
+    }
+    if (whatToShow != null) {
+      return _createTreeWalker_3(root, whatToShow);
+    }
+    return _createTreeWalker_4(root);
+  }
+
+  TreeWalker _createTreeWalker_1(root, whatToShow, filter, expandEntityReferences) native "Document__createTreeWalker_1_Callback";
+
+  TreeWalker _createTreeWalker_2(root, whatToShow, filter) native "Document__createTreeWalker_2_Callback";
+
+  TreeWalker _createTreeWalker_3(root, whatToShow) native "Document__createTreeWalker_3_Callback";
+
+  TreeWalker _createTreeWalker_4(root) native "Document__createTreeWalker_4_Callback";
+
   @DomName('Document.elementFromPoint')
   @DocsEditable()
   Element $dom_elementFromPoint(int x, int y) native "Document_elementFromPoint_Callback";
@@ -19285,6 +19327,47 @@
   static const int SHOW_TEXT = 0x00000004;
 
 }
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DomName('NodeIterator')
+@Unstable()
+class NodeIterator extends NativeFieldWrapperClass1 {
+  factory NodeIterator(Node root, int whatToShow) {
+    return document.$dom_createNodeIterator(root, whatToShow, null, false);
+  }
+
+  @DomName('NodeIterator.pointerBeforeReferenceNode')
+  @DocsEditable()
+  bool get pointerBeforeReferenceNode native "NodeIterator_pointerBeforeReferenceNode_Getter";
+
+  @DomName('NodeIterator.referenceNode')
+  @DocsEditable()
+  Node get referenceNode native "NodeIterator_referenceNode_Getter";
+
+  @DomName('NodeIterator.root')
+  @DocsEditable()
+  Node get root native "NodeIterator_root_Getter";
+
+  @DomName('NodeIterator.whatToShow')
+  @DocsEditable()
+  int get whatToShow native "NodeIterator_whatToShow_Getter";
+
+  @DomName('NodeIterator.detach')
+  @DocsEditable()
+  void detach() native "NodeIterator_detach_Callback";
+
+  @DomName('NodeIterator.nextNode')
+  @DocsEditable()
+  Node nextNode() native "NodeIterator_nextNode_Callback";
+
+  @DomName('NodeIterator.previousNode')
+  @DocsEditable()
+  Node previousNode() native "NodeIterator_previousNode_Callback";
+
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
@@ -25765,6 +25848,73 @@
   String get pseudoElement native "TransitionEvent_pseudoElement_Getter";
 
 }
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DomName('TreeWalker')
+@Unstable()
+class TreeWalker extends NativeFieldWrapperClass1 {
+  factory TreeWalker(Node root, int whatToShow) {
+    return document.$dom_createTreeWalker(root, whatToShow, null, false);
+  }
+
+  @DomName('TreeWalker.currentNode')
+  @DocsEditable()
+  Node get currentNode native "TreeWalker_currentNode_Getter";
+
+  @DomName('TreeWalker.currentNode')
+  @DocsEditable()
+  void set currentNode(Node value) native "TreeWalker_currentNode_Setter";
+
+  @DomName('TreeWalker.expandEntityReferences')
+  @DocsEditable()
+  // http://dom.spec.whatwg.org/#dom-traversal
+  @deprecated // deprecated
+  bool get expandEntityReferences native "TreeWalker_expandEntityReferences_Getter";
+
+  @DomName('TreeWalker.filter')
+  @DocsEditable()
+  NodeFilter get filter native "TreeWalker_filter_Getter";
+
+  @DomName('TreeWalker.root')
+  @DocsEditable()
+  Node get root native "TreeWalker_root_Getter";
+
+  @DomName('TreeWalker.whatToShow')
+  @DocsEditable()
+  int get whatToShow native "TreeWalker_whatToShow_Getter";
+
+  @DomName('TreeWalker.firstChild')
+  @DocsEditable()
+  Node firstChild() native "TreeWalker_firstChild_Callback";
+
+  @DomName('TreeWalker.lastChild')
+  @DocsEditable()
+  Node lastChild() native "TreeWalker_lastChild_Callback";
+
+  @DomName('TreeWalker.nextNode')
+  @DocsEditable()
+  Node nextNode() native "TreeWalker_nextNode_Callback";
+
+  @DomName('TreeWalker.nextSibling')
+  @DocsEditable()
+  Node nextSibling() native "TreeWalker_nextSibling_Callback";
+
+  @DomName('TreeWalker.parentNode')
+  @DocsEditable()
+  Node parentNode() native "TreeWalker_parentNode_Callback";
+
+  @DomName('TreeWalker.previousNode')
+  @DocsEditable()
+  Node previousNode() native "TreeWalker_previousNode_Callback";
+
+  @DomName('TreeWalker.previousSibling')
+  @DocsEditable()
+  Node previousSibling() native "TreeWalker_previousSibling_Callback";
+
+}
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
diff --git a/sdk/lib/io/eventhandler.dart b/sdk/lib/io/eventhandler.dart
index 003c3ed..376b799 100644
--- a/sdk/lib/io/eventhandler.dart
+++ b/sdk/lib/io/eventhandler.dart
@@ -5,6 +5,7 @@
 part of dart.io;
 
 class _EventHandler {
-  external static void _start();
-  external static _sendData(Object sender, ReceivePort receivePort, int data);
+  external static void _sendData(Object sender,
+                                 ReceivePort receivePort,
+                                 int data);
 }
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 6e56e3e..4939a629b 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -21,7 +21,6 @@
   static Timer _createTimer(void callback(Timer timer),
                             int milliSeconds,
                             bool repeating) {
-    _EventHandler._start();
     _Timer timer = new _Timer._internal();
     timer._callback = callback;
     timer._wakeupTime =
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 49c0eb8..3cfc4fc 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -2,6 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+/**
+ * Concurrent programming using _isolates_:
+ * independent workers that are similar to threads
+ * but don't share memory,
+ * communicating only via messages.
+ *
+ * See also:
+ * [dart:isolate - Concurrency with Isolates](https://www.dartlang.org/docs/dart-up-and-running/contents/ch03.html#ch03-dartisolate---concurrency-with-isolates)
+ * in the library tour.
+ */
 library dart.isolate;
 
 import "dart:async";
@@ -15,43 +25,53 @@
 }
 
 /**
- * The initial [ReceivePort] available by default for this isolate. This
- * [ReceivePort] is created automatically and it is commonly used to establish
- * the first communication between isolates (see [spawnFunction] and
- * [spawnUri]).
+ * The initial ReceivePort available by default for this isolate.
+ *
+ * This ReceivePort is created automatically
+ * and is commonly used to establish
+ * the first communication between isolates.
+ * (See [spawnFunction] and [spawnUri].)
  */
 ReceivePort get port => _Isolate.port;
 
 /**
- * Creates and spawns an isolate that shares the same code as the current
- * isolate, but that starts from [topLevelFunction]. The [topLevelFunction]
- * argument must be a static top-level function or a static method that takes no
+ * Creates and spawns an isolate
+ * that shares the same code as the current isolate,
+ * but that starts from the specified function.
+ *
+ * The [topLevelFunction] argument must be
+ * a static top-level function or a static method that takes no
  * arguments. It is illegal to pass a function closure.
  *
  * When any isolate starts (even the main script of the application), a default
  * [ReceivePort] is created for it. This port is available from the top-level
  * getter [port] defined in this library.
  *
- * [spawnFunction] returns a [SendPort] derived from the child isolate's default
- * port.
+ * This function returns a [SendPort] derived from
+ * the child isolate's default port.
  *
  * The optional [unhandledExceptionCallback] argument is invoked whenever an
  * exception inside the isolate is unhandled. It can be seen as a big
  * `try/catch` around everything that is executed inside the isolate. The
- * callback should return `true` when it was able to handled the exception.
+ * callback should return `true` if it was able to handle the exception.
  */
 SendPort spawnFunction(void topLevelFunction(),
     [bool unhandledExceptionCallback(IsolateUnhandledException e)])
     => _Isolate.spawnFunction(topLevelFunction, unhandledExceptionCallback);
 
 /**
- * Creates and spawns an isolate whose code is available at [uri].  Like with
- * [spawnFunction], the child isolate will have a default [ReceivePort], and a
- * this function returns a [SendPort] derived from it.
+ * Creates and spawns an isolate that runs the code from the specified URI.
+ *
+ * As with [spawnFunction],
+ * the child isolate has a default [ReceivePort],
+ * and this function returns a [SendPort] derived from it.
  */
 SendPort spawnUri(String uri) => _Isolate.spawnUri(uri);
 
 /**
+ * Together with [ReceivePort],
+ * the only means of communication between isolates.
+ *
  * [SendPort]s are created from [ReceivePort]s. Any message sent through
  * a [SendPort] is delivered to its respective [ReceivePort]. There might be
  * many [SendPort]s for the same [ReceivePort].
@@ -105,8 +125,10 @@
 }
 
 /**
- * [ReceivePort]s, together with [SendPort]s, are the only means of
- * communication between isolates. [ReceivePort]s have a [:toSendPort:] method
+ * Together with [SendPort], the only means of
+ * communication between isolates.
+ *
+ * [ReceivePort]s have a [:toSendPort:] method
  * which returns a [SendPort]. Any message that is sent through this [SendPort]
  * is delivered to the [ReceivePort] it has been created from. There, they are
  * dispatched to the callback that has been registered on the receive port.
diff --git a/sdk/lib/isolate/isolate_stream.dart b/sdk/lib/isolate/isolate_stream.dart
index f16271e..922f6f9 100644
--- a/sdk/lib/isolate/isolate_stream.dart
+++ b/sdk/lib/isolate/isolate_stream.dart
@@ -5,16 +5,17 @@
 part of dart.isolate;
 
 /**
- * The initial [IsolateStream] available by default for this isolate. This
- * [IsolateStream] is created automatically and it is commonly used to establish
- * the first communication between isolates (see [streamSpawnFunction] and
- * [streamSpawnUri]).
+ * The initial IsolateStream available by default for this isolate.
+ *
+ * This IsolateStream is created automatically and is commonly used
+ * to establish the first communication between isolates.
+ * (See [streamSpawnFunction].)
  */
 final IsolateStream stream = new IsolateStream._fromOriginalReceivePort(port);
 
 /**
- * A [MessageBox] creates an [IsolateStream], [stream], and an [IsolateSink],
- * [sink].
+ * The creator of the [IsolateStream] and [IsolateSink]
+ * that allow an isolate to exchange messages with other isolates.
  *
  * Any message that is written into the [sink] (independent of the isolate) is
  * sent to the [stream] where its subscribers can react to the messages.
@@ -30,8 +31,10 @@
 external bool _isCloseToken(var object);
 
 /**
- * [IsolateStream]s, together with [IsolateSink]s, are the only means of
- * communication between isolates. Each IsolateStream has a corresponding
+ * Together with [IsolateSink], the only means of
+ * communication between isolates.
+ *
+ * Each IsolateStream has a corresponding
  * [IsolateSink]. Any message written into that sink will be delivered to
  * the stream and then dispatched to the stream's subscribers.
  */
@@ -64,7 +67,7 @@
   }
 
   /**
-   * Close the stream from the receiving end.
+   * Closes the stream from the receiving end.
    *
    * Closing an already closed port has no effect.
    */
@@ -88,9 +91,11 @@
 }
 
 /**
- * [IsolateSink]s represent the feed for [IsolateStream]s. Any message written
- * to [this] is delivered to its respective [IsolateStream]. [IsolateSink]s are
- * created by [MessageBox]es.
+ * The feed for an [IsolateStream].
+ * 
+ * Any message written to [this] is delivered
+ * to its respective [IsolateStream].
+ * [IsolateSink]s are created by [MessageBox]es.
  *
  * [IsolateSink]s can be transmitted to other isolates.
  */
@@ -99,8 +104,8 @@
   // control).
 
   /**
-   * Sends an asynchronous [message] to the linked [IsolateStream]. The message
-   * is copied to the receiving isolate.
+   * Sends an asynchronous [message] to the linked [IsolateStream];
+   * the message is copied to the receiving isolate.
    *
    * The content of [message] can be: primitive values (null, num, bool, double,
    * String), instances of [IsolateSink]s, and lists and maps whose elements are
@@ -129,9 +134,10 @@
 
 /**
  * Creates and spawns an isolate that shares the same code as the current
- * isolate, but that starts from [topLevelFunction]. The [topLevelFunction]
- * argument must be a static top-level function or a static method that takes no
- * arguments.
+ * isolate, but that starts from the specified function.
+ * 
+ * The [topLevelFunction] argument must be
+ * a static top-level function or a static method that takes no arguments.
  *
  * When any isolate starts (even the main script of the application), a default
  * [IsolateStream] is created for it. This sink is available from the top-level
@@ -143,7 +149,7 @@
  * The optional [unhandledExceptionCallback] argument is invoked whenever an
  * exception inside the isolate is unhandled. It can be seen as a big
  * `try/catch` around everything that is executed inside the isolate. The
- * callback should return `true` when it was able to handled the exception.
+ * callback should return `true` if it was able to handle the exception.
  */
 external IsolateSink streamSpawnFunction(
     void topLevelFunction(),
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index c22d3c3..66b9abd 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -135,7 +135,8 @@
  * This function returns a [ClassMirror] reflecting *C*.
  *
  * If [key] is not an instance of [Type] then this function
- * throws an [ArgumentError].
+ * throws an [ArgumentError]. If [key] is the Type dynamic,
+ * throws an [ArgumentError] because dynamic is not a class.
  *
  * Note that since one cannot obtain a [Type] object from
  * another isolate, this function can only be used to
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 4d9ef03..843ace1 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -227,6 +227,10 @@
 # co19 issue #531, void f(void f()) {f();} is error. Gilad: The formal parameter conflicts with the name of the function.
 Language/13_Statements/04_Local_Function_Declaration_A01_t01: fail, OK
 
+# co19 issue #541: tests contain unqualified reference to static members defined in superclass
+Language/12_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t07: fail, OK
+Language/12_Expressions/30_Identifier_Reference_A14_t03: fail, OK
+
 
 # co19-roll r546 (11.08.2013) caused these failures
 Language/13_Statements/11_Return_A07_t01: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 97bece2..3d31a9d 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -64,8 +64,11 @@
 Utils/tests/Expect/listEquals_A03_t01: FAIL, OK # co19 issue 500
 Utils/tests/Expect/setEquals_A02_t01: FAIL, OK # co19 issue 499
 
-LibTest/isolate_api/streamSpawnFunction_A02_t02: Pass, Fail # co19 issue 540
-LibTest/isolate_api/streamSpawnFunction_A02_t03: Pass, Fail # co19 issue 540
+LibTest/isolate_api/streamSpawnFunction_A02_t02: PASS, FAIL, OK # co19 issue 540
+LibTest/isolate_api/streamSpawnFunction_A02_t03: PASS, FAIL, OK # co19 issue 540
+LibTest/isolate/IsolateStream/contains_A02_t01: PASS, FAIL, OK # co19 issue 540
+
+LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # co19 issue 542
 
 ### CHECKED MODE FAILURES ###
 
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index e373794..82ddff6 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -200,7 +200,6 @@
 
 [ $compiler == dart2js && $runtime == ie9 ]
 LibTest/math/cos_A01_t01: Fail # co19 issue 44
-LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # Issue 12595
 
 #
 # The following tests are failing. Please add the error message
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index c52aec6..3e06a4b 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -104,7 +104,6 @@
 
 [ $compiler == none && $runtime == vm && $mode == debug ]
 LibTest/isolate/isolate_api/spawnFunction_A02_t01: Crash
-Language/12_Expressions/00_Object_Identity/1_Object_Identity_A04_t02: Crash # co19-roll r546: Please triage this failure
 LibTest/async/Stream/Stream.periodic_A03_t01: Fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateStream/contains_A02_t01: Fail # co19-roll r546: Please triage this failure
 
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 4e70d58..3e81bd4 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -24,6 +24,7 @@
 
 [ $compiler == dart2js && $runtime == ie9 ]
 class_test: Fail
+deferred/deferred_function_test: Pass, Fail, Timeout # Issue 12635
 
 [ $compiler == dart2js && $runtime == none ]
 *: Fail, Pass # TODO(ahe): Triage these tests.
diff --git a/tests/html/html.status b/tests/html/html.status
index 7c00a70..b3c80c6 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -2,10 +2,6 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# Skipped for in-progress Dartium rull on 8-16-2013
-node_test/iterating: Fail
-websocket_test: skip
-
 async_window_test: Skip #TODO(gram): investigating
 event_test: Skip  # Issue 1996
 interactive_test: Skip # Must be run manually.
@@ -23,10 +19,10 @@
 [ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 # postMessage in dartium always transfers the typed array buffer, never a view
 postmessage_structured_test/typed_arrays: Fail
-custom_elements_test/lifecycle: Fail   # Issue 9326 - Implement "extends Element" in dartium
-# Issue 9326 failures
-custom/attribute_changed_callback_test: Fail
-custom/created_callback_test: Fail
+xhr_test: Pass, Fail # Issue 12648
+custom_elements_test/lifecycle: Fail # Issue 12642
+custom/attribute_changed_callback_test: Fail # 12643
+custom/created_callback_test: Fail # Issue 12642
 
 [ $compiler == none && $runtime == drt && $system == windows ]
 worker_test/functional: Pass, Crash # Issue 9929.
diff --git a/tests/html/websocket_test.dart b/tests/html/websocket_test.dart
index 752856c..2e02761 100644
--- a/tests/html/websocket_test.dart
+++ b/tests/html/websocket_test.dart
@@ -19,7 +19,7 @@
 
     test('constructorTest', () {
       expect(() {
-        var socket = new WebSocket('ws://localhost');
+        var socket = new WebSocket('ws://localhost/ws', 'chat');
         expect(socket, isNotNull);
         expect(socket, isWebSocket);
         }, expectation);
@@ -27,7 +27,8 @@
 
     if (WebSocket.supported) {
       test('echo', () {
-        var socket = new WebSocket('ws://${window.location.host}/ws', 'chat');
+        var socket = new WebSocket('ws://${window.location.host}/ws');
+
         socket.onOpen.first.then((_) {
           socket.send('hello!');
         });
diff --git a/tests/html/xhr_test.dart b/tests/html/xhr_test.dart
index d47707f..1d53209 100644
--- a/tests/html/xhr_test.dart
+++ b/tests/html/xhr_test.dart
@@ -201,7 +201,7 @@
         for (var i = 0; i < data.length; ++i) {
           data[i] = i & 0xFF;
         }
-        xhr.send(data);
+        xhr.send(new Uint8List.view(data.buffer));
 
         return xhr.onLoad.first.then((_) {
           expect(progressCalled, isTrue);
diff --git a/tests/isolate/compute_this_script_browser_stream_test.dart b/tests/isolate/browser/compute_this_script_browser_stream_test.dart
similarity index 90%
rename from tests/isolate/compute_this_script_browser_stream_test.dart
rename to tests/isolate/browser/compute_this_script_browser_stream_test.dart
index a6f5173..509614e 100644
--- a/tests/isolate/compute_this_script_browser_stream_test.dart
+++ b/tests/isolate/browser/compute_this_script_browser_stream_test.dart
@@ -9,8 +9,8 @@
 
 import 'dart:html';
 import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
 
 child() {
   var sink;
diff --git a/tests/isolate/compute_this_script_browser_test.dart b/tests/isolate/browser/compute_this_script_browser_test.dart
similarity index 90%
rename from tests/isolate/compute_this_script_browser_test.dart
rename to tests/isolate/browser/compute_this_script_browser_test.dart
index e91d4a9..74cd118 100644
--- a/tests/isolate/compute_this_script_browser_test.dart
+++ b/tests/isolate/browser/compute_this_script_browser_test.dart
@@ -9,8 +9,8 @@
 
 import 'dart:html';
 import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
 
 child() {
   port.receive((msg, reply) {
diff --git a/tests/isolate/ports_compilation_browser_test.dart b/tests/isolate/browser/ports_compilation_browser_test.dart
similarity index 91%
rename from tests/isolate/ports_compilation_browser_test.dart
rename to tests/isolate/browser/ports_compilation_browser_test.dart
index 5ab16ab..5eb76d7 100644
--- a/tests/isolate/ports_compilation_browser_test.dart
+++ b/tests/isolate/browser/ports_compilation_browser_test.dart
@@ -8,19 +8,19 @@
 library ports_compilation;
 import 'dart:html';
 import 'dart:isolate';
-import '../../pkg/unittest/lib/unittest.dart';
-import '../../pkg/unittest/lib/html_config.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
 
 void foo() {
   // Create a "SendPortSync" object and access one of its members.
   SendPortSync s_port;
   s_port.callSync;
-  
+
   // Create a "ReceivePortSync" object (with the constructor) and
   // access one of its members.
   var r_port = new ReceivePortSync();
   r_port.receive;
-  
+
   // Call getComputedStyle() from the HTML library.
   query("").getComputedStyle("");
 }
diff --git a/tests/isolate/typed_data_message_test.dart b/tests/isolate/browser/typed_data_message_test.dart
similarity index 97%
rename from tests/isolate/typed_data_message_test.dart
rename to tests/isolate/browser/typed_data_message_test.dart
index b725b1c..38e7815 100644
--- a/tests/isolate/typed_data_message_test.dart
+++ b/tests/isolate/browser/typed_data_message_test.dart
@@ -8,7 +8,7 @@
 library TypedDataMessageTest;
 import 'dart:isolate';
 import 'dart:typed_data';
-import '../../pkg/unittest/lib/unittest.dart';
+import 'package:unittest/unittest.dart';
 
 // ---------------------------------------------------------------------------
 // Message passing test.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 3655cf9..df59051 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -3,43 +3,31 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $runtime == vm ]
-isolate2_negative_test: Skip  # Need to resolve correct behaviour.
-isolate3_negative_test: Skip  # test depends on isolate error exiting process.
-serialization_test: Skip  # tests dart2js-specific serialization code
-spawn_uri_test: Fail, OK # test uses a ".js" suffix that is bogus on vm.
-compute_this_script_browser_test: Skip # browser specific test
-compute_this_script_browser_stream_test: Skip # browser specific test
-ports_compilation_browser_test: Skip # browser specific test
-unresolved_ports_negative_test: Skip # See Issue 6839
-isolate_stress_test: Fail # TODO(ahe): This should be able to pass when we have wrapper-less tests.
+browser/*: SkipByDesign  # Browser specific tests
+unresolved_ports_negative_test: Skip # Issue 6839
+isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
 
-[ $compiler == none && $runtime == drt ]
-isolate2_negative_test: Skip  # Inherited from VM.
-isolate3_negative_test: Skip  # Inherited from VM.
-serialization_test: Skip  # tests dart2js-specific serialization code
-spawn_uri_test: Skip # uses a .js extension (not for dartium)
-spawn_uri_negative_test: Skip # ditto
+[ $compiler == none ]
+serialization_test: SkipByDesign # Tests dart2js-specific serialization code
+spawn_uri_test: SkipByDesign # Test uses a ".js" URI.
+spawn_uri_negative_test: SkipByDesign # Test uses a ".js" URI.
+isolate2_negative_test: Skip  # Issue 12587.
+isolate3_negative_test: Skip  # Issue 12587.
 
-[ $compiler == dartanalyzer ]
-isolate2_negative_test: fail
-isolate_negative_test: fail
-spawn_function_negative_test: fail
-spawn_uri_negative_test: fail
-spawn_uri_vm_negative_test: fail
-unresolved_ports_negative_test: fail
+[ $analyzer ]
+isolate2_negative_test: Fail
+isolate_negative_test: Fail
+spawn_function_negative_test: Fail
+spawn_uri_negative_test: Fail
+spawn_uri_vm_negative_test: Fail
+unresolved_ports_negative_test: Fail
 
 [ $compiler == dart2analyzer ]
-isolate2_negative_test: fail
-isolate_import_negative_test: fail
-isolate_negative_test: fail
-spawn_function_negative_test: fail
-spawn_uri_negative_test: fail
-spawn_uri_vm_negative_test: fail
-unresolved_ports_negative_test: fail
+isolate_import_negative_test: Fail
 
-[ $compiler == dart2js && ($runtime == d8 || $jscl) ]
+[ $compiler == dart2js && $jscl ]
+browser/*: SkipByDesign  # Browser specific tests
 illegal_msg_stream_test: Fail # Issue 6750
-typed_data_message_test: Fail, OK # DataView only supported in browsers.
 
 [ $compiler == dart2js && $browser ]
 illegal_msg_stream_test: Fail, Pass # Issue 6750
@@ -48,50 +36,54 @@
 unresolved_ports_negative_test: Pass, Crash # Issue 10613
 
 [ $compiler == dart2js ]
-serialization_test: Fail # Tries to access class TestingOnly declared in isolate_patch.dart
+serialization_test: Fail # Issue 1882, tries to access class TestingOnly declared in isolate_patch.dart
 illegal_msg_test: Fail # Issue 6750
 stream_mangling_test: Fail # Issue 9245
 
-global_error_handler_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler_stream_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler2_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
-global_error_handler_stream2_test: Pass, Fail # http://dartbug.com/9012 and http://dartbug.com/9024
+global_error_handler_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler_stream_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler2_test: Pass, Fail # Issue 9012, Issue 9024
+global_error_handler_stream2_test: Pass, Fail # Issue 9012, Issue 9024
 
 [ $compiler == dart2js && ($runtime == drt || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == ie9 || $runtime == ie10 || $runtime == safari) ]
-typed_data_message_test: Fail
+browser/typed_data_message_test: Fail # Issue 12624
 
-[ $runtime == safari ]
-cross_isolate_message_test: Skip      # Depends on 32/64 bit Safari. See Issue 1120
-message_test: Skip
+[ $compiler == dart2js && $runtime == safari ]
+cross_isolate_message_test: Skip # Issue 12627
+message_test: Skip # Issue 12627
 
-[ $runtime == opera ]
-isolate2_negative_test: Skip # Timeout.
-unresolved_ports_negative_test: Skip # See Issue 6839
+[ $compiler == dart2js && $runtime == opera ]
+isolate2_negative_test: Skip # Issue 12625
+unresolved_ports_negative_test: Skip # Issue 12626
+
+[ $compiler == dart2js ]
+spawn_uri_vm_test: SkipByDesign # Test uses a ".dart" URI.
+spawn_uri_nested_vm_test: SkipByDesign # Test uses a ".dart" URI.
+spawn_uri_vm_negative_test: SkipByDesign # Test uses a ".dart" URI.
 
 [ $compiler == dart2js && $browser ]
-spawn_uri_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_nested_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_vm_negative_test: Skip # ditto above.
 isolate2_negative_test: Fail, Pass # Issue 7769
 
 [ $compiler == dart2js && $jscl ]
-spawn_uri_negative_test: Pass # for the wrong reasons (not supported in d8)
-spawn_uri_test: Fail, OK # loading another file is not supported in d8
-spawn_uri_vm_negative_test: Skip # ditto above.
-spawn_uri_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
-spawn_uri_nested_vm_test: Skip # test uses a ".dart" suffix that only works in vm.
+spawn_uri_test: SkipByDesign # Loading another file is not supported in JS shell
 
 [ $compiler == dart2js && $runtime == ie9 ]
-spawn_uri_test: Fail
+spawn_uri_test: Fail # Issue 12630
 
 [ $compiler == dart2js && $runtime == none ]
-*: Fail, Pass # TODO(ahe): Triage these tests.
+spawn_function_negative_test: Fail # Issue 12628
+spawn_uri_negative_test: Fail # Issue 12628
+unresolved_ports_negative_test: Fail # Issue 12628
+stream_mangling_test: Pass # Issue 12628
+isolate_negative_test: Fail # Issue 12628
+serialization_test: Pass # Issue 12628
+isolate_import_negative_test: Fail # Issue 12628
+isolate2_negative_test: Fail # Issue 12628
+illegal_msg_test: Pass # Issue 12628
 
 [ $compiler == dart2dart ]
-# Skip until we stabilize language tests.
-*: Skip
+*: Skip # Issue 12629
 
-# TODO(ajohnsen): Fix this as part of library changes.
 [ $compiler == none ]
 isolate_negative_test: Skip # Bug 6890
 
@@ -100,18 +92,13 @@
 mandel_isolate_stream_test: Pass, Fail, Timeout # Issue 7952
 
 [ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome ) ]
-isolate_stress_test: Pass, Slow # http://dartbug.com/10697
+isolate_stress_test: Pass, Slow # Issue 10697
 
 [ $arch == arm || $arch == simarm ]
-*: Skip
+*: Skip # Issue 12589
 
-[ $arch == mips ]
-*: Skip
-
-[ $arch == simmips ]
-*: Skip
+[ $arch == mips || $arch == simmips ]
+*: Skip # Issue 12590
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium) ]
-# Skipped for in-progress Dartium rull on 8-16-2013
-isolate_stress_test: Skip
-
+isolate_stress_test: Skip # Issue 12537
diff --git a/tests/isolate/isolate_stress_test.dart b/tests/isolate/isolate_stress_test.dart
index 84a3447..f00e457 100644
--- a/tests/isolate/isolate_stress_test.dart
+++ b/tests/isolate/isolate_stress_test.dart
@@ -9,7 +9,7 @@
 import 'dart:async';
 import 'dart:isolate';
 
-// TODO(ahe): Remove this import when we have wrapper-less testing.
+// TODO(12588): Remove this import when we have wrapper-less testing.
 import 'dart:html';
 
 worker() {
diff --git a/tests/language/final_var_negative_test.dart b/tests/language/final_var_negative_test.dart
deleted file mode 100644
index 62d4e53..0000000
--- a/tests/language/final_var_negative_test.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// Disallow re-assignment of a final local variable.
-
-main() {
-  final x = 1;
-  x = 2;  // <- reassignment not allowed.
-  return x;
-}
diff --git a/tests/language/final_variable_assignment_test.dart b/tests/language/final_variable_assignment_test.dart
index f173747..f195c75 100644
--- a/tests/language/final_variable_assignment_test.dart
+++ b/tests/language/final_variable_assignment_test.dart
@@ -6,8 +6,8 @@
 
 main() {
   final x = 30;
-  x = 0;    /// 01: compile-time error
-  x += 1;   /// 02: compile-time error
-  ++x;      /// 03: compile-time error
-  x++;      /// 04: compile-time error
+  x = 0;    /// 01: static type warning, runtime error
+  x += 1;   /// 02: static type warning, runtime error
+  ++x;      /// 03: static type warning, runtime error
+  x++;      /// 04: static type warning, runtime error
 }
diff --git a/tests/language/language.status b/tests/language/language.status
index cdac989..70f61d0 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -6,55 +6,44 @@
 # current state of the language.
 
 [ $compiler == dart2js && ($runtime == ie9 || $runtime == ie10) ]
-licm2_test: Skip # Issue: 12298
+licm2_test: Skip # Issue 12298
 
 [ $compiler == dart2dart ]
-mixin_super_constructor_named_test: Fail
-mixin_super_constructor_positionals_test: Fail
+mixin_super_constructor_named_test: Fail # Issue 12631
+mixin_super_constructor_positionals_test: Fail # Issue 12631
 function_type_alias6_test/00: Fail # Issue 11986
 function_type_alias9_test/00: Crash # Issue 11986
 
 [ $compiler == none ]
-mixin_super_constructor_named_test: Fail
-mixin_super_constructor_positionals_test: Fail
-built_in_identifier_prefix_test: Fail # http://dartbug.com/6970
+mixin_super_constructor_named_test: Fail # Issue 12631
+mixin_super_constructor_positionals_test: Fail # Issue 12631
+built_in_identifier_prefix_test: Fail # Issue 6970
 library_juxtaposition_test: Fail # Issue 6877
 switch_int_double_test/01: Fail # Issue 7307
 switch_int_double_test/02: Fail # Issue 7307
 
 # These bugs refer currently ongoing language discussions.
-constructor5_test: Fail           # (Discussion ongoing)
-
-constructor_initializer_test: Fail # Side effects in constructor parameters
-
-constructor6_test: Fail           # Issue 6422
+constructor_initializer_test: Fail # Issue 12633
+constructor5_test: Fail # Issue 6422
+constructor6_test: Fail # Issue 6422
 closure_in_initializer_test: Fail # Issue 6422
 
 # Regular bugs which should be fixed.
 super_first_constructor_test: Fail # Issue 1372.
-
 parameter_initializer6_negative_test: Fail # Issue 3502
-
-named_parameters_aggregated_test/05: Fail # Compile-time error reported instead of static type warning.
-
 lazy_static3_test: Fail # Issue 12593
-
-export_cyclic_test: Fail, Crash # issue 6060
-duplicate_export_negative_test: Fail # issue 6134
-
+export_cyclic_test: Fail, Crash # Issue 6060
+duplicate_export_negative_test: Fail # Issue 6134
 on_catch_malformed_type_test: Fail # Issue 8601
-
-mixin_mixin_test: Fail
-mixin_issue10216_2_test: Fail
+mixin_mixin_test: Fail # Issue 12636
+mixin_issue10216_2_test: Fail # Issue 12636
 mixin_illegal_object_test/01: Crash # Issue 10952
 mixin_illegal_object_test/02: Crash # Issue 10952
-
 mixin_forwarding_constructor2_test: Fail # Issue 11888
 mixin_typedef_constructor_test: Fail # Issue 11888
 mixin_type_parameter2_test: Fail # Issue 11888
 
 [ $compiler == none && $unchecked ]
-
 # Only checked mode reports an error on type assignment
 # problems in compile time constants.
 compile_time_constant_checked_test/02: Fail, OK
@@ -71,18 +60,9 @@
 compile_time_constant_checked3_test/05: Fail, OK
 compile_time_constant_checked3_test/06: Fail, OK
 
-
-[ $compiler == none && $runtime == drt ]
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
-
-
 [ $runtime == dartium ]
 import_combinators_test: Fail
 
-
 [ $runtime == vm || ($runtime == drt && $compiler == none) ]
 first_class_types_literals_test: Fail # issue 11761
 call_test: Fail # Issue 12602
@@ -144,12 +124,6 @@
 setter_override_test/03: Fail # Issue 11496
 setter_override2_test/02: Fail # Issue 11496
 
-# Missing compile-time error when modifying final local variables
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
-
 compile_time_constant10_test/01: Fail # http://dartbug.com/5519
 compile_time_constant10_test/02: Fail # http://dartbug.com/5519
 compile_time_constant_arguments_test/01: Fail # http://dartbug.com/5519
@@ -190,7 +164,6 @@
 # declarations are simply not parsed.  In pseudo kw dart2js
 # chokes on things like typedef(x) => "typedef $x" and alike.
 abstract_syntax_test/01: Fail
-abstract_syntax_test/02: Fail
 pseudo_kw_test: Fail
 # external keyword is not yet supported by dart2js/dart2dart.
 external_test/*: Skip
@@ -235,8 +208,6 @@
 # TODO(antonm): proper support in test framework.
 no_such_method_test: Pass, Fail, OK # Hard codes the name of invoked method ("foo").
 
-named_parameters_aggregated_test/05: Fail # Compile-time error reported instead of static type warning.
-
 new_expression_type_args_test/00: Fail # Wrongly reports compile-time error.
 new_expression_type_args_test/01: Fail # Wrongly reports compile-time error.
 
@@ -248,7 +219,6 @@
 get_set_syntax_test/05: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/06: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/07: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/08: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/13: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 34b721d..381133f 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -60,28 +60,6 @@
 block_scope_test: fail
 lazy_static3_test: fail
 
-# test issue 10890; on-catch UnknownType is a static warning, not error
-try_catch_on_syntax_test/01: fail
-
-# test issue 10899; it is static warning, not error, to call methods of class literal
-class_literal_test/02: fail
-class_literal_test/05: fail
-class_literal_test/07: fail
-class_literal_test/10: fail
-class_literal_test/11: fail
-class_literal_test/12: fail
-class_literal_test/14: fail
-class_literal_test/17: fail
-class_literal_test/18: fail
-class_literal_test/19: fail
-class_literal_test/22: fail
-class_literal_test/23: fail
-class_literal_test/24: fail
-class_literal_test/27: fail
-class_literal_test/28: fail
-class_literal_test/29: fail
-class_literal_test/none: fail
-
 # Test issue 11124, Uninitialized finals are warnings not errors
 field3a_negative_test: fail
 const_syntax_test/01: fail
@@ -127,15 +105,9 @@
 # test issue 11579, assignment, no setter
 getter_no_setter_test/none: fail
 
-# test issue 11580, Function is not a malformed type
-black_listed_test/11: fail
-
 # test issue 11581, it is not warning to call dynamic
 call_through_getter_test: fail
 
-# test issue 11583, int is valid key for constant map literal
-compile_time_constant_c_test/01: fail
-
 # test issue 11584, positional arguments cannot be used for named parameters
 compile_time_constant_e_test: fail
 
@@ -156,11 +128,6 @@
 # test issue 11591, assigning to the final variable is warning, not error
 final_for_in_variable_test/01: fail
 final_param_negative_test: fail
-final_var_negative_test: fail
-final_variable_assignment_test/01: fail
-final_variable_assignment_test/02: fail
-final_variable_assignment_test/03: fail
-final_variable_assignment_test/04: fail
 getter_no_setter_test/01: fail
 
 # test issue 11592, Function type alias (typedef) is not a constant
@@ -261,7 +228,6 @@
 static_field_test/03: fail
 static_field_test/04: fail
 
-null_test/03: Fail  # Issue 12484
 
 [ $compiler == dartanalyzer && $checked ]
 factory1_test/00: fail
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 6a18173..84c6492 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -21,7 +21,6 @@
 
 # TBF: It is a compile-time error if the superclass of a class C appears in the implements clause of C.
 const_constructor_super_test/01: fail
-compile_time_constant_c_test/01: fail
 
 # TBF: m([int p = 'String']) and call 'const' instance creation
 compile_time_constant_checked2_test/03: fail
@@ -103,28 +102,6 @@
 block_scope_test: fail
 lazy_static3_test: fail
 
-# test issue 10890; on-catch UnknownType is a static warning, not error
-try_catch_on_syntax_test/01: fail
-
-# test issue 10899; it is static warning, not error, to call methods of class literal
-class_literal_test/02: fail
-class_literal_test/05: fail
-class_literal_test/07: fail
-class_literal_test/10: fail
-class_literal_test/11: fail
-class_literal_test/12: fail
-class_literal_test/14: fail
-class_literal_test/17: fail
-class_literal_test/18: fail
-class_literal_test/19: fail
-class_literal_test/22: fail
-class_literal_test/23: fail
-class_literal_test/24: fail
-class_literal_test/27: fail
-class_literal_test/28: fail
-class_literal_test/29: fail
-class_literal_test/none: fail
-
 # Test issue 11124, Uninitialized finals are warnings not errors
 field3a_negative_test: fail
 const_syntax_test/01: fail
@@ -175,15 +152,9 @@
 # test issue 11579, assignment, no setter
 getter_no_setter_test/none: fail
 
-# test issue 11580, Function is not a malformed type
-black_listed_test/11: fail
-
 # test issue 11581, it is not warning to call dynamic
 call_through_getter_test: fail
 
-# test issue 11583, int is valid key for constant map literal
-compile_time_constant_c_test/01: fail
-
 # test issue 11584, positional arguments cannot be used for named parameters
 compile_time_constant_e_test: fail
 
@@ -204,11 +175,6 @@
 # test issue 11591, assigning to the final variable is warning, not error
 final_for_in_variable_test/01: fail
 final_param_negative_test: fail
-final_var_negative_test: fail
-final_variable_assignment_test/01: fail
-final_variable_assignment_test/02: fail
-final_variable_assignment_test/03: fail
-final_variable_assignment_test/04: fail
 getter_no_setter_test/01: fail
 
 # test issue 11592, Function type alias (typedef) is not a constant
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index a3223eb..7b31008 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -4,30 +4,6 @@
 
 [ $compiler == dart2js || $compiler == dart2dart ]
 compile_time_constant_c_test/none: Fail # Map literal with int key.
-class_literal_test/01: Fail # Class literals are expression now; delete this test.
-class_literal_test/02: Fail # Class literals are expression now; delete this test.
-class_literal_test/05: Fail # Class literals are expression now; delete this test.
-class_literal_test/06: Fail # Class literals are expression now; delete this test.
-class_literal_test/07: Fail # Class literals are expression now; delete this test.
-class_literal_test/10: Fail # Class literals are expression now; delete this test.
-class_literal_test/11: Fail # Class literals are expression now; delete this test.
-class_literal_test/12: Fail # Class literals are expression now; delete this test.
-class_literal_test/13: Fail # Class literals are expression now; delete this test.
-class_literal_test/14: Fail # Class literals are expression now; delete this test.
-class_literal_test/17: Fail # Class literals are expression now; delete this test.
-class_literal_test/18: Fail # Class literals are expression now; delete this test.
-class_literal_test/19: Fail # Class literals are expression now; delete this test.
-class_literal_test/20: Fail # Class literals are expression now; delete this test.
-class_literal_test/21: Fail # Class literals are expression now; delete this test.
-class_literal_test/22: Fail # Class literals are expression now; delete this test.
-class_literal_test/23: Fail # Class literals are expression now; delete this test.
-class_literal_test/24: Fail # Class literals are expression now; delete this test.
-class_literal_test/25: Fail # Class literals are expression now; delete this test.
-class_literal_test/26: Fail # Class literals are expression now; delete this test.
-class_literal_test/27: Fail # Class literals are expression now; delete this test.
-class_literal_test/28: Fail # Class literals are expression now; delete this test.
-class_literal_test/29: Fail # Class literals are expression now; delete this test.
-
 constructor_initializer_test: Fail, OK # Depends on ?parameter check.
 
 black_listed_test/none: Fail # Issue 12446.
@@ -110,10 +86,6 @@
 left_shift_test: Fail # Issue 1533
 factory_redirection_test/01: Fail
 factory_redirection_test/07: Fail
-final_variable_assignment_test/01: Fail
-final_variable_assignment_test/02: Fail
-final_variable_assignment_test/03: Fail
-final_variable_assignment_test/04: Fail
 bad_override_test/01: Fail # Issue 11496
 bad_override_test/02: Fail # Issue 11496
 bad_override_test/06: Fail # Issue 11496
@@ -166,20 +138,15 @@
 get_set_syntax_test/05: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/06: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/07: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/08: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/13: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/14: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 get_set_syntax_test/15: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
-get_set_syntax_test/16: Fail # Fixed by https://chromiumcodereview.appspot.com/10915111
 method_binding_test: Fail # internal error: super property read not implemented.
 method_override_test: Fail # cannot resolve type GetKeysFunctionType
 method_override5_test: Pass, Fail # Issue 11496 (passes if it's inlined)
-abstract_getter_test/01: Fail # instantiation of abstract class
-abstract_factory_constructor_test/01: Fail # instantiation of abstract class
 parameter_initializer6_negative_test: Fail # Issue 3502
 named_parameters_aggregated_test/01: Fail # Presence of default values for optional params is not properly validated in type definitions.
 named_parameters_aggregated_test/03: Fail # Presence of default values for optional params is not properly validated in closure types.
-named_parameters_aggregated_test/05: Fail # Absence of positional parameters before named parameters does not trigger static type warning.
 pseudo_kw_test: Fail # Unexpected token '('
 super_implicit_closure_test: Fail # internal error: super property read not implemented
 
@@ -195,7 +162,6 @@
 external_test/12: Fail
 external_test/13: Skip  # Runtime error (missing patch).
 external_test/14: Fail
-external_test/15: Fail
 external_test/20: Skip  # Runtime error (missing patch).
 external_test/21: Fail
 external_test/22: Fail
@@ -220,7 +186,6 @@
 # The following tests are all negative tests that should be fixed.
 #
 abstract_syntax_test/01: Fail # Negative language test.
-abstract_syntax_test/02: Fail # Negative language test.
 const_constructor_syntax_test/04: Fail # Negative language test.
 const_syntax_test/04: Fail # Negative language test.
 constructor2_negative_test: Fail # Negative language test.
diff --git a/tests/language/named_parameters_aggregated_test.dart b/tests/language/named_parameters_aggregated_test.dart
index 4e61963..a743569 100644
--- a/tests/language/named_parameters_aggregated_test.dart
+++ b/tests/language/named_parameters_aggregated_test.dart
@@ -49,7 +49,7 @@
   );
 
   // Expect compile-time error due to missing positional argument.
-  NamedParametersAggregatedTests.F31(b:25, c:35);  /// 05: static type warning
+  Expect.throws(() => NamedParametersAggregatedTests.F31(b:25, c:35), (e) => e is NoSuchMethodError);  /// 05: static type warning
 
   new TypeTester<Callback>();
 
diff --git a/tests/lib/convert/ascii_test.dart b/tests/lib/convert/ascii_test.dart
new file mode 100644
index 0000000..239130f
--- /dev/null
+++ b/tests/lib/convert/ascii_test.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+var asciiStrings = [
+  "pure ascii",
+  "\x00 with control characters \n",
+  "\x01 edge cases \x7f"
+];
+
+var nonAsciiStrings = [
+  "\x80 edge case first",
+  "Edge case ASCII \u{80}",
+  "Edge case byte \u{ff}",
+  "Edge case super-BMP \u{10000}"
+];
+
+void main() {
+  // Build longer versions of the example strings.
+  for (int i = 0, n = asciiStrings.length; i < n ; i++) {
+    var string = asciiStrings[i];
+    while (string.length < 1024) {
+      string += string;
+    }
+    asciiStrings.add(string);
+  }
+  for (int i = 0, n = nonAsciiStrings.length; i < n ; i++) {
+    var string = nonAsciiStrings[i];
+    while (string.length < 1024) {
+      string += string;
+    }
+    nonAsciiStrings.add(string);
+  }
+  testDirectConversions();
+  testChunkedConversions();
+}
+
+void testDirectConversions() {
+  for (var codec in [ASCII, new AsciiCodec()]) {
+    for (var asciiString in asciiStrings) {
+      List bytes = codec.encoder.convert(asciiString);
+      Expect.listEquals(asciiString.codeUnits.toList(), bytes, asciiString);
+      String roundTripString = codec.decoder.convert(bytes);
+      Expect.equals(asciiString, roundTripString);
+      roundTripString = codec.decode(bytes);
+      Expect.equals(asciiString, roundTripString);
+    }
+
+    for (var nonAsciiString in nonAsciiStrings) {
+      Expect.throws(() {
+        print(codec.encoder.convert(nonAsciiString));
+      }, null, nonAsciiString);
+    }
+  }
+
+  var allowInvalidCodec = new AsciiCodec(allowInvalid: true);
+  var invalidBytes = [0, 1, 0xff, 0xdead, 0];
+  String decoded = allowInvalidCodec.decode(invalidBytes);
+  Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+  decoded = allowInvalidCodec.decoder.convert(invalidBytes);
+  Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+  decoded = ASCII.decode(invalidBytes, allowInvalid: true);
+  Expect.equals("\x00\x01\uFFFD\uFFFD\x00", decoded);
+}
+
+List<int> encode(String str, int chunkSize,
+                 Converter<String, List<int>> converter) {
+  List<int> bytes = <int>[];
+  ChunkedConversionSink byteSink =
+      new ByteConversionSink.withCallback(bytes.addAll);
+  var stringConversionSink = converter.startChunkedConversion(byteSink);
+  for (int i = 0; i < str.length; i += chunkSize) {
+    if (i + chunkSize <= str.length) {
+      stringConversionSink.add(str.substring(i, i + chunkSize));
+    } else {
+      stringConversionSink.add(str.substring(i));
+    }
+  }
+  stringConversionSink.close();
+  return bytes;
+}
+
+String decode(List<int> bytes, int chunkSize,
+              Converter<List<int>, String> converter) {
+  StringBuffer buf = new StringBuffer();
+  var stringSink =
+      new StringConversionSink.fromStringSink(buf);
+  var byteConversionSink = converter.startChunkedConversion(stringSink);
+  for (int i = 0; i < bytes.length; i += chunkSize) {
+    if (i + chunkSize <= bytes.length) {
+      byteConversionSink.add(bytes.sublist(i, i + chunkSize));
+    } else {
+      byteConversionSink.add(bytes.sublist(i));
+    }
+  }
+  byteConversionSink.close();
+  return buf.toString();
+}
+
+void testChunkedConversions() {
+  // Check encoding.
+  for (var converter in [ASCII.encoder,
+                         new AsciiCodec().encoder,
+                         new AsciiEncoder()]) {
+    for (int chunkSize in [1, 2, 5, 50]) {
+      for (var asciiString in asciiStrings) {
+        var units = asciiString.codeUnits.toList();
+        List bytes = encode(asciiString, chunkSize, converter);
+        Expect.listEquals(units, bytes);
+      }
+      for (var nonAsciiString in nonAsciiStrings) {
+        Expect.throws(() {
+          encode(nonAsciiStrings, chunkSize, converter);
+        });
+      }
+    }
+  }
+  // Check decoding.
+  for (var converter in [ASCII.decoder,
+                         new AsciiCodec().decoder,
+                         new AsciiDecoder()]) {
+    for (int chunkSize in [1, 2, 5, 50]) {
+      for (var asciiString in asciiStrings) {
+        var units = asciiString.codeUnits.toList();
+        Expect.equals(asciiString, decode(units, chunkSize, converter));
+      }
+      for (var nonAsciiString in nonAsciiStrings) {
+        var units = nonAsciiString.codeUnits.toList();
+        Expect.throws(() {
+          decode(units, chunkSize, converter);
+        });
+      }
+    }
+  }
+}
diff --git a/tests/lib/convert/chunked_conversion_utf89_test.dart b/tests/lib/convert/chunked_conversion_utf89_test.dart
new file mode 100644
index 0000000..a045124
--- /dev/null
+++ b/tests/lib/convert/chunked_conversion_utf89_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+class MySink extends ChunkedConversionSink<String> {
+  final Function _add;
+  final Function _close;
+
+  MySink(this._add, this._close);
+
+  void add(x) { _add(x); }
+  void close() { _close(); }
+}
+
+main() {
+  // Make sure the UTF-8 decoder works eagerly.
+  String lastString;
+  bool isClosed = false;
+  ChunkedConversionSink sink = new MySink((x) => lastString = x,
+                                          () => isClosed = true);
+  var byteSink = new Utf8Decoder().startChunkedConversion(sink);
+  byteSink.add("abc".codeUnits);
+  Expect.equals("abc", lastString);
+  byteSink.add([0x61, 0xc3]);  // 'a' followed by first part of Î.
+  Expect.equals("a", lastString);
+  byteSink.add([0x8e]);  // second part of Î.
+  Expect.equals("Î", lastString);
+  Expect.isFalse(isClosed);
+  byteSink.close();
+  Expect.isTrue(isClosed);
+}
diff --git a/tests/lib/convert/latin1_test.dart b/tests/lib/convert/latin1_test.dart
new file mode 100644
index 0000000..18a7797
--- /dev/null
+++ b/tests/lib/convert/latin1_test.dart
@@ -0,0 +1,136 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+var latin1Strings = [
+  "pure ascii",
+  "blåbærgrød",
+  "\x00 edge cases \xff"
+];
+
+var nonLatin1Strings = [
+  "Edge case \u{100}",
+  "Edge case super-BMP \u{10000}"
+];
+
+void main() {
+  // Build longer versions of the example strings.
+  for (int i = 0, n = latin1Strings.length; i < n ; i++) {
+    var string = latin1Strings[i];
+    while (string.length < 1024) {
+      string += string;
+    }
+    latin1Strings.add(string);
+  }
+  for (int i = 0, n = nonLatin1Strings.length; i < n ; i++) {
+    var string = nonLatin1Strings[i];
+    while (string.length < 1024) {
+      string += string;
+    }
+    nonLatin1Strings.add(string);
+  }
+  testDirectConversions();
+  testChunkedConversions();
+}
+
+void testDirectConversions() {
+  for (var codec in [LATIN1, new Latin1Codec()]) {
+    for (var latin1String in latin1Strings) {
+      List bytes = codec.encoder.convert(latin1String);
+      Expect.listEquals(latin1String.codeUnits.toList(), bytes, latin1String);
+      String roundTripString = codec.decoder.convert(bytes);
+      Expect.equals(latin1String, roundTripString);
+      roundTripString = codec.decode(bytes);
+      Expect.equals(latin1String, roundTripString);
+    }
+
+    for (var nonLatin1String in nonLatin1Strings) {
+      Expect.throws(() {
+        print(codec.encoder.convert(nonLatin1String));
+      }, null, nonLatin1String);
+    }
+  }
+
+  var allowInvalidCodec = new Latin1Codec(allowInvalid: true);
+  var invalidBytes = [0, 1, 0xff, 0xdead, 0];
+  String decoded = allowInvalidCodec.decode(invalidBytes);
+  Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+  decoded = allowInvalidCodec.decoder.convert(invalidBytes);
+  Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+  decoded = LATIN1.decode(invalidBytes, allowInvalid: true);
+  Expect.equals("\x00\x01\xFF\uFFFD\x00", decoded);
+}
+
+List<int> encode(String str, int chunkSize,
+                 Converter<String, List<int>> converter) {
+  List<int> bytes = <int>[];
+  ChunkedConversionSink byteSink =
+      new ByteConversionSink.withCallback(bytes.addAll);
+  var stringConversionSink = converter.startChunkedConversion(byteSink);
+  for (int i = 0; i < str.length; i += chunkSize) {
+    if (i + chunkSize <= str.length) {
+      stringConversionSink.add(str.substring(i, i + chunkSize));
+    } else {
+      stringConversionSink.add(str.substring(i));
+    }
+  }
+  stringConversionSink.close();
+  return bytes;
+}
+
+String decode(List<int> bytes, int chunkSize,
+              Converter<List<int>, String> converter) {
+  StringBuffer buf = new StringBuffer();
+  var stringSink =
+      new StringConversionSink.fromStringSink(buf);
+  var byteConversionSink = converter.startChunkedConversion(stringSink);
+  for (int i = 0; i < bytes.length; i += chunkSize) {
+    if (i + chunkSize <= bytes.length) {
+      byteConversionSink.add(bytes.sublist(i, i + chunkSize));
+    } else {
+      byteConversionSink.add(bytes.sublist(i));
+    }
+  }
+  byteConversionSink.close();
+  return buf.toString();
+}
+
+void testChunkedConversions() {
+  // Check encoding.
+  for (var converter in [LATIN1.encoder,
+                         new Latin1Codec().encoder,
+                         new Latin1Encoder()]) {
+    for (int chunkSize in [1, 2, 5, 50]) {
+      for (var latin1String in latin1Strings) {
+        var units = latin1String.codeUnits.toList();
+        List bytes = encode(latin1String, chunkSize, converter);
+        Expect.listEquals(units, bytes);
+      }
+      for (var nonLatin1String in nonLatin1Strings) {
+        Expect.throws(() {
+          encode(nonLatin1Strings, chunkSize, converter);
+        });
+      }
+    }
+  }
+  // Check decoding.
+  for (var converter in [LATIN1.decoder,
+                         new Latin1Codec().decoder,
+                         new Latin1Decoder()]) {
+    for (int chunkSize in [1, 2, 5, 50]) {
+      for (var latin1String in latin1Strings) {
+        var units = latin1String.codeUnits.toList();
+        Expect.equals(latin1String, decode(units, chunkSize, converter));
+      }
+      for (var nonLatin1String in nonLatin1Strings) {
+        var units = nonLatin1String.codeUnits.toList();
+        Expect.throws(() {
+          decode(units, chunkSize, converter);
+        });
+      }
+    }
+  }
+}
diff --git a/tests/lib/convert/utf82_test.dart b/tests/lib/convert/utf82_test.dart
index b52f240..e3a5811 100644
--- a/tests/lib/convert/utf82_test.dart
+++ b/tests/lib/convert/utf82_test.dart
@@ -50,7 +50,13 @@
   [ 0xC0, 0x80 ],
   [ 0xC1, 0x80 ],
   // Outside valid range.
-  [ 0xF4, 0xBF, 0xBF, 0xBF ]];
+  [ 0xF4, 0xBF, 0xBF, 0xBF ],
+  // Negative
+  [ -0x01 ],
+  [ -0xFF ],
+  [ -0x80000000 ],
+  [ -0x40000000 ],
+  [ -0x80000000000000000]];
 
 final TESTS2 = [
   // Test that 0xC0|1, 0x80 does not eat the next character.
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 49dda71..b90b26e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -15,6 +15,7 @@
 mirrors/invoke_private_test: Fail # Issue 12164
 mirrors/function_type_mirror_test: Fail # Issue 12166
 mirrors/generics_test: Fail # Issue 12333
+mirrors/hierarchy_invariants_test: Fail # Issue 11863
 mirrors/fake_function_test: Fail # Issue 11612
 mirrors/method_mirror_name_test: Fail # Issue 6335
 mirrors/method_mirror_properties_test: Fail # Issue 11861
@@ -125,6 +126,5 @@
 convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12025.
 convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
 
-[ $arch == simarm || $arch == arm ]
-typed_data/uint32x4_arithmetic_test: Crash # Unimplemented
-
+[ $arch == simarm ]
+convert/chunked_conversion_utf88_test: Pass, Slow # Issue 12644.
diff --git a/tests/lib/mirrors/hierarchy_invariants_test.dart b/tests/lib/mirrors/hierarchy_invariants_test.dart
new file mode 100644
index 0000000..0197dd3
--- /dev/null
+++ b/tests/lib/mirrors/hierarchy_invariants_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.hierarchy_invariants_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+check(classMirror) {
+  if (classMirror is TypedefMirror) return;
+
+  Expect.isTrue(classMirror.simpleName is Symbol);
+  Expect.notEquals(null, classMirror.owner);
+  Expect.isTrue(classMirror.owner is LibraryMirror);
+  Expect.isTrue(classMirror.superinterfaces is List);
+  if (classMirror.superclass == null) {
+    Expect.equals(reflectClass(Object), classMirror);
+  } else {
+    check(classMirror.superclass);
+  }
+}
+
+main() {
+  currentMirrorSystem().libraries.values.forEach((libraryMirror) {
+    libraryMirror.classes.values.forEach((classMirror) {
+      check(classMirror);
+    });
+  });
+
+  Expect.throws(() => reflectClass(dynamic),
+                (e) => e is ArgumentError,
+                'dynamic is not a class');
+}
diff --git a/tools/VERSION b/tools/VERSION
index df4a568..2a8dc7c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 6
-BUILD 20
-PATCH 1
+BUILD 21
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index e469d6a..3f9d9c3 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -119,13 +119,13 @@
   supported_platforms = {
     'linux': ['ff', 'chromeOnAndroid', 'chrome'],
     'mac': ['safari'],
-    'windows': []
+    'windows': ['ie9']
   }
   # Platforms that we run on the fyi waterfall only.
   fyi_supported_platforms = {
     'linux': [],
     'mac': [],
-    'windows': ['ie9']
+    'windows': []
   }
 
   if (runtime in supported_platforms[system]):
diff --git a/tools/dom/idl/dart/dart.idl b/tools/dom/idl/dart/dart.idl
index 7b1639a..a132f15 100644
--- a/tools/dom/idl/dart/dart.idl
+++ b/tools/dom/idl/dart/dart.idl
@@ -348,15 +348,6 @@
 [Suppressed]
 interface TextDecoder {};
 
-// TODO(jacobr): renable these as part of fixing dartbug.com/12537
-// We need to apply changes analogous to https://chromiumcodereview.appspot.com/21274004
-// to the Dart bindings so that we can reenable NodeIterator and TreeWalker
-[Suppressed]
-interface NodeIterator {};
-
-[Suppressed]
-interface TreeWalker {};
-
 [Supplemental]
 interface Window : EventTarget {};
 
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 9a6436e..8280e8c 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -976,8 +976,14 @@
       # Generate to Dart conversion of C++ value.
       if return_type_info.dart_type() == 'bool':
         set_return_value = 'Dart_SetBooleanReturnValue(args, %s)' % (value_expression)
-      elif return_type_info.dart_type() == 'int' and return_type_info.native_type() == 'int':
-        set_return_value = 'Dart_SetIntegerReturnValue(args, %s)' % (value_expression)
+      elif return_type_info.dart_type() == 'int':
+        if return_type_info.native_type() == 'unsigned':
+          set_return_value = 'DartUtilities::setDartUnsignedReturnValue(args, %s)' % (value_expression)
+        elif return_type_info.native_type() == 'unsigned long long':
+          set_return_value = 'DartUtilities::setDartUnsignedLongLongReturnValue(args, %s)' % (value_expression)
+        else:
+          assert (return_type_info.native_type() == 'int' or return_type_info.native_type() == 'long long')
+          set_return_value = 'DartUtilities::setDartIntegerReturnValue(args, %s)' % (value_expression)
       elif return_type_info.dart_type() == 'double':
         set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
       elif return_type_info.dart_type() == 'String':
diff --git a/tools/get_archive.py b/tools/get_archive.py
index e7ab03d..c5547b6 100755
--- a/tools/get_archive.py
+++ b/tools/get_archive.py
@@ -32,23 +32,23 @@
 DRT_DIR = os.path.join('client', 'tests', 'drt')
 DRT_VERSION = os.path.join(DRT_DIR, 'LAST_VERSION')
 DRT_LATEST_PATTERN = (
-    'gs://dartium-archive/latest/drt-%(osname)s-inc-*.zip')
-DRT_PERMANENT_PATTERN = ('gs://dartium-archive/drt-%(osname)s-inc/drt-'
-                         '%(osname)s-inc-%(num1)s.%(num2)s.zip')
+    'gs://dartium-archive/latest/drt-%(osname)s-%(bot)s-*.zip')
+DRT_PERMANENT_PATTERN = ('gs://dartium-archive/drt-%(osname)s-%(bot)s/drt-'
+                         '%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
 
 DARTIUM_DIR = os.path.join('client', 'tests', 'dartium')
 DARTIUM_VERSION = os.path.join(DARTIUM_DIR, 'LAST_VERSION')
 DARTIUM_LATEST_PATTERN = (
-    'gs://dartium-archive/latest/dartium-%(osname)s-inc-*.zip')
-DARTIUM_PERMANENT_PATTERN = ('gs://dartium-archive/dartium-%(osname)s-inc/'
-                             'dartium-%(osname)s-inc-%(num1)s.%(num2)s.zip')
+    'gs://dartium-archive/latest/dartium-%(osname)s-%(bot)s-*.zip')
+DARTIUM_PERMANENT_PATTERN = ('gs://dartium-archive/dartium-%(osname)s-%(bot)s/'
+                             'dartium-%(osname)s-%(bot)s-%(num1)s.%(num2)s.zip')
 
 CHROMEDRIVER_DIR = os.path.join('tools', 'testing', 'dartium-chromedriver')
 CHROMEDRIVER_VERSION = os.path.join(CHROMEDRIVER_DIR, 'LAST_VERSION')
 CHROMEDRIVER_LATEST_PATTERN = (
-    'gs://dartium-archive/latest/chromedriver-%(osname)s-inc-*.zip')
+    'gs://dartium-archive/latest/chromedriver-%(osname)s-%(bot)s-*.zip')
 CHROMEDRIVER_PERMANENT_PATTERN = ('gs://dartium-archive/chromedriver-%(osname)s'
-                                  '-inc/chromedriver-%(osname)s-inc-%(num1)s.'
+                                  '-%(bot)s/chromedriver-%(osname)s-%(bot)s-%(num1)s.'
                                   '%(num2)s.zip')
 
 SDK_DIR = os.path.join(utils.GetBuildRoot(utils.GuessOS(), 'release', 'ia32'),
@@ -57,7 +57,7 @@
 SDK_LATEST_PATTERN = 'gs://dart-editor-archive-continuous/latest/VERSION'
 # TODO(efortuna): Once the x64 VM also is optimized, select the version
 # based on whether we are running on a 32-bit or 64-bit system.
-SDK_PERMANENT = ('gs://dart-editor-archive-continuous/%(version_num)s/' + 
+SDK_PERMANENT = ('gs://dart-editor-archive-continuous/%(version_num)s/' +
     'dartsdk-%(osname)s-32.zip')
 
 # Dictionary storing the earliest revision of each download we have stored.
@@ -124,7 +124,7 @@
     sys.exit(1)
 
 
-def GetDartiumRevision(name, directory, version_file, latest_pattern,
+def GetDartiumRevision(name, bot, directory, version_file, latest_pattern,
     permanent_prefix, revision_num=None):
   """Get the latest binary that is stored in the dartium archive.
 
@@ -146,16 +146,16 @@
     if not revision_num:
       revision_num = latest[latest.rindex('-') + 1 : latest.index('.')]
       latest = (permanent_prefix[:permanent_prefix.rindex('/')] % { 'osname' :
-          osname } + latest[latest.rindex('/'):])
+          osname, 'bot' : bot } + latest[latest.rindex('/'):])
     else:
       latest = (permanent_prefix % { 'osname' : osname, 'num1' : revision_num,
-          'num2' : revision_num })
+          'num2' : revision_num, 'bot' : bot })
       foundURL = False
       while not foundURL:
         # Test to ensure this URL exists because the dartium-archive builds can
         # have unusual numbering (a range of CL numbers) sometimes.
         result, out = Gsutil('ls', permanent_prefix % {'osname' : osname,
-            'num1': revision_num, 'num2': '*' })
+            'num1': revision_num, 'num2': '*', 'bot': bot })
         if result == 0:
           # First try to find one with the the second number the same as the
           # requested number.
@@ -179,9 +179,9 @@
           if revision_num <= 0:
             TooEarlyError()
     return latest
-    
-  GetFromGsutil(name, directory, version_file, latest_pattern, osdict, 
-                  FindPermanentUrl, revision_num)
+
+  GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
+                  FindPermanentUrl, revision_num, bot)
 
 
 def GetSdkRevision(name, directory, version_file, latest_pattern,
@@ -216,13 +216,13 @@
         return ''
     latest = (permanent_prefix % { 'osname' : osname, 'version_num': rev_num})
     return latest
-    
+
   GetFromGsutil(name, directory, version_file, latest_pattern, osdict,
                   FindPermanentUrl, revision_num)
 
 
 def GetFromGsutil(name, directory, version_file, latest_pattern,
-    os_name_dict, get_permanent_url, revision_num = ''):
+    os_name_dict, get_permanent_url, revision_num = '', bot = None):
   """Download and unzip the desired file from Google Storage.
     Args:
     name: the name of the desired download
@@ -246,8 +246,8 @@
 
   EnsureConfig()
 
-  # Query for the lastest version
-  pattern = latest_pattern  % { 'osname' : osname }
+  # Query for the latest version
+  pattern = latest_pattern  % { 'osname' : osname, 'bot' : bot }
   result, out = Gsutil('ls', pattern)
   if result == 0:
     # use permanent link instead, just in case the latest zip entry gets deleted
@@ -330,24 +330,32 @@
                     help='Desired revision number to retrieve for the SDK. If '
                     'unspecified, retrieve the latest SDK build.',
                     action='store', default=None)
+  parser.add_option('-d', '--debug', dest='debug',
+                    help='Download a debug archive instead of a release.',
+                    action='store_true', default=False)
   args, positional = parser.parse_args()
 
   if args.revision and int(args.revision) < LAST_VALID[positional[0]]:
     return TooEarlyError()
 
+  # Use the incremental release bot ('dartium-*-inc') by default.
+  bot = 'inc'
+  if args.debug:
+    bot = 'debug'
+
   if positional[0] == 'dartium':
-    GetDartiumRevision('Dartium', DARTIUM_DIR, DARTIUM_VERSION,
+    GetDartiumRevision('Dartium', bot, DARTIUM_DIR, DARTIUM_VERSION,
                          DARTIUM_LATEST_PATTERN, DARTIUM_PERMANENT_PATTERN,
                          args.revision)
   elif positional[0] == 'chromedriver':
-    GetDartiumRevision('chromedriver', CHROMEDRIVER_DIR, CHROMEDRIVER_VERSION,
+    GetDartiumRevision('chromedriver', bot, CHROMEDRIVER_DIR, CHROMEDRIVER_VERSION,
                          CHROMEDRIVER_LATEST_PATTERN,
                          CHROMEDRIVER_PERMANENT_PATTERN, args.revision)
   elif positional[0] == 'sdk':
     GetSdkRevision('sdk', SDK_DIR, SDK_VERSION, SDK_LATEST_PATTERN,
         SDK_PERMANENT, args.revision)
   elif positional[0] == 'drt':
-    GetDartiumRevision('content_shell', DRT_DIR, DRT_VERSION,
+    GetDartiumRevision('content_shell', bot, DRT_DIR, DRT_VERSION,
                          DRT_LATEST_PATTERN, DRT_PERMANENT_PATTERN,
                          args.revision)
     CopyDrtFont(DRT_DIR)
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index 6d55aee..214a765 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -654,9 +654,10 @@
       return;
     }
 
-    if (status.timeout) {
+    if (status == null || status.timeout) {
       // We don't do anything, this browser is currently being killed and
-      // replaced.
+      // replaced. The browser here can be null if we decided to kill the
+      // browser.
     } else if (status.currentTest != null) {
       status.currentTest.timeoutTimer.cancel();
       status.currentTest.stopwatch.stop();
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 646115b..dbfd7e5 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -12,6 +12,7 @@
 <html>
 <head>
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
   <title> Test $title </title>
   <style>
      .unittest-table { font-family:monospace; border:1px; }
@@ -36,12 +37,14 @@
 </html>
 """;
 
-String getHtmlLayoutContents(String scriptType, Path sourceScript) =>
+String getHtmlLayoutContents(String scriptType,
+                             Path sourceScript) =>
 """
 <!DOCTYPE html>
 <html>
 <head>
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="dart.unittest" content="full-stack-traces">
 </head>
 <body>
   <script type="text/javascript">
diff --git a/tools/testing/dart/status_file_parser.dart b/tools/testing/dart/status_file_parser.dart
index 36dd839..3c07ff4 100644
--- a/tools/testing/dart/status_file_parser.dart
+++ b/tools/testing/dart/status_file_parser.dart
@@ -17,6 +17,7 @@
  * An indication to skip the test.  The caller is responsible for skipping it.
  */
 const SKIP = "skip";
+const SKIP_BY_DESIGN = "skipbydesign";
 const OK = "ok";
 /**
  * An indication that a test is slow and we should allow extra time for
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index fbb1de1..edc65e8 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -540,7 +540,8 @@
   bool get usesWebDriver => TestUtils.usesWebDriver(configuration['runtime']);
 
   bool get isFlaky {
-      if (expectedOutcomes.contains(SKIP)) {
+      if (expectedOutcomes.contains(SKIP) ||
+          expectedOutcomes.contains(SKIP_BY_DESIGN)) {
         return false;
       }
 
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 4f62e29..5f5e4ef 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -355,7 +355,10 @@
         SummaryReport.add(expectations);
       }
 
-      if (expectations.contains(SKIP)) return;
+      if (expectations.contains(SKIP) ||
+          expectations.contains(SKIP_BY_DESIGN)) {
+        return;
+      }
 
       var args = TestUtils.standardOptions(configuration);
       args.add(testName);
@@ -683,7 +686,10 @@
         SummaryReport.add(expectations);
       }
     }
-    if (expectations.contains(SKIP)) return;
+    if (expectations.contains(SKIP) ||
+        expectations.contains(SKIP_BY_DESIGN)) {
+      return;
+    }
 
     if (configuration['compiler'] != 'none' && info.hasCompileError) {
       // If a compile-time error is expected, and we're testing a
@@ -1907,6 +1913,7 @@
 class SummaryReport {
   static int total = 0;
   static int skipped = 0;
+  static int skippedByDesign = 0;
   static int noCrash = 0;
   static int pass = 0;
   static int failOk = 0;
@@ -1919,6 +1926,9 @@
     ++total;
     if (expectations.contains(SKIP)) {
       ++skipped;
+    } else if (expectations.contains(SKIP_BY_DESIGN)) {
+      ++skipped;
+      ++skippedByDesign;
     } else {
       if (expectations.contains(PASS) && expectations.contains(FAIL) &&
           !expectations.contains(CRASH) && !expectations.contains(OK)) {
@@ -1950,7 +1960,7 @@
   static void printReport() {
     if (total == 0) return;
     String report = """Total: $total tests
- * $skipped tests will be skipped
+ * $skipped tests will be skipped ($skippedByDesign skipped by design)
  * $noCrash tests are expected to be flaky but not crash
  * $pass tests are expected to pass
  * $failOk tests are expected to fail that we won't fix