Version 0.5.19.0

svn merge -r 24018:24061 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@24070 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index c7360e9..d65c4e0 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -104,13 +104,7 @@
   cmds = [sys.executable, toolsBuildScript,
           '--mode=' + mode, '--revision=' + version,
           '--name=' + name, '--out=' + outdir]
-  local_env = os.environ.copy()
-  # The buildbot sets AWS_CREDENTIAL_FILE/BOTO_CONFIG to the chromium specific
-  # file, we use the one in home.
-  if 'BOTO_CONFIG' in local_env:
-    del local_env['BOTO_CONFIG']
-  if 'AWS_CREDENTIAL_FILE' in local_env:
-    del local_env['AWS_CREDENTIAL_FILE']
+  local_env = EnvironmentWithoutBotoConfig()
   #if 'linux' in name:
   #  javahome = os.path.join(os.path.expanduser('~'), 'jdk1.6.0_25')
   #  local_env['JAVA_HOME'] = javahome
@@ -119,20 +113,31 @@
 
   return subprocess.call(cmds, env=local_env)
 
-def ProcessBot(name, target):
+def EnvironmentWithoutBotoConfig(environment=None):
+  # The buildbot sets AWS_CREDENTIAL_FILE/BOTO_CONFIG to the chromium specific
+  # file, we use the one in home.
+  custom_env = dict(environment or os.environ)
+  if 'BOTO_CONFIG' in custom_env:
+    del custom_env['BOTO_CONFIG']
+  if 'AWS_CREDENTIAL_FILE' in custom_env:
+    del custom_env['AWS_CREDENTIAL_FILE']
+  return custom_env
+
+def ProcessBot(name, target, custom_env=None):
   '''
   Build and test the named bot target (compiler, android, pub). We look for
   the supporting script in tools/bots/ to run the tests and build.
   '''
   print 'Process%s' % target.capitalize()
-  has_shell=False
+  has_shell = False
+  environment = custom_env or os.environ
   if '-win' in name:
     # In Windows we need to run in the shell, so that we have all the
     # environment variables available.
-    has_shell=True
+    has_shell = True
   return subprocess.call([sys.executable,
       os.path.join('tools', 'bots', target + '.py')],
-      env=os.environ, shell=has_shell)
+      env=environment, shell=has_shell)
 
 def FixJavaHome():
   buildbot_javahome = os.getenv('BUILDBOT_JAVA_HOME')
@@ -222,7 +227,8 @@
   elif name.startswith('vm-android'):
     status = ProcessBot(name, 'android')
   elif name.startswith('cross') or name.startswith('target'):
-    status = ProcessBot(name, 'cross-vm')
+    status = ProcessBot(name, 'cross-vm',
+                        custom_env=EnvironmentWithoutBotoConfig())
   else:
     status = ProcessBot(name, 'compiler')
 
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_junit.dart b/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
index 1fa994e..8d43a53 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_junit.dart
@@ -59,7 +59,7 @@
 class _IsNotSameAs extends BaseMatcher {
   final _expected;
   const _IsNotSameAs(this._expected);
-  bool matches(item, MatchState matchState) => !identical(item, _expected);
+  bool matches(item, Map matchState) => !identical(item, _expected);
   Description describe(Description description) =>
       description.add('not same instance as ').addDescriptionOf(_expected);
 }
@@ -69,14 +69,14 @@
   final String msg;
   final expectedValue;
   const _EqualsWithMessage(this.msg, this.expectedValue);
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item == expectedValue;
   }
   Description describe(Description mismatchDescription) {
     return mismatchDescription.replace(msg);
   }
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     return mismatchDescription.replace(msg).add(" $item != $expectedValue");
   }
 }
@@ -85,14 +85,14 @@
 class _IsTrueWithMessage extends BaseMatcher {
   final String msg;
   const _IsTrueWithMessage(this.msg);
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item == true;
   }
   Description describe(Description mismatchDescription) {
     return mismatchDescription.replace(msg);
   }
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     return mismatchDescription.replace(msg).add(" $item is not true");
   }
 }
@@ -101,14 +101,14 @@
 class _IsFalseWithMessage extends BaseMatcher {
   final String msg;
   const _IsFalseWithMessage(this.msg);
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item == false;
   }
   Description describe(Description mismatchDescription) {
     return mismatchDescription.replace(msg);
   }
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     return mismatchDescription.replace(msg).add(" $item is not false");
   }
 }
@@ -117,14 +117,14 @@
 class _IsNotNullWithMessage extends BaseMatcher {
   final String msg;
   const _IsNotNullWithMessage(this.msg);
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item != null;
   }
   Description describe(Description mismatchDescription) {
     return mismatchDescription.replace(msg);
   }
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     return mismatchDescription.replace(msg).add(" $item is null");
   }
 }
diff --git a/pkg/http/test/multipart_test.dart b/pkg/http/test/multipart_test.dart
index 78121f6..6153541 100644
--- a/pkg/http/test/multipart_test.dart
+++ b/pkg/http/test/multipart_test.dart
@@ -26,7 +26,7 @@
 
   _BodyMatches(this._pattern);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! http.MultipartRequest) return false;
 
     var future = item.finalize().toBytes().then((bodyBytes) {
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index 6d86985..ed09137 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -149,7 +149,7 @@
 
   _Parse(this._matcher);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! String) return false;
 
     var parsed;
@@ -177,7 +177,7 @@
 
 class _HttpException extends TypeMatcher {
   const _HttpException() : super("HttpException");
-  bool matches(item, MatchState matchState) => item is HttpException;
+  bool matches(item, Map matchState) => item is HttpException;
 }
 
 /// A matcher for RedirectLimitExceededExceptions.
@@ -192,7 +192,7 @@
   const _RedirectLimitExceededException() :
       super("RedirectLimitExceededException");
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
     item is RedirectException && item.message == "Redirect limit exceeded";
 }
 
@@ -205,5 +205,5 @@
 
 class _SocketException extends TypeMatcher {
   const _SocketException() : super("SocketException");
-  bool matches(item, MatchState matchState) => item is SocketException;
+  bool matches(item, Map matchState) => item is SocketException;
 }
diff --git a/pkg/oauth2/test/utils.dart b/pkg/oauth2/test/utils.dart
index 9198c80..fddcd37 100644
--- a/pkg/oauth2/test/utils.dart
+++ b/pkg/oauth2/test/utils.dart
@@ -54,7 +54,7 @@
 
 class _AuthorizationException extends TypeMatcher {
   const _AuthorizationException() : super("AuthorizationException");
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
     item is oauth2.AuthorizationException;
 }
 
@@ -67,6 +67,6 @@
 
 class _ExpirationException extends TypeMatcher {
   const _ExpirationException() : super("ExpirationException");
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
     item is oauth2.ExpirationException;
 }
diff --git a/pkg/pkg.status b/pkg/pkg.status
index ae61138..1a4e87f 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -64,21 +64,6 @@
 analyzer_experimental/test/generated/ast_test: Fail, Slow # Issue 11230
 unittest/test/instance_test: Fail # http://dartbug.com/11191
 
-[ $compiler == dart2js && $runtime == d8 && $checked ]
-pathos/test/pathos_io_test: Fail # Issue 11258
-oauth2/*: Fail # Issue 11258
-oauth2/test/utils_test: Pass
-http/*: Fail # Issue 11258
-stack_trace/*: Fail # Issue 11258
-intl/test/date_time_format_file_odd_test: Fail # Issue 11258
-intl/test/date_time_format_file_even_test: Fail # Issue 11258
-intl/test/message_extraction/message_extraction_test: Fail # Issue 11258
-scheduled_test/*: Fail # Issue 11258
-scheduled_test/test/substitute_future_test: Pass
-scheduled_test/test/value_future_test: Pass
-analyzer_experimental/test/error_test: Fail # Issue 11258
-analyzer_experimental/test/services/formatter_test: Fail # Issue 11258
-
 [ $compiler == dartc ]
 unittest/test/mock_regexp_negative_test: Fail
 unittest/test/mock_stepwise_negative_test: Fail
@@ -116,10 +101,13 @@
 crypto/test/sha1_test: Fail # V8 bug: https://code.google.com/p/v8/issues/detail?id=2692
 
 [ $compiler == dart2js && $browser ]
-pathos/test/pathos_dartium_test: Fail, OK # Issue 6490
+pathos/test/pathos_dartium_test: Fail # Issue 6490
 crypto/test/sha256_test: Slow, Pass
 crypto/test/sha1_test: Slow, Pass
 
+[ $compiler == dart2js && $checked ]
+pathos/test/pathos_dartium_test: Crash
+
 [ $browser ]
 analyzer_experimental/test/error_test: Fail, OK # Uses dart:io.
 analyzer_experimental/test/generated/element_test: Fail, OK # Uses dart:io.
diff --git a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
index fcdaacb..07609ff 100644
--- a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
@@ -46,7 +46,7 @@
 
   const _ScheduledCompletes(this._matcher, this._description);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Future) return false;
 
     // TODO(nweiz): parse the stack, figure out on what line these were called,
diff --git a/pkg/scheduled_test/test/descriptor/file_test.dart b/pkg/scheduled_test/test/descriptor/file_test.dart
index 96d4418..5c64586 100644
--- a/pkg/scheduled_test/test/descriptor/file_test.dart
+++ b/pkg/scheduled_test/test/descriptor/file_test.dart
@@ -221,8 +221,8 @@
     test('test 2', () {
       expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
       expect(errors.map((e) => e.error.message), equals([
-        "Expected: contains 'baaz'\n     But: was 'barfoobaz'.\n"
-        "Actual: 'barfoobaz'"
+        "Expected: contains 'baaz'\n"
+        "  Actual: 'barfoobaz'"
       ]), verbose: true);
     });
   }, passing: ['test 2']);
@@ -263,8 +263,7 @@
       expect(errors, everyElement(new isInstanceOf<ScheduleError>()));
       expect(errors.map((e) => e.error.message), equals([
         "Expected: contains <12>\n"
-        "     But: was [98, 97, 114, 102, 111, 111, 98, 97, 122].\n"
-        "Actual: [98, 97, 114, 102, 111, 111, 98, 97, 122]"
+        "  Actual: [98, 97, 114, 102, 111, 111, 98, 97, 122]"
       ]), verbose: true);
     });
   }, passing: ['test 2']);
diff --git a/pkg/unittest/lib/mock.dart b/pkg/unittest/lib/mock.dart
index 385194f..8b60078 100644
--- a/pkg/unittest/lib/mock.dart
+++ b/pkg/unittest/lib/mock.dart
@@ -136,7 +136,7 @@
  * that was used to select the logs that were verified.
  */
 String _mockingErrorFormatter(actual, Matcher matcher, String signature,
-                              MatchState matchState, bool verbose) {
+                              Map matchState, bool verbose) {
   var description = new StringDescription();
   description.add('Expected ${signature} ').addDescriptionOf(matcher).
       add('\n     but: ');
@@ -157,7 +157,7 @@
     proxy.fail(reason);
   }
   void failMatch(actual, Matcher matcher, String reason,
-                 MatchState matchState, bool verbose) {
+                 Map matchState, bool verbose) {
     proxy.fail(_mockingErrorFormatter(actual, matcher, reason,
         matchState, verbose));
   }
@@ -288,7 +288,7 @@
    * if it matches this [CallMatcher.
    */
   bool matches(String method, List arguments) {
-    var matchState = new MatchState();
+    var matchState = {};
     if (!nameFilter.matches(method, matchState)) {
       return false;
     }
@@ -541,7 +541,7 @@
     Function entryFilter = _makePredicate(logFilter);
     String filterName = _qualifiedName(mockNameFilter, logFilter.toString());
     LogEntryList rtn = new LogEntryList(filterName);
-    MatchState matchState = new MatchState();
+    var matchState = {};
     for (var i = 0; i < logs.length; i++) {
       LogEntry entry = logs[i];
       if (mockNameFilter.matches(entry.mockName, matchState) &&
@@ -895,7 +895,7 @@
     var keyIterator = keys.logs.iterator;
     keyIterator.moveNext();
     LogEntry keyEntry = keyIterator.current;
-    MatchState matchState = new MatchState();
+    Map matchState = {};
 
     for (LogEntry logEntry in logs) {
       // If we have a log entry match, copy the saved matches from the
@@ -1000,7 +1000,7 @@
 
   const _TimesMatcher(this.min, [this.max = -1]);
 
-  bool matches(logList, MatchState matchState) => logList.length >= min &&
+  bool matches(logList, Map matchState) => logList.length >= min &&
       (max < 0 || logList.length <= max);
 
   Description describe(Description description) {
@@ -1018,7 +1018,7 @@
   }
 
   Description describeMismatch(logList, Description mismatchDescription,
-                               MatchState matchState, bool verbose) =>
+                               Map matchState, bool verbose) =>
       mismatchDescription.add('was called ${logList.length} times');
 }
 
@@ -1059,7 +1059,7 @@
 
   const _ResultMatcher(this.action, this.value);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! LogEntry) {
      return false;
     }
@@ -1081,7 +1081,7 @@
   }
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item.action == Action.RETURN || item.action == Action.PROXY) {
       mismatchDescription.add('returned ');
     } else {
@@ -1139,7 +1139,7 @@
 
   const _ResultSetMatcher(this.action, this.value, this.frequency);
 
-  bool matches(logList, MatchState matchState) {
+  bool matches(logList, Map matchState) {
     for (LogEntry entry in logList) {
       // normalize the action; PROXY is like RETURN.
       Action eaction = entry.action;
@@ -1148,10 +1148,7 @@
       }
       if (eaction == action && value.matches(entry.value, matchState)) {
         if (frequency == _Frequency.NONE) {
-          matchState.state = {
-              'state' : matchState.state,
-              'entry' : entry
-          };
+          addStateInfo(matchState, {'entry': entry});
           return false;
         } else if (frequency == _Frequency.SOME) {
           return true;
@@ -1159,10 +1156,7 @@
       } else {
         // Mismatch.
         if (frequency == _Frequency.ALL) { // We need just one mismatch to fail.
-          matchState.state = {
-              'state' : matchState.state,
-              'entry' : entry
-          };
+          addStateInfo(matchState, {'entry': entry});
           return false;
         }
       }
@@ -1185,9 +1179,9 @@
   }
 
   Description describeMismatch(logList, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (frequency != _Frequency.SOME) {
-      LogEntry entry = matchState.state['entry'];
+      LogEntry entry = matchState['entry'];
       if (entry.action == Action.RETURN || entry.action == Action.PROXY) {
         mismatchDescription.add('returned');
       } else {
@@ -1195,7 +1189,7 @@
       }
       mismatchDescription.add(' value that ');
       value.describeMismatch(entry.value, mismatchDescription,
-        matchState.state['state'], verbose);
+        matchState['state'], verbose);
       mismatchDescription.add(' at least once');
     } else {
       mismatchDescription.add('never did');
@@ -1369,7 +1363,7 @@
       }
     }
     bool matchedMethodName = false;
-    MatchState matchState = new MatchState();
+    Map matchState = {};
     for (String k in _behaviors.keys) {
       Behavior b = _behaviors[k];
       if (b.matcher.nameFilter.matches(method, matchState)) {
diff --git a/pkg/unittest/lib/src/basematcher.dart b/pkg/unittest/lib/src/basematcher.dart
index a74928c..099494d 100644
--- a/pkg/unittest/lib/src/basematcher.dart
+++ b/pkg/unittest/lib/src/basematcher.dart
@@ -5,23 +5,6 @@
 part of matcher;
 
 /**
- * MatchState is a simple wrapper around an arbitrary object.
- * [Matcher] [matches] methods can use this to store useful
- * information upon match failures, and this information will
- * be passed to [describeMismatch]. Each [Matcher] is responsible
- * for its own use of this state, so the state created by [matches]
- * should be consistent with that expected by [describeMismatch] in
- * the same [Matcher] class, but can vary between classes. The inner
- * state, if set, will typically be a [Map] with a number of key-value
- * pairs containing relevant state information.
- */
-class MatchState {
-  var state = null;
-
-  MatchState([this.state]);
-}
-
-/**
  * BaseMatcher is the base class for all matchers. To implement a new
  * matcher, either add a class that implements Matcher or a class that
  * extends BaseMatcher. Extending BaseMatcher has the benefit that a
@@ -36,7 +19,7 @@
    * [matchState] may be used to return additional info for
    * the use of [describeMismatch].
    */
-  bool matches(item, MatchState matchState);
+  bool matches(item, Map matchState);
 
   /**
    * Creates a textual description of a matcher,
@@ -50,8 +33,11 @@
    * It does not check whether the [item] fails the match, as it is
    * only called after a failed match. There may be additional info
    * about the mismatch in [matchState].
+   * The base matcher does not add anything as the actual value is
+   * typically sufficient, but matchers that can add valuable info
+   * should override this.
    */
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) =>
-    mismatchDescription.add('was ').addDescriptionOf(item);
+                               Map matchState, bool verbose) =>
+    mismatchDescription;
 }
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 25767e3..4b5bdbb 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -12,7 +12,7 @@
 
 class _Empty extends BaseMatcher {
   const _Empty();
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is Map || item is Iterable) {
       return item.isEmpty;
     } else if (item is String) {
@@ -33,14 +33,14 @@
 
 class _IsNull extends BaseMatcher {
   const _IsNull();
-  bool matches(item, MatchState matchState) => item == null;
+  bool matches(item, Map matchState) => item == null;
   Description describe(Description description) =>
       description.add('null');
 }
 
 class _IsNotNull extends BaseMatcher {
   const _IsNotNull();
-  bool matches(item, MatchState matchState) => item != null;
+  bool matches(item, Map matchState) => item != null;
   Description describe(Description description) =>
       description.add('not null');
 }
@@ -53,14 +53,14 @@
 
 class _IsTrue extends BaseMatcher {
   const _IsTrue();
-  bool matches(item, MatchState matchState) => item == true;
+  bool matches(item, Map matchState) => item == true;
   Description describe(Description description) =>
       description.add('true');
 }
 
 class _IsFalse extends BaseMatcher {
   const _IsFalse();
-  bool matches(item, MatchState matchState) => item == false;
+  bool matches(item, Map matchState) => item == false;
   Description describe(Description description) =>
       description.add('false');
 }
@@ -74,7 +74,7 @@
 class _IsSameAs extends BaseMatcher {
   final _expected;
   const _IsSameAs(this._expected);
-  bool matches(item, MatchState matchState) => identical(item, _expected);
+  bool matches(item, Map matchState) => identical(item, _expected);
   // If all types were hashable we could show a hash here.
   Description describe(Description description) =>
       description.add('same instance as ').addDescriptionOf(_expected);
@@ -97,76 +97,77 @@
 
   _DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit;
 
-  String _compareIterables(expected, actual, matcher, depth) {
+  // Returns a pair (reason, location)
+  List _compareIterables(expected, actual, matcher, depth, location) {
     if (actual is !Iterable) {
-      return 'is not Iterable';
+      return ['is not Iterable', location];
     }
     var expectedIterator = expected.iterator;
     var actualIterator = actual.iterator;
-    var position = 0;
-    String reason = null;
-    while (reason == null) {
+    var index = 0;
+    while (true) {
       if (expectedIterator.moveNext()) {
+        var newLocation = '${location}[${index}]';
         if (actualIterator.moveNext()) {
-          Description r = matcher(expectedIterator.current,
-                           actualIterator.current,
-                           'mismatch at position ${position}',
+          var rp = matcher(expectedIterator.current,
+                           actualIterator.current, newLocation,
                            depth);
-          if (r != null) reason = r.toString();
-          ++position;
+          if (rp != null) return rp;
+          ++index;
         } else {
-          reason = 'shorter than expected';
+          return ['shorter than expected', newLocation];
         }
       } else if (actualIterator.moveNext()) {
-        reason = 'longer than expected';
+        return ['longer than expected', newLocation];
       } else {
         return null;
       }
     }
-    return reason;
+    return null;
   }
 
-  Description _recursiveMatch(expected, actual, String location, int depth) {
-    Description reason = null;
+  List _recursiveMatch(expected, actual, String location, int depth) {
+    String reason = null;
     // If _limit is 1 we can only recurse one level into object.
     bool canRecurse = depth == 0 || _limit > 1;
     if (expected == actual) {
       // Do nothing.
     } else if (depth > _limit) {
-      reason = new StringDescription('recursion depth limit exceeded');
+      reason = 'recursion depth limit exceeded';
     } else {
       if (expected is Iterable && canRecurse) {
-        String r = _compareIterables(expected, actual,
-            _recursiveMatch, depth+1);
-        if (r != null) reason = new StringDescription(r);
+        List result = _compareIterables(expected, actual,
+            _recursiveMatch, depth + 1, location);
+        if (result != null) {
+          reason = result[0];
+          location = result[1];
+        }
       } else if (expected is Map && canRecurse) {
         if (actual is !Map) {
-          reason = new StringDescription('expected a map');
+          reason = 'expected a map';
         } else {
           var err = (expected.length == actual.length) ? '' :
-                    'different map lengths; ';
+                    'has different length and ';
           for (var key in expected.keys) {
             if (!actual.containsKey(key)) {
-              reason = new StringDescription(err);
-              reason.add('missing map key ');
-              reason.addDescriptionOf(key);
+              reason = '${err}is missing map key \'$key\'';
               break;
             }
           }
           if (reason == null) {
             for (var key in actual.keys) {
               if (!expected.containsKey(key)) {
-                reason = new StringDescription(err);
-                reason.add('extra map key ');
-                reason.addDescriptionOf(key);
+                reason = '${err}has extra map key \'$key\'';
                 break;
               }
             }
             if (reason == null) {
               for (var key in expected.keys) {
-                reason = _recursiveMatch(expected[key], actual[key],
-                    'with key <${key}> ${location}', depth+1);
-                if (reason != null) {
+                var rp = _recursiveMatch(expected[key], actual[key],
+                    "${location}['${key}']", depth+1);
+                if (rp != null) {
+                  reason = rp[0];
+                  location = rp[1];
                   break;
                 }
               }
@@ -174,38 +175,62 @@
           }
         }
       } else {
-        reason = new StringDescription();
+        var description = new StringDescription();
         // If we have recursed, show the expected value too; if not,
         // expect() will show it for us.
         if (depth > 0) {
-          reason.add('expected ');
-          reason.addDescriptionOf(expected).add(' but ');
+          description.add('was ').
+              addDescriptionOf(actual).
+              add(' instead of ').
+              addDescriptionOf(expected);
+          reason = description.toString();
+        } else {
+          reason = ''; // We're not adding any value to the actual value.
         }
-        reason.add('was ');
-        reason.addDescriptionOf(actual);
       }
     }
-    if (reason != null && location.length > 0) {
-      reason.add(' ').add(location);
+    if (reason == null) return null;
+    return [reason, location];
+  }
+
+  String _match(expected, actual, Map matchState) {
+    var rp  = _recursiveMatch(expected, actual, '', 0);
+    if (rp == null) return null;
+    var reason;
+    if (rp[0].length > 0) {
+      if (rp[1].length > 0) {
+        reason = "${rp[0]} at location ${rp[1]}";
+      } else {
+        reason = rp[0];
+      }
+    } else {
+      reason = '';
     }
+    // Cache the failure reason in the matchState.
+    addStateInfo(matchState, {'reason': reason});
     return reason;
   }
 
-  String _match(expected, actual) {
-    Description reason = _recursiveMatch(expected, actual, '', 0);
-    return reason == null ? null : reason.toString();
-  }
-
-  // TODO(gram) - see if we can make use of matchState here to avoid
-  // recursing again in describeMismatch.
-  bool matches(item, MatchState matchState) => _match(_expected, item) == null;
+  bool matches(item, Map matchState) =>
+      _match(_expected, item, matchState) == null;
 
   Description describe(Description description) =>
     description.addDescriptionOf(_expected);
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) =>
-    mismatchDescription.add(_match(_expected, item));
+                               Map matchState, bool verbose) {
+    var reason = matchState['reason'];
+    // If we didn't get a good reason, that would normally be a 
+    // simple 'is <value>' message. We only add that if the mismatch
+    // description is non empty (so we are supplementing the mismatch
+    // description).
+    if (reason.length == 0 && mismatchDescription.length > 0) {
+      mismatchDescription.add('is ').addDescriptionOf(item);
+    } else {
+      mismatchDescription.add(reason);
+    }
+    return mismatchDescription;
+  }
 }
 
 /** A special equality matcher for strings. */
@@ -216,18 +241,18 @@
 
   bool get showActualValue => true;
 
-  bool matches(item, MatchState mismatchState) => _value == item;
+  bool matches(item, Map matchState) => _value == item;
 
   Description describe(Description description) =>
       description.addDescriptionOf(_value);
 
   Description describeMismatch(item, Description mismatchDescription,
-      MatchState matchState, bool verbose) {
+      Map matchState, bool verbose) {
     if (item is! String) {
-      return mismatchDescription.addDescriptionOf(item).add(' not a string');
+      return mismatchDescription.addDescriptionOf(item).add('is not a string');
     } else {
       var buff = new StringBuffer();
-      buff.write('Strings are not equal.');
+      buff.write('is different.');
       var escapedItem = _escape(item);
       var escapedValue = _escape(_value);
       int minLength = escapedItem.length < escapedValue.length ?
@@ -257,7 +282,7 @@
         _writeTrailing(buff, escapedItem, start);
         buff.write('\n          ');
         for (int i = (start > 10 ? 14 : start); i > 0; i--) buff.write(' ');
-        buff.write('^\n Differ at position $start');
+        buff.write('^\n Differ at offset $start');
       }
 
       return mismatchDescription.replace(buff.toString());
@@ -291,7 +316,7 @@
 
 class _IsAnything extends BaseMatcher {
   const _IsAnything();
-  bool matches(item, MatchState matchState) => true;
+  bool matches(item, Map matchState) => true;
   Description describe(Description description) =>
       description.add('anything');
 }
@@ -321,7 +346,7 @@
 class isInstanceOf<T> extends BaseMatcher {
   final String _name;
   const isInstanceOf([name = 'specified type']) : this._name = name;
-  bool matches(obj, MatchState matchState) => obj is T;
+  bool matches(obj, Map matchState) => obj is T;
   // The description here is lame :-(
   Description describe(Description description) =>
       description.add('an instance of ${_name}');
@@ -376,7 +401,7 @@
   const Throws([Matcher matcher]) :
     this._matcher = matcher;
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Function && item is! Future) return false;
     if (item is Future) {
       var done = wrapAsync((fn) => fn());
@@ -409,10 +434,7 @@
       if (_matcher == null ||_matcher.matches(e, matchState)) {
         return true;
       } else {
-        matchState.state = {
-            'exception' :e,
-            'stack': s
-        };
+        addStateInfo(matchState, {'exception': e, 'stack': s});
         return false;
       }
     }
@@ -420,29 +442,26 @@
 
   Description describe(Description description) {
     if (_matcher == null) {
-      return description.add("throws an exception");
+      return description.add("throws");
     } else {
-      return description.add('throws an exception which matches ').
-          addDescriptionOf(_matcher);
+      return description.add('throws ').addDescriptionOf(_matcher);
     }
   }
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState,
+                               Map matchState,
                                bool verbose) {
     if (item is! Function && item is! Future) {
-      return mismatchDescription.add(' not a Function or Future');
-    } else if (_matcher == null ||  matchState.state == null) {
-      return mismatchDescription.add(' no exception');
+      return mismatchDescription.add('is not a Function or Future');
+    } else if (_matcher == null || matchState['exception'] == null) {
+      return mismatchDescription.add('did not throw');
     } else {
-      mismatchDescription.
-          add(' exception ').addDescriptionOf(matchState.state['exception']);
+      mismatchDescription. add('threw ').
+          addDescriptionOf(matchState['exception']);
       if (verbose) {
-          mismatchDescription.add(' at ').
-          add(matchState.state['stack'].toString());
+        mismatchDescription.add(' at ').add(matchState['stack'].toString());
       }
-       mismatchDescription.add(' does not match ').addDescriptionOf(_matcher);
-       return mismatchDescription;
+      return mismatchDescription;
     }
   }
 }
@@ -450,15 +469,12 @@
 class _ReturnsNormally extends BaseMatcher {
   const _ReturnsNormally();
 
-  bool matches(f, MatchState matchState) {
+  bool matches(f, Map matchState) {
     try {
       f();
       return true;
     } catch (e, s) {
-      matchState.state = {
-          'exception' : e,
-          'stack': s
-      };
+      addStateInfo(matchState, {'exception': e, 'stack': s});
       return false;
     }
   }
@@ -467,15 +483,13 @@
       description.add("return normally");
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState,
+                               Map matchState,
                                bool verbose) {
-      mismatchDescription.add(' threw ').
-          addDescriptionOf(matchState.state['exception']);
-      if (verbose) {
-        mismatchDescription.add(' at ').
-        add(matchState.state['stack'].toString());
-      }
-      return mismatchDescription;
+    mismatchDescription.add('threw ').addDescriptionOf(matchState['exception']);
+    if (verbose) {
+      mismatchDescription.add(' at ').add(matchState['stack'].toString());
+    }
+    return mismatchDescription;
   }
 }
 
@@ -516,7 +530,7 @@
 
 class _FormatException extends TypeMatcher {
   const _FormatException() : super("FormatException");
-  bool matches(item, MatchState matchState) => item is FormatException;
+  bool matches(item, Map matchState) => item is FormatException;
 }
 
 /** A matcher for Exceptions. */
@@ -527,7 +541,7 @@
 
 class _Exception extends TypeMatcher {
   const _Exception() : super("Exception");
-  bool matches(item, MatchState matchState) => item is Exception;
+  bool matches(item, Map matchState) => item is Exception;
 }
 
 /** A matcher for ArgumentErrors. */
@@ -539,7 +553,7 @@
 
 class _ArgumentError extends TypeMatcher {
   const _ArgumentError() : super("ArgumentError");
-  bool matches(item, MatchState matchState) => item is ArgumentError;
+  bool matches(item, Map matchState) => item is ArgumentError;
 }
 
 /** A matcher for RangeErrors. */
@@ -551,7 +565,7 @@
 
 class _RangeError extends TypeMatcher {
   const _RangeError() : super("RangeError");
-  bool matches(item, MatchState matchState) => item is RangeError;
+  bool matches(item, Map matchState) => item is RangeError;
 }
 
 /** A matcher for NoSuchMethodErrors. */
@@ -563,7 +577,7 @@
 
 class _NoSuchMethodError extends TypeMatcher {
   const _NoSuchMethodError() : super("NoSuchMethodError");
-  bool matches(item, MatchState matchState) => item is NoSuchMethodError;
+  bool matches(item, Map matchState) => item is NoSuchMethodError;
 }
 
 /** A matcher for UnimplementedErrors. */
@@ -575,7 +589,7 @@
 
 class _UnimplementedError extends TypeMatcher {
   const _UnimplementedError() : super("UnimplementedError");
-  bool matches(item, MatchState matchState) => item is UnimplementedError;
+  bool matches(item, Map matchState) => item is UnimplementedError;
 }
 
 /** A matcher for UnsupportedError. */
@@ -587,7 +601,7 @@
 class _UnsupportedError extends TypeMatcher {
   const _UnsupportedError() :
       super("UnsupportedError");
-  bool matches(item, MatchState matchState) => item is UnsupportedError;
+  bool matches(item, Map matchState) => item is UnsupportedError;
 }
 
 /** A matcher for StateErrors. */
@@ -599,7 +613,7 @@
 
 class _StateError extends TypeMatcher {
   const _StateError() : super("StateError");
-  bool matches(item, MatchState matchState) => item is StateError;
+  bool matches(item, Map matchState) => item is StateError;
 }
 
 
@@ -608,7 +622,7 @@
 
 class _IsMap extends TypeMatcher {
   const _IsMap() : super("Map");
-  bool matches(item, MatchState matchState) => item is Map;
+  bool matches(item, Map matchState) => item is Map;
 }
 
 /** A matcher for List types. */
@@ -616,7 +630,7 @@
 
 class _IsList extends TypeMatcher {
   const _IsList() : super("List");
-  bool matches(item, MatchState matchState) => item is List;
+  bool matches(item, Map matchState) => item is List;
 }
 
 /**
@@ -630,8 +644,16 @@
   final Matcher _matcher;
   const _HasLength([Matcher matcher = null]) : this._matcher = matcher;
 
-  bool matches(item, MatchState matchState) {
-    return _matcher.matches(item.length, matchState);
+  bool matches(item, Map matchState) {
+    try {
+      // This is harmless code that will throw if no length property
+      // but subtle enough that an optimizer shouldn't strip it out.
+      if (item.length * item.length >= 0) {
+        return _matcher.matches(item.length, matchState);
+      }
+    } catch (e) {
+      return false;
+    }
   }
 
   Description describe(Description description) =>
@@ -639,17 +661,16 @@
         addDescriptionOf(_matcher);
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     try {
       // We want to generate a different description if there is no length
-      // property. This is harmless code that will throw if no length property
-      // but subtle enough that an optimizer shouldn't strip it out.
+      // property; we use the same trick as in matches().
       if (item.length * item.length >= 0) {
-        return mismatchDescription.add('had length of ').
+        return mismatchDescription.add('has length of ').
             addDescriptionOf(item.length);
       }
     } catch (e) {
-      return mismatchDescription.add('had no length property');
+      return mismatchDescription.add('has no length property');
     }
   }
 }
@@ -670,7 +691,7 @@
 
   const _Contains(this._expected);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is String) {
       return item.indexOf(_expected) >= 0;
     } else if (item is Iterable) {
@@ -687,6 +708,16 @@
 
   Description describe(Description description) =>
       description.add('contains ').addDescriptionOf(_expected);
+
+  Description describeMismatch(item, Description mismatchDescription,
+                               Map matchState, bool verbose) {
+    if (item is String || item is Iterable || item is Map) {
+      return super.describeMismatch(item, mismatchDescription, matchState,
+          verbose);
+    } else {
+      return mismatchDescription.add('is not a string, map or iterable');
+    }
+  }
 }
 
 /**
@@ -701,7 +732,7 @@
 
   const _In(this._expected);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (_expected is String) {
       return _expected.indexOf(item) >= 0;
     } else if (_expected is Iterable) {
@@ -732,7 +763,7 @@
 
   const _Predicate(this._matcher, this._description);
 
-  bool matches(item, MatchState matchState) => _matcher(item);
+  bool matches(item, Map matchState) => _matcher(item);
 
   Description describe(Description description) =>
       description.add(_description);
@@ -770,10 +801,10 @@
   /** Override this to extract the interesting feature.*/
   featureValueOf(actual) => actual;
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     var f = featureValueOf(item);
     if (_matcher.matches(f, matchState)) return true;
-    matchState.state = { 'innerState': matchState.state, 'feature': f };
+    addStateInfo(matchState, {'feature': f});
     return false;
   }
 
@@ -781,10 +812,16 @@
       description.add(_featureDescription).add(' ').addDescriptionOf(_matcher);
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
-    mismatchDescription.add(_featureName).add(' ');
-    _matcher.describeMismatch(matchState.state['feature'], mismatchDescription,
-        matchState.state['innerState'], verbose);
+                               Map matchState, bool verbose) {
+    mismatchDescription.add('has ').add(_featureName).add(' with value ').
+        addDescriptionOf(matchState['feature']);
+    var innerDescription = new StringDescription();
+    _matcher.describeMismatch(matchState['feature'], innerDescription,
+        matchState['state'], verbose);
+    if (innerDescription.length > 0) {
+      mismatchDescription.add(' which ').add(innerDescription.toString());
+    }
     return mismatchDescription;
   }
 }
+
diff --git a/pkg/unittest/lib/src/description.dart b/pkg/unittest/lib/src/description.dart
index cde5243..6c43077 100644
--- a/pkg/unittest/lib/src/description.dart
+++ b/pkg/unittest/lib/src/description.dart
@@ -17,11 +17,13 @@
     _out = init;
   }
 
+  int get length => _out.length;
+
   /** Get the description as a string. */
   String toString() => _out;
 
-  /** Append some plain [text] to the description.  */
-  Description add(String text) {
+  /** Append [text] to the description.  */
+  Description add(text) {
     _out = '${_out}${text}';
     return this;
   }
diff --git a/pkg/unittest/lib/src/expect.dart b/pkg/unittest/lib/src/expect.dart
index 562eb24..92eb9c4 100644
--- a/pkg/unittest/lib/src/expect.dart
+++ b/pkg/unittest/lib/src/expect.dart
@@ -17,6 +17,17 @@
 }
 
 /**
+ * Useful utility for nesting match states.
+ */
+
+void addStateInfo(Map matchState, Map values) {
+  var innerState = new Map.from(matchState);
+  matchState.clear();
+  matchState['state'] = innerState;
+  matchState.addAll(values);
+}
+
+/**
  * Some matchers, like those for Futures and exception testing,
  * can fail in asynchronous sections, and throw exceptions.
  * A user of this library will typically want to catch and handle 
@@ -51,7 +62,7 @@
             bool verbose : false}) {
   matcher = wrapMatcher(matcher);
   bool doesMatch;
-  var matchState = new MatchState();
+  var matchState = {};
   try {
     doesMatch = matcher.matches(actual, matchState);
   } catch (e, trace) {
@@ -105,7 +116,7 @@
     throw new TestFailure(reason);
   }
   void failMatch(actual, Matcher matcher, String reason,
-      MatchState matchState, bool verbose) {
+      Map matchState, bool verbose) {
     fail(_assertErrorFormatter(actual, matcher, reason, matchState, verbose));
   }
 }
@@ -135,16 +146,17 @@
 
 // The default error formatter implementation.
 String _defaultErrorFormatter(actual, Matcher matcher, String reason,
-    MatchState matchState, bool verbose) {
+    Map matchState, bool verbose) {
   var description = new StringDescription();
   description.add('Expected: ').addDescriptionOf(matcher).add('\n');
+  description.add('  Actual: ').addDescriptionOf(actual);
 
   var mismatchDescription = new StringDescription();
   matcher.describeMismatch(actual, mismatchDescription, matchState, verbose);
-  description.add('     But: ')
-      .add(mismatchDescription.toString()).add('.\n');
 
-  description.add('Actual: ').addDescriptionOf(actual);
+  if (mismatchDescription.length > 0) {
+    description.add('   Which: ${mismatchDescription}\n');
+  }
   if (reason != null) {
     description.add(reason).add('\n');
   }
diff --git a/pkg/unittest/lib/src/future_matchers.dart b/pkg/unittest/lib/src/future_matchers.dart
index f92625a..38f98ed 100644
--- a/pkg/unittest/lib/src/future_matchers.dart
+++ b/pkg/unittest/lib/src/future_matchers.dart
@@ -36,7 +36,7 @@
 
   const _Completes(this._matcher, this._id);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Future) return false;
     var done = wrapAsync((fn) => fn(), _id);
 
diff --git a/pkg/unittest/lib/src/interfaces.dart b/pkg/unittest/lib/src/interfaces.dart
index 909c93e..660c49f 100644
--- a/pkg/unittest/lib/src/interfaces.dart
+++ b/pkg/unittest/lib/src/interfaces.dart
@@ -16,7 +16,7 @@
  * error formatter with another.
  */
 typedef String ErrorFormatter(actual, Matcher matcher, String reason,
-    MatchState matchState, bool verbose);
+    Map matchState, bool verbose);
 
 /**
  * Matchers build up their error messages by appending to
@@ -58,7 +58,7 @@
    * and may be used to add details about the mismatch that are too
    * costly to determine in [describeMismatch].
    */
-  bool matches(item, MatchState matchState);
+  bool matches(item, Map matchState);
 
   /** This builds a textual description of the matcher. */
   Description describe(Description description);
@@ -66,7 +66,7 @@
   /**
    * This builds a textual description of a specific mismatch. [item]
    * is the value that was tested by [matches]; [matchState] is
-   * the [MatchState] that was passed to and supplemented by [matches]
+   * the [Map] that was passed to and supplemented by [matches]
    * with additional information about the mismact, and [mismatchDescription]
    * is the [Description] that is being built to decribe the mismatch.
    * A few matchers make use of the [verbose] flag to provide detailed
@@ -74,7 +74,7 @@
    * diagnosing failures, such as stack traces.
    */
   Description describeMismatch(item, Description mismatchDescription,
-      MatchState matchState, bool verbose);
+      Map matchState, bool verbose);
 }
 
 /**
@@ -96,6 +96,6 @@
    * an [ErrorFormatter]) and then call [fail] with this message.
    */
   void failMatch(actual, Matcher matcher, String reason,
-                 MatchState matchState, bool verbose);
+                 Map matchState, bool verbose);
 }
 
diff --git a/pkg/unittest/lib/src/iterable_matchers.dart b/pkg/unittest/lib/src/iterable_matchers.dart
index 65bc610..f7bddf0 100644
--- a/pkg/unittest/lib/src/iterable_matchers.dart
+++ b/pkg/unittest/lib/src/iterable_matchers.dart
@@ -15,18 +15,14 @@
 
   _EveryElement(Matcher this._matcher);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Iterable) {
       return false;
     }
     var i = 0;
     for (var element in item) {
       if (!_matcher.matches(element, matchState)) {
-        matchState.state = {
-            'index': i,
-            'element': element,
-            'state': matchState.state
-        };
+        addStateInfo(matchState, {'index': i, 'element': element});
         return false;
       }
       ++i;
@@ -35,16 +31,26 @@
   }
 
   Description describe(Description description) =>
-      description.add('every element ').addDescriptionOf(_matcher);
+      description.add('every element(').addDescriptionOf(_matcher).add(')');
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
-    if (matchState.state != null) {
-      var index = matchState.state['index'];
-      var element = matchState.state['element'];
-      mismatchDescription.add('position $index ');
-      return _matcher.describeMismatch(element, mismatchDescription,
-            matchState.state['state'], verbose);
+                               Map matchState, bool verbose) {
+    if (matchState['index'] != null) {
+      var index = matchState['index'];
+      var element = matchState['element'];
+      mismatchDescription.add('has value ').addDescriptionOf(element).
+          add(' which ');
+      var subDescription = new StringDescription();
+      _matcher.describeMismatch(element, subDescription,
+            matchState['state'], verbose);
+      if (subDescription.length > 0) {
+        mismatchDescription.add(subDescription);
+      } else {
+        mismatchDescription.add("doesn't match ");
+        _matcher.describe(mismatchDescription);
+      }
+      mismatchDescription.add(' at index $index');
+      return mismatchDescription;
     }
     return super.describeMismatch(item, mismatchDescription,
           matchState, verbose);
@@ -62,7 +68,7 @@
 
   _SomeElement(this._matcher);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item.any((e) => _matcher.matches(e, matchState));
   }
 
@@ -86,16 +92,16 @@
     _matcher = equals(_expected, 1);
   }
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       (item is Iterable) && _matcher.matches(item, matchState);
 
   Description describe(Description description) =>
       description.add('equals ').addDescriptionOf(_expected).add(' ordered');
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is !Iterable) {
-      return mismatchDescription.add('not an Iterable');
+      return mismatchDescription.add('is not an Iterable');
     } else {
       return _matcher.describeMismatch(item, mismatchDescription,
           matchState, verbose);
@@ -149,7 +155,7 @@
         Description reason = new StringDescription();
         reason.add('has no match for element ').
             addDescriptionOf(expectedElement).
-            add(' at position ${expectedPosition}');
+            add(' at index ${expectedPosition}');
         return reason.toString();
       }
       ++expectedPosition;
@@ -157,13 +163,13 @@
     return null;
   }
 
-  bool matches(item, MatchState mismatchState) => (_test(item) == null);
+  bool matches(item, Map mismatchState) => (_test(item) == null);
 
   Description describe(Description description) =>
       description.add('equals ').addDescriptionOf(_expected).add(' unordered');
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) =>
+                               Map matchState, bool verbose) =>
       mismatchDescription.add(_test(item));
 }
 
@@ -174,7 +180,7 @@
 abstract class _IterableMatcher extends BaseMatcher {
   const _IterableMatcher();
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is! Iterable) {
       return mismatchDescription.
           addDescriptionOf(item).
@@ -203,7 +209,7 @@
 
   _PairwiseCompare(this._expected, this._comparator, this._description);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Iterable) return false;
     if (item.length != _expected.length) return false;
     var iterator = item.iterator;
@@ -211,12 +217,8 @@
     for (var e in _expected) {
       iterator.moveNext();
       if (!_comparator(e, iterator.current)) {
-        matchState.state = {
-            'index': i,
-            'expected': e,
-            'actual' : iterator.current,
-            'state': matchState.state
-        };
+        addStateInfo(matchState, {'index': i, 'expected': e,
+            'actual': iterator.current});
         return false;
       }
       i++;
@@ -228,18 +230,19 @@
       description.add('pairwise $_description ').addDescriptionOf(_expected);
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is !Iterable) {
-      return mismatchDescription.add('not an Iterable');
+      return mismatchDescription.add('is not an Iterable');
     } else if (item.length != _expected.length) {
       return mismatchDescription.
-          add('length was ${item.length} instead of ${_expected.length}');
+          add('has length ${item.length} instead of ${_expected.length}');
     } else {
       return mismatchDescription.
-          addDescriptionOf(matchState.state["actual"]).
-          add(' not $_description ').
-          addDescriptionOf(matchState.state["expected"]).
-          add(' at position ${matchState.state["index"]}');
+          add('has ').
+          addDescriptionOf(matchState["actual"]).
+          add(' which is not $_description ').
+          addDescriptionOf(matchState["expected"]).
+          add(' at index ${matchState["index"]}');
     }
   }
 }
diff --git a/pkg/unittest/lib/src/map_matchers.dart b/pkg/unittest/lib/src/map_matchers.dart
index 72984f9..91d2f06 100644
--- a/pkg/unittest/lib/src/map_matchers.dart
+++ b/pkg/unittest/lib/src/map_matchers.dart
@@ -14,7 +14,7 @@
 
   const _ContainsValue(this._value);
 
-  bool matches(item, MatchState matchState) => item.containsValue(_value);
+  bool matches(item, Map matchState) => item.containsValue(_value);
   Description describe(Description description) =>
       description.add('contains value ').addDescriptionOf(_value);
 }
@@ -32,7 +32,7 @@
 
   const _ContainsMapping(this._key, Matcher this._valueMatcher);
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       item.containsKey(_key) &&
       _valueMatcher.matches(item[_key], matchState);
 
@@ -42,7 +42,7 @@
   }
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (!item.containsKey(_key)) {
       return mismatchDescription.add(" doesn't contain key ")
           .addDescriptionOf(_key);
diff --git a/pkg/unittest/lib/src/numeric_matchers.dart b/pkg/unittest/lib/src/numeric_matchers.dart
index 84afb49..1ebd33f 100644
--- a/pkg/unittest/lib/src/numeric_matchers.dart
+++ b/pkg/unittest/lib/src/numeric_matchers.dart
@@ -100,7 +100,7 @@
     [valueInDescription = true]) :
       this._valueInDescription = valueInDescription;
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item == _value) {
       return _equalValue;
     } else if (item < _value) {
@@ -118,6 +118,12 @@
       return description.add(_comparisonDescription);
     }
   }
+
+  Description describeMismatch(item, Description mismatchDescription,
+                               Map matchState, bool verbose) {
+    mismatchDescription.add('is not ');
+    return describe(mismatchDescription);
+  }
 }
 
 /**
@@ -132,7 +138,7 @@
 
   const _IsCloseTo(this._value, this._delta);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (!_isNumeric(item)) {
       return false;
     }
@@ -148,14 +154,14 @@
         addDescriptionOf(_value);
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is !num) {
       return mismatchDescription.add(' not numeric');
     } else {
       var diff = item - _value;
       if (diff < 0) diff = -diff;
       return mismatchDescription.
-          add(' differed by ').
+          add(' differs by ').
           addDescriptionOf(diff);
     }
   }
@@ -192,7 +198,7 @@
   const _InRange(this._low, this._high,
     this._lowMatchValue, this._highMatchValue);
 
-  bool matches(value, MatchState matchState) {
+  bool matches(value, Map matchState) {
     if (value is !num) {
       return false;
     }
@@ -214,7 +220,7 @@
         "$_high (${_highMatchValue ? 'inclusive' : 'exclusive'})");
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is !num) {
       return mismatchDescription.
           addDescriptionOf(item).
diff --git a/pkg/unittest/lib/src/operator_matchers.dart b/pkg/unittest/lib/src/operator_matchers.dart
index c7421b7..dde08f3 100644
--- a/pkg/unittest/lib/src/operator_matchers.dart
+++ b/pkg/unittest/lib/src/operator_matchers.dart
@@ -14,7 +14,7 @@
 
   const _IsNot(Matcher this._matcher);
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       !_matcher.matches(item, matchState);
 
   Description describe(Description description) =>
@@ -78,13 +78,10 @@
 
   const _AllOf(this._matchers);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
      for (var matcher in _matchers) {
        if (!matcher.matches(item, matchState)) {
-         matchState.state = {
-             'matcher': matcher,
-             'state': matchState.state
-         };
+        addStateInfo(matchState, {'matcher': matcher});
          return false;
        }
      }
@@ -92,11 +89,10 @@
   }
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
-    var matcher = matchState.state['matcher'];
+                               Map matchState, bool verbose) {
+    var matcher = matchState['matcher'];
     matcher.describeMismatch(item, mismatchDescription,
-        matchState.state['state'], verbose);
-    mismatchDescription.add(" (wasn't ").addDescriptionOf(matcher).add(')');
+        matchState['state'], verbose);
     return mismatchDescription;
   }
 
@@ -166,7 +162,7 @@
 
   const _AnyOf(this._matchers);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
      for (var matcher in _matchers) {
        if (matcher.matches(item, matchState)) {
          return true;
diff --git a/pkg/unittest/lib/src/string_matchers.dart b/pkg/unittest/lib/src/string_matchers.dart
index ae79cce..2180e82 100644
--- a/pkg/unittest/lib/src/string_matchers.dart
+++ b/pkg/unittest/lib/src/string_matchers.dart
@@ -18,7 +18,7 @@
     _matchValue = _value.toLowerCase();
   }
 
-  bool matches(item, MatchState mismatchState) =>
+  bool matches(item, Map matchState) =>
       item is String && _matchValue == item.toLowerCase();
 
   Description describe(Description description) =>
@@ -44,17 +44,18 @@
     _matchValue = collapseWhitespace(_value);
   }
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       item is String && _matchValue == collapseWhitespace(item);
 
   Description describe(Description description) =>
     description.addDescriptionOf(_matchValue).add(' ignoring whitespace');
 
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (item is String) {
-      return mismatchDescription.add('was ').
-          addDescriptionOf(collapseWhitespace(item));
+      return mismatchDescription.add('is ').
+          addDescriptionOf(collapseWhitespace(item)).
+          add(' with whitespace compressed');
     } else {
       return super.describeMismatch(item, mismatchDescription,
           matchState, verbose);
@@ -96,7 +97,7 @@
 
   const _StringStartsWith(this._prefix);
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       item is String && item.startsWith(_prefix);
 
   Description describe(Description description) =>
@@ -115,7 +116,7 @@
 
   const _StringEndsWith(this._suffix);
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
       item is String && item.endsWith(_suffix);
 
   Description describe(Description description) =>
@@ -139,7 +140,7 @@
 
   const _StringContainsInOrder(this._substrings);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (!(item is String)) {
       return false;
     }
@@ -178,7 +179,7 @@
     }
   }
 
-  bool matches(item, MatchState matchState) =>
+  bool matches(item, Map matchState) =>
     item is String ? _regexp.hasMatch(item) : false;
 
   Description describe(Description description) =>
@@ -190,7 +191,7 @@
 abstract class _StringMatcher extends BaseMatcher {
   const _StringMatcher();
   Description describeMismatch(item, Description mismatchDescription,
-                               MatchState matchState, bool verbose) {
+                               Map matchState, bool verbose) {
     if (!(item is String)) {
       return mismatchDescription.
           addDescriptionOf(item).
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index 7dd1e1a..ec78877 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -863,6 +863,12 @@
 /** Signature for a test function. */
 typedef dynamic TestFunction();
 
+/**
+ * A flag that controls whether we hide unittest details in exception stacks.
+ * Useful to disable when debugging unittest or matcher customizations.
+ */
+bool formatStacks = true;
+
 // Stack formatting utility. Strips extraneous content from a stack trace.
 // Stack frame lines are parsed with a regexp, which has been tested
 // in Chrome, Firefox and the VM. If a line fails to be parsed it is
@@ -886,6 +892,7 @@
     r'):([:\d]+)[\)]?$'); // Get the line number and optional column number.
 
 String _formatStack(stack) {
+  if (!formatStacks) return "$stack";
   var lines;
   if (stack is StackTrace) {
     lines = stack.toString().split('\n');
diff --git a/pkg/unittest/test/instance_test.dart b/pkg/unittest/test/instance_test.dart
index 1d165d8..cac6ca0 100644
--- a/pkg/unittest/test/instance_test.dart
+++ b/pkg/unittest/test/instance_test.dart
@@ -13,17 +13,17 @@
   group('Type Matchers', () {
     test('isInstanceOf', () {
       shouldFail(0, new isInstanceOf<String>('String'),
-          "Expected: an instance of String But: was <0>. Actual: <0>");
+          "Expected: an instance of String Actual: <0>");
       shouldPass('cow', new isInstanceOf<String>('String'));
     });
 
     test('throwsA', () {
       shouldPass(doesThrow, throwsA(equals('X')));
       shouldFail(doesThrow, throwsA(equals('Y')),
-          "Expected: throws an exception which matches 'Y' "
-          "But:  exception 'X' does not match 'Y'. "
+          "Expected: throws 'Y' "
           "Actual: <Closure: (dynamic) => dynamic "
-              "from Function 'doesThrow': static.>");
+              "from Function 'doesThrow': static.> "
+          "Which: threw 'X'");
     });
   });
 }
diff --git a/pkg/unittest/test/matchers_minified_test.dart b/pkg/unittest/test/matchers_minified_test.dart
index 3fb875d..d9ee642 100644
--- a/pkg/unittest/test/matchers_minified_test.dart
+++ b/pkg/unittest/test/matchers_minified_test.dart
@@ -24,10 +24,9 @@
       shouldFail(() { throw new Exception(); },
           throwsFormatException,
           matches(
-              r"Expected: throws an exception which matches FormatException +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match FormatException\."
-              r"Actual: <Closure>"));
+              r"Expected: throws FormatException +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsArgumentError', () {
@@ -36,10 +35,9 @@
       shouldFail(() { throw new Exception(); },
           throwsArgumentError,
           matches(
-              r"Expected: throws an exception which matches ArgumentError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match ArgumentError\."
-              r"Actual: <Closure>"));
+              r"Expected: throws ArgumentError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsRangeError', () {
@@ -48,10 +46,9 @@
       shouldFail(() { throw new Exception(); },
           throwsRangeError,
           matches(
-              r"Expected: throws an exception which matches RangeError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match RangeError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws RangeError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsNoSuchMethodError', () {
@@ -60,10 +57,9 @@
       shouldFail(() { throw new Exception(); },
           throwsNoSuchMethodError,
           matches(
-              r"Expected: throws an exception which matches NoSuchMethodError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match NoSuchMethodError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws NoSuchMethodError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsUnimplementedError', () {
@@ -72,11 +68,9 @@
       shouldFail(() { throw new Exception(); },
           throwsUnimplementedError,
           matches(
-              r"Expected: throws an exception which matches "
-                  r"UnimplementedError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match UnimplementedError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws UnimplementedError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsUnsupportedError', () {
@@ -85,10 +79,9 @@
       shouldFail(() { throw new Exception(); },
           throwsUnsupportedError,
           matches(
-              r"Expected: throws an exception which matches UnsupportedError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match UnsupportedError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws UnsupportedError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
 
     test('throwsStateError', () {
@@ -97,10 +90,9 @@
       shouldFail(() { throw new Exception(); },
           throwsStateError,
           matches(
-              r"Expected: throws an exception which matches StateError +"
-              r"But:  exception " + _minifiedName + r":<Exception> "
-                  r"does not match StateError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws StateError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw " + _minifiedName + r":<Exception>"));
     });
   });
 
@@ -110,7 +102,7 @@
       var e = new SimpleIterable(1);
       shouldPass(d, isEmpty);
       shouldFail(e, isEmpty,
-          matches(r"Expected: empty +But: was " + _minifiedName + r":\[1\]\."));
+          matches(r"Expected: empty +Actual: " + _minifiedName + r":\[1\]"));
     });
 
     test('contains', () {
@@ -119,7 +111,7 @@
       shouldFail(d, contains(5),
           matches(
               r"Expected: contains <5> +"
-              r"But: was " + _minifiedName + r":\[3, 2, 1\]\."));
+              r"Actual: " + _minifiedName + r":\[3, 2, 1\]"));
     });
   });
 
@@ -133,8 +125,9 @@
           matches(
               r"Expected: Widget with a price that is a value greater than "
                   r"<10> +"
-              r"But: price was <10>\."
-              r"Actual: <Instance of '" + _minifiedName + r"'>"));
+              r"Actual: <Instance of '" + _minifiedName + r"'> +"
+              r"Which: has price with value <10> which is not "
+              r"a value greater than <10>"));
     });
   });
 }
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index e623c5a..ebe87e9 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -20,36 +20,30 @@
 
     test('isTrue', () {
       shouldPass(true, isTrue);
-      shouldFail(false, isTrue, "Expected: true But: was <false>. "
-          "Actual: <false>");
+      shouldFail(false, isTrue, "Expected: true Actual: <false>");
     });
 
     test('isFalse', () {
       shouldPass(false, isFalse);
-      shouldFail(10, isFalse, "Expected: false But: was <10>. "
-          "Actual: <10>");
-      shouldFail(true, isFalse, "Expected: false But: was <true>. "
-          "Actual: <true>");
+      shouldFail(10, isFalse, "Expected: false Actual: <10>");
+      shouldFail(true, isFalse, "Expected: false Actual: <true>");
     });
 
     test('isNull', () {
       shouldPass(null, isNull);
-      shouldFail(false, isNull, "Expected: null But: was <false>. "
-          "Actual: <false>");
+      shouldFail(false, isNull, "Expected: null Actual: <false>");
     });
 
     test('isNotNull', () {
       shouldPass(false, isNotNull);
-      shouldFail(null, isNotNull, "Expected: not null But: was <null>. "
-          "Actual: <null>");
+      shouldFail(null, isNotNull, "Expected: not null Actual: <null>");
     });
 
     test('same', () {
       var a = new Map();
       var b = new Map();
       shouldPass(a, same(a));
-      shouldFail(b, same(a), "Expected: same instance as {} But: was {}. "
-          "Actual: {}");
+      shouldFail(b, same(a), "Expected: same instance as {} Actual: {}");
     });
 
     test('equals', () {
@@ -64,41 +58,44 @@
       shouldPass(0, anything);
       shouldPass(null, anything);
       shouldPass(a, anything);
-      shouldFail(a, isNot(anything), "Expected: not anything "
-          "But: was {}. Actual: {}");
+      shouldFail(a, isNot(anything), "Expected: not anything Actual: {}");
     });
 
     test('throws', () {
       shouldFail(doesNotThrow, throws,
           matches(
-              r"Expected: throws an exception +But:  no exception\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic "
-                  r"from Function 'doesNotThrow': static\.)?>"));
+              r"Expected: throws"
+              r"  Actual: <Closure(: \(dynamic\) => dynamic "
+              r"from Function 'doesNotThrow': static\.)?>"
+              r"   Which: did not throw"));
       shouldPass(doesThrow, throws);
       shouldFail(true, throws,
-          "Expected: throws an exception But: not a Function or Future. "
-          "Actual: <true>");
+          "Expected: throws"
+          "  Actual: <true>"
+          "   Which: is not a Function or Future");
     });
 
     test('throwsA', () {
       shouldPass(doesThrow, throwsA(equals('X')));
       shouldFail(doesThrow, throwsA(equals('Y')),
           matches(
-              r"Expected: throws an exception which matches 'Y' +"
-              r"But:  exception 'X' does not match 'Y'\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic "
-                  r"from Function 'doesThrow': static\.)?>"));
+              r"Expected: throws 'Y'"
+              r"  Actual: <Closure(: \(dynamic\) => dynamic "
+              r"from Function 'doesThrow': static\.)?>"
+              r"   Which: threw 'X'"));
     });
 
     test('returnsNormally', () {
       shouldPass(doesNotThrow, returnsNormally);
       shouldFail(doesThrow, returnsNormally,
           matches(
-              r"Expected: return normally +But:  threw 'X'\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic "
-                  r"from Function 'doesThrow': static\.)?>"));
+              r"Expected: return normally"
+              r"  Actual: <Closure(: \(dynamic\) => dynamic "
+              r"from Function 'doesThrow': static\.)?>"
+              r"   Which: threw 'X'"));
     });
 
+
     test('hasLength', () {
       var a = new Map();
       var b = new List();
@@ -107,43 +104,66 @@
       shouldPass('a', hasLength(1));
       shouldFail(0, hasLength(0), new PrefixMatcher(
           "Expected: an object with length of <0> "
-          "But: had no length property."
-          "Actual: <0>"));
+          "Actual: <0> "
+          "Which: has no length property"));
 
       b.add(0);
       shouldPass(b, hasLength(1));
       shouldFail(b, hasLength(2),
           "Expected: an object with length of <2> "
-          "But: had length of <1>. "
-          "Actual: [0]");
+          "Actual: [0] "
+          "Which: has length of <1>");
 
       b.add(0);
       shouldFail(b, hasLength(1),
           "Expected: an object with length of <1> "
-          "But: had length of <2>. "
-          "Actual: [0, 0]");
+          "Actual: [0, 0] "
+          "Which: has length of <2>");
       shouldPass(b, hasLength(2));
     });
 
     test('scalar type mismatch', () {
       shouldFail('error', equals(5.1),
           "Expected: <5.1> "
-          "But: was 'error'. Actual: 'error'");
+          "Actual: 'error'");
     });
 
     test('nested type mismatch', () {
       shouldFail(['error'], equals([5.1]),
           "Expected: [5.1] "
-          "But: expected <5.1> but was 'error' mismatch at position 0. "
-          "Actual: ['error']");
+          "Actual: ['error'] "
+          "Which: was 'error' instead of <5.1> at location [0]");
     });
 
     test('doubly-nested type mismatch', () {
       shouldFail([['error']], equals([[5.1]]),
           "Expected: [[5.1]] "
-          "But: expected <5.1> but was 'error' "
-          "mismatch at position 0 mismatch at position 0. "
-          "Actual: [['error']]");
+          "Actual: [['error']] "
+          "Which: was 'error' instead of <5.1> at location [0][0]");
+    });
+
+    test('doubly nested inequality', () {
+      var actual1 = [['foo', 'bar'], ['foo'], 3, []];
+      var expected1 = [['foo', 'bar'], ['foo'], 4, []];
+      var reason1 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+          "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+          "Which: was <3> instead of <4> at location [2]";
+
+      var actual2 = [['foo', 'barry'], ['foo'], 4, []];
+      var expected2 = [['foo', 'bar'], ['foo'], 4, []];
+      var reason2 = "Expected: [['foo', 'bar'], ['foo'], 4, []] "
+          "Actual: [['foo', 'barry'], ['foo'], 4, []] "
+          "Which: was 'barry' instead of 'bar' at location [0][1]";
+
+      var actual3 = [['foo', 'bar'], ['foo'], 4, {'foo':'bar'}];
+      var expected3 = [['foo', 'bar'], ['foo'], 4, {'foo':'barry'}];
+      var reason3 = "Expected: [['foo', 'bar'], ['foo'], 4, {'foo': 'barry'}] "
+          "Actual: [['foo', 'bar'], ['foo'], 4, {'foo': 'bar'}] "
+          "Which: was 'bar' instead of 'barry' at location [3]['foo']";
+
+      shouldFail(actual1, equals(expected1), reason1);
+      shouldFail(actual2, equals(expected2), reason2);
+      shouldFail(actual3, equals(expected3), reason3);
     });
   });
 
@@ -152,67 +172,87 @@
     test('greaterThan', () {
       shouldPass(10, greaterThan(9));
       shouldFail(9, greaterThan(10),
-        "Expected: a value greater than <10> But: was <9>. Actual: <9>");
+        "Expected: a value greater than <10> "
+        "Actual: <9> "
+        "Which: is not a value greater than <10>");
     });
 
     test('greaterThanOrEqualTo', () {
       shouldPass(10, greaterThanOrEqualTo(10));
       shouldFail(9, greaterThanOrEqualTo(10),
-        "Expected: a value greater than or equal to <10> But: was <9>. "
-        "Actual: <9>");
+        "Expected: a value greater than or equal to <10> "
+        "Actual: <9> "
+        "Which: is not a value greater than or equal to <10>");
     });
 
     test('lessThan', () {
-      shouldFail(10, lessThan(9), "Expected: a value less than <9> "
-          "But: was <10>. Actual: <10>");
+      shouldFail(10, lessThan(9),
+          "Expected: a value less than <9> "
+          "Actual: <10> "
+          "Which: is not a value less than <9>");
       shouldPass(9, lessThan(10));
     });
 
     test('lessThanOrEqualTo', () {
       shouldPass(10, lessThanOrEqualTo(10));
       shouldFail(11, lessThanOrEqualTo(10),
-        "Expected: a value less than or equal to <10> But: was <11>. "
-        "Actual: <11>");
+        "Expected: a value less than or equal to <10> "
+        "Actual: <11> "
+        "Which: is not a value less than or equal to <10>");
     });
 
     test('isZero', () {
       shouldPass(0, isZero);
-      shouldFail(1, isZero, "Expected: a value equal to <0> But: was <1>."
-          " Actual: <1>");
+      shouldFail(1, isZero, 
+          "Expected: a value equal to <0> "
+          "Actual: <1> "
+          "Which: is not a value equal to <0>");
     });
 
     test('isNonZero', () {
-      shouldFail(0, isNonZero, "Expected: a value not equal to <0> "
-          "But: was <0>. Actual: <0>");
+      shouldFail(0, isNonZero,
+          "Expected: a value not equal to <0> "
+          "Actual: <0> "
+          "Which: is not a value not equal to <0>");
       shouldPass(1, isNonZero);
     });
 
     test('isPositive', () {
-      shouldFail(-1, isPositive, "Expected: a positive value "
-          "But: was <-1>. Actual: <-1>");
-      shouldFail(0, isPositive, "Expected: a positive value "
-          "But: was <0>. Actual: <0>");
+      shouldFail(-1, isPositive,
+          "Expected: a positive value "
+          "Actual: <-1> "
+          "Which: is not a positive value");
+      shouldFail(0, isPositive, 
+          "Expected: a positive value "
+          "Actual: <0> "
+          "Which: is not a positive value");
       shouldPass(1, isPositive);
     });
 
     test('isNegative', () {
       shouldPass(-1, isNegative);
       shouldFail(0, isNegative,
-          "Expected: a negative value But: was <0>. Actual: <0>");
+          "Expected: a negative value "
+          "Actual: <0> "
+          "Which: is not a negative value");
     });
 
     test('isNonPositive', () {
       shouldPass(-1, isNonPositive);
       shouldPass(0, isNonPositive);
       shouldFail(1, isNonPositive,
-          "Expected: a non-positive value But: was <1>. Actual: <1>");
+          "Expected: a non-positive value "
+          "Actual: <1> "
+          "Which: is not a non-positive value");
     });
 
     test('isNonNegative', () {
       shouldPass(1, isNonNegative);
       shouldPass(0, isNonNegative);
       shouldFail(-1, isNonNegative,
-        "Expected: a non-negative value But: was <-1>. Actual: <-1>");
+        "Expected: a non-negative value "
+        "Actual: <-1> "
+        "Which: is not a non-negative value");
     });
 
     test('closeTo', () {
@@ -221,40 +261,40 @@
       shouldPass(1, closeTo(0, 1));
       shouldFail(1.001, closeTo(0, 1),
           "Expected: a numeric value within <1> of <0> "
-          "But: differed by <1.001>. "
-          "Actual: <1.001>");
+          "Actual: <1.001> "
+          "Which: differs by <1.001>");
       shouldFail(-1.001, closeTo(0, 1),
           "Expected: a numeric value within <1> of <0> "
-          "But: differed by <1.001>. "
-          "Actual: <-1.001>");
+          "Actual: <-1.001> "
+          "Which: differs by <1.001>");
     });
 
     test('inInclusiveRange', () {
       shouldFail(-1, inInclusiveRange(0,2),
           "Expected: be in range from 0 (inclusive) to 2 (inclusive) "
-          "But: was <-1>. Actual: <-1>");
+          "Actual: <-1>");
       shouldPass(0, inInclusiveRange(0,2));
       shouldPass(1, inInclusiveRange(0,2));
       shouldPass(2, inInclusiveRange(0,2));
       shouldFail(3, inInclusiveRange(0,2),
           "Expected: be in range from 0 (inclusive) to 2 (inclusive) "
-          "But: was <3>. Actual: <3>");
+          "Actual: <3>");
     });
 
     test('inExclusiveRange', () {
       shouldFail(0, inExclusiveRange(0,2),
           "Expected: be in range from 0 (exclusive) to 2 (exclusive) "
-          "But: was <0>. Actual: <0>");
+          "Actual: <0>");
       shouldPass(1, inExclusiveRange(0,2));
       shouldFail(2, inExclusiveRange(0,2),
           "Expected: be in range from 0 (exclusive) to 2 (exclusive) "
-          "But: was <2>. Actual: <2>");
+          "Actual: <2>");
     });
 
     test('inOpenClosedRange', () {
       shouldFail(0, inOpenClosedRange(0,2),
           "Expected: be in range from 0 (exclusive) to 2 (inclusive) "
-          "But: was <0>. Actual: <0>");
+          "Actual: <0>");
       shouldPass(1, inOpenClosedRange(0,2));
       shouldPass(2, inOpenClosedRange(0,2));
     });
@@ -264,7 +304,7 @@
       shouldPass(1, inClosedOpenRange(0,2));
       shouldFail(2, inClosedOpenRange(0,2),
           "Expected: be in range from 0 (inclusive) to 2 (exclusive) "
-          "But: was <2>. Actual: <2>");
+          "Actual: <2>");
     });
   });
 
@@ -273,23 +313,24 @@
     test('isEmpty', () {
       shouldPass('', isEmpty);
       shouldFail(null, isEmpty,
-          "Expected: empty But: was <null>. Actual: <null>");
+          "Expected: empty Actual: <null>");
       shouldFail(0, isEmpty,
-          "Expected: empty But: was <0>. Actual: <0>");
-      shouldFail('a', isEmpty, "Expected: empty But: was 'a'. Actual: 'a'");
+          "Expected: empty Actual: <0>");
+      shouldFail('a', isEmpty, "Expected: empty Actual: 'a'");
     });
 
     test('equalsIgnoringCase', () {
       shouldPass('hello', equalsIgnoringCase('HELLO'));
       shouldFail('hi', equalsIgnoringCase('HELLO'),
-          "Expected: 'HELLO' ignoring case But: was 'hi'. Actual: 'hi'");
+          "Expected: 'HELLO' ignoring case Actual: 'hi'");
     });
 
     test('equalsIgnoringWhitespace', () {
       shouldPass(' hello   world  ', equalsIgnoringWhitespace('hello world'));
       shouldFail(' helloworld  ', equalsIgnoringWhitespace('hello world'),
           "Expected: 'hello world' ignoring whitespace "
-          "But: was 'helloworld'. Actual: ' helloworld '");
+          "Actual: ' helloworld ' "
+          "Which: is 'helloworld' with whitespace compressed");
     });
 
     test('startsWith', () {
@@ -298,7 +339,7 @@
       shouldPass('hello', startsWith('hello'));
       shouldFail('hello', startsWith('hello '),
           "Expected: a string starting with 'hello ' "
-          "But: was 'hello'. Actual: 'hello'");
+          "Actual: 'hello'");
     });
 
     test('endsWith', () {
@@ -307,7 +348,7 @@
       shouldPass('hello', endsWith('hello'));
       shouldFail('hello', endsWith(' hello'),
           "Expected: a string ending with ' hello' "
-          "But: was 'hello'. Actual: 'hello'");
+          "Actual: 'hello'");
     });
 
     test('contains', () {
@@ -317,7 +358,7 @@
       shouldPass('hello', contains('hell'));
       shouldPass('hello', contains('hello'));
       shouldFail('hello', contains(' '),
-          "Expected: contains ' ' But: was 'hello'. Actual: 'hello'");
+          "Expected: contains ' ' Actual: 'hello'");
     });
 
     test('stringContainsInOrder', () {
@@ -336,14 +377,14 @@
       shouldFail('goodbye cruel world',
         stringContainsInOrder(['goo', 'cruel', 'bye']),
         "Expected: a string containing 'goo', 'cruel', 'bye' in order "
-        "But: was 'goodbye cruel world'. Actual: 'goodbye cruel world'");
+        "Actual: 'goodbye cruel world'");
     });
 
     test('matches', () {
       shouldPass('c0d', matches('[a-z][0-9][a-z]'));
       shouldPass('c0d', matches(new RegExp('[a-z][0-9][a-z]')));
       shouldFail('cOd', matches('[a-z][0-9][a-z]'),
-          "Expected: match '[a-z][0-9][a-z]' But: was 'cOd'. Actual: 'cOd'");
+          "Expected: match '[a-z][0-9][a-z]' Actual: 'cOd'");
     });
   });
 
@@ -351,37 +392,70 @@
 
     test('isEmpty', () {
       shouldPass([], isEmpty);
-      shouldFail([1], isEmpty, "Expected: empty But: was [1]. Actual: [1]");
+      shouldFail([1], isEmpty, "Expected: empty Actual: [1]");
     });
 
     test('contains', () {
       var d = [1, 2];
       shouldPass(d, contains(1));
       shouldFail(d, contains(0), "Expected: contains <0> "
-          "But: was [1, 2]. Actual: [1, 2]");
+          "Actual: [1, 2]");
     });
 
     test('isIn', () {
       var d = [1, 2];
       shouldPass(1, isIn(d));
-      shouldFail(0, isIn(d), "Expected: is in [1, 2] But: was <0>. Actual: <0>");
+      shouldFail(0, isIn(d), "Expected: is in [1, 2] Actual: <0>");
     });
 
     test('everyElement', () {
       var d = [1, 2];
       var e = [1, 1, 1];
       shouldFail(d, everyElement(1),
-          "Expected: every element <1> But: position 1 was <2>. "
-          "Actual: [1, 2]");
+          "Expected: every element(<1>) "
+          "Actual: [1, 2] "
+          "Which: has value <2> which doesn't match <1> at index 1");
       shouldPass(e, everyElement(1));
     });
 
+    test('nested everyElement', () {
+      var d = [['foo', 'bar'], ['foo'], []];
+      var e = [['foo', 'bar'], ['foo'], 3, []];
+      shouldPass(d, everyElement(anyOf(isEmpty, contains('foo'))));
+      shouldFail(d, everyElement(everyElement(equals('foo'))),
+          "Expected: every element(every element('foo')) "
+          "Actual: [['foo', 'bar'], ['foo'], []] "
+          "Which: has value ['foo', 'bar'] which has value 'bar' "
+          "which is different. Expected: foo Actual: bar ^ "
+          "Differ at offset 0 at index 1 at index 0");
+      shouldFail(d, everyElement(allOf(hasLength(greaterThan(0)), 
+          contains('foo'))),
+           "Expected: every element((an object with length of a value "
+           "greater than <0> and contains 'foo')) "
+           "Actual: [['foo', 'bar'], ['foo'], []] "
+           "Which: has value [] which has length of <0> at index 2");
+      shouldFail(d, everyElement(allOf(contains('foo'),
+          hasLength(greaterThan(0)))),
+          "Expected: every element((contains 'foo' and "
+          "an object with length of a value greater than <0>)) "
+          "Actual: [['foo', 'bar'], ['foo'], []] "
+          "Which: has value [] which doesn't match (contains 'foo' and "
+          "an object with length of a value greater than <0>) at index 2");
+      shouldFail(e, everyElement(allOf(contains('foo'),
+          hasLength(greaterThan(0)))),
+          "Expected: every element((contains 'foo' and an object with "
+          "length of a value greater than <0>)) "
+          "Actual: [['foo', 'bar'], ['foo'], 3, []] "
+          "Which: has value <3> which is not a string, map or iterable "
+          "at index 2");
+    });
+
     test('someElement', () {
       var d = [1, 2];
       var e = [1, 1, 1];
       shouldPass(d, someElement(2));
       shouldFail(e, someElement(2),
-          "Expected: some element <2> But: was [1, 1, 1]. Actual: [1, 1, 1]");
+          "Expected: some element <2> Actual: [1, 1, 1]");
     });
 
     test('orderedEquals', () {
@@ -390,8 +464,8 @@
       shouldPass(d, orderedEquals([1, 2]));
       shouldFail(d, orderedEquals([2, 1]),
           "Expected: equals [2, 1] ordered "
-          "But: expected <2> but was <1> mismatch at position 0. "
-          "Actual: [1, 2]");
+          "Actual: [1, 2] "
+          "Which: was <1> instead of <2> at location [0]");
     });
 
     test('unorderedEquals', () {
@@ -399,16 +473,16 @@
       shouldPass(d, unorderedEquals([2, 1]));
       shouldFail(d, unorderedEquals([1]),
           "Expected: equals [1] unordered "
-          "But: has too many elements (2 > 1). "
-          "Actual: [1, 2]");
+          "Actual: [1, 2] "
+          "Which: has too many elements (2 > 1)");
       shouldFail(d, unorderedEquals([3, 2, 1]),
           "Expected: equals [3, 2, 1] unordered "
-          "But: has too few elements (2 < 3). "
-          "Actual: [1, 2]");
+          "Actual: [1, 2] "
+          "Which: has too few elements (2 < 3)");
       shouldFail(d, unorderedEquals([3, 1]),
           "Expected: equals [3, 1] unordered "
-          "But: has no match for element <3> at position 0. "
-          "Actual: [1, 2]");
+          "Actual: [1, 2] "
+          "Which: has no match for element <3> at index 0");
     });
 
     test('pairwise compare', () {
@@ -418,22 +492,22 @@
       shouldFail('x', pairwiseCompare(e, (e,a) => a <= e,
           "less than or equal"),
           "Expected: pairwise less than or equal [1, 4, 9] "
-          "But: not an Iterable. "
-          "Actual: 'x'");
+          "Actual: 'x' "
+          "Which: is not an Iterable");
       shouldFail(c, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"),
           "Expected: pairwise less than or equal [1, 4, 9] "
-          "But: length was 2 instead of 3. "
-          "Actual: [1, 2]");
+          "Actual: [1, 2] "
+          "Which: has length 2 instead of 3");
       shouldPass(d, pairwiseCompare(e, (e,a) => a <= e, "less than or equal"));
       shouldFail(d, pairwiseCompare(e, (e,a) => a < e, "less than"),
           "Expected: pairwise less than [1, 4, 9] "
-          "But: <1> not less than <1> at position 0. "
-          "Actual: [1, 2, 3]");
+          "Actual: [1, 2, 3] "
+          "Which: has <1> which is not less than <1> at index 0");
       shouldPass(d, pairwiseCompare(e, (e,a) => a * a == e, "square root of"));
       shouldFail(d, pairwiseCompare(e, (e,a) => a + a == e, "double"),
           "Expected: pairwise double [1, 4, 9] "
-          "But: <1> not double <1> at position 0. "
-          "Actual: [1, 2, 3]");
+          "Actual: [1, 2, 3] "
+          "Which: has <1> which is not double <1> at index 0");
     });
   });
 
@@ -444,7 +518,7 @@
       shouldPass({}, isEmpty);
       shouldPass(a, isEmpty);
       a['foo'] = 'bar';
-      shouldFail(a, isEmpty, "Expected: empty But: was {'foo': 'bar'}. "
+      shouldFail(a, isEmpty, "Expected: empty "
           "Actual: {'foo': 'bar'}");
     });
 
@@ -457,8 +531,9 @@
       c['bar'] = 'foo';
       shouldPass(a, equals(b));
       shouldFail(b, equals(c),
-          "Expected: {'bar': 'foo'} But: missing map key 'bar'. "
-          "Actual: {'foo': 'bar'}");
+          "Expected: {'bar': 'foo'} "
+          "Actual: {'foo': 'bar'} "
+          "Which: is missing map key 'bar'");
     });
 
     test('equals with different lengths', () {
@@ -472,28 +547,28 @@
       c['barrista'] = 'caffeine';
       shouldFail(a, equals(b),
           "Expected: {'foo': 'bar', 'bar': 'foo'} "
-          "But: different map lengths; missing map key 'bar'. "
-          "Actual: {'foo': 'bar'}");
+          "Actual: {'foo': 'bar'} "
+          "Which: has different length and is missing map key 'bar'");
       shouldFail(b, equals(a),
           "Expected: {'foo': 'bar'} "
-          "But: different map lengths; extra map key 'bar'. "
-          "Actual: {'foo': 'bar', 'bar': 'foo'}");
+          "Actual: {'foo': 'bar', 'bar': 'foo'} "
+          "Which: has different length and has extra map key 'bar'");
       shouldFail(b, equals(c),
           "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
-          "But: missing map key 'barrista'. "
-          "Actual: {'foo': 'bar', 'bar': 'foo'}");
+          "Actual: {'foo': 'bar', 'bar': 'foo'} "
+          "Which: is missing map key 'barrista'");
       shouldFail(c, equals(b),
           "Expected: {'foo': 'bar', 'bar': 'foo'} "
-          "But: missing map key 'foo'. "
-          "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
+          "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Which: is missing map key 'foo'");
       shouldFail(a, equals(c),
           "Expected: {'bar': 'foo', 'barrista': 'caffeine'} "
-          "But: different map lengths; missing map key 'bar'. "
-          "Actual: {'foo': 'bar'}");
+          "Actual: {'foo': 'bar'} "
+          "Which: has different length and is missing map key 'bar'");
       shouldFail(c, equals(a),
           "Expected: {'foo': 'bar'} "
-          "But: different map lengths; missing map key 'foo'. "
-          "Actual: {'bar': 'foo', 'barrista': 'caffeine'}");
+          "Actual: {'bar': 'foo', 'barrista': 'caffeine'} "
+          "Which: has different length and is missing map key 'foo'");
     });
 
     test('contains', () {
@@ -502,9 +577,10 @@
       var b = new Map();
       shouldPass(a, contains('foo'));
       shouldFail(b, contains('foo'),
-          "Expected: contains 'foo' But: was {}. Actual: {}");
+          "Expected: contains 'foo' Actual: {}");
       shouldFail(10, contains('foo'),
-          "Expected: contains 'foo' But: was <10>. Actual: <10>");
+          "Expected: contains 'foo' Actual: <10> "
+          "Which: is not a string, map or iterable");
     });
 
     test('containsValue', () {
@@ -512,7 +588,7 @@
       a['foo'] = 'bar';
       shouldPass(a, containsValue('bar'));
       shouldFail(a, containsValue('ba'),
-          "Expected: contains value 'ba' But: was {'foo': 'bar'}. "
+          "Expected: contains value 'ba' "
           "Actual: {'foo': 'bar'}");
     });
 
@@ -522,13 +598,13 @@
       shouldPass(a, containsPair('foo', 'bar'));
       shouldFail(a, containsPair('foo', 'ba'),
           "Expected: contains pair 'foo' => 'ba' "
-          "But: Strings are not equal. Both strings start the same, "
-          "but the given value also has the following trailing characters: r. "
-          "Actual: {'foo': 'bar'}");
+          "Actual: {'foo': 'bar'} "
+          "Which: is different. Both strings start the same, but "
+          "the given value also has the following trailing characters: r");
       shouldFail(a, containsPair('fo', 'bar'),
           "Expected: contains pair 'fo' => 'bar' "
-          "But: doesn't contain key 'fo'. "
-          "Actual: {'foo': 'bar'}");
+          "Actual: {'foo': 'bar'} "
+          "Which: doesn't contain key 'fo'");
     });
 
     test('hasLength', () {
@@ -538,8 +614,8 @@
       shouldPass(a, hasLength(1));
       shouldFail(b, hasLength(1),
           "Expected: an object with length of <1> "
-          "But: had length of <0>. "
-          "Actual: {}");
+          "Actual: {} "
+          "Which: has length of <0>");
     });
   });
 
@@ -547,7 +623,7 @@
 
     test('anyOf', () {
       shouldFail(0, anyOf([equals(1), equals(2)]),
-          "Expected: (<1> or <2>) But: was <0>. Actual: <0>");
+          "Expected: (<1> or <2>) Actual: <0>");
       shouldPass(1, anyOf([equals(1), equals(2)]));
     });
 
@@ -555,7 +631,8 @@
       shouldPass(1, allOf([lessThan(10), greaterThan(0)]));
       shouldFail(-1, allOf([lessThan(10), greaterThan(0)]),
           "Expected: (a value less than <10> and a value greater than <0>) "
-          "But: was <-1> (wasn't a value greater than <0>). Actual: <-1>");
+          "Actual: <-1> "
+          "Which: is not a value greater than <0>");
     });
   });
 
@@ -615,8 +692,9 @@
       var completer = new Completer();
       completer.completeError('X');
       shouldFail(completer.future, throwsA(equals('Y')),
-          "Expected: 'Y' But: Strings are not equal. "
-          "Expected: Y Actual: X ^ Differ at position 0. Actual: 'X'",
+          "Expected: 'Y' Actual: 'X' "
+          "Which: is different. "
+          "Expected: Y Actual: X ^ Differ at offset 0",
           isAsync: true);
     });
   });
@@ -624,7 +702,7 @@
   group('Predicate Matchers', () {
     test('isInstanceOf', () {
       shouldFail(0, predicate((x) => x is String, "an instance of String"),
-          "Expected: an instance of String But: was <0>. Actual: <0>");
+          "Expected: an instance of String Actual: <0>");
       shouldPass('cow', predicate((x) => x is String, "an instance of String"));
     });
   });
diff --git a/pkg/unittest/test/matchers_unminified_test.dart b/pkg/unittest/test/matchers_unminified_test.dart
index 51629ca..11fb2e9 100644
--- a/pkg/unittest/test/matchers_unminified_test.dart
+++ b/pkg/unittest/test/matchers_unminified_test.dart
@@ -22,9 +22,10 @@
       shouldFail(() { throw new Exception(); },
           throwsFormatException,
           matches(
-              r"Expected: throws an exception which matches FormatException +"
-              r"But:  exception \?:<Exception> does not match FormatException\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws FormatException +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
+
     });
 
     test('throwsArgumentError', () {
@@ -33,10 +34,9 @@
       shouldFail(() { throw new Exception(); },
           throwsArgumentError,
           matches(
-              r"Expected: throws an exception which matches ArgumentError +"
-              r"But:  exception \?:<Exception> does not match "
-                  r"ArgumentError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws ArgumentError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
 
     test('throwsRangeError', () {
@@ -45,9 +45,9 @@
       shouldFail(() { throw new Exception(); },
           throwsRangeError,
           matches(
-              r"Expected: throws an exception which matches RangeError +"
-              r"But:  exception \?:<Exception> does not match RangeError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws RangeError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
 
     test('throwsNoSuchMethodError', () {
@@ -56,10 +56,9 @@
       shouldFail(() { throw new Exception(); },
           throwsNoSuchMethodError,
           matches(
-              r"Expected: throws an exception which matches NoSuchMethodError +"
-              r"But:  exception \?:<Exception> does not match "
-                  r"NoSuchMethodError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws NoSuchMethodError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
 
     test('throwsUnimplementedError', () {
@@ -68,11 +67,9 @@
       shouldFail(() { throw new Exception(); },
           throwsUnimplementedError,
           matches(
-              r"Expected: throws an exception which matches "
-                  r"UnimplementedError +"
-              r"But:  exception \?:<Exception> does not match "
-                  r"UnimplementedError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws UnimplementedError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
 
     test('throwsUnsupportedError', () {
@@ -81,10 +78,9 @@
       shouldFail(() { throw new Exception(); },
           throwsUnsupportedError,
           matches(
-              r"Expected: throws an exception which matches UnsupportedError +"
-              r"But:  exception \?:<Exception> does not match "
-                  r"UnsupportedError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws UnsupportedError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
 
     test('throwsStateError', () {
@@ -93,10 +89,9 @@
       shouldFail(() { throw new Exception(); },
           throwsStateError,
           matches(
-              r"Expected: throws an exception which matches StateError +"
-              r"But:  exception \?:<Exception> does not match "
-                  r"StateError\."
-              r"Actual: <Closure(: \(dynamic\) => dynamic)?>"));
+              r"Expected: throws StateError +"
+              r"Actual: <Closure(: \(dynamic\) => dynamic)?> +"
+              r"Which: threw \?:<Exception>"));
     });
   });
 
@@ -106,7 +101,6 @@
       var e = new SimpleIterable(1);
       shouldPass(d, isEmpty);
       shouldFail(e, isEmpty, "Expected: empty "
-          "But: was SimpleIterable:[1]. "
           "Actual: SimpleIterable:[1]");
     });
 
@@ -115,7 +109,6 @@
       shouldPass(d, contains(2));
       shouldFail(d, contains(5),
           "Expected: contains <5> "
-          "But: was SimpleIterable:[3, 2, 1]. "
           "Actual: SimpleIterable:[3, 2, 1]");
     });
   });
@@ -128,8 +121,9 @@
       shouldPass(w, new HasPrice(greaterThan(0)));
       shouldFail(w, new HasPrice(greaterThan(10)),
           "Expected: Widget with a price that is a value greater than <10> "
-          "But: price was <10>. "
-          "Actual: <Instance of 'Widget'>");
+          "Actual: <Instance of 'Widget'> "
+          "Which: has price with value <10> which is not "
+          "a value greater than <10>");
     });
   });
 }
diff --git a/pkg/unittest/test/test_utils.dart b/pkg/unittest/test/test_utils.dart
index f0b276d..5364da6 100644
--- a/pkg/unittest/test/test_utils.dart
+++ b/pkg/unittest/test/test_utils.dart
@@ -69,7 +69,7 @@
 class PrefixMatcher extends BaseMatcher {
   final String _prefix;
   const PrefixMatcher(this._prefix);
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     return item is String &&
         (collapseWhitespace(item)).startsWith(collapseWhitespace(_prefix));
   }
diff --git a/pkg/unittest/test/unittest_test.dart b/pkg/unittest/test/unittest_test.dart
index d6486c4..55d2245 100644
--- a/pkg/unittest/test/unittest_test.dart
+++ b/pkg/unittest/test/unittest_test.dart
@@ -405,7 +405,7 @@
   var tests = {
     'single correct test': buildStatusString(1, 0, 0, 'single correct test'),
     'single failing test': buildStatusString(0, 1, 0, 'single failing test',
-        message: 'Expected: <5> But: was <4>. Actual: <4>'),
+        message: 'Expected: <5> Actual: <4>'),
     'exception test': buildStatusString(0, 1, 0, 'exception test',
         message: 'Caught Exception: Fail.'),
     'group name test': buildStatusString(2, 0, 0, 'a a::a b b'),
@@ -427,7 +427,7 @@
         message: 'Callback called (2) after test case testOne has already '
                  'been marked as pass.:testTwo:'),
     'middle exception test': buildStatusString(2, 1, 0,
-        'testOne::testTwo:Expected: false But: was <true>. Actual: <true>:testThree'),
+        'testOne::testTwo:Expected: false Actual: <true>:testThree'),
     'async setup/teardown test': buildStatusString(2, 0, 3,
         'good setup/good teardown foo1::'
         'good setup/bad teardown foo2:good setup/bad teardown '
@@ -440,13 +440,13 @@
     'test returning future': buildStatusString(2, 4, 0,
         'successful::'
         'error1:Callback called more times than expected (1).:'
-        'fail1:Expected: <false> But: was <true>. Actual: <true>:'
+        'fail1:Expected: <false> Actual: <true>:'
         'error2:Callback called more times than expected (1).:'
         'fail2:failure:'
         'foo5'),
     'test returning future using runAsync': buildStatusString(2, 4, 0,
         'successful::'
-        'fail1:Expected: <false> But: was <true>. Actual: <true>:'
+        'fail1:Expected: <false> Actual: <true>:'
         'error1:Callback called more times than expected (1).:'
         'fail2:failure:'
         'error2:Callback called more times than expected (1).:'
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index fa7a79c..3537e32 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -52,6 +52,7 @@
   V(File_LinkTarget, 1)                                                        \
   V(File_Delete, 1)                                                            \
   V(File_DeleteLink, 1)                                                        \
+  V(File_Rename, 2)                                                            \
   V(File_FullPath, 1)                                                          \
   V(File_OpenStdio, 1)                                                         \
   V(File_GetStdioHandleType, 1)                                                \
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index a971f961..87fc2c1 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -506,6 +506,24 @@
 }
 
 
+void FUNCTION_NAME(File_Rename)(Dart_NativeArguments args) {
+  Dart_EnterScope();
+  const char* old_path =
+      DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+  const char* new_path =
+      DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+  bool result = File::Rename(old_path, new_path);
+  if (result) {
+    Dart_SetReturnValue(args, Dart_NewBoolean(result));
+  } else {
+    Dart_Handle err = DartUtils::NewDartOSError();
+    if (Dart_IsError(err)) Dart_PropagateError(err);
+    Dart_SetReturnValue(args, err);
+  }
+  Dart_ExitScope();
+}
+
+
 void FUNCTION_NAME(File_FullPath)(Dart_NativeArguments args) {
   Dart_EnterScope();
   const char* str =
@@ -707,6 +725,20 @@
 }
 
 
+static CObject* FileRenameRequest(const CObjectArray& request) {
+  if (request.Length() == 3 &&
+      request[1]->IsString() &&
+      request[2]->IsString()) {
+    CObjectString old_path(request[1]);
+    CObjectString new_path(request[2]);
+    bool completed = File::Rename(old_path.CString(), new_path.CString());
+    if (completed) return CObject::True();
+    return CObject::NewOSError();
+  }
+  return CObject::IllegalArgumentError();
+}
+
+
 static CObject* FileFullPathRequest(const CObjectArray& request) {
   if (request.Length() == 2 && request[1]->IsString()) {
     CObjectString filename(request[1]);
@@ -1168,6 +1200,9 @@
         case File::kDeleteRequest:
           response = FileDeleteRequest(request);
           break;
+        case File::kRenameRequest:
+          response = FileRenameRequest(request);
+          break;
         case File::kFullPathRequest:
           response = FileFullPathRequest(request);
           break;
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 839c557..a2bf20d 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -65,27 +65,28 @@
     kExistsRequest = 0,
     kCreateRequest = 1,
     kDeleteRequest = 2,
-    kOpenRequest = 3,
-    kFullPathRequest = 4,
-    kCloseRequest = 5,
-    kPositionRequest = 6,
-    kSetPositionRequest = 7,
-    kTruncateRequest = 8,
-    kLengthRequest = 9,
-    kLengthFromPathRequest = 10,
-    kLastModifiedRequest = 11,
-    kFlushRequest = 12,
-    kReadByteRequest = 13,
-    kWriteByteRequest = 14,
-    kReadRequest = 15,
-    kReadIntoRequest = 16,
-    kWriteFromRequest = 17,
-    kCreateLinkRequest = 18,
-    kDeleteLinkRequest = 19,
-    kLinkTargetRequest = 20,
-    kTypeRequest = 21,
-    kIdenticalRequest = 22,
-    kStatRequest = 23
+    kRenameRequest = 3,
+    kOpenRequest = 4,
+    kFullPathRequest = 5,
+    kCloseRequest = 6,
+    kPositionRequest = 7,
+    kSetPositionRequest = 8,
+    kTruncateRequest = 9,
+    kLengthRequest = 10,
+    kLengthFromPathRequest = 11,
+    kLastModifiedRequest = 12,
+    kFlushRequest = 13,
+    kReadByteRequest = 14,
+    kWriteByteRequest = 15,
+    kReadRequest = 16,
+    kReadIntoRequest = 17,
+    kWriteFromRequest = 18,
+    kCreateLinkRequest = 19,
+    kDeleteLinkRequest = 20,
+    kLinkTargetRequest = 21,
+    kTypeRequest = 22,
+    kIdenticalRequest = 23,
+    kStatRequest = 24
   };
 
   enum FileStat {
@@ -152,6 +153,7 @@
   static bool CreateLink(const char* path, const char* target);
   static bool Delete(const char* path);
   static bool DeleteLink(const char* path);
+  static bool Rename(const char* old_path, const char* new_path);
   static off_t LengthFromPath(const char* path);
   static void Stat(const char* path, int64_t* data);
   static time_t LastModified(const char* path);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 939929a..513f96e 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -192,6 +192,19 @@
 }
 
 
+bool File::Rename(const char* old_path, const char* new_path) {
+  File::Type type = File::GetType(old_path, true);
+  if (type == kIsFile) {
+    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+  } else if (type == kIsDirectory) {
+    errno = EISDIR;
+  } else {
+    errno = ENOENT;
+  }
+  return false;
+}
+
+
 off_t File::LengthFromPath(const char* name) {
   struct stat st;
   if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 8f1a114..840e6b9 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -193,6 +193,19 @@
 }
 
 
+bool File::Rename(const char* old_path, const char* new_path) {
+  File::Type type = File::GetType(old_path, true);
+  if (type == kIsFile) {
+    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+  } else if (type == kIsDirectory) {
+    errno = EISDIR;
+  } else {
+    errno = ENOENT;
+  }
+  return false;
+}
+
+
 off_t File::LengthFromPath(const char* name) {
   struct stat st;
   if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index e29c6ab..c2308b6 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -195,6 +195,19 @@
 }
 
 
+bool File::Rename(const char* old_path, const char* new_path) {
+  File::Type type = File::GetType(old_path, true);
+  if (type == kIsFile) {
+    return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+  } else if (type == kIsDirectory) {
+    errno = EISDIR;
+  } else {
+    errno = ENOENT;
+  }
+  return false;
+}
+
+
 off_t File::LengthFromPath(const char* name) {
   struct stat st;
   if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 218c729..e788a42 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -14,6 +14,8 @@
   /* patch */ static _linkTarget(String path) native "File_LinkTarget";
   /* patch */ static _delete(String path) native "File_Delete";
   /* patch */ static _deleteLink(String path) native "File_DeleteLink";
+  /* patch */ static _rename(String oldPath, String newPath)
+      native "File_Rename";
   /* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
   /* patch */ static _lastModified(String path) native "File_LastModified";
   /* patch */ static _open(String path, int mode) native "File_Open";
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index d149c08..723bd6c 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -286,6 +286,26 @@
 }
 
 
+bool File::Rename(const char* old_path, const char* new_path) {
+  File::Type type = GetType(old_path, false);
+  if (type == kIsFile) {
+    const wchar_t* system_old_path = StringUtils::Utf8ToWide(old_path);
+    const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path);
+    DWORD flags = MOVEFILE_WRITE_THROUGH;
+    int move_status =
+        MoveFileExW(system_old_path, system_new_path, flags);
+    free(const_cast<wchar_t*>(system_old_path));
+    free(const_cast<wchar_t*>(system_new_path));
+    return (move_status != 0);
+  } else if (type == kIsDirectory) {
+    SetLastError(ERROR_FILE_NOT_FOUND);
+  } else {
+    SetLastError(ERROR_FILE_NOT_FOUND);
+  }
+  return false;
+}
+
+
 off_t File::LengthFromPath(const char* name) {
   struct _stat st;
   const wchar_t* system_name = StringUtils::Utf8ToWide(name);
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index ec54765..3a3fd9d 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -266,7 +266,7 @@
   BOOL optval = true;
   int status = setsockopt(s,
                           SOL_SOCKET,
-                          SO_REUSEADDR,
+                          SO_EXCLUSIVEADDRUSE,
                           reinterpret_cast<const char*>(&optval),
                           sizeof(optval));
   if (status == SOCKET_ERROR) {
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 790f6f6..a6ea151 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -79,6 +79,32 @@
   return Dart_True();  // Indicates success.  Result is in is_mirror.
 }
 
+static Dart_Handle IsMethodMirror(Dart_Handle object, bool* is_mirror) {
+  Dart_Handle cls_name = NewString("MethodMirror");
+  Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+  if (Dart_IsError(cls)) {
+    return cls;
+  }
+  Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+  if (Dart_IsError(result)) {
+    return result;
+  }
+  return Dart_True();  // Indicates success.  Result is in is_mirror.
+}
+
+static Dart_Handle IsVariableMirror(Dart_Handle object, bool* is_mirror) {
+  Dart_Handle cls_name = NewString("VariableMirror");
+  Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name);
+  if (Dart_IsError(cls)) {
+    return cls;
+  }
+  Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror);
+  if (Dart_IsError(result)) {
+    return result;
+  }
+  return Dart_True();  // Indicates success.  Result is in is_mirror.
+}
+
 
 static bool IsSimpleValue(Dart_Handle object) {
   return (Dart_IsNull(object) ||
@@ -133,6 +159,11 @@
   return vm_ref;
 }
 
+static Dart_Handle StringFromSymbol(Dart_Handle symbol) {
+  Dart_Handle result = Dart_Invoke(MirrorLib(), NewString("_n"), 1, &symbol);
+  return result;
+}
+
 
 static Dart_Handle UnwrapVMReference(Dart_Handle vm_ref) {
   // Retrieve the persistent handle from the VMReference
@@ -151,8 +182,9 @@
   return handle;
 }
 
+static Dart_Handle UnwrapMirror(Dart_Handle mirror);
 
-static Dart_Handle UnwrapMirror(Dart_Handle mirror) {
+static Dart_Handle UnwrapObjectMirror(Dart_Handle mirror) {
   Dart_Handle field_name = NewString("_reference");
   Dart_Handle vm_ref = Dart_GetField(mirror, field_name);
   if (Dart_IsError(vm_ref)) {
@@ -162,6 +194,78 @@
 }
 
 
+static Dart_Handle UnwrapMethodMirror(Dart_Handle methodMirror) {
+  Dart_Handle namefield_name = NewString("simpleName");
+  Dart_Handle name_ref = Dart_GetField(methodMirror, namefield_name);
+  if (Dart_IsError(name_ref)) {
+    return name_ref;
+  }
+  Dart_Handle ownerfield_name = NewString("_owner");
+  Dart_Handle owner_mirror = Dart_GetField(methodMirror, ownerfield_name);
+  if (Dart_IsError(owner_mirror)) {
+    return owner_mirror;
+  }
+  Dart_Handle owner = UnwrapMirror(owner_mirror);
+  if (Dart_IsError(owner)) {
+    return owner;
+  }
+  Dart_Handle func = Dart_LookupFunction(owner, StringFromSymbol(name_ref));
+  if (Dart_IsError(func)) {
+    return func;
+  }
+  ASSERT(!Dart_IsNull(func));
+  return func;
+}
+
+static Dart_Handle UnwrapVariableMirror(Dart_Handle variableMirror) {
+  Dart_Handle namefield_name = NewString("simpleName");
+  Dart_Handle name_ref = Dart_GetField(variableMirror, namefield_name);
+  if (Dart_IsError(name_ref)) {
+    return name_ref;
+  }
+  Dart_Handle ownerfield_name = NewString("_owner");
+  Dart_Handle owner_mirror = Dart_GetField(variableMirror, ownerfield_name);
+  ASSERT(!Dart_IsNull(owner_mirror));
+  if (Dart_IsError(owner_mirror)) {
+    return owner_mirror;
+  }
+  Dart_Handle owner = UnwrapMirror(owner_mirror);
+  if (Dart_IsError(owner)) {
+    return owner;
+  }
+  Dart_Handle variable =
+  Dart_LookupVariable(owner, StringFromSymbol(name_ref));
+  if (Dart_IsError(variable)) {
+    return variable;
+  }
+  ASSERT(!Dart_IsNull(variable));
+  return variable;
+}
+
+static Dart_Handle UnwrapMirror(Dart_Handle mirror) {
+  // Caveat Emptor:
+  // only works for ObjectMirrors, VariableMirrors and MethodMirrors
+  // and their subtypes
+  bool is_method_mirror = false;
+  Dart_Handle result = IsMethodMirror(mirror, &is_method_mirror);
+  if (Dart_IsError(result)) {
+    return result;
+  }
+  if (is_method_mirror) {
+    return UnwrapMethodMirror(mirror);
+  }
+  bool is_variable_mirror = false;
+  result = IsVariableMirror(mirror, &is_variable_mirror);
+  if (Dart_IsError(result)) {
+    return result;
+  }
+  if (is_variable_mirror) {
+    return UnwrapVariableMirror(mirror);
+  }
+  return UnwrapObjectMirror(mirror);
+  // will return nonsense if mirror is not an ObjectMirror
+}
+
 static Dart_Handle UnwrapArg(Dart_Handle arg) {
     if (Dart_IsError(arg)) {
       return arg;
@@ -466,6 +570,7 @@
   }
 
   // TODO(turnidge): Why am I getting Null when I expect Object?
+  // TODO(gbracha): this is probably the root of bug 7868
   Dart_Handle super_class = Dart_GetSuperclass(intf);
   if (Dart_IsNull(super_class)) {
     super_class = Dart_GetClass(CoreLib(), NewString("Object"));
@@ -1108,6 +1213,20 @@
   Dart_ExitScope();
 }
 
+void NATIVE_ENTRY_FUNCTION(Mirrors_metadata)(Dart_NativeArguments args) {
+  Dart_EnterScope();
+  Dart_Handle mirror = Dart_GetNativeArgument(args, 0);
+
+  Dart_Handle reflectee = UnwrapMirror(mirror);
+  Dart_Handle result = Dart_GetMetadata(reflectee);
+  if (Dart_IsError(result)) {
+    Dart_PropagateError(result);
+  }
+  ASSERT(Dart_IsList(result));
+  Dart_SetReturnValue(args, result);
+  Dart_ExitScope();
+}
+
 void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_invoke)(
     Dart_NativeArguments args) {
   Dart_EnterScope();
@@ -1278,7 +1397,6 @@
   Dart_ExitScope();
 }
 
-
 void HandleMirrorsMessage(Isolate* isolate,
                           Dart_Port reply_port,
                           const Instance& message) {
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index ef95c2b..cb18187 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -70,6 +70,10 @@
     return result;
 }
 
+List<InstanceMirror> _metadata(mirror) 
+  native 'Mirrors_metadata';
+
+
 class _LocalMirrorSystemImpl extends MirrorSystem {
   // Change parameter back to "this.libraries" when native code is changed.
   _LocalMirrorSystemImpl(Map<String, LibraryMirror> libraries, this.isolate)
@@ -602,6 +606,10 @@
     }
   }
 
+  // get the metadata objects, convert them into InstanceMirrors using
+  // reflect() and then make them into a Dart list
+  List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
   static _invokeConstructor(ref, constructorName, positionalArguments, async)
       native 'LocalClassMirrorImpl_invokeConstructor';
 }
@@ -704,6 +712,10 @@
     return _upperBound;
   }
 
+  // get the metadata objects, convert them into InstanceMirrors using
+  // reflect() and then make them into a Dart list
+  List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
   String toString() => "TypeVariableMirror on '$simpleName'";
 }
 
@@ -843,6 +855,10 @@
     return _variables;
   }
 
+  // get the metadata objects, convert them into InstanceMirrors using
+  // reflect() and then make them into a Dart list
+  List<InstanceMirror> get metadata => _metadata(this).map(reflect).toList();
+
   String toString() => "LibraryMirror on '$simpleName'";
 }
 
@@ -943,6 +959,13 @@
   final bool isRedirectingConstructor;
   final bool isFactoryConstructor;
 
+  List<InstanceMirror> get metadata {
+    owner; // ensure owner is computed
+    // get the metadata objects, convert them into InstanceMirrors using
+    // reflect() and then make them into a Dart list
+    return _metadata(this).map(reflect).toList();
+  }
+
   String toString() => "MethodMirror on '$simpleName'";
 }
 
@@ -997,6 +1020,13 @@
   final bool isStatic;
   final bool isFinal;
 
+  List<InstanceMirror> get metadata {
+    owner; // ensure owner is computed
+    // get the metadata objects, convert them into InstanceMirrors using
+    // reflect() and then make them into a Dart list
+    return _metadata(this).map(reflect).toList();
+  }
+
   String toString() => "VariableMirror on '$simpleName'";
 }
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index a7adc56..29b9253 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -235,8 +235,9 @@
   V(isolate_spawnUri, 1)                                                       \
   V(Mirrors_isLocalPort, 1)                                                    \
   V(Mirrors_makeLocalInstanceMirror, 1)                                        \
-  V(Mirrors_makeLocalClassMirror, 1)                                        \
+  V(Mirrors_makeLocalClassMirror, 1)                                           \
   V(Mirrors_makeLocalMirrorSystem, 0)                                          \
+  V(Mirrors_metadata, 1)                                                       \
   V(LocalObjectMirrorImpl_invoke, 4)                                           \
   V(LocalObjectMirrorImpl_getField, 2)                                         \
   V(LocalObjectMirrorImpl_setField, 4)                                         \
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index a524b8e..b869940 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2853,7 +2853,8 @@
 
 
 void EffectGraphVisitor::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
-  LoadStaticFieldInstr* load = new LoadStaticFieldInstr(node->field());
+  Value* field_value = Bind(new ConstantInstr(node->field()));
+  LoadStaticFieldInstr* load = new LoadStaticFieldInstr(field_value);
   ReturnDefinition(load);
 }
 
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index e3d2acf..3a1c685 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -22,19 +22,19 @@
 #define RECOGNIZED_LIST_FACTORY_LIST(V)                                        \
   V(ObjectArrayFactory, kArrayCid, 97987288)                                   \
   V(GrowableObjectArrayWithData, kGrowableObjectArrayCid, 816132033)           \
-  V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 552407276)            \
-  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1168404493)                     \
-  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 2094565809)                   \
-  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1449285088)     \
-  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1430476167)                   \
-  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 996241892)                  \
-  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 360797715)                    \
-  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 995053409)                  \
-  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 570248142)                    \
-  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1114332856)                 \
-  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1896334311)               \
-  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1719636031)               \
-  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1768466392)           \
+  V(GrowableObjectArrayFactory, kGrowableObjectArrayCid, 1821003625)           \
+  V(_Int8ArrayFactory, kTypedDataInt8ArrayCid, 1139775342)                     \
+  V(_Uint8ArrayFactory, kTypedDataUint8ArrayCid, 2065936658)                   \
+  V(_Uint8ClampedArrayFactory, kTypedDataUint8ClampedArrayCid, 1420655937)     \
+  V(_Int16ArrayFactory, kTypedDataInt16ArrayCid, 1401847016)                   \
+  V(_Uint16ArrayFactory, kTypedDataUint16ArrayCid, 967612741)                  \
+  V(_Int32ArrayFactory, kTypedDataInt32ArrayCid, 332168564)                    \
+  V(_Uint32ArrayFactory, kTypedDataUint32ArrayCid, 966424258)                  \
+  V(_Int64ArrayFactory, kTypedDataInt64ArrayCid, 541618991)                    \
+  V(_Uint64ArrayFactory, kTypedDataUint64ArrayCid, 1085703705)                 \
+  V(_Float64ArrayFactory, kTypedDataFloat64ArrayCid, 1867705160)               \
+  V(_Float32ArrayFactory, kTypedDataFloat32ArrayCid, 1691006880)               \
+  V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 1739837241)           \
 
 
 // An class to collect the exits from an inlined function during graph
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 5094329..36646d3 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -3670,7 +3670,8 @@
 
     LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
     if (load_static_field != NULL) {
-      return Alias::Field(GetFieldId(kAnyInstance, load_static_field->field()));
+      return Alias::Field(GetFieldId(kAnyInstance,
+                                     load_static_field->StaticField()));
     }
 
     UNREACHABLE();
@@ -3846,7 +3847,7 @@
 
     LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
     if (load_static_field != NULL) {
-      return load_static_field->field().is_final();
+      return load_static_field->StaticField().is_final();
     }
 
     return false;
@@ -3974,7 +3975,7 @@
       location = store_field->offset_in_bytes();
     } else if (key->IsLoadStaticField()) {
       LoadStaticFieldInstr* load_static_field = key->AsLoadStaticField();
-      object = String::Handle(load_static_field->field().name()).Hash();
+      object = String::Handle(load_static_field->StaticField().name()).Hash();
     } else if (key->IsStoreStaticField()) {
       StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
       object = String::Handle(store_static_field->field().name()).Hash();
@@ -4004,7 +4005,7 @@
       if (key->IsStoreStaticField()) {
         LoadStaticFieldInstr* load_static_field = kv->AsLoadStaticField();
         StoreStaticFieldInstr* store_static_field = key->AsStoreStaticField();
-        return load_static_field->field().raw() ==
+        return load_static_field->StaticField().raw() ==
             store_static_field->field().raw();
       }
       return false;
@@ -5236,7 +5237,7 @@
 
 
 void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
-  const Field& field = instr->field();
+  const Field& field = instr->StaticField();
   ASSERT(field.is_static());
   if (field.is_final()) {
     Instance& obj = Instance::Handle(field.value());
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 5b6d6b2..0ffb7f0 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -888,7 +888,7 @@
 CompileType LoadStaticFieldInstr::ComputeType() const {
   if (FLAG_enable_type_checks) {
     return CompileType::FromAbstractType(
-        AbstractType::ZoneHandle(field().type()));
+        AbstractType::ZoneHandle(StaticField().type()));
   }
   return CompileType::Dynamic();
 }
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index f7aa016..1a4f025 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -440,7 +440,7 @@
 
 
 void LoadStaticFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
-  f->Print("%s", String::Handle(field().name()).ToCString());
+  field_value()->PrintTo(f);
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 186e148..8cc2bcd 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -173,7 +173,7 @@
 
 
 EffectSet LoadStaticFieldInstr::Dependencies() const {
-  return field().is_final() ? EffectSet::None() : EffectSet::All();
+  return StaticField().is_final() ? EffectSet::None() : EffectSet::All();
 }
 
 
@@ -181,9 +181,16 @@
   LoadStaticFieldInstr* other_load = other->AsLoadStaticField();
   ASSERT(other_load != NULL);
   // Assert that the field is initialized.
-  ASSERT(field().value() != Object::sentinel().raw());
-  ASSERT(field().value() != Object::transition_sentinel().raw());
-  return field().raw() == other_load->field().raw();
+  ASSERT(StaticField().value() != Object::sentinel().raw());
+  ASSERT(StaticField().value() != Object::transition_sentinel().raw());
+  return StaticField().raw() == other_load->StaticField().raw();
+}
+
+
+const Field& LoadStaticFieldInstr::StaticField() const {
+  Field& field = Field::Handle();
+  field ^= field_value()->BoundConstant().raw();
+  return field;
 }
 
 
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index e3bd33d..0ad33b9 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -60,22 +60,22 @@
   V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050)          \
   V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050)     \
   V(_StringBase, get:length, StringBaseLength, 320803993)                      \
-  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1026765313)                   \
+  V(_StringBase, get:isEmpty, StringBaseIsEmpty, 110631520)                    \
   V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 984449525)                  \
   V(_StringBase, [], StringBaseCharAt, 1062366987)                             \
   V(_OneByteString, _setAt, OneByteStringSetAt, 342452817)                     \
-  V(_IntegerImplementation, toDouble, IntegerToDouble, 1267108971)             \
+  V(_IntegerImplementation, toDouble, IntegerToDouble, 1331752138)             \
   V(_Double, toInt, DoubleToInteger, 362666636)                                \
   V(_Double, truncateToDouble, DoubleTruncate, 620870996)                      \
   V(_Double, roundToDouble, DoubleRound, 620870996)                            \
   V(_Double, floorToDouble, DoubleFloor, 620870996)                            \
   V(_Double, ceilToDouble, DoubleCeil, 620870996)                              \
-  V(_Double, pow, DoublePow, 631903778)                                        \
+  V(_Double, pow, DoublePow, 102305574)                                        \
   V(_Double, _modulo, DoubleMod, 437099337)                                    \
   V(::, sqrt, MathSqrt, 1662640002)                                            \
-  V(Float32x4, Float32x4., Float32x4Constructor, 1327837070)                   \
-  V(Float32x4, Float32x4.zero, Float32x4Zero, 927169529)                       \
-  V(Float32x4, Float32x4.splat, Float32x4Splat, 1778587275)                    \
+  V(Float32x4, Float32x4., Float32x4Constructor, 1492157358)                   \
+  V(Float32x4, Float32x4.zero, Float32x4Zero, 444339161)                       \
+  V(Float32x4, Float32x4.splat, Float32x4Splat, 1843231403)                    \
   V(_Float32x4, get:xxxx, Float32x4ShuffleXXXX, 42621627)                      \
   V(_Float32x4, get:yyyy, Float32x4ShuffleYYYY, 42621627)                      \
   V(_Float32x4, get:zzzz, Float32x4ShuffleZZZZ, 42621627)                      \
@@ -104,12 +104,12 @@
   V(_Float32x4, withZ, Float32x4WithZ, 219466242)                              \
   V(_Float32x4, withW, Float32x4WithW, 219466242)                              \
   V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 1044409108)                  \
-  V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 1489869343)              \
+  V(Uint32x4, Uint32x4.bool, Uint32x4BoolConstructor, 487876159)               \
   V(_Uint32x4, get:flagX, Uint32x4GetFlagX, 782547529)                         \
   V(_Uint32x4, get:flagY, Uint32x4GetFlagY, 782547529)                         \
   V(_Uint32x4, get:flagZ, Uint32x4GetFlagZ, 782547529)                         \
   V(_Uint32x4, get:flagW, Uint32x4GetFlagW, 782547529)                         \
-  V(_Uint32x4, select, Uint32x4Select, 405662786)                              \
+  V(_Uint32x4, select, Uint32x4Select, 810336099)                              \
   V(_Uint32x4, withFlagX, Uint32x4WithFlagX, 980864994)                        \
   V(_Uint32x4, withFlagY, Uint32x4WithFlagY, 980864994)                        \
   V(_Uint32x4, withFlagZ, Uint32x4WithFlagZ, 980864994)                        \
@@ -3380,28 +3380,32 @@
 };
 
 
-class LoadStaticFieldInstr : public TemplateDefinition<0> {
+class LoadStaticFieldInstr : public TemplateDefinition<1> {
  public:
-  explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
+  explicit LoadStaticFieldInstr(Value* field_value) {
+    ASSERT(field_value->BindsToConstant());
+    SetInputAt(0, field_value);
+  }
 
   DECLARE_INSTRUCTION(LoadStaticField)
   virtual CompileType ComputeType() const;
 
-  const Field& field() const { return field_; }
+  const Field& StaticField() const;
+
+  Value* field_value() const { return inputs_[0]; }
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return false; }
 
-  virtual bool AllowsCSE() const { return field_.is_final(); }
+  virtual bool AllowsCSE() const { return StaticField().is_final(); }
   virtual EffectSet Effects() const { return EffectSet::None(); }
   virtual EffectSet Dependencies() const;
   virtual bool AttributesEqual(Instruction* other) const;
 
   virtual bool MayThrow() const { return false; }
- private:
-  const Field& field_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldInstr);
 };
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 01edb86..eacd243 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1054,13 +1054,17 @@
 
 
 LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
-  UNIMPLEMENTED();
-  return NULL;
+  const intptr_t kNumInputs = 1;
+  return LocationSummary::Make(kNumInputs,
+                               Location::RequiresRegister(),
+                               LocationSummary::kNoCall);
 }
 
 
 void LoadUntaggedInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  UNIMPLEMENTED();
+  Register object = locs()->in(0).reg();
+  Register result = locs()->out().reg();
+  __ LoadFromOffset(kLoadWord, result, object, offset() - kHeapObjectTag);
 }
 
 
@@ -1363,10 +1367,6 @@
       locs->set_in(2, Location::WritableRegister());
       break;
     case kTypedDataFloat32ArrayCid:
-      // TODO(regis): Verify.
-      // Need temp register for float-to-double conversion.
-      locs->AddTemp(Location::RequiresFpuRegister());
-      // Fall through.
     case kTypedDataFloat64ArrayCid:  // TODO(srdjan): Support Float64 constants.
     case kTypedDataFloat32x4ArrayCid:
       locs->set_in(2, Location::RequiresFpuRegister());
@@ -1496,7 +1496,16 @@
       break;
     }
     case kTypedDataFloat32ArrayCid:
+      // Convert to single precision.
+      __ vcvtsd(STMP, locs()->in(2).fpu_reg());
+      // Store.
+      __ add(index.reg(), index.reg(), ShifterOperand(array));
+      __ StoreSToOffset(STMP, index.reg(), 0);
+      break;
     case kTypedDataFloat64ArrayCid:
+      __ add(index.reg(), index.reg(), ShifterOperand(array));
+      __ StoreDToOffset(locs()->in(2).fpu_reg(), index.reg(), 0);
+      break;
     case kTypedDataFloat32x4ArrayCid:
       UNIMPLEMENTED();
       break;
@@ -1695,17 +1704,21 @@
 
 
 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
-  return LocationSummary::Make(0,
-                               Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register field = locs()->in(0).reg();
   Register result = locs()->out().reg();
-  __ LoadObject(result, field());
   __ LoadFromOffset(kLoadWord, result,
-                    result, Field::value_offset() - kHeapObjectTag);
+                    field, Field::value_offset() - kHeapObjectTag);
 }
 
 
@@ -2126,6 +2139,7 @@
       if (left_int == 0) {
         __ cmp(right, ShifterOperand(0));
         __ b(deopt, MI);
+        __ mov(result, ShifterOperand(0));
         return;
       }
       const intptr_t max_right = kSmiBits - Utils::HighestBit(left_int);
@@ -2339,6 +2353,7 @@
 
         if (value == 0) {
           // TODO(vegorov): should be handled outside.
+          __ MoveRegister(result, left);
           break;
         } else if (value < 0) {
           // TODO(vegorov): should be handled outside.
@@ -2426,7 +2441,22 @@
       break;
     }
     case Token::kSHR: {
-      UNIMPLEMENTED();
+      if (CanDeoptimize()) {
+        __ CompareImmediate(right, 0);
+        __ b(deopt, LT);
+      }
+      __ SmiUntag(right);
+      // sarl operation masks the count to 5 bits.
+      const intptr_t kCountLimit = 0x1F;
+      Range* right_range = this->right()->definition()->range();
+      if ((right_range == NULL) ||
+          !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
+        __ CompareImmediate(right, kCountLimit);
+        __ LoadImmediate(right, kCountLimit, GT);
+      }
+      __ SmiUntag(left);
+      __ Asr(result, left, right);
+      __ SmiTag(result);
       break;
     }
     case Token::kDIV: {
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 3f043e3..e6eb45b 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1759,16 +1759,22 @@
 
 
 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
-  return LocationSummary::Make(0,
-                               Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  // By specifying same register as input, our simple register allocator can
+  // generate better code.
+  summary->set_out(Location::SameAsFirstInput());
+  return summary;
 }
 
 
 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register field = locs()->in(0).reg();
   Register result = locs()->out().reg();
-  __ LoadObject(result, field());
-  __ movl(result, FieldAddress(result, Field::value_offset()));
+  __ movl(result, FieldAddress(field, Field::value_offset()));
 }
 
 
@@ -2535,7 +2541,7 @@
       Range* right_range = this->right()->definition()->range();
       if ((right_range == NULL) ||
           !right_range->IsWithin(RangeBoundary::kMinusInfinity, kCountLimit)) {
-       __ cmpl(right, Immediate(kCountLimit));
+        __ cmpl(right, Immediate(kCountLimit));
         Label count_ok;
         __ j(LESS, &count_ok, Assembler::kNearJump);
         __ movl(right, Immediate(kCountLimit));
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 0245899..8bf386e 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1659,17 +1659,21 @@
 
 
 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
-  return LocationSummary::Make(0,
-                               Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ TraceSimMsg("LoadStaticFieldInstr");
+  Register field = locs()->in(0).reg();
   Register result = locs()->out().reg();
-  __ LoadObject(result, field());
-  __ lw(result, Address(result, Field::value_offset() - kHeapObjectTag));
+  __ lw(result, FieldAddress(field, Field::value_offset()));
 }
 
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index c93b79a3..357c907 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1743,16 +1743,20 @@
 
 
 LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
-  return LocationSummary::Make(0,
-                               Location::RequiresRegister(),
-                               LocationSummary::kNoCall);
+  const intptr_t kNumInputs = 1;
+  const intptr_t kNumTemps = 0;
+  LocationSummary* summary =
+      new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+  summary->set_in(0, Location::RequiresRegister());
+  summary->set_out(Location::RequiresRegister());
+  return summary;
 }
 
 
 void LoadStaticFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  Register field = locs()->in(0).reg();
   Register result = locs()->out().reg();
-  __ LoadObject(result, field());
-  __ movq(result, FieldAddress(result, Field::value_offset()));
+  __ movq(result, FieldAddress(field, Field::value_offset()));
 }
 
 
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 0e0f942..f61d667 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -17,18 +17,18 @@
 // build and run to get the correct fingerprint from the mismatch error.
 #define CORE_LIB_INTRINSIC_LIST(V)                                             \
   V(_Smi, ~, Smi_bitNegate, 882629793)                                         \
-  V(_Double, >, Double_greaterThan, 301935359)                                 \
-  V(_Double, >=, Double_greaterEqualThan, 1184528952)                          \
-  V(_Double, <, Double_lessThan, 1596251333)                                   \
-  V(_Double, <=, Double_lessEqualThan, 1184499161)                             \
-  V(_Double, ==, Double_equal, 1706047712)                                     \
-  V(_Double, +, Double_add, 210576655)                                         \
-  V(_Double, -, Double_sub, 1605354741)                                        \
-  V(_Double, *, Double_mul, 788270837)                                         \
-  V(_Double, /, Double_div, 1202831412)                                        \
+  V(_Double, >, Double_greaterThan, 498448864)                                 \
+  V(_Double, >=, Double_greaterEqualThan, 1322959863)                          \
+  V(_Double, <, Double_lessThan, 1595326820)                                   \
+  V(_Double, <=, Double_lessEqualThan, 1322930072)                             \
+  V(_Double, ==, Double_equal, 1012968674)                                     \
+  V(_Double, +, Double_add, 407090160)                                         \
+  V(_Double, -, Double_sub, 1801868246)                                        \
+  V(_Double, *, Double_mul, 984784342)                                         \
+  V(_Double, /, Double_div, 1399344917)                                        \
   V(_Double, get:isNaN, Double_getIsNaN, 54462366)                             \
   V(_Double, get:isNegative, Double_getIsNegative, 54462366)                   \
-  V(_Double, _mulFromInteger, Double_mulFromInteger, 704314034)                \
+  V(_Double, _mulFromInteger, Double_mulFromInteger, 550294258)                \
   V(_Double, .fromInteger, Double_fromInteger, 842078193)                      \
   V(_ObjectArray, ., ObjectArray_Allocate, 97987288)                           \
   V(_ObjectArray, get:length, Array_getLength, 405297088)                      \
@@ -41,12 +41,12 @@
   V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 1048007636)           \
   V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 796709584)      \
   V(_GrowableObjectArray, _setData, GrowableArray_setData, 629110947)          \
-  V(_GrowableObjectArray, add, GrowableArray_add, 1904852879)                  \
+  V(_GrowableObjectArray, add, GrowableArray_add, 112207566)                   \
   V(_ImmutableArray, [], ImmutableArray_getIndexed, 486821199)                 \
   V(_ImmutableArray, get:length, ImmutableArray_getLength, 433698233)          \
-  V(Object, ==, Object_equal, 2126897013)                                      \
+  V(Object, ==, Object_equal, 2126867222)                                      \
   V(_StringBase, get:hashCode, String_getHashCode, 320803993)                  \
-  V(_StringBase, get:isEmpty, String_getIsEmpty, 1026765313)                   \
+  V(_StringBase, get:isEmpty, String_getIsEmpty, 110631520)                    \
   V(_StringBase, get:length, String_getLength, 320803993)                      \
   V(_StringBase, codeUnitAt, String_codeUnitAt, 984449525)                     \
   V(_OneByteString, get:hashCode, OneByteString_getHashCode, 682660413)        \
@@ -57,35 +57,35 @@
 
 #define CORE_INTEGER_LIB_INTRINSIC_LIST(V)                                     \
   V(_IntegerImplementation, _addFromInteger, Integer_addFromInteger, 726019207)\
-  V(_IntegerImplementation, +, Integer_add, 1768648592)                        \
+  V(_IntegerImplementation, +, Integer_add, 25837296)                          \
   V(_IntegerImplementation, _subFromInteger, Integer_subFromInteger, 726019207)\
-  V(_IntegerImplementation, -, Integer_sub, 1292467582)                        \
+  V(_IntegerImplementation, -, Integer_sub, 1697139934)                        \
   V(_IntegerImplementation, _mulFromInteger, Integer_mulFromInteger, 726019207)\
-  V(_IntegerImplementation, *, Integer_mul, 1853182047)                        \
-  V(_IntegerImplementation, %, Integer_modulo, 1211518976)                     \
-  V(_IntegerImplementation, remainder, Integer_remainder, 1131753683)          \
-  V(_IntegerImplementation, ~/, Integer_truncDivide, 142750059)                \
-  V(_IntegerImplementation, unary-, Integer_negate, 676633254)                 \
+  V(_IntegerImplementation, *, Integer_mul, 110370751)                         \
+  V(_IntegerImplementation, %, Integer_modulo, 980686435)                      \
+  V(_IntegerImplementation, remainder, Integer_remainder, 1536426035)          \
+  V(_IntegerImplementation, ~/, Integer_truncDivide, 2059401166)               \
+  V(_IntegerImplementation, unary-, Integer_negate, 675709702)                 \
   V(_IntegerImplementation, _bitAndFromInteger,                                \
     Integer_bitAndFromInteger, 726019207)                                      \
-  V(_IntegerImplementation, &, Integer_bitAnd, 354347153)                      \
+  V(_IntegerImplementation, &, Integer_bitAnd, 759019505)                      \
   V(_IntegerImplementation, _bitOrFromInteger,                                 \
     Integer_bitOrFromInteger, 726019207)                                       \
-  V(_IntegerImplementation, |, Integer_bitOr, 875694946)                       \
+  V(_IntegerImplementation, |, Integer_bitOr, 1280367298)                      \
   V(_IntegerImplementation, _bitXorFromInteger,                                \
     Integer_bitXorFromInteger, 726019207)                                      \
-  V(_IntegerImplementation, ^, Integer_bitXor, 282155459)                      \
+  V(_IntegerImplementation, ^, Integer_bitXor, 686827811)                      \
   V(_IntegerImplementation,                                                    \
     _greaterThanFromInteger,                                                   \
     Integer_greaterThanFromInt, 79222670)                                      \
-  V(_IntegerImplementation, >, Integer_greaterThan, 462314913)                 \
-  V(_IntegerImplementation, ==, Integer_equal, 1424765465)                     \
+  V(_IntegerImplementation, >, Integer_greaterThan, 866987265)                 \
+  V(_IntegerImplementation, ==, Integer_equal, 1763184121)                     \
   V(_IntegerImplementation, _equalToInteger, Integer_equalToInteger, 79222670) \
-  V(_IntegerImplementation, <, Integer_lessThan, 1424838471)                   \
-  V(_IntegerImplementation, <=, Integer_lessEqualThan, 949016155)              \
-  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 949045946)           \
-  V(_IntegerImplementation, <<, Integer_shl, 1195917829)                       \
-  V(_IntegerImplementation, >>, Integer_sar, 1980227743)                       \
+  V(_IntegerImplementation, <, Integer_lessThan, 1423913958)                   \
+  V(_IntegerImplementation, <=, Integer_lessEqualThan, 1087447066)             \
+  V(_IntegerImplementation, >=, Integer_greaterEqualThan, 1087476857)          \
+  V(_IntegerImplementation, <<, Integer_shl, 1600590181)                       \
+  V(_IntegerImplementation, >>, Integer_sar, 237416447)                        \
   V(_Double, toInt, Double_toInt, 362666636)
 
 
@@ -93,7 +93,7 @@
   V(::, sqrt, Math_sqrt, 1662640002)                                           \
   V(::, sin, Math_sin, 1273932041)                                             \
   V(::, cos, Math_cos, 1749547468)                                             \
-  V(_Random, _nextState, Random_nextState, 77315414)                           \
+  V(_Random, _nextState, Random_nextState, 287494804)                          \
 
 
 #define TYPED_DATA_LIB_INTRINSIC_LIST(V)                                       \
@@ -110,18 +110,18 @@
   V(_Float32Array, _new, TypedData_Float32Array_new, 723829075)                \
   V(_Float64Array, _new, TypedData_Float64Array_new, 111654177)                \
   V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 984763738)            \
-  V(_Int8Array, ., TypedData_Int8Array_factory, 1168404493)                    \
-  V(_Uint8Array, ., TypedData_Uint8Array_factory, 2094565809)                  \
-  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1449285088)    \
-  V(_Int16Array, ., TypedData_Int16Array_factory, 1430476167)                  \
-  V(_Uint16Array, ., TypedData_Uint16Array_factory, 996241892)                 \
-  V(_Int32Array, ., TypedData_Int32Array_factory, 360797715)                   \
-  V(_Uint32Array, ., TypedData_Uint32Array_factory, 995053409)                 \
-  V(_Int64Array, ., TypedData_Int64Array_factory, 570248142)                   \
-  V(_Uint64Array, ., TypedData_Uint64Array_factory, 1114332856)                \
-  V(_Float32Array, ., TypedData_Float32Array_factory, 1719636031)              \
-  V(_Float64Array, ., TypedData_Float64Array_factory, 1896334311)              \
-  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1768466392)          \
+  V(_Int8Array, ., TypedData_Int8Array_factory, 1139775342)                    \
+  V(_Uint8Array, ., TypedData_Uint8Array_factory, 2065936658)                  \
+  V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1420655937)    \
+  V(_Int16Array, ., TypedData_Int16Array_factory, 1401847016)                  \
+  V(_Uint16Array, ., TypedData_Uint16Array_factory, 967612741)                 \
+  V(_Int32Array, ., TypedData_Int32Array_factory, 332168564)                   \
+  V(_Uint32Array, ., TypedData_Uint32Array_factory, 966424258)                 \
+  V(_Int64Array, ., TypedData_Int64Array_factory, 541618991)                   \
+  V(_Uint64Array, ., TypedData_Uint64Array_factory, 1085703705)                \
+  V(_Float32Array, ., TypedData_Float32Array_factory, 1691006880)              \
+  V(_Float64Array, ., TypedData_Float64Array_factory, 1867705160)              \
+  V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 1739837241)          \
 
 // TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
 //   _FixedSizeArrayIterator, moveNext.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e1185d5..12cfe2d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -4654,6 +4654,8 @@
       // This output can be copied into a file, then used with sed
       // to replace the old values.
       // sed -i .bak -f /tmp/newkeys runtime/vm/intrinsifier.h
+      // sed -i .bak -f /tmp/newkeys runtime/vm/intermediate_language.h
+      // sed -i .bak -f /tmp/newkeys runtime/vm/flow_graph_builder.h
       OS::Print("s/%d/%d/\n", fp, SourceFingerprint());
     } else {
       OS::Print("FP mismatch while recognizing method %s:"
@@ -5238,7 +5240,6 @@
       case Token::kPERIOD:
       case Token::kLPAREN:
       case Token::kLBRACK:
-      case Token::kTIGHTADD:
       case Token::kINTERPOL_VAR:
       case Token::kINTERPOL_START:
       case Token::kINTERPOL_END:
@@ -9202,21 +9203,35 @@
 }
 
 
-RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
-  ASSERT(!IsNull());
-  if (this->IsCanonical()) {
-    return this->raw();
+#if defined(DEBUG)
+class CheckForPointers : public ObjectPointerVisitor {
+ public:
+  explicit CheckForPointers(Isolate* isolate)
+      : ObjectPointerVisitor(isolate), has_pointers_(false) {}
+
+  bool has_pointers() const { return has_pointers_; }
+
+  void VisitPointers(RawObject** first, RawObject** last) {
+    if (first != last) {
+      has_pointers_ = true;
+    }
   }
-  Instance& result = Instance::Handle();
+
+ private:
+  bool has_pointers_;
+
+  DISALLOW_COPY_AND_ASSIGN(CheckForPointers);
+};
+#endif  // DEBUG
+
+
+bool Instance::CheckAndCanonicalizeFields(const char** error_str) const {
   const Class& cls = Class::Handle(this->clazz());
-  // TODO(srdjan): Check that predefined classes do not have fields that need
-  // to be checked/canonicalized as well.
-  if ((cls.id() >= kNumPredefinedCids) || cls.IsArray()) {
+  if ((cls.id() >= kNumPredefinedCids)) {
     // Iterate over all fields, canonicalize numbers and strings, expect all
-    // other instances to be canonical otherwise report error (return
-    // Instance::null()).
+    // other instances to be canonical otherwise report error (return false).
     Object& obj = Object::Handle();
-    const intptr_t end_field_offset = cls.instance_size() - kWordSize;
+    intptr_t end_field_offset = cls.instance_size() - kWordSize;
     for (intptr_t field_offset = 0;
          field_offset <= end_field_offset;
          field_offset += kWordSize) {
@@ -9234,11 +9249,32 @@
           char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
           OS::SNPrint(chars, len, kFormat, obj.ToCString());
           *error_str = chars;
-          return Instance::null();
+          return false;
         }
       }
     }
+  } else {
+#if defined(DEBUG)
+    // Make sure that we are not missing any fields.
+    CheckForPointers has_pointers(Isolate::Current());
+    this->raw()->VisitPointers(&has_pointers);
+    ASSERT(!has_pointers.has_pointers());
+#endif  // DEBUG
   }
+  return true;
+}
+
+
+RawInstance* Instance::CheckAndCanonicalize(const char** error_str) const {
+  ASSERT(!IsNull());
+  if (this->IsCanonical()) {
+    return this->raw();
+  }
+  if (!CheckAndCanonicalizeFields(error_str)) {
+    return Instance::null();
+  }
+  Instance& result = Instance::Handle();
+  const Class& cls = Class::Handle(this->clazz());
   Array& constants = Array::Handle(cls.constants());
   const intptr_t constants_len = constants.Length();
   // Linear search to see whether this value is already present in the
@@ -12758,6 +12794,33 @@
 }
 
 
+bool Array::CheckAndCanonicalizeFields(const char** error_str) const {
+  Object& obj = Object::Handle();
+  // Iterate over all elements, canonicalize numbers and strings, expect all
+  // other instances to be canonical otherwise report error (return false).
+  for (intptr_t i = 0; i < Length(); i++) {
+    obj = At(i);
+    if (obj.IsInstance() && !obj.IsSmi() && !obj.IsCanonical()) {
+      if (obj.IsNumber() || obj.IsString()) {
+        obj = Instance::Cast(obj).CheckAndCanonicalize(NULL);
+        ASSERT(!obj.IsNull());
+        this->SetAt(i, obj);
+      } else {
+        ASSERT(error_str != NULL);
+        const char* kFormat = "element at index %"Pd": %s\n";
+        const intptr_t len =
+            OS::SNPrint(NULL, 0, kFormat, i, obj.ToCString()) + 1;
+        char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+        OS::SNPrint(chars, len, kFormat, i, obj.ToCString());
+        *error_str = chars;
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+
 RawImmutableArray* ImmutableArray::New(intptr_t len,
                                        Heap::Space space) {
   ASSERT(Isolate::Current()->object_store()->immutable_array_class() !=
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 492b595..90e55f8 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -3531,6 +3531,9 @@
   // Returns error in error_str, pass NULL if an error cannot occur.
   virtual RawInstance* CheckAndCanonicalize(const char** error_str) const;
 
+  // Returns true if all fields are OK for canonicalization.
+  virtual bool CheckAndCanonicalizeFields(const char** error_str) const;
+
   RawObject* GetField(const Field& field) const {
     return *FieldAddr(field);
   }
@@ -4984,6 +4987,9 @@
     return RoundedAllocationSize(sizeof(RawArray) + (len * kBytesPerElement));
   }
 
+  // Returns true if all elements are OK for canonicalization.
+  virtual bool CheckAndCanonicalizeFields(const char** error_str) const;
+
   // Make the array immutable to Dart code by switching the class pointer
   // to ImmutableArray.
   void MakeImmutable() const;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 0115294..f235827 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -1670,6 +1670,10 @@
   EXPECT(!array.Equals(other_array));
 
   EXPECT_EQ(0, Object::empty_array().Length());
+
+  array.MakeImmutable();
+  Object& obj = Object::Handle(array.raw());
+  ASSERT(obj.IsArray());
 }
 
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index e2ade07..0aec272 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -6806,8 +6806,7 @@
 
 
 static bool IsPrefixOperator(Token::Kind token) {
-  return (token == Token::kTIGHTADD) ||   // Valid for literals only!
-         (token == Token::kSUB) ||
+  return (token == Token::kSUB) ||
          (token == Token::kNOT) ||
          (token == Token::kBIT_NOT);
 }
@@ -6920,9 +6919,6 @@
   while (current_preced >= min_preced) {
     while (Token::Precedence(CurrentToken()) == current_preced) {
       Token::Kind op_kind = CurrentToken();
-      if (op_kind == Token::kTIGHTADD) {
-        op_kind = Token::kADD;
-      }
       const intptr_t op_pos = TokenPos();
       ConsumeToken();
       AstNode* right_operand = NULL;
@@ -7331,13 +7327,7 @@
     }
     ConsumeToken();
     expr = ParseUnaryExpr();
-    if (unary_op == Token::kTIGHTADD) {
-      // kTIGHADD is added only in front of a number literal.
-      if (!expr->IsLiteralNode()) {
-        ErrorMsg(op_pos, "unexpected operator '+'");
-      }
-      // Expression is the literal itself.
-    } else if (expr->IsPrimaryNode() && (expr->AsPrimaryNode()->IsSuper())) {
+    if (expr->IsPrimaryNode() && (expr->AsPrimaryNode()->IsSuper())) {
       expr = BuildUnarySuperOperator(unary_op, expr->AsPrimaryNode());
     } else {
       expr = UnaryOpNode::UnaryOpOrLiteral(op_pos, unary_op, expr);
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 6162d1a..896142c 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -189,7 +189,7 @@
     return true;
   }
   if ((tokens.length() == 3) &&
-      ((tokens[0].kind == Token::kTIGHTADD) ||
+      ((tokens[0].kind == Token::kADD) ||
        (tokens[0].kind == Token::kSUB)) &&
       (tokens[1].kind == literal_kind) &&
       (tokens[2].kind == Token::kEOS)) {
@@ -197,7 +197,7 @@
     if ((tokens[0].offset + 1) != tokens[1].offset) {
       return false;
     }
-    *is_positive = tokens[0].kind == Token::kTIGHTADD;
+    *is_positive = tokens[0].kind == Token::kADD;
     *value = tokens[1].literal;
     return true;
   }
@@ -639,15 +639,8 @@
         break;
 
       case '+':  // +  ++  +=
-        ReadChar();
-        current_token_.kind =
-            IsNumberStart(c0_) ? Token::kTIGHTADD : Token::kADD;
-        // Unary + is not allowed for hexadecimal integers, so treat the
-        // + as a binary operator.
-        if ((c0_ == '0') &&
-            ((LookaheadChar(1) == 'x') || (LookaheadChar(1) == 'X'))) {
-          current_token_.kind = Token::kADD;
-        } else if (c0_ == '+') {
+        Recognize(Token::kADD);
+        if (c0_ == '+') {
           Recognize(Token::kINCR);
         } else if (c0_ == '=') {
           Recognize(Token::kASSIGN_ADD);
diff --git a/runtime/vm/scanner_test.cc b/runtime/vm/scanner_test.cc
index 1e04b8d..d4a653a 100644
--- a/runtime/vm/scanner_test.cc
+++ b/runtime/vm/scanner_test.cc
@@ -327,7 +327,7 @@
   CheckKind(tokens, 3, Token::kDOUBLE);
   CheckKind(tokens, 4, Token::kDOUBLE);
   CheckKind(tokens, 5, Token::kDOUBLE);
-  CheckKind(tokens, 6, Token::kTIGHTADD);
+  CheckKind(tokens, 6, Token::kADD);
   CheckKind(tokens, 7, Token::kINTEGER);
   CheckKind(tokens, 8, Token::kEOS);
 }
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index c568ddd..1b58858 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -79,8 +79,6 @@
   /* Additive operators. */                                                    \
   TOK(kADD, "+", 12, kNoAttribute)                                             \
   TOK(kSUB, "-", 12, kNoAttribute)                                             \
-  /* A 'plus' without a trailing whitespace (handle literals). */              \
-  TOK(kTIGHTADD, "+", 12, kNoAttribute)                                        \
                                                                                \
   /* Multiplicative operators */                                               \
   TOK(kMUL, "*", 13, kNoAttribute)                                             \
diff --git a/sdk/bin/pub.bat b/sdk/bin/pub.bat
index 99846ec..6f0d4e0 100644
--- a/sdk/bin/pub.bat
+++ b/sdk/bin/pub.bat
@@ -1,16 +1,49 @@
 @echo off
-:: 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.
+REM Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
 
-:: Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
-:: structure.
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
 
-set SCRIPTPATH=%~dp0
+rem Get absolute full name for SDK_DIR.
+for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
 
-:: Does the string have a trailing slash? If so, remove it.
-if %SCRIPTPATH:~-1%==\ set SCRIPTPATH=%SCRIPTPATH:~0,-1%
+rem Remove trailing backslash if there is one
+IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
 
-:: The trailing forward slash in --package-root is required because of issue
-:: 9499.
-"%SCRIPTPATH%\dart.exe" "%SCRIPTPATH%\..\bin\snapshots\pub.dart.snapshot" %*
+set PUB=%SDK_DIR%\lib\_internal\pub\bin\pub.dart
+set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
+set PACKAGES_DIR=%BUILD_DIR%\packages\
+set DART=%BIN_DIR%\dart
+set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\pub.dart.snapshot
+
+if exist "%SNAPSHOT%" (
+  "%DART%" --checked "%SNAPSHOT%" %*
+) else (
+  "%DART_IN_BUILT_SDK%" --checked --package-root=%PACKAGES_DIR% "%PUB%" %*
+)
+
+endlocal
+
+exit /b %errorlevel%
+
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "tokens=2 delims=[]" %%i in ('dir /a:l ^"%~dp1^" 2^>nul ^
+                                     ^| find ">     %~n1 ["') do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index b51e9f5..c850caa 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -182,6 +182,10 @@
     ClassElement classElement = element.getEnclosingClass();
     return classElement == compiler.objectClass;
   }
+
+  void enableMirrors() {}
+
+  void registerStaticUse(Element element, Enqueuer enqueuer) {}
 }
 
 /**
@@ -524,7 +528,7 @@
 
   bool get analyzeAll => analyzeAllFlag || compileAll;
 
-  bool get compileAll => mirrorsEnabled;
+  bool get compileAll => false;
 
   bool get disableTypeInference => disableTypeInferenceFlag || mirrorsEnabled;
 
@@ -663,6 +667,7 @@
     }
     if (uri == Uri.parse('dart:mirrors')) {
       mirrorSystemClass = library.find(const SourceString('MirrorSystem'));
+      backend.enableMirrors();
       metadataHandler = constantHandler;
     } else if (uri == Uri.parse('dart:_collection-dev')) {
       symbolImplementationClass = library.find(const SourceString('Symbol'));
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index a1a2ed2..f3dae36 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -62,7 +62,6 @@
     compiler.libraries.values.forEach(addMemberByName);
   }
 
-
   String get name => 'Enqueue';
 
   EnqueueTask(Compiler compiler)
@@ -95,6 +94,8 @@
   EnqueueTask task;
   native.NativeEnqueuer nativeEnqueuer;  // Set by EnqueueTask
 
+  bool hasEnqueuedEverything = false;
+
   Enqueuer(this.name, this.compiler,
            ItemCompilationContext itemCompilationContextCreator())
     : this.itemCompilationContextCreator = itemCompilationContextCreator;
@@ -342,40 +343,45 @@
     for (var link = task.allElementsByName[name];
          link != null && !link.isEmpty;
          link = link.tail) {
-      Element element = link.head;
-      if (Elements.isUnresolved(element)) {
-        // Ignore.
-      } else if (element.isConstructor()) {
-        ClassElement cls = element.declaration.getEnclosingClass();
-        registerInstantiatedType(cls.rawType, elements);
-        registerStaticUse(element.declaration);
-      } else if (element.impliesType()) {
-        // Don't enqueue classes, typedefs, and type variables.
-      } else if (Elements.isStaticOrTopLevel(element)) {
-        registerStaticUse(element.declaration);
-      } else if (element.isInstanceMember()) {
-        if (element.isFunction()) {
-          int arity =
-              element.asFunctionElement().requiredParameterCount(compiler);
-          Selector selector =
-              new Selector.call(element.name, element.getLibrary(), arity);
-          registerInvocation(element.name, selector);
-        } else if (element.isSetter()) {
-          Selector selector =
-              new Selector.setter(element.name, element.getLibrary());
-          registerInvokedSetter(element.name, selector);
-        } else if (element.isGetter()) {
-          Selector selector =
-              new Selector.getter(element.name, element.getLibrary());
-          registerInvokedGetter(element.name, selector);
-        } else if (element.isField()) {
-          Selector selector =
-              new Selector.setter(element.name, element.getLibrary());
-          registerInvokedSetter(element.name, selector);
-          selector =
-              new Selector.getter(element.name, element.getLibrary());
-          registerInvokedGetter(element.name, selector);
-        }
+      pretendElementWasUsed(link.head, elements);
+    }
+  }
+
+  void pretendElementWasUsed(Element element, TreeElements elements) {
+    if (Elements.isUnresolved(element)) {
+      // Ignore.
+    } else if (element.isSynthesized
+               && element.getLibrary().isPlatformLibrary) {
+      // TODO(ahe): Work-around for http://dartbug.com/11205.
+    } else if (element.isConstructor()) {
+      ClassElement cls = element.declaration.getEnclosingClass();
+      registerInstantiatedType(cls.rawType, elements);
+      registerStaticUse(element.declaration);
+    } else if (element.impliesType()) {
+      // Don't enqueue classes, typedefs, and type variables.
+    } else if (Elements.isStaticOrTopLevel(element)) {
+      registerStaticUse(element.declaration);
+    } else if (element.isInstanceMember()) {
+      if (element.isFunction()) {
+        int arity =
+            element.asFunctionElement().requiredParameterCount(compiler);
+        Selector selector =
+            new Selector.call(element.name, element.getLibrary(), arity);
+        registerInvocation(element.name, selector);
+      } else if (element.isSetter()) {
+        Selector selector =
+            new Selector.setter(element.name, element.getLibrary());
+        registerInvokedSetter(element.name, selector);
+      } else if (element.isGetter()) {
+        Selector selector =
+            new Selector.getter(element.name, element.getLibrary());
+        registerInvokedGetter(element.name, selector);
+      } else if (element.isField()) {
+        Selector selector =
+            new Selector.setter(element.name, element.getLibrary());
+        registerInvokedSetter(element.name, selector);
+        selector = new Selector.getter(element.name, element.getLibrary());
+        registerInvokedGetter(element.name, selector);
       }
     }
   }
@@ -384,6 +390,18 @@
   void registerNewSymbol(TreeElements elements) {
   }
 
+  void enqueueEverything() {
+    if (hasEnqueuedEverything) return;
+    compiler.log('Enqueuing everything');
+    task.ensureAllElementsByName();
+    for (Link link in task.allElementsByName.values) {
+      for (Element element in link) {
+        pretendElementWasUsed(element, compiler.globalDependencies);
+      }
+    }
+    hasEnqueuedEverything = true;
+  }
+
   processLink(Map<String, Link<Element>> map,
               SourceString n,
               bool f(Element e)) {
@@ -456,6 +474,7 @@
     if (element == null) return;
     assert(invariant(element, element.isDeclaration));
     addToWorkList(element);
+    compiler.backend.registerStaticUse(element, this);
   }
 
   void registerGetOfStaticFunction(FunctionElement element) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 419f521..87e7294 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -75,7 +75,6 @@
   HType mutableArrayType;
   HType fixedArrayType;
   HType extendableArrayType;
-  
 
   // TODO(9577): Make it so that these are not needed when there are no native
   // classes.
@@ -156,6 +155,14 @@
 
   final RuntimeTypes rti;
 
+  /// Holds the method "disableTreeShaking" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionElement disableTreeShakingMarker;
+
+  /// Holds the method "preserveNames" in js_mirrors when
+  /// dart:mirrors has been loaded.
+  FunctionElement preserveNamesMarker;
+
   JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
       : namer = determineNamer(compiler),
         usedInterceptors = new Set<Selector>(),
@@ -1114,4 +1121,19 @@
   ClassElement get typeImplementation => typeLiteralClass;
   ClassElement get boolImplementation => jsBoolClass;
   ClassElement get nullImplementation => jsNullClass;
+
+  void enableMirrors() {
+    LibraryElement library = compiler.libraries['dart:_js_mirrors'];
+    disableTreeShakingMarker =
+        library.find(const SourceString('disableTreeShaking'));
+    preserveNamesMarker =
+        library.find(const SourceString('preserveNames'));
+ }
+
+  void registerStaticUse(Element element, Enqueuer enqueuer) {
+    if (element == disableTreeShakingMarker) {
+      enqueuer.enqueueEverything();
+    } else if (element == preserveNamesMarker) {
+    }
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index 1396a72..e4d3ce1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -214,44 +214,6 @@
     return calledInLoop;
   }
 
-  // Returns whether an invocation of [selector] on [receiver] will throw a
-  // [ArgumentError] if the argument is not of the right type.
-  bool willThrowArgumentError(Selector selector,
-                              HInstruction receiver,
-                              HType speculativeType) {
-    if (receiver != null
-        && (receiver.isInteger() || receiver.isString(compiler))) {
-      return selector.isOperator()
-          && selector.name != const SourceString('==')
-          && (speculativeType.isNumber() && !speculativeType.isInteger());
-    }
-    return false;
-  }
-
-  // Returns whether an invocation of [selector] will throw a
-  // [NoSuchMethodError] if the receiver is not of the type
-  // [speculativeType].
-  bool willThrowNoSuchMethodErrorIfNot(Selector selector,
-                                       HType speculativeType) {
-    return compiler.world.hasSingleMatch(selector)
-        // In some cases, we want the receiver to be an integer,
-        // but that does not mean we will get a NoSuchMethodError
-        // if it's not: the receiver could be a double.
-        && !speculativeType.isInteger()
-        // We speculate on the [operator==] instruction, but we know it
-        // will never throw a [NoSuchMethodError].
-        && selector.name != const SourceString('==');
-  }
-
-  bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) {
-    if (!speculativeType.isUseful()) return false;
-    // If the types agree we don't need to check.
-    if (speculativeType == instruction.instructionType) return false;
-    // If a bailout check is more expensive than doing the actual operation
-    // don't do it either.
-    return typeGuardWouldBeValuable(instruction, speculativeType);
-  }
-
   HInstruction computeFirstDominatingUserWithSelector(
       HInstruction instruction) {
     // TODO(ngeoffray): We currently only look at the instruction's
@@ -283,49 +245,43 @@
   bool tryTypeConversion(HInstruction instruction, HType speculativeType) {
     HInstruction firstUser =
         computeFirstDominatingUserWithSelector(instruction);
-    if (firstUser == null) return false;
+    if (firstUser is !HInvokeDynamic) return false;
 
     // If we have found a user with a selector, we find out if it
-    // will throw [NoSuchMethodError] or [ArgumentError].
+    // will throw [NoSuchMethodError] or [ArgumentError]. If it does,
+    // then we change just add a [HTypeConversion] instruction and
+    // avoid a bailout.
     Selector selector = firstUser.selector;
-    Selector receiverSelectorOnThrow = null;
+    if (!selector.isOperator()) return false;
     HInstruction receiver = firstUser.getDartReceiver(compiler);
-    bool willThrow = false;
-    if (receiver == instruction) {
-      if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) {
-        receiverSelectorOnThrow = selector;
-        willThrow = true;
-      }
-    // We need to call the actual method in checked mode to get
-    // the right type error.
-    } else if (!compiler.enableTypeAssertions
-               && willThrowArgumentError(selector, receiver, speculativeType)) {
-      willThrow = true;
+
+    if (instruction == receiver) {
+      // If the instruction on which we're speculating the
+      // type is the receiver of the call, check if it will throw
+      // [NoSuchMethodError] if [instruction] is not of the speculated
+      // type.
+      return checkReceiver(firstUser);
+    } else if (!selector.isUnaryOperator()
+               && instruction == firstUser.inputs[2]) {
+      // If the instruction is a parameter of the call, we check if
+      // the method will throw an [ArgumentError] if [instruction] is
+      // not of the speculated type.
+      return checkArgument(firstUser);
     }
-
-    if (!willThrow) return false;
-
-    HTypeConversion check = new HTypeConversion(
-            null,
-            receiverSelectorOnThrow == null
-                ? HTypeConversion.ARGUMENT_TYPE_CHECK
-                : HTypeConversion.RECEIVER_TYPE_CHECK,
-            speculativeType,
-            instruction,
-            receiverSelectorOnThrow);
-    hasInsertedChecks = true;
-    firstUser.block.addBefore(firstUser, check);
-    instruction.replaceAllUsersDominatedBy(firstUser, check);
-    return true;
+    return false;
   }
 
   bool updateType(HInstruction instruction) {
     bool hasChanged = super.updateType(instruction);
     HType speculativeType = savedTypes[instruction];
-    if (speculativeType == null) return hasChanged;
+    if (speculativeType == null
+        || !speculativeType.isUseful()
+        || speculativeType == instruction.instructionType) {
+      return hasChanged;
+    }
 
-    if (shouldInsertTypeGuard(instruction, speculativeType)
-        && !tryTypeConversion(instruction, speculativeType)) {
+    if (!tryTypeConversion(instruction, speculativeType)
+        && typeGuardWouldBeValuable(instruction, speculativeType)) {
       HInstruction insertionPoint;
       if (instruction is HPhi) {
         insertionPoint = instruction.block.first;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 1cd2255..61e465b 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -1215,6 +1215,7 @@
                        Selector selector,
                        List<HInstruction> providedArguments,
                        Node currentNode) {
+    backend.registerStaticUse(element, compiler.enqueuer.codegen);
     // We cannot inline a method from a deferred library into a method
     // which isn't deferred.
     // TODO(ahe): But we should still inline into the same
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 01ad49e..b4f0d92 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -2421,8 +2421,14 @@
 
   js.Expression generateTest(HCheck node) {
     HInstruction input = node.checkedInput;
+    TypeMask receiver = input.instructionType.computeMask(compiler);
+    TypeMask mask = node.instructionType.computeMask(compiler);
+    bool turnIntoNullCheck = mask.nullable() == receiver;
     js.Expression test;
-    if (node.isInteger()) {
+    if (turnIntoNullCheck) {
+      use(input);
+      test = new js.Binary("==", pop(), new js.LiteralNull());
+    } else if (node.isInteger()) {
       // input is !int
       checkInt(input, '!==');
       test = pop();
@@ -2486,7 +2492,7 @@
           new js.Binary('||', objectTest, notIndexingTest);
       test = new js.Binary('&&', stringTest, notObjectOrIndexingTest);
     } else {
-      compiler.internalError('Unexpected type guard', instruction: input);
+      compiler.internalError('Unexpected check', instruction: input);
     }
     return test;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index f86ac3c..fdfd0db 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -40,6 +40,10 @@
     return null;
   }
 
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return false;
+  }
+
   Operation operation(ConstantSystem constantSystem) => null;
 
   static InvokeDynamicSpecializer lookupSpecializer(Selector selector) {
@@ -123,6 +127,10 @@
     }
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
 }
 
 class IndexSpecializer extends InvokeDynamicSpecializer {
@@ -159,6 +167,10 @@
     }
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
 }
 
 class BitNotSpecializer extends InvokeDynamicSpecializer {
@@ -194,6 +206,10 @@
     if (input.isNumber()) return new HBitNot(input, instruction.selector);
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
 }
 
 class UnaryNegateSpecializer extends InvokeDynamicSpecializer {
@@ -230,6 +246,10 @@
     if (input.isNumber()) return new HNegate(input, instruction.selector);
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
 }
 
 abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer {
@@ -295,6 +315,10 @@
     return null;
   }
 
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
+
   HInstruction newBuiltinVariant(HInvokeDynamic instruction);
 }
 
@@ -352,6 +376,10 @@
     // Modulo cannot be mapped to the native operator (different semantics).    
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return false;
+  }
 }
 
 class MultiplySpecializer extends BinaryArithmeticSpecializer {
@@ -391,6 +419,10 @@
     // Truncating divide does not have a JS equivalent.    
     return null;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return false;
+  }
 }
 
 abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer {
@@ -431,11 +463,8 @@
                                    Compiler compiler) {
     HInstruction left = instruction.inputs[1];
     HInstruction right = instruction.inputs[2];
-    if (!left.isNumber() || !right.isConstantInteger()) return null;
-    HConstant rightConstant = right;
-    IntConstant intConstant = rightConstant.constant;
-    int count = intConstant.value;
-    if (count >= 0 && count <= 31) {
+    if (!left.isNumber()) return null;
+    if (argumentLessThan32(right)) {
       return newBuiltinVariant(instruction);
     }
     return null;
@@ -445,6 +474,18 @@
     return new HShiftLeft(
         instruction.inputs[1], instruction.inputs[2], instruction.selector);
   }
+
+  bool argumentLessThan32(HInstruction instruction) {
+    if (!instruction.isConstantInteger()) return false;
+    HConstant rightConstant = instruction;
+    IntConstant intConstant = rightConstant.constant;
+    int count = intConstant.value;
+    return count >= 0 && count <= 31;
+  }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return argumentLessThan32(instruction.inputs[2]);
+  }
 }
 
 class ShiftRightSpecializer extends BinaryBitOpSpecializer {
@@ -458,6 +499,10 @@
   BinaryOperation operation(ConstantSystem constantSystem) {
     return constantSystem.shiftRight;
   }
+
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
 }
 
 class BitOrSpecializer extends BinaryBitOpSpecializer {
@@ -537,6 +582,10 @@
     return null;
   }
 
+  bool hasBuiltinVariant(HInvokeDynamic instruction, Compiler compiler) {
+    return true;
+  }
+
   HInstruction newBuiltinVariant(HInvokeDynamic instruction);
 }
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index c61ff48..ce291f2 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -50,6 +50,9 @@
           new SsaDeadPhiEliminator(),
           new SsaConstantFolder(constantSystem, backend, work),
           new SsaNonSpeculativeTypePropagator(compiler),
+          // Run a dead code eliminator before LICM because dead
+          // interceptors are often in the way of LICM'able instructions.
+          new SsaDeadCodeEliminator(),
           new SsaGlobalValueNumberer(compiler),
           new SsaCodeMotion(),
           new SsaValueRangeAnalyzer(compiler, constantSystem, work),
@@ -1013,6 +1016,7 @@
         // were visited before because we are iterating in post-order.
         // So instructions that are GVN'ed in an inner loop are in their
         // loop entry, and [info.blocks] contains this loop entry.
+        moveLoopInvariantCodeFromBlock(block, block, changesFlags);
         for (HBasicBlock other in info.blocks) {
           moveLoopInvariantCodeFromBlock(other, block, changesFlags);
         }
@@ -1023,14 +1027,15 @@
   void moveLoopInvariantCodeFromBlock(HBasicBlock block,
                                       HBasicBlock loopHeader,
                                       int changesFlags) {
-    assert(block.parentLoopHeader == loopHeader);
+    assert(block.parentLoopHeader == loopHeader || block == loopHeader);
     HBasicBlock preheader = loopHeader.predecessors[0];
     int dependsFlags = SideEffects.computeDependsOnFlags(changesFlags);
     HInstruction instruction = block.first;
+    bool firstInstructionInLoop = block == loopHeader;
     while (instruction != null) {
       HInstruction next = instruction.next;
       if (instruction.useGvn()
-          && !instruction.canThrow()
+          && (!instruction.canThrow() || firstInstructionInLoop)
           && !instruction.sideEffects.dependsOn(dependsFlags)) {
         bool loopInvariantInputs = true;
         List<HInstruction> inputs = instruction.inputs;
@@ -1046,6 +1051,8 @@
         if (loopInvariantInputs) {
           block.detach(instruction);
           preheader.moveAtExit(instruction);
+        } else {
+          firstInstructionInLoop = false;
         }
       }
       int oldChangesFlags = changesFlags;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index ff49492..188969a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -260,6 +260,10 @@
   }
 
   HType simplify(Compiler compiler) => this;
+
+  HType nonNullable(compiler) {
+    return new HType.fromMask(computeMask(compiler).nonNullable(), compiler);
+  }
 }
 
 /** Used to represent [HType.UNKNOWN] and [HType.CONFLICTING]. */
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index d2ef66c..9ff7a6c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -7,17 +7,15 @@
 abstract class SsaTypePropagator extends HBaseVisitor
     implements OptimizationPhase {
 
-  final Map<int, HInstruction> workmap;
-  final List<int> worklist;
-  final Map<HInstruction, Function> pendingOptimizations;
+  final Map<int, HInstruction> workmap = new Map<int, HInstruction>();
+  final List<int> worklist = new List<int>();
+  final Map<HInstruction, Function> pendingOptimizations =
+      new Map<HInstruction, Function>();  
 
   final Compiler compiler;
   String get name => 'type propagator';
 
-  SsaTypePropagator(this.compiler)
-      : workmap = new Map<int, HInstruction>(),
-        worklist = new List<int>(),
-        pendingOptimizations = new Map<HInstruction, Function>();
+  SsaTypePropagator(this.compiler);
 
   // Compute the (shared) type of the inputs if any. If all inputs
   // have the same known type return it. If any two inputs have
@@ -110,6 +108,7 @@
     } while (!worklist.isEmpty);
   }
 
+
   void addDependentInstructionsToWorkList(HInstruction instruction) {}
 
   void addToWorkList(HInstruction instruction) {
@@ -121,11 +120,6 @@
     }
   }
 
-  void processPendingOptimizations() {
-    pendingOptimizations.forEach((instruction, action) => action());
-    pendingOptimizations.clear();
-  }
-
   HType visitInvokeDynamic(HInvokeDynamic instruction) {
     return instruction.specializer.computeTypeFromInputTypes(
         instruction, compiler);
@@ -153,6 +147,107 @@
     if (inputsType.isConflicting()) return HType.UNKNOWN;
     return inputsType;
   }
+
+  void convertInput(HInvokeDynamic instruction,
+                    HInstruction input,
+                    HType type,
+                    int kind) {
+    Selector selector = (kind == HTypeConversion.RECEIVER_TYPE_CHECK)
+        ? instruction.selector
+        : null;
+    HTypeConversion converted = new HTypeConversion(
+        null, kind, type, input, selector);
+    instruction.block.addBefore(instruction, converted);
+    input.replaceAllUsersDominatedBy(instruction, converted);    
+  }
+
+  bool isCheckEnoughForNsmOrAe(HInstruction instruction,
+                               HType type) {
+    // In some cases, we want the receiver to be an integer,
+    // but that does not mean we will get a NoSuchMethodError
+    // if it's not: the receiver could be a double.
+    if (type.isInteger()) {
+      // If the instruction's type is integer or null, the codegen
+      // will emit a null check, which is enough to know if it will
+      // hit a noSuchMethod.
+      return instruction.instructionType.isIntegerOrNull();
+    }
+    return true;
+  }
+
+  // Add a receiver type check when the call can only hit
+  // [noSuchMethod] if the receiver is not of a specific type.
+  // Return true if the receiver type check was added.
+  bool checkReceiver(HInvokeDynamic instruction) {
+    HInstruction receiver = instruction.inputs[1];
+    if (receiver.isNumber()) return false;
+    if (receiver.isNumberOrNull()) {
+      convertInput(instruction,
+                   receiver,
+                   receiver.instructionType.nonNullable(compiler),
+                   HTypeConversion.RECEIVER_TYPE_CHECK);
+      return true;
+    } else if (instruction.element == null) {
+      Iterable<Element> targets =
+          compiler.world.allFunctions.filter(instruction.selector);
+      if (targets.length == 1) {
+        Element target = targets.first;
+        ClassElement cls = target.getEnclosingClass();
+        HType type = new HType.nonNullSubclass(cls.rawType, compiler);
+        // TODO(ngeoffray): We currently only optimize on primitive
+        // types.
+        if (!type.isPrimitive(compiler)) return false;
+        if (!isCheckEnoughForNsmOrAe(receiver, type)) return false;
+        instruction.element = target;
+        convertInput(instruction,
+                     receiver,
+                     type,
+                     HTypeConversion.RECEIVER_TYPE_CHECK);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Add an argument type check if the argument is not of a type
+  // expected by the call.
+  // Return true if the argument type check was added.
+  bool checkArgument(HInvokeDynamic instruction) {
+    // We want the righ error in checked mode.
+    if (compiler.enableTypeAssertions) return false;
+    HInstruction left = instruction.inputs[1];
+    HType receiverType = left.instructionType;
+
+    // A [HTypeGuard] holds the speculated type when it is being
+    // inserted, so we go find the real receiver type.
+    if (left is HTypeGuard) {
+      var guard = left;
+      while (guard is HTypeGuard && !guard.isEnabled) {
+        guard = guard.checkedInput;
+      }
+      receiverType = guard.instructionType;
+    }
+    HInstruction right = instruction.inputs[2];
+    Selector selector = instruction.selector;
+    if (selector.isOperator() && receiverType.isNumber()) {
+      if (right.isNumber()) return false;
+      // TODO(ngeoffray): Some number operations don't have a builtin
+      // variant and will do the check in their method anyway. We
+      // still add a check because it allows to GVN these operations,
+      // but we should find a better way.
+      convertInput(instruction,
+                   right,
+                   HType.NUMBER,
+                   HTypeConversion.ARGUMENT_TYPE_CHECK);
+      return true;
+    }
+    return false;
+  }
+
+  void processPendingOptimizations() {
+    pendingOptimizations.forEach((instruction, action) => action());
+    pendingOptimizations.clear();
+  }
 }
 
 class SsaNonSpeculativeTypePropagator extends SsaTypePropagator {
@@ -168,38 +263,29 @@
     }
   }
 
-  void convertInput(HInstruction instruction, HInstruction input, HType type) {
-    HTypeConversion converted = new HTypeConversion(
-        null, HTypeConversion.ARGUMENT_TYPE_CHECK, type, input);
-    instruction.block.addBefore(instruction, converted);
-    Set<HInstruction> dominatedUsers = input.dominatedUsers(instruction);
-    for (HInstruction user in dominatedUsers) {
-      user.changeUse(input, converted);
-      addToWorkList(user);
-    }
+  void addAllUsersBut(HInvokeDynamic invoke, HInstruction instruction) {
+    instruction.usedBy.forEach((HInstruction user) {
+      if (user != invoke) addToWorkList(user);
+    });
   }
 
   HType visitInvokeDynamic(HInvokeDynamic instruction) {
-    // Update the pending optimizations map based on the potentially
-    // new types of the operands. If the operand types no longer allow
-    // us to optimize, we remove the pending optimization.
-    if (instruction.specializer is BinaryArithmeticSpecializer) {
-      HInstruction left = instruction.inputs[1];
-      HInstruction right = instruction.inputs[2];
-      if (left.isNumber()
-          && !right.isNumber()
-          // We need to call the actual method in checked mode to get
-          // the right type error.
-          && !compiler.enableTypeAssertions) {
-        pendingOptimizations[instruction] = () {
-          // This callback function is invoked after we're done
-          // propagating types. The types shouldn't have changed.
-          assert(left.isNumber() && !right.isNumber());
-          convertInput(instruction, right, HType.NUMBER);
-        };
-      } else {
-        pendingOptimizations.remove(instruction);
-      }
+    if (instruction.isInterceptedCall) {
+      // We cannot do the following optimization now, because we have
+      // to wait for the type propagation to be stable. The receiver
+      // of [instruction] might move from number to dynamic.
+      pendingOptimizations.putIfAbsent(instruction, () => () {
+        Selector selector = instruction.selector;
+        if (selector.isOperator()
+            && selector.name != const SourceString('==')) {
+          if (checkReceiver(instruction)) {
+            addAllUsersBut(instruction, instruction.inputs[1]);
+          }
+          if (!selector.isUnaryOperator() && checkArgument(instruction)) {
+            addAllUsersBut(instruction, instruction.inputs[2]);
+          }
+        }
+      });
     }
     return super.visitInvokeDynamic(instruction);
   }
@@ -220,10 +306,23 @@
     return HType.UNKNOWN;
   }
 
-  HType visitBoundsCheck(HBoundsCheck boundsCheck) {
+  HType visitCheck(HCheck check) {
     // If the desired type of the input is already a number, we want
     // to specialize it to an integer.
-    if (input == boundsCheck.index && input.isNumber()) return HType.INTEGER;
+    if (input == check.checkedInput
+        && check.isInteger()
+        && check.checkedInput.isNumberOrNull()) {
+      return HType.INTEGER;
+    }
+    return HType.UNKNOWN;
+  }
+
+  HType visitTypeConversion(HTypeConversion check) {
+    // The following checks are inserted by our optimizers, so we
+    // want to optimize them even more.
+    if (check.isArgumentTypeCheck || check.isReceiverTypeCheck) {
+      return visitCheck(check);
+    }
     return HType.UNKNOWN;
   }
 
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index e006fa5..25df301 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -90,6 +90,9 @@
   patch static _deleteLink(String path) {
     throw new UnsupportedError("File._deleteLink");
   }
+  patch static _rename(String oldPath, String newPath) {
+    throw new UnsupportedError("File._delete");
+  }
   patch static _lengthFromPath(String path) {
     throw new UnsupportedError("File._lengthFromPath");
   }
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index a4254b8..18d6e6d 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -19,7 +19,18 @@
     createInvocationMirror;
 import 'dart:_interceptors' show Interceptor;
 
-String getName(Symbol symbol) => n(symbol);
+/// No-op method that is called to inform the compiler that
+/// tree-shaking needs to be disabled.
+disableTreeShaking() => preserveNames();
+
+/// No-op method that is called to inform the compiler that unmangled
+/// named must be preserved.
+preserveNames() {}
+
+String getName(Symbol symbol) {
+  preserveNames();
+  return n(symbol);
+}
 
 final Map<String, String> mangledNames = JsMirrorSystem.computeMangledNames();
 
@@ -42,6 +53,7 @@
   }
 
   static Map<String, List<LibraryMirror>> computeLibrariesByName() {
+    disableTreeShaking();
     var result = new Map<String, List<LibraryMirror>>();
     var jsLibraries = JS('=List|Null', 'init.libraries');
     if (jsLibraries == null) return result;
@@ -61,6 +73,7 @@
   }
 
   static Map<String, String> computeMangledNames() {
+    disableTreeShaking();
     var mangledNames = JS('', 'init.mangledNames');
     var keys = extractKeys(mangledNames);
     var result = <String, String>{};
@@ -71,6 +84,7 @@
   }
 
   static Map<String, String> computeReflectiveNames() {
+    disableTreeShaking();
     var result = <String, String>{};
     mangledNames.forEach((String mangledName, String reflectiveName) {
       result[reflectiveName] = mangledName;
@@ -200,6 +214,7 @@
 }
 
 ClassMirror reflectClassByName(Symbol symbol) {
+  disableTreeShaking();
   String className = n(symbol);
   var constructor = Primitives.getConstructor(className);
   if (constructor == null) {
@@ -573,6 +588,7 @@
   JsClosureMirror(reflectee) : super(reflectee);
 
   MethodMirror get function {
+    disableTreeShaking();
     // TODO(ahe): What about optional parameters (named or not).
     var extractCallName = JS('', r'''
 function(reflectee) {
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 4700896..4813ee4 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -792,7 +792,7 @@
 
   _PairMatcher(this._firstMatcher, this._lastMatcher);
 
-  bool matches(item, MatchState matchState) {
+  bool matches(item, Map matchState) {
     if (item is! Pair) return false;
     return _firstMatcher.matches(item.first, matchState) &&
         _lastMatcher.matches(item.last, matchState);
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
index a0b900a..5a9e55c 100644
--- a/sdk/lib/_internal/pub/test/version_solver_test.dart
+++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -954,7 +954,7 @@
 
   Description describeMismatch(SolveResult result,
                                Description description,
-                               MatchState state, bool verbose) {
+                               Map state, bool verbose) {
     if (!result.succeeded) {
       description.add('Solver failed with:\n${result.error}');
       return null;
@@ -965,7 +965,7 @@
     return description;
   }
 
-  bool matches(SolveResult result, MatchState state) {
+  bool matches(SolveResult result, Map state) {
     if (!result.succeeded) return false;
 
     var expected = new Map.from(_expected);
@@ -1030,12 +1030,12 @@
 
   Description describeMismatch(SolveResult result,
                                Description description,
-                               MatchState state, bool verbose) {
+                               Map state, bool verbose) {
     description.add(state.state);
     return description;
   }
 
-  bool matches(SolveResult result, MatchState state) {
+  bool matches(SolveResult result, Map state) {
     var failures = new StringBuffer();
 
     if (result.succeeded) {
diff --git a/sdk/lib/_internal/pub/test/version_test.dart b/sdk/lib/_internal/pub/test/version_test.dart
index e4a1b0c..6210264 100644
--- a/sdk/lib/_internal/pub/test/version_test.dart
+++ b/sdk/lib/_internal/pub/test/version_test.dart
@@ -430,14 +430,14 @@
 
   VersionConstraintMatcher(this._expected, this._allow);
 
-  bool matches(item, MatchState matchState) => (item is VersionConstraint) &&
+  bool matches(item, Map matchState) => (item is VersionConstraint) &&
       _expected.every((version) => item.allows(version) == _allow);
 
   Description describe(Description description) =>
       description.add(' ${_allow ? "allows" : "does not allow"} versions');
 
   Description describeMismatch(item, Description mismatchDescription,
-      MatchState matchState, bool verbose) {
+      Map matchState, bool verbose) {
     if (item is! VersionConstraint) {
       mismatchDescription.add('was not a VersionConstraint');
       return mismatchDescription;
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index 163307f..c45fcf5 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.dart
@@ -9,10 +9,16 @@
   /**
    * Constructs a new Symbol.
    *
-   * An [ArgumentError] is thrown if [name] starts with an underscore,
-   * or if [name] is not a [String].  An [ArgumentError] is thrown if
-   * [name] is not an empty string and is not a valid qualified
-   * identifier optionally followed by [:'=':].
+   * An [ArgumentError] is thrown if [name] starts with an underscore, or if
+   * [name] is not a [String].  An [ArgumentError] is thrown if [name] is not
+   * an empty string and is not a valid qualified identifier optionally
+   * followed by [:'=':].
+   *
+   * The following text is non-normative:
+   *
+   * Creating non-const Symbol instances may result in larger output.  If
+   * possible, use [MirrorsUsed] in "dart:mirrors" to specify which names might
+   * be passed to this constructor.
    */
   const factory Symbol(String name) = _collection_dev.Symbol;
 }
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index ac1a268..450a902 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -80,6 +80,26 @@
   void deleteSync();
 
   /**
+   * Renames this file. Returns a `Future<File>` that completes
+   * with a [File] instance for the renamed file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory, the
+   * operation fails and the future completes with an exception.
+   */
+  Future<File> rename(String newPath);
+
+   /**
+   * Synchronously renames this file. Returns a [File]
+   * instance for the renamed file.
+   *
+   * If [newPath] identifies an existing file, that file is
+   * replaced. If [newPath] identifies an existing directory the
+   * operation fails and an exception is thrown.
+   */
+  File renameSync(String newPath);
+
+  /**
    * Get a [Directory] object for the directory containing this
    * file.
    */
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 59695a2..9ad3001 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -202,27 +202,28 @@
 const int _EXISTS_REQUEST = 0;
 const int _CREATE_REQUEST = 1;
 const int _DELETE_REQUEST = 2;
-const int _OPEN_REQUEST = 3;
-const int _FULL_PATH_REQUEST = 4;
-const int _CLOSE_REQUEST = 5;
-const int _POSITION_REQUEST = 6;
-const int _SET_POSITION_REQUEST = 7;
-const int _TRUNCATE_REQUEST = 8;
-const int _LENGTH_REQUEST = 9;
-const int _LENGTH_FROM_PATH_REQUEST = 10;
-const int _LAST_MODIFIED_REQUEST = 11;
-const int _FLUSH_REQUEST = 12;
-const int _READ_BYTE_REQUEST = 13;
-const int _WRITE_BYTE_REQUEST = 14;
-const int _READ_REQUEST = 15;
-const int _READ_LIST_REQUEST = 16;
-const int _WRITE_LIST_REQUEST = 17;
-const int _CREATE_LINK_REQUEST = 18;
-const int _DELETE_LINK_REQUEST = 19;
-const int _LINK_TARGET_REQUEST = 20;
-const int _TYPE_REQUEST = 21;
-const int _IDENTICAL_REQUEST = 22;
-const int _STAT_REQUEST = 23;
+const int _RENAME_REQUEST = 3;
+const int _OPEN_REQUEST = 4;
+const int _FULL_PATH_REQUEST = 5;
+const int _CLOSE_REQUEST = 6;
+const int _POSITION_REQUEST = 7;
+const int _SET_POSITION_REQUEST = 8;
+const int _TRUNCATE_REQUEST = 9;
+const int _LENGTH_REQUEST = 10;
+const int _LENGTH_FROM_PATH_REQUEST = 11;
+const int _LAST_MODIFIED_REQUEST = 12;
+const int _FLUSH_REQUEST = 13;
+const int _READ_BYTE_REQUEST = 14;
+const int _WRITE_BYTE_REQUEST = 15;
+const int _READ_REQUEST = 16;
+const int _READ_LIST_REQUEST = 17;
+const int _WRITE_LIST_REQUEST = 18;
+const int _CREATE_LINK_REQUEST = 19;
+const int _DELETE_LINK_REQUEST = 20;
+const int _LINK_TARGET_REQUEST = 21;
+const int _TYPE_REQUEST = 22;
+const int _IDENTICAL_REQUEST = 23;
+const int _STAT_REQUEST = 24;
 
 // TODO(ager): The only reason for this class is that the patching
 // mechanism doesn't seem to like patching a private top level
@@ -316,6 +317,29 @@
     throwIfError(result, "Cannot delete file '$_path'");
   }
 
+  Future<File> rename(String newPath) {
+    _ensureFileService();
+    List request = new List(3);
+    request[0] = _RENAME_REQUEST;
+    request[1] = _path;
+    request[2] = newPath;
+    return _fileService.call(request).then((response) {
+      if (_isErrorResponse(response)) {
+        throw _exceptionFromResponse(
+            response, "Cannot rename file '$_path' to '$newPath'");
+      }
+      return new File(newPath);
+    });
+  }
+
+  external static _rename(String oldPath, String newPath);
+
+  File renameSync(String newPath) {
+    var result = _rename(_path, newPath);
+    throwIfError(result, "Cannot rename file '$_path' to '$newPath'");
+    return new File(newPath);
+  }
+
   Directory get directory {
     Path path = new Path(_path).directoryPath;
     return new Directory.fromPath(path);
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index e82d329..7a59c19 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -468,6 +468,7 @@
     if (_headersWritten) return new Future.value();
     _headersWritten = true;
     headers._synchronize();  // Be sure the 'chunked' option is updated.
+    _dataSink.encoding = encoding;
     bool isServerSide = this is _HttpResponse;
     if (isServerSide) {
       var response = this;
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 6b36f30..f6ba0c9 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -95,6 +95,14 @@
    */
   TypeMirror get voidType;
 
+  /**
+   * Returns the name of [symbol].
+   *
+   * The following text is non-normative:
+   *
+   * Using this method may result in larger output.  If possible, use
+   * [MirrorsUsed] to specify which symbols must be retained in clear text.
+   */
   external static String getName(Symbol symbol);
 }
 
@@ -112,8 +120,7 @@
 /**
  * Returns an [InstanceMirror] for some Dart language object.
  *
- * This only works if this mirror system is associated with the
- * current running isolate.
+ * This only works with objects local to the current isolate.
  */
 external InstanceMirror reflect(Object reflectee);
 
@@ -225,6 +232,15 @@
 
   /**
    * A list of the metadata associated with this declaration.
+   *
+   * Let *D* be the declaration this mirror reflects.
+   * If *D* is decorated with annotations *A1, ..., An*
+   * where *n > 0*, then for each annotation *Ai* associated 
+   * with *D, 1 <= i <= n*, let *ci* be the constant object 
+   * specified by *Ai*. Then this method returns a list whose 
+   * members are instance mirrors on *c1, ..., cn*.
+   * If no annotations are associated with *D*, then 
+   * an empty list is returned.
    */
   List<InstanceMirror> get metadata;
 }
@@ -309,7 +325,7 @@
    * the the result is a [MirrorError] wrapping *e*.
    */
   /* TODO(turnidge): Handle ambiguous names.*/
-  InstanceMirror setField(Symbol fieldName, Object arg);
+  InstanceMirror setField(Symbol fieldName, Object value);
 
   /**
    * Invokes the named function and returns a mirror on the result.
@@ -345,8 +361,8 @@
    * TODO(turnidge): Handle optional & named arguments.
    */
   Future<InstanceMirror> invokeAsync(Symbol memberName,
-                                     List<Object> positionalArguments,
-                                     [Map<Symbol, Object> namedArguments]);
+                                     List positionalArguments,
+                                     [Map<Symbol, dynamic> namedArguments]);
 
   /**
    * Invokes a getter and returns a mirror on the result. The getter
@@ -373,7 +389,7 @@
    * Invokes a setter and returns a mirror on the result. The setter
    * may be either the implicit setter for a non-final field or a
    * user-defined setter method.
-   * The argument must be an instance of [InstanceMirror], or of
+   * The second argument must be an instance of [InstanceMirror], or of
    * a type that is serializable across isolates (currently [num],
    * [String], or [bool]).
    *
@@ -481,8 +497,8 @@
    * If the invocation throws an exception *e* (that it does not catch)
    * the the result is a [MirrorError] wrapping *e*.
    */
-  InstanceMirror apply(List<Object> positionalArguments,
-                       [Map<Symbol,Object> namedArguments]);
+  InstanceMirror apply(List positionalArguments,
+                       [Map<Symbol, dynamic> namedArguments]);
 
   /**
    * Executes the closure and returns a mirror on the result.
@@ -511,8 +527,8 @@
    * a type that is serializable across isolates (currently [num],
    * [String], or [bool]).
    */
-  Future<InstanceMirror> applyAsync(List<Object> positionalArguments,
-                                    [Map<Symbol, Object> namedArguments]);
+  Future<InstanceMirror> applyAsync(List positionalArguments,
+                                    [Map<Symbol, dynamic> namedArguments]);
 
   /**
    * Looks up the value of a name in the scope of the closure. The
@@ -754,8 +770,8 @@
    * then *k* is completed with a [MirrorError] wrapping *e*.
 */
   Future<InstanceMirror> newInstanceAsync(Symbol constructorName,
-                                          List<Object> positionalArguments,
-                                          [Map<Symbol, Object> namedArguments]);
+                                          List positionalArguments,
+                                          [Map<Symbol, dynamic> namedArguments]);
 
   /**
    * Does this mirror represent a class?
@@ -1078,3 +1094,104 @@
 
   const Comment(this.text, this.trimmedText, this.isDocComment);
 }
+
+/**
+ * EXPERIMENTAL API: Description of how "dart:mirrors" is used.
+ *
+ * When used as metadata on an import of "dart:mirrors" in library *L*, this
+ * class describes how "dart:mirrors" is used by library *L* unless overridden.
+ * See [override].
+ *
+ * The following text is non-normative:
+ *
+ * In some scenarios, for example, when minifying Dart code, or when generating
+ * JavaScript code from a Dart program, the size and performance of the output
+ * can suffer from use of reflection.  In those cases, telling the compiler
+ * what is used, can have a significant impact.
+ *
+ * Example usage:
+ *
+ * [:
+ * @MirrorsUsed(symbols: 'foo', override: '*')
+ * import 'dart:mirrors';
+ *
+ * class Foo {
+ *   noSuchMethod(Invocation invocation) {
+ *     print(Mirrors.getName(invocation.memberName));
+ *   }
+ * }
+ *
+ * main() {
+ *   new Foo().foo(); // Prints "foo".
+ *   new Foo().bar(); // Might print an arbitrary (mangled) name, "bar".
+ * }
+ * :]
+ */
+// TODO(ahe): Remove ", override: '*'" when it isn't necessary anymore.
+class MirrorsUsed {
+  // Note: the fields of this class are untyped.  This is because the most
+  // convenient way to specify to specify symbols today is using a single
+  // string. In some cases, a const list of classes might be convenient. Some
+  // might prefer to use a const list of symbols.
+
+  /**
+   * The list of strings passed to new [Symbol], and symbols that might be
+   * passed to [MirrorSystem.getName].
+   *
+   * Combined with the names of [reflectiveTarget], [metaTargets] and their
+   * members, this forms the complete list of strings passed to new [Symbol],
+   * and symbols that might be passed to [MirrorSystem.getName] by the library
+   * to which this metadata applies.
+   *
+   * The following text is non-normative:
+   *
+   * Specifying this option turns off the following warnings emitted by
+   * dart2js:
+   *
+   * * Using "MirrorSystem.getName" may result in larger output.
+   * * Using "new #{name}" may result in larger output.
+   *
+   * Use symbols = "*" to turn off the warnings mentioned above.
+   *
+   * For example, if using [noSuchMethod] to interact with a database, extract
+   * all the possible column names and include them in this list.  Similarly,
+   * if using [noSuchMethod] to interact with another language (JavaScript, for
+   * example) extract all the identifiers from API used and include them in
+   * this list.
+   */
+  final symbols;
+
+  /**
+   * A list of reflective targets.
+   *
+   * Combined with [metaTargets], this provides the complete list of reflective
+   * targets used by the library to which this metadata applies.
+   *
+   * The following text is non-normative:
+   *
+   * For now, there is no formal description of what a reflective target is.
+   * Informally, it is a list of things that are expected to have fully
+   * functional mirrors.
+   */
+  final targets;
+
+  /**
+   * A list of classes that when used as metadata indicates a reflective
+   * target.
+   *
+   * See [targets].
+   */
+  final metaTargets;
+
+  /**
+   * A list of library names or "*".
+   *
+   * When used as metadata on an import of "dart:mirrors", this metadata does
+   * not apply to the library in which the annotation is used, but instead
+   * applies to the other libraries (all libraries if "*" is used).
+   */
+  final override;
+
+  const MirrorsUsed(
+      {this.symbols, this.targets, this.metaTargets, this.override});
+}
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index 8e13499..065b1c1 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -3,6 +3,19 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2dart ]
+
+# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
+LibTest/core/double/floor_A01_t05: Fail # issue 428
+LibTest/core/double/ceil_A01_t05: Fail # issue 428
+Language/12_Statements/02_Expression_Statements_A01_t06: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t10: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t08: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t04: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t03: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t02: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t01: Fail # co19 issue 428
+Language/11_Expressions/01_Constants_A01_t01: Fail # co19 issue 428
+
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: Fail # TODO(dart2dart-team): Please triage this failure.
 Language/07_Classes/9_Superclasses/1_Inheritance_and_Overriding_A01_t03: Fail # TODO(dart2dart-team): Please triage this failure.
 Language/11_Expressions/01_Constants_A18_t06: Fail # TODO(dart2dart-team): Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index b38e62f..6a518b5 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -7,6 +7,19 @@
 Language/07_Classes/6_Constructors_A02_t01: Skip # co19 issue 415.
 
 [ $compiler == none && $runtime == vm ]
+
+# The following tests fail because they contain number literals with a + prefix (co19 issue 428)
+LibTest/core/double/floor_A01_t05: Fail # issue 428
+LibTest/core/double/ceil_A01_t05: Fail # issue 428
+Language/12_Statements/02_Expression_Statements_A01_t06: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t10: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t08: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t04: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t03: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t02: Fail # co19 issue 428
+Language/11_Expressions/03_Numbers_A01_t01: Fail # co19 issue 428
+Language/11_Expressions/01_Constants_A01_t01: Fail # co19 issue 428
+
 Language/05_Variables/05_Variables_A07_t01: Fail # TODO(vm-team): Please triage this failure.
 Language/05_Variables/05_Variables_A07_t02: Fail # TODO(vm-team): Please triage this failure.
 Language/05_Variables/05_Variables_A07_t03: Fail # TODO(vm-team): Please triage this failure.
diff --git a/tests/compiler/dart2js/code_motion_test.dart b/tests/compiler/dart2js/code_motion_test.dart
index 0259492..e45095a 100644
--- a/tests/compiler/dart2js/code_motion_test.dart
+++ b/tests/compiler/dart2js/code_motion_test.dart
@@ -7,14 +7,16 @@
 
 const String TEST_ONE = r"""
 foo(int a, int b, bool param2) {
+  // Make sure a and b become numbers.
+  var c = a - b;
   for (int i = 0; i < 1; i++) {
-    var x = a + 5;  // '+' is now GVNed.
     if (param2) {
       print(a + b);
     } else {
       print(a + b);
     }
   }
+  return c;
 }
 """;
 
diff --git a/tests/compiler/dart2js/gvn_test.dart b/tests/compiler/dart2js/gvn_test.dart
index b648bca..85bfad9 100644
--- a/tests/compiler/dart2js/gvn_test.dart
+++ b/tests/compiler/dart2js/gvn_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import "package:expect/expect.dart";
 import 'compiler_helper.dart';
 
 const String TEST_ONE = r"""
@@ -60,6 +61,49 @@
 }
 """;
 
+// Check that a gvn'able instruction in the loop header gets hoisted.
+const String TEST_SIX = r"""
+class A {
+  final field = 54;
+}
+
+main() {
+  var a = new A();
+  while (a.field == 54) { a.field = 42; }
+}
+""";
+
+// Check that a gvn'able instruction that may throw in the loop header
+// gets hoisted.
+const String TEST_SEVEN = r"""
+class A {
+  final field;
+  A() : field = null;
+  A.bar() : field = 42;
+}
+
+main() {
+  var a = new A();
+  var b = new A.bar();
+  while (a.field == 54) { a.field = 42; b.field = 42; }
+}
+""";
+
+// Check that a check in a loop header gets hoisted.
+const String TEST_EIGHT = r"""
+class A {
+  final field;
+  A() : field = null;
+  A.bar() : field = 42;
+}
+
+main() {
+  var a = new A();
+  var b = new A.bar();
+  for (int i = 0; i < a.field; i++) { a.field = 42; b.field = 42; }
+}
+""";
+
 main() {
   String generated = compile(TEST_ONE, entry: 'foo');
   RegExp regexp = new RegExp(r"1 \+ [a-z]+");
@@ -77,4 +121,13 @@
   generated = compileAll(TEST_FIVE);
   checkNumberOfMatches(
       new RegExp("get\\\$foo").allMatches(generated).iterator, 1);
+
+  generated = compileAll(TEST_SIX);
+  Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
+
+  generated = compileAll(TEST_SEVEN);
+  Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
+
+  generated = compileAll(TEST_EIGHT);
+  Expect.isTrue(generated.contains('for (; i < t1; ++i)'));
 }
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index e0f544d..9b9da69 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -17,7 +17,7 @@
 
 const String TEST_TWO = r"""
   foo(a) {
-    var myVariableName = a + 42;
+    var myVariableName = a.toString();
     print(myVariableName);
     print(myVariableName);
   }
@@ -42,7 +42,7 @@
   // Check that one-shot interceptors preserve variable names, see
   // https://code.google.com/p/dart/issues/detail?id=8106.
   generated = compile(TEST_TWO, entry: 'foo');
-  Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.\$add\$n\(a, 42\)')));
+  Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.toString\$0\(a\)')));
   Expect.isTrue(generated.contains('myVariableName'));
 
   // Check that an intercepted getter that does not need to be
diff --git a/tests/compiler/dart2js/is_inference_test.dart b/tests/compiler/dart2js/is_inference_test.dart
index 7bb12fb..d648913 100644
--- a/tests/compiler/dart2js/is_inference_test.dart
+++ b/tests/compiler/dart2js/is_inference_test.dart
@@ -7,6 +7,7 @@
 
 const String TEST_IF = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is int) {
     param = param + 42;
   }
@@ -16,6 +17,7 @@
 
 const String TEST_IF_ELSE = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is int) {
     param = param + 42;
   } else {
@@ -27,6 +29,7 @@
 
 const String TEST_IF_RETURN = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is int) {
     return param + 42;
   }
@@ -36,6 +39,7 @@
 
 const String TEST_IF_NOT_ELSE = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is !int) {
     param = param + 53;
   } else {
@@ -47,6 +51,7 @@
 
 const String TEST_IF_NOT_RETURN = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is !int) return param + 53;
   return param + 42;
 }
@@ -54,6 +59,7 @@
 
 const String TEST_IF_NOT_ELSE_RETURN = r"""
 test(param) {
+  print('Printing this ensures that String+ is in the system.');
   if (param is !int) {
     return param + 53;
   } else {
diff --git a/tests/compiler/dart2js/mirror_tree_shaking_test.dart b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
new file mode 100644
index 0000000..7025c41
--- /dev/null
+++ b/tests/compiler/dart2js/mirror_tree_shaking_test.dart
@@ -0,0 +1,64 @@
+// 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.
+
+// Test that tree-shaking hasn't been turned off.
+
+import 'package:expect/expect.dart';
+import 'memory_source_file_helper.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+       show NullSink;
+
+import '../../../sdk/lib/_internal/compiler/compiler.dart'
+       show Diagnostic;
+
+import 'dart:async';
+
+main() {
+  Uri script = currentDirectory.resolve(nativeToUriPath(new Options().script));
+  Uri libraryRoot = script.resolve('../../../sdk/');
+  Uri packageRoot = script.resolve('./packages/');
+
+  MemorySourceFileProvider.MEMORY_SOURCE_FILES = MEMORY_SOURCE_FILES;
+  var provider = new MemorySourceFileProvider();
+  void diagnosticHandler(Uri uri, int begin, int end,
+                         String message, Diagnostic kind) {
+    if (kind == Diagnostic.VERBOSE_INFO || kind == Diagnostic.WARNING) {
+      return;
+    }
+    throw '$uri:$begin:$end:$message:$kind';
+  }
+
+  EventSink<String> outputProvider(String name, String extension) {
+    return new NullSink('$name.$extension');
+  }
+
+  Compiler compiler = new Compiler(provider.readStringFromUri,
+                                   outputProvider,
+                                   diagnosticHandler,
+                                   libraryRoot,
+                                   packageRoot,
+                                   []);
+  compiler.run(Uri.parse('memory:main.dart'));
+  Expect.isFalse(compiler.compilationFailed);
+  Expect.isFalse(compiler.enqueuer.resolution.hasEnqueuedEverything);
+  Expect.isFalse(compiler.enqueuer.codegen.hasEnqueuedEverything);
+}
+
+const Map MEMORY_SOURCE_FILES = const {
+  'main.dart': r"""
+import 'dart:mirrors';
+
+class Foo {
+  noSuchMethod(invocation) {
+    print('Invoked ${MirrorSystem.getName(invocation.memberName)}');
+    return reflect('foobar').delegate(invocation);
+  }
+}
+
+void main() {
+  print(new Foo().substring(3));
+}
+""",
+};
diff --git a/tests/compiler/dart2js/value_range_test.dart b/tests/compiler/dart2js/value_range_test.dart
index 474d2a1..940b615 100644
--- a/tests/compiler/dart2js/value_range_test.dart
+++ b/tests/compiler/dart2js/value_range_test.dart
@@ -159,7 +159,7 @@
 main(value) {
   // Force [value] to be an int by having the speculative optimizer
   // want an int.
-  int sum = 0;
+  int sum = ~value;
   for (int i = 0; i < 42; i++) sum += (value & 4);
   var a = new List();
   if (value > a.length - 1) return;
@@ -173,7 +173,7 @@
 main(value) {
   // Force [value] to be an int by having the speculative optimizer
   // want an int.
-  int sum = 0;
+  int sum = ~value;
   for (int i = 0; i < 42; i++) sum += (value & 4);
   var a = new List();
   if (value <= a.length - 1) {
@@ -188,7 +188,7 @@
 main(value) {
   // Force [value] to be an int by having the speculative optimizer
   // want an int.
-  int sum = 0;
+  int sum = ~value;
   for (int i = 0; i < 42; i++) sum += (value & 4);
   var a = new List();
   if (value >= a.length) return;
@@ -261,6 +261,7 @@
     operator ==(other) {}
   }
   class JSInt extends JSNumber {
+    operator~() => this;
   }
   class JSDouble extends JSNumber {
   }
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 527f220..f449e11 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -138,33 +138,8 @@
 [ $compiler == dart2js && ( $runtime == ff || $runtime == safari ) ]
 isolate_stress_test: Pass, Timeout # http://dartbug.com/10697
 
-[ $arch == simarm && $mode == debug ]
-message_test: Crash # Issue: 11207
-unresolved_ports_test: Pass, Crash # Issue: 11207
-
-[ ($arch == arm || $arch == simarm) && $checked ]
-count_test: Pass, Crash # Issue: 11207
-isolate_complex_messages_test: Pass, Crash # Issue: 11207
-mandel_isolate_test: Pass, Crash # Issue 11207
-cross_isolate_message_test: Pass, Crash # Issue: 11207
-nested_spawn_test: Pass, Crash # Issue: 11207
-
 [ $arch == arm || $arch == simarm ]
-request_reply_test: Pass, Crash # Issue: 11207
-nested_spawn_test: Pass, Crash # Issue: 11207
-nested_spawn2_test: Pass, Crash # Issue: 11207
-count_stream_test: Pass, Crash # Issue: 11207
-cross_isolate_message_stream_test: Crash # Issue: 11207
-mandel_isolate_stream_test: Crash # Issue: 11207
-message2_test: Pass, Crash # Issue: 11207
-message_stream2_test: Crash # Issue: 11207
-nested_spawn_stream_test: Crash, Pass # Issue: 11207
-nested_spawn_stream2_test: Pass, Crash # Issue: 11207
-spawn_function_negative_test: Pass, Crash # Issue: 11207
-spawn_uri_vm_negative_test: Crash, Pass # Issue: 11207 (Pass on Mac)
-stream_mangling_test: Crash # Issue: 11207
-message_test: Pass, Crash # Issue: 11207
-mint_maker_test: Pass, Crash # Issue: 11207
+*: Skip
 
 [ $arch == mips ]
 *: Skip
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 456c164..27a984d 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -173,7 +173,6 @@
 syntax_test/31: fail
 syntax_test/32: fail
 syntax_test/33: fail
-ternary_test: fail
 throw7_negative_test: fail
 type_error_test: fail
 type_parameter_test/01: fail
@@ -196,8 +195,6 @@
 type_variable_bounds_test/09: fail
 type_variable_identifier_expression_negative_test: fail
 type_variable_static_context_negative_test: fail
-unary2_test: fail
-unary_test: fail
 unresolved_in_factory_negative_test: fail
 unresolved_top_level_method_negative_test: fail
 unresolved_top_level_var_negative_test: fail
diff --git a/tests/language/ternary_test.dart b/tests/language/ternary_test.dart
index 6549990..b20c188 100644
--- a/tests/language/ternary_test.dart
+++ b/tests/language/ternary_test.dart
@@ -9,11 +9,11 @@
   static true_cond() { return true; }
   static false_cond() { return false; }
   static foo() { return -4; }
-  static moo() { return +5; }
+  static moo() { return 5; }
   static testMain() {
     Expect.equals(-4, (TernaryTest.true_cond() ? TernaryTest.foo()
                                                : TernaryTest.moo()));
-    Expect.equals(+5, (TernaryTest.false_cond() ? TernaryTest.foo()
+    Expect.equals(5, (TernaryTest.false_cond() ? TernaryTest.foo()
                                                 : TernaryTest.moo()));
   }
 }
diff --git a/tests/language/unary2_test.dart b/tests/language/unary2_test.dart
index 81d3335..19b4825 100644
--- a/tests/language/unary2_test.dart
+++ b/tests/language/unary2_test.dart
@@ -7,10 +7,9 @@
 
 class UnaryTest {
   static foo() { return -4; }
-  static moo() { return +5; }
+  static moo() { return 5; }
   static testMain() {
     Expect.equals(1, (UnaryTest.foo() + UnaryTest.moo()));
-    var x = +.5;  // Legal number, '+' is not a unary operator.
   }
 }
 
diff --git a/tests/language/unary_test.dart b/tests/language/unary_test.dart
index a4001e7..08a6ced 100644
--- a/tests/language/unary_test.dart
+++ b/tests/language/unary_test.dart
@@ -8,7 +8,7 @@
 
 class UnaryTest {
   static foo() { return 4; }
-  static moo() { return +5; }
+  static moo() { return 5; }
   static testMain() {
     Expect.equals(9.0, (UnaryTest.foo() + UnaryTest.moo()));
   }
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index cdf2a9d..ed775e2 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -20,13 +20,15 @@
 typed_data/byte_data_test: Fail, OK # d8/ie9 doesn't support DataView
 
 [ $compiler == dart2js && $minified ]
+mirrors/metadata_test: Fail
 mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
 mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # Issue 6490
 mirrors/disable_tree_shaking_test: Fail # Issue 6490
 mirrors/reflect_model_test: Fail # Issue 6490
 
 [ $csp ]
-mirrors/metadata_test: Fail # Issue 6490
+mirrors/library_metadata_test: Fail # Issue 10906
+mirrors/metadata_test: Fail # Issue 10906
 mirrors/reflect_runtime_type_test: Fail # Issue 6490
 mirrors/reflect_uninstantiated_class_test: Fail # Issue 6490
 mirrors/superclass_test: Fail # Issue 6490
@@ -62,10 +64,12 @@
                                          # implement timer (currently only in d8)
 
 [ $compiler == dart2dart ]
+mirrors/metadata_test: Fail
 mirrors/mirrors_test: Fail              # Issue 10957
 mirrors/library_uri_package_test: Fail  # Issue 10957
 async/run_async6_test: Fail             # Issue 10957 - may be related to issue 10910
 mirrors/reflect_model_test: Fail # http://dartbug.com/11219
+mirrors/disable_tree_shaking_test: Fail
 
 [ $compiler == dart2dart && $minified ]
 json/json_test: Fail                           # Issue 10961
@@ -75,7 +79,6 @@
 typed_data/float32x4_unbox_regress_test: Fail  # Issue 10961
 mirrors/reflect_runtime_type_test: Fail
 mirrors/reflect_uninstantiated_class_test: Fail
-mirrors/disable_tree_shaking_test: Fail
 
 
 [ $runtime == ff ]
@@ -101,7 +104,7 @@
 
 [ $runtime == vm || ($compiler == none && $runtime == drt) ]
 async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
-mirrors/metadata_test: Fail # http://dartbug.com/10906
+mirrors/library_metadata_test: Fail # http://dartbug.com/10906
 mirrors/superclass_test: Fail # http://dartbug.com/11142
 mirrors/reflectively_instantiate_uninstantiated_class_test: Fail # http://dartbug.com/11187
 mirrors/reflect_model_test: Fail # http://dartbug.com/11219
@@ -119,33 +122,7 @@
 
 
 [ $arch == arm || $arch == simarm ]
-async/future_test: Pass, Crash # Issue: 11207
-async/run_async6_test: Pass, Fail # Issue: 11207
-async/run_async_test: Pass, Crash # Issue: 11207
-async/slow_consumer2_test: Pass, Crash # Issue: 11207
-async/slow_consumer3_test: Pass, Crash # Issue: 11207
-async/slow_consumer_test: Pass, Crash # Issue: 11207
-async/stream_controller_async_test: Pass, Crash # Issue: 11207
-async/stream_controller_test: Timeout, Pass, Crash # Issue: 11207
-async/stream_from_iterable_test: Pass, Crash # Issue: 11207
-async/stream_periodic2_test: Pass, Crash # Issue: 11207
-async/stream_periodic3_test: Pass, Crash # Issue: 11207
-async/stream_periodic4_test: Pass, Crash # Issue: 11207
-async/stream_periodic5_test: Pass, Crash # Issue: 11207
-async/stream_single_to_multi_subscriber_test: Pass, Crash # Issue: 11207
-async/stream_state_nonzero_timer_test: Pass, Crash # Issue: 11207
-async/stream_state_test: Pass, Crash # Issue: 11207
-async/stream_subscription_as_future_test: Pass, Crash # Issue: 11207
-async/stream_transform_test: Pass, Crash # Issue: 11207
-async/timer_cancel1_test: Pass, Crash # Issue: 11207
-async/timer_cancel2_test: Pass, Crash # Issue: 11207
-math/pi_test: Crash, Fail # Issue: 11207
-math/random_test: Fail # Issue: 11207
-mirrors/reflect_model_test: Pass, Crash # Issue: 11207
-typed_data/float32x4_list_test: Crash # Issue: 11207
-typed_data/float32x4_test: Crash # Issue: 11207
-typed_data/float32x4_unbox_phi_test: Crash # Issue: 11207
-typed_data/float32x4_unbox_regress_test: Crash # Issue: 11207
+*: Skip
 
 [ $arch == mips ]
 *: Skip
diff --git a/tests/lib/math/math2_test.dart b/tests/lib/math/math2_test.dart
index 2f741d4..7ba8c3f 100644
--- a/tests/lib/math/math2_test.dart
+++ b/tests/lib/math/math2_test.dart
@@ -209,6 +209,11 @@
     Expect.equals(9, int.parse("09"));
     Expect.equals(9, int.parse(" 09 "));
     Expect.equals(-9, int.parse("-09"));
+    Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+    Expect.equals(0x1234567890, int.parse("   +0x1234567890   "));
+    Expect.equals(0x100, int.parse("+0x100"));
+    Expect.equals(0x100, int.parse("   +0x100   "));
+
     Expect.equals(true, parseIntThrowsFormatException("1b"));
     Expect.equals(true, parseIntThrowsFormatException(" 1b "));
     Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
@@ -236,10 +241,6 @@
     Expect.equals(true, parseIntThrowsFormatException("- 5"));
     Expect.equals(true, parseIntThrowsFormatException(""));
     Expect.equals(true, parseIntThrowsFormatException("  "));
-    Expect.equals(true, parseIntThrowsFormatException("+0x1234567890"));
-    Expect.equals(true, parseIntThrowsFormatException("   +0x1234567890   "));
-    Expect.equals(true, parseIntThrowsFormatException("+0x100"));
-    Expect.equals(true, parseIntThrowsFormatException("   +0x100   "));
   }
 
   static testMain() {
diff --git a/tests/lib/math/math_test.dart b/tests/lib/math/math_test.dart
index 2bc7741..04a5022 100644
--- a/tests/lib/math/math_test.dart
+++ b/tests/lib/math/math_test.dart
@@ -206,6 +206,10 @@
     Expect.equals(9, int.parse("09"));
     Expect.equals(9, int.parse(" 09 "));
     Expect.equals(-9, int.parse("-09"));
+    Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+    Expect.equals(0x1234567890,int.parse("   +0x1234567890   "));
+    Expect.equals(0x100, int.parse("+0x100"));
+    Expect.equals(0x100, int.parse("   +0x100   "));
     Expect.equals(true, parseIntThrowsFormatException("1b"));
     Expect.equals(true, parseIntThrowsFormatException(" 1b "));
     Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
@@ -233,10 +237,6 @@
     Expect.equals(true, parseIntThrowsFormatException("- 5"));
     Expect.equals(true, parseIntThrowsFormatException(""));
     Expect.equals(true, parseIntThrowsFormatException("  "));
-    Expect.equals(true, parseIntThrowsFormatException("+0x1234567890"));
-    Expect.equals(true, parseIntThrowsFormatException("   +0x1234567890   "));
-    Expect.equals(true, parseIntThrowsFormatException("+0x100"));
-    Expect.equals(true, parseIntThrowsFormatException("   +0x100   "));
   }
 
   static testMain() {
diff --git a/tests/lib/mirrors/library_metadata_test.dart b/tests/lib/mirrors/library_metadata_test.dart
new file mode 100644
index 0000000..3ae8b11
--- /dev/null
+++ b/tests/lib/mirrors/library_metadata_test.dart
@@ -0,0 +1,45 @@
+// 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.
+
+@string @symbol
+library test.library_metadata_test;
+
+import 'dart:mirrors';
+
+const string = 'a metadata string';
+
+const symbol = const Symbol('symbol');
+
+const hest = 'hest';
+
+checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
+  List metadata = mirror.metadata.map((m) => m.reflectee).toList();
+  if (metadata == null) {
+    throw 'Null metadata on $mirror';
+  }
+  int expectedLength = expectedMetadata.length;
+  int actualLength = metadata.length;
+  if (expectedLength != actualLength) {
+    throw 'Expected length = $expectedLength, but got length = $actualLength.';
+  }
+  for (int i = 0; i < expectedLength; i++) {
+    if (metadata[i] != expectedMetadata[i]) {
+      throw '${metadata[i]} is not "${expectedMetadata[i]}"'
+          ' in $mirror at index $i';
+    }
+  }
+  print(metadata);
+}
+
+main() {
+  if (MirrorSystem.getName(symbol) != 'symbol') {
+    // This happened in dart2js due to how early library metadata is
+    // computed.
+    throw 'Bad constant: $symbol';
+  }
+
+  MirrorSystem mirrors = currentMirrorSystem();
+  checkMetadata(mirrors.findLibrary(const Symbol('test.library_metadata_test')).first,
+                [string, symbol]); 
+}
diff --git a/tests/lib/mirrors/metadata_test.dart b/tests/lib/mirrors/metadata_test.dart
index fbd888a..6db3e55 100644
--- a/tests/lib/mirrors/metadata_test.dart
+++ b/tests/lib/mirrors/metadata_test.dart
@@ -2,7 +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.
 
-@string @symbol
 library test.metadata_test;
 
 import 'dart:mirrors';
@@ -51,14 +50,13 @@
   }
 
   MirrorSystem mirrors = currentMirrorSystem();
-  checkMetadata(mirrors.findLibrary(const Symbol('test.metadata_test')).first,
-                [string, symbol]);
   ClassMirror myClassMirror = reflectClass(MyClass);
   checkMetadata(myClassMirror, [symbol, string]);
-  ClosureMirror closure = reflect(main);
-  checkMetadata(closure.function, [symbol, string, symbol]);
-  closure = reflect(new MyClass().myMethod);
-  checkMetadata(closure.function, [string, symbol, string]);
+  LibraryMirror lib = mirrors.findLibrary(const Symbol('test.metadata_test')).first;
+  MethodMirror function = lib.functions[const Symbol('main')];
+  checkMetadata(function, [symbol, string, symbol]);
+  MethodMirror method = myClassMirror.methods[const Symbol('myMethod')];
+  checkMetadata(method, [string, symbol, string]);
 
   VariableMirror xMirror = myClassMirror.variables[const Symbol('x')];
   checkMetadata(xMirror, [hest, hest, symbol]);
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index b931475..c34b823 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -1218,6 +1218,59 @@
     Expect.isFalse(file.existsSync());
   }
 
+  // Test that opens the same file for writing then for appending to test
+  // that the file is not truncated when opened for appending.
+  static void testRename() {
+    var file = new File('${tempDirectory.path}/rename_name');
+    file.create().then((file) {
+      file.rename("${tempDirectory.path}/rename_newname").then((newfile) {
+        file.exists().then((e) {
+          Expect.isFalse(e);
+          newfile.exists().then((e) {
+            Expect.isTrue(e);
+            newfile.delete().then((_) {
+              file.exists().then((e) {
+                Expect.isFalse(e);
+                if (Platform.operatingSystem != "windows") {
+                  var brokenLink =
+                      new Link('${tempDirectory.path}/rename_name');
+                  brokenLink.create(
+                      '${tempDirectory.path}/rename_newname').then((_) {
+                      file.rename("xxx").then((_) {
+                        throw "Rename of broken link succeeded";
+                      }).catchError((e) {
+                        Expect.isTrue(e is FileException);
+                        asyncTestDone("testRename");
+                      });
+                  });
+
+                } else {
+                  asyncTestDone("testRename");
+                }
+              });
+            });
+          });
+        });
+      });
+    });
+    asyncTestStarted();
+  }
+
+  static void testRenameSync() {
+    var file = new File('${tempDirectory.path}/rename_name_sync');
+    file.createSync();
+    var newfile = file.renameSync('${tempDirectory.path}/rename_newname_sync');
+    Expect.isFalse(file.existsSync());
+    Expect.isTrue(newfile.existsSync());
+    newfile.deleteSync();
+    Expect.isFalse(newfile.existsSync());
+    if (Platform.operatingSystem != "windows") {
+      var brokenLink = new Link('${tempDirectory.path}/rename_name_sync');
+      brokenLink.createSync('${tempDirectory.path}/rename_newname_sync');
+      Expect.throws(() => file.renameSync('xxx'));
+    }
+  }
+
   // Helper method to be able to run the test from the runtime
   // directory, or the top directory.
   static String getFilename(String path) =>
@@ -1276,6 +1329,8 @@
       testDirectorySync();
       testWriteStringUtf8();
       testWriteStringUtf8Sync();
+      testRename();
+      testRenameSync();
     });
   }
 }
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index 232cf43..fb5f916 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -46,21 +46,16 @@
   });
 
   // Bind to a port already in use.
-  // Either an error or a successful bind is allowed.
-  // Windows platforms allow multiple binding to the same socket, with
-  // unpredictable results.
   RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
     RawSecureServerSocket.bind(HOST_NAME,
                                s.port,
                                CERTIFICATE).then((t) {
-      Expect.equals('windows', Platform.operatingSystem);
-      Expect.equals(s.port, t.port);
+      Expect.fail("Multiple listens on same port");
       s.close();
       t.close();
       port.toSendPort().send(1);
     })
     .catchError((error) {
-      Expect.notEquals('windows', Platform.operatingSystem);
       Expect.isTrue(error is SocketException);
       s.close();
       port.toSendPort().send(1);
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
index 381c0ed..08ed693 100644
--- a/tests/standalone/io/raw_socket_test.dart
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -48,19 +48,14 @@
       });
 
   // Bind to a port already in use.
-  // Either an error or a successful bind is allowed.
-  // Windows platforms allow multiple binding to the same socket, with
-  // unpredictable results.
   RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0)
       .then((s) {
           RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, s.port)
             .then((t) {
-              Expect.equals('windows', Platform.operatingSystem);
-              Expect.equals(s.port, t.port);
+              Expect.fail("Multiple listens on same port");
               port.toSendPort().send(1);
             })
             .catchError((error) {
-              Expect.notEquals('windows', Platform.operatingSystem);
               Expect.isTrue(error is SocketException);
               port.toSendPort().send(1);
             });
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index a7c0801..9563fc9 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -46,20 +46,13 @@
   });
 
   // Bind to a port already in use.
-  // Either an error or a successful bind is allowed.
-  // Windows platforms allow multiple binding to the same socket, with
-  // unpredictable results.
   SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
     SecureServerSocket.bind(HOST_NAME,
                             s.port,
                             CERTIFICATE).then((t) {
-      Expect.equals('windows', Platform.operatingSystem);
-      Expect.equals(s.port, t.port);
-      s.close();
-      t.close();
+      Expect.fail("Multiple listens on same port");
       port.toSendPort().send(1);
     }).catchError((error) {
-      Expect.notEquals('windows', Platform.operatingSystem);
       Expect.isTrue(error is SocketException);
       s.close();
       port.toSendPort().send(1);
diff --git a/tests/standalone/io/socket_test.dart b/tests/standalone/io/socket_test.dart
index 32e7742..4220980 100644
--- a/tests/standalone/io/socket_test.dart
+++ b/tests/standalone/io/socket_test.dart
@@ -48,20 +48,16 @@
       });
 
   // Bind to a port already in use.
-  // Either an error or a successful bind is allowed.
-  // Windows platforms allow multiple binding to the same socket, with
-  // unpredictable results.
   ServerSocket.bind("127.0.0.1", 0)
       .then((s) {
         ServerSocket.bind("127.0.0.1", s.port)
             .then((t) {
-              Expect.equals('windows', Platform.operatingSystem);
-              Expect.equals(s.port, t.port);
+              Expect.fail("Multiple listens on same port");
               port.toSendPort().send(1);
             })
             .catchError((error) {
-              Expect.notEquals('windows', Platform.operatingSystem);
               Expect.isTrue(error is SocketException);
+              s.close();
               port.toSendPort().send(1);
             });
       });
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 3f8543e..9f81106 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -162,144 +162,16 @@
 # Skip until we stabilize language tests.
 *: Skip
 
-[ $arch == simarm ]
-io/file_system_links_test: Crash # Issue: 11207
-io/process_exit_negative_test: Timeout, Pass, Crash # Issue: 11207
-io/socket_many_connections_test: Pass, Crash # Issue: 11207
-out_of_memory_test: Pass, Crash # Issue: 11207 (Pass on Mac)
-
-[ $arch == arm ]
-io/process_shell_test: Crash # Issue: 11207
-io/raw_secure_server_socket_argument_test: Crash # Issue: 11207
-io/secure_socket_argument_test: Crash # Issue: 11207
-
 [ $arch == arm || $arch == simarm ]
-constant_left_shift_test: Fail # Issue: 11207
 coverage_test: Crash # Issue: 11207
 debugger/basic_debugger_test: Crash # Issue: 11207
 debugger/closure_debugger_test: Crash # Issue: 11207
-deoptimization_test: Crash # Issue: 11207
-float_array_test: Crash # Issue: 11207
 http_launch_test: Crash # Issue: 11207
-io/dart_std_io_pipe_test: Fail, Crash # Issue: 11207
-io/delete_symlink_test: Crash # Issue: 11207
-io/directory_test: Crash, Timeout # Issue: 11207
-io/echo_server_stream_test: Crash # Issue: 11207
-io/file_error_test: Pass, Crash # Issue: 11207
-io/file_fuzz_test: Crash # Issue: 11207
-io/file_input_stream_test: Pass, Crash # Issue: 11207
-io/file_non_ascii_test: Pass, Crash # Issue: 11207
-io/file_output_stream_test: Pass, Crash # Issue 11207
-io/file_read_special_device_test: Crash, Fail, Timeout # Issue: 11207
-io/file_stat_test: Crash # Issue: 11207
-io/file_system_async_links_test: Crash # Issue: 11207
-io/file_system_delete_test: Pass, Crash # Issue: 11207
-io/file_system_links_test: Timeout, Pass, Crash # Issue: 11207
-io/file_test: Timeout, Crash # Issue: 11207
-io/file_write_as_test: Crash # Issue: 11207
-io/http_10_test: Crash # Issue: 11207
-io/http_advanced_test: Crash # Issue: 11207
-io/http_auth_digest_test: Crash # Issue: 11207
-io/http_auth_test: Crash # Issue: 11207
-io/http_basic_test: Crash # Issue: 11207
-io/http_body_test: Crash # Issue: 11207
-io/http_client_connect_test: Crash # Issue: 11207
-io/http_client_exception_test: Pass, Crash # Issue: 11207
-io/http_client_request_test: Crash # Issue: 11207
-io/http_client_timeout_test: Crash # Issue: 11207
-io/http_close_test: Crash # Issue: 11207
-io/http_compression_test: Crash # Issue: 11207
-io/http_connection_close_test: Crash # Issue: 11207
-io/http_connection_header_test: Crash # Issue: 11207
-io/http_connection_info_test: Crash # Issue: 11207
-io/http_content_length_test: Crash # Issue: 11207
-io/http_cookie_test: Crash # Issue: 11207
-io/http_detach_socket_test: Crash # Issue: 11207
-io/http_headers_state_test: Crash # Issue: 11207
-io/http_head_test: Crash # Issue: 11207
-io/http_keep_alive_test: Crash # Issue: 11207
-io/http_multipart_test: Crash # Issue: 11207
-io/http_parser_test: Pass, Crash # Issue 11207
-io/http_proxy_test: Crash # Issue: 11207
-io/http_read_test: Crash # Issue: 11207
-io/http_redirect_test: Crash # Issue: 11207
-io/http_request_pipeling_test: Crash # Issue: 11207
-io/https_client_certificate_test: Crash # Issue: 11207
-io/http_server_early_client_close2_test: Crash # Issue: 11207
-io/http_server_early_client_close_test: Crash # Issue: 11207
-io/http_server_early_server_close_test: Crash # Issue: 11207
-io/http_server_response_test: Crash # Issue: 11207
-io/http_server_test: Crash # Issue: 11207
-io/http_session_test: Crash # Issue: 11207
-io/http_shutdown_test: Crash # Issue: 11207
-io/https_server_test: Crash # Issue: 11207
-io/http_stream_close_test: Crash # Issue: 11207
-io/link_async_test: Pass, Crash # Issue: 11207
-io/link_test: Pass, Crash # Issue: 11207
-io/mime_multipart_parser_test: Pass, Crash # Issue 11207
-io/pipe_server_test: Crash # Issue: 11207
-io/process_broken_pipe_test: Pass, Crash # Issue: 11207
-io/process_check_arguments_test: Pass, Crash # Issue: 11207
-io/process_environment_test: Crash # Issue: 11207
-io/process_exit_test: Crash # Issue: 11207
-io/process_invalid_arguments_test: Crash # Issue: 11207
-io/process_kill_test: Pass, Crash # Issue: 11207
-io/process_non_ascii_test: Pass, Crash # Issue: 11207
-io/process_path_environment_test: Crash # Issue: 11207
-io/process_path_test: Pass, Crash # Issue: 11207
-io/process_pid_test: Pass, Crash # Issue: 11207
-io/process_run_output_test: Pass, Crash # Issue: 11207
-io/process_segfault_test: Crash # Issue: 11207
-io/process_set_exit_code_test: Crash # Issue: 11207
-io/process_shell_test: Pass, Crash # Issue: 11207
-io/process_stderr_test: Pass, Crash # Issue: 11207
-io/process_stdin_transform_unsubscribe_test: Crash # Issue: 11207
-io/process_stdout_test: Pass, Crash # Issue: 11207
-io/process_working_directory_test: Crash # Issue: 11207
-io/raw_secure_server_closing_test: Crash # Issue: 11207
-io/raw_secure_server_socket_test: Crash # Issue: 11207
-io/raw_secure_socket_pause_test: Crash # Issue: 11207
-io/raw_secure_socket_test: Crash # Issue: 11207
-io/raw_socket_test: Crash # Issue: 11207
-io/raw_socket_typed_data_test: Pass, Crash # Issue: 11207
-io/raw_socket_write_destroy_test: Pass, Crash # Issue: 11207
-io/regress_10026_test: Crash # Issue: 11207
-io/regress_7191_test: Crash # Issue: 11207
-io/regress_8828_test: Crash # Issue: 11207
-io/regress_9194_test: Crash # Issue: 11207
-io/secure_builtin_roots_database_test: Crash # Issue: 11207
-io/secure_builtin_roots_test: Crash # Issue: 11207
-io/secure_client_raw_server_test: Crash, Timeout # Issue: 11207
-io/secure_client_server_test: Timeout, Crash # Issue: 11207
-io/secure_multiple_client_server_test: Crash # Issue: 11207
-io/secure_no_builtin_roots_database_test: Crash # Issue: 11207
-io/secure_no_builtin_roots_test: Crash # Issue: 11207
-io/secure_server_client_certificate_test: Crash # Issue: 11207
-io/secure_server_closing_test: Crash # Issue: 11207
-io/secure_server_socket_test: Crash # Issue: 11207
-io/secure_session_resume_test: Crash # Issue: 11207
-io/secure_socket_bad_certificate_test: Pass, Crash # Issue: 11207
-io/secure_socket_test: Crash # Issue: 11207
-io/socket_close_test: Crash # Issue: 11207
-io/socket_exception_test: Crash, Timeout # Issue: 11207
-io/socket_info_test: Pass, Crash # Issue: 11207
-io/socket_invalid_arguments_test: Crash # Issue: 11207
-io/socket_ipv6_test: Pass, Crash # Issue: 11207
-io/socket_port_test: Pass, Crash # Issue: 11207
-io/socket_test: Crash # Issue: 11207
-io/socket_upgrade_to_secure_test: Crash # Issue: 11207
-io/status_file_parser_test: Crash # Issue: 11207
-io/stdout_stderr_test: Pass, Crash # Issue: 11207
-io/stream_pipe_test: Pass, Crash # Issue: 11207
-io/test_extension_fail_test: Crash # Issue: 11207
-io/test_extension_test: Crash # Issue: 11207
-io/web_socket_protocol_processor_test: Crash # Issue: 11207
-io/web_socket_test: Crash # Issue: 11207
-io/web_socket_typed_data_test: Pass, Crash # Issue: 11207
 left_shift_bit_and_op_test: Fail # Issue: 11207
 package/package_isolate_test: Pass, Crash # Issue: 11207
-typed_data_test: Crash # Issue: 11207
-io/regress_7679_test: Pass, Crash
+out_of_memory_test: Pass, Crash # Issue: 11207 (Pass on Mac)
+typed_data_test: Timeout, Crash # Issue: 11207
+io/*: Skip # Skip IO tests for now as they are still quite flaky.
 
 [ $arch == mips ]
 *: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 1954d2f..28542e6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 5
-BUILD 18
+BUILD 19
 PATCH 0