Version 0.7.3.0

svn merge -r 27229:27471 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@27480 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/.gitignore b/.gitignore
index 1632934..3b24772 100644
--- a/.gitignore
+++ b/.gitignore
@@ -54,6 +54,14 @@
 # Vim temporary swap files.
 *.swp
 
+# Kate temporary files.
+*~
+*.kate-swp
+
+# Merge files.
+*.orig
+*.rej
+
 # Generated files.
 tools/out
 tools/xcodebuild
diff --git a/pkg/analyzer_experimental/bin/formatter.dart b/pkg/analyzer_experimental/bin/formatter.dart
index d80a0e2..52b8fd7 100755
--- a/pkg/analyzer_experimental/bin/formatter.dart
+++ b/pkg/analyzer_experimental/bin/formatter.dart
@@ -5,6 +5,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
+import 'dart:utf';
 
 import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
@@ -17,15 +18,16 @@
 final argParser = _initArgParser();
 
 bool overwriteFileContents;
+const followLinks = false;
 
-void main() {
+main() {
   var options = argParser.parse(new Options().arguments);
   if (options['help']) {
     _printUsage();
     return;
   }
   overwriteFileContents = options['write'];
-  
+
   if (options.rest.isEmpty) {
     _formatStdin(options);
   } else {
@@ -51,10 +53,10 @@
   }
 }
 
-_formatDirectory(dir) => 
-    dir.listSync().forEach((resource) => _formatResource(resource));
+_formatDirectory(dir) => dir.listSync(followLinks: followLinks)
+    .forEach((resource) => _formatResource(resource));
 
-void _formatFile(file) {
+_formatFile(file) {
   if (_isDartFile(file)) {
     try {
       var buffer = new StringBuffer();
@@ -66,7 +68,7 @@
         print(formatted);
       }
     } catch (e) {
-      _log('Error formatting "${file.path}": $e');
+      _log('Unable to format "${file.path}": $e');
     }
   }
 }
@@ -74,11 +76,11 @@
 _isDartFile(file) => dartFileRegExp.hasMatch(path.basename(file.path));
 
 _formatStdin(options) {
-  _log('not supported yet!');
-//  stdin.transform(new StringDecoder())
-//      .listen((String data) => print(data),
-//        onError: (error) => print('Error reading from stdin'),
-//        onDone: () => print('Finished reading data'));
+  var input = new StringBuffer();
+  stdin.transform(new Utf8DecoderTransformer())
+      .listen((data) => input.write(data),
+        onError: (error) => _log('Error reading from stdin'),
+        onDone: () => print(_formatCU(input.toString())));
 }
 
 /// Initialize the arg parser instance.
diff --git a/pkg/analyzer_experimental/lib/src/generated/java_core.dart b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
index d13bb3d..769fdf1 100644
--- a/pkg/analyzer_experimental/lib/src/generated/java_core.dart
+++ b/pkg/analyzer_experimental/lib/src/generated/java_core.dart
@@ -31,15 +31,12 @@
   if (oTypeName == tTypeName) {
     return true;
   }
-  if (oTypeName.startsWith("HashMap") && tTypeName == "Map") {
-    return true;
-  }
-  if (oTypeName.startsWith("LinkedHashMap") && tTypeName == "Map") {
-    return true;
-  }
   if (oTypeName.startsWith("List") && tTypeName == "List") {
     return true;
   }
+  if (tTypeName == "Map" && o is Map) {
+    return true;
+  }
   // Dart Analysis Engine specific
   if (oTypeName == "${tTypeName}Impl") {
     return true;
diff --git a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
index 71855f5..180e9de 100644
--- a/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer_experimental/lib/src/services/formatter_impl.dart
@@ -12,9 +12,6 @@
 import 'package:analyzer_experimental/src/generated/source.dart';
 import 'package:analyzer_experimental/src/services/writer.dart';
 
-/// OS line separator. --- TODO(pquitslund): may not be necessary
-const NEW_LINE = '\n' ; //Platform.pathSeparator;
-
 /// Formatter options.
 class FormatterOptions {
 
@@ -43,13 +40,19 @@
   final String message;
 
   /// Creates a new FormatterException with an optional error [message].
-  const FormatterException([this.message = '']);
+  const FormatterException([this.message = 'FormatterException']);
 
-  FormatterException.forError(List<AnalysisError> errors) :
-    // TODO(pquitslund): add descriptive message based on errors
-    message = 'an analysis error occured during format';
+  FormatterException.forError(List<AnalysisError> errors, [LineInfo line]) :
+    message = _createMessage(errors);
 
-  String toString() => 'FormatterException: $message';
+  static String _createMessage(errors) {
+    //TODO(pquitslund): consider a verbosity flag to add/suppress details
+    var errorCode = errors[0].errorCode;
+    var phase = errorCode is ParserErrorCode ? 'parsing' : 'scanning';
+    return 'An error occured while ${phase} (${errorCode.name}).';
+  }
+
+  String toString() => '$message';
 }
 
 /// Specifies the kind of code snippet to format.
@@ -84,6 +87,7 @@
 
   final FormatterOptions options;
   final errors = <AnalysisError>[];
+  final whitespace = new RegExp(r'[\s]+');
 
   LineInfo lineInfo;
 
@@ -92,18 +96,25 @@
   String format(CodeKind kind, String source, {int offset, int end,
       int indentationLevel: 0}) {
 
-    var start = tokenize(source);
+    var startToken = tokenize(source);
     checkForErrors();
 
-    var node = parse(kind, start);
+    var node = parse(kind, startToken);
     checkForErrors();
 
     var formatter = new SourceVisitor(options, lineInfo);
     node.accept(formatter);
 
-    return formatter.writer.toString();
+    var formattedSource = formatter.writer.toString();
+    
+    checkTokenStreams(startToken, tokenize(formattedSource));
+
+    return formattedSource;
   }
 
+  checkTokenStreams(Token t1, Token t2) =>
+      new TokenStreamComparator(lineInfo, t1, t2).verifyEquals();
+
   ASTNode parse(CodeKind kind, Token start) {
 
     var parser = new Parser(null, this);
@@ -118,13 +129,13 @@
     throw new FormatterException('Unsupported format kind: $kind');
   }
 
-  void checkForErrors() {
+  checkForErrors() {
     if (errors.length > 0) {
       throw new FormatterException.forError(errors);
     }
   }
 
-  void onError(AnalysisError error) {
+  onError(AnalysisError error) {
     errors.add(error);
   }
 
@@ -138,6 +149,123 @@
 }
 
 
+// Compares two token streams.  Used for sanity checking formatted results.
+class TokenStreamComparator {
+
+  final LineInfo lineInfo;
+  Token token1, token2;
+
+  TokenStreamComparator(this.lineInfo, this.token1, this.token2);
+
+  /// Verify that these two token streams are equal.
+  verifyEquals() {
+    while (!isEOF(token1)) {
+      checkPrecedingComments();
+      if (!checkTokens()) {
+        throwNotEqualException(token1, token2);
+      }
+      advance();
+
+    }
+    if (!isEOF(token2)) {
+      throw new FormatterException(
+          'Expected "EOF" but got "${token2}".');
+    }
+  }
+
+  checkPrecedingComments() {
+    var comment1 = token1.precedingComments;
+    var comment2 = token2.precedingComments;
+    while (comment1 != null) {
+      if (comment2 == null) {
+        throw new FormatterException(
+            'Expected comment, "${comment1}", at ${describeLocation(token1)}, '
+            'but got none.');
+      }
+      if (!equivalentComments(comment1, comment2)) {
+        throwNotEqualException(comment1, comment2);
+      }
+      comment1 = comment1.next;
+      comment2 = comment2.next;
+    }
+    if (comment2 != null) {
+      throw new FormatterException(
+          'Unexpected comment, "${comment2}", at ${describeLocation(token2)}.');
+    }
+  }
+
+  bool equivalentComments(Token comment1, Token comment2) =>
+      comment1.lexeme.trim() == comment2.lexeme.trim();
+
+  throwNotEqualException(t1, t2) {
+    throw new FormatterException(
+        'Expected "${t1}" but got "${t2}", at ${describeLocation(t1)}.');
+  }
+
+  String describeLocation(Token token) => lineInfo == null ? '<unknown>' :
+      'Line: ${lineInfo.getLocation(token.offset).lineNumber}, '
+      'Column: ${lineInfo.getLocation(token.offset).columnNumber}';
+
+  advance() {
+    token1 = token1.next;
+    token2 = token2.next;
+  }
+
+  bool checkTokens() {
+    if (token1 == null || token2 == null) {
+      return false;
+    }
+    if (token1 == token2 || token1.lexeme == token2.lexeme) {
+      return true;
+    }
+
+    // '[' ']' => '[]'
+    if (isOPEN_SQ_BRACKET(token1) && isCLOSE_SQUARE_BRACKET(token1.next)) {
+      if (isINDEX(token2)) {
+        token1 = token1.next;
+        return true;
+      }
+    }
+    // '>' '>' => '>>'
+    if (isGT(token1) && isGT(token1.next)) {
+      if (isGT_GT(token2)) {
+        token1 = token1.next;
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+}
+
+// Cached parser for testing token types.
+final tokenTester = new Parser(null,null);
+
+/// Test if this token is an EOF token.
+bool isEOF(Token token) => tokenIs(token, TokenType.EOF);
+
+/// Test for token type.
+bool tokenIs(Token token, TokenType type) => 
+    token != null && tokenTester.matches4(token, type);
+
+/// Test if this token is a GT token.
+bool isGT(Token token) => tokenIs(token, TokenType.GT);
+
+/// Test if this token is a GT_GT token.
+bool isGT_GT(Token token) => tokenIs(token, TokenType.GT_GT);
+
+/// Test if this token is an INDEX token.
+bool isINDEX(Token token) => tokenIs(token, TokenType.INDEX);
+
+/// Test if this token is a OPEN_SQUARE_BRACKET token.
+bool isOPEN_SQ_BRACKET(Token token) =>
+    tokenIs(token, TokenType.OPEN_SQUARE_BRACKET);
+
+/// Test if this token is a CLOSE_SQUARE_BRACKET token.
+bool isCLOSE_SQUARE_BRACKET(Token token) =>
+    tokenIs(token, TokenType.CLOSE_SQUARE_BRACKET);
+
 /// An AST visitor that drives formatting heuristics.
 class SourceVisitor implements ASTVisitor {
 
@@ -155,7 +283,7 @@
 
   /// Used for matching EOL comments
   final twoSlashes = new RegExp(r'//[^/]');
-  
+
   /// Initialize a newly created visitor to write source code representing
   /// the visited nodes to the given [writer].
   SourceVisitor(FormatterOptions options, this.lineInfo) :
@@ -327,6 +455,9 @@
 
     // Handle trailing whitespace
     token(node.endToken /* EOF */);
+    
+    // Be a good citizen, end with a NL
+    ensureTrailingNewline();
   }
 
   visitConditionalExpression(ConditionalExpression node) {
@@ -671,6 +802,7 @@
     visit(node.typeArguments);
     token(node.leftBracket);
     visitNodes(node.elements, separatedBy: commaSeperator);
+    optionalTrailingComma(node.rightBracket);
     token(node.rightBracket);
   }
 
@@ -679,9 +811,10 @@
     visitNode(node.typeArguments, followedBy: space);
     token(node.leftBracket);
     visitNodes(node.entries, separatedBy: commaSeperator);
+    optionalTrailingComma(node.rightBracket);
     token(node.rightBracket);
   }
-
+  
   visitMapLiteralEntry(MapLiteralEntry node) {
     visit(node.key);
     token(node.separator);
@@ -1025,13 +1158,19 @@
     token(modifier, followedBy: space);
   }
 
-
   /// Indicate that at least one newline should be emitted and possibly more
   /// if the source has them.
   newlines() {
     needsNewline = true;
   }
 
+  /// Optionally emit a trailing comma.
+  optionalTrailingComma(Token rightBracket) {
+    if (rightBracket.previous.lexeme == ',') {
+      comma();
+    }
+  }
+  
   token(Token token, {precededBy(), followedBy(), int minNewlines: 0}) {
     if (token != null) {
       if (needsNewline) {
@@ -1041,7 +1180,7 @@
       if (emitted > 0) {
         needsNewline = false;
       }
-      if (precededBy !=null) {
+      if (precededBy != null) {
         precededBy();
       }
       append(token.lexeme);
@@ -1074,7 +1213,7 @@
 
   /// Append the given [string] to the source writer if it's non-null.
   append(String string) {
-    if (string != null) {
+    if (string != null && !string.isEmpty) {
       writer.print(string);
     }
   }
@@ -1089,30 +1228,30 @@
     writer.unindent();
   }
 
-  
-  /// Emit any detected comments and newlines or a minimum as specified 
+
+  /// Emit any detected comments and newlines or a minimum as specified
   /// by [min].
   int emitPrecedingCommentsAndNewlines(Token token, {min: 0}) {
-    
+
     var comment = token.precedingComments;
     var currentToken = comment != null ? comment : token;
-    
+
     //Handle EOLs before newlines
     if (isAtEOL(comment)) {
       emitComment(comment, previousToken);
       comment = comment.next;
       currentToken = comment != null ? comment : token;
     }
-    
+
     var lines = max(min, countNewlinesBetween(previousToken, currentToken));
     writer.newlines(lines);
-    
+
     var previousToken = currentToken.previous;
-    
+
     while (comment != null) {
 
       emitComment(comment, previousToken);
-      
+
       var nextToken = comment.next != null ? comment.next : token;
       var newlines = calculateNewlinesBetweenComments(comment, nextToken);
       if (newlines > 0) {
@@ -1121,7 +1260,7 @@
       } else if (!isEOF(token)) {
         space();
       }
-      
+
       previousToken = comment;
       comment = comment.next;
     }
@@ -1130,9 +1269,17 @@
     return lines;
   }
 
+
+  ensureTrailingNewline() {
+    if (writer.lastToken is! NewlineToken) {
+      writer.newline();
+    }
+  }
+  
+  
   /// Test if this [comment] is at the end of a line.
-  bool isAtEOL(Token comment) => 
-      comment != null && comment.toString().trim().startsWith(twoSlashes) && 
+  bool isAtEOL(Token comment) =>
+      comment != null && comment.toString().trim().startsWith(twoSlashes) &&
       sameLine(comment, previousToken);
 
   /// Emit this [comment], inserting leading whitespace if appropriate.
@@ -1144,17 +1291,14 @@
         space();
       }
     }
-    
+
     append(comment.toString().trim());
   }
 
-  /// Test if this token is an EOF token.
-  bool isEOF(Token token) => token.type == TokenType.EOF;
-  
   /// Count spaces between these tokens.  Tokens on different lines return 0.
-  int countSpacesBetween(Token last, Token current) => isEOF(last) || 
-      countNewlinesBetween(last, current) > 0 ? 0 : current.offset - last.end;  
-     
+  int countSpacesBetween(Token last, Token current) => isEOF(last) ||
+      countNewlinesBetween(last, current) > 0 ? 0 : current.offset - last.end;
+
   /// Count the blanks between these two nodes.
   int countBlankLinesBetween(ASTNode lastNode, ASTNode currentNode) =>
       countNewlinesBetween(lastNode.endToken, currentNode.beginToken);
@@ -1175,37 +1319,37 @@
 
     return linesBetween(last.end - 1, current.offset);
   }
-  
+
   /// Calculate the newlines that should separate these comments.
   int calculateNewlinesBetweenComments(Token last, Token current) {
     // Insist on a newline after doc comments or single line comments
     // (NOTE that EOL comments have already been processed).
     if (isOldSingleLineDocComment(last) || isSingleLineComment(last)) {
-      return max(1, countNewlinesBetween(last, current)); 
+      return max(1, countNewlinesBetween(last, current));
     } else {
       return countNewlinesBetween(last, current);
     }
   }
-  
+
   /// Single line multi-line comments (e.g., '/** like this */').
   bool isOldSingleLineDocComment(Token comment) =>
       comment.lexeme.startsWith(r'/**') && singleLine(comment);
-  
+
   /// Test if this [token] spans just one line.
   bool singleLine(Token token) => linesBetween(token.offset, token.end) < 1;
 
   /// Test if token [first] is on the same line as [second].
   bool sameLine(Token first, Token second) =>
       countNewlinesBetween(first, second) == 0;
-   
+
   /// Test if this is a multi-line [comment] (e.g., '/* ...' or '/** ...')
-  bool isMultiLineComment(Token comment) => 
+  bool isMultiLineComment(Token comment) =>
       comment.type == TokenType.MULTI_LINE_COMMENT;
-  
+
   /// Test if this is a single-line [comment] (e.g., '// ...')
-  bool isSingleLineComment(Token comment) => 
+  bool isSingleLineComment(Token comment) =>
       comment.type == TokenType.SINGLE_LINE_COMMENT;
-  
+
   /// Test if this [comment] is a block comment (e.g., '/* like this */')..
   bool isBlock(Token comment) =>
       isMultiLineComment(comment) && singleLine(comment);
diff --git a/pkg/analyzer_experimental/lib/src/services/writer.dart b/pkg/analyzer_experimental/lib/src/services/writer.dart
index d73a1fa..d7f8fd3 100644
--- a/pkg/analyzer_experimental/lib/src/services/writer.dart
+++ b/pkg/analyzer_experimental/lib/src/services/writer.dart
@@ -41,9 +41,7 @@
 
   String toString() {
     var buffer = new StringBuffer();
-    for (var tok in tokens) {
-      buffer.write(tok.toString());
-    }
+    tokens.forEach((tok) => buffer.write(tok.toString()));
     return buffer.toString();
   }
 
@@ -84,28 +82,29 @@
 
   final String lineSeparator;
   int indentCount = 0;
-
-  SourceWriter({this.indentCount: 0, this.lineSeparator: '\n'}) {
+  
+  LineToken _lastToken;
+  
+  SourceWriter({this.indentCount: 0, this.lineSeparator: NEW_LINE}) {
     currentLine = new Line(indent: indentCount);
   }
 
+  LineToken get lastToken => _lastToken;
+  
+  _addToken(LineToken token) {
+    _lastToken = token;
+    currentLine.addToken(token);
+  }
+  
   void indent() {
     ++indentCount;
   }
 
-  void unindent() {
-    --indentCount;
-  }
-
-  void print(x) {
-    currentLine.addToken(new LineToken(x));
-  }
-
   void newline() {
     if (currentLine.isWhitespace()) {
       currentLine.tokens.clear();
     }
-    currentLine.addToken(new NewlineToken(this.lineSeparator));
+    _addToken(new NewlineToken(this.lineSeparator));
     buffer.write(currentLine.toString());
     currentLine = new Line(indent: indentCount);
   }
@@ -116,6 +115,15 @@
     }
   }
 
+  void print(x) {
+    _addToken(new LineToken(x));
+  }
+  
+  void println(String s) {
+    print(s);
+    newline();
+  }
+  
   void space() {
     spaces(1);
   }
@@ -123,12 +131,11 @@
   void spaces(n) {
     currentLine.addSpaces(n);
   }
-
-  void println(String s) {
-    print(s);
-    newline();
+  
+  void unindent() {
+    --indentCount;
   }
-
+  
   String toString() {
     var source = new StringBuffer(buffer.toString());
     if (!currentLine.isWhitespace()) {
@@ -139,7 +146,7 @@
 
 }
 
-
+const NEW_LINE = '\n';
 const SPACE = ' ';
 const SPACES = const [
           '',
diff --git a/pkg/analyzer_experimental/test/services/formatter_test.dart b/pkg/analyzer_experimental/test/services/formatter_test.dart
index afd2fc7..37147f7 100644
--- a/pkg/analyzer_experimental/test/services/formatter_test.dart
+++ b/pkg/analyzer_experimental/test/services/formatter_test.dart
@@ -46,7 +46,7 @@
           'class A {\n'
           '  }',
           'class A {\n'
-          '}'
+          '}\n'
         );
     });
 
@@ -64,7 +64,7 @@
           'class A  { int meaningOfLife() => 42; }',
           'class A {\n'
           '  int meaningOfLife() => 42;\n'
-          '}'
+          '}\n'
       );
     });
 
@@ -162,7 +162,7 @@
           'library a; class B { }',
           'library a;\n'
           'class B {\n'
-          '}'
+          '}\n'
       );
     });
 
@@ -196,7 +196,7 @@
           'import "foo";\n\n'
           '//Killer class\n'
           'class A {\n'
-          '}'
+          '}\n'
         );
     });
 
@@ -410,7 +410,7 @@
           '}\n'
       );
     });
-    
+
     test('CU - mixed comments', () {
       expectCUFormatsTo(
           'library foo;\n'
@@ -428,17 +428,17 @@
           '\n'
           '// Comment 2\n'
           '\n'
-          '/* Comment 3 */'
+          '/* Comment 3 */\n'
         );
     });
-    
+
     test('CU - comments (EOF)', () {
       expectCUFormatsTo(
           'library foo; //zamm',
           'library foo; //zamm\n' //<-- note extra NEWLINE
         );
-    });  
-    
+    });
+
     test('CU - comments (0)', () {
       expectCUFormatsTo(
           'library foo; //zamm\n'
@@ -458,11 +458,11 @@
           '/* foo */ /* bar */\n'
       );
     });
-    
+
     test('CU - comments (2)', () {
       expectCUFormatsTo(
           '/** foo */ /** bar */\n',
-          '/** foo */\n' 
+          '/** foo */\n'
           '/** bar */\n'
       );
     });
@@ -479,10 +479,10 @@
           'class X { //X!\n'
           '}',
           'class X { //X!\n'
-          '}'
+          '}\n'
       );
     });
-    
+
     test('CU - comments (5)', () {
       expectCUFormatsTo(
           '//comment one\n\n'
@@ -490,22 +490,22 @@
           '//comment one\n\n'
           '//comment two\n\n'
       );
-    });    
-    
+    });
+
     test('CU - comments (6)', () {
       expectCUFormatsTo(
           'var x;   //x\n',
           'var x; //x\n'
       );
-    });    
+    });
 
     test('CU - comments (6)', () {
       expectCUFormatsTo(
           'var /* int */ x; //x\n',
           'var /* int */ x; //x\n'
       );
-    });    
-    
+    });
+
     test('CU - comments (7)', () {
       expectCUFormatsTo(
           'library foo;\n'
@@ -534,7 +534,13 @@
           'int x;\n'
         );
     });
-    
+
+    test('CU - EOF nl', () {
+      expectCUFormatsTo(
+          'var x = 1;',
+          'var x = 1;\n'
+      );
+    });
     
     test('CU - constructor', () {
       expectCUFormatsTo(
@@ -671,12 +677,30 @@
         'var numbers = <int>[1, 2, (3 + 4)];'
       );
     });
+    
+    test('stmt (lists)', () {
+      expectStmtFormatsTo(
+        'var l = [1,2,3,4];',
+        'var l = [1, 2, 3, 4];'
+      );
+      //Dangling ','
+      expectStmtFormatsTo(
+        'var l = [1,];',
+        'var l = [1,];'
+      );
+    });
 
     test('stmt (maps)', () {
       expectStmtFormatsTo(
         'var map = const {"foo": "bar", "fuz": null};',
         'var map = const {"foo": "bar", "fuz": null};'
       );
+      
+      //Dangling ','
+      expectStmtFormatsTo(
+        'var map = {"foo": "bar",};',
+        'var map = {"foo": "bar",};'
+      );
     });
 
     test('stmt (try/catch)', () {
@@ -750,6 +774,51 @@
   });
 
 
+  /// Token streams
+  group('token streams', () {
+
+    test('string tokens', () {
+      expectTokenizedEqual('class A{}', 'class A{ }');
+      expectTokenizedEqual('class A{}', 'class A{\n  }\n');
+      expectTokenizedEqual('class A {}', 'class A{ }');
+      expectTokenizedEqual('  class A {}', 'class A{ }');
+    });
+
+    test('string tokens - w/ comments', () {
+      expectTokenizedEqual('//foo\nint bar;', '//foo\nint bar;');
+      expectTokenizedNotEqual('int bar;', '//foo\nint bar;');
+      expectTokenizedNotEqual('//foo\nint bar;', 'int bar;');
+    });
+
+    test('INDEX', () {
+      /// '[' ']' => '[]'
+      var t1 = openSqBracket()..setNext(closeSqBracket()..setNext(eof()));
+      var t2 = index()..setNext(eof());
+      expectStreamsEqual(t1, t2);
+    });
+
+    test('GT_GT', () {
+      /// '>' '>' => '>>'
+      var t1 = gt()..setNext(gt()..setNext(eof()));
+      var t2 = gt_gt()..setNext(eof());
+      expectStreamsEqual(t1, t2);
+    });
+
+    test('t1 < t2', () {
+      var t1 = string('foo')..setNext(eof());
+      var t2 = string('foo')..setNext(string('bar')..setNext(eof()));
+      expectStreamsNotEqual(t1, t2);
+    });
+
+    test('t1 > t2', () {
+      var t1 = string('foo')..setNext(string('bar')..setNext(eof()));
+      var t2 = string('foo')..setNext(eof());
+      expectStreamsNotEqual(t1, t2);
+    });
+
+  });
+
+
   /// Line tests
   group('line', () {
 
@@ -853,8 +922,21 @@
 
 }
 
-Token classKeyword(int offset) =>
-    new KeywordToken(Keyword.CLASS, offset);
+Token closeSqBracket() => new Token(TokenType.CLOSE_SQUARE_BRACKET, 0);
+
+Token eof() => new Token(TokenType.EOF, 0);
+
+Token gt() => new Token(TokenType.GT, 0);
+
+Token gt_gt() => new Token(TokenType.GT_GT, 0);
+
+Token index() => new Token(TokenType.INDEX, 0);
+
+Token openSqBracket() => new BeginToken(TokenType.OPEN_SQUARE_BRACKET, 0);
+
+Token string(String lexeme) => new StringToken(TokenType.STRING, lexeme, 0);
+
+Token classKeyword(int offset) => new KeywordToken(Keyword.CLASS, offset);
 
 Token identifier(String value, int offset) =>
     new StringToken(TokenType.IDENTIFIER, value, offset);
@@ -878,6 +960,23 @@
 String formatStatement(src, {options: const FormatterOptions()}) =>
     new CodeFormatter(options).format(CodeKind.STATEMENT, src);
 
+Token tokenize(String str) => new StringScanner(null, str, null).tokenize();
+
+
+expectTokenizedEqual(String s1, String s2) =>
+    expectStreamsEqual(tokenize(s1), tokenize(s2));
+
+expectTokenizedNotEqual(String s1, String s2) =>
+    expect(()=> expectStreamsEqual(tokenize(s1), tokenize(s2)),
+    throwsA(new isInstanceOf<FormatterException>()));
+
+expectStreamsEqual(Token t1, Token t2) =>
+    new TokenStreamComparator(null, t1, t2).verifyEquals();
+
+expectStreamsNotEqual(Token t1, Token t2) =>
+    expect(() => new TokenStreamComparator(null, t1, t2).verifyEquals(),
+    throwsA(new isInstanceOf<FormatterException>()));
+
 expectCUFormatsTo(src, expected) => expect(formatCU(src), equals(expected));
 
 expectStmtFormatsTo(src, expected) => expect(formatStatement(src),
diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart
index 0950654..0b877cd 100644
--- a/pkg/args/lib/args.dart
+++ b/pkg/args/lib/args.dart
@@ -3,141 +3,144 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * This library lets you define parsers for parsing raw command-line arguments
- * into a set of options and values using [GNU][] and [POSIX][] style options.
+ * Parser support for transforming raw command-line arguments into a set
+ * of options and values.
  *
- * ## Installing ##
+ * This library supports [GNU][] and [POSIX][] style options, and it works
+ * in both server-side and client-side apps.
  *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- *     dependencies:
- *       args: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
+ * For information on installing this library, see the
  * [args package on pub.dartlang.org](http://pub.dartlang.org/packages/args).
+ * Here's an example of importing this library:
  *
- * ## Defining options ##
+ *     import 'package:args/args.dart';
  *
- * To use this library, you create an [ArgParser] object which will contain
- * the set of options you support:
+ * ## Defining options
+ *
+ * To use this library, first create an [ArgParser]:
  *
  *     var parser = new ArgParser();
  *
- * Then you define a set of options on that parser using [addOption()] and
- * [addFlag()]. The minimal way to create an option is:
+ * Then define a set of options on that parser using [addOption()] and
+ * [addFlag()]. Here's the minimal way to create an option named "name":
  *
  *     parser.addOption('name');
  *
- * This creates an option named "name". Options must be given a value on the
- * command line. If you have a simple on/off flag, you can instead use:
+ * When an option can only be set or unset (as opposed to taking a string
+ * value), use a flag:
  *
  *     parser.addFlag('name');
  *
- * Flag options will, by default, accept a 'no-' prefix to negate the option.
- * This can be disabled like so:
+ * Flag options, by default, accept a 'no-' prefix to negate the option.
+ * You can disable the 'no-' prefix using the `negatable` parameter:
  *
  *     parser.addFlag('name', negatable: false);
  *
- * (From here on out "option" will refer to both "regular" options and flags.
- * In cases where the distinction matters, we'll use "non-flag option".)
+ * **Terminology note:**
+ * From here on out, the term _option_ refers to both regular options and
+ * flags. In cases where the distinction matters, this documentation uses
+ * the term _non-flag option._
  *
- * Options may have an optional single-character abbreviation:
+ * Options can have an optional single-character abbreviation, specified
+ * with the `abbr` parameter:
  *
  *     parser.addOption('mode', abbr: 'm');
  *     parser.addFlag('verbose', abbr: 'v');
  *
- * They may also specify a default value. The default value will be used if the
- * option isn't provided:
+ * Options can also have a default value, specified with the `defaultsTo`
+ * parameter. The default value is used when arguments don't specify the
+ * option.
  *
  *     parser.addOption('mode', defaultsTo: 'debug');
  *     parser.addFlag('verbose', defaultsTo: false);
  *
- * The default value for non-flag options can be any [String]. For flags, it
- * must be a [bool].
+ * The default value for non-flag options can be any [String]. For flags,
+ * it must be a [bool].
  *
- * To validate non-flag options, you may provide an allowed set of values. When
- * you do, it will throw a [FormatException] when you parse the arguments if
- * the value for an option is not in the allowed set:
+ * To validate a non-flag option, you can use the `allowed` parameter to
+ * provide an allowed set of values. When you do, the parser throws a
+ * [FormatException] if the value for an option is not in the allowed set.
+ * Here's an example of specifying allowed values:
  *
  *     parser.addOption('mode', allowed: ['debug', 'release']);
  *
- * You can provide a callback when you define an option. When you later parse
- * a set of arguments, the callback for that option will be invoked with the
- * value provided for it:
+ * You can use the `callback` parameter to associate a function with an
+ * option. Later, when parsing occurs, the callback function is invoked
+ * with the value of the option:
  *
  *     parser.addOption('mode', callback: (mode) => print('Got mode $mode));
  *     parser.addFlag('verbose', callback: (verbose) {
  *       if (verbose) print('Verbose');
  *     });
  *
- * The callback for each option will *always* be called when you parse a set of
- * arguments. If the option isn't provided in the args, the callback will be
- * passed the default value, or `null` if there is none set.
+ * The callbacks for all options are called whenever a set of arguments
+ * is parsed. If an option isn't provided in the args, its callback is
+ * passed the default value, or `null` if no default value is set.
  *
- * ## Parsing arguments ##
+ * ## Parsing arguments
  *
- * Once you have an [ArgParser] set up with some options and flags, you use it
- * by calling [ArgParser.parse()] with a set of arguments:
+ * Once you have an [ArgParser] set up with some options and flags, you
+ * use it by calling [ArgParser.parse()] with a set of arguments:
  *
  *     var results = parser.parse(['some', 'command', 'line', 'args']);
  *
- * These will usually come from `new Options().arguments`, but you can pass in
- * any list of strings. It returns an instance of [ArgResults]. This is a
- * map-like object that will return the value of any parsed option.
+ * These arguments usually come from dart:io's Options class
+ * (`new Options().arguments`), but you can pass in any list of strings.
+ * The parse() method returns an instance of [ArgResults], a map-like
+ * object that contains the values of the parsed options.
  *
  *     var parser = new ArgParser();
  *     parser.addOption('mode');
  *     parser.addFlag('verbose', defaultsTo: true);
- *     var results = parser.parse('['--mode', 'debug', 'something', 'else']);
+ *     var results = parser.parse(['--mode', 'debug', 'something', 'else']);
  *
  *     print(results['mode']); // debug
  *     print(results['verbose']); // true
  *
- * The [parse()] method will stop as soon as it reaches `--` or anything that
- * it doesn't recognize as an option, flag, or option value. If there are still
- * arguments left, they will be provided to you in
- * [ArgResults.rest].
+ * By default, the parse() method stops as soon as it reaches `--` by itself
+ * or anything that the parser doesn't recognize as an option, flag, or
+ * option value. If arguments still remain, they go into [ArgResults.rest].
  *
  *     print(results.rest); // ['something', 'else']
  *
- * ## Specifying options ##
+ * To continue to parse options found after non-option arguments, call
+ * parse() with `allowTrailingOptions: true`.
  *
- * To actually pass in options and flags on the command line, use GNU or POSIX
- * style. If you define an option like:
+ * ## Specifying options
+ *
+ * To actually pass in options and flags on the command line, use GNU or
+ * POSIX style. Consider this option:
  *
  *     parser.addOption('name', abbr: 'n');
  *
- * Then a value for it can be specified on the command line using any of:
+ * You can specify its value on the command line using any of the following:
  *
  *     --name=somevalue
  *     --name somevalue
  *     -nsomevalue
  *     -n somevalue
  *
- * Given this flag:
+ * Consider this flag:
  *
  *     parser.addFlag('name', abbr: 'n');
  *
- * You can set it on using one of:
+ * You can set it to true using one of the following:
  *
  *     --name
  *     -n
  *
- * Or set it off using:
+ * You can set it to false using the following:
  *
  *     --no-name
  *
- * Multiple flag abbreviation can also be collapsed into a single argument. If
- * you define:
+ * Multiple flag abbreviations can be collapsed into a single argument. Say
+ * you define these flags:
  *
  *     parser.addFlag('verbose', abbr: 'v');
  *     parser.addFlag('french', abbr: 'f');
  *     parser.addFlag('iambic-pentameter', abbr: 'i');
  *
- * Then all three flags could be set using:
+ * You can set all three flags at once:
  *
  *     -vfi
  *
@@ -149,9 +152,9 @@
  *     var results = parser.parse(['--mode', 'on', '--mode', 'off']);
  *     print(results['mode']); // prints 'off'
  *
- * If you need multiple values, set the [allowMultiple] flag. In that
- * case the option can occur multiple times and when parsing arguments a
- * List of values will be returned:
+ * If you need multiple values, set the `allowMultiple` parameter. In that
+ * case the option can occur multiple times, and the parse() method returns
+ * a list of values:
  *
  *     var parser = new ArgParser();
  *     parser.addOption('mode', allowMultiple: true);
@@ -160,68 +163,73 @@
  *
  * ## Defining commands ##
  *
- * In addition to *options*, you can also define *commands*. A command is a
- * named argument that has its own set of options. For example, when you run:
+ * In addition to *options*, you can also define *commands*. A command is
+ * a named argument that has its own set of options. For example, consider
+ * this shell command:
  *
  *     $ git commit -a
  *
- * The executable is `git`, the command is `commit`, and the `-a` option is an
- * option passed to the command. You can add a command like so:
+ * The executable is `git`, the command is `commit`, and the `-a` option is
+ * an option passed to the command. You can add a command using the
+ * [addCommand] method:
  *
  *     var parser = new ArgParser();
  *     var command = parser.addCommand('commit');
  *
- * It returns another [ArgParser] which you can then use to define options
- * specific to that command. If you already have an [ArgParser] for the
- * command's options, you can pass it to [addCommand]:
+ * The addCommand() method returns another [ArgParser], which you can then
+ * use to define options specific to that command. If you already have an
+ * [ArgParser] for the command's options, you can pass it to addCommand:
  *
  *     var parser = new ArgParser();
  *     var command = new ArgParser();
  *     parser.addCommand('commit', command);
  *
- * The [ArgParser] for a command can then define whatever options or flags:
+ * The [ArgParser] for a command can then define options or flags:
  *
  *     command.addFlag('all', abbr: 'a');
  *
  * You can add multiple commands to the same parser so that a user can select
- * one from a range of possible commands. When an argument list is parsed,
+ * one from a range of possible commands. When parsing an argument list,
  * you can then determine which command was entered and what options were
  * provided for it.
  *
  *     var results = parser.parse(['commit', '-a']);
- *     print(results.command.name); // "commit"
- *     print(results.command['a']); // true
+ *     print(results.command.name);   // "commit"
+ *     print(results.command['all']); // true
  *
  * Options for a command must appear after the command in the argument list.
  * For example, given the above parser, "git -a commit" is *not* valid. The
- * parser will try to find the right-most command that accepts an option. For
+ * parser tries to find the right-most command that accepts an option. For
  * example:
  *
  *     var parser = new ArgParser();
  *     parser.addFlag('all', abbr: 'a');
- *     var command = new ArgParser().addCommand('commit');
- *     parser.addFlag('all', abbr: 'a');
+ *     var command = parser.addCommand('commit');
+ *     command.addFlag('all', abbr: 'a');
+ *
  *     var results = parser.parse(['commit', '-a']);
- *     print(results.command['a']); // true
+ *     print(results.command['all']); // true
  *
- * Here, both the top-level parser and the "commit" command can accept a "-a"
- * (which is probably a bad command line interface, admittedly). In that case,
- * when "-a" appears after "commit", it will be applied to that command. If it
- * appears to the left of "commit", it will be given to the top-level parser.
+ * Here, both the top-level parser and the "commit" command can accept a
+ * "-a" (which is probably a bad command line interface, admittedly). In
+ * that case, when "-a" appears after "commit", it is applied to that
+ * command. If it appears to the left of "commit", it is given to the
+ * top-level parser.
  *
- * ## Displaying usage ##
+ * ## Displaying usage
  *
- * This library can also be used to automatically generate nice usage help
- * text like you get when you run a program with `--help`. To use this, you
- * will also want to provide some help text when you create your options. To
- * define help text for the entire option, do:
+ * You can automatically generate nice help text, suitable for use as the
+ * output of `--help`. To display good usage information, you should
+ * provide some help text when you create your options.
+ *
+ * To define help text for an entire option, use the `help` parameter:
  *
  *     parser.addOption('mode', help: 'The compiler configuration',
  *         allowed: ['debug', 'release']);
  *     parser.addFlag('verbose', help: 'Show additional diagnostic info');
  *
  * For non-flag options, you can also provide detailed help for each expected
- * value using a map:
+ * value by using the `allowedHelp` parameter:
  *
  *     parser.addOption('arch', help: 'The architecture to compile for',
  *         allowedHelp: {
@@ -229,11 +237,11 @@
  *           'arm': 'ARM Holding 32-bit chip'
  *         });
  *
- * If you define a set of options like the above, then calling this:
+ * To display the help, use the ArgParser getUsage() method:
  *
  *     print(parser.getUsage());
- *
- * Will display something like:
+ * 
+ * The resulting string looks something like this:
  *
  *     --mode            The compiler configuration
  *                       [debug, release]
@@ -244,14 +252,12 @@
  *           [arm]       ARM Holding 32-bit chip
  *           [ia32]      Intel x86
  *
- * To assist the formatting of the usage help, single line help text will
- * be followed by a single new line. Options with multi-line help text
- * will be followed by two new lines. This provides spatial diversity between
- * options.
+ * To assist the formatting of the usage help, single-line help text is
+ * followed by a single new line. Options with multi-line help text are
+ * followed by two new lines. This provides spatial diversity between options.
  *
  * [posix]: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02
  * [gnu]: http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces
- * [pub]: http://pub.dartlang.org
  */
 library args;
 
diff --git a/pkg/async_helper/lib/async_helper.dart b/pkg/async_helper/lib/async_helper.dart
index 84df557..808e198 100644
--- a/pkg/async_helper/lib/async_helper.dart
+++ b/pkg/async_helper/lib/async_helper.dart
@@ -8,13 +8,18 @@
 /// finished] even if the asynchronous operations fail).
 /// Tests which can't use the unittest framework should use the helper functions
 /// in this library.
-/// This library provides two methods
+/// This library provides four methods
 ///  - asyncStart(): Needs to be called before an asynchronous operation is
 ///                  scheduled.
 ///  - asyncEnd(): Needs to be called as soon as the asynchronous operation
 ///                ended.
+///  - asyncSuccess(_): Variant of asyncEnd useful together with Future.then.
+///  - asyncTest(f()): Helper method that wraps a computation that returns a
+///                    Future with matching calls to asyncStart() and
+///                    asyncSuccess(_).
 /// After the last asyncStart() called was matched with a corresponding
-/// asyncEnd() call, the testing driver will be notified that the tests is done.
+/// asyncEnd() or asyncSuccess(_) call, the testing driver will be notified that
+/// the tests is done.
 
 library async_helper;
 
@@ -32,6 +37,7 @@
   return new Exception('Fatal: $msg. This is most likely a bug in your test.');
 }
 
+/// Call this method before an asynchronous test is created.
 void asyncStart() {
   if (_initialized && _asyncLevel == 0) {
     throw _buildException('asyncStart() was called even though we are done '
@@ -45,6 +51,7 @@
   _asyncLevel++;
 }
 
+/// Call this after an asynchronous test has ended successfully.
 void asyncEnd() {
   if (_asyncLevel <= 0) {
     if (!_initialized) {
@@ -62,7 +69,26 @@
   }
 }
 
+/**
+ * Call this after an asynchronous test has ended successfully. This is a helper
+ * for calling [asyncEnd].
+ *
+ * This method intentionally has a signature that matches [:Future.then:] as a
+ * convenience for calling [asyncEnd] when a [:Future:] completes without error,
+ * like this:
+ *
+ *     asyncStart();
+ *     Future result = test();
+ *     result.then(asyncSuccess);
+ */
+void asyncSuccess(_) => asyncEnd();
+
+/**
+ * Helper method for performing asynchronous tests involving [:Future:].
+ *
+ * [f] must return a [:Future:] for the test computation.
+ */
 void asyncTest(f()) {
   asyncStart();
-  f().whenComplete(() => asyncEnd());
+  f().then(asyncSuccess);
 }
\ No newline at end of file
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index 37816bc..95f498e 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -83,7 +83,7 @@
 ///
 /// This returns a map whose keys are the return values of [fn] and whose values
 /// are lists of each element in [iter] for which [fn] returned that key.
-Map groupBy(Iterable iter, fn(element)) {
+Map<Object, List> groupBy(Iterable iter, fn(element)) {
   var map = {};
   for (var element in iter) {
     var list = map.putIfAbsent(fn(element), () => []);
diff --git a/pkg/csslib/lib/parser.dart b/pkg/csslib/lib/parser.dart
index a1cd715..9f7b3ff 100644
--- a/pkg/csslib/lib/parser.dart
+++ b/pkg/csslib/lib/parser.dart
@@ -13,6 +13,7 @@
 import 'src/options.dart';
 
 part 'src/analyzer.dart';
+part 'src/polyfill.dart';
 part 'src/property.dart';
 part 'src/token.dart';
 part 'src/tokenizer_base.dart';
@@ -44,7 +45,8 @@
 
 // TODO(terry): Remove nested name parameter.
 /** Parse and analyze the CSS file. */
-StyleSheet compile(var input, {List errors, List options, bool nested: true}) {
+StyleSheet compile(var input,
+    {List errors, List options, bool nested: true, bool polyfill: false}) {
   var source = _inputAsString(input);
 
   _createMessages(errors: errors, options: options);
@@ -55,6 +57,11 @@
 
   analyze([tree], errors: errors, options: options);
 
+  if (polyfill) {
+    var processCss = new PolyFill(messages, true);
+    processCss.process(tree);
+  }
+
   return tree;
 }
 
diff --git a/pkg/csslib/lib/src/polyfill.dart b/pkg/csslib/lib/src/polyfill.dart
new file mode 100644
index 0000000..ab56771
--- /dev/null
+++ b/pkg/csslib/lib/src/polyfill.dart
@@ -0,0 +1,246 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of csslib.parser;
+
+/**
+ * CSS polyfill emits CSS to be understood by older parsers that which do not
+ * understand (var, calc, etc.).
+ */
+class PolyFill {
+  final Messages _messages;
+  final bool _warningsAsErrors;
+
+  Set<StyleSheet> allStyleSheets = new Set<StyleSheet>();
+
+  /**
+   * [_pseudoElements] list of known pseudo attributes found in HTML, any
+   * CSS pseudo-elements 'name::custom-element' is mapped to the manged name
+   * associated with the pseudo-element key.
+   */
+  PolyFill(this._messages, this._warningsAsErrors);
+
+  /**
+   * Run the analyzer on every file that is a style sheet or any component that
+   * has a style tag.
+   */
+  void process(StyleSheet stylesheet) {
+    // TODO(terry): Process all imported stylesheets.
+
+    var styleSheets = processVars([stylesheet]);
+    allStyleSheets.addAll(styleSheets);
+
+    normalize();
+  }
+
+  void normalize() {
+    // Remove all var definitions for all style sheets analyzed.
+    for (var tree in allStyleSheets)
+      new _RemoveVarDefinitions().visitTree(tree);
+  }
+
+  List<StyleSheet> processVars(List<StyleSheet> styleSheets) {
+    // TODO(terry): Process all dependencies.
+    // Build list of all var definitions.
+    Map varDefs = new Map();
+    for (var tree in styleSheets) {
+      var allDefs = (new _VarDefinitions()..visitTree(tree)).found;
+      allDefs.forEach((key, value) {
+        varDefs[key] = value;
+      });
+    }
+
+    // Resolve all definitions to a non-VarUsage (terminal expression).
+    varDefs.forEach((key, value) {
+      for (var expr in (value.expression as Expressions).expressions) {
+        var def = _findTerminalVarDefinition(varDefs, value);
+        varDefs[key] = def;
+      }
+    });
+
+    // Resolve all var usages.
+    for (var tree in styleSheets) {
+      new _ResolveVarUsages(varDefs).visitTree(tree);
+    }
+
+    return styleSheets;
+  }
+}
+
+/**
+ * Find var- definitions in a style sheet.
+ * [found] list of known definitions.
+ */
+class _VarDefinitions extends Visitor {
+  final Map<String, VarDefinition> found = new Map();
+
+  void visitTree(StyleSheet tree) {
+    visitStyleSheet(tree);
+  }
+
+  visitVarDefinition(VarDefinition node) {
+    // Replace with latest variable definition.
+    found[node.definedName] = node;
+    super.visitVarDefinition(node);
+  }
+
+  void visitVarDefinitionDirective(VarDefinitionDirective node) {
+    visitVarDefinition(node.def);
+  }
+}
+
+/**
+ * Resolve any CSS expression which contains a var() usage to the ultimate real
+ * CSS expression value e.g.,
+ *
+ *    var-one: var(two);
+ *    var-two: #ff00ff;
+ *
+ *    .test {
+ *      color: var(one);
+ *    }
+ *
+ * then .test's color would be #ff00ff
+ */
+class _ResolveVarUsages extends Visitor {
+  final Map<String, VarDefinition> varDefs;
+  bool inVarDefinition = false;
+  bool inUsage = false;
+  Expressions currentExpressions;
+
+  _ResolveVarUsages(this.varDefs);
+
+  void visitTree(StyleSheet tree) {
+    visitStyleSheet(tree);
+  }
+
+  void visitVarDefinition(VarDefinition varDef) {
+    inVarDefinition = true;
+    super.visitVarDefinition(varDef);
+    inVarDefinition = false;
+  }
+
+  void visitExpressions(Expressions node) {
+    currentExpressions = node;
+    super.visitExpressions(node);
+    currentExpressions = null;
+  }
+
+  void visitVarUsage(VarUsage node) {
+    // Don't process other var() inside of a varUsage.  That implies that the
+    // default is a var() too.  Also, don't process any var() inside of a
+    // varDefinition (they're just place holders until we've resolved all real
+    // usages.
+    if (!inUsage && !inVarDefinition && currentExpressions != null) {
+      var expressions = currentExpressions.expressions;
+      var index = expressions.indexOf(node);
+      assert(index >= 0);
+      var def = varDefs[node.name];
+      if (def != null) {
+        // Found a VarDefinition use it.
+        _resolveVarUsage(currentExpressions.expressions, index, def);
+      } else if (node.defaultValues.any((e) => e is VarUsage)) {
+        // Don't have a VarDefinition need to use default values resolve all
+        // default values.
+        var terminalDefaults = [];
+        for (var defaultValue in node.defaultValues) {
+          terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
+        }
+        expressions.replaceRange(index, index + 1, terminalDefaults);
+      } else {
+        // No VarDefinition but default value is a terminal expression; use it.
+        expressions.replaceRange(index, index + 1, node.defaultValues);
+      }
+    }
+
+    inUsage = true;
+    super.visitVarUsage(node);
+    inUsage = false;
+  }
+
+  List<Expression> resolveUsageTerminal(VarUsage usage) {
+    var result = [];
+
+    var varDef = varDefs[usage.name];
+    var expressions;
+    if (varDef == null) {
+      // VarDefinition not found try the defaultValues.
+      expressions = usage.defaultValues;
+    } else {
+      // Use the VarDefinition found.
+      expressions = (varDef.expression as Expressions).expressions;
+    }
+
+    for (var expr in expressions) {
+      if (expr is VarUsage) {
+        // Get terminal value.
+        result.addAll(resolveUsageTerminal(expr));
+      }
+    }
+
+    // We're at a terminal just return the VarDefinition expression.
+    if (result.isEmpty && varDef != null) {
+      result = (varDef.expression as Expressions).expressions;
+    }
+
+    return result;
+  }
+
+  _resolveVarUsage(List<Expressions> expressions, int index,
+                   VarDefinition def) {
+    var defExpressions = (def.expression as Expressions).expressions;
+    expressions.replaceRange(index, index + 1, defExpressions);
+  }
+}
+
+/** Remove all var definitions. */
+class _RemoveVarDefinitions extends Visitor {
+  void visitTree(StyleSheet tree) {
+    visitStyleSheet(tree);
+  }
+
+  void visitStyleSheet(StyleSheet ss) {
+    ss.topLevels.removeWhere((e) => e is VarDefinitionDirective);
+    super.visitStyleSheet(ss);
+  }
+
+  void visitDeclarationGroup(DeclarationGroup node) {
+    node.declarations.removeWhere((e) => e is VarDefinition);
+    super.visitDeclarationGroup(node);
+  }
+}
+
+/** Find terminal definition (non VarUsage implies real CSS value). */
+VarDefinition _findTerminalVarDefinition(Map<String, VarDefinition> varDefs,
+    VarDefinition varDef) {
+  var expressions = varDef.expression as Expressions;
+  for (var expr in expressions.expressions) {
+    if (expr is VarUsage) {
+      var usageName = (expr as VarUsage).name;
+      var foundDef = varDefs[usageName];
+
+      // If foundDef is unknown check if defaultValues; if it exist then resolve
+      // to terminal value.
+      if (foundDef == null) {
+        // We're either a VarUsage or terminal definition if in varDefs;
+        // either way replace VarUsage with it's default value because the
+        // VarDefinition isn't found.
+        var defaultValues = (expr as VarUsage).defaultValues;
+        var replaceExprs = expressions.expressions;
+        assert(replaceExprs.length == 1);
+        replaceExprs.replaceRange(0, 1, defaultValues);
+        return varDef;
+      }
+      if (foundDef is VarDefinition) {
+        return _findTerminalVarDefinition(varDefs, foundDef);
+      }
+    } else {
+      // Return real CSS property.
+      return varDef;
+    }
+  }
+
+  // Didn't point to a var definition that existed.
+  return varDef;
+}
diff --git a/pkg/csslib/test/testing.dart b/pkg/csslib/test/testing.dart
index e7b14bd..f2e1273 100644
--- a/pkg/csslib/test/testing.dart
+++ b/pkg/csslib/test/testing.dart
@@ -27,9 +27,11 @@
  * CSS will allow any property/value pairs regardless of validity; all of our
  * tests (by default) will ensure that the CSS is really valid.
  */
-StyleSheet compileCss(String cssInput, {List errors, List opts}) =>
+StyleSheet compileCss(String cssInput,
+    {List errors, List opts, bool polyfill: false}) =>
   compile(cssInput, errors: errors, options: opts == null ?
-      ['--no-colors', '--checked', '--warnings_as_errors', 'memory'] : opts);
+      ['--no-colors', '--checked', '--warnings_as_errors', 'memory'] : opts,
+      polyfill: polyfill);
 
 /** CSS emitter walks the style sheet tree and emits readable CSS. */
 var _emitCss = new CssPrinter();
diff --git a/pkg/csslib/test/var_test.dart b/pkg/csslib/test/var_test.dart
index afdc570..11e94be 100644
--- a/pkg/csslib/test/var_test.dart
+++ b/pkg/csslib/test/var_test.dart
@@ -623,6 +623,31 @@
   expect(prettyPrint(stylesheet), generated2);
 }
 
+void polyfill() {
+  var errors = [];
+  var input = r'''
+@color-background: red;
+@color-foreground: blue;
+.test {
+  background-color: @color-background;
+  color: @color-foreground;
+}''';
+
+  var generated = r'''.test {
+  background-color: #f00;
+  color: #00f;
+}''';
+
+  var stylesheet = compileCss(input, errors: errors,
+      opts: ['--no-colors', 'memory'], polyfill: true);
+
+  expect(stylesheet != null, true);
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(prettyPrint(stylesheet), generated);
+}
+
+
+
 main() {
   test('Simple var', simpleVar);
   test('Expressions var', expressionsVar);
@@ -631,4 +656,5 @@
   test('Var syntax', testVar);
   test('Cycles var', cyclesVar);
   test('Less syntax', testLess);
+  test('Polyfill', polyfill);
 }
diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
index 400730b..be0a360 100644
--- a/pkg/custom_element/lib/custom-elements.debug.js
+++ b/pkg/custom_element/lib/custom-elements.debug.js
@@ -1045,23 +1045,23 @@
    *
    * When a registered element is created, a `readyCallback` method is called
    * in the scope of the element. The `readyCallback` method can be specified on
-   * either `inOptions.prototype` or `inOptions.lifecycle` with the latter taking
+   * either `options.prototype` or `options.lifecycle` with the latter taking
    * precedence.
    *
    * @method register
-   * @param {String} inName The tag name to register. Must include a dash ('-'),
+   * @param {String} name The tag name to register. Must include a dash ('-'),
    *    for example 'x-component'.
-   * @param {Object} inOptions
-   *    @param {String} [inOptions.extends]
+   * @param {Object} options
+   *    @param {String} [options.extends]
    *      (_off spec_) Tag name of an element to extend (or blank for a new
    *      element). This parameter is not part of the specification, but instead
    *      is a hint for the polyfill because the extendee is difficult to infer.
    *      Remember that the input prototype must chain to the extended element's
    *      prototype (or HTMLElement.prototype) regardless of the value of
    *      `extends`.
-   *    @param {Object} inOptions.prototype The prototype to use for the new
+   *    @param {Object} options.prototype The prototype to use for the new
    *      element. The prototype must inherit from HTMLElement.
-   *    @param {Object} [inOptions.lifecycle]
+   *    @param {Object} [options.lifecycle]
    *      Callbacks that fire at important phases in the life of the custom
    *      element.
    *
@@ -1078,18 +1078,23 @@
    *      });
    * @return {Function} Constructor for the newly registered type.
    */
-  function register(inName, inOptions) {
-    //console.warn('document.register("' + inName + '", ', inOptions, ')');
+  function register(name, options) {
+    //console.warn('document.register("' + name + '", ', options, ')');
     // construct a defintion out of options
-    // TODO(sjmiles): probably should clone inOptions instead of mutating it
-    var definition = inOptions || {};
-    if (!inName) {
+    // TODO(sjmiles): probably should clone options instead of mutating it
+    var definition = options || {};
+    if (!name) {
       // TODO(sjmiles): replace with more appropriate error (EricB can probably
       // offer guidance)
-      throw new Error('Name argument must not be empty');
+      throw new Error('document.register: first argument `name` must not be empty');
+    }
+    if (name.indexOf('-') < 0) {
+      // TODO(sjmiles): replace with more appropriate error (EricB can probably
+      // offer guidance)
+      throw new Error('document.register: first argument `name` must contain a dash (\'-\'). Argument was \'' + String(name) + '\'.');
     }
     // record name
-    definition.name = inName;
+    definition.name = name;
     // must have a prototype, default to an extension of HTMLElement
     // TODO(sjmiles): probably should throw if no prototype, check spec
     if (!definition.prototype) {
@@ -1112,7 +1117,7 @@
     // overrides to implement attributeChanged callback
     overrideAttributeApi(definition.prototype);
     // 7.1.5: Register the DEFINITION with DOCUMENT
-    registerDefinition(inName, definition);
+    registerDefinition(name, definition);
     // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
     // 7.1.8. Return the output of the previous step.
     definition.ctor = generateConstructor(definition);
@@ -1127,40 +1132,40 @@
     return definition.ctor;
   }
 
-  function ancestry(inExtends) {
-    var extendee = registry[inExtends];
+  function ancestry(extnds) {
+    var extendee = registry[extnds];
     if (extendee) {
       return ancestry(extendee.extends).concat([extendee]);
     }
     return [];
   }
 
-  function resolveTagName(inDefinition) {
+  function resolveTagName(definition) {
     // if we are explicitly extending something, that thing is our
     // baseTag, unless it represents a custom component
-    var baseTag = inDefinition.extends;
+    var baseTag = definition.extends;
     // if our ancestry includes custom components, we only have a
     // baseTag if one of them does
-    for (var i=0, a; (a=inDefinition.ancestry[i]); i++) {
+    for (var i=0, a; (a=definition.ancestry[i]); i++) {
       baseTag = a.is && a.tag;
     }
     // our tag is our baseTag, if it exists, and otherwise just our name
-    inDefinition.tag = baseTag || inDefinition.name;
+    definition.tag = baseTag || definition.name;
     if (baseTag) {
       // if there is a base tag, use secondary 'is' specifier
-      inDefinition.is = inDefinition.name;
+      definition.is = definition.name;
     }
   }
 
-  function resolvePrototypeChain(inDefinition) {
+  function resolvePrototypeChain(definition) {
     // if we don't support __proto__ we need to locate the native level
     // prototype for precise mixing in
     if (!Object.__proto__) {
       // default prototype
       var native = HTMLElement.prototype;
       // work out prototype when using type-extension
-      if (inDefinition.is) {
-        var inst = document.createElement(inDefinition.tag);
+      if (definition.is) {
+        var inst = document.createElement(definition.tag);
         native = Object.getPrototypeOf(inst);
       }
       // ensure __proto__ reference is installed at each point on the prototype
@@ -1168,7 +1173,7 @@
       // NOTE: On platforms without __proto__, a mixin strategy is used instead
       // of prototype swizzling. In this case, this generated __proto__ provides
       // limited support for prototype traversal.
-      var proto = inDefinition.prototype, ancestor;
+      var proto = definition.prototype, ancestor;
       while (proto && (proto !== native)) {
         var ancestor = Object.getPrototypeOf(proto);
         proto.__proto__ = ancestor;
@@ -1176,49 +1181,49 @@
       }
     }
     // cache this in case of mixin
-    inDefinition.native = native;
+    definition.native = native;
   }
 
   // SECTION 4
 
-  function instantiate(inDefinition) {
+  function instantiate(definition) {
     // 4.a.1. Create a new object that implements PROTOTYPE
     // 4.a.2. Let ELEMENT by this new object
     //
     // the custom element instantiation algorithm must also ensure that the
     // output is a valid DOM element with the proper wrapper in place.
     //
-    return upgrade(domCreateElement(inDefinition.tag), inDefinition);
+    return upgrade(domCreateElement(definition.tag), definition);
   }
 
-  function upgrade(inElement, inDefinition) {
+  function upgrade(element, definition) {
     // some definitions specify an 'is' attribute
-    if (inDefinition.is) {
-      inElement.setAttribute('is', inDefinition.is);
+    if (definition.is) {
+      element.setAttribute('is', definition.is);
     }
-    // make 'element' implement inDefinition.prototype
-    implement(inElement, inDefinition);
+    // make 'element' implement definition.prototype
+    implement(element, definition);
     // flag as upgraded
-    inElement.__upgraded__ = true;
-    // there should never be a shadow root on inElement at this point
+    element.__upgraded__ = true;
+    // there should never be a shadow root on element at this point
     // we require child nodes be upgraded before `created`
-    scope.upgradeSubtree(inElement);
+    scope.upgradeSubtree(element);
     // lifecycle management
-    created(inElement);
+    created(element);
     // OUTPUT
-    return inElement;
+    return element;
   }
 
-  function implement(inElement, inDefinition) {
+  function implement(element, definition) {
     // prototype swizzling is best
     if (Object.__proto__) {
-      inElement.__proto__ = inDefinition.prototype;
+      element.__proto__ = definition.prototype;
     } else {
       // where above we can re-acquire inPrototype via
       // getPrototypeOf(Element), we cannot do so when
       // we use mixin, so we install a magic reference
-      customMixin(inElement, inDefinition.prototype, inDefinition.native);
-      inElement.__proto__ = inDefinition.prototype;
+      customMixin(element, definition.prototype, definition.native);
+      element.__proto__ = definition.prototype;
     }
   }
 
@@ -1246,10 +1251,10 @@
     }
   }
 
-  function created(inElement) {
+  function created(element) {
     // invoke createdCallback
-    if (inElement.createdCallback) {
-      inElement.createdCallback();
+    if (element.createdCallback) {
+      element.createdCallback();
     }
   }
 
@@ -1282,34 +1287,55 @@
 
   var registry = {};
 
-  function registerDefinition(inName, inDefinition) {
-    if (registry[inName]) {
-      throw new Error('Cannot register a tag more than once');
+  function registerDefinition(name, definition) {
+    if (registry[name]) {
+      throw new Error('a type with that name is already registered.');
     }
-    registry[inName] = inDefinition;
+    registry[name] = definition;
   }
 
-  function generateConstructor(inDefinition) {
+  function generateConstructor(definition) {
     return function() {
-      return instantiate(inDefinition);
+      return instantiate(definition);
     };
   }
 
   function createElement(tag, typeExtension) {
-    // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
-    // error check it, or perhaps there should only ever be one argument
     var definition = registry[typeExtension || tag];
     if (definition) {
-      return new definition.ctor();
+      if (tag == definition.tag && typeExtension == definition.is) {
+        return new definition.ctor();
+      }
+      // Handle empty string for type extension.
+      if (!typeExtension && !definition.is) {
+        return new definition.ctor();
+      }
     }
-    return domCreateElement(tag);
+
+    if (typeExtension) {
+      var element = createElement(tag);
+      element.setAttribute('is', typeExtension);
+      return element;
+    }
+    var element = domCreateElement(tag);
+    // Custom tags should be HTMLElements even if not upgraded.
+    if (tag.indexOf('-') >= 0) {
+      implement(element, HTMLElement);
+    }
+    return element;
   }
 
-  function upgradeElement(inElement) {
-    if (!inElement.__upgraded__ && (inElement.nodeType === Node.ELEMENT_NODE)) {
-      var type = inElement.getAttribute('is') || inElement.localName;
-      var definition = registry[type];
-      return definition && upgrade(inElement, definition);
+  function upgradeElement(element) {
+    if (!element.__upgraded__ && (element.nodeType === Node.ELEMENT_NODE)) {
+      var is = element.getAttribute('is');
+      var definition = registry[is || element.localName];
+      if (definition) {
+        if (is && definition.tag == element.localName) {
+          return upgrade(element, definition);
+        } else if (!is && !definition.extends) {
+          return upgrade(element, definition);
+        }
+      }
     }
   }
 
@@ -1345,7 +1371,7 @@
    * if it matches no registered custom tag name.
    *
    * @method ugprade
-   * @param {Element} inElement The element to upgrade.
+   * @param {Element} element The element to upgrade.
    * @return {Element} The upgraded element.
    */
   scope.upgrade = upgradeElement;
diff --git a/pkg/custom_element/lib/custom-elements.min.js b/pkg/custom_element/lib/custom-elements.min.js
index f0c3e81..7f7c6e3 100644
--- a/pkg/custom_element/lib/custom-elements.min.js
+++ b/pkg/custom_element/lib/custom-elements.min.js
@@ -25,4 +25,4 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-window.CustomElements={flags:{}};var SideTable;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new SideTable,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g}(this),!window.MutationObserver&&(window.MutationObserver=window.WebKitMutationObserver||window.JsMutationObserver,!MutationObserver))throw new Error("no mutation observer support");!function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.webkitShadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(j(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return logFlags.dom&&console.group("upgrade:",b.localName),a.upgrade(b),logFlags.dom&&console.groupEnd(),!0}}function i(a){j(a),m(a)&&d(a,function(a){j(a)})}function j(a){(a.enteredDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.group("inserted:",a.localName),m(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?logFlags.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredDocumentCallback&&(logFlags.dom&&console.log("inserted:",a.localName),a.enteredDocumentCallback())),logFlags.dom&&console.groupEnd())}function k(a){l(a),d(a,function(a){l(a)})}function l(a){(a.leftDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.log("removed:",a.localName),m(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?logFlags.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftDocumentCallback&&a.leftDocumentCallback()))}function m(a){for(var b=a;b;){if(b==a.ownerDocument)return!0;b=b.parentNode||b.host}}function n(a){if(a.webkitShadowRoot&&!a.webkitShadowRoot.__watched){logFlags.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.webkitShadowRoot;b;)o(b),b=b.olderShadowRoot}}function o(a){a.__watched||(t(a),a.__watched=!0)}function p(a){n(a),d(a,function(){n(a)})}function q(a){switch(a.localName){case"style":case"script":case"template":case void 0:return!0}}function r(a){if(logFlags.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(x(a.addedNodes,function(a){q(a)||g(a)}),x(a.removedNodes,function(a){q(a)||k(a)}))}),logFlags.dom&&console.groupEnd()}function s(){r(w.takeRecords())}function t(a){w.observe(a,{childList:!0,subtree:!0})}function u(a){t(a)}function v(a){logFlags.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),logFlags.dom&&console.groupEnd()}var w=new MutationObserver(r),x=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=n,a.watchAllShadows=p,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=u,a.upgradeDocument=v,a.takeRecords=s}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("Name argument must not be empty");if(g.name=b,!g.prototype)throw new Error("Options missing required prototype property");return g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),m(b,g),g.ctor=n(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeAll(document),g.ctor}function c(a){var b=v[a];return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(w(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a,b){l.call(this,a,b,c)}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments),this.attributeChangedCallback&&this.getAttribute(a)!==d&&this.attributeChangedCallback(a,d)}function m(a,b){if(v[a])throw new Error("Cannot register a tag more than once");v[a]=b}function n(a){return function(){return f(a)}}function o(a,b){var c=v[b||a];return c?new c.ctor:w(a)}function p(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is")||a.localName,c=v[b];return c&&g(a,c)}}function q(b){var c=x.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var r=a.flags,s=Boolean(document.webkitRegister||document.register),t=!r.register&&s;if(t){document.register=document.register||document.webkitRegister;var u=function(){};a.registry={},a.upgradeElement=u,a.watchShadow=u,a.watchAllShadows=u,a.upgrade=u,a.upgradeAll=u,a.upgradeSubtree=u,a.observeDocument=u,a.upgradeDocument=u,a.takeRecords=u}else{var v={},w=document.createElement.bind(document),x=Node.prototype.cloneNode;document.register=b,document.createElement=o,Node.prototype.cloneNode=q,a.registry=v,a.upgrade=p}a.hasNative=s,a.useNative=t}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(){function a(){setTimeout(function(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))},0)}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState)a();else{var b=window.HTMLImports?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(b,a)}}();
+window.CustomElements={flags:{}};var SideTable;if("undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:function(){var a=Object.defineProperty,b=Object.hasOwnProperty,c=(new Date).getTime()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(c++ +"__")},SideTable.prototype={set:function(b,c){a(b,this.name,{value:c,writable:!0})},get:function(a){return b.call(a,this.name)?a[this.name]:void 0},"delete":function(a){this.set(a,void 0)}}}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new SideTable,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g}(this),!window.MutationObserver&&(window.MutationObserver=window.WebKitMutationObserver||window.JsMutationObserver,!MutationObserver))throw new Error("no mutation observer support");!function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.webkitShadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(j(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return logFlags.dom&&console.group("upgrade:",b.localName),a.upgrade(b),logFlags.dom&&console.groupEnd(),!0}}function i(a){j(a),m(a)&&d(a,function(a){j(a)})}function j(a){(a.enteredDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.group("inserted:",a.localName),m(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?logFlags.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredDocumentCallback&&(logFlags.dom&&console.log("inserted:",a.localName),a.enteredDocumentCallback())),logFlags.dom&&console.groupEnd())}function k(a){l(a),d(a,function(a){l(a)})}function l(a){(a.leftDocumentCallback||a.__upgraded__&&logFlags.dom)&&(logFlags.dom&&console.log("removed:",a.localName),m(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?logFlags.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftDocumentCallback&&a.leftDocumentCallback()))}function m(a){for(var b=a;b;){if(b==a.ownerDocument)return!0;b=b.parentNode||b.host}}function n(a){if(a.webkitShadowRoot&&!a.webkitShadowRoot.__watched){logFlags.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.webkitShadowRoot;b;)o(b),b=b.olderShadowRoot}}function o(a){a.__watched||(t(a),a.__watched=!0)}function p(a){n(a),d(a,function(){n(a)})}function q(a){switch(a.localName){case"style":case"script":case"template":case void 0:return!0}}function r(a){if(logFlags.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(x(a.addedNodes,function(a){q(a)||g(a)}),x(a.removedNodes,function(a){q(a)||k(a)}))}),logFlags.dom&&console.groupEnd()}function s(){r(w.takeRecords())}function t(a){w.observe(a,{childList:!0,subtree:!0})}function u(a){t(a)}function v(a){logFlags.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),logFlags.dom&&console.groupEnd()}var w=new MutationObserver(r),x=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=n,a.watchAllShadows=p,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=u,a.upgradeDocument=v,a.takeRecords=s}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.register: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.register: first argument `name` must contain a dash ('-'). Argument was '"+String(b)+"'.");if(g.name=b,!g.prototype)throw new Error("Options missing required prototype property");return g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),m(b,g),g.ctor=n(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,a.ready&&a.upgradeAll(document),g.ctor}function c(a){var b=v[a];return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(w(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a,b){l.call(this,a,b,c)}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments),this.attributeChangedCallback&&this.getAttribute(a)!==d&&this.attributeChangedCallback(a,d)}function m(a,b){if(v[a])throw new Error("a type with that name is already registered.");v[a]=b}function n(a){return function(){return f(a)}}function o(a,b){var c=v[b||a];if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=o(a);return d.setAttribute("is",b),d}var d=w(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function p(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=v[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function q(b){var c=x.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var r=a.flags,s=Boolean(document.webkitRegister||document.register),t=!r.register&&s;if(t){document.register=document.register||document.webkitRegister;var u=function(){};a.registry={},a.upgradeElement=u,a.watchShadow=u,a.watchAllShadows=u,a.upgrade=u,a.upgradeAll=u,a.upgradeSubtree=u,a.observeDocument=u,a.upgradeDocument=u,a.takeRecords=u}else{var v={},w=document.createElement.bind(document),x=Node.prototype.cloneNode;document.register=b,document.createElement=o,Node.prototype.cloneNode=q,a.registry=v,a.upgrade=p}a.hasNative=s,a.useNative=t}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(){function a(){setTimeout(function(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))},0)}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState)a();else{var b=window.HTMLImports?"HTMLImportsLoaded":"DOMContentLoaded";window.addEventListener(b,a)}}();
diff --git a/pkg/custom_element/test/custom_element_test.dart b/pkg/custom_element/test/custom_element_test.dart
index 341713a..3094518 100644
--- a/pkg/custom_element/test/custom_element_test.dart
+++ b/pkg/custom_element/test/custom_element_test.dart
@@ -13,16 +13,16 @@
 main() {
   useHtmlConfiguration();
 
-  // Load the MutationObserver polyfill.
-  HttpRequest.getString('/root_dart/pkg/mutation_observer/lib/'
-      'mutation_observer.js').then((code) {
-    document.head.children.add(new ScriptElement()..text = code);
-
-    customElementTests();
+  setUp(() {
+    // Load the MutationObserver polyfill if needed.
+    if (!MutationObserver.supported) {
+      var script = new ScriptElement()
+          ..src =  '/packages/mutation_observer/mutation_observer.js';
+      document.head.append(script);
+      return script.onLoad.first;
+    }
   });
-}
 
-customElementTests() {
   test('register creates the element and calls lifecycle methods', () {
     // Add element to the page.
     var element = new Element.html('<fancy-button>foo bar</fancy-button>',
diff --git a/pkg/docgen/bin/dartdoc.py b/pkg/docgen/bin/dartdoc.py
index 948a24a..15f0de1 100644
--- a/pkg/docgen/bin/dartdoc.py
+++ b/pkg/docgen/bin/dartdoc.py
@@ -54,7 +54,7 @@
     join(DIRECTORY, 'docgen.dart')]
   docgen.extend(options.options.split())
   ExecuteCommand(docgen)
-  ExecuteCommand(['git', 'clone', '-b', 'dev',
+  ExecuteCommand(['git', 'clone', '-b', 'master',
    'git://github.com/dart-lang/dartdoc-viewer.git'])
   ExecuteCommand(['mv', 'docs', 'dartdoc-viewer/client/local'])
   os.chdir('dartdoc-viewer/client/')
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index fdfa05b..28704dc 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -21,9 +21,9 @@
   for (var pair in queryList.split("&")) {
     var split = split1(pair, "=");
     if (split.isEmpty) continue;
-    var key = Uri.decodeQueryComponent(split[0], decode: encoding.decode);
+    var key = Uri.decodeQueryComponent(split[0], encoding: encoding);
     var value = Uri.decodeQueryComponent(split.length > 1 ? split[1] : "",
-        decode: encoding.decode);
+        encoding: encoding);
     map[key] = value;
   }
   return map;
diff --git a/pkg/http_server/lib/src/http_body_impl.dart b/pkg/http_server/lib/src/http_body_impl.dart
index b1186405..f3ffa9e 100644
--- a/pkg/http_server/lib/src/http_body_impl.dart
+++ b/pkg/http_server/lib/src/http_body_impl.dart
@@ -121,7 +121,7 @@
             return asText(ASCII)
                 .then((body) {
                   var map = Uri.splitQueryString(body.body,
-                      decode: (s) => defaultEncoding.decode(s));
+                      encoding: defaultEncoding);
                   var result = {};
                   for (var key in map.keys) {
                     result[key] = map[key];
diff --git a/pkg/intl/lib/bidi_formatter.dart b/pkg/intl/lib/bidi_formatter.dart
index 6ae3982..0e5bee6 100644
--- a/pkg/intl/lib/bidi_formatter.dart
+++ b/pkg/intl/lib/bidi_formatter.dart
@@ -85,7 +85,11 @@
    * Escapes HTML-special characters of [text] so that the result can be
    * included verbatim in HTML source code, either in an element body or in an
    * attribute value.
+   *
+   * *htmlEscape* is deprecated. Use [HtmlEscape] from the `dart:convert`
+   * package. *htmlEscape* will be removed the 30th of September 2013.
    */
+  // TODO(kevmoo) Remove this!
   @deprecated
   String htmlEscape(String text) => HTML_ESCAPE.convert(text);
 
diff --git a/pkg/intl/lib/extract_messages.dart b/pkg/intl/lib/extract_messages.dart
index 0679ff8..2a34a43 100644
--- a/pkg/intl/lib/extract_messages.dart
+++ b/pkg/intl/lib/extract_messages.dart
@@ -147,6 +147,7 @@
    */
   void visitMethodDeclaration(MethodDeclaration node) {
     parameters = node.parameters;
+    if (parameters == null) parameters = new FormalParameterList();
     name = node.name.name;
     super.visitMethodDeclaration(node);
   }
@@ -157,6 +158,7 @@
    */
   void visitFunctionDeclaration(FunctionDeclaration node) {
     parameters = node.functionExpression.parameters;
+    if (parameters == null) parameters = new FormalParameterList();
     name = node.name.name;
     super.visitFunctionDeclaration(node);
   }
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 285e05e..0095c89 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -85,7 +85,7 @@
  * We can't use a hyphen in a Dart library name, so convert the locale
  * separator to an underscore.
  */
-String _libraryName(String x) => x.replaceAll('-', '_');
+String _libraryName(String x) => 'messages_' + x.replaceAll('-', '_');
 
 /**
  * Generate a file <[generated_file_prefix]>_messages_<[locale]>.dart
@@ -135,7 +135,7 @@
  * function name.
  */
 
-library messages_${locale.replaceAll('-','_')};
+library ${_libraryName(locale)};
 import 'package:$intlImportPath/intl.dart';
 import 'package:$intlImportPath/message_lookup_by_library.dart';
 
diff --git a/pkg/intl/lib/src/intl_message.dart b/pkg/intl/lib/src/intl_message.dart
index 0eb67b1..2fe5fd0 100644
--- a/pkg/intl/lib/src/intl_message.dart
+++ b/pkg/intl/lib/src/intl_message.dart
@@ -239,18 +239,37 @@
  */
 class VariableSubstitution extends Message {
   VariableSubstitution(this._index, Message parent) : super(parent);
-  VariableSubstitution.named(this._variableName, Message parent)
-      : super(parent);
+
+  /**
+   * Create a substitution based on the name rather than the index. The name
+   * may have been used as all upper-case in the translation tool, so we
+   * save it separately and look it up case-insensitively once the parent
+   * (and its arguments) are definitely available.
+   */
+  VariableSubstitution.named(String name, Message parent)
+      : super(parent) {
+    _variableNameUpper = name.toUpperCase();
+  }
 
   /** The index in the list of parameters of the containing function. */
   int _index;
   int get index {
     if (_index != null) return _index;
     if (arguments.isEmpty) return null;
-    return _index = arguments.indexOf(_variableName);
+    // We may have been given an all-uppercase version of the name, so compare
+    // case-insensitive.
+    _index = arguments.map((x) => x.toUpperCase()).toList()
+        .indexOf(_variableNameUpper);
+    return _index;
   }
 
   /**
+   * The variable name we get from parsing. This may be an all uppercase version
+   * of the Dart argument name.
+   */
+  String _variableNameUpper;
+
+  /**
    * The name of the variable in the parameter list of the containing function.
    * Used when generating code for the interpolation.
    */
diff --git a/pkg/intl/test/message_extraction/foo_messages_all.dart b/pkg/intl/test/message_extraction/foo_messages_all.dart
index 829df89..1568a64 100644
--- a/pkg/intl/test/message_extraction/foo_messages_all.dart
+++ b/pkg/intl/test/message_extraction/foo_messages_all.dart
@@ -11,14 +11,14 @@
 import 'package:intl/src/intl_helpers.dart';
 import 'package:intl/intl.dart';
 
-import 'foo_messages_fr.dart' as fr;
-import 'foo_messages_de_DE.dart' as de_DE;
+import 'foo_messages_fr.dart' as messages_fr;
+import 'foo_messages_de_DE.dart' as messages_de_DE;
 
 
 MessageLookupByLibrary _findExact(localeName) {
   switch (localeName) {
-    case 'fr' : return fr.messages;
-    case 'de_DE' : return de_DE.messages;
+    case 'fr' : return messages_fr.messages;
+    case 'de_DE' : return messages_de_DE.messages;
     default: return null;
   }
 }
diff --git a/pkg/intl/test/message_extraction/sample_with_messages.dart b/pkg/intl/test/message_extraction/sample_with_messages.dart
index 8fc65c7..f678a35 100644
--- a/pkg/intl/test/message_extraction/sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/sample_with_messages.dart
@@ -47,7 +47,7 @@
     Intl.message("Interpolation is tricky when it ends a sentence like ${s}.",
         name: 'trickyInterpolation', args: [s]);
 
-leadingQuotes() => Intl.message("\"So-called\"", name: 'leadingQuotes');
+get leadingQuotes => Intl.message("\"So-called\"", name: 'leadingQuotes');
 
 // A message with characters not in the basic multilingual plane.
 originalNotInBMP() => Intl.message("Ancient Greek hangman characters: 𐅆𐅇.",
@@ -135,7 +135,7 @@
     printOut(messageVariable(1,2,3));
     printOut(multiLine());
     printOut(types(1, "b", ["c", "d"]));
-    printOut(leadingQuotes());
+    printOut(leadingQuotes);
     printOut(alwaysTranslated());
     printOut(trickyInterpolation("this"));
     var thing = new YouveGotMessages();
diff --git a/pkg/mdv/lib/mdv.dart b/pkg/mdv/lib/mdv.dart
index fe9d9c8..ee27616 100644
--- a/pkg/mdv/lib/mdv.dart
+++ b/pkg/mdv/lib/mdv.dart
@@ -14,9 +14,6 @@
 import 'dart:html';
 import 'package:observe/observe.dart';
 
-// TODO(jmesserly): get this from somewhere else. See http://dartbug.com/4161.
-import 'package:serialization/src/serialization_helpers.dart' show IdentityMap;
-
 import 'src/list_diff.dart' show calculateSplices, ListChangeDelta;
 
 part 'src/element.dart';
diff --git a/pkg/mdv/lib/src/template_iterator.dart b/pkg/mdv/lib/src/template_iterator.dart
index 6c87a42..8458165 100644
--- a/pkg/mdv/lib/src/template_iterator.dart
+++ b/pkg/mdv/lib/src/template_iterator.dart
@@ -344,9 +344,7 @@
       return;
     }
 
-    // TODO(jmesserly): IdentityMap matches JS semantics, but it's O(N) right
-    // now. See http://dartbug.com/4161.
-    var instanceCache = new IdentityMap();
+    var instanceCache = new HashMap(equals: identical);
     var removeDelta = 0;
     for (var splice in splices) {
       for (int i = 0; i < splice.removedCount; i++) {
diff --git a/pkg/mdv/pubspec.yaml b/pkg/mdv/pubspec.yaml
index c962aed..937a8cc 100644
--- a/pkg/mdv/pubspec.yaml
+++ b/pkg/mdv/pubspec.yaml
@@ -1,16 +1,14 @@
 name: mdv
-author: "Web UI Team <web-ui-dev@dartlang.org>"
-homepage: https://github.com/dart-lang/web-ui
+author: Web UI Team <web-ui-dev@dartlang.org>
 description: >
   Model-Driven-Views (MDV) extends HTML and the DOM APIs to support a sensible
   separation between the UI (DOM) of a document or application and its
   underlying data (model).
   Updates to the model are reflected in the DOM and user input into the DOM is
   immediately assigned to the model.
+homepage: https://www.dartlang.org/polymer-dart/
 dependencies:
   logging: any
   observe: any
-  # This is only for IdentityMap. See http://dartbug.com/4161.
-  serialization: any
 dev_dependencies:
   unittest: any
diff --git a/pkg/observe/lib/observe.dart b/pkg/observe/lib/observe.dart
index c1a2f80..8b972d3 100644
--- a/pkg/observe/lib/observe.dart
+++ b/pkg/observe/lib/observe.dart
@@ -65,8 +65,8 @@
  *       print('done!');
  *     }
  *
- * [Tools](https://github.com/dart-lang/web-ui) exist to convert the first form
- * into the second form automatically, to get the best of both worlds.
+ * [Tools](https://www.dartlang.org/polymer-dart/) exist to convert the first
+ * form into the second form automatically, to get the best of both worlds.
  */
 library observe;
 
diff --git a/pkg/observe/lib/src/observable.dart b/pkg/observe/lib/src/observable.dart
index 0127d6e..d39f84a 100644
--- a/pkg/observe/lib/src/observable.dart
+++ b/pkg/observe/lib/src/observable.dart
@@ -97,6 +97,8 @@
   Map<Symbol, Object> _values;
   List<ChangeRecord> _records;
 
+  static final _objectType = reflectClass(Object);
+
   Stream<List<ChangeRecord>> get changes {
     if (_changes == null) {
       _changes = new StreamController.broadcast(sync: true,
@@ -114,19 +116,21 @@
     var mirror = reflect(this);
     var values = new Map<Symbol, Object>();
 
-    // TODO(jmesserly): this should consider the superclass. Unfortunately
-    // that is not possible right now because of:
-    // http://code.google.com/p/dart/issues/detail?id=9434
-    for (var field in mirror.type.variables.values) {
-      if (field.isFinal || field.isStatic || field.isPrivate) continue;
+    // Note: we scan for @observable regardless of whether the base type
+    // actually includes this mixin. While perhaps too inclusive, it lets us
+    // avoid complex logic that walks "with" and "implements" clauses.
+    for (var type = mirror.type; type != _objectType; type = type.superclass) {
+      for (var field in type.variables.values) {
+        if (field.isFinal || field.isStatic || field.isPrivate) continue;
 
-      for (var meta in field.metadata) {
-        if (identical(observable, meta.reflectee)) {
-          var name = field.simpleName;
-          // Note: since this is a field, getting the value shouldn't execute
-          // user code, so we don't need to worry about errors.
-          values[name] = mirror.getField(name).reflectee;
-          break;
+        for (var meta in field.metadata) {
+          if (identical(observable, meta.reflectee)) {
+            var name = field.simpleName;
+            // Note: since this is a field, getting the value shouldn't execute
+            // user code, so we don't need to worry about errors.
+            values[name] = mirror.getField(name).reflectee;
+            break;
+          }
         }
       }
     }
diff --git a/pkg/observe/pubspec.yaml b/pkg/observe/pubspec.yaml
index 7324aef..8fbfb39 100644
--- a/pkg/observe/pubspec.yaml
+++ b/pkg/observe/pubspec.yaml
@@ -6,7 +6,7 @@
   UI (DOM) of a document or application and its underlying data (model).
   Updates to the model are reflected in the DOM and user input into the DOM is
   immediately assigned to the model.
-homepage: https://github.com/dart-lang/web-ui
+homepage: https://www.dartlang.org/polymer-dart/
 dependencies:
   analyzer_experimental: any
   barback: any
diff --git a/pkg/observe/test/observe_test.dart b/pkg/observe/test/observe_test.dart
index b181ccb..da58c3b 100644
--- a/pkg/observe/test/observe_test.dart
+++ b/pkg/observe/test/observe_test.dart
@@ -22,9 +22,11 @@
     expect(dirty_check.allObservablesCount, 0);
   });
 
-  group('WatcherModel', () { _observeTests(watch: true); });
+  group('WatcherModel', () => _observeTests((x) => new WatcherModel(x)));
 
-  group('ObservableBox', () { _observeTests(); });
+  group('ObservableBox', () => _observeTests((x) => new ObservableBox(x)));
+
+  group('ModelSubclass', () => _observeTests((x) => new ModelSubclass(x)));
 
   group('dirtyCheck loops can be debugged', () {
     var messages;
@@ -60,9 +62,8 @@
   });
 }
 
-void _observeTests({bool watch: false}) {
-  final createModel = watch ? (x) => new WatcherModel(x)
-      : (x) => new ObservableBox(x);
+void _observeTests(createModel(x)) {
+  final watch = createModel(null) is! ChangeNotifierMixin;
 
   // Track the subscriptions so we can clean them up in tearDown.
   List subs;
@@ -255,3 +256,7 @@
 
   String toString() => '#<$runtimeType value: $value>';
 }
+
+class ModelSubclass<T> extends WatcherModel<T> {
+  ModelSubclass([T initialValue]) : super(initialValue);
+}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 6460d2e..e398666 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -12,8 +12,7 @@
 
 # Skip non-test files ending with "_test".
 scheduled_test/lib/*: Skip
-polymer/lib/*: Skip
-polymer/example/*: Skip
+polymer/example/scoped_style/*: Skip
 
 scheduled_test/test/scheduled_server_test: Pass, Fail, Slow, Crash # Issue 9231, 9582
 scheduled_test/test/scheduled_process_test: Pass, Slow # Issue 9231
@@ -62,12 +61,29 @@
 crypto/test/sha1_test: Fail # Issue 11407.
 stack_trace/test/trace_test: Fail # http://dartbug.com/12380
 crypto/test/sha256_test: Pass, Fail # Issue 12502
+crypto/test/hmac_sha256_test: Pass, Fail # Issue 12502
+polymer/test/events_test: Fail # Issue 12865, 13197
+polymer/test/event_path_test: Fail # Issue 12865, 13197
+
+[ $runtime == ff ]
+polymer/test/event_path_test: Fail # Issue 12865, 13197
+
+[ $runtime == ie9 || $runtime == ie10 ]
+polymer/test/events_test: Fail, Timeout # Issue 12865, 13197, 13260
+polymer/test/event_path_test: Fail, Timeout # Issue 12865, 13197, 13260
+
+[ $system == windows && ($runtime == chrome || $runtime == ff) ]
+polymer/test/events_test: Pass, Timeout # Issue 13260
+polymer/test/event_path_test: Pass, Timeout # Issue 13260
 
 # Skip browser-specific tests on VM
 [ $runtime == vm ]
 path/test/browser_test: Fail, OK # Uses dart:html
 intl/test/find_default_locale_browser_test: Skip
 intl/test/date_time_format_http_request_test: Skip
+polymer/test/events_test: Fail, OK # Uses dart:html
+polymer/test/event_path_test: Fail, OK # Uses dart:html
+polymer/example: Fail, OK # Uses dart:html
 
 [ $runtime == vm && $system == windows ]
 docgen/test/single_library_test: Fail # Issue 11985
@@ -105,6 +121,7 @@
 stack_trace/test/vm_test: Fail, OK # VM-specific traces
 crypto/test/sha256_test: Slow, Pass
 crypto/test/sha1_test: Slow, Pass
+polymer/example/component: Fail # Issue 13198
 
 [ $browser ]
 analyzer_experimental/test/error_test: Fail, OK # Uses dart:io.
@@ -133,7 +150,8 @@
 oauth2/test/handle_access_token_response_test: Fail, OK # Uses dart:io.
 observe/test/transform_test: Fail, OK # Uses dart:io.
 path/test/io_test: Fail, OK # Uses dart:io.
-polymer/test/*: Fail, OK # Uses dart:io.
+polymer/test/build/*: Fail, OK # Uses dart:io.
+polymer/test/utils_test: Fail, OK # Uses dart:io.
 watcher/test/*: Fail, OK # Uses dart:io.
 
 scheduled_test/test/descriptor/async_test: Fail # http://dartbug.com/8440
diff --git a/pkg/polymer/build.dart b/pkg/polymer/build.dart
deleted file mode 100755
index 4599716..0000000
--- a/pkg/polymer/build.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env dart
-// 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.
-
-/** Build logic that lets the Dart editor build examples in the background. */
-library build;
-import 'package:polymer/component_build.dart';
-import 'dart:io';
-
-void main() {
-  build(new Options().arguments, [
-    'example/component/news/web/index.html',
-    'example/scoped_style/index.html']);
-}
diff --git a/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt b/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt
deleted file mode 100644
index 0850734..0000000
--- a/pkg/polymer/example/component/news/test/expected/news_index_test.html.txt
+++ /dev/null
@@ -1,75 +0,0 @@
-Content-Type: text/plain
-<html><head>
-  <title>Simple Web Components Example</title>
-  
-  <script src="packages/polymer/testing/testing.js"></script>
-<style>template,
-thead[template],
-tbody[template],
-tfoot[template],
-th[template],
-tr[template],
-td[template],
-caption[template],
-colgroup[template],
-col[template],
-option[template] {
-  display: none;
-}</style></head>
-<body><script src="packages/shadow_dom/shadow_dom.min.js"></script>
-<script src="packages/browser/interop.js"></script>
-<polymer-element name="x-news" extends="ul">
-    <template>
-        <style scoped="">
-            div.breaking {
-                color: Red;
-                font-size: 20px;
-                border: 1px dashed Purple;
-            }
-            div.other {
-                padding: 2px 0 0 0;
-                border: 1px solid Cyan;
-            }
-        </style>
-        <div class="breaking">
-            <h2>Breaking Stories</h2>
-            <ul>
-                <content select=".breaking"></content>
-            </ul>
-        </div>
-        <div class="other">
-            <h2>Other News</h2>
-            <ul>
-                <content></content>
-            </ul>
-        </div>
-    </template>
-    
-</polymer-element>
-<h1>Simple Web Components Example</h1>
-<ul is="x-news"><shadow-root>
-        <style scoped="">/* style hidden by testing.js */</style>
-        <div class="breaking">
-            <h2>Breaking Stories</h2>
-            <ul>
-                <content select=".breaking"></content>
-            </ul>
-        </div>
-        <div class="other">
-            <h2>Other News</h2>
-            <ul>
-                <content></content>
-            </ul>
-        </div>
-    </shadow-root>
-    <li><a href="//example.com/stories/1">A story</a></li>
-    <li><a href="//example.com/stories/2">Another story</a></li>
-    <li class="breaking"><a href="//example.com/stories/3">Also a story</a></li>
-    <li><a href="//example.com/stories/4">Yet another story</a></li>
-    <li><a href="//example.com/stories/4">Awesome story</a></li>
-    <li class="breaking"><a href="//example.com/stories/5">Horrible story</a></li>
-</ul>
-
-
-
-<script type="application/dart" src="news_index_test.html_bootstrap.dart"></script></body></html>
diff --git a/pkg/polymer/example/component/news/test/news_index_test.dart b/pkg/polymer/example/component/news/test/news_index_test.dart
new file mode 100644
index 0000000..67ebbe3
--- /dev/null
+++ b/pkg/polymer/example/component/news/test/news_index_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:polymer/polymer.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+/**
+ * This test runs the news example and checks the state of the initial page.
+ */
+main() {
+  useHtmlConfiguration();
+
+  extractLinks(nodes) => nodes.where((n) => n is Element)
+      .map((n) => n.query('a').href.split('/').last).toList();
+
+  test('initial state', () {
+    final listComp = query('ul');
+    final items = listComp.queryAll('li');
+    expect(items.length, 6);
+    expect(extractLinks(items), ['1', '2', '3', '4', '4', '5']);
+    expect(listComp.xtag is PolymerElement, true,
+        reason: 'x-news should be created');
+
+    final contents = listComp.shadowRoot.queryAll('content');
+    expect(contents.length, 2, reason: 'news has 2 content tags');
+    expect(extractLinks(contents[0].getDistributedNodes()),
+        ['3', '5'], reason: 'breaking stories first');
+    expect(extractLinks(contents[1].getDistributedNodes()),
+        ['1', '2', '4', '4'], reason: 'other stories after breaking stories');
+  });
+}
diff --git a/pkg/polymer/example/component/news/test/news_index_test.html b/pkg/polymer/example/component/news/test/news_index_test.html
index 95bfadd..873b2d5 100644
--- a/pkg/polymer/example/component/news/test/news_index_test.html
+++ b/pkg/polymer/example/component/news/test/news_index_test.html
@@ -7,7 +7,8 @@
 <head>
   <title>Simple Web Components Example</title>
   <link rel="import" href="../web/news-component.html">
-  <script src="packages/polymer/testing/testing.js"></script>
+  <script src="packages/polymer/boot.js"></script>
+  <script src="packages/unittest/test_controller.js"></script>
 </head>
 <body>
 <h1>Simple Web Components Example</h1>
@@ -19,11 +20,6 @@
     <li><a href="//example.com/stories/4">Awesome story</a></li>
     <li class="breaking"><a href="//example.com/stories/5">Horrible story</a></li>
 </ul>
-<script type="application/dart">
-import 'dart:html';
-main() {
-  window.postMessage('done', '*');
-}
-</script>
+<script type="application/dart" src="news_index_test.dart"></script>
 </body>
 </html>
diff --git a/pkg/polymer/example/component/news/test/test.dart b/pkg/polymer/example/component/news/test/test.dart
deleted file mode 100755
index a4c98a0..0000000
--- a/pkg/polymer/example/component/news/test/test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env dart
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io';
-import 'package:polymer/testing/content_shell_test.dart';
-import 'package:unittest/compact_vm_config.dart';
-
-void main() {
-  useCompactVMConfiguration();
-  // Base directory, input, expected, output:
-  renderTests('..', '.', 'expected', 'out');
-}
diff --git a/pkg/polymer/lib/builder.dart b/pkg/polymer/lib/builder.dart
new file mode 100644
index 0000000..eb5ee43
--- /dev/null
+++ b/pkg/polymer/lib/builder.dart
@@ -0,0 +1,292 @@
+// 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.
+
+/**
+ * Common logic to make it easy to run the polymer linter and deploy tool.
+ * 
+ * The functions in this library are designed to make it easier to create
+ * `build.dart` files. A `build.dart` file is a Dart script that can be invoked
+ * from the command line, but that can also invoked automatically by the Dart
+ * Editor whenever a file in your project changes or when selecting some menu
+ * options, such as 'Reanalyze Sources'.
+ *
+ * To work correctly, place the `build.dart` in the root of your project (where
+ * pubspec.yaml lives). The file must be named exactly `build.dart`.
+ *
+ * It's quite likely that in the near future `build.dart` will be replaced with
+ * something else.  For example, `pub deploy` will deal with deploying
+ * applications automatically, and the Dart Editor might provide other
+ * mechanisms to hook linters.
+ *
+ * There are three important functions exposed by this library [build], [lint],
+ * and [deploy]. The following examples show common uses of these functions when
+ * writing a `build.dart` file.
+ *
+ * **Example 1**: Uses build.dart to run the linter tool.
+ *
+ *     import 'dart:io';
+ *     import 'package:polymer/builder.dart';
+ *
+ *     main() {
+ *        lint();
+ *     }
+ *
+ * **Example 2**: Runs the linter and creates a deployable version of the app
+ * every time.
+ *
+ *     import 'dart:io';
+ *     import 'package:polymer/builder.dart';
+ *
+ *     main() {
+ *        lint().then(() => deploy());
+ *     }
+ *
+ * **Example 3**: Runs the linter, but conditionally does the deploy step. See
+ * [parseOptions] for a description of options parsed automatically by this
+ * helper library.
+ *
+ *     import 'dart:io';
+ *     import 'package:polymer/builder.dart';
+ *
+ *     main() {
+ *        var options = parseOptions();
+ *        lint().then(() {
+ *          if (options.forceDeploy) deploy();
+ *        });
+ *     }
+ *
+ * **Example 4**: Same as above, but uses [build] (which internally calls [lint]
+ * and [deploy]).
+ *
+ *     import 'dart:io';
+ *     import 'package:polymer/builder.dart';
+ *
+ *     main() {
+ *        build();
+ *     }
+ *
+ * **Example 5**: Like the previous example, but indicates to the linter and
+ * deploy tool which files are actually used as entry point files. See the
+ * documentation of [build] below for more details.
+ *
+ *     import 'dart:io';
+ *     import 'package:polymer/builder.dart';
+ *
+ *     main() {
+ *        build(entryPoints: ['web/index.html']);
+ *     }
+ */
+library polymer.builder;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:args/args.dart';
+
+import 'src/build/linter.dart';
+import 'src/build/runner.dart';
+import 'transformer.dart';
+
+
+/**
+ * Runs the polymer linter on any relevant file in your package, such as any
+ * .html file under 'lib/', 'asset/', and 'web/'. And, if requested, creates a
+ * directory suitable for deploying a Polymer application to a server.
+ *
+ * The [entryPoints] list contains files under web/ that should be treated as
+ * entry points. Each entry on this list is a relative path from the package
+ * root (for example 'web/index.html'). If null, all files under 'web/' are
+ * treated as possible entry points. 
+ *
+ * Options are read from the command line arguments, but you can override them
+ * passing the [options] argument. The deploy operation is run only when the
+ * command-line argument `--deploy` is present, or equivalently when
+ * `options.forceDeploy` is true.
+ *
+ * The linter and deploy steps needs to know the name of the [currentPackage]
+ * and the location where to find the code for any package it depends on
+ * ([packageDirs]). This is inferred automatically, but can be overriden if
+ * those arguments are provided.
+ */
+Future build({List<String> entryPoints, CommandLineOptions options,
+    String currentPackage, Map<String, String> packageDirs}) {
+  if (options == null) options = _options;
+  return lint(entryPoints: entryPoints, options: options,
+      currentPackage: currentPackage, packageDirs: packageDirs).then((res) {
+    if (options.forceDeploy) {
+      return deploy(entryPoints: entryPoints, options: options,
+          currentPackage: currentPackage, packageDirs: packageDirs);
+    }
+  });
+}
+
+
+/**
+ * Runs the polymer linter on any relevant file in your package, 
+ * such as any .html file under 'lib/', 'asset/', and 'web/'.
+ *
+ * The [entryPoints] list contains files under web/ that should be treated as
+ * entry points. Each entry on this list is a relative path from the package
+ * root (for example 'web/index.html'). If null, all files under 'web/' are
+ * treated as possible entry points. 
+ *
+ * Options are read from the command line arguments, but you can override them
+ * passing the [options] argument.
+ *
+ * The linter needs to know the name of the [currentPackage] and the location
+ * where to find the code for any package it depends on ([packageDirs]). This is
+ * inferred automatically, but can be overriden if those arguments are provided.
+ */
+Future lint({List<String> entryPoints, CommandLineOptions options,
+    String currentPackage, Map<String, String> packageDirs}) {
+  if (options == null) options = _options;
+  if (currentPackage == null) currentPackage = readCurrentPackageFromPubspec();
+  var linterOptions = new TransformOptions(currentPackage, entryPoints);
+  var formatter = options.machineFormat ? jsonFormatter : consoleFormatter;
+  var linter = new Linter(linterOptions, formatter);
+  return runBarback(new BarbackOptions([[linter]], null,
+      currentPackage: currentPackage, packageDirs: packageDirs)).then((assets) {
+    var messages = {};
+    var futures = [];
+    for (var asset in assets) {
+      var id = asset.id;
+      if (id.package == currentPackage && id.path.endsWith('.messages')) {
+        futures.add(asset.readAsString().then((content) {
+          if (content.isEmpty) return;
+          messages[id] = content;
+        }));
+      }
+    }
+
+    return Future.wait(futures).then((_) {
+      // Print messages sorting by package and filepath.
+      var orderedKeys = messages.keys.toList();
+      orderedKeys.sort((a, b) {
+        int packageCompare = a.package.compareTo(b.package);
+        if (packageCompare != 0) return packageCompare;
+        return a.path.compareTo(b.path);
+      });
+
+      for (var key in orderedKeys) {
+        print(messages[key]);
+      }
+    });
+  });
+}
+
+/**
+ * Creates a directory suitable for deploying a Polymer application to a server.
+ *
+ * **Note**: this function will be replaced in the future by the `pub deploy`
+ * command.
+ *
+ * The [entryPoints] list contains files under web/ that should be treated as
+ * entry points. Each entry on this list is a relative path from the package
+ * root (for example 'web/index.html'). If null, all files under 'web/' are
+ * treated as possible entry points. 
+ *
+ * Options are read from the command line arguments, but you can override them
+ * passing the [options] list.
+ *
+ * The deploy step needs to know the name of the [currentPackage] and the
+ * location where to find the code for any package it depends on
+ * ([packageDirs]). This is inferred automatically, but can be overriden if
+ * those arguments are provided.
+ */
+Future deploy({List<String> entryPoints, CommandLineOptions options,
+    String currentPackage, Map<String, String> packageDirs}) {
+  if (options == null) options = _options;
+  if (currentPackage == null) currentPackage = readCurrentPackageFromPubspec();
+  var barbackOptions = new BarbackOptions(
+      createDeployPhases(new TransformOptions(currentPackage, entryPoints)),
+      options.outDir, currentPackage: currentPackage,
+      packageDirs: packageDirs);
+  return runBarback(barbackOptions)
+      .then((_) => print('Done! All files written to "${options.outDir}"'));
+}
+
+
+/**
+ * Options that may be used either in build.dart or by the linter and deploy
+ * tools.
+ */
+class CommandLineOptions {
+  /** Files marked as changed. */
+  final List<String> changedFiles;
+
+  /** Files marked as removed. */
+  final List<String> removedFiles;
+
+  /** Whether to clean intermediate artifacts, if any. */
+  final bool clean;
+
+  /** Whether to do a full build (as if all files have changed). */
+  final bool full;
+
+  /** Whether to print results using a machine parseable format. */
+  final bool machineFormat;
+
+  /** Whether the force deploy option was passed in the command line. */
+  final bool forceDeploy;
+
+  /** Location where to generate output files. */
+  final String outDir;
+
+  CommandLineOptions(this.changedFiles, this.removedFiles, this.clean,
+      this.full, this.machineFormat, this.forceDeploy, this.outDir);
+}
+
+/** Options parsed directly from the command line arguments. */
+CommandLineOptions _options = parseOptions();
+
+/**
+ * Parse command-line arguments and return a [CommandLineOptions] object. The
+ * following flags are parsed by this method.
+ *
+ *   * `--changed file-path`: notify of a file change.
+ *   * `--removed file-path`: notify that a file was removed.
+ *   * `--clean`: remove temporary artifacts (if any)
+ *   * `--full`: build everything, similar to marking every file as changed
+ *   * `--machine`: produce output that can be parsed by tools, such as the Dart
+ *     Editor.
+ *   * `--deploy`: force deploy.
+ *   * `--help`: print documentation for each option and exit.
+ *
+ * Currently not all the flags are used by [lint] or [deploy] above, but they
+ * are available so they can be used from your `build.dart`. For instance, see
+ * the top-level library documentation for an example that uses the force-deploy
+ * option to conditionally call [deploy].
+ *
+ * If this documentation becomes out of date, the best way to discover which
+ * flags are supported is to invoke this function from your build.dart, and run
+ * it with the `--help` command-line flag.
+ */
+CommandLineOptions parseOptions([List<String> args]) {
+  var parser = new ArgParser()
+    ..addOption('changed', help: 'The file has changed since the last build.',
+        allowMultiple: true)
+    ..addOption('removed', help: 'The file was removed since the last build.',
+        allowMultiple: true)
+    ..addFlag('clean', negatable: false,
+        help: 'Remove any build artifacts (if any).')
+    ..addFlag('full', negatable: false, help: 'perform a full build')
+    ..addFlag('machine', negatable: false,
+        help: 'Produce warnings in a machine parseable format.')
+    ..addFlag('deploy', negatable: false,
+        help: 'Whether to force deploying.')
+    ..addOption('out', abbr: 'o', help: 'Directory to generate files into.',
+        defaultsTo: 'out')
+    ..addFlag('help', abbr: 'h',
+        negatable: false, help: 'Displays this help and exit.');
+  var res = parser.parse(args == null ? new Options().arguments : args);
+  if (res['help']) {
+    print('A build script that invokes the polymer linter and deploy tools.');
+    print('Usage: dart build.dart [options]');
+    print('\nThese are valid options expected by build.dart:');
+    print(parser.getUsage());
+    exit(0);
+  }
+  return new CommandLineOptions(res['changed'], res['removed'], res['clean'],
+      res['full'], res['machine'], res['deploy'], res['out']);
+}
diff --git a/pkg/polymer/lib/component_build.dart b/pkg/polymer/lib/component_build.dart
index 7184787..6a923f0 100644
--- a/pkg/polymer/lib/component_build.dart
+++ b/pkg/polymer/lib/component_build.dart
@@ -2,105 +2,21 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-/**
- * Common logic to make it easy to create a `build.dart` for your project.
- *
- * The `build.dart` script is invoked automatically by the Editor whenever a
- * file in the project changes. It must be placed in the root of a project
- * (where pubspec.yaml lives) and should be named exactly 'build.dart'.
- *
- * A common `build.dart` would look as follows:
- *
- *     import 'dart:io';
- *     import 'package:polymer/component_build.dart';
- *
- *     main() => build(new Options().arguments, ['web/index.html']);
- */
+/** This library is deprecated. Please use `builder.dart` instead. */
+@deprecated
 library build_utils;
 
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'package:args/args.dart';
+import 'package:meta/meta.dart';
 
-import 'dwc.dart' as dwc;
-import 'src/utils.dart';
-import 'src/compiler_options.dart';
+import 'builder.dart' as builder;
 
 /**
- * Set up 'build.dart' to compile with the dart web components compiler every
- * [entryPoints] listed. On clean commands, the directory where [entryPoints]
- * live will be scanned for generated files to delete them.
+ * This function is deprecated. Please use `build` from `builder.dart`
+ * instead.
  */
-Future<List<dwc.AnalysisResults>> build(List<String> arguments,
-    List<String> entryPoints,
+@deprecated
+Future build(List<String> arguments, List<String> entryPoints,
     {bool printTime: true, bool shouldPrint: true}) {
-  bool useColors = stdioType(stdout) == StdioType.TERMINAL;
-  return asyncTime('Total time', () {
-    var args = _processArgs(arguments);
-    var tasks = new FutureGroup();
-    var lastTask = new Future.value(null);
-    tasks.add(lastTask);
-
-    var changedFiles = args["changed"];
-    var removedFiles = args["removed"];
-    var cleanBuild = args["clean"];
-    var machineFormat = args["machine"];
-    // Also trigger a full build if the script was run from the command line
-    // with no arguments
-    var fullBuild = args["full"] || (!machineFormat && changedFiles.isEmpty &&
-        removedFiles.isEmpty && !cleanBuild);
-
-    var options = CompilerOptions.parse(args.rest, checkUsage: false);
-
-    if (fullBuild || !changedFiles.isEmpty || !removedFiles.isEmpty) {
-      for (var file in entryPoints) {
-        var dwcArgs = new List.from(args.rest);
-        if (machineFormat) dwcArgs.add('--json_format');
-        if (!useColors) dwcArgs.add('--no-colors');
-        dwcArgs.add(file);
-        // Chain tasks to that we run one at a time.
-        lastTask = lastTask.then((_) => dwc.run(dwcArgs, printTime: printTime,
-            shouldPrint: shouldPrint));
-        if (machineFormat) {
-          lastTask = lastTask.then((res) {
-            appendMessage(Map jsonMessage) {
-              var message = JSON.encode([jsonMessage]);
-              if (shouldPrint) print(message);
-              res.messages.add(message);
-            }
-            return res;
-          });
-        }
-        tasks.add(lastTask);
-      }
-    }
-    return tasks.future.then((r) => r.where((v) => v != null));
-  }, printTime: printTime, useColors: useColors);
-}
-
-/** Process the command-line arguments. */
-ArgResults _processArgs(List<String> arguments) {
-  var parser = new ArgParser()
-    ..addOption("changed", help: "the file has changed since the last build",
-        allowMultiple: true)
-    ..addOption("removed", help: "the file was removed since the last build",
-        allowMultiple: true)
-    ..addFlag("clean", negatable: false, help: "currently a noop, may be used "
-        "in the future to remove any build artifacts")
-    ..addFlag("full", negatable: false, help: "perform a full build")
-    ..addFlag("machine", negatable: false,
-        help: "produce warnings in a machine parseable format")
-    ..addFlag("help", abbr: 'h',
-        negatable: false, help: "displays this help and exit");
-  var args = parser.parse(arguments);
-  if (args["help"]) {
-    print('A build script that invokes the web-ui compiler (dwc).');
-    print('Usage: dart build.dart [options] [-- [dwc-options]]');
-    print('\nThese are valid options expected by build.dart:');
-    print(parser.getUsage());
-    print('\nThese are valid options expected by dwc:');
-    dwc.run(['-h']).then((_) => exit(0));
-  }
-  return args;
+  return builder.build(
+      entryPoints: entryPoints, options: parseOptions(arguments));
 }
diff --git a/pkg/polymer/lib/deploy.dart b/pkg/polymer/lib/deploy.dart
index 4c5b564..8445ac8 100644
--- a/pkg/polymer/lib/deploy.dart
+++ b/pkg/polymer/lib/deploy.dart
@@ -3,6 +3,9 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
+ * **Note**: If you already have a `build.dart` in your application, we
+ * recommend to use the `package:polymer/builder.dart` library instead.
+
  * Temporary deploy command used to create a version of the app that can be
  * compiled with dart2js and deployed. Following pub layout conventions, this
  * script will treat any HTML file under a package 'web/' and 'test/'
@@ -20,34 +23,33 @@
 library polymer.deploy;
 
 import 'dart:async';
-import 'dart:convert';
 import 'dart:io';
 
-import 'package:barback/barback.dart';
-import 'package:path/path.dart' as path;
-import 'package:polymer/src/transform.dart' show phases;
-import 'package:stack_trace/stack_trace.dart';
-import 'package:yaml/yaml.dart';
 import 'package:args/args.dart';
+import 'package:path/path.dart' as path;
+import 'src/build/runner.dart';
+import 'transformer.dart';
 
 main() {
   var args = _parseArgs(new Options().arguments);
-  if (args == null) return;
+  if (args == null) exit(1);
 
   var test = args['test'];
-  if (test != null) {
-    _initForTest(test);
-  }
-
-  print('polymer/deploy.dart: creating a deploy target for "$_currentPackage"');
   var outDir = args['out'];
-  _run(outDir, test != null).then(
-      (_) => print('Done! All files written to "$outDir"'));
+  var options = (test == null)
+    ? new BarbackOptions(createDeployPhases(new TransformOptions()), outDir)
+    : _createTestOptions(test, outDir);
+  if (options == null) exit(1);
+
+  print('polymer/deploy.dart: creating a deploy target for '
+      '"${options.currentPackage}"');
+
+  runBarback(options)
+      .then((_) => print('Done! All files written to "$outDir"'))
+      .catchError(_reportErrorAndExit);
 }
 
-// TODO(jmesserly): the current deploy/barback architecture is very unfriendly
-// to deploying a single test. We need to fix it somehow but it isn't clear yet.
-void _initForTest(String testFile) {
+BarbackOptions _createTestOptions(String testFile, String outDir) {
   var testDir = path.normalize(path.dirname(testFile));
 
   // A test must be allowed to import things in the package.
@@ -57,11 +59,15 @@
   if (pubspecDir == null) {
     print('error: pubspec.yaml file not found, please run this script from '
         'your package root directory or a subdirectory.');
-    exit(1);
+    return null;
   }
 
-  _currentPackage = '_test';
-  _packageDirs = {'_test' : pubspecDir};
+  var phases = createDeployPhases(new TransformOptions(
+        '_test', [path.relative(testFile, from: pubspecDir)]));
+  return new BarbackOptions(phases, outDir,
+      currentPackage: '_test',
+      packageDirs: {'_test' : pubspecDir},
+      transformTests: true);
 }
 
 String _findDirWithFile(String dir, String filename) {
@@ -74,208 +80,18 @@
   return dir;
 }
 
-/**
- * API exposed for testing purposes. Runs this deploy command but prentend that
- * the sources under [webDir] belong to package 'test'.
- */
-Future runForTest(String webDir, String outDir) {
-  _currentPackage = 'test';
-
-  // associate package dirs with their location in the repo:
-  _packageDirs = {'test' : '.'};
-  _addPackages('..');
-  _addPackages('../third_party');
-  _addPackages('../../third_party/pkg');
-  return _run(webDir, outDir);
+void _reportErrorAndExit(e) {
+  var trace = getAttachedStackTrace(e);
+  print('Uncaught error: $e');
+  if (trace != null) print(trace);
+  exit(1);
 }
 
-_addPackages(String dir) {
-  for (var packageDir in new Directory(dir).listSync().map((d) => d.path)) {
-    _packageDirs[path.basename(packageDir)] = packageDir;
-  }
-}
-
-Future _run(String outDir, bool includeTests) {
-  var barback = new Barback(new _PolymerDeployProvider());
-  _initializeBarback(barback, includeTests);
-  _attachListeners(barback);
-  return _emitAllFiles(barback, 'web', outDir).then(
-      (_) => includeTests ? _emitAllFiles(barback, 'test', outDir) : null);
-}
-
-/** Tell barback which transformers to use and which assets to process. */
-void _initializeBarback(Barback barback, bool includeTests) {
-  var assets = [];
-  void addAssets(String package, String subDir) {
-    for (var filepath in _listDir(package, subDir)) {
-      assets.add(new AssetId(package, filepath));
-    }
-  }
-
-  for (var package in _packageDirs.keys) {
-    // Do not process packages like 'polymer' where there is nothing to do.
-    if (_ignoredPackages.contains(package)) continue;
-    barback.updateTransformers(package, phases);
-
-    // notify barback to process anything under 'lib' and 'asset'
-    addAssets(package, 'lib');
-    addAssets(package, 'asset');
-  }
-
-  // In case of the current package, include also 'web'.
-  addAssets(_currentPackage, 'web');
-  if (includeTests) addAssets(_currentPackage, 'test');
-
-  barback.updateSources(assets);
-}
-
-/** Return the relative path of each file under [subDir] in a [package]. */
-Iterable<String> _listDir(String package, String subDir) {
-  var packageDir = _packageDirs[package];
-  if (packageDir == null) return const [];
-  var dir = new Directory(path.join(packageDir, subDir));
-  if (!dir.existsSync()) return const [];
-  return dir.listSync(recursive: true, followLinks: false)
-      .where((f) => f is File)
-      .map((f) => path.relative(f.path, from: packageDir));
-}
-
-/** Attach error listeners on [barback] so we can report errors. */
-void _attachListeners(Barback barback) {
-  // Listen for errors and results
-  barback.errors.listen((e) {
-    var trace = getAttachedStackTrace(e);
-    if (trace != null) {
-      print(Trace.format(trace));
-    }
-    print('error running barback: $e');
-    exit(1);
-  });
-
-  barback.results.listen((result) {
-    if (!result.succeeded) {
-      print("build failed with errors: ${result.errors}");
-      exit(1);
-    }
-  });
-}
-
-/** Ensure [dirpath] exists. */
-void _ensureDir(var dirpath) {
-  new Directory(dirpath).createSync(recursive: true);
-}
-
-/**
- * Emits all outputs of [barback] and copies files that we didn't process (like
- * polymer's libraries).
- */
-Future _emitAllFiles(Barback barback, String webDir, String outDir) {
-  return barback.getAllAssets().then((assets) {
-    // Copy all the assets we transformed
-    var futures = [];
-    for (var asset in assets) {
-      var id = asset.id;
-      var filepath;
-      if (id.package == _currentPackage && id.path.startsWith('$webDir/')) {
-        filepath = path.join(outDir, id.path);
-      } else if (id.path.startsWith('lib/')) {
-        filepath = path.join(outDir, webDir, 'packages', id.package,
-            id.path.substring(4));
-      } else {
-        // TODO(sigmund): do something about other assets?
-        continue;
-      }
-
-      _ensureDir(path.dirname(filepath));
-      var writer = new File(filepath).openWrite();
-      futures.add(writer.addStream(asset.read()).then((_) => writer.close()));
-    }
-    return Future.wait(futures);
-  }).then((_) {
-    // Copy also all the files we didn't process
-    var futures = [];
-    for (var package in _ignoredPackages) {
-      for (var relpath in _listDir(package, 'lib')) {
-        var inpath = path.join(_packageDirs[package], relpath);
-        var outpath = path.join(outDir, webDir, 'packages', package,
-            relpath.substring(4));
-        _ensureDir(path.dirname(outpath));
-
-        var writer = new File(outpath).openWrite();
-        futures.add(writer.addStream(new File(inpath).openRead())
-          .then((_) => writer.close()));
-      }
-    }
-    return Future.wait(futures);
-  });
-}
-
-/** A simple provider that reads files directly from the pub cache. */
-class _PolymerDeployProvider implements PackageProvider {
-
-  Iterable<String> get packages => _packageDirs.keys;
-  _PolymerDeployProvider();
-
-  Future<Asset> getAsset(AssetId id) =>
-      new Future.value(new Asset.fromPath(id, path.join(
-              _packageDirs[id.package],
-              // Assets always use the posix style paths
-              path.joinAll(path.posix.split(id.path)))));
-}
-
-
-/** The current package extracted from the pubspec.yaml file. */
-String _currentPackage = () {
-  var pubspec = new File('pubspec.yaml');
-  if (!pubspec.existsSync()) {
-    print('error: pubspec.yaml file not found, please run this script from '
-        'your package root directory.');
-    return null;
-  }
-  return loadYaml(pubspec.readAsStringSync())['name'];
-}();
-
-/**
- * Maps package names to the path in the file system where to find the sources
- * of such package. This map will contain an entry for the current package and
- * everything it depends on (extracted via `pub list-pacakge-dirs`).
- */
-Map<String, String> _packageDirs = () {
-  var pub = path.join(path.dirname(new Options().executable),
-      Platform.isWindows ? 'pub.bat' : 'pub');
-  var result = Process.runSync(pub, ['list-package-dirs']);
-  if (result.exitCode != 0) {
-    print("unexpected error invoking 'pub':");
-    print(result.stdout);
-    print(result.stderr);
-    exit(result.exitCode);
-  }
-  var map = JSON.decode(result.stdout)["packages"];
-  map.forEach((k, v) { map[k] = path.dirname(v); });
-  map[_currentPackage] = '.';
-  return map;
-}();
-
-/**
- * Internal packages used by polymer which we can copy directly to the output
- * folder without having to process them with barback.
- */
-// TODO(sigmund): consider computing this list by recursively parsing
-// pubspec.yaml files in the [_packageDirs].
-final Set<String> _ignoredPackages =
-    (const [ 'analyzer_experimental', 'args', 'barback', 'browser', 'csslib',
-             'custom_element', 'fancy_syntax', 'html5lib', 'html_import', 'js',
-             'logging', 'mdv', 'meta', 'mutation_observer', 'observe', 'path',
-             'polymer', 'polymer_expressions', 'serialization', 'shadow_dom',
-             'source_maps', 'stack_trace', 'unittest',
-             'unmodifiable_collection', 'yaml'
-           ]).toSet();
-
 ArgResults _parseArgs(arguments) {
   var parser = new ArgParser()
       ..addFlag('help', abbr: 'h', help: 'Displays this help message.',
           defaultsTo: false, negatable: false)
-      ..addOption('out', abbr: 'o', help: 'Directory where to generated files.',
+      ..addOption('out', abbr: 'o', help: 'Directory to generate files into.',
           defaultsTo: 'out')
       ..addOption('test', help: 'Deploy the test at the given path.\n'
           'Note: currently this will deploy all tests in its directory,\n'
@@ -295,6 +111,7 @@
 }
 
 _showUsage(parser) {
-  print('Usage: dart package:polymer/deploy.dart [options]');
+  print('Usage: dart --package-root=packages/ '
+      'package:polymer/deploy.dart [options]');
   print(parser.getUsage());
 }
diff --git a/pkg/polymer/lib/dwc.dart b/pkg/polymer/lib/dwc.dart
deleted file mode 100644
index b0cc4db..0000000
--- a/pkg/polymer/lib/dwc.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** The entry point to the compiler. Used to implement `bin/dwc.dart`. */
-library dwc;
-
-import 'dart:async';
-import 'dart:io';
-import 'package:logging/logging.dart' show Level;
-
-import 'src/compiler.dart';
-import 'src/file_system/console.dart';
-import 'src/messages.dart';
-import 'src/compiler_options.dart';
-import 'src/utils.dart';
-
-void main() {
-  run(new Options().arguments).then((result) {
-    exit(result.success ? 0 : 1);
-  });
-}
-
-/** Contains the result of a compiler run. */
-class AnalysisResults {
-
-  /** False when errors were found by our polymer analyzer. */
-  final bool success;
-
-  /** Error and warning messages collected by the analyzer. */
-  final List<String> messages;
-
-  AnalysisResults(this.success, this.messages);
-}
-
-/**
- * Runs the polymer analyzer with the command-line options in [args].
- * See [CompilerOptions] for the definition of valid arguments.
- */
-// TODO(sigmund): rename to analyze? and rename file as analyzer.dart
-Future<AnalysisResults> run(List<String> args, {bool printTime,
-    bool shouldPrint: true}) {
-  var options = CompilerOptions.parse(args);
-  if (options == null) return new Future.value(new AnalysisResults(true, []));
-  if (printTime == null) printTime = options.verbose;
-
-  return asyncTime('Total time spent on ${options.inputFile}', () {
-    var messages = new Messages(options: options, shouldPrint: shouldPrint);
-    var compiler = new Compiler(new ConsoleFileSystem(), options, messages);
-    return compiler.run().then((_) {
-      var success = messages.messages.every((m) => m.level != Level.SEVERE);
-      var msgs = options.jsonFormat
-          ? messages.messages.map((m) => m.toJson())
-          : messages.messages.map((m) => m.toString());
-      return new AnalysisResults(success, msgs.toList());
-    });
-  }, printTime: printTime, useColors: options.useColors);
-}
diff --git a/pkg/polymer/lib/polymer_element.dart b/pkg/polymer/lib/polymer_element.dart
index 14d4096..3f42390 100644
--- a/pkg/polymer/lib/polymer_element.dart
+++ b/pkg/polymer/lib/polymer_element.dart
@@ -16,7 +16,7 @@
 import 'package:observe/src/microtask.dart';
 import 'package:polymer_expressions/polymer_expressions.dart';
 
-import 'src/utils_observe.dart' show toCamelCase, toHyphenedName;
+import 'src/utils.dart' show toCamelCase, toHyphenedName;
 
 /**
  * Registers a [PolymerElement]. This is similar to [registerCustomElement]
diff --git a/pkg/polymer/lib/src/analyzer.dart b/pkg/polymer/lib/src/analyzer.dart
deleted file mode 100644
index b8011a0..0000000
--- a/pkg/polymer/lib/src/analyzer.dart
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Part of the template compilation that concerns with extracting information
- * from the HTML parse tree.
- */
-library analyzer;
-
-import 'package:html5lib/dom.dart';
-import 'package:html5lib/dom_parsing.dart';
-
-import 'custom_tag_name.dart';
-import 'files.dart';
-import 'info.dart';
-import 'messages.dart';
-
-/**
- * Finds custom elements in this file and the list of referenced files with
- * component declarations. This is the first pass of analysis on a file.
- *
- * Adds emitted error/warning messages to [messages], if [messages] is
- * supplied.
- */
-FileInfo analyzeDefinitions(GlobalInfo global, UrlInfo inputUrl,
-    Document document, String packageRoot, Messages messages) {
-  var result = new FileInfo(inputUrl);
-  var loader = new _ElementLoader(global, result, packageRoot, messages);
-  loader.visit(document);
-  return result;
-}
-
-/**
- *  Extract relevant information from all files found from the root document.
- *
- *  Adds emitted error/warning messages to [messages], if [messages] is
- *  supplied.
- */
-void analyzeFile(SourceFile file, Map<String, FileInfo> info,
-                 Iterator<int> uniqueIds, GlobalInfo global,
-                 Messages messages, emulateScopedCss) {
-  var fileInfo = info[file.path];
-  var analyzer = new _Analyzer(fileInfo, uniqueIds, global, messages,
-      emulateScopedCss);
-  analyzer._normalize(fileInfo, info);
-  analyzer.visit(file.document);
-}
-
-
-/** A visitor that walks the HTML to extract all the relevant information. */
-class _Analyzer extends TreeVisitor {
-  final FileInfo _fileInfo;
-  LibraryInfo _currentInfo;
-  Iterator<int> _uniqueIds;
-  GlobalInfo _global;
-  Messages _messages;
-
-  int _generatedClassNumber = 0;
-
-  /**
-   * Whether to keep indentation spaces. Break lines and indentation spaces
-   * within templates are preserved in HTML. When users specify the attribute
-   * 'indentation="remove"' on a template tag, we'll trim those indentation
-   * spaces that occur within that tag and its decendants. If any decendant
-   * specifies 'indentation="preserve"', then we'll switch back to the normal
-   * behavior.
-   */
-  bool _keepIndentationSpaces = true;
-
-  final bool _emulateScopedCss;
-
-  _Analyzer(this._fileInfo, this._uniqueIds, this._global, this._messages,
-      this._emulateScopedCss) {
-    _currentInfo = _fileInfo;
-  }
-
-  void visitElement(Element node) {
-    if (node.tagName == 'script') {
-      // We already extracted script tags in previous phase.
-      return;
-    }
-
-    if (node.tagName == 'style') {
-      // We've already parsed the CSS.
-      // If this is a component remove the style node.
-      if (_currentInfo is ComponentInfo && _emulateScopedCss) node.remove();
-      return;
-    }
-
-    _bindCustomElement(node);
-
-    var lastInfo = _currentInfo;
-    if (node.tagName == 'polymer-element') {
-      // If element is invalid _ElementLoader already reported an error, but
-      // we skip the body of the element here.
-      var name = node.attributes['name'];
-      if (name == null) return;
-
-      ComponentInfo component = _fileInfo.components[name];
-      if (component == null) return;
-
-      _analyzeComponent(component);
-
-      _currentInfo = component;
-
-      // Remove the <element> tag from the tree
-      node.remove();
-    }
-
-    node.attributes.forEach((name, value) {
-      if (name.startsWith('on')) {
-        _validateEventHandler(node, name, value);
-      } else  if (name == 'pseudo' && _currentInfo is ComponentInfo) {
-        // Any component's custom pseudo-element(s) defined?
-        _processPseudoAttribute(node, value.split(' '));
-      }
-    });
-
-    var keepSpaces = _keepIndentationSpaces;
-    if (node.tagName == 'template' &&
-        node.attributes.containsKey('indentation')) {
-      var value = node.attributes['indentation'];
-      if (value != 'remove' && value != 'preserve') {
-        _messages.warning(
-            "Invalid value for 'indentation' ($value). By default we preserve "
-            "the indentation. Valid values are either 'remove' or 'preserve'.",
-            node.sourceSpan);
-      }
-      _keepIndentationSpaces = value != 'remove';
-    }
-
-    // Invoke super to visit children.
-    super.visitElement(node);
-
-    _keepIndentationSpaces = keepSpaces;
-    _currentInfo = lastInfo;
-  }
-
-  void _analyzeComponent(ComponentInfo component) {
-    var baseTag = component.extendsTag;
-    component.extendsComponent = baseTag == null ? null
-        : _fileInfo.components[baseTag];
-    if (component.extendsComponent == null && isCustomTag(baseTag)) {
-      _messages.warning(
-          'custom element with tag name ${component.extendsTag} not found.',
-          component.element.sourceSpan);
-    }
-  }
-
-  void _bindCustomElement(Element node) {
-    // <fancy-button>
-    var component = _fileInfo.components[node.tagName];
-    if (component == null) {
-      // TODO(jmesserly): warn for unknown element tags?
-
-      // <button is="fancy-button">
-      var componentName = node.attributes['is'];
-      if (componentName != null) {
-        component = _fileInfo.components[componentName];
-      } else if (isCustomTag(node.tagName)) {
-        componentName = node.tagName;
-      }
-      if (component == null && componentName != null &&
-          componentName != 'polymer-element') {
-        _messages.warning(
-            'custom element with tag name $componentName not found.',
-            node.sourceSpan);
-      }
-    }
-
-    if (component != null) {
-      var baseTag = component.baseExtendsTag;
-      var nodeTag = node.tagName;
-      var hasIsAttribute = node.attributes.containsKey('is');
-
-      if (baseTag != null && !hasIsAttribute) {
-        _messages.warning(
-            'custom element "${component.tagName}" extends from "$baseTag", but'
-            ' this tag will not include the default properties of "$baseTag". '
-            'To fix this, either write this tag as <$baseTag '
-            'is="${component.tagName}"> or remove the "extends" attribute from '
-            'the custom element declaration.', node.sourceSpan);
-      } else if (hasIsAttribute) {
-        if (baseTag == null) {
-          _messages.warning(
-              'custom element "${component.tagName}" doesn\'t declare any type '
-              'extensions. To fix this, either rewrite this tag as '
-              '<${component.tagName}> or add \'extends="$nodeTag"\' to '
-              'the custom element declaration.', node.sourceSpan);
-        } else if (baseTag != nodeTag) {
-          _messages.warning(
-              'custom element "${component.tagName}" extends from "$baseTag". '
-              'Did you mean to write <$baseTag is="${component.tagName}">?',
-              node.sourceSpan);
-        }
-      }
-    }
-  }
-
-  void _processPseudoAttribute(Node node, List<String> values) {
-    List mangledValues = [];
-    for (var pseudoElement in values) {
-      if (_global.pseudoElements.containsKey(pseudoElement)) continue;
-
-      _uniqueIds.moveNext();
-      var newValue = "${pseudoElement}_${_uniqueIds.current}";
-      _global.pseudoElements[pseudoElement] = newValue;
-      // Mangled name of pseudo-element.
-      mangledValues.add(newValue);
-
-      if (!pseudoElement.startsWith('x-')) {
-        // TODO(terry): The name must start with x- otherwise it's not a custom
-        //              pseudo-element.  May want to relax since components no
-        //              longer need to start with x-.  See isse #509 on
-        //              pseudo-element prefix.
-        _messages.warning("Custom pseudo-element must be prefixed with 'x-'.",
-            node.sourceSpan);
-      }
-    }
-
-    // Update the pseudo attribute with the new mangled names.
-    node.attributes['pseudo'] = mangledValues.join(' ');
-  }
-
-  /**
-   * Support for inline event handlers that take expressions.
-   * For example: `on-double-click=myHandler($event, todo)`.
-   */
-  void _validateEventHandler(Element node, String name, String value) {
-    if (!name.startsWith('on-')) {
-      // TODO(jmesserly): do we need an option to suppress this warning?
-      _messages.warning('Event handler $name will be interpreted as an inline '
-          'JavaScript event handler. Use the form '
-          'on-event-name="handlerName" if you want a Dart handler '
-          'that will automatically update the UI based on model changes.',
-          node.sourceSpan);
-    }
-
-    if (value.contains('.') || value.contains('(')) {
-      // TODO(sigmund): should we allow more if we use fancy-syntax?
-      _messages.warning('Invalid event handler body "$value". Declare a method '
-          'in your custom element "void handlerName(event, detail, target)" '
-          'and use the form on-event-name="handlerName".',
-          node.sourceSpan);
-    }
-  }
-
-  /**
-   * Normalizes references in [info]. On the [analyzeDefinitions] phase, the
-   * analyzer extracted names of files and components. Here we link those names
-   * to actual info classes. In particular:
-   *   * we initialize the [FileInfo.components] map in [info] by importing all
-   *     [declaredComponents],
-   *   * we scan all [info.componentLinks] and import their
-   *     [info.declaredComponents], using [files] to map the href to the file
-   *     info. Names in [info] will shadow names from imported files.
-   */
-  void _normalize(FileInfo info, Map<String, FileInfo> files) {
-    for (var component in info.declaredComponents) {
-      _addComponent(info, component);
-    }
-
-    for (var link in info.componentLinks) {
-      var file = files[link.resolvedPath];
-      // We already issued an error for missing files.
-      if (file == null) continue;
-      file.declaredComponents.forEach((c) => _addComponent(info, c));
-    }
-  }
-
-  /** Adds a component's tag name to the names in scope for [fileInfo]. */
-  void _addComponent(FileInfo fileInfo, ComponentInfo component) {
-    var existing = fileInfo.components[component.tagName];
-    if (existing != null) {
-      if (existing == component) {
-        // This is the same exact component as the existing one.
-        return;
-      }
-
-      if (existing is ComponentInfo && component is! ComponentInfo) {
-        // Components declared in [fileInfo] shadow component names declared in
-        // imported files.
-        return;
-      }
-
-      if (existing.hasConflict) {
-        // No need to report a second error for the same name.
-        return;
-      }
-
-      existing.hasConflict = true;
-
-      if (component is ComponentInfo) {
-        _messages.error('duplicate custom element definition for '
-            '"${component.tagName}".', existing.sourceSpan);
-        _messages.error('duplicate custom element definition for '
-            '"${component.tagName}" (second location).', component.sourceSpan);
-      } else {
-        _messages.error('imported duplicate custom element definitions '
-            'for "${component.tagName}".', existing.sourceSpan);
-        _messages.error('imported duplicate custom element definitions '
-            'for "${component.tagName}" (second location).',
-            component.sourceSpan);
-      }
-    } else {
-      fileInfo.components[component.tagName] = component;
-    }
-  }
-}
-
-/** A visitor that finds `<link rel="import">` and `<element>` tags.  */
-class _ElementLoader extends TreeVisitor {
-  final GlobalInfo _global;
-  final FileInfo _fileInfo;
-  LibraryInfo _currentInfo;
-  String _packageRoot;
-  bool _inHead = false;
-  Messages _messages;
-
-  /**
-   * Adds emitted warning/error messages to [_messages]. [_messages]
-   * must not be null.
-   */
-  _ElementLoader(this._global, this._fileInfo, this._packageRoot,
-      this._messages) {
-    _currentInfo = _fileInfo;
-  }
-
-  void visitElement(Element node) {
-    switch (node.tagName) {
-      case 'link': visitLinkElement(node); break;
-      case 'element':
-        _messages.warning('<element> elements are not supported, use'
-            ' <polymer-element> instead', node.sourceSpan);
-        break;
-      case 'polymer-element':
-         visitElementElement(node);
-         break;
-      case 'script': visitScriptElement(node); break;
-      case 'head':
-        var savedInHead = _inHead;
-        _inHead = true;
-        super.visitElement(node);
-        _inHead = savedInHead;
-        break;
-      default: super.visitElement(node); break;
-    }
-  }
-
-  /**
-   * Process `link rel="import"` as specified in:
-   * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/components/index.html#link-type-component>
-   */
-  void visitLinkElement(Element node) {
-    var rel = node.attributes['rel'];
-    if (rel != 'component' && rel != 'components' &&
-        rel != 'import' && rel != 'stylesheet') return;
-
-    if (!_inHead) {
-      _messages.warning('link rel="$rel" only valid in '
-          'head.', node.sourceSpan);
-      return;
-    }
-
-    if (rel == 'component' || rel == 'components') {
-      _messages.warning('import syntax is changing, use '
-          'rel="import" instead of rel="$rel".', node.sourceSpan);
-    }
-
-    var href = node.attributes['href'];
-    if (href == null || href == '') {
-      _messages.warning('link rel="$rel" missing href.',
-          node.sourceSpan);
-      return;
-    }
-
-    bool isStyleSheet = rel == 'stylesheet';
-    var urlInfo = UrlInfo.resolve(href, _fileInfo.inputUrl, node.sourceSpan,
-        _packageRoot, _messages, ignoreAbsolute: isStyleSheet);
-    if (urlInfo == null) return;
-    if (isStyleSheet) {
-      _fileInfo.styleSheetHrefs.add(urlInfo);
-    } else {
-      _fileInfo.componentLinks.add(urlInfo);
-    }
-  }
-
-  void visitElementElement(Element node) {
-    // TODO(jmesserly): what do we do in this case? It seems like an <element>
-    // inside a Shadow DOM should be scoped to that <template> tag, and not
-    // visible from the outside.
-    if (_currentInfo is ComponentInfo) {
-      _messages.error('Nested component definitions are not yet supported.',
-          node.sourceSpan);
-      return;
-    }
-
-    var tagName = node.attributes['name'];
-    var extendsTag = node.attributes['extends'];
-
-    if (tagName == null) {
-      _messages.error('Missing tag name of the component. Please include an '
-          'attribute like \'name="your-tag-name"\'.',
-          node.sourceSpan);
-      return;
-    }
-
-    var component = new ComponentInfo(node, tagName, extendsTag);
-    _fileInfo.declaredComponents.add(component);
-    _addComponent(component);
-
-    var lastInfo = _currentInfo;
-    _currentInfo = component;
-    super.visitElement(node);
-    _currentInfo = lastInfo;
-  }
-
-  /** Adds a component's tag name to the global list. */
-  void _addComponent(ComponentInfo component) {
-    var existing = _global.components[component.tagName];
-    if (existing != null) {
-      if (existing.hasConflict) {
-        // No need to report a second error for the same name.
-        return;
-      }
-
-      existing.hasConflict = true;
-
-      _messages.error('duplicate custom element definition for '
-          '"${component.tagName}".', existing.sourceSpan);
-      _messages.error('duplicate custom element definition for '
-          '"${component.tagName}" (second location).', component.sourceSpan);
-    } else {
-      _global.components[component.tagName] = component;
-    }
-  }
-
-  void visitScriptElement(Element node) {
-    var scriptType = node.attributes['type'];
-    var src = node.attributes["src"];
-
-    if (scriptType == null) {
-      // Note: in html5 leaving off type= is fine, but it defaults to
-      // text/javascript. Because this might be a common error, we warn about it
-      // in two cases:
-      //   * an inline script tag in a web component
-      //   * a script src= if the src file ends in .dart (component or not)
-      //
-      // The hope is that neither of these cases should break existing valid
-      // code, but that they'll help component authors avoid having their Dart
-      // code accidentally interpreted as JavaScript by the browser.
-      if (src == null && _currentInfo is ComponentInfo) {
-        _messages.warning('script tag in component with no type will '
-            'be treated as JavaScript. Did you forget type="application/dart"?',
-            node.sourceSpan);
-      }
-      if (src != null && src.endsWith('.dart')) {
-        _messages.warning('script tag with .dart source file but no type will '
-            'be treated as JavaScript. Did you forget type="application/dart"?',
-            node.sourceSpan);
-      }
-      return;
-    }
-
-    if (scriptType != 'application/dart') return;
-
-    if (src != null) {
-      if (!src.endsWith('.dart')) {
-        _messages.warning('"application/dart" scripts should '
-            'use the .dart file extension.',
-            node.sourceSpan);
-      }
-
-      if (node.innerHtml.trim() != '') {
-        _messages.error('script tag has "src" attribute and also has script '
-            'text.', node.sourceSpan);
-      }
-    }
-  }
-}
diff --git a/pkg/polymer/lib/src/transform/code_extractor.dart b/pkg/polymer/lib/src/build/code_extractor.dart
similarity index 93%
rename from pkg/polymer/lib/src/transform/code_extractor.dart
rename to pkg/polymer/lib/src/build/code_extractor.dart
index a46300e..5e9135d 100644
--- a/pkg/polymer/lib/src/transform/code_extractor.dart
+++ b/pkg/polymer/lib/src/build/code_extractor.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /** Transfomer that extracts inlined script code into separate assets. */
-library polymer.src.transformers;
+library polymer.src.build.code_extractor;
 
 import 'dart:async';
 
@@ -20,7 +20,11 @@
  * Transformer that extracts Dart code inlined in HTML script tags and outputs a
  * separate file for each.
  */
-class InlineCodeExtractor extends Transformer {
+class InlineCodeExtractor extends Transformer with PolymerTransformer {
+  final TransformOptions options;
+
+  InlineCodeExtractor(this.options);
+
   /** Only run this transformer on .html files. */
   final String allowedExtensions = ".html";
 
diff --git a/pkg/polymer/lib/src/transform/common.dart b/pkg/polymer/lib/src/build/common.dart
similarity index 67%
rename from pkg/polymer/lib/src/transform/common.dart
rename to pkg/polymer/lib/src/build/common.dart
index e18a053..6233aa3 100644
--- a/pkg/polymer/lib/src/transform/common.dart
+++ b/pkg/polymer/lib/src/build/common.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /** Common methods used by transfomers. */
-library polymer.src.transform.common;
+library polymer.src.build.common;
 
 import 'dart:async';
 
@@ -34,23 +34,50 @@
   return document;
 }
 
-Future<Document> readPrimaryAsHtml(Transform transform) {
-  var asset = transform.primaryInput;
-  var id = asset.id;
-  return asset.readAsString().then((content) {
-    return _parseHtml(content, id.path, transform.logger,
-      checkDocType: isPrimaryHtml(id));
-  });
+/** Additional options used by polymer transformers */
+class TransformOptions {
+  String currentPackage;
+  List<String> entryPoints;
+
+  TransformOptions([this.currentPackage, entryPoints])
+      : entryPoints = entryPoints == null ? null
+          : entryPoints.map(_systemToAssetPath).toList();
+
+  /** Whether an asset with [id] is an entry point HTML file. */
+  bool isHtmlEntryPoint(AssetId id) {
+    if (id.extension != '.html') return false;
+
+    // Note: [id.path] is a relative path from the root of a package.
+    if (currentPackage == null || entryPoints == null) {
+      return id.path.startsWith('web/') || id.path.startsWith('test/');
+    }
+
+    return id.package == currentPackage && entryPoints.contains(id.path);
+  }
 }
 
-Future<Document> readAsHtml(AssetId id, Transform transform) {
-  var primaryId = transform.primaryInput.id;
-  var url = (id.package == primaryId.package) ? id.path
-      : assetUrlFor(id, primaryId, transform.logger, allowAssetUrl: true);
-  return transform.readInputAsString(id).then((content) {
-    return _parseHtml(content, url, transform.logger,
-      checkDocType: isPrimaryHtml(id));
-  });
+/** Mixin for polymer transformers. */
+abstract class PolymerTransformer {
+  TransformOptions get options;
+
+  Future<Document> readPrimaryAsHtml(Transform transform) {
+    var asset = transform.primaryInput;
+    var id = asset.id;
+    return asset.readAsString().then((content) {
+      return _parseHtml(content, id.path, transform.logger,
+        checkDocType: options.isHtmlEntryPoint(id));
+    });
+  }
+
+  Future<Document> readAsHtml(AssetId id, Transform transform) {
+    var primaryId = transform.primaryInput.id;
+    var url = (id.package == primaryId.package) ? id.path
+        : assetUrlFor(id, primaryId, transform.logger, allowAssetUrl: true);
+    return transform.readInputAsString(id).then((content) {
+      return _parseHtml(content, url, transform.logger,
+        checkDocType: options.isHtmlEntryPoint(id));
+    });
+  }
 }
 
 /** Create an [AssetId] for a [url] seen in the [source] asset. */
@@ -92,11 +119,6 @@
   return new AssetId(package, targetPath);
 }
 
-/** Whether an asset with [id] is considered a primary entry point HTML file. */
-bool isPrimaryHtml(AssetId id) => id.extension == '.html' &&
-    // Note: [id.path] is a relative path from the root of a package.
-    (id.path.startsWith('web/') || id.path.startsWith('test/'));
-
 /**
  * Generate the import url for a file described by [id], referenced by a file
  * with [sourceId].
@@ -128,3 +150,10 @@
   return builder.relative(builder.join('/', id.path),
       from: builder.join('/', builder.dirname(sourceId.path)));
 }
+
+
+/** Convert system paths to asset paths (asset paths are posix style). */
+String _systemToAssetPath(String assetPath) {
+  if (path.Style.platform != path.Style.windows) return assetPath;
+  return path.posix.joinAll(path.split(assetPath));
+}
diff --git a/pkg/polymer/lib/src/transform/import_inliner.dart b/pkg/polymer/lib/src/build/import_inliner.dart
similarity index 95%
rename from pkg/polymer/lib/src/transform/import_inliner.dart
rename to pkg/polymer/lib/src/build/import_inliner.dart
index 889ce20..987fe9f 100644
--- a/pkg/polymer/lib/src/transform/import_inliner.dart
+++ b/pkg/polymer/lib/src/build/import_inliner.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /** Transfomer that inlines polymer-element definitions from html imports. */
-library polymer.src.transform.import_inliner;
+library polymer.src.build.import_inliner;
 
 import 'dart:async';
 
@@ -16,10 +16,14 @@
 /** Recursively inlines polymer-element definitions from html imports. */
 // TODO(sigmund): make sure we match semantics of html-imports for tags other
 // than polymer-element (see dartbug.com/12613).
-class ImportedElementInliner extends Transformer {
+class ImportedElementInliner extends Transformer with PolymerTransformer {
+  final TransformOptions options;
+
+  ImportedElementInliner(this.options);
+
   /** Only run on entry point .html files. */
   Future<bool> isPrimary(Asset input) =>
-      new Future.value(isPrimaryHtml(input.id));
+      new Future.value(options.isHtmlEntryPoint(input.id));
 
   Future apply(Transform transform) {
     var seen = new Set<AssetId>();
diff --git a/pkg/polymer/lib/src/linter.dart b/pkg/polymer/lib/src/build/linter.dart
similarity index 91%
rename from pkg/polymer/lib/src/linter.dart
rename to pkg/polymer/lib/src/build/linter.dart
index f443603..f65741a 100644
--- a/pkg/polymer/lib/src/linter.dart
+++ b/pkg/polymer/lib/src/build/linter.dart
@@ -6,8 +6,9 @@
  * Logic to validate that developers are correctly using Polymer constructs.
  * This is mainly used to produce warnings for feedback in the editor.
  */
-library polymer.src.linter;
+library polymer.src.build.linter;
 
+import 'dart:io';
 import 'dart:async';
 import 'dart:mirrors';
 import 'dart:convert' show JSON;
@@ -16,7 +17,7 @@
 import 'package:html5lib/dom.dart';
 import 'package:html5lib/dom_parsing.dart';
 
-import 'transform/common.dart';
+import 'common.dart';
 
 typedef String MessageFormatter(String kind, String message, Span span);
 
@@ -25,13 +26,15 @@
  * show on the editor or the command line. Leaves sources unchanged, but creates
  * a new asset containing all the warnings.
  */
-class Linter extends Transformer {
+class Linter extends Transformer with PolymerTransformer {
+  final TransformOptions options;
+
   /** Only run on .html files. */
   final String allowedExtensions = '.html';
 
   final MessageFormatter _formatter;
 
-  Linter([this._formatter]);
+  Linter(this.options, [this._formatter]);
 
   Future apply(Transform transform) {
     var wrapper = new _LoggerInterceptor(transform, _formatter);
@@ -120,7 +123,7 @@
   final MessageFormatter _formatter;
 
   _LoggerInterceptor(this._original, MessageFormatter formatter)
-      : _formatter = formatter == null ? _defaultFormatter : formatter;
+      : _formatter = formatter == null ? consoleFormatter : formatter;
 
   TransformLogger get logger => this;
 
@@ -137,10 +140,10 @@
 }
 
 /**
- * Default formatter that generates messages using a format that can be parsed
+ * Formatter that generates messages using a format that can be parsed
  * by tools, such as the Dart Editor, for reporting error messages.
  */
-String _defaultFormatter(String kind, String message, Span span) {
+String jsonFormatter(String kind, String message, Span span) {
   return JSON.encode((span == null)
       ? [{'method': 'warning', 'params': {'message': message}}]
       : [{'method': kind,
@@ -153,6 +156,26 @@
           }}]);
 }
 
+/**
+ * Formatter that generates messages that are easy to read on the console (used
+ * by default).
+ */
+String consoleFormatter(String kind, String message, Span span) {
+  var useColors = stdioType(stdout) == StdioType.TERMINAL;
+  var levelColor = (kind == 'error') ? _RED_COLOR : _MAGENTA_COLOR;
+  var output = new StringBuffer();
+  if (useColors) output.write(levelColor);
+  output..write(kind)..write(' ');
+  if (useColors) output.write(_NO_COLOR);
+  if (span == null) {
+    output.write(message);
+  } else {
+    output.write(span.getLocationMessage(message,
+          useColors: useColors,
+          color: levelColor));
+  }
+  return output.toString();
+}
 
 /**
  * Information needed about other polymer-element tags in order to validate
@@ -415,3 +438,7 @@
   if (name == null || !name.contains('-')) return false;
   return !_invalidTagNames.containsKey(name);
 }
+
+final String _RED_COLOR = '\u001b[31m';
+final String _MAGENTA_COLOR = '\u001b[35m';
+final String _NO_COLOR = '\u001b[0m';
diff --git a/pkg/polymer/lib/src/transform/polyfill_injector.dart b/pkg/polymer/lib/src/build/polyfill_injector.dart
similarity index 91%
rename from pkg/polymer/lib/src/transform/polyfill_injector.dart
rename to pkg/polymer/lib/src/build/polyfill_injector.dart
index 6b95113..7c3d3cf 100644
--- a/pkg/polymer/lib/src/transform/polyfill_injector.dart
+++ b/pkg/polymer/lib/src/build/polyfill_injector.dart
@@ -6,7 +6,7 @@
  * Final phase of the polymer transformation: includes any additional polyfills
  * that may needed by the deployed app.
  */
-library polymer.src.transform.polyfill_injector;
+library polymer.src.build.polyfill_injector;
 
 import 'dart:async';
 
@@ -21,10 +21,14 @@
  * script tag that loads the shadow_dom polyfill and interop.js (used for the
  * css shimming).
  */
-class PolyfillInjector extends Transformer {
+class PolyfillInjector extends Transformer with PolymerTransformer {
+  final TransformOptions options;
+
+  PolyfillInjector(this.options);
+
   /** Only run on entry point .html files. */
   Future<bool> isPrimary(Asset input) =>
-      new Future.value(isPrimaryHtml(input.id));
+      new Future.value(options.isHtmlEntryPoint(input.id));
 
   Future apply(Transform transform) {
     return readPrimaryAsHtml(transform).then((document) {
diff --git a/pkg/polymer/lib/src/build/runner.dart b/pkg/polymer/lib/src/build/runner.dart
new file mode 100644
index 0000000..d940c18
--- /dev/null
+++ b/pkg/polymer/lib/src/build/runner.dart
@@ -0,0 +1,312 @@
+// 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.
+
+/**
+ * Definitions used to run the polymer linter and deploy tools without using
+ * pub serve or pub deploy.
+ */
+library polymer.src.build.runner;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:barback/barback.dart';
+import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
+import 'package:yaml/yaml.dart';
+
+
+/** Collects different parameters needed to configure and run barback. */
+class BarbackOptions {
+  /** Phases of transformers to run. */
+  final List<List<Transformer>> phases;
+
+  /** Package to treat as the current package in barback. */
+  final String currentPackage;
+
+  /**
+   * Mapping between package names and the path in the file system where
+   * to find the sources of such package.
+   */
+  final Map<String, String> packageDirs;
+
+  /** Whether to run transformers on the test folder. */
+  final bool transformTests;
+
+  /** Whether to apply transformers on polymer dependencies. */
+  final bool transformPolymerDependencies;
+
+  /** Directory where to generate code, if any. */
+  final String outDir;
+
+  BarbackOptions(this.phases, this.outDir, {currentPackage, packageDirs,
+      this.transformTests: false, this.transformPolymerDependencies: false})
+      : currentPackage = (currentPackage != null
+          ? currentPackage : readCurrentPackageFromPubspec()),
+        packageDirs = (packageDirs != null
+          ? packageDirs : _readPackageDirsFromPub(currentPackage));
+
+}
+
+/**
+ * Creates a barback system as specified by [options] and runs it.  Returns a
+ * future that contains the list of assets generated after barback runs to
+ * completion.
+ */
+Future<AssetSet> runBarback(BarbackOptions options) {
+  var barback = new Barback(new _PolymerPackageProvider(options.packageDirs));
+  _initBarback(barback, options);
+  _attachListeners(barback);
+  if (options.outDir == null) return barback.getAllAssets();
+  return _emitAllFiles(barback, options);
+}
+
+/** Extract the current package from the pubspec.yaml file. */
+String readCurrentPackageFromPubspec() {
+  var pubspec = new File('pubspec.yaml');
+  if (!pubspec.existsSync()) {
+    print('error: pubspec.yaml file not found, please run this script from '
+        'your package root directory.');
+    return null;
+  }
+  return loadYaml(pubspec.readAsStringSync())['name'];
+}
+
+/**
+ * Extract a mapping between package names and the path in the file system where
+ * to find the sources of such package. This map will contain an entry for the
+ * current package and everything it depends on (extracted via `pub
+ * list-pacakge-dirs`).
+ */
+Map<String, String> _readPackageDirsFromPub(String currentPackage) {
+  var dartExec = new Options().executable;
+  // If dartExec == dart, then dart and pub are in standard PATH.
+  var sdkDir = dartExec == 'dart' ? '' : path.dirname(dartExec);
+  var pub = path.join(sdkDir, Platform.isWindows ? 'pub.bat' : 'pub');
+  var result = Process.runSync(pub, ['list-package-dirs']);
+  if (result.exitCode != 0) {
+    print("unexpected error invoking 'pub':");
+    print(result.stdout);
+    print(result.stderr);
+    exit(result.exitCode);
+  }
+  var map = JSON.decode(result.stdout)["packages"];
+  map.forEach((k, v) { map[k] = path.dirname(v); });
+  map[currentPackage] = '.';
+  return map;
+}
+
+/** Internal packages used by polymer. */
+// TODO(sigmund): consider computing this list by recursively parsing
+// pubspec.yaml files in the `Options.packageDirs`.
+final Set<String> _polymerPackageDependencies = [
+    'analyzer_experimental', 'args', 'barback', 'browser', 'csslib',
+    'custom_element', 'fancy_syntax', 'html5lib', 'html_import', 'js',
+    'logging', 'mdv', 'meta', 'mutation_observer', 'observe', 'path', 'polymer',
+    'polymer_expressions', 'serialization', 'shadow_dom', 'source_maps',
+    'stack_trace', 'unittest', 'unmodifiable_collection', 'yaml'].toSet();
+
+/** Return the relative path of each file under [subDir] in [package]. */
+Iterable<String> _listPackageDir(String package, String subDir,
+    BarbackOptions options) {
+  var packageDir = options.packageDirs[package];
+  if (packageDir == null) return const [];
+  var dir = new Directory(path.join(packageDir, subDir));
+  if (!dir.existsSync()) return const [];
+  return dir.listSync(recursive: true, followLinks: false)
+      .where((f) => f is File)
+      .map((f) => path.relative(f.path, from: packageDir));
+}
+
+/** A simple provider that reads files directly from the pub cache. */
+class _PolymerPackageProvider implements PackageProvider {
+  Map<String, String> packageDirs;
+  Iterable<String> get packages => packageDirs.keys;
+
+  _PolymerPackageProvider(this.packageDirs);
+
+  Future<Asset> getAsset(AssetId id) => new Future.value(
+      new Asset.fromPath(id, path.join(packageDirs[id.package],
+      _toSystemPath(id.path))));
+}
+
+/** Convert asset paths to system paths (Assets always use the posix style). */
+String _toSystemPath(String assetPath) {
+  if (path.Style.platform != path.Style.windows) return assetPath;
+  return path.joinAll(path.posix.split(assetPath));
+}
+
+/** Tell barback which transformers to use and which assets to process. */
+void _initBarback(Barback barback, BarbackOptions options) {
+  var assets = [];
+  void addAssets(String package, String subDir) {
+    for (var filepath in _listPackageDir(package, subDir, options)) {
+      assets.add(new AssetId(package, filepath));
+    }
+  }
+
+  for (var package in options.packageDirs.keys) {
+    // There is nothing to do in the 'polymer' package and its dependencies.
+    if (!options.transformPolymerDependencies &&
+        _polymerPackageDependencies.contains(package)) continue;
+    barback.updateTransformers(package, options.phases);
+
+    // Notify barback to process anything under 'lib' and 'asset'.
+    addAssets(package, 'lib');
+    addAssets(package, 'asset');
+  }
+
+  // In case of the current package, include also 'web'.
+  addAssets(options.currentPackage, 'web');
+  if (options.transformTests) addAssets(options.currentPackage, 'test');
+
+  barback.updateSources(assets);
+}
+
+/** Attach error listeners on [barback] so we can report errors. */
+void _attachListeners(Barback barback) {
+  // Listen for errors and results
+  barback.errors.listen((e) {
+    var trace = getAttachedStackTrace(e);
+    if (trace != null) {
+      print(Trace.format(trace));
+    }
+    print('error running barback: $e');
+    exit(1);
+  });
+
+  barback.results.listen((result) {
+    if (!result.succeeded) {
+      print("build failed with errors: ${result.errors}");
+      exit(1);
+    }
+  });
+}
+
+/**
+ * Emits all outputs of [barback] and copies files that we didn't process (like
+ * polymer's libraries).
+ */
+Future _emitAllFiles(Barback barback, BarbackOptions options) {
+  return barback.getAllAssets().then((assets) {
+    // Delete existing output folder before we generate anything
+    var dir = new Directory(options.outDir);
+    if (dir.existsSync()) dir.deleteSync(recursive: true);
+    return _emitPackagesDir(options)
+      .then((_) => _emitTransformedFiles(assets, options))
+      .then((_) => _addPackagesSymlinks(assets, options))
+      .then((_) => assets);
+  });
+}
+
+Future _emitTransformedFiles(AssetSet assets, BarbackOptions options) {
+  // Copy all the assets we transformed
+  var futures = [];
+  var currentPackage = options.currentPackage;
+  var transformTests = options.transformTests;
+  var outPackages = path.join(options.outDir, 'packages');
+  for (var asset in assets) {
+    var id = asset.id;
+    var dir = _firstDir(id.path);
+    if (dir == null) continue;
+
+    var filepath;
+    if (dir == 'lib') {
+      // Put lib files directly under the packages folder (e.g. 'lib/foo.dart'
+      // will be emitted at out/packages/package_name/foo.dart).
+      filepath = path.join(outPackages, id.package,
+          _toSystemPath(id.path.substring(4)));
+    } else if (id.package == currentPackage &&
+        (dir == 'web' || (transformTests && dir == 'test'))) {
+      filepath = path.join(options.outDir, _toSystemPath(id.path));
+    } else {
+      // TODO(sigmund): do something about other assets?
+      continue;
+    }
+
+    futures.add(_writeAsset(filepath, asset));
+  }
+  return Future.wait(futures);
+}
+
+/**
+ * Adds a package symlink from each directory under `out/web/foo/` to
+ * `out/packages`.
+ */
+Future _addPackagesSymlinks(AssetSet assets, BarbackOptions options) {
+  var outPackages = path.join(options.outDir, 'packages');
+  var currentPackage = options.currentPackage;
+  for (var asset in assets) {
+    var id = asset.id;
+    if (id.package != currentPackage) continue;
+    var firstDir = _firstDir(id.path);
+    if (firstDir == null) continue;
+
+    if (firstDir == 'web' || (options.transformTests && firstDir == 'test')) {
+      var dir = path.join(options.outDir, path.dirname(_toSystemPath(id.path)));
+      var linkPath = path.join(dir, 'packages');
+      var link = new Link(linkPath);
+      if (!link.existsSync()) {
+        var targetPath = Platform.operatingSystem == 'windows'
+            ? path.normalize(path.absolute(outPackages))
+            : path.normalize(path.relative(outPackages, from: dir));
+        link.createSync(targetPath);
+      }
+    }
+  }
+}
+
+/**
+ * Emits a 'packages' directory directly under `out/packages` with the contents
+ * of every file that was not transformed by barback.
+ */
+Future _emitPackagesDir(BarbackOptions options) {
+  if (options.transformPolymerDependencies) return new Future.value(null);
+  var outPackages = path.join(options.outDir, 'packages');
+  _ensureDir(outPackages);
+
+  // Copy all the files we didn't process
+  var futures = [];
+  var dirs = options.packageDirs;
+  for (var package in _polymerPackageDependencies) {
+    for (var relpath in _listPackageDir(package, 'lib', options)) {
+      var inpath = path.join(dirs[package], relpath);
+      var outpath = path.join(outPackages, package, relpath.substring(4));
+      futures.add(_copyFile(inpath, outpath));
+    }
+  }
+  return Future.wait(futures);
+}
+
+/** Ensure [dirpath] exists. */
+void _ensureDir(String dirpath) {
+  new Directory(dirpath).createSync(recursive: true);
+}
+
+/**
+ * Returns the first directory name on a url-style path, or null if there are no
+ * slashes.
+ */
+String _firstDir(String url) {
+  var firstSlash = url.indexOf('/');
+  if (firstSlash == -1) return null;
+  return url.substring(0, firstSlash);
+}
+
+/** Copy a file from [inpath] to [outpath]. */
+Future _copyFile(String inpath, String outpath) {
+  _ensureDir(path.dirname(outpath));
+  var writer = new File(outpath).openWrite();
+  return writer.addStream(new File(inpath).openRead())
+      .then((_) => writer.close());
+}
+
+/** Write contents of an [asset] into a file at [filepath]. */
+Future _writeAsset(String filepath, Asset asset) {
+  _ensureDir(path.dirname(filepath));
+  var writer = new File(filepath).openWrite();
+  return writer.addStream(asset.read()).then((_) => writer.close());
+}
diff --git a/pkg/polymer/lib/src/transform/script_compactor.dart b/pkg/polymer/lib/src/build/script_compactor.dart
similarity index 93%
rename from pkg/polymer/lib/src/transform/script_compactor.dart
rename to pkg/polymer/lib/src/build/script_compactor.dart
index c247f2d..a20fcd6 100644
--- a/pkg/polymer/lib/src/transform/script_compactor.dart
+++ b/pkg/polymer/lib/src/build/script_compactor.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /** Transfomer that combines multiple dart script tags into a single one. */
-library polymer.src.transform.script_compactor;
+library polymer.src.build.script_compactor;
 
 import 'dart:async';
 
@@ -27,10 +27,14 @@
  * invoke the main method on each of these libraries and register any polymer
  * elements annotated with `@CustomTag`.
  */
-class ScriptCompactor extends Transformer {
+class ScriptCompactor extends Transformer with PolymerTransformer {
+  final TransformOptions options;
+
+  ScriptCompactor(this.options);
+
   /** Only run on entry point .html files. */
   Future<bool> isPrimary(Asset input) =>
-      new Future.value(isPrimaryHtml(input.id));
+      new Future.value(options.isHtmlEntryPoint(input.id));
 
   Future apply(Transform transform) {
     var id = transform.primaryInput.id;
@@ -47,7 +51,7 @@
             continue;
           }
           var last = src.split('/').last;
-          if (last == 'dart.js' || last == 'testing.js') {
+          if (last == 'dart.js') {
             dartLoaderTag = tag;
           }
         }
diff --git a/pkg/polymer/lib/src/compiler.dart b/pkg/polymer/lib/src/compiler.dart
deleted file mode 100644
index 9d5d10d..0000000
--- a/pkg/polymer/lib/src/compiler.dart
+++ /dev/null
@@ -1,360 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library compiler;
-
-import 'dart:async';
-import 'dart:collection' show SplayTreeMap;
-
-import 'package:csslib/visitor.dart' show StyleSheet, treeToDebugString;
-import 'package:html5lib/dom.dart';
-import 'package:html5lib/parser.dart';
-
-import 'analyzer.dart';
-import 'css_analyzer.dart' show analyzeCss, findUrlsImported,
-       findImportsInStyleSheet, parseCss;
-import 'css_emitters.dart' show rewriteCssUris,
-       emitComponentStyleSheet, emitOriginalCss, emitStyleSheet;
-import 'file_system.dart';
-import 'files.dart';
-import 'info.dart';
-import 'messages.dart';
-import 'compiler_options.dart';
-import 'utils.dart';
-
-/**
- * Parses an HTML file [contents] and returns a DOM-like tree.
- * Note that [contents] will be a [String] if coming from a browser-based
- * [FileSystem], or it will be a [List<int>] if running on the command line.
- *
- * Adds emitted error/warning to [messages], if [messages] is supplied.
- */
-Document parseHtml(contents, String sourcePath, Messages messages,
-    bool checkDocType) {
-  var parser = new HtmlParser(contents, generateSpans: true,
-      sourceUrl: sourcePath);
-  var document = parser.parse();
-
-  // Note: errors aren't fatal in HTML (unless strict mode is on).
-  // So just print them as warnings.
-  for (var e in parser.errors) {
-    if (checkDocType || e.errorCode != 'expected-doctype-but-got-start-tag') {
-      messages.warning(e.message, e.span);
-    }
-  }
-  return document;
-}
-
-/** Compiles an application written with Dart web components. */
-class Compiler {
-  final FileSystem fileSystem;
-  final CompilerOptions options;
-  final List<SourceFile> files = <SourceFile>[];
-
-  String _mainPath;
-  String _packageRoot;
-  String _resetCssFile;
-  StyleSheet _cssResetStyleSheet;
-  Messages _messages;
-
-  FutureGroup _tasks;
-  Set _processed;
-
-  /** Information about source [files] given their href. */
-  final Map<String, FileInfo> info = new SplayTreeMap<String, FileInfo>();
-
-  final GlobalInfo global = new GlobalInfo();
-
-  /** Creates a compiler with [options] using [fileSystem]. */
-  Compiler(this.fileSystem, this.options, this._messages) {
-    _mainPath = options.inputFile;
-    var mainDir = path.dirname(_mainPath);
-    var baseDir = options.baseDir != null ? options.baseDir : mainDir;
-    _packageRoot = options.packageRoot != null ? options.packageRoot
-        : path.join(path.dirname(_mainPath), 'packages');
-
-    if (options.resetCssFile != null) {
-      _resetCssFile = options.resetCssFile;
-      if (path.isRelative(_resetCssFile)) {
-        // If CSS reset file path is relative from our current path.
-        _resetCssFile = path.resolve(_resetCssFile);
-      }
-    }
-
-    // Normalize paths - all should be relative or absolute paths.
-    if (path.isAbsolute(_mainPath) || path.isAbsolute(baseDir)
-        || path.isAbsolute(_packageRoot)) {
-      if (path.isRelative(_mainPath)) _mainPath = path.resolve(_mainPath);
-      if (path.isRelative(baseDir)) baseDir = path.resolve(baseDir);
-      if (path.isRelative(_packageRoot)) {
-        _packageRoot = path.resolve(_packageRoot);
-      }
-    }
-  }
-
-  /** Compile the application starting from the given input file. */
-  Future run() {
-    if (path.basename(_mainPath).endsWith('.dart')) {
-      _messages.error("Please provide an HTML file as your entry point.",
-          null);
-      return new Future.value(null);
-    }
-    return _parseAndDiscover(_mainPath).then((_) {
-      _analyze();
-
-      // Analyze all CSS files.
-      _time('Analyzed Style Sheets', '', () =>
-          analyzeCss(_packageRoot, files, info,
-              global.pseudoElements, _messages,
-              warningsAsErrors: options.warningsAsErrors));
-    });
-  }
-
-  /**
-   * Asynchronously parse [inputFile] and transitively discover web components
-   * to load and parse. Returns a future that completes when all files are
-   * processed.
-   */
-  Future _parseAndDiscover(String inputFile) {
-    _tasks = new FutureGroup();
-    _processed = new Set();
-    _processed.add(inputFile);
-    _tasks.add(_parseHtmlFile(new UrlInfo(inputFile, inputFile, null), true));
-    return _tasks.future;
-  }
-
-  void _processHtmlFile(UrlInfo inputUrl, SourceFile file) {
-    if (file == null) return;
-
-    bool isEntryPoint = _processed.length == 1;
-
-    files.add(file);
-
-    var fileInfo = _time('Analyzed definitions', inputUrl.url, () {
-      return analyzeDefinitions(global, inputUrl, file.document, _packageRoot,
-        _messages);
-    });
-    info[inputUrl.resolvedPath] = fileInfo;
-
-    if (isEntryPoint && _resetCssFile != null) {
-      _processed.add(_resetCssFile);
-      _tasks.add(_parseCssFile(new UrlInfo(_resetCssFile, _resetCssFile,
-          null)));
-    }
-
-    // Load component files referenced by [file].
-    for (var link in fileInfo.componentLinks) {
-      _loadFile(link, _parseHtmlFile);
-    }
-
-    // Load stylesheet files referenced by [file].
-    for (var link in fileInfo.styleSheetHrefs) {
-      _loadFile(link, _parseCssFile);
-    }
-
-    // Process any @imports inside of a <style> tag.
-    var urlInfos = findUrlsImported(fileInfo, fileInfo.inputUrl, _packageRoot,
-        file.document, _messages, options);
-    for (var urlInfo in urlInfos) {
-      _loadFile(urlInfo, _parseCssFile);
-    }
-
-    // Load .dart files being referenced in components.
-    for (var component in fileInfo.declaredComponents) {
-      // Process any @imports inside of the <style> tag in a component.
-      var urlInfos = findUrlsImported(component, fileInfo.inputUrl,
-          _packageRoot, component.element, _messages, options);
-      for (var urlInfo in urlInfos) {
-        _loadFile(urlInfo, _parseCssFile);
-      }
-    }
-  }
-
-  /**
-   * Helper function to load [urlInfo] and parse it using [loadAndParse] if it
-   * hasn't been loaded before.
-   */
-  void _loadFile(UrlInfo urlInfo, Future loadAndParse(UrlInfo inputUrl)) {
-    if (urlInfo == null) return;
-    var resolvedPath = urlInfo.resolvedPath;
-    if (!_processed.contains(resolvedPath)) {
-      _processed.add(resolvedPath);
-      _tasks.add(loadAndParse(urlInfo));
-    }
-  }
-
-  /** Parse an HTML file. */
-  Future _parseHtmlFile(UrlInfo inputUrl, [bool checkDocType = false]) {
-    var filePath = inputUrl.resolvedPath;
-    return fileSystem.readTextOrBytes(filePath)
-        .catchError((e) => _readError(e, inputUrl))
-        .then((source) {
-          if (source == null) return;
-          var file = new SourceFile(filePath);
-          file.document = _time('Parsed', filePath,
-              () => parseHtml(source, filePath, _messages, checkDocType));
-          _processHtmlFile(inputUrl, file);
-        });
-  }
-
-  /** Parse a stylesheet file. */
-  Future _parseCssFile(UrlInfo inputUrl) {
-    if (!options.emulateScopedCss) {
-      return new Future<SourceFile>.value(null);
-    }
-    var filePath = inputUrl.resolvedPath;
-    return fileSystem.readText(filePath)
-        .catchError((e) => _readError(e, inputUrl, isWarning: true))
-        .then((code) {
-          if (code == null) return;
-          var file = new SourceFile(filePath, type: SourceFile.STYLESHEET);
-          file.code = code;
-          _processCssFile(inputUrl, file);
-        });
-  }
-
-
-  SourceFile _readError(error, UrlInfo inputUrl, {isWarning: false}) {
-    var message = 'unable to open file "${inputUrl.resolvedPath}"';
-    if (options.verbose) {
-      message = '$message. original message:\n $error';
-    }
-    if (isWarning) {
-      _messages.warning(message, inputUrl.sourceSpan);
-    } else {
-      _messages.error(message, inputUrl.sourceSpan);
-    }
-    return null;
-  }
-
-  void _processCssFile(UrlInfo inputUrl, SourceFile cssFile) {
-    if (cssFile == null) return;
-
-    files.add(cssFile);
-
-    var fileInfo = new FileInfo(inputUrl);
-    info[inputUrl.resolvedPath] = fileInfo;
-
-    var styleSheet = parseCss(cssFile.code, _messages, options);
-    if (inputUrl.url == _resetCssFile) {
-      _cssResetStyleSheet = styleSheet;
-    } else if (styleSheet != null) {
-      _resolveStyleSheetImports(inputUrl, cssFile.path, styleSheet);
-      fileInfo.styleSheets.add(styleSheet);
-    }
-  }
-
-  /** Load and parse all style sheets referenced with an @imports. */
-  void _resolveStyleSheetImports(UrlInfo inputUrl, String processingFile,
-      StyleSheet styleSheet) {
-    var urlInfos = _time('CSS imports', processingFile, () =>
-        findImportsInStyleSheet(styleSheet, _packageRoot, inputUrl, _messages));
-
-    for (var urlInfo in urlInfos) {
-      if (urlInfo == null) break;
-      // Load any @imported stylesheet files referenced in this style sheet.
-      _loadFile(urlInfo, _parseCssFile);
-    }
-  }
-
-  /** Run the analyzer on every input html file. */
-  void _analyze() {
-    var uniqueIds = new IntIterator();
-    for (var file in files) {
-      if (file.isHtml) {
-        _time('Analyzed contents', file.path, () =>
-            analyzeFile(file, info, uniqueIds, global, _messages,
-              options.emulateScopedCss));
-      }
-    }
-  }
-
-  // TODO(jmesserly): refactor this and other CSS related transforms out of
-  // Compiler.
-  /**
-   * Generate an CSS file for all style sheets (main and components).
-   * Returns true if a file was generated, otherwise false.
-   */
-  bool _emitAllCss() {
-    if (!options.emulateScopedCss) return false;
-
-    var buff = new StringBuffer();
-
-    // Emit all linked style sheet files first.
-    for (var file in files) {
-      var css = new StringBuffer();
-      var fileInfo = info[file.path];
-      if (file.isStyleSheet) {
-        for (var styleSheet in fileInfo.styleSheets) {
-          css.write(
-              '/* Auto-generated from style sheet href = ${file.path} */\n'
-              '/* DO NOT EDIT. */\n\n');
-          css.write(emitStyleSheet(styleSheet, fileInfo));
-          css.write('\n\n');
-        }
-      }
-    }
-
-    // Emit all CSS for each component (style scoped).
-    for (var file in files) {
-      if (file.isHtml) {
-        var fileInfo = info[file.path];
-        for (var component in fileInfo.declaredComponents) {
-          for (var styleSheet in component.styleSheets) {
-            // Translate any URIs in CSS.
-            if (buff.isEmpty) {
-              buff.write(
-                  '/* Auto-generated from components style tags. */\n'
-                  '/* DO NOT EDIT. */\n\n');
-            }
-            buff.write(
-                '/* ==================================================== \n'
-                '   Component ${component.tagName} stylesheet \n'
-                '   ==================================================== */\n');
-
-            var tagName = component.tagName;
-            if (!component.hasAuthorStyles) {
-              if (_cssResetStyleSheet != null) {
-                // If component doesn't have apply-author-styles then we need to
-                // reset the CSS the styles for the component (if css-reset file
-                // option was passed).
-                buff.write('\n/* Start CSS Reset */\n');
-                var style;
-                if (options.emulateScopedCss) {
-                  style = emitComponentStyleSheet(_cssResetStyleSheet, tagName);
-                } else {
-                  style = emitOriginalCss(_cssResetStyleSheet);
-                }
-                buff.write(style);
-                buff.write('/* End CSS Reset */\n\n');
-              }
-            }
-            if (options.emulateScopedCss) {
-              buff.write(emitComponentStyleSheet(styleSheet, tagName));
-            } else {
-              buff.write(emitOriginalCss(styleSheet));
-            }
-            buff.write('\n\n');
-          }
-        }
-      }
-    }
-
-    if (buff.isEmpty) return false;
-    return true;
-  }
-
-  _time(String logMessage, String filePath, callback(),
-      {bool printTime: false}) {
-    var message = new StringBuffer();
-    message.write(logMessage);
-    var filename = path.basename(filePath);
-    for (int i = (60 - logMessage.length - filename.length); i > 0 ; i--) {
-      message.write(' ');
-    }
-    message.write(filename);
-    return time(message.toString(), callback,
-        printTime: options.verbose || printTime);
-  }
-}
diff --git a/pkg/polymer/lib/src/compiler_options.dart b/pkg/polymer/lib/src/compiler_options.dart
deleted file mode 100644
index 2d446ef..0000000
--- a/pkg/polymer/lib/src/compiler_options.dart
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library polymer.src.compiler_options;
-
-import 'package:args/args.dart';
-
-class CompilerOptions {
-  /** Report warnings as errors. */
-  final bool warningsAsErrors;
-
-  /** True to show informational messages. The `--verbose` flag. */
-  final bool verbose;
-
-  /** Remove any generated files. */
-  final bool clean;
-
-  /** Whether to use colors to print messages on the terminal. */
-  final bool useColors;
-
-  /** Force mangling any generated name (even when --out is provided). */
-  final bool forceMangle;
-
-  /** Generate component's dart code, but not the main entry point file. */
-  final bool componentsOnly;
-
-  /** File to process by the compiler. */
-  String inputFile;
-
-  /** Directory where all sources are found. */
-  final String baseDir;
-
-  /** Directory where all output will be generated. */
-  final String outputDir;
-
-  /** Directory where to look for 'package:' imports. */
-  final String packageRoot;
-
-  /**
-   * Adjust resource URLs in the output HTML to point back to the original
-   * location in the file system. Commonly this is enabled during development,
-   * but disabled for deployment.
-   */
-  final bool rewriteUrls;
-
-  /**
-   * Whether to print error messages using the json format understood by the
-   * Dart editor.
-   */
-  final bool jsonFormat;
-
-  /** Emulate scoped styles using a CSS polyfill. */
-  final bool emulateScopedCss;
-
-  /** Use CSS file for CSS Reset. */
-  final String resetCssFile;
-
-  // We could make this faster, if it ever matters.
-  factory CompilerOptions() => parse(['']);
-
-  CompilerOptions.fromArgs(ArgResults args)
-    : warningsAsErrors = args['warnings_as_errors'],
-      verbose = args['verbose'],
-      clean = args['clean'],
-      useColors = args['colors'],
-      baseDir = args['basedir'],
-      outputDir = args['out'],
-      packageRoot = args['package-root'],
-      rewriteUrls = args['rewrite-urls'],
-      forceMangle = args['unique_output_filenames'],
-      jsonFormat = args['json_format'],
-      componentsOnly = args['components_only'],
-      emulateScopedCss = args['scoped-css'],
-      resetCssFile = args['css-reset'],
-      inputFile = args.rest.length > 0 ? args.rest[0] : null;
-
-  /**
-   * Returns the compiler options parsed from [arguments]. Set [checkUsage] to
-   * false to suppress checking of correct usage or printing help messages.
-   */
-  // TODO(sigmund): convert all flags to use dashes instead of underscores
-  static CompilerOptions parse(List<String> arguments,
-      {bool checkUsage: true}) {
-    var parser = new ArgParser()
-      ..addFlag('verbose', abbr: 'v')
-      ..addFlag('clean', help: 'Remove all generated files',
-          defaultsTo: false, negatable: false)
-      ..addFlag('warnings_as_errors', abbr: 'e',
-          help: 'Warnings handled as errors',
-          defaultsTo: false, negatable: false)
-      ..addFlag('colors', help: 'Display errors/warnings in colored text',
-          defaultsTo: true)
-      ..addFlag('rewrite-urls',
-          help: 'Adjust every resource url to point to the original location in'
-          ' the filesystem.\nThis on by default during development and can be'
-          ' disabled to make the generated code easier to deploy.',
-          defaultsTo: true)
-      ..addFlag('unique_output_filenames', abbr: 'u',
-          help: 'Use unique names for all generated files, so they will not '
-                'have the\nsame name as your input files, even if they are in a'
-                ' different directory',
-          defaultsTo: false, negatable: false)
-      ..addFlag('json_format',
-          help: 'Print error messsages in a json format easy to parse by tools,'
-                ' such as the Dart editor',
-          defaultsTo: false, negatable: false)
-      ..addFlag('components_only',
-          help: 'Generate only the code for component classes, do not generate '
-                'HTML files or the main bootstrap code.',
-          defaultsTo: false, negatable: false)
-      ..addFlag('scoped-css', help: 'Emulate scoped styles with CSS polyfill',
-          defaultsTo: false)
-      ..addOption('css-reset', abbr: 'r', help: 'CSS file used to reset CSS')
-      // TODO(sigmund): remove this flag 
-      ..addFlag('deploy', help: '(deprecated) currently a noop',
-          defaultsTo: false, negatable: false)
-      ..addOption('out', abbr: 'o', help: 'Directory where to generate files'
-          ' (defaults to the same directory as the source file)')
-      ..addOption('basedir', help: 'Base directory where to find all source '
-          'files (defaults to the source file\'s directory)')
-      ..addOption('package-root', help: 'Where to find "package:" imports'
-          '(defaults to the "packages/" subdirectory next to the source file)')
-      ..addFlag('help', abbr: 'h', help: 'Displays this help message',
-          defaultsTo: false, negatable: false);
-    try {
-      var results = parser.parse(arguments);
-      if (checkUsage && (results['help'] || results.rest.length == 0)) {
-        showUsage(parser);
-        return null;
-      }
-      return new CompilerOptions.fromArgs(results);
-    } on FormatException catch (e) {
-      print(e.message);
-      showUsage(parser);
-      return null;
-    }
-  }
-
-  static showUsage(parser) {
-    print('Usage: dwc [options...] input.html');
-    print(parser.getUsage());
-  }
-}
diff --git a/pkg/polymer/lib/src/css_analyzer.dart b/pkg/polymer/lib/src/css_analyzer.dart
deleted file mode 100644
index 0b96825..0000000
--- a/pkg/polymer/lib/src/css_analyzer.dart
+++ /dev/null
@@ -1,503 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** Portion of the analyzer dealing with CSS sources. */
-library polymer.src.css_analyzer;
-
-import 'package:csslib/parser.dart' as css;
-import 'package:csslib/visitor.dart';
-import 'package:html5lib/dom.dart';
-import 'package:html5lib/dom_parsing.dart';
-
-import 'info.dart';
-import 'files.dart' show SourceFile;
-import 'messages.dart';
-import 'compiler_options.dart';
-
-void analyzeCss(String packageRoot, List<SourceFile> files,
-                Map<String, FileInfo> info, Map<String, String> pseudoElements,
-                Messages messages, {warningsAsErrors: false}) {
-  var analyzer = new _AnalyzerCss(packageRoot, info, pseudoElements, messages,
-      warningsAsErrors);
-  for (var file in files) analyzer.process(file);
-  analyzer.normalize();
-}
-
-class _AnalyzerCss {
-  final String packageRoot;
-  final Map<String, FileInfo> info;
-  final Map<String, String> _pseudoElements;
-  final Messages _messages;
-  final bool _warningsAsErrors;
-
-  Set<StyleSheet> allStyleSheets = new Set<StyleSheet>();
-
-  /**
-   * [_pseudoElements] list of known pseudo attributes found in HTML, any
-   * CSS pseudo-elements 'name::custom-element' is mapped to the manged name
-   * associated with the pseudo-element key.
-   */
-  _AnalyzerCss(this.packageRoot, this.info, this._pseudoElements,
-               this._messages, this._warningsAsErrors);
-
-  /**
-   * Run the analyzer on every file that is a style sheet or any component that
-   * has a style tag.
-   */
-  void process(SourceFile file) {
-    var fileInfo = info[file.path];
-    if (file.isStyleSheet || fileInfo.styleSheets.length > 0) {
-      var styleSheets = processVars(fileInfo.inputUrl, fileInfo);
-
-      // Add to list of all style sheets analyzed.
-      allStyleSheets.addAll(styleSheets);
-    }
-
-    // Process any components.
-    for (var component in fileInfo.declaredComponents) {
-      var all = processVars(fileInfo.inputUrl, component);
-
-      // Add to list of all style sheets analyzed.
-      allStyleSheets.addAll(all);
-    }
-
-    processCustomPseudoElements();
-  }
-
-  void normalize() {
-    // Remove all var definitions for all style sheets analyzed.
-    for (var tree in allStyleSheets) new _RemoveVarDefinitions().visitTree(tree);
-  }
-
-  List<StyleSheet> processVars(inputUrl, libraryInfo) {
-    // Get list of all stylesheet(s) dependencies referenced from this file.
-    var styleSheets = _dependencies(inputUrl, libraryInfo).toList();
-
-    var errors = [];
-    css.analyze(styleSheets, errors: errors, options:
-      [_warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
-
-    // Print errors as warnings.
-    for (var e in errors) {
-      _messages.warning(e.message, e.span);
-    }
-
-    // Build list of all var definitions.
-    Map varDefs = new Map();
-    for (var tree in styleSheets) {
-      var allDefs = (new _VarDefinitions()..visitTree(tree)).found;
-      allDefs.forEach((key, value) {
-        varDefs[key] = value;
-      });
-    }
-
-    // Resolve all definitions to a non-VarUsage (terminal expression).
-    varDefs.forEach((key, value) {
-      for (var expr in (value.expression as Expressions).expressions) {
-        var def = _findTerminalVarDefinition(varDefs, value);
-        varDefs[key] = def;
-      }
-    });
-
-    // Resolve all var usages.
-    for (var tree in styleSheets) new _ResolveVarUsages(varDefs).visitTree(tree);
-
-    return styleSheets;
-  }
-
-  processCustomPseudoElements() {
-    var polyFiller = new _PseudoElementExpander(_pseudoElements);
-    for (var tree in allStyleSheets) {
-      polyFiller.visitTree(tree);
-    }
-  }
-
-  /**
-   * Given a component or file check if any stylesheets referenced.  If so then
-   * return a list of all referenced stylesheet dependencies (@imports or <link
-   * rel="stylesheet" ..>).
-   */
-  Set<StyleSheet> _dependencies(inputUrl, libraryInfo, {Set<StyleSheet> seen}) {
-    if (seen == null) seen = new Set();
-
-    for (var styleSheet in libraryInfo.styleSheets) {
-      if (!seen.contains(styleSheet)) {
-        // TODO(terry): VM uses expandos to implement hashes.  Currently, it's a
-        //              linear (not constant) time cost (see dartbug.com/5746).
-        //              If this bug isn't fixed and performance show's this a
-        //              a problem we'll need to implement our own hashCode or
-        //              use a different key for better perf.
-        // Add the stylesheet.
-        seen.add(styleSheet);
-
-        // Any other imports in this stylesheet?
-        var urlInfos = findImportsInStyleSheet(styleSheet, packageRoot,
-            inputUrl, _messages);
-
-        // Process other imports in this stylesheets.
-        for (var importSS in urlInfos) {
-          var importInfo = info[importSS.resolvedPath];
-          if (importInfo != null) {
-            // Add all known stylesheets processed.
-            seen.addAll(importInfo.styleSheets);
-            // Find dependencies for stylesheet referenced with a
-            // @import
-            for (var ss in importInfo.styleSheets) {
-              var urls = findImportsInStyleSheet(ss, packageRoot, inputUrl,
-                  _messages);
-              for (var url in urls) {
-                var fileInfo = info[url.resolvedPath];
-                _dependencies(fileInfo.inputUrl, fileInfo, seen: seen);
-              }
-            }
-          }
-        }
-      }
-    }
-
-    return seen;
-  }
-}
-
-/**
- * Find var- definitions in a style sheet.
- * [found] list of known definitions.
- */
-class _VarDefinitions extends Visitor {
-  final Map<String, VarDefinition> found = new Map();
-
-  void visitTree(StyleSheet tree) {
-    visitStyleSheet(tree);
-  }
-
-  visitVarDefinition(VarDefinition node) {
-    // Replace with latest variable definition.
-    found[node.definedName] = node;
-    super.visitVarDefinition(node);
-  }
-
-  void visitVarDefinitionDirective(VarDefinitionDirective node) {
-    visitVarDefinition(node.def);
-  }
-}
-
-/**
- * Resolve any CSS expression which contains a var() usage to the ultimate real
- * CSS expression value e.g.,
- *
- *    var-one: var(two);
- *    var-two: #ff00ff;
- *
- *    .test {
- *      color: var(one);
- *    }
- *
- * then .test's color would be #ff00ff
- */
-class _ResolveVarUsages extends Visitor {
-  final Map<String, VarDefinition> varDefs;
-  bool inVarDefinition = false;
-  bool inUsage = false;
-  Expressions currentExpressions;
-
-  _ResolveVarUsages(this.varDefs);
-
-  void visitTree(StyleSheet tree) {
-    visitStyleSheet(tree);
-  }
-
-  void visitVarDefinition(VarDefinition varDef) {
-    inVarDefinition = true;
-    super.visitVarDefinition(varDef);
-    inVarDefinition = false;
-  }
-
-  void visitExpressions(Expressions node) {
-    currentExpressions = node;
-    super.visitExpressions(node);
-    currentExpressions = null;
-  }
-
-  void visitVarUsage(VarUsage node) {
-    // Don't process other var() inside of a varUsage.  That implies that the
-    // default is a var() too.  Also, don't process any var() inside of a
-    // varDefinition (they're just place holders until we've resolved all real
-    // usages.
-    if (!inUsage && !inVarDefinition && currentExpressions != null) {
-      var expressions = currentExpressions.expressions;
-      var index = expressions.indexOf(node);
-      assert(index >= 0);
-      var def = varDefs[node.name];
-      if (def != null) {
-        // Found a VarDefinition use it.
-        _resolveVarUsage(currentExpressions.expressions, index, def);
-      } else if (node.defaultValues.any((e) => e is VarUsage)) {
-        // Don't have a VarDefinition need to use default values resolve all
-        // default values.
-        var terminalDefaults = [];
-        for (var defaultValue in node.defaultValues) {
-          terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
-        }
-        expressions.replaceRange(index, index + 1, terminalDefaults);
-      } else {
-        // No VarDefinition but default value is a terminal expression; use it.
-        expressions.replaceRange(index, index + 1, node.defaultValues);
-      }
-    }
-
-    inUsage = true;
-    super.visitVarUsage(node);
-    inUsage = false;
-  }
-
-  List<Expression> resolveUsageTerminal(VarUsage usage) {
-    var result = [];
-
-    var varDef = varDefs[usage.name];
-    var expressions;
-    if (varDef == null) {
-      // VarDefinition not found try the defaultValues.
-      expressions = usage.defaultValues;
-    } else {
-      // Use the VarDefinition found.
-      expressions = (varDef.expression as Expressions).expressions;
-    }
-
-    for (var expr in expressions) {
-      if (expr is VarUsage) {
-        // Get terminal value.
-        result.addAll(resolveUsageTerminal(expr));
-      }
-    }
-
-    // We're at a terminal just return the VarDefinition expression.
-    if (result.isEmpty && varDef != null) {
-      result = (varDef.expression as Expressions).expressions;
-    }
-
-    return result;
-  }
-
-  _resolveVarUsage(List<Expressions> expressions, int index,
-                   VarDefinition def) {
-    var defExpressions = (def.expression as Expressions).expressions;
-    expressions.replaceRange(index, index + 1, defExpressions);
-  }
-}
-
-/** Remove all var definitions. */
-class _RemoveVarDefinitions extends Visitor {
-  void visitTree(StyleSheet tree) {
-    visitStyleSheet(tree);
-  }
-
-  void visitStyleSheet(StyleSheet ss) {
-    ss.topLevels.removeWhere((e) => e is VarDefinitionDirective);
-    super.visitStyleSheet(ss);
-  }
-
-  void visitDeclarationGroup(DeclarationGroup node) {
-    node.declarations.removeWhere((e) => e is VarDefinition);
-    super.visitDeclarationGroup(node);
-  }
-}
-
-/**
- * Process all selectors looking for a pseudo-element in a selector.  If the
- * name is found in our list of known pseudo-elements.  Known pseudo-elements
- * are built when parsing a component looking for an attribute named "pseudo".
- * The value of the pseudo attribute is the name of the custom pseudo-element.
- * The name is mangled so Dart/JS can't directly access the pseudo-element only
- * CSS can access a custom pseudo-element (and see issue #510, querying needs
- * access to custom pseudo-elements).
- *
- * Change the custom pseudo-element to be a child of the pseudo attribute's
- * mangled custom pseudo element name. e.g,
- *
- *    .test::x-box
- *
- * would become:
- *
- *    .test > *[pseudo="x-box_2"]
- */
-class _PseudoElementExpander extends Visitor {
-  final Map<String, String> _pseudoElements;
-
-  _PseudoElementExpander(this._pseudoElements);
-
-  void visitTree(StyleSheet tree) => visitStyleSheet(tree);
-
-  visitSelector(Selector node) {
-    var selectors = node.simpleSelectorSequences;
-    for (var index = 0; index < selectors.length; index++) {
-      var selector = selectors[index].simpleSelector;
-      if (selector is PseudoElementSelector) {
-        if (_pseudoElements.containsKey(selector.name)) {
-          // Pseudo Element is a custom element.
-          var mangledName = _pseudoElements[selector.name];
-
-          var span = selectors[index].span;
-
-          var attrSelector = new AttributeSelector(
-              new Identifier('pseudo', span), css.TokenKind.EQUALS,
-              mangledName, span);
-          // The wildcard * namespace selector.
-          var wildCard = new ElementSelector(new Wildcard(span), span);
-          selectors[index] = new SimpleSelectorSequence(wildCard, span,
-                  css.TokenKind.COMBINATOR_GREATER);
-          selectors.insert(++index,
-              new SimpleSelectorSequence(attrSelector, span));
-        }
-      }
-    }
-  }
-}
-
-List<UrlInfo> findImportsInStyleSheet(StyleSheet styleSheet,
-    String packageRoot, UrlInfo inputUrl, Messages messages) {
-  var visitor = new _CssImports(packageRoot, inputUrl, messages);
-  visitor.visitTree(styleSheet);
-  return visitor.urlInfos;
-}
-
-/**
- * Find any imports in the style sheet; normalize the style sheet href and
- * return a list of all fully qualified CSS files.
- */
-class _CssImports extends Visitor {
-  final String packageRoot;
-
-  /** Input url of the css file, used to normalize relative import urls. */
-  final UrlInfo inputUrl;
-
-  /** List of all imported style sheets. */
-  final List<UrlInfo> urlInfos = [];
-
-  final Messages _messages;
-
-  _CssImports(this.packageRoot, this.inputUrl, this._messages);
-
-  void visitTree(StyleSheet tree) {
-    visitStyleSheet(tree);
-  }
-
-  void visitImportDirective(ImportDirective node) {
-    var urlInfo = UrlInfo.resolve(node.import, inputUrl,
-        node.span, packageRoot, _messages, ignoreAbsolute: true);
-    if (urlInfo == null) return;
-    urlInfos.add(urlInfo);
-  }
-}
-
-StyleSheet parseCss(String content, Messages messages,
-    CompilerOptions options) {
-  if (content.trim().isEmpty) return null;
-
-  var errors = [];
-
-  // TODO(terry): Add --checked when fully implemented and error handling.
-  var stylesheet = css.parse(content, errors: errors, options:
-      [options.warningsAsErrors ? '--warnings_as_errors' : '', 'memory']);
-
-  // Note: errors aren't fatal in HTML (unless strict mode is on).
-  // So just print them as warnings.
-  for (var e in errors) {
-    messages.warning(e.message, e.span);
-  }
-
-  return stylesheet;
-}
-
-/** Find terminal definition (non VarUsage implies real CSS value). */
-VarDefinition _findTerminalVarDefinition(Map<String, VarDefinition> varDefs,
-                                        VarDefinition varDef) {
-  var expressions = varDef.expression as Expressions;
-  for (var expr in expressions.expressions) {
-    if (expr is VarUsage) {
-      var usageName = (expr as VarUsage).name;
-      var foundDef = varDefs[usageName];
-
-      // If foundDef is unknown check if defaultValues; if it exist then resolve
-      // to terminal value.
-      if (foundDef == null) {
-        // We're either a VarUsage or terminal definition if in varDefs;
-        // either way replace VarUsage with it's default value because the
-        // VarDefinition isn't found.
-        var defaultValues = (expr as VarUsage).defaultValues;
-        var replaceExprs = expressions.expressions;
-        assert(replaceExprs.length == 1);
-        replaceExprs.replaceRange(0, 1, defaultValues);
-        return varDef;
-      }
-      if (foundDef is VarDefinition) {
-        return _findTerminalVarDefinition(varDefs, foundDef);
-      }
-    } else {
-      // Return real CSS property.
-      return varDef;
-    }
-  }
-
-  // Didn't point to a var definition that existed.
-  return varDef;
-}
-
-/**
- * Find urls imported inside style tags under [info].  If [info] is a FileInfo
- * then process only style tags in the body (don't process any style tags in a
- * component).  If [info] is a ComponentInfo only process style tags inside of
- * the element are processed.  For an [info] of type FileInfo [node] is the
- * file's document and for an [info] of type ComponentInfo then [node] is the
- * component's element tag.
- */
-List<UrlInfo> findUrlsImported(LibraryInfo info, UrlInfo inputUrl,
-    String packageRoot, Node node, Messages messages, CompilerOptions options) {
-  // Process any @imports inside of the <style> tag.
-  var styleProcessor =
-      new _CssStyleTag(packageRoot, info, inputUrl, messages, options);
-  styleProcessor.visit(node);
-  return styleProcessor.imports;
-}
-
-/* Process CSS inside of a style tag. */
-class _CssStyleTag extends TreeVisitor {
-  final String _packageRoot;
-
-  /** Either a FileInfo or ComponentInfo. */
-  final LibraryInfo _info;
-  final Messages _messages;
-  final CompilerOptions _options;
-
-  /**
-   * Path of the declaring file, for a [_info] of type FileInfo it's the file's
-   * path for a type ComponentInfo it's the declaring file path.
-   */
-  final UrlInfo _inputUrl;
-
-  /** List of @imports found. */
-  List<UrlInfo> imports = [];
-
-  _CssStyleTag(this._packageRoot, this._info, this._inputUrl, this._messages,
-      this._options);
-
-  void visitElement(Element node) {
-    // Don't process any style tags inside of element if we're processing a
-    // FileInfo.  The style tags inside of a component defintion will be
-    // processed when _info is a ComponentInfo.
-    if (node.tagName == 'polymer-element' && _info is FileInfo) return;
-    if (node.tagName == 'style') {
-      // Parse the contents of the scoped style tag.
-      var styleSheet = parseCss(node.nodes.single.value, _messages, _options);
-      if (styleSheet != null) {
-        _info.styleSheets.add(styleSheet);
-
-        // Find all imports return list of @imports in this style tag.
-        var urlInfos = findImportsInStyleSheet(styleSheet, _packageRoot,
-            _inputUrl, _messages);
-        imports.addAll(urlInfos);
-      }
-    }
-    super.visitElement(node);
-  }
-}
diff --git a/pkg/polymer/lib/src/css_emitters.dart b/pkg/polymer/lib/src/css_emitters.dart
deleted file mode 100644
index a4d4b7d..0000000
--- a/pkg/polymer/lib/src/css_emitters.dart
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library polymer.src.css_emitters;
-
-import 'package:csslib/visitor.dart' show Visitor, CssPrinter, ElementSelector,
-       UriTerm, Selector, HostDirective, SimpleSelectorSequence, StyleSheet;
-
-import 'info.dart';
-
-
-/** Emit the contents of the style tag outside of a component. */
-String emitStyleSheet(StyleSheet ss, FileInfo file) =>
-  (new _CssEmitter(file.components.keys.toSet())
-      ..visitTree(ss, pretty: true)).toString();
-
-/** Emit a component's style tag content emulating scoped css. */
-String emitComponentStyleSheet(StyleSheet ss, String tagName) =>
-    (new _ComponentCssEmitter(tagName)..visitTree(ss, pretty: true)).toString();
-
-String emitOriginalCss(StyleSheet css) =>
-    (new CssPrinter()..visitTree(css)).toString();
-
-/** Only x-tag name element selectors are emitted as [is="x-"]. */
-class _CssEmitter extends CssPrinter {
-  final Set _componentsTag;
-  _CssEmitter(this._componentsTag);
-
-  void visitElementSelector(ElementSelector node) {
-    // If element selector is a component's tag name, then change selector to
-    // find element who's is attribute's the component's name.
-    if (_componentsTag.contains(node.name)) {
-      emit('[is="${node.name}"]');
-      return;
-    }
-    super.visitElementSelector(node);
-  }
-}
-
-/**
- * Emits a css stylesheet applying rules to emulate scoped css. The rules adjust
- * element selectors to include the component's tag name.
- */
-class _ComponentCssEmitter extends CssPrinter {
-  final String _componentTagName;
-  bool _inHostDirective = false;
-  bool _selectorStartInHostDirective = false;
-
-  _ComponentCssEmitter(this._componentTagName);
-
-  /** Is the element selector an x-tag name. */
-  bool _isSelectorElementXTag(Selector node) {
-    if (node.simpleSelectorSequences.length > 0) {
-      var selector = node.simpleSelectorSequences[0].simpleSelector;
-      return selector is ElementSelector && selector.name == _componentTagName;
-    }
-    return false;
-  }
-
-  void visitSelector(Selector node) {
-    // If the selector starts with an x-tag name don't emit it twice.
-    if (!_isSelectorElementXTag(node)) {
-      if (_inHostDirective) {
-        // Style the element that's hosting the component, therefore don't emit
-        // the descendent combinator (first space after the [is="x-..."]).
-        emit('[is="$_componentTagName"]');
-        // Signal that first simpleSelector must be checked.
-        _selectorStartInHostDirective = true;
-      } else {
-        // Emit its scoped as a descendent (space at end).
-        emit('[is="$_componentTagName"] ');
-      }
-    }
-    super.visitSelector(node);
-  }
-
-  /**
-   * If first simple selector of a ruleset in a @host directive is a wildcard
-   * then don't emit the wildcard.
-   */
-  void visitSimpleSelectorSequence(SimpleSelectorSequence node) {
-    if (_selectorStartInHostDirective) {
-      _selectorStartInHostDirective = false;
-      if (node.simpleSelector.isWildcard) {
-        // Skip the wildcard if first item in the sequence.
-        return;
-      }
-      assert(node.isCombinatorNone);
-    }
-
-    super.visitSimpleSelectorSequence(node);
-  }
-
-  void visitElementSelector(ElementSelector node) {
-    // If element selector is the component's tag name, then change selector to
-    // find element who's is attribute is the component's name.
-    if (_componentTagName == node.name) {
-      emit('[is="$_componentTagName"]');
-      return;
-    }
-    super.visitElementSelector(node);
-  }
-
-  /**
-   * If we're polyfilling scoped styles the @host directive is stripped.  Any
-   * ruleset(s) processed in an @host will fixup the first selector.  See
-   * visitSelector and visitSimpleSelectorSequence in this class, they adjust
-   * the selectors so it styles the element hosting the compopnent.
-   */
-  void visitHostDirective(HostDirective node) {
-    _inHostDirective = true;
-    emit('/* @host */');
-    for (var ruleset in node.rulesets) {
-      ruleset.visit(this);
-    }
-    _inHostDirective = false;
-    emit('/* end of @host */\n');
-  }
-}
diff --git a/pkg/polymer/lib/src/custom_tag_name.dart b/pkg/polymer/lib/src/custom_tag_name.dart
deleted file mode 100644
index 637b937..0000000
--- a/pkg/polymer/lib/src/custom_tag_name.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library polymer.src.custom_tag_name;
-
-/**
- * Returns true if this is a valid custom element name. See:
- * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-name>
- */
-bool isCustomTag(String name) {
-  if (name == null || !name.contains('-')) return false;
-
-  // These names have meaning in SVG or MathML, so they aren't allowed as custom
-  // tags.
-  var invalidNames = const {
-    'annotation-xml': '',
-    'color-profile': '',
-    'font-face': '',
-    'font-face-src': '',
-    'font-face-uri': '',
-    'font-face-format': '',
-    'font-face-name': '',
-    'missing-glyph': '',
-  };
-  return !invalidNames.containsKey(name);
-}
diff --git a/pkg/polymer/lib/src/file_system.dart b/pkg/polymer/lib/src/file_system.dart
deleted file mode 100644
index c6af55c..0000000
--- a/pkg/polymer/lib/src/file_system.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** Abstraction for file systems and utility functions to manipulate paths. */
-library file_system;
-
-import 'dart:async';
-
-/**
- * Abstraction around file system access to work in a variety of different
- * environments.
- */
-abstract class FileSystem {
-  /**
-   * Apply all pending writes.  Until this method is called, writeString is not
-   * guaranteed to have any observable impact.
-   */
-  Future flush();
-
-  /**
-   * Reads bytes if possible, but falls back to text if running in a browser.
-   * Return type is either [Future<List<int>>] or [Future<String>].
-   */
-  Future readTextOrBytes(String path);
-
-  /* Like [readTextOrBytes], but decodes bytes as UTF-8. Used for Dart code. */
-  Future<String> readText(String path);
-
-  /**
-   * Writes [text] to file at [path]. Call flush to insure that changes are
-   * visible.
-   */
-  void writeString(String path, String text);
-}
diff --git a/pkg/polymer/lib/src/file_system/console.dart b/pkg/polymer/lib/src/file_system/console.dart
deleted file mode 100644
index 346eb4b..0000000
--- a/pkg/polymer/lib/src/file_system/console.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library console;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'package:polymer/src/file_system.dart';
-
-/** File system implementation for console VM (i.e. no browser). */
-class ConsoleFileSystem implements FileSystem {
-
-  /** Pending futures for file write requests. */
-  final _pending = <String, Future>{};
-
-  Future flush() => Future.wait(_pending.values.toList());
-
-  void writeString(String path, String text) {
-    if(!_pending.containsKey(path)) {
-      _pending[path] = new File(path).open(mode: FileMode.WRITE)
-          .then((file) => file.writeString(text))
-          .then((file) => file.close())
-          .whenComplete(() { _pending.remove(path); });
-    }
-  }
-
-  // TODO(jmesserly): even better would be to pass the RandomAccessFile directly
-  // to html5lib. This will require a further restructuring of FileSystem.
-  // Probably it just needs "readHtml" and "readText" methods.
-  Future<List<int>> readTextOrBytes(String path) {
-    return new File(path).open().then(
-        (file) => file.length().then((length) {
-      // TODO(jmesserly): is this guaranteed to read all of the bytes?
-      var buffer = new List<int>(length);
-      return file.readInto(buffer, 0, length)
-          .then((_) => file.close())
-          .then((_) => buffer);
-    }));
-  }
-
-  // TODO(jmesserly): do we support any encoding other than UTF-8 for Dart?
-  Future<String> readText(String path) {
-    return readTextOrBytes(path).then(UTF8.decode);
-  }
-}
diff --git a/pkg/polymer/lib/src/files.dart b/pkg/polymer/lib/src/files.dart
deleted file mode 100644
index 9fea763..0000000
--- a/pkg/polymer/lib/src/files.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library files;
-
-import 'package:html5lib/dom.dart';
-
-/** An input file to process by the template compiler. */
-class SourceFile {
-  static const int HTML = 1;
-  static const int DART = 2;
-  static const int STYLESHEET = 3;
-
-  final String path;
-  final int type;
-
-  Document document;
-
-  /** Dart code or contents of a linked style sheet. */
-  String code;
-
-  SourceFile(this.path, {this.type: HTML});
-
-  bool get isDart => type == DART;
-  bool get isHtml => type == HTML;
-  bool get isStyleSheet => type == STYLESHEET;
-
-  String toString() => "#<SourceFile $path>";
-}
-
-/** An output file to generated by the template compiler. */
-class OutputFile {
-  final String path;
-  final String contents;
-
-  /**
-   * Path to the source file that was transformed into this OutputFile, `null`
-   * for files that are generated and do not correspond to an input
-   * [SourceFile].
-   */
-  final String source;
-
-  OutputFile(this.path, this.contents, {this.source});
-
-  String toString() => "#<OutputFile $path>";
-}
diff --git a/pkg/polymer/lib/src/info.dart b/pkg/polymer/lib/src/info.dart
deleted file mode 100644
index 5fa901f..0000000
--- a/pkg/polymer/lib/src/info.dart
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Datatypes holding information extracted by the analyzer and used by later
- * phases of the compiler.
- */
-library polymer.src.info;
-
-import 'dart:collection' show SplayTreeMap, LinkedHashMap;
-
-import 'package:csslib/visitor.dart';
-import 'package:html5lib/dom.dart';
-import 'package:source_maps/span.dart' show Span;
-
-import 'messages.dart';
-import 'utils.dart';
-
-/**
- * Information that is global. Roughly corresponds to `window` and `document`.
- */
-class GlobalInfo {
-  /**
-   * Pseudo-element names exposed in a component via a pseudo attribute.
-   * The name is only available from CSS (not Dart code) so they're mangled.
-   * The same pseudo-element in different components maps to the same
-   * mangled name (as the pseudo-element is scoped inside of the component).
-   */
-  final Map<String, String> pseudoElements = <String, String>{};
-
-  /** All components declared in the application. */
-  final Map<String, ComponentInfo> components = new SplayTreeMap();
-}
-
-/**
- * Information for any library-like input. We consider each HTML file a library,
- * and each component declaration a library as well. Hence we use this as a base
- * class for both [FileInfo] and [ComponentInfo]. Both HTML files and components
- * can have .dart code provided by the user for top-level user scripts and
- * component-level behavior code. This code can either be inlined in the HTML
- * file or included in a script tag with the "src" attribute.
- */
-abstract class LibraryInfo {
-  /** Parsed cssSource. */
-  List<StyleSheet> styleSheets = [];
-}
-
-/** Information extracted at the file-level. */
-class FileInfo extends LibraryInfo {
-  /** Relative path to this file from the compiler's base directory. */
-  final UrlInfo inputUrl;
-
-  /**
-   * All custom element definitions in this file. This may contain duplicates.
-   * Normally you should use [components] for lookup.
-   */
-  final List<ComponentInfo> declaredComponents = new List<ComponentInfo>();
-
-  /**
-   * All custom element definitions defined in this file or imported via
-   *`<link rel='components'>` tag. Maps from the tag name to the component
-   * information. This map is sorted by the tag name.
-   */
-  final Map<String, ComponentInfo> components =
-      new SplayTreeMap<String, ComponentInfo>();
-
-  /** Files imported with `<link rel="import">` */
-  final List<UrlInfo> componentLinks = <UrlInfo>[];
-
-  /** Files imported with `<link rel="stylesheet">` */
-  final List<UrlInfo> styleSheetHrefs = <UrlInfo>[];
-
-  FileInfo(this.inputUrl);
-}
-
-
-/** Information about a web component definition declared locally. */
-class ComponentInfo extends LibraryInfo {
-
-  /** The component tag name, defined with the `name` attribute on `element`. */
-  final String tagName;
-
-  /**
-   * The tag name that this component extends, defined with the `extends`
-   * attribute on `element`.
-   */
-  final String extendsTag;
-
-  /**
-   * The component info associated with the [extendsTag] name, if any.
-   * This will be `null` if the component extends a built-in HTML tag, or
-   * if the analyzer has not run yet.
-   */
-  ComponentInfo extendsComponent;
-
-  /** The declaring `<element>` tag. */
-  final Node element;
-
-  /**
-   * True if [tagName] was defined by more than one component. If this happened
-   * we will skip over the component.
-   */
-  bool hasConflict = false;
-
-  ComponentInfo(this.element, this.tagName, this.extendsTag);
-
-  /**
-   * Gets the HTML tag extended by the base of the component hierarchy.
-   * Equivalent to [extendsTag] if this inherits directly from an HTML element,
-   * in other words, if [extendsComponent] is null.
-   */
-  String get baseExtendsTag =>
-      extendsComponent == null ? extendsTag : extendsComponent.baseExtendsTag;
-
-  Span get sourceSpan => element.sourceSpan;
-
-  /** Is apply-author-styles enabled. */
-  bool get hasAuthorStyles =>
-      element.attributes.containsKey('apply-author-styles');
-
-  String toString() => '#<ComponentInfo $tagName>';
-}
-
-
-/**
- * Information extracted about a URL that refers to another file. This is
- * mainly introduced to be able to trace back where URLs come from when
- * reporting errors.
- */
-class UrlInfo {
-  /** Original url. */
-  final String url;
-
-  /** Path that the URL points to. */
-  final String resolvedPath;
-
-  /** Original source location where the URL was extracted from. */
-  final Span sourceSpan;
-
-  UrlInfo(this.url, this.resolvedPath, this.sourceSpan);
-
-  /**
-   * Resolve a path from an [url] found in a file located at [inputUrl].
-   * Returns null for absolute [url]. Unless [ignoreAbsolute] is true, reports
-   * an error message if the url is an absolute url.
-   */
-  static UrlInfo resolve(String url, UrlInfo inputUrl, Span span,
-      String packageRoot, Messages messages, {bool ignoreAbsolute: false}) {
-
-    var uri = Uri.parse(url);
-    if (uri.host != '' || (uri.scheme != '' && uri.scheme != 'package')) {
-      if (!ignoreAbsolute) {
-        messages.error('absolute paths not allowed here: "$url"', span);
-      }
-      return null;
-    }
-
-    var target;
-    if (url.startsWith('package:')) {
-      target = path.join(packageRoot, url.substring(8));
-    } else if (path.isAbsolute(url)) {
-      if (!ignoreAbsolute) {
-        messages.error('absolute paths not allowed here: "$url"', span);
-      }
-      return null;
-    } else {
-      target = path.join(path.dirname(inputUrl.resolvedPath), url);
-      url = pathToUrl(path.normalize(path.join(
-          path.dirname(inputUrl.url), url)));
-    }
-    target = path.normalize(target);
-
-    return new UrlInfo(url, target, span);
-  }
-
-  bool operator ==(UrlInfo other) =>
-      url == other.url && resolvedPath == other.resolvedPath;
-
-  int get hashCode => resolvedPath.hashCode;
-
-  String toString() => "#<UrlInfo url: $url, resolvedPath: $resolvedPath>";
-}
diff --git a/pkg/polymer/lib/src/messages.dart b/pkg/polymer/lib/src/messages.dart
deleted file mode 100644
index b0a5ebd..0000000
--- a/pkg/polymer/lib/src/messages.dart
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library messages;
-
-import 'dart:convert';
-
-import 'package:barback/barback.dart' show TransformLogger;
-import 'package:source_maps/span.dart' show Span;
-import 'package:logging/logging.dart' show Level;
-
-import 'compiler_options.dart';
-import 'utils.dart';
-
-/** Map between error levels and their display color. */
-final Map<Level, String> _ERROR_COLORS = (() {
-  var colorsMap = new Map<Level, String>();
-  colorsMap[Level.SEVERE] = RED_COLOR;
-  colorsMap[Level.WARNING] = MAGENTA_COLOR;
-  colorsMap[Level.INFO] = GREEN_COLOR;
-  return colorsMap;
-})();
-
-/** A single message from the compiler. */
-class Message {
-  final Level level;
-  final String message;
-  final Span span;
-  final bool useColors;
-
-  Message(this.level, this.message, {this.span, this.useColors: false});
-
-  String get kind => level == Level.SEVERE ? 'error' :
-      (level == Level.WARNING ? 'warning' : 'info');
-
-  String toString() {
-    var output = new StringBuffer();
-    bool colors = useColors && _ERROR_COLORS.containsKey(level);
-    var levelColor =  _ERROR_COLORS[level];
-    if (colors) output.write(levelColor);
-    output..write(kind)..write(' ');
-    if (colors) output.write(NO_COLOR);
-
-    if (span == null) {
-      output.write(message);
-    } else {
-      output.write(span.getLocationMessage(message, useColors: colors,
-          color: levelColor));
-    }
-
-    return output.toString();
-  }
-
-  String toJson() {
-    if (span == null) return toString();
-    return JSON.encode([{
-      'method': kind,
-      'params': {
-        'file': span.sourceUrl,
-        'message': message,
-        'line': span.start.line + 1,
-        'charStart': span.start.offset,
-        'charEnd': span.end.offset,
-      }
-    }]);
-  }
-}
-
-/**
- * This class tracks and prints information, warnings, and errors emitted by the
- * compiler.
- */
-class Messages implements TransformLogger {
-  final CompilerOptions options;
-  final bool shouldPrint;
-
-  final List<Message> messages = <Message>[];
-
-  Messages({CompilerOptions options, this.shouldPrint: true})
-      : options = options != null ? options : new CompilerOptions();
-
-  /**
-   * Creates a new instance of [Messages] which doesn't write messages to
-   * the console.
-   */
-  Messages.silent(): this(shouldPrint: false);
-
-  /**
-   * True if we have an error that prevents correct codegen.
-   * For example, if we failed to read an input file.
-   */
-  bool get hasErrors => messages.any((m) => m.level == Level.SEVERE);
-
-  // Convenience methods for testing
-  int get length => messages.length;
-
-  Message operator[](int index) => messages[index];
-
-  void clear() {
-    messages.clear();
-  }
-
-  /** [message] is considered a static compile-time error by the Dart lang. */
-  void error(String message, [Span span]) {
-    var msg = new Message(Level.SEVERE, message, span: span,
-        useColors: options.useColors);
-
-    messages.add(msg);
-    printMessage(msg);
-  }
-
-  /** [message] is considered a type warning by the Dart lang. */
-  void warning(String message, [Span span]) {
-    if (options.warningsAsErrors) {
-      error(message, span);
-    } else {
-      var msg = new Message(Level.WARNING, message,
-          span: span, useColors: options.useColors);
-
-      messages.add(msg);
-      printMessage(msg);
-    }
-  }
-
-  /// the list of error messages. Empty list, if there are no error messages.
-  List<Message> get errors =>
-        messages.where((m) => m.level == Level.SEVERE).toList();
-
-  /// the list of warning messages. Empty list if there are no warning messages.
-  List<Message> get warnings =>
-        messages.where((m) => m.level == Level.WARNING).toList();
-
-  /**
-   * [message] at [span] will tell the user about what the compiler
-   * is doing.
-   */
-  void info(String message, [Span span]) {
-    var msg = new Message(Level.INFO, message, span: span,
-        useColors: options.useColors);
-
-    messages.add(msg);
-    if (options.verbose) printMessage(msg);
-  }
-
-  void printMessage(msg) {
-    if (shouldPrint) print(options.jsonFormat ? msg.toJson() : msg);
-  }
-}
diff --git a/pkg/polymer/lib/src/transform.dart b/pkg/polymer/lib/src/transform.dart
deleted file mode 100644
index d2bf910..0000000
--- a/pkg/polymer/lib/src/transform.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** Transfomers used for pub-serve and pub-deploy. */
-// TODO(sigmund): move into a plugin directory when pub supports it.
-library polymer.src.transform;
-
-import 'package:observe/transform.dart';
-import 'transform/code_extractor.dart';
-import 'transform/import_inliner.dart';
-import 'transform/script_compactor.dart';
-import 'transform/polyfill_injector.dart';
-
-export 'transform/code_extractor.dart';
-export 'transform/import_inliner.dart';
-export 'transform/script_compactor.dart';
-export 'transform/polyfill_injector.dart';
-
-/** Phases to deploy a polymer application. */
-var phases = [
-  [new InlineCodeExtractor()],
-  [new ObservableTransformer()],
-  [new ImportedElementInliner()],
-  [new ScriptCompactor()],
-  [new PolyfillInjector()]
-];
diff --git a/pkg/polymer/lib/src/utils.dart b/pkg/polymer/lib/src/utils.dart
index da79dc2..59fdc73 100644
--- a/pkg/polymer/lib/src/utils.dart
+++ b/pkg/polymer/lib/src/utils.dart
@@ -1,177 +1,34 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 library polymer.src.utils;
 
-import 'dart:async';
-import 'package:path/path.dart' show Builder;
-export 'utils_observe.dart' show toCamelCase, toHyphenedName;
-
 /**
- * An instance of the pathos library builder. We could just use the default
- * builder in pathos, but we add this indirection to make it possible to run
- * unittest for windows paths.
+ * Converts a string name with hyphens into an identifier, by removing hyphens
+ * and capitalizing the following letter. Optionally [startUppercase] to
+ * captialize the first letter.
  */
-Builder path = new Builder();
-
-/** Convert a OS specific path into a url. */
-String pathToUrl(String relPath) =>
-  (path.separator == '/') ? relPath : path.split(relPath).join('/');
-
-/**
- * Invokes [callback], logs how long it took to execute in ms, and returns
- * whatever [callback] returns. The log message will be printed if [printTime]
- * is true.
- */
-time(String logMessage, callback(),
-     {bool printTime: false, bool useColors: false}) {
-  final watch = new Stopwatch();
-  watch.start();
-  var result = callback();
-  watch.stop();
-  final duration = watch.elapsedMilliseconds;
-  if (printTime) {
-    _printMessage(logMessage, duration, useColors);
-  }
-  return result;
-}
-
-/**
- * Invokes [callback], logs how long it takes from the moment [callback] is
- * executed until the future it returns is completed. Returns the future
- * returned by [callback]. The log message will be printed if [printTime]
- * is true.
- */
-Future asyncTime(String logMessage, Future callback(),
-                 {bool printTime: false, bool useColors: false}) {
-  final watch = new Stopwatch();
-  watch.start();
-  return callback()..then((_) {
-    watch.stop();
-    final duration = watch.elapsedMilliseconds;
-    if (printTime) {
-      _printMessage(logMessage, duration, useColors);
+String toCamelCase(String hyphenedName, {bool startUppercase: false}) {
+  var segments = hyphenedName.split('-');
+  int start = startUppercase ? 0 : 1;
+  for (int i = start; i < segments.length; i++) {
+    var segment = segments[i];
+    if (segment.length > 0) {
+      // Character between 'a'..'z' mapped to 'A'..'Z'
+      segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
     }
-  });
+  }
+  return segments.join('');
 }
 
-void _printMessage(String logMessage, int duration, bool useColors) {
-  var buf = new StringBuffer();
-  buf.write(logMessage);
-  for (int i = logMessage.length; i < 60; i++) buf.write(' ');
-  buf.write(' -- ');
-  if (useColors) {
-    buf.write(GREEN_COLOR);
+/** Reverse of [toCamelCase]. */
+String toHyphenedName(String word) {
+  var sb = new StringBuffer();
+  for (int i = 0; i < word.length; i++) {
+    var lower = word[i].toLowerCase();
+    if (word[i] != lower && i > 0) sb.write('-');
+    sb.write(lower);
   }
-  if (duration < 10) buf.write(' ');
-  if (duration < 100) buf.write(' ');
-  buf..write(duration)..write(' ms');
-  if (useColors) {
-    buf.write(NO_COLOR);
-  }
-  print(buf.toString());
-}
-
-// Color constants used for generating messages.
-final String GREEN_COLOR = '\u001b[32m';
-final String RED_COLOR = '\u001b[31m';
-final String MAGENTA_COLOR = '\u001b[35m';
-final String NO_COLOR = '\u001b[0m';
-
-/** A future that waits until all added [Future]s complete. */
-// TODO(sigmund): this should be part of the futures/core libraries.
-class FutureGroup {
-  static const _FINISHED = -1;
-
-  int _pending = 0;
-  Future _failedTask;
-  final Completer<List> _completer = new Completer<List>();
-  final List results = [];
-
-  /** Gets the task that failed, if any. */
-  Future get failedTask => _failedTask;
-
-  /**
-   * Wait for [task] to complete.
-   *
-   * If this group has already been marked as completed, you'll get a
-   * [StateError].
-   *
-   * If this group has a [failedTask], new tasks will be ignored, because the
-   * error has already been signaled.
-   */
-  void add(Future task) {
-    if (_failedTask != null) return;
-    if (_pending == _FINISHED) throw new StateError("Future already completed");
-
-    _pending++;
-    var i = results.length;
-    results.add(null);
-    task.then((res) {
-      results[i] = res;
-      if (_failedTask != null) return;
-      _pending--;
-      if (_pending == 0) {
-        _pending = _FINISHED;
-        _completer.complete(results);
-      }
-    }, onError: (e) {
-      if (_failedTask != null) return;
-      _failedTask = task;
-      _completer.completeError(e, getAttachedStackTrace(e));
-    });
-  }
-
-  Future<List> get future => _completer.future;
-}
-
-
-/**
- * Escapes [text] for use in a Dart string.
- * [single] specifies single quote `'` vs double quote `"`.
- * [triple] indicates that a triple-quoted string, such as `'''` or `"""`.
- */
-String escapeDartString(String text, {bool single: true, bool triple: false}) {
-  // Note: don't allocate anything until we know we need it.
-  StringBuffer result = null;
-
-  for (int i = 0; i < text.length; i++) {
-    int code = text.codeUnitAt(i);
-    var replace = null;
-    switch (code) {
-      case 92/*'\\'*/: replace = r'\\'; break;
-      case 36/*r'$'*/: replace = r'\$'; break;
-      case 34/*'"'*/:  if (!single) replace = r'\"'; break;
-      case 39/*"'"*/:  if (single) replace = r"\'"; break;
-      case 10/*'\n'*/: if (!triple) replace = r'\n'; break;
-      case 13/*'\r'*/: if (!triple) replace = r'\r'; break;
-
-      // Note: we don't escape unicode characters, under the assumption that
-      // writing the file in UTF-8 will take care of this.
-
-      // TODO(jmesserly): do we want to replace any other non-printable
-      // characters (such as \f) for readability?
-    }
-
-    if (replace != null && result == null) {
-      result = new StringBuffer(text.substring(0, i));
-    }
-
-    if (result != null) result.write(replace != null ? replace : text[i]);
-  }
-
-  return result == null ? text : result.toString();
-}
-
-/** Iterates through an infinite sequence, starting from zero. */
-class IntIterator implements Iterator<int> {
-  int _next = -1;
-
-  int get current => _next < 0 ? null : _next;
-
-  bool moveNext() {
-    _next++;
-    return true;
-  }
+  return sb.toString();
 }
diff --git a/pkg/polymer/lib/src/utils_observe.dart b/pkg/polymer/lib/src/utils_observe.dart
deleted file mode 100644
index b568d0c..0000000
--- a/pkg/polymer/lib/src/utils_observe.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library polymer.src.utils_observe;
-
-/**
- * Converts a string name with hyphens into an identifier, by removing hyphens
- * and capitalizing the following letter. Optionally [startUppercase] to
- * captialize the first letter.
- */
-String toCamelCase(String hyphenedName, {bool startUppercase: false}) {
-  var segments = hyphenedName.split('-');
-  int start = startUppercase ? 0 : 1;
-  for (int i = start; i < segments.length; i++) {
-    var segment = segments[i];
-    if (segment.length > 0) {
-      // Character between 'a'..'z' mapped to 'A'..'Z'
-      segments[i] = '${segment[0].toUpperCase()}${segment.substring(1)}';
-    }
-  }
-  return segments.join('');
-}
-
-String toHyphenedName(String word) {
-  var sb = new StringBuffer();
-  for (int i = 0; i < word.length; i++) {
-    var lower = word[i].toLowerCase();
-    if (word[i] != lower && i > 0) sb.write('-');
-    sb.write(lower);
-  }
-  return sb.toString();
-}
diff --git a/pkg/polymer/lib/testing/content_shell_test.dart b/pkg/polymer/lib/testing/content_shell_test.dart
deleted file mode 100644
index cc60912..0000000
--- a/pkg/polymer/lib/testing/content_shell_test.dart
+++ /dev/null
@@ -1,226 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Helper library to run tests in content_shell
- */
-library polymer.testing.end2end;
-
-import 'dart:io';
-import 'package:args/args.dart';
-import 'package:path/path.dart' as path;
-import 'package:unittest/unittest.dart';
-import 'package:polymer/deploy.dart' as deploy;
-
-
-/**
- * Compiles [testFile] with the web-ui compiler, and then runs the output as a
- * unit test in content_shell.
- */
-void endToEndTests(String inputDir, String outDir, {List<String> arguments}) {
-  _testHelper(new _TestOptions(inputDir, inputDir, null, outDir,
-      arguments: arguments));
-}
-
-/**
- * Compiles [testFile] with the web-ui compiler, and then runs the output as a
- * render test in content_shell.
- */
-void renderTests(String webDir, String inputDir, String expectedDir,
-    String outDir, {List<String> arguments, String script, String pattern,
-    bool deleteDir: true}) {
-  _testHelper(new _TestOptions(webDir, inputDir, expectedDir, outDir,
-      arguments: arguments, script: script, pattern: pattern,
-      deleteDir: deleteDir));
-}
-
-void _testHelper(_TestOptions options) {
-  expect(options, isNotNull);
-
-  var paths = new Directory(options.inputDir).listSync()
-      .where((f) => f is File).map((f) => f.path)
-      .where((p) => p.endsWith('_test.html') && options.pattern.hasMatch(p));
-
-  if (paths.isEmpty) return;
-
-  // First clear the output folder. Otherwise we can miss bugs when we fail to
-  // generate a file.
-  var dir = new Directory(options.outDir);
-  if (dir.existsSync() && options.deleteDir) {
-    print('Cleaning old output for ${path.normalize(options.outDir)}');
-    dir.deleteSync(recursive: true);
-  }
-  dir.createSync(recursive: true);
-
-  for (var filePath in paths) {
-    var filename = path.basename(filePath);
-    test('compile $filename', () {
-      return deploy.runForTest(options.webDir, options.outDir);
-    });
-  }
-
-  var filenames = paths.map(path.basename).toList();
-  // Sort files to match the order in which run.sh runs diff.
-  filenames.sort();
-
-  var finalOutDir = path.join(options.outDir, options.inputDir);
-  var outBaseDir = path.join(options.outDir, options.webDir);
-
-  runTests(String search) {
-    var output;
-
-    for (var filename in filenames) {
-      test('content_shell run $filename$search', () {
-        var lnArgs = ['-s', '$outBaseDir/packages', '$finalOutDir/packages'];
-        return Process.run('ln', lnArgs).then((_) {
-          var args = ['--dump-render-tree',
-              'file://$finalOutDir/$filename$search'];
-          var env = {'DART_FLAGS': '--checked'};
-          return Process.run('content_shell', args, environment: env)
-              .then((res) {
-                expect(res.exitCode, 0, reason: 'content_shell exit code: '
-                    '${res.exitCode}. Contents of stderr: \n${res.stderr}');
-                var outs = res.stdout.split('#EOF\n')
-                  .where((s) => !s.trim().isEmpty).toList();
-                expect(outs.length, 1);
-                output = outs.first;
-              });
-        });
-      });
-
-      test('verify $filename $search', () {
-        expect(output, isNotNull, reason:
-          'Output not available, maybe content_shell failed to run.');
-        var outPath = path.join(options.outDir, '$filename.txt');
-        new File(outPath).writeAsStringSync(output);
-        if (options.isRenderTest) {
-          var expectedPath = path.join(options.expectedDir, '$filename.txt');
-          var expected = new File(expectedPath).readAsStringSync();
-          expect(output, expected, reason: 'unexpected output for <$filename>');
-        } else {
-          bool passes = matches(
-              new RegExp('All .* tests passed')).matches(output, {});
-          expect(passes, true, reason: 'unit test failed:\n$output');
-        }
-      });
-    }
-  }
-
-  bool compiled = false;
-  ensureCompileToJs() {
-    if (compiled) return;
-    compiled = true;
-
-    for (var filename in filenames) {
-      test('dart2js $filename', () {
-        // TODO(jmesserly): this depends on DWC's output scheme.
-        // Alternatively we could use html5lib to find the script tag.
-        var inPath = '${filename}_bootstrap.dart';
-        var outPath = '${inPath}.js';
-
-        inPath = path.join(finalOutDir, inPath);
-        outPath = path.join(finalOutDir, outPath);
-
-        expect(Process.run('dart2js', ['-o$outPath', inPath]).then((res) {
-          expect(res.exitCode, 0, reason: 'dart2js exit code: '
-            '${res.exitCode}. Contents of stderr: \n${res.stderr}. '
-            'Contents of stdout: \n${res.stdout}.');
-          expect(new File(outPath).existsSync(), true, reason: 'input file '
-            '$inPath should have been compiled to $outPath.');
-        }), completes);
-      });
-    }
-  }
-
-  if (options.runAsDart) {
-    runTests('');
-  }
-  if (options.runAsJs) {
-    ensureCompileToJs();
-    runTests('?js=1');
-  }
-  if (options.forcePolyfillShadowDom) {
-    ensureCompileToJs();
-    runTests('?js=1&shadowdomjs=1');
-  }
-}
-
-class _TestOptions {
-  final String webDir;
-  final String inputDir;
-
-  final String expectedDir;
-  bool get isRenderTest => expectedDir != null;
-
-  final String outDir;
-  final bool deleteDir;
-
-  final bool runAsDart;
-  final bool runAsJs;
-  final bool forcePolyfillShadowDom;
-
-  final List<String> compilerArgs;
-  final RegExp pattern;
-
-  factory _TestOptions(String webDir, String inputDir, String expectedDir,
-      String outDir, {List<String> arguments, String script, String pattern,
-      bool deleteDir: true}) {
-    if (arguments == null) arguments = new Options().arguments;
-    if (script == null) script = new Options().script;
-
-    var args = _parseArgs(arguments, script);
-    if (args == null) return null;
-    var compilerArgs = args.rest;
-    var filePattern;
-    if (pattern != null) {
-      filePattern = new RegExp(pattern);
-    } else if (compilerArgs.length > 0) {
-      filePattern = new RegExp(compilerArgs[0]);
-      compilerArgs = compilerArgs.sublist(1);
-    } else {
-      filePattern = new RegExp('.');
-    }
-
-    var scriptDir = path.absolute(path.dirname(script));
-    webDir = path.relative(path.join(scriptDir, webDir));
-    inputDir = path.relative(path.join(scriptDir, inputDir));
-    outDir = path.join(scriptDir, outDir);
-    if (expectedDir != null) {
-      expectedDir = path.join(scriptDir, expectedDir);
-    }
-
-    return new _TestOptions._(webDir, inputDir, expectedDir, outDir, deleteDir,
-        args['dart'] == true, args['js'] == true, args['shadowdom'] == true,
-        compilerArgs, filePattern);
-  }
-
-  _TestOptions._(this.webDir, this.inputDir, this.expectedDir, this.outDir,
-      this.deleteDir, this.runAsDart, this.runAsJs,
-      this.forcePolyfillShadowDom, this.compilerArgs, this.pattern);
-}
-
-ArgResults _parseArgs(List<String> arguments, String script) {
-  var parser = new ArgParser()
-    ..addFlag('dart', abbr: 'd', help: 'run on Dart VM', defaultsTo: true)
-    ..addFlag('js', abbr: 'j', help: 'run compiled dart2js', defaultsTo: true)
-    ..addFlag('shadowdom', abbr: 's',
-        help: 'run dart2js and polyfilled ShadowDOM', defaultsTo: true)
-    ..addFlag('help', abbr: 'h', help: 'Displays this help message',
-        defaultsTo: false, negatable: false);
-
-  showUsage() {
-    print('Usage: $script [options...] [test_name_regexp]');
-    print(parser.getUsage());
-    return null;
-  }
-
-  try {
-    var results = parser.parse(arguments);
-    if (results['help']) return showUsage();
-    return results;
-  } on FormatException catch (e) {
-    print(e.message);
-    return showUsage();
-  }
-}
diff --git a/pkg/polymer/lib/testing/testing.js b/pkg/polymer/lib/testing/testing.js
deleted file mode 100644
index 3c22f05..0000000
--- a/pkg/polymer/lib/testing/testing.js
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-(function() {
-  var undoReplaceScripts = [];
-
-  var flags = {};
-  // populate flags from location
-  location.search.slice(1).split('&').forEach(function(o) {
-    o = o.split('=');
-    o[0] && (flags[o[0]] = o[1] || true);
-  });
-
-  // Webkit is migrating from layoutTestController to testRunner, we use
-  // layoutTestController as a fallback until that settles in.
-  var runner = window.testRunner || window.layoutTestController;
-
-  if (runner) {
-    runner.dumpAsText();
-    runner.waitUntilDone();
-  }
-
-  function dumpDOM() {
-    // Undo any scripts that were modified.
-    undoReplaceScripts.forEach(function(undo) { undo(); });
-
-    function expandShadowRoot(node) {
-      for (var n = node.firstChild; n; n = n.nextSibling) {
-        expandShadowRoot(n);
-      }
-      var shadow = node.shadowRoot || node.webkitShadowRoot ||
-          node.olderShadowRoot;
-
-      if (shadow) {
-        expandShadowRoot(shadow);
-
-        var name = 'shadow-root';
-        if (shadow == node.olderShadowRoot) name = 'older-' + name;
-
-        var fakeShadow = document.createElement(name);
-        while (shadow.firstChild) fakeShadow.appendChild(shadow.firstChild);
-        node.insertBefore(fakeShadow, node.firstChild);
-      }
-    }
-
-    // TODO(jmesserly): use querySelector to workaround unwrapped "document".
-    expandShadowRoot(document.querySelector('body'));
-
-    // Clean up all of the junk added to the DOM by js-interop and shadow CSS
-    // TODO(jmesserly): it seems like we're leaking lots of dart-port attributes
-    // for the document elemenet
-    function cleanTree(node) {
-      for (var n = node.firstChild; n; n = n.nextSibling) {
-        cleanTree(n);
-      }
-
-      // TODO(terry): Need to remove attributes in the dart-port: namespace
-      //              these are added for JS interop. See bug
-      //              https://code.google.com/p/dart/issues/detail?id=12645
-      //              The new dart:js shouldn't need these attrs for dart2js or
-      //              Dartium (won't need with native support) then remove the
-      //              below code.
-      // Remove JS interop dart-port attributes,
-      if (node.tagName == 'HTML' && node.attributes) {
-        for (var i = node.attributes.length; i--; i >= 0) {
-          var attrNode = node.attributes[i];
-          if (attrNode && attrNode.name.indexOf('dart-port:') == 0) {
-            node.removeAttributeNode(attrNode);
-          }
-        }
-      }
-
-      // We remove the contents of style tags so that we can compare both runs
-      // with and without the runtmie css shim. We keep the STYLE right under
-      // HEAD, because it is not affected by the shim.
-      if (node.tagName == 'STYLE') {
-        if (node.attributes['shadowcssshim'] != null) {
-          node.parentNode.removeChild(node);
-        } else if (node.parentNode.tagName != "HEAD") {
-          node.textContent = '/* style hidden by testing.js */'
-        }
-      }
-
-      if (node.tagName == 'SCRIPT') {
-        if (node.textContent.indexOf('_DART_TEMPORARY_ATTACHED') >= 0)  {
-          node.parentNode.removeChild(node);
-        } else {
-          // Remove the JS Interop script.
-          var typeAttr = node.getAttributeNode("type");
-          if (typeAttr && typeAttr.value == "text/javascript") {
-            if (node.textContent.indexOf(
-                "(function() {\n  // Proxy support for js.dart.\n\n") == 0) {
-              node.parentNode.removeChild(node);
-            }
-          }
-        }
-      }
-    }
-
-    // TODO(jmesserly): use querySelector to workaround unwrapped "document".
-    cleanTree(document.querySelector('html'));
-
-    var out = document.createElement('pre');
-    out.textContent = document.documentElement.outerHTML;
-    document.body.innerHTML = '';
-    document.body.appendChild(out);
-  }
-
-  function messageHandler(e) {
-    if (e.data == 'done' && runner) {
-      // On success, dump the DOM. Convert shadowRoot contents into
-      // <shadow-root>
-      dumpDOM();
-      runner.notifyDone();
-    }
-  }
-
-  window.addEventListener('message', messageHandler, false);
-
-  function errorHandler(e) {
-    if (runner) {
-      window.setTimeout(function() { runner.notifyDone(); }, 0);
-    }
-    window.console.log('FAIL');
-  }
-
-  window.addEventListener('error', errorHandler, false);
-
-  if (navigator.webkitStartDart && !flags.js) {
-    // TODO(jmesserly): fix this so we don't need to copy from browser/dart.js
-    if (!navigator.webkitStartDart()) {
-      document.body.innerHTML = 'This build has expired.  Please download a new Dartium at http://www.dartlang.org/dartium/index.html';
-    }
-  } else {
-    if (flags.shadowdomjs) {
-      // Allow flags to force polyfill of ShadowDOM so we can test it.
-      window.__forceShadowDomPolyfill = true;
-    }
-
-    // TODO:
-    // - Support in-browser compilation.
-    // - Handle inline Dart scripts.
-    window.addEventListener("DOMContentLoaded", function (e) {
-      // Fall back to compiled JS. Run through all the scripts and
-      // replace them if they have a type that indicate that they source
-      // in Dart code.
-      //
-      //   <script type="application/dart" src="..."></script>
-      //
-      var scripts = document.getElementsByTagName("script");
-      var length = scripts.length;
-      for (var i = 0; i < length; ++i) {
-        var script = scripts[i];
-        if (script.type == "application/dart") {
-          // Remap foo.dart to foo.dart.js.
-          if (script.src && script.src != '') {
-            var jsScript = document.createElement('script');
-            jsScript.src = script.src.replace(/\.dart(?=\?|$)/, '.dart.js');
-            var parent = script.parentNode;
-            // TODO(vsm): Find a solution for issue 8455 that works with more
-            // than one script.
-            document.currentScript = jsScript;
-
-            undoReplaceScripts.push(function() {
-              parent.replaceChild(script, jsScript);
-            });
-            parent.replaceChild(jsScript, script);
-          }
-        }
-      }
-    }, false);
-  }
-
-})();
diff --git a/pkg/polymer/lib/transformer.dart b/pkg/polymer/lib/transformer.dart
new file mode 100644
index 0000000..5f4dc02
--- /dev/null
+++ b/pkg/polymer/lib/transformer.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/** Transfomers used for pub-serve and pub-deploy. */
+// TODO(sigmund): move into a plugin directory when pub supports it.
+library polymer.src.transform;
+
+import 'package:observe/transform.dart';
+import 'src/build/code_extractor.dart';
+import 'src/build/import_inliner.dart';
+import 'src/build/script_compactor.dart';
+import 'src/build/polyfill_injector.dart';
+import 'src/build/common.dart';
+
+export 'src/build/code_extractor.dart';
+export 'src/build/import_inliner.dart';
+export 'src/build/script_compactor.dart';
+export 'src/build/polyfill_injector.dart';
+export 'src/build/common.dart' show TransformOptions;
+
+/** Creates phases to deploy a polymer application. */
+List<List<Transformer>> createDeployPhases(TransformOptions options) {
+  return [
+    [new InlineCodeExtractor(options)],
+    [new ObservableTransformer()],
+    [new ImportedElementInliner(options)],
+    [new ScriptCompactor(options)],
+    [new PolyfillInjector(options)]
+  ];
+}
diff --git a/pkg/polymer/pubspec.yaml b/pkg/polymer/pubspec.yaml
index eb03098..fd765fd 100644
--- a/pkg/polymer/pubspec.yaml
+++ b/pkg/polymer/pubspec.yaml
@@ -4,7 +4,7 @@
   Polymer.dart is a new type of library for the web, built on top of Web
   Components, and designed to leverage the evolving web platform on modern
   browsers.
-homepage: https://www.dartlang.org
+homepage: https://www.dartlang.org/polymer-dart/
 dependencies:
   analyzer_experimental: any
   args: any
diff --git a/pkg/polymer/test/transform/all_phases_test.dart b/pkg/polymer/test/build/all_phases_test.dart
similarity index 97%
rename from pkg/polymer/test/transform/all_phases_test.dart
rename to pkg/polymer/test/build/all_phases_test.dart
index 81de2f9..e35347a 100644
--- a/pkg/polymer/test/transform/all_phases_test.dart
+++ b/pkg/polymer/test/build/all_phases_test.dart
@@ -2,15 +2,16 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transform.all_phases_test;
+library polymer.test.build.all_phases_test;
 
-import 'package:polymer/src/transform.dart';
+import 'package:polymer/transformer.dart';
 import 'package:unittest/compact_vm_config.dart';
 
 import 'common.dart';
 
 void main() {
   useCompactVMConfiguration();
+  var phases = createDeployPhases(new TransformOptions());
 
   testPhases('no changes', phases, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
@@ -211,7 +212,7 @@
   set $fieldName(int value) {
     __\$$fieldName = notifyPropertyChange(const Symbol('$fieldName'), __\$$fieldName, value);
   }
-  
+
   $className($fieldName) : __\$$fieldName = $fieldName;
 }
 ''';
diff --git a/pkg/polymer/test/transform/code_extractor_test.dart b/pkg/polymer/test/build/code_extractor_test.dart
similarity index 85%
rename from pkg/polymer/test/transform/code_extractor_test.dart
rename to pkg/polymer/test/build/code_extractor_test.dart
index 72aefb9..3130faf 100644
--- a/pkg/polymer/test/transform/code_extractor_test.dart
+++ b/pkg/polymer/test/build/code_extractor_test.dart
@@ -2,24 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transform.code_extractor_test;
+library polymer.test.build.code_extractor_test;
 
-import 'package:polymer/src/transform/code_extractor.dart';
+import 'package:polymer/src/build/code_extractor.dart';
+import 'package:polymer/src/build/common.dart';
 import 'package:unittest/compact_vm_config.dart';
 
 import 'common.dart';
 
 void main() {
   useCompactVMConfiguration();
+  var phases = [[new InlineCodeExtractor(new TransformOptions())]];
 
-  testPhases('no changes', [[new InlineCodeExtractor()]], {
+  testPhases('no changes', phases, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     }, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     });
 
-  testPhases('single script, no library in script',
-      [[new InlineCodeExtractor()]], {
+  testPhases('single script, no library in script', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart">main() { }</script>',
@@ -33,7 +34,7 @@
           'library web_test_html_0;\nmain() { }',
     });
 
-  testPhases('single script, with library', [[new InlineCodeExtractor()]], {
+  testPhases('single script, with library', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart">library f;\nmain() { }</script>',
@@ -47,8 +48,7 @@
           'library f;\nmain() { }',
     });
 
-  testPhases('under lib/ directory also transformed',
-      [[new InlineCodeExtractor()]], {
+  testPhases('under lib/ directory also transformed', phases, {
       'a|lib/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart">library f;\nmain() { }</script>',
@@ -62,7 +62,7 @@
           'library f;\nmain() { }',
     });
 
-  testPhases('multiple scripts', [[new InlineCodeExtractor()]], {
+  testPhases('multiple scripts', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart">library a1;\nmain1() { }</script>'
@@ -81,7 +81,7 @@
           'library a2;\nmain2() { }',
     });
 
-  testPhases('multiple deeper scripts', [[new InlineCodeExtractor()]], {
+  testPhases('multiple deeper scripts', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart">main1() { }</script>'
diff --git a/pkg/polymer/test/transform/common.dart b/pkg/polymer/test/build/common.dart
similarity index 91%
rename from pkg/polymer/test/transform/common.dart
rename to pkg/polymer/test/build/common.dart
index f1d8500..b855938 100644
--- a/pkg/polymer/test/transform/common.dart
+++ b/pkg/polymer/test/build/common.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transfom.common;
+library polymer.test.build.common;
 
 import 'dart:async';
 
@@ -16,6 +16,10 @@
   return new AssetId(s.substring(0, index), s.substring(index + 1));
 }
 
+String _removeTrailingWhitespace(String str) =>
+    str.splitMapJoin('\n',
+        onNonMatch: (s) => s.replaceAll(new RegExp(r'\s+$'), ''));
+
 /**
  * A helper package provider that has files stored in memory, also wraps
  * [Barback] to simply our tests.
@@ -74,6 +78,8 @@
 
   Future check(String assetIdString, String content) {
     return this[assetIdString].then((value) {
+      value = _removeTrailingWhitespace(value);
+      content = _removeTrailingWhitespace(content);
       expect(value, content, reason: 'Final output of $assetIdString differs.');
     });
   }
diff --git a/pkg/polymer/test/transform/import_inliner_test.dart b/pkg/polymer/test/build/import_inliner_test.dart
similarity index 92%
rename from pkg/polymer/test/transform/import_inliner_test.dart
rename to pkg/polymer/test/build/import_inliner_test.dart
index fbc405f..8654107 100644
--- a/pkg/polymer/test/transform/import_inliner_test.dart
+++ b/pkg/polymer/test/build/import_inliner_test.dart
@@ -2,9 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transform.import_inliner_test;
+library polymer.test.build.import_inliner_test;
 
-import 'package:polymer/src/transform/import_inliner.dart';
+import 'package:polymer/src/build/common.dart';
+import 'package:polymer/src/build/import_inliner.dart';
 import 'package:unittest/compact_vm_config.dart';
 import 'package:unittest/unittest.dart';
 
@@ -12,13 +13,14 @@
 
 void main() {
   useCompactVMConfiguration();
-  testPhases('no changes', [[new ImportedElementInliner()]], {
+  var phases = [[new ImportedElementInliner(new TransformOptions())]];
+  testPhases('no changes', phases, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     }, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     });
 
-  testPhases('empty import', [[new ImportedElementInliner()]], {
+  testPhases('empty import', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="">' // empty href
@@ -36,7 +38,7 @@
           '</head><body></body></html>',
     });
 
-  testPhases('shallow, no elements', [[new ImportedElementInliner()]], {
+  testPhases('shallow, no elements', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test2.html">'
@@ -53,7 +55,7 @@
           '</head></html>',
     });
 
-  testPhases('shallow, elements, one import', [[new ImportedElementInliner()]],
+  testPhases('shallow, elements, one import', phases,
     {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
@@ -73,7 +75,7 @@
           '</head><body><polymer-element>2</polymer-element></html>',
     });
 
-  testPhases('no transformation outside web/', [[new ImportedElementInliner()]],
+  testPhases('no transformation outside web/', phases,
     {
       'a|lib/test.html':
           '<!DOCTYPE html><html><head>'
@@ -92,7 +94,7 @@
           '</head><body><polymer-element>2</polymer-element></html>',
     });
 
-  testPhases('shallow, elements, many', [[new ImportedElementInliner()]],
+  testPhases('shallow, elements, many', phases,
     {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
@@ -120,7 +122,7 @@
           '</head><body><polymer-element>3</polymer-element></html>',
     });
 
-  testPhases('deep, elements, one per file', [[new ImportedElementInliner()]], {
+  testPhases('deep, elements, one per file', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test2.html">'
@@ -158,7 +160,7 @@
           '</head><body><polymer-element>4</polymer-element></html>',
     });
 
-  testPhases('deep, elements, many imports', [[new ImportedElementInliner()]], {
+  testPhases('deep, elements, many imports', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test2a.html">'
@@ -233,7 +235,7 @@
           '</body></html>',
     });
 
-  testPhases('imports cycle, 1-step lasso', [[new ImportedElementInliner()]], {
+  testPhases('imports cycle, 1-step lasso', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test_1.html">'
@@ -264,7 +266,7 @@
           '<polymer-element>2</polymer-element></body></html>',
     });
 
-  testPhases('imports cycle, 2-step lasso', [[new ImportedElementInliner()]], {
+  testPhases('imports cycle, 2-step lasso', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test_1.html">'
@@ -308,7 +310,7 @@
           '<polymer-element>3</polymer-element></body></html>',
     });
 
-  testPhases('imports cycle, self cycle', [[new ImportedElementInliner()]], {
+  testPhases('imports cycle, self cycle', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test_1.html">'
@@ -328,7 +330,7 @@
           '<polymer-element>1</polymer-element></body></html>',
     });
 
-  testPhases('imports DAG', [[new ImportedElementInliner()]], {
+  testPhases('imports DAG', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<link rel="import" href="test_1.html">'
diff --git a/pkg/polymer/test/linter_test.dart b/pkg/polymer/test/build/linter_test.dart
similarity index 98%
rename from pkg/polymer/test/linter_test.dart
rename to pkg/polymer/test/build/linter_test.dart
index 1b4c348..c2eb75e 100644
--- a/pkg/polymer/test/linter_test.dart
+++ b/pkg/polymer/test/build/linter_test.dart
@@ -4,12 +4,13 @@
 
 library polymer.test.linter_test;
 
+import 'package:polymer/src/build/common.dart';
+import 'package:polymer/src/build/linter.dart';
 import 'package:source_maps/span.dart';
-import 'package:polymer/src/linter.dart';
 import 'package:unittest/compact_vm_config.dart';
 import 'package:unittest/unittest.dart';
 
-import 'transform/common.dart';
+import 'common.dart';
 
 void main() {
   useCompactVMConfiguration();
@@ -23,7 +24,7 @@
     _testLinter('in web', {
         'a|web/test.html': '<html></html>',
       }, {
-        'a|web/test.html.messages': 
+        'a|web/test.html.messages':
             'warning: Unexpected start tag (html). Expected DOCTYPE. '
             '(web/test.html 0 0)',
       });
@@ -400,7 +401,7 @@
 }
 
 _testLinter(String name, Map inputFiles, Map outputMessages) {
-  var linter = new Linter(_testFormatter);
+  var linter = new Linter(new TransformOptions(), _testFormatter);
   var outputFiles = {};
   inputFiles.forEach((k, v) => outputFiles[k] = v);
   outputMessages.forEach((k, v) => outputFiles[k] = v);
diff --git a/pkg/polymer/test/transform/polyfill_injector_test.dart b/pkg/polymer/test/build/polyfill_injector_test.dart
similarity index 80%
rename from pkg/polymer/test/transform/polyfill_injector_test.dart
rename to pkg/polymer/test/build/polyfill_injector_test.dart
index e8bbb89..124b21b 100644
--- a/pkg/polymer/test/transform/polyfill_injector_test.dart
+++ b/pkg/polymer/test/build/polyfill_injector_test.dart
@@ -2,23 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transform.polyfill_injector_test;
+library polymer.test.build.polyfill_injector_test;
 
-import 'package:polymer/src/transform.dart';
+import 'package:polymer/src/build/common.dart';
+import 'package:polymer/src/build/polyfill_injector.dart';
 import 'package:unittest/compact_vm_config.dart';
 
 import 'common.dart';
 
 void main() {
   useCompactVMConfiguration();
+  var phases = [[new PolyfillInjector(new TransformOptions())]];
 
-  testPhases('no changes', [[new PolyfillInjector()]], {
+  testPhases('no changes', phases, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     }, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     });
 
-  testPhases('no changes under lib ', [[new PolyfillInjector()]], {
+  testPhases('no changes under lib ', phases, {
       'a|lib/test.html':
           '<!DOCTYPE html><html><head></head><body>'
           '<script type="application/dart" src="a.dart"></script>',
@@ -28,7 +30,7 @@
           '<script type="application/dart" src="a.dart"></script>',
     });
 
-  testPhases('with some script', [[new PolyfillInjector()]], {
+  testPhases('with some script', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head></head><body>'
           '<script type="application/dart" src="a.dart"></script>',
@@ -40,7 +42,7 @@
           '</body></html>',
     });
 
-  testPhases('interop/shadow dom already present', [[new PolyfillInjector()]], {
+  testPhases('interop/shadow dom already present', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head></head><body>'
           '<script type="application/dart" src="a.dart"></script>'
diff --git a/pkg/polymer/test/transform/script_compactor_test.dart b/pkg/polymer/test/build/script_compactor_test.dart
similarity index 87%
rename from pkg/polymer/test/transform/script_compactor_test.dart
rename to pkg/polymer/test/build/script_compactor_test.dart
index 1588bd1..7f0c390 100644
--- a/pkg/polymer/test/transform/script_compactor_test.dart
+++ b/pkg/polymer/test/build/script_compactor_test.dart
@@ -2,23 +2,25 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library polymer.test.transform.script_compactor_test;
+library polymer.test.build.script_compactor_test;
 
-import 'package:polymer/src/transform/script_compactor.dart';
+import 'package:polymer/src/build/common.dart';
+import 'package:polymer/src/build/script_compactor.dart';
 import 'package:unittest/compact_vm_config.dart';
 
 import 'common.dart';
 
 void main() {
   useCompactVMConfiguration();
+  var phases = [[new ScriptCompactor(new TransformOptions())]];
 
-  testPhases('no changes', [[new ScriptCompactor()]], {
+  testPhases('no changes', phases, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     }, {
       'a|web/test.html': '<!DOCTYPE html><html></html>',
     });
 
-  testPhases('no changes outside web/', [[new ScriptCompactor()]], {
+  testPhases('no changes outside web/', phases, {
       'a|lib/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart" src="a.dart"></script>',
@@ -28,7 +30,7 @@
           '<script type="application/dart" src="a.dart"></script>',
     });
 
-  testPhases('single script', [[new ScriptCompactor()]], {
+  testPhases('single script', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart" src="a.dart"></script>',
@@ -56,7 +58,7 @@
           '''.replaceAll('\n          ', '\n'),
     });
 
-  testPhases('several scripts', [[new ScriptCompactor()]], {
+  testPhases('several scripts', phases, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head>'
           '<script type="application/dart" src="a.dart"></script>'
diff --git a/pkg/polymer/test/compiler_test.dart b/pkg/polymer/test/compiler_test.dart
deleted file mode 100644
index abe5e32..0000000
--- a/pkg/polymer/test/compiler_test.dart
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** End-to-end tests for the [Compiler] API. */
-library compiler_test;
-
-import 'package:logging/logging.dart' show Level;
-import 'package:path/path.dart' as path;
-import 'package:polymer/src/messages.dart';
-import 'package:unittest/compact_vm_config.dart';
-import 'package:unittest/unittest.dart';
-
-import 'testing.dart';
-
-main() {
-  useCompactVMConfiguration();
-
-  test('recursive dependencies', () {
-    var messages = new Messages.silent();
-    var compiler = createCompiler({
-      'index.html': '<head>'
-                    '<link rel="import" href="foo.html">'
-                    '<link rel="import" href="bar.html">'
-                    '<body><x-foo></x-foo><x-bar></x-bar>'
-                    '<script type="application/dart">main() {}</script>',
-      'foo.html': '<head><link rel="import" href="bar.html">'
-                  '<body><polymer-element name="x-foo" constructor="Foo">'
-                  '<template><x-bar>',
-      'bar.html': '<head><link rel="import" href="foo.html">'
-                  '<body><polymer-element name="x-bar" constructor="Boo">'
-                  '<template><x-foo>',
-    }, messages);
-
-    compiler.run().then(expectAsync1((e) {
-      MockFileSystem fs = compiler.fileSystem;
-      expect(fs.readCount, equals({
-        'index.html': 1,
-        'foo.html': 1,
-        'bar.html': 1
-      }), reason: 'Actual:\n  ${fs.readCount}');
-    }));
-  });
-
-  group('missing files', () {
-    test('main script', () {
-      var messages = new Messages.silent();
-      var compiler = createCompiler({
-        'index.html': '<head></head><body>'
-            '<script type="application/dart" src="notfound.dart"></script>'
-            '</body>',
-      }, messages);
-
-      compiler.run().then(expectAsync1((e) {
-        var msgs = messages.messages.where((m) =>
-            m.message.contains('unable')).toList();
-        expect(msgs.length, 0);
-        MockFileSystem fs = compiler.fileSystem;
-        expect(fs.readCount, { 'index.html': 1 });
-      }));
-    });
-
-    test('component html', () {
-      var messages = new Messages.silent();
-      var compiler = createCompiler({
-        'index.html': '<head>'
-            '<link rel="import" href="notfound.html">'
-            '<body><x-foo>'
-            '<script type="application/dart">main() {}</script>',
-      }, messages);
-
-      compiler.run().then(expectAsync1((e) {
-        var msgs = messages.messages.where((m) =>
-            m.message.contains('unable')).toList();
-
-        expect(msgs.length, 1);
-        expect(msgs[0].level, Level.SEVERE);
-        expect(msgs[0].message, contains('unable to open file'));
-        expect(msgs[0].span, isNotNull);
-        expect(msgs[0].span.sourceUrl, 'index.html');
-
-        MockFileSystem fs = compiler.fileSystem;
-        expect(fs.readCount, { 'index.html': 1, 'notfound.html': 1 });
-      }));
-    });
-
-    test('component script', () {
-      var messages = new Messages.silent();
-      var compiler = createCompiler({
-        'index.html': '<head>'
-            '<link rel="import" href="foo.html">'
-            '<body><x-foo></x-foo>'
-            '<script type="application/dart">main() {}</script>'
-            '</body>',
-        'foo.html': '<body><polymer-element name="x-foo" constructor="Foo">'
-            '<template></template>'
-            '<script type="application/dart" src="notfound.dart"></script>',
-      }, messages);
-
-      compiler.run().then(expectAsync1((e) {
-        var msgs = messages.messages.where((m) =>
-            m.message.contains('unable')).toList();
-        expect(msgs.length, 0);
-        MockFileSystem fs = compiler.fileSystem;
-        expect(fs.readCount,
-            { 'index.html': 1, 'foo.html': 1 });
-      }));
-    });
-  });
-}
diff --git a/pkg/polymer/test/css_test.dart b/pkg/polymer/test/css_test.dart
deleted file mode 100644
index 9f4c734..0000000
--- a/pkg/polymer/test/css_test.dart
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library css_test;
-
-import 'package:path/path.dart' as path;
-import 'package:polymer/src/messages.dart';
-import 'package:polymer/src/utils.dart' as utils;
-import 'package:unittest/compact_vm_config.dart';
-import 'package:unittest/unittest.dart';
-
-import 'testing.dart';
-
-test_simple_var() {
-  Map createFiles() {
-    return {
-      'index.html':
-        '<!DOCTYPE html>'
-        '<html lang="en">'
-          '<head>'
-            '<meta charset="utf-8">'
-          '</head>'
-          '<body>'
-            '<style>'
-              '@main_color: var(b);'
-              '@b: var(c);'
-              '@c: red;'
-            '</style>'
-            '<style>'
-              '.test { color: var(main_color); }'
-            '</style>'
-            '<script type="application/dart">main() {}</script>'
-          '</body>'
-        '</html>',
-    };
-  }
-
-  var messages = new Messages.silent();
-  var compiler = createCompiler(createFiles(), messages, errors: true,
-      scopedCss: true);
-
-  compiler.run().then(expectAsync1((e) {
-    MockFileSystem fs = compiler.fileSystem;
-    expect(fs.readCount, equals({
-      'index.html': 1,
-    }), reason: 'Actual:\n  ${fs.readCount}');
-
-    var htmlInfo = compiler.info['index.html'];
-    expect(htmlInfo.styleSheets.length, 2);
-    expect(prettyPrintCss(htmlInfo.styleSheets[0]), '');
-    expect(prettyPrintCss(htmlInfo.styleSheets[1]), '.test { color: red; }');
-  }));
-}
-
-test_var() {
-  Map createFiles() {
-    return {
-      'index.html':
-        '<!DOCTYPE html>'
-        '<html lang="en">'
-          '<head>'
-            '<meta charset="utf-8">'
-          '</head>'
-          '<body>'
-            '<style>'
-              '@main-color: var(b);'
-              '@b: var(c);'
-              '@c: red;'
-              '@d: var(main-color-1, green);'
-              '@border-pen: solid;'
-              '@inset: 5px;'
-              '@frame-color: solid orange;'
-              '@big-border: 2px 2px 2px;'
-              '@border-stuff: 3px dashed var(main-color);'
-              '@border-2: 3px var(big-border) dashed var(main-color-1, green);'
-              '@blue-border: bold var(not-found, 1px 10px blue)'
-            '</style>'
-            '<style>'
-              '.test-1 { color: var(main-color-1, blue); }'
-              '.test-2 { color: var(main-color-1, var(main-color)); }'
-              '.test-3 { color: var(d, yellow); }'
-              '.test-4 { color: var(d-1, yellow); }'
-              '.test-5 { color: var(d-1, var(d)); }'
-              '.test-6 { border: var(inset) var(border-pen) var(d); }'
-              '.test-7 { border: 10px var(border-pen) var(d); }'
-              '.test-8 { border: 20px var(border-pen) yellow; }'
-              '.test-9 { border: 30px dashed var(d); }'
-              '.test-10 { border: 40px var(frame-color);}'
-              '.test-11 { border: 40px var(frame-color-1, blue);}'
-              '.test-12 { border: 40px var(frame-color-1, solid blue);}'
-              '.test-13 {'
-                 'border: 40px var(x1, var(x2, var(x3, var(frame-color)));'
-              '}'
-              '.test-14 { border: 40px var(x1, var(frame-color); }'
-              '.test-15 { border: 40px var(x1, solid blue);}'
-              '.test-16 { border: 1px 1px 2px 3px var(frame-color);}'
-              '.test-17 { border: 1px 1px 2px 3px var(x1, solid blue);}'
-              '.test-18 { border: 1px 1px 2px var(border-stuff);}'
-              '.test-19 { border: var(big-border) var(border-stuff);}'
-              '.test-20 { border: var(border-2);}'
-              '.test-21 { border: var(blue-border);}'
-            '</style>'
-            '<script type="application/dart">main() {}</script>'
-          '</body>'
-        '</html>',
-    };
-  }
-
-  var messages = new Messages.silent();
-  var compiler = createCompiler(createFiles(), messages, errors: true,
-    scopedCss: true);
-
-  compiler.run().then(expectAsync1((e) {
-    MockFileSystem fs = compiler.fileSystem;
-    expect(fs.readCount, equals({
-      'index.html': 1,
-    }), reason: 'Actual:\n  ${fs.readCount}');
-
-    var htmlInfo = compiler.info['index.html'];
-    expect(htmlInfo.styleSheets.length, 2);
-    expect(prettyPrintCss(htmlInfo.styleSheets[0]), '');
-    expect(prettyPrintCss(htmlInfo.styleSheets[1]),
-        '.test-1 { color: blue; } '
-        '.test-2 { color: red; } '
-        '.test-3 { color: green; } '
-        '.test-4 { color: yellow; } '
-        '.test-5 { color: green; } '
-        '.test-6 { border: 5px solid green; } '
-        '.test-7 { border: 10px solid green; } '
-        '.test-8 { border: 20px solid yellow; } '
-        '.test-9 { border: 30px dashed green; } '
-        '.test-10 { border: 40px solid orange; } '
-        '.test-11 { border: 40px blue; } '
-        '.test-12 { border: 40px solid blue; } '
-        '.test-13 { border: 40px solid orange; } '
-        '.test-14 { border: 40px solid orange; } '
-        '.test-15 { border: 40px solid blue; } '
-        '.test-16 { border: 1px 1px 2px 3px solid orange; } '
-        '.test-17 { border: 1px 1px 2px 3px solid blue; } '
-        '.test-18 { border: 1px 1px 2px 3px dashed red; } '
-        '.test-19 { border: 2px 2px 2px 3px dashed red; } '
-        '.test-20 { border: 3px 2px 2px 2px dashed green; } '
-        '.test-21 { border: bold 1px 10px blue; }');
-  }));
-}
-
-test_simple_import() {
-  Map createFiles() {
-    return {
-      'foo.css':  r'''@main_color: var(b);
-        @b: var(c);
-        @c: red;''',
-      'index.html':
-        '<!DOCTYPE html>'
-        '<html lang="en">'
-          '<head>'
-             '<meta charset="utf-8">'
-          '</head>'
-          '<body>'
-            '<style>'
-              '@import "foo.css";'
-              '.test { color: var(main_color); }'
-            '</style>'
-            '<script type="application/dart">main() {}</script>'
-          '</body>'
-        '</html>',
-    };
-  }
-
-  var messages = new Messages.silent();
-  var compiler = createCompiler(createFiles(), messages, errors: true,
-      scopedCss: true);
-
-  compiler.run().then(expectAsync1((e) {
-    MockFileSystem fs = compiler.fileSystem;
-    expect(fs.readCount, equals({
-      'foo.css': 1,
-      'index.html': 1,
-    }), reason: 'Actual:\n  ${fs.readCount}');
-
-    var cssInfo = compiler.info['foo.css'];
-    expect(cssInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(cssInfo.styleSheets[0]), '');
-
-    var htmlInfo = compiler.info['index.html'];
-    expect(htmlInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(htmlInfo.styleSheets[0]),
-        '@import url(foo.css); .test { color: red; }');
-  }));
-}
-
-test_imports() {
-  Map createFiles() {
-    return {
-      'first.css':
-        '@import "third.css";'
-        '@main-width: var(main-width-b);'
-        '@main-width-b: var(main-width-c);'
-        '@main-width-c: var(wide-width);',
-      'second.css':
-        '@import "fourth.css";'
-        '@main-color: var(main-color-b);'
-        '@main-color-b: var(main-color-c);'
-        '@main-color-c: var(color-value);',
-      'third.css':
-        '@wide-width: var(wide-width-b);'
-        '@wide-width-b: var(wide-width-c);'
-        '@wide-width-c: 100px;',
-      'fourth.css':
-        '@color-value: var(color-value-b);'
-        '@color-value-b: var(color-value-c);'
-        '@color-value-c: red;',
-      'index.html':
-        '<!DOCTYPE html>'
-        '<html lang="en">'
-          '<head>'
-            '<meta charset="utf-8">'
-            '<link rel="stylesheet" href="first.css">'
-          '</head>'
-          '<body>'
-            '<style>'
-              '@import "first.css";'
-              '@import "second.css";'
-              '.test-1 { color: var(main-color); }'
-              '.test-2 { width: var(main-width); }'
-            '</style>'
-            '<script type="application/dart">main() {}</script>'
-          '</body>'
-        '</html>',
-    };
-  }
-
-  var messages = new Messages.silent();
-  var compiler = createCompiler(createFiles(), messages, errors: true,
-      scopedCss: true);
-
-  compiler.run().then(expectAsync1((e) {
-    MockFileSystem fs = compiler.fileSystem;
-    expect(fs.readCount, equals({
-      'first.css': 1,
-      'second.css': 1,
-      'third.css': 1,
-      'fourth.css': 1,
-      'index.html': 1,
-    }), reason: 'Actual:\n  ${fs.readCount}');
-
-    var firstInfo = compiler.info['first.css'];
-    expect(firstInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(firstInfo.styleSheets[0]), '@import url(third.css);');
-
-    var secondInfo = compiler.info['second.css'];
-    expect(secondInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(secondInfo.styleSheets[0]),
-        '@import url(fourth.css);');
-
-    var thirdInfo = compiler.info['third.css'];
-    expect(thirdInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(thirdInfo.styleSheets[0]), '');
-
-    var fourthInfo = compiler.info['fourth.css'];
-    expect(fourthInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(fourthInfo.styleSheets[0]), '');
-
-    var htmlInfo = compiler.info['index.html'];
-    expect(htmlInfo.styleSheets.length, 1);
-    expect(prettyPrintCss(htmlInfo.styleSheets[0]),
-        '@import url(first.css); '
-        '@import url(second.css); '
-        '.test-1 { color: red; } '
-        '.test-2 { width: 100px; }');
-  }));
-}
-
-test_component_var() {
-  Map createFiles() {
-    return {
-      'index.html': '<!DOCTYPE html>'
-                    '<html lang="en">'
-                      '<head>'
-                        '<meta charset="utf-8">'
-                        '<link rel="import" href="foo.html">'
-                      '</head>'
-                      '<body>'
-                        '<x-foo></x-foo>'
-                        '<script type="application/dart">main() {}</script>'
-                      '</body>'
-                    '</html>',
-      'foo.html': '<!DOCTYPE html>'
-                  '<html lang="en">'
-                    '<head>'
-                      '<meta charset="utf-8">'
-                    '</head>'
-                    '<body>'
-                      '<polymer-element name="x-foo" constructor="Foo">'
-                        '<template>'
-                          '<style scoped>'
-                            '@import "foo.css";'
-                            '.main { color: var(main_color); }'
-                            '.test-background { '
-                              'background:  url(http://www.foo.com/bar.png);'
-                            '}'
-                          '</style>'
-                        '</template>'
-                      '</polymer-element>'
-                    '</body>'
-                  '</html>',
-      'foo.css':  r'''@main_color: var(b);
-                      @b: var(c);
-                      @c: red;
-
-                      @one: var(two);
-                      @two: var(one);
-
-                      @four: var(five);
-                      @five: var(six);
-                      @six: var(four);
-
-                      @def-1: var(def-2);
-                      @def-2: var(def-3);
-                      @def-3: var(def-2);''',
-    };
-  }
-
-  test('var- and Less @define', () {
-    var messages = new Messages.silent();
-    var compiler = createCompiler(createFiles(), messages, errors: true,
-      scopedCss: true);
-
-    compiler.run().then(expectAsync1((e) {
-      MockFileSystem fs = compiler.fileSystem;
-      expect(fs.readCount, equals({
-        'index.html': 1,
-        'foo.html': 1,
-        'foo.css': 1
-      }), reason: 'Actual:\n  ${fs.readCount}');
-
-      var cssInfo = compiler.info['foo.css'];
-      expect(cssInfo.styleSheets.length, 1);
-      var htmlInfo = compiler.info['foo.html'];
-      expect(htmlInfo.styleSheets.length, 0);
-      expect(htmlInfo.declaredComponents.length, 1);
-      expect(htmlInfo.declaredComponents[0].styleSheets.length, 1);
-
-      // TODO(sigmund,terry): reenable
-      //   if (file.path == 'out/index.html.css') {
-      //     expect(file.contents,
-      //         '/* Auto-generated from components style tags. */\n'
-      //         '/* DO NOT EDIT. */\n\n'
-      //         '/* ==================================================== \n'
-      //         '   Component x-foo stylesheet \n'
-      //         '   ==================================================== */\n'
-      //         '@import "foo.css";\n'
-      //         '[is="x-foo"] .main {\n'
-      //         '  color: #f00;\n'
-      //         '}\n'
-      //         '[is="x-foo"] .test-background {\n'
-      //         '  background: url("http://www.foo.com/bar.png");\n'
-      //         '}\n\n');
-      //   } else if (file.path == 'out/foo.css') {
-      //     expect(file.contents,
-      //         '/* Auto-generated from style sheet href = foo.css */\n'
-      //         '/* DO NOT EDIT. */\n\n\n\n');
-      //   }
-
-      // Check for warning messages about var- cycles in no expected order.
-      expect(messages.messages.length, 8);
-      int testBitMap = 0;
-      for (var errorMessage in messages.messages) {
-        var message = errorMessage.message;
-        if (message.contains('var cycle detected var-def-1')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 11);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@def-1: var(def-2)');
-          testBitMap |= 1 << 0;
-        } else if (message.contains('var cycle detected var-five')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 8);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@five: var(six)');
-          testBitMap |= 1 << 1;
-        } else if (message.contains('var cycle detected var-six')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 9);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@six: var(four)');
-          testBitMap |= 1 << 2;
-        } else if (message.contains('var cycle detected var-def-3')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 13);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@def-3: var(def-2)');
-          testBitMap |= 1 << 3;
-        } else if (message.contains('var cycle detected var-two')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 5);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@two: var(one)');
-          testBitMap |= 1 << 4;
-        } else if (message.contains('var cycle detected var-def-2')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 12);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@def-2: var(def-3)');
-          testBitMap |= 1 << 5;
-        } else if (message.contains('var cycle detected var-one')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 4);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@one: var(two)');
-          testBitMap |= 1 << 6;
-        } else if (message.contains('var cycle detected var-four')) {
-          expect(errorMessage.span, isNotNull);
-          expect(errorMessage.span.start.line, 7);
-          expect(errorMessage.span.start.column, 22);
-          expect(errorMessage.span.text, '@four: var(five)');
-          testBitMap |= 1 << 7;
-        }
-      }
-      expect(testBitMap, equals((1 << 8) - 1));
-    }));
-  });
-}
-
-test_pseudo_element() {
-  var messages = new Messages.silent();
-  var compiler = createCompiler({
-    'index.html': '<head>'
-                  '<link rel="import" href="foo.html">'
-                  '<style>'
-                    '.test::x-foo { background-color: red; }'
-                    '.test::x-foo1 { color: blue; }'
-                    '.test::x-foo2 { color: green; }'
-                  '</style>'
-                  '<body>'
-                    '<x-foo class=test></x-foo>'
-                    '<x-foo></x-foo>'
-                  '<script type="application/dart">main() {}</script>',
-    'foo.html': '<head>'
-                '<body><polymer-element name="x-foo" constructor="Foo">'
-                '<template>'
-                  '<div pseudo="x-foo">'
-                    '<div>Test</div>'
-                  '</div>'
-                  '<div pseudo="x-foo1 x-foo2">'
-                  '<div>Test</div>'
-                  '</div>'
-                '</template>',
-    }, messages, scopedCss: true);
-
-    compiler.run().then(expectAsync1((e) {
-      MockFileSystem fs = compiler.fileSystem;
-      expect(fs.readCount, equals({
-        'index.html': 1,
-        'foo.html': 1,
-      }), reason: 'Actual:\n  ${fs.readCount}');
-
-      // TODO(sigmund, terry): reenable
-      // expect(compiler.output.last.contents, contains(
-      //     '<div pseudo="x-foo_0">'
-      //       '<div>Test</div>'
-      //     '</div>'
-      //     '<div pseudo="x-foo1_1 x-foo2_2">'
-      //     '<div>Test</div>'
-      //     '</div>'));
-      // expect(compiler.output.last.contents, contains(
-      //     '<style>.test > *[pseudo="x-foo_0"] {\n'
-      //       '  background-color: #f00;\n'
-      //     '}\n'
-      //     '.test > *[pseudo="x-foo1_1"] {\n'
-      //     '  color: #00f;\n'
-      //     '}\n'
-      //     '.test > *[pseudo="x-foo2_2"] {\n'
-      //     '  color: #008000;\n'
-      //     '}'
-      //     '</style>'));
-    }));
-}
-
-main() {
-  useCompactVMConfiguration();
-
-  group('css', () {
-    setUp(() {
-      utils.path = new path.Builder(style: path.Style.posix);
-    });
-
-    tearDown(() {
-      utils.path = new path.Builder();
-    });
-
-    test('test_simple_var', test_simple_var);
-    test('test_var', test_var);
-    test('test_simple_import', test_simple_import);
-    test('test_imports', test_imports);
-    group('test_component_var', test_component_var);
-    test('test_pseudo_element', test_pseudo_element);
-  });
-}
diff --git a/pkg/polymer/test/data/unit/web/event_path_test.html b/pkg/polymer/test/data/unit/web/event_path_test.html
deleted file mode 100644
index 811479d..0000000
--- a/pkg/polymer/test/data/unit/web/event_path_test.html
+++ /dev/null
@@ -1,142 +0,0 @@
-<!doctype html>
-<!--
-   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.
--->
-<html>
-  <head>
-    <title>event path</title>
-    <script src="packages/polymer/testing/testing.js"></script>
-    <script src="packages/unittest/test_controller.js"></script>
-    <!--
-    Test ported from:
-    https://github.com/Polymer/polymer/blob/7936ff8/test/html/event-path.html
-
-    This test actually doesn't test the polymer's event layer. It just ensures
-    that tests are propagated in the right order when using Shadow DOM.
-    -->
-  </head>
-  <body>
-
-  <polymer-element name="x-selector">
-    <template>
-      <div id="selectorDiv">
-        <content id="selectorContent"></content>
-      </div>
-    </template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-      @CustomTag("x-selector")
-      class XSelector extends PolymerElement {}
-    </script>
-  </polymer-element>
-
-  <polymer-element name="x-overlay">
-    <template>
-      <content id="overlayContent"></content>
-    </template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-      @CustomTag("x-overlay")
-      class XOverlay extends PolymerElement {}
-    </script>
-  </polymer-element>
-
-  <polymer-element name="x-menu" extends="x-selector">
-    <template>
-      <div id="menuDiv">
-        <shadow id="menuShadow"></shadow>
-      </div>
-    </template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-      @CustomTag("x-menu")
-      class XMenu extends PolymerElement {}
-    </script>
-  </polymer-element>
-
-  <polymer-element name="x-menu-button">
-    <template>
-    <div>
-      <x-overlay id="overlay">
-        <div id="menuButtonDiv">
-          <x-menu id="menu">
-            <content id="menuButtonContent"></content>
-          </x-menu>
-        </div>
-      </x-overlay>
-      </div>
-    </template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-      @CustomTag("x-menu-button")
-      class XMenuButton extends PolymerElement {}
-    </script>
-  </polymer-element>
-
-  <x-menu-button id="menuButton">
-    <div id="item1"><div id="source"></div>Item1</div>
-    <div id="item2">Item2</div>
-  </x-menu-button>
-
-
-  <script type="application/dart">
-    import 'dart:html';
-    import 'dart:async';
-    import 'package:unittest/unittest.dart';
-    import 'package:unittest/html_config.dart';
-
-    main() {
-      useHtmlConfiguration();
-      test('bubbling in the right order', () {
-        // TODO(sigmund): this should change once we port over the
-        // 'WebComponentsReady' event.
-        runAsync(expectAsync0(() {
-          var item1 = query('#item1');
-          var menuButton = query('#menuButton');
-          // Note: polymer uses automatic node finding (menuButton.$.menu)
-          // also note that their node finding code also reachs into the ids
-          // from the parent shadow (menu.$.selectorContent instead of
-          // menu.$.menuShadow.$.selectorContent)
-          var menu = menuButton.shadowRoot.query('#menu');
-          var selector = menu.shadowRoot.query("#menuShadow");
-          var overlay = menuButton.shadowRoot.query('#overlay');
-          var expectedPath = <Node>[
-              item1,
-              menuButton.shadowRoot.query('#menuButtonContent'),
-              selector.olderShadowRoot.query('#selectorContent'),
-              selector.olderShadowRoot.query('#selectorDiv'),
-              menu.shadowRoot.query('#menuShadow').olderShadowRoot,
-              menu.shadowRoot.query('#menuShadow'),
-              menu.shadowRoot.query('#menuDiv'),
-              menu.shadowRoot,
-              menu,
-              menuButton.shadowRoot.query('#menuButtonDiv'),
-              // TODO(sigmund): this test is currently broken because currently
-              // registerElement is sensitive to the order in which each custom
-              // element is registered. When fixed, we should be able to add the
-              // following three targets:
-              //   overlay.shadowRoot.query('#overlayContent'),
-              //   overlay.shadowRoot,
-              //   overlay,
-              menuButton.shadowRoot,
-              menuButton
-          ];
-          var x = 0;
-          for (int i = 0; i < expectedPath.length; i++) {
-            var node = expectedPath[i];
-            expect(node, isNotNull, reason: "Should not be null at $i");
-            node.on['x'].listen(expectAsync1((e) {
-              expect(e.currentTarget, node);
-              expect(x++, i);
-            }));
-          }
-
-          item1.dispatchEvent(new Event('x', canBubble: true));
-        }));
-      });
-    }
-  </script>
-  </body>
-</html>
diff --git a/pkg/polymer/test/data/unit/web/events_test.html b/pkg/polymer/test/data/unit/web/events_test.html
deleted file mode 100644
index cbf33d1..0000000
--- a/pkg/polymer/test/data/unit/web/events_test.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!doctype html>
-<!--
-   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.
--->
-<html>
-  <head>
-    <title>event path</title>
-    <script src="packages/polymer/testing/testing.js"></script>
-    <script src="packages/unittest/test_controller.js"></script>
-    <!--
-    Test ported from:
-    https://github.com/Polymer/polymer/blob/7936ff8/test/js/events.js
-
-    TODO(sigmund): when we have support for mutation observers, render all of
-    the test in Dart (like events.js does in JS)
-    -->
-  </head>
-  <body>
-
-  <polymer-element name="test-a" on-click="clickHandler">
-    <template></template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-
-      @CustomTag("test-a")
-      class TestA extends PolymerElement {
-        List clicks = [];
-        void clickHandler() {
-          clicks.add('host click on: $localName (id $id)');
-        }
-      }
-    </script>
-  </polymer-element>
-
-  <polymer-element name="test-b">
-    <template>
-      <div>
-        <span id="b-1">1</span>
-        <span id="b-2" on-click="clickHandler">2</span>
-      </div>
-    </template>
-    <script type="application/dart">
-      import 'package:polymer/polymer.dart';
-
-      @CustomTag("test-b")
-      class TestB extends PolymerElement {
-        List clicks = [];
-        void clickHandler(event, detail, target) {
-          clicks.add('local click under $localName (id $id) on ${target.id}');
-        }
-      }
-    </script>
-  </polymer-element>
-
-  <test-a id="a"></test-a>
-  <test-b id="b"></test-b>
-
-  <script type="application/dart">
-    import 'dart:html';
-    import 'dart:async';
-    import 'package:unittest/unittest.dart';
-    import 'package:unittest/html_config.dart';
-
-    main() {
-      useHtmlConfiguration();
-
-      test('host event', () {
-        // Note: this test is currently the only event in
-        // polymer/test/js/events.js at commit #7936ff8
-        Timer.run(expectAsync0(() {
-          var testA = query('#a');
-          expect(testA.xtag.clicks, isEmpty);
-          testA.click();
-          expect(testA.xtag.clicks, ['host click on: test-a (id a)']);
-        }));
-      });
-
-      test('local event', () {
-        Timer.run(expectAsync0(() {
-          var testB = query('#b');
-          expect(testB.xtag.clicks, isEmpty);
-          testB.click();
-          expect(testB.xtag.clicks, []);
-          var b1 = testB.shadowRoot.query('#b-1');
-          b1.click();
-          expect(testB.xtag.clicks, []);
-          var b2 = testB.shadowRoot.query('#b-2');
-          b2.click();
-          expect(testB.xtag.clicks, ['local click under test-b (id b) on b-2']);
-        }));
-      });
-    }
-  </script>
-  </body>
-</html>
diff --git a/pkg/polymer/test/event_path_test.dart b/pkg/polymer/test/event_path_test.dart
new file mode 100644
index 0000000..550731c
--- /dev/null
+++ b/pkg/polymer/test/event_path_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.web.event_path_test;
+
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() {
+  useHtmlConfiguration();
+  test('bubbling in the right order', () {
+    // TODO(sigmund): this should change once we port over the
+    // 'WebComponentsReady' event.
+    runAsync(expectAsync0(() {
+      var item1 = query('#item1');
+      var menuButton = query('#menuButton');
+      // Note: polymer uses automatic node finding (menuButton.$.menu)
+      // also note that their node finding code also reachs into the ids
+      // from the parent shadow (menu.$.selectorContent instead of
+      // menu.$.menuShadow.$.selectorContent)
+      var menu = menuButton.shadowRoot.query('#menu');
+      var selector = menu.shadowRoot.query("#menuShadow");
+      var overlay = menuButton.shadowRoot.query('#overlay');
+      var expectedPath = <Node>[
+          item1,
+          menuButton.shadowRoot.query('#menuButtonContent'),
+          selector.olderShadowRoot.query('#selectorContent'),
+          selector.olderShadowRoot.query('#selectorDiv'),
+          menu.shadowRoot.query('#menuShadow').olderShadowRoot,
+          menu.shadowRoot.query('#menuShadow'),
+          menu.shadowRoot.query('#menuDiv'),
+          menu.shadowRoot,
+          menu,
+          menuButton.shadowRoot.query('#menuButtonDiv'),
+          // TODO(sigmund): this test is currently broken because currently
+          // registerElement is sensitive to the order in which each custom
+          // element is registered. When fixed, we should be able to add the
+          // following three targets:
+          //   overlay.shadowRoot.query('#overlayContent'),
+          //   overlay.shadowRoot,
+          //   overlay,
+          menuButton.shadowRoot,
+          menuButton
+      ];
+      var x = 0;
+      for (int i = 0; i < expectedPath.length; i++) {
+        var node = expectedPath[i];
+        expect(node, isNotNull, reason: "Should not be null at $i");
+        node.on['x'].listen(expectAsync1((e) {
+          expect(e.currentTarget, node);
+          expect(x++, i);
+        }));
+      }
+
+      item1.dispatchEvent(new Event('x', canBubble: true));
+    }));
+  });
+}
diff --git a/pkg/polymer/test/event_path_test.html b/pkg/polymer/test/event_path_test.html
new file mode 100644
index 0000000..3e5af21
--- /dev/null
+++ b/pkg/polymer/test/event_path_test.html
@@ -0,0 +1,86 @@
+<!doctype html>
+<!--
+   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.
+-->
+<html>
+  <head>
+    <title>event path</title>
+    <script src="packages/polymer/boot.js"></script>
+    <script src="packages/unittest/test_controller.js"></script>
+    <!--
+    Test ported from:
+    https://github.com/Polymer/polymer/blob/7936ff8/test/html/event-path.html
+
+    This test actually doesn't test the polymer's event layer. It just ensures
+    that tests are propagated in the right order when using Shadow DOM.
+    -->
+  </head>
+  <body>
+
+  <polymer-element name="x-selector">
+    <template>
+      <div id="selectorDiv">
+        <content id="selectorContent"></content>
+      </div>
+    </template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+      @CustomTag("x-selector")
+      class XSelector extends PolymerElement {}
+    </script>
+  </polymer-element>
+
+  <polymer-element name="x-overlay">
+    <template>
+      <content id="overlayContent"></content>
+    </template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+      @CustomTag("x-overlay")
+      class XOverlay extends PolymerElement {}
+    </script>
+  </polymer-element>
+
+  <polymer-element name="x-menu" extends="x-selector">
+    <template>
+      <div id="menuDiv">
+        <shadow id="menuShadow"></shadow>
+      </div>
+    </template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+      @CustomTag("x-menu")
+      class XMenu extends PolymerElement {}
+    </script>
+  </polymer-element>
+
+  <polymer-element name="x-menu-button">
+    <template>
+    <div>
+      <x-overlay id="overlay">
+        <div id="menuButtonDiv">
+          <x-menu id="menu">
+            <content id="menuButtonContent"></content>
+          </x-menu>
+        </div>
+      </x-overlay>
+      </div>
+    </template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+      @CustomTag("x-menu-button")
+      class XMenuButton extends PolymerElement {}
+    </script>
+  </polymer-element>
+
+  <x-menu-button id="menuButton">
+    <div id="item1"><div id="source"></div>Item1</div>
+    <div id="item2">Item2</div>
+  </x-menu-button>
+
+
+  <script type="application/dart" src="event_path_test.dart"></script>
+  </body>
+</html>
diff --git a/pkg/polymer/test/events_test.dart b/pkg/polymer/test/events_test.dart
new file mode 100644
index 0000000..9199329
--- /dev/null
+++ b/pkg/polymer/test/events_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library polymer.test.web.events_test;
+
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+main() {
+  useHtmlConfiguration();
+
+  test('host event', () {
+    // Note: this test is currently the only event in
+    // polymer/test/js/events.js at commit #7936ff8
+    Timer.run(expectAsync0(() {
+      var testA = query('#a');
+      expect(testA.xtag.clicks, isEmpty);
+      testA.click();
+      expect(testA.xtag.clicks, ['host click on: test-a (id a)']);
+    }));
+  });
+
+  test('local event', () {
+    Timer.run(expectAsync0(() {
+      var testB = query('#b');
+      expect(testB.xtag.clicks, isEmpty);
+      testB.click();
+      expect(testB.xtag.clicks, []);
+      var b1 = testB.shadowRoot.query('#b-1');
+      b1.click();
+      expect(testB.xtag.clicks, []);
+      var b2 = testB.shadowRoot.query('#b-2');
+      b2.click();
+      expect(testB.xtag.clicks, ['local click under test-b (id b) on b-2']);
+    }));
+  });
+}
diff --git a/pkg/polymer/test/events_test.html b/pkg/polymer/test/events_test.html
new file mode 100644
index 0000000..b077163
--- /dev/null
+++ b/pkg/polymer/test/events_test.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<!--
+   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.
+-->
+<html>
+  <head>
+    <title>event path</title>
+    <script src="packages/polymer/boot.js"></script>
+    <script src="packages/unittest/test_controller.js"></script>
+    <!--
+    Test ported from:
+    https://github.com/Polymer/polymer/blob/7936ff8/test/js/events.js
+
+    TODO(sigmund): when we have support for mutation observers, render all of
+    the test in Dart (like events.js does in JS)
+    -->
+  </head>
+  <body>
+
+  <polymer-element name="test-a" on-click="clickHandler">
+    <template></template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+
+      @CustomTag("test-a")
+      class TestA extends PolymerElement {
+        List clicks = [];
+        void clickHandler() {
+          clicks.add('host click on: $localName (id $id)');
+        }
+      }
+    </script>
+  </polymer-element>
+
+  <polymer-element name="test-b">
+    <template>
+      <div>
+        <span id="b-1">1</span>
+        <span id="b-2" on-click="clickHandler">2</span>
+      </div>
+    </template>
+    <script type="application/dart">
+      import 'package:polymer/polymer.dart';
+
+      @CustomTag("test-b")
+      class TestB extends PolymerElement {
+        List clicks = [];
+        void clickHandler(event, detail, target) {
+          clicks.add('local click under $localName (id $id) on ${target.id}');
+        }
+      }
+    </script>
+  </polymer-element>
+
+  <test-a id="a"></test-a>
+  <test-b id="b"></test-b>
+
+  <script type="application/dart" src="events_test.dart"></script>
+  </body>
+</html>
diff --git a/pkg/polymer/test/run.sh b/pkg/polymer/test/run.sh
index 3d04337..7c20556 100755
--- a/pkg/polymer/test/run.sh
+++ b/pkg/polymer/test/run.sh
@@ -1,131 +1,25 @@
 #!/bin/bash
-# Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+# Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# Usage: call directly in the commandline as test/run.sh ensuring that you have
-# both 'dart' and 'content_shell' in your path. Filter tests by passing a
-# pattern as an argument to this script.
-
-# TODO(sigmund): replace with a real test runner
+# Usage: run from a Dart SVN checkout after building.
 
 # bail on error
 set -e
 
-# print commands executed by this script
-# set -x
-
+# Note: test.dart needs to be run from the root of the Dart checkout
 DIR=$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd )
-# Note: dartanalyzer and some tests needs to be run from the root directory
-pushd $DIR/.. > /dev/null
+pushd $DIR/../../.. > /dev/null
 
-export DART_FLAGS="--checked"
+echo "*** Running unit tests for Polymer.dart and its dependencies."
 
-# Search for the first argument that doesn't look like an option ('--foo')
-function first_non_option {
-  while [[ $# -gt 0 ]]; do
-    if [[ $1 != --* ]]; then # Note: --* is a regex
-      echo $1
-      return
-    fi
-    shift
-  done
-}
+SUITES="pkg/polymer samples/third_party/todomvc"
 
-TEST_PATTERN=$(first_non_option $@)
+CONFIG="-m release -r vm,drt,ff,chrome -c none,dart2js,dartanalyzer --checked $*"
 
-SDK_DIR=$(cd ../../out/ReleaseIA32/dart-sdk/; pwd)
-package_root=$SDK_DIR/../packages
-dart="$SDK_DIR/bin/dart --package-root=$package_root"
-dartanalyzer="$SDK_DIR/bin/dartanalyzer --package-root=$package_root"
-
-function fail {
-  return 1
-}
-
-function show_diff {
-  diff -u -N $1 $2 | \
-    sed -e "s/^\(+.*\)/\1/" |\
-    sed -e "s/^\(-.*\)/\1/"
-  return 1
-}
-
-function update {
-  read -p "Would you like to update the expectations? [y/N]: " answer
-  if [[ $answer == 'y' || $answer == 'Y' ]]; then
-    cp $2 $1
-    return 0
-  fi
-  return 1
-}
-
-function pass {
-  echo -e "OK"
-}
-
-function compare {
-  # use a standard diff, if they are not identical, format the diff nicely to
-  # see what's the error and prompt to see if they wish to update it. If they
-  # do, continue running more tests.
-  diff -q $1 $2 && pass || show_diff $1 $2 || update $1 $2
-}
-
-if [[ ($TEST_PATTERN == "") ]]; then
-  echo Analyzing analyzer for warnings or type errors
-  $dartanalyzer --hints --fatal-warnings --fatal-type-errors lib/dwc.dart
-
-  echo Analyzing deploy-compiler for warnings or type errors
-  $dartanalyzer --hints --fatal-warnings --fatal-type-errors lib/deploy.dart
-
-  echo -e "\nAnalyzing runtime for warnings or type errors"
-  $dartanalyzer --hints --fatal-warnings --fatal-type-errors lib/polymer.dart
-
-  popd > /dev/null
-fi
-
-function compare_all {
-# TODO(jmesserly): bash and dart regexp might not be 100% the same. Ideally we
-# could do all the heavy lifting in Dart code, and keep this script as a thin
-# wrapper that sets `--enable-type-checks --enable-asserts`
-  for input in $DIR/../example/component/news/test/*_test.html; do
-    if [[ ($TEST_PATTERN == "") || ($input =~ $TEST_PATTERN) ]]; then
-      FILENAME=`basename $input`
-      DIRNAME=`dirname $input`
-      if [[ `basename $DIRNAME` == 'input' ]]; then
-        DIRNAME=`dirname $DIRNAME`
-      fi
-      echo -e -n "Checking diff for $FILENAME "
-      DUMP="test/data/out/example/test/$FILENAME.txt"
-      EXPECTATION="$DIRNAME/expected/$FILENAME.txt"
-
-      compare $EXPECTATION $DUMP
-    fi
-  done
-  echo -e "Some tests failed"
-  fail
-}
-
-if [[ ($TEST_PATTERN == "") ]]; then
-  echo -e "\nTesting build.dart... "
-  $dart $DART_FLAGS build.dart
-  # Run it the way the editor does. Hide stdout because it is in noisy machine
-  # format. Show stderr in case something breaks.
-  # NOTE: not using --checked because the editor doesn't use it, and to workaround
-  # http://dartbug.com/9637
-  $dart build.dart --machine --clean > /dev/null
-  $dart build.dart --machine --full > /dev/null
-fi
-
-echo -e "\nRunning unit tests... "
-$dart $DART_FLAGS test/run_all.dart $@ || compare_all
-
-# Run Dart analyzer to check that we're generating warning clean code.
-# It's a bit slow, so only do this for one test.
-OUT_PATTERN="$DIR/../example/component/news/test/out/test/*$TEST_PATTERN*_bootstrap.dart"
-if [[ `ls $OUT_PATTERN 2>/dev/null` != "" ]]; then
-  echo -e "\nAnalyzing generated code for warnings or type errors."
-  ls $OUT_PATTERN 2>/dev/null | $dartanalyzer \
-      --fatal-warnings --fatal-type-errors -batch
-fi
+CMD="xvfb-run ./tools/test.py $CONFIG $SUITES"
+echo "*** $CMD"
+$CMD
 
 echo -e "All tests pass"
diff --git a/pkg/polymer/test/run_all.dart b/pkg/polymer/test/run_all.dart
deleted file mode 100644
index 6191492..0000000
--- a/pkg/polymer/test/run_all.dart
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * This is a helper for run.sh. We try to run all of the Dart code in one
- * instance of the Dart VM to reduce warm-up time.
- */
-library run_impl;
-
-import 'dart:io';
-import 'package:unittest/compact_vm_config.dart';
-import 'package:unittest/unittest.dart';
-import 'package:polymer/testing/content_shell_test.dart';
-
-import 'compiler_test.dart' as compiler_test;
-import 'css_test.dart' as css_test;
-import 'transform/all_phases_test.dart' as all_phases_test;
-import 'transform/code_extractor_test.dart' as code_extractor_test;
-import 'transform/import_inliner_test.dart' as import_inliner_test;
-import 'transform/polyfill_injector_test.dart' as polyfill_injector_test;
-import 'transform/script_compactor_test.dart' as script_compactor_test;
-import 'utils_test.dart' as utils_test;
-import 'linter_test.dart' as linter_test;
-
-main() {
-  var args = new Options().arguments;
-  var pattern = new RegExp(args.length > 0 ? args[0] : '.');
-
-  useCompactVMConfiguration();
-
-  void addGroup(testFile, testMain) {
-    if (pattern.hasMatch(testFile)) {
-      group(testFile.replaceAll('_test.dart', ':'), testMain);
-    }
-  }
-
-  addGroup('linter_test.dart', linter_test.main);
-  addGroup('compiler_test.dart', compiler_test.main);
-  addGroup('css_test.dart', css_test.main);
-  addGroup('utils_test.dart', utils_test.main);
-  addGroup('transform/code_extractor_test.dart', code_extractor_test.main);
-  addGroup('transform/import_inliner_test.dart', import_inliner_test.main);
-  addGroup('transform/script_compactor_test.dart', script_compactor_test.main);
-  addGroup('transform/polyfill_injector_test.dart',
-      polyfill_injector_test.main);
-  addGroup('transform/all_phases_test.dart', all_phases_test.main);
-
-  endToEndTests('data/unit/web', 'data/out');
-
-  // Note: if you're adding more render test suites, make sure to update run.sh
-  // as well for convenient baseline diff/updating.
-
-  // TODO(jmesserly): figure out why this fails in content_shell but works in
-  // Dartium and Firefox when using the ShadowDOM polyfill.
-  exampleTest('../example/component/news', ['--no-shadowdom']..addAll(args));
-}
-
-void exampleTest(String path, [List args]) {
-  // TODO(sigmund): renderTests currently contatenates [path] with the out
-  // folder. This can be a problem with relative paths that go up (like todomvc
-  // above, which has '../../../'). If we continue running tests with
-  // test/run.sh, we should fix this. For now we work around this problem by
-  // using a long path 'data/out/example/test'. That way we avoid dumping output
-  // in the source-tree.
-  renderTests(path, '$path/test', '$path/test/expected',
-      'data/out/example/test', arguments: args);
-}
diff --git a/pkg/polymer/test/testing.dart b/pkg/polymer/test/testing.dart
deleted file mode 100644
index c89b416..0000000
--- a/pkg/polymer/test/testing.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/** Common definitions used for setting up the test environment. */
-library testing;
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:csslib/visitor.dart';
-import 'package:html5lib/dom.dart';
-import 'package:html5lib/parser.dart';
-import 'package:polymer/src/analyzer.dart';
-import 'package:polymer/src/compiler.dart';
-import 'package:polymer/src/file_system.dart';
-import 'package:polymer/src/info.dart';
-import 'package:polymer/src/messages.dart';
-import 'package:polymer/src/compiler_options.dart';
-import 'package:polymer/src/files.dart';
-import 'package:polymer/src/utils.dart';
-
-
-Document parseDocument(String html) => parse(html);
-
-Element parseSubtree(String html) => parseFragment(html).nodes[0];
-
-FileInfo analyzeDefinitionsInTree(Document doc, Messages messages,
-    {String packageRoot: 'packages'}) {
-
-  return analyzeDefinitions(new GlobalInfo(), new UrlInfo('', '', null),
-      doc, packageRoot, messages);
-}
-
-/** Parses files in [fileContents], with [mainHtmlFile] being the main file. */
-List<SourceFile> parseFiles(Map<String, String> fileContents,
-    [String mainHtmlFile = 'index.html']) {
-
-  var result = <SourceFile>[];
-  fileContents.forEach((filename, contents) {
-    var src = new SourceFile(filename);
-    src.document = parse(contents);
-    result.add(src);
-  });
-
-  return result;
-}
-
-/** Analyze all files. */
-Map<String, FileInfo> analyzeFiles(List<SourceFile> files,
-    {Messages messages, String packageRoot: 'packages'}) {
-  messages = messages == null ? new Messages.silent() : messages;
-  var result = new Map<String, FileInfo>();
-
-  // analyze definitions
-  var global = new GlobalInfo();
-  for (var file in files) {
-    var path = file.path;
-    result[path] = analyzeDefinitions(global, new UrlInfo(path, path, null),
-        file.document, packageRoot, messages);
-  }
-
-  // analyze file contents
-  var uniqueIds = new IntIterator();
-  var pseudoElements = new Map();
-  for (var file in files) {
-    analyzeFile(file, result, uniqueIds, pseudoElements, messages, true);
-  }
-  return result;
-}
-
-Compiler createCompiler(Map files, Messages messages, {bool errors: false,
-    bool scopedCss: false}) {
-  List baseOptions = ['--no-colors', '-o', 'out', '--deploy', 'index.html'];
-  if (errors) baseOptions.insert(0, '--warnings_as_errors');
-  if (scopedCss) baseOptions.insert(0, '--scoped-css');
-  var options = CompilerOptions.parse(baseOptions);
-  var fs = new MockFileSystem(files);
-  return new Compiler(fs, options, messages);
-}
-
-String prettyPrintCss(StyleSheet styleSheet) =>
-    ((new CssPrinter())..visitTree(styleSheet)).toString();
-
-/**
- * Abstraction around file system access to work in a variety of different
- * environments.
- */
-class MockFileSystem extends FileSystem {
-  final Map _files;
-  final Map readCount = {};
-
-  MockFileSystem(this._files);
-
-  Future readTextOrBytes(String filename) => readText(filename);
-
-  Future<String> readText(String path) {
-    readCount[path] = readCount.putIfAbsent(path, () => 0) + 1;
-    var file = _files[path];
-    if (file != null) {
-      return new Future.value(file);
-    } else {
-      return new Future.error(
-          new FileException('MockFileSystem: $path not found'));
-    }
-  }
-
-  // Compiler doesn't call these
-  void writeString(String outfile, String text) {}
-  Future flush() {}
-}
diff --git a/pkg/polymer/test/utils_test.dart b/pkg/polymer/test/utils_test.dart
index 393d215..335e538 100644
--- a/pkg/polymer/test/utils_test.dart
+++ b/pkg/polymer/test/utils_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /** Tests for some of the utility helper functions used by the compiler. */
-library utils_test;
+library polymer.test.utils_test;
 
 import 'package:unittest/compact_vm_config.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/polymer_expressions/lib/eval.dart b/pkg/polymer_expressions/lib/eval.dart
index 7ed7b5a..7341e05 100644
--- a/pkg/polymer_expressions/lib/eval.dart
+++ b/pkg/polymer_expressions/lib/eval.dart
@@ -259,7 +259,7 @@
   String toString() => _expr.toString();
 }
 
-class Updater extends RecursiveVisitor<ExpressionObserver> {
+class Updater extends RecursiveVisitor {
   final Scope scope;
 
   Updater(this.scope);
@@ -469,9 +469,12 @@
     var f = _BINARY_OPERATORS[operator];
     if (operator == '&&' || operator == '||') {
       _value = f(_toBool(left._value), _toBool(right._value));
+    } else if (operator == '==' || operator == '!=') {
+      _value = f(left._value, right._value);
+    } else if (left._value == null || right._value == null) {
+      _value = null;
     } else {
-      _value = (left._value == null || right._value == null)
-          ? null : f(left._value, right._value);
+      _value = f(left._value, right._value);
     }
   }
 
diff --git a/pkg/polymer_expressions/lib/parser.dart b/pkg/polymer_expressions/lib/parser.dart
index cc06681..9a16300 100644
--- a/pkg/polymer_expressions/lib/parser.dart
+++ b/pkg/polymer_expressions/lib/parser.dart
@@ -196,6 +196,10 @@
       _advance();
       return _astFactory.literal(false);
     }
+    if (_token.value == 'null') {
+      _advance();
+      return _astFactory.literal(null);
+    }
     var identifier = _parseIdentifier();
     var args = _parseArguments();
     if (args == null) {
diff --git a/pkg/polymer_expressions/lib/visitor.dart b/pkg/polymer_expressions/lib/visitor.dart
index a11a0d4..03341c2 100644
--- a/pkg/polymer_expressions/lib/visitor.dart
+++ b/pkg/polymer_expressions/lib/visitor.dart
@@ -6,8 +6,8 @@
 
 import 'expression.dart';
 
-abstract class Visitor<E extends Expression> {
-  visit(E s) => s.accept(this);
+abstract class Visitor {
+  visit(Expression s) => s.accept(this);
   visitEmptyExpression(EmptyExpression e);
   visitParenthesizedExpression(ParenthesizedExpression e);
   visitInvoke(Invoke i);
@@ -20,8 +20,8 @@
   visitInExpression(InExpression c);
 }
 
-abstract class RecursiveVisitor<E> extends Visitor<E> {
-  visitExpression(E e);
+abstract class RecursiveVisitor extends Visitor {
+  visitExpression(Expression e);
 
   visitEmptyExpression(EmptyExpression e) => visitExpression(e);
 
diff --git a/pkg/polymer_expressions/test/eval_test.dart b/pkg/polymer_expressions/test/eval_test.dart
index b2d9123..ece4396 100644
--- a/pkg/polymer_expressions/test/eval_test.dart
+++ b/pkg/polymer_expressions/test/eval_test.dart
@@ -47,6 +47,10 @@
       expectEval('false', false);
     });
 
+    test('should return a literal null', () {
+      expectEval('null', null);
+    });
+
     test('should return a literal map', () {
       expectEval('{"a": 1}', equals(new Map.from({'a': 1})));
       expectEval('{"a": 1}', containsPair('a', 1));
@@ -70,8 +74,10 @@
 
       expectEval('1 == 1', true);
       expectEval('1 == 2', false);
+      expectEval('1 == null', false);
       expectEval('1 != 1', false);
       expectEval('1 != 2', true);
+      expectEval('1 != null', true);
 
       expectEval('1 > 1', false);
       expectEval('1 > 2', false);
@@ -162,6 +168,10 @@
     });
 
     test('should treat null as false', () {
+      expectEval('!null', true);
+      expectEval('true && null', false);
+      expectEval('null || false', false);
+
       expectEval('!a', true, null, {'a': null});
 
       expectEval('a && b', false, null, {'a': null, 'b': true});
diff --git a/pkg/polymer_expressions/test/parser_test.dart b/pkg/polymer_expressions/test/parser_test.dart
index 21b11fb..66c1d04 100644
--- a/pkg/polymer_expressions/test/parser_test.dart
+++ b/pkg/polymer_expressions/test/parser_test.dart
@@ -27,6 +27,15 @@
       expectParse('"abc"', literal('abc'));
     });
 
+    test('should parse a bool literal', () {
+      expectParse('true', literal(true));
+      expectParse('false', literal(false));
+    });
+
+    test('should parse a null literal', () {
+      expectParse('null', literal(null));
+    });
+
     test('should parse an integer literal', () {
       expectParse('123', literal(123));
     });
diff --git a/pkg/serialization/lib/src/reader_writer.dart b/pkg/serialization/lib/src/reader_writer.dart
index b40196e..9203185 100644
--- a/pkg/serialization/lib/src/reader_writer.dart
+++ b/pkg/serialization/lib/src/reader_writer.dart
@@ -40,7 +40,7 @@
    * but also serves to record which objects we have already seen.
    */
   final Map<dynamic, Reference> references =
-      new IdentityMap<Object, Reference>();
+      new HashMap<Object, Reference>(equals: identical);
 
   /**
    * The state of objects that need to be serialized is stored here.
diff --git a/pkg/serialization/lib/src/serialization_helpers.dart b/pkg/serialization/lib/src/serialization_helpers.dart
index ec89857..d9ad747 100644
--- a/pkg/serialization/lib/src/serialization_helpers.dart
+++ b/pkg/serialization/lib/src/serialization_helpers.dart
@@ -180,64 +180,3 @@
   final _wrappedObject;
   const _Sentinel(this._wrappedObject);
 }
-
-/**
- * This is used in the implementation of [IdentityMap]. We wrap all the keys
- * in an [_IdentityMapKey] that compares using the identity of the wrapped
- * objects. It also treats equal primitive values as identical
- * to conserve space.
- */
-class _IdentityMapKey {
-  _IdentityMapKey(this._value);
-  var _value;
-
-  /**
-   * Check if an object is primitive to know if we should compare it using
-   * equality or identity. We don't test null/true/false where it's the same.
-   */
-  _isPrimitive(x) => x is String || x is num;
-
-  operator ==(_IdentityMapKey w) =>
-      _isPrimitive(_value) ? _value == w._value : identical(_value, w._value);
-  get hashCode => _value.hashCode;
-  get object => _value;
-}
-
-/**
- * This provides an identity map. We wrap all the objects in
- * an [_IdentityMapKey] that compares using the identity of the
- * wrapped objects. It also treats equal primitive values as identical
- * to conserve space.
- */
-class IdentityMap<K, V> extends LinkedHashMap<K, V> {
-// TODO(alanknight): Replace with a system identity-based map once
-// one is available. Issue 4161.
-// TODO(lrn): Replace with identity map when custom hash maps are introduced
-// (which is soon).
-
-  // Check before wrapping because some methods may call others, e.g. on
-  // dart2js putIfAbsent calls containsKey, so without this we wrap forever.
-  _wrap(Object key) =>
-      (key is _IdentityMapKey) ? key : new _IdentityMapKey(key);
-  _unwrap(_IdentityMapKey wrapper) => wrapper.object;
-
-  Iterable<K> get keys => super.keys.map((x) => _unwrap(x));
-  Iterable<V> get values => super.values;
-
-  void forEach(void f(K key, V value)) {
-    super.forEach((k, v) => f(_unwrap(k), v));
-  }
-
-  V operator [](K key) => super[_wrap(key)];
-
-  void operator []=(K key, V value) {
-      super[_wrap(key)] = value;
-  }
-
-  V putIfAbsent(K key, Function ifAbsent) =>
-      super.putIfAbsent(_wrap(key), ifAbsent);
-
-  bool containsKey(Object key) => super.containsKey(_wrap(key));
-
-  V remove(Object key) => super.remove(_wrap(key));
-}
diff --git a/pkg/serialization/test/polyfill_identity_map_test.dart b/pkg/serialization/test/polyfill_identity_map_test.dart
deleted file mode 100644
index bfc8fef..0000000
--- a/pkg/serialization/test/polyfill_identity_map_test.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Provide a trivial test for identity based hashed collections, which we
- * provide here until an implementation is available in the regular libraries.
- */
-// TODO(alanknight): Remove once identity-hashed collections are available.
-// Issue 4161.
-library identity_set_test;
-
-import 'package:unittest/unittest.dart';
-import 'package:serialization/src/serialization_helpers.dart';
-
-class Foo {
-  var x;
-  Foo(this.x);
-  int get hashCode => x.hashCode;
-  bool operator ==(a) => a.x == x;
-}
-
-main() {
-  test('basic', () {
-    var one = new Foo(3);
-    var two = new Foo(3);
-    var map = new Map();
-    var identityMap = new IdentityMap();
-    map[one] = one;
-    map[two] = two;
-    identityMap[one] = one;
-    identityMap[two] = two;
-    expect(map.length, 1);
-    expect(identityMap.length, 2);
-    for (var each in identityMap.values) {
-      expect(each, one);
-    }
-  });
-
-  test('uniquing primitives', () {
-    var map = new IdentityMap();
-    var one = 'one';
-    var two = new String.fromCharCodes(one.codeUnits);
-    map[one] = 1;
-    expect(map[two], 1);
-    expect(map[one], 1);
-  });
-}
diff --git a/pkg/shadow_dom/lib/shadow_dom.debug.js b/pkg/shadow_dom/lib/shadow_dom.debug.js
index 07b283e..b889a5e 100644
--- a/pkg/shadow_dom/lib/shadow_dom.debug.js
+++ b/pkg/shadow_dom/lib/shadow_dom.debug.js
@@ -16,28 +16,1350 @@
   }
 })();
 
+// Copyright 2012 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+(function(global) {
+  'use strict';
+
+  function detectObjectObserve() {
+    if (typeof Object.observe !== 'function' ||
+        typeof Array.observe !== 'function') {
+      return false;
+    }
+
+    var gotSplice = false;
+    function callback(records) {
+      if (records[0].type === 'splice' && records[1].type === 'splice')
+        gotSplice = true;
+    }
+
+    var test = [0];
+    Array.observe(test, callback);
+    test[1] = 1;
+    test.length = 0;
+    Object.deliverChangeRecords(callback);
+    return gotSplice;
+  }
+
+  var hasObserve = detectObjectObserve();
+
+  function detectEval() {
+    // don't test for eval if document has CSP securityPolicy object and we can see that
+    // eval is not supported. This avoids an error message in console even when the exception
+    // is caught
+    if (global.document &&
+        'securityPolicy' in global.document &&
+        !global.document.securityPolicy.allowsEval) {
+      return false;
+    }
+
+    try {
+      var f = new Function('', 'return true;');
+      return f();
+    } catch (ex) {
+      return false;
+    }
+  }
+
+  var hasEval = detectEval();
+
+  function isIndex(s) {
+    return +s === s >>> 0;
+  }
+
+  function toNumber(s) {
+    return +s;
+  }
+
+  function isObject(obj) {
+    return obj === Object(obj);
+  }
+
+  var numberIsNaN = global.Number.isNaN || function isNaN(value) {
+    return typeof value === 'number' && global.isNaN(value);
+  }
+
+  function areSameValue(left, right) {
+    if (left === right)
+      return left !== 0 || 1 / left === 1 / right;
+    if (numberIsNaN(left) && numberIsNaN(right))
+      return true;
+
+    return left !== left && right !== right;
+  }
+
+  var createObject = ('__proto__' in {}) ?
+    function(obj) { return obj; } :
+    function(obj) {
+      var proto = obj.__proto__;
+      if (!proto)
+        return obj;
+      var newObject = Object.create(proto);
+      Object.getOwnPropertyNames(obj).forEach(function(name) {
+        Object.defineProperty(newObject, name,
+                             Object.getOwnPropertyDescriptor(obj, name));
+      });
+      return newObject;
+    };
+
+  var identStart = '[\$_a-zA-Z]';
+  var identPart = '[\$_a-zA-Z0-9]';
+  var ident = identStart + '+' + identPart + '*';
+  var elementIndex = '(?:[0-9]|[1-9]+[0-9]+)';
+  var identOrElementIndex = '(?:' + ident + '|' + elementIndex + ')';
+  var path = '(?:' + identOrElementIndex + ')(?:\\s*\\.\\s*' + identOrElementIndex + ')*';
+  var pathRegExp = new RegExp('^' + path + '$');
+
+  function isPathValid(s) {
+    if (typeof s != 'string')
+      return false;
+    s = s.trim();
+
+    if (s == '')
+      return true;
+
+    if (s[0] == '.')
+      return false;
+
+    return pathRegExp.test(s);
+  }
+
+  var constructorIsPrivate = {};
+
+  function Path(s, privateToken) {
+    if (privateToken !== constructorIsPrivate)
+      throw Error('Use Path.get to retrieve path objects');
+
+    if (s.trim() == '')
+      return this;
+
+    if (isIndex(s)) {
+      this.push(s);
+      return this;
+    }
+
+    s.split(/\s*\.\s*/).filter(function(part) {
+      return part;
+    }).forEach(function(part) {
+      this.push(part);
+    }, this);
+
+    if (hasEval && !hasObserve && this.length) {
+      this.getValueFrom = this.compiledGetValueFromFn();
+    }
+  }
+
+  // TODO(rafaelw): Make simple LRU cache
+  var pathCache = {};
+
+  function getPath(pathString) {
+    if (pathString instanceof Path)
+      return pathString;
+
+    if (pathString == null)
+      pathString = '';
+
+    if (typeof pathString !== 'string')
+      pathString = String(pathString);
+
+    var path = pathCache[pathString];
+    if (path)
+      return path;
+    if (!isPathValid(pathString))
+      return invalidPath;
+    var path = new Path(pathString, constructorIsPrivate);
+    pathCache[pathString] = path;
+    return path;
+  }
+
+  Path.get = getPath;
+
+  Path.prototype = createObject({
+    __proto__: [],
+    valid: true,
+
+    toString: function() {
+      return this.join('.');
+    },
+
+    getValueFrom: function(obj, observedSet) {
+      for (var i = 0; i < this.length; i++) {
+        if (obj == null)
+          return;
+        if (observedSet)
+          observedSet.observe(obj);
+        obj = obj[this[i]];
+      }
+      return obj;
+    },
+
+    compiledGetValueFromFn: function() {
+      var accessors = this.map(function(ident) {
+        return isIndex(ident) ? '["' + ident + '"]' : '.' + ident;
+      });
+
+      var str = '';
+      var pathString = 'obj';
+      str += 'if (obj != null';
+      var i = 0;
+      for (; i < (this.length - 1); i++) {
+        var ident = this[i];
+        pathString += accessors[i];
+        str += ' &&\n     ' + pathString + ' != null';
+      }
+      str += ')\n';
+
+      pathString += accessors[i];
+
+      str += '  return ' + pathString + ';\nelse\n  return undefined;';
+      return new Function('obj', str);
+    },
+
+    setValueFrom: function(obj, value) {
+      if (!this.length)
+        return false;
+
+      for (var i = 0; i < this.length - 1; i++) {
+        if (!isObject(obj))
+          return false;
+        obj = obj[this[i]];
+      }
+
+      if (!isObject(obj))
+        return false;
+
+      obj[this[i]] = value;
+      return true;
+    }
+  });
+
+  var invalidPath = new Path('', constructorIsPrivate);
+  invalidPath.valid = false;
+  invalidPath.getValueFrom = invalidPath.setValueFrom = function() {};
+
+  var MAX_DIRTY_CHECK_CYCLES = 1000;
+
+  function dirtyCheck(observer) {
+    var cycles = 0;
+    while (cycles < MAX_DIRTY_CHECK_CYCLES && observer.check()) {
+      observer.report();
+      cycles++;
+    }
+    if (global.testingExposeCycleCount)
+      global.dirtyCheckCycleCount = cycles;
+  }
+
+  function objectIsEmpty(object) {
+    for (var prop in object)
+      return false;
+    return true;
+  }
+
+  function diffIsEmpty(diff) {
+    return objectIsEmpty(diff.added) &&
+           objectIsEmpty(diff.removed) &&
+           objectIsEmpty(diff.changed);
+  }
+
+  function diffObjectFromOldObject(object, oldObject) {
+    var added = {};
+    var removed = {};
+    var changed = {};
+    var oldObjectHas = {};
+
+    for (var prop in oldObject) {
+      var newValue = object[prop];
+
+      if (newValue !== undefined && newValue === oldObject[prop])
+        continue;
+
+      if (!(prop in object)) {
+        removed[prop] = undefined;
+        continue;
+      }
+
+      if (newValue !== oldObject[prop])
+        changed[prop] = newValue;
+    }
+
+    for (var prop in object) {
+      if (prop in oldObject)
+        continue;
+
+      added[prop] = object[prop];
+    }
+
+    if (Array.isArray(object) && object.length !== oldObject.length)
+      changed.length = object.length;
+
+    return {
+      added: added,
+      removed: removed,
+      changed: changed
+    };
+  }
+
+  function copyObject(object, opt_copy) {
+    var copy = opt_copy || (Array.isArray(object) ? [] : {});
+    for (var prop in object) {
+      copy[prop] = object[prop];
+    };
+    if (Array.isArray(object))
+      copy.length = object.length;
+    return copy;
+  }
+
+  function Observer(object, callback, target, token) {
+    this.closed = false;
+    this.object = object;
+    this.callback = callback;
+    // TODO(rafaelw): Hold this.target weakly when WeakRef is available.
+    this.target = target;
+    this.token = token;
+    this.reporting = true;
+    if (hasObserve) {
+      var self = this;
+      this.boundInternalCallback = function(records) {
+        self.internalCallback(records);
+      };
+    }
+
+    addToAll(this);
+  }
+
+  Observer.prototype = {
+    internalCallback: function(records) {
+      if (this.closed)
+        return;
+      if (this.reporting && this.check(records)) {
+        this.report();
+        if (this.testingResults)
+          this.testingResults.anyChanged = true;
+      }
+    },
+
+    close: function() {
+      if (this.closed)
+        return;
+      if (this.object && typeof this.object.close === 'function')
+        this.object.close();
+
+      this.disconnect();
+      this.object = undefined;
+      this.closed = true;
+    },
+
+    deliver: function(testingResults) {
+      if (this.closed)
+        return;
+      if (hasObserve) {
+        this.testingResults = testingResults;
+        Object.deliverChangeRecords(this.boundInternalCallback);
+        this.testingResults = undefined;
+      } else {
+        dirtyCheck(this);
+      }
+    },
+
+    report: function() {
+      if (!this.reporting)
+        return;
+
+      this.sync(false);
+      if (this.callback) {
+        this.reportArgs.push(this.token);
+        this.invokeCallback(this.reportArgs);
+      }
+      this.reportArgs = undefined;
+    },
+
+    invokeCallback: function(args) {
+      try {
+        this.callback.apply(this.target, args);
+      } catch (ex) {
+        Observer._errorThrownDuringCallback = true;
+        console.error('Exception caught during observer callback: ' + (ex.stack || ex));
+      }
+    },
+
+    reset: function() {
+      if (this.closed)
+        return;
+
+      if (hasObserve) {
+        this.reporting = false;
+        Object.deliverChangeRecords(this.boundInternalCallback);
+        this.reporting = true;
+      }
+
+      this.sync(true);
+    }
+  }
+
+  var collectObservers = !hasObserve || global.forceCollectObservers;
+  var allObservers;
+  Observer._allObserversCount = 0;
+
+  if (collectObservers) {
+    allObservers = [];
+  }
+
+  function addToAll(observer) {
+    if (!collectObservers)
+      return;
+
+    allObservers.push(observer);
+    Observer._allObserversCount++;
+  }
+
+  var runningMicrotaskCheckpoint = false;
+
+  var hasDebugForceFullDelivery = typeof Object.deliverAllChangeRecords == 'function';
+
+  global.Platform = global.Platform || {};
+
+  global.Platform.performMicrotaskCheckpoint = function() {
+    if (runningMicrotaskCheckpoint)
+      return;
+
+    if (hasDebugForceFullDelivery) {
+      Object.deliverAllChangeRecords();
+      return;
+    }
+
+    if (!collectObservers)
+      return;
+
+    runningMicrotaskCheckpoint = true;
+
+    var cycles = 0;
+    var results = {};
+
+    do {
+      cycles++;
+      var toCheck = allObservers;
+      allObservers = [];
+      results.anyChanged = false;
+
+      for (var i = 0; i < toCheck.length; i++) {
+        var observer = toCheck[i];
+        if (observer.closed)
+          continue;
+
+        if (hasObserve) {
+          observer.deliver(results);
+        } else if (observer.check()) {
+          results.anyChanged = true;
+          observer.report();
+        }
+
+        allObservers.push(observer);
+      }
+    } while (cycles < MAX_DIRTY_CHECK_CYCLES && results.anyChanged);
+
+    if (global.testingExposeCycleCount)
+      global.dirtyCheckCycleCount = cycles;
+
+    Observer._allObserversCount = allObservers.length;
+    runningMicrotaskCheckpoint = false;
+  };
+
+  if (collectObservers) {
+    global.Platform.clearObservers = function() {
+      allObservers = [];
+    };
+  }
+
+  function ObjectObserver(object, callback, target, token) {
+    Observer.call(this, object, callback, target, token);
+    this.connect();
+    this.sync(true);
+  }
+
+  ObjectObserver.prototype = createObject({
+    __proto__: Observer.prototype,
+
+    connect: function() {
+      if (hasObserve)
+        Object.observe(this.object, this.boundInternalCallback);
+    },
+
+    sync: function(hard) {
+      if (!hasObserve)
+        this.oldObject = copyObject(this.object);
+    },
+
+    check: function(changeRecords) {
+      var diff;
+      var oldValues;
+      if (hasObserve) {
+        if (!changeRecords)
+          return false;
+
+        oldValues = {};
+        diff = diffObjectFromChangeRecords(this.object, changeRecords,
+                                           oldValues);
+      } else {
+        oldValues = this.oldObject;
+        diff = diffObjectFromOldObject(this.object, this.oldObject);
+      }
+
+      if (diffIsEmpty(diff))
+        return false;
+
+      this.reportArgs =
+          [diff.added || {}, diff.removed || {}, diff.changed || {}];
+      this.reportArgs.push(function(property) {
+        return oldValues[property];
+      });
+
+      return true;
+    },
+
+    disconnect: function() {
+      if (!hasObserve)
+        this.oldObject = undefined;
+      else if (this.object)
+        Object.unobserve(this.object, this.boundInternalCallback);
+    }
+  });
+
+  function ArrayObserver(array, callback, target, token) {
+    if (!Array.isArray(array))
+      throw Error('Provided object is not an Array');
+    ObjectObserver.call(this, array, callback, target, token);
+  }
+
+  ArrayObserver.prototype = createObject({
+    __proto__: ObjectObserver.prototype,
+
+    connect: function() {
+      if (hasObserve)
+        Array.observe(this.object, this.boundInternalCallback);
+    },
+
+    sync: function() {
+      if (!hasObserve)
+        this.oldObject = this.object.slice();
+    },
+
+    check: function(changeRecords) {
+      var splices;
+      if (hasObserve) {
+        if (!changeRecords)
+          return false;
+        splices = projectArraySplices(this.object, changeRecords);
+      } else {
+        splices = calcSplices(this.object, 0, this.object.length,
+                              this.oldObject, 0, this.oldObject.length);
+      }
+
+      if (!splices || !splices.length)
+        return false;
+
+      this.reportArgs = [splices];
+      return true;
+    }
+  });
+
+  ArrayObserver.applySplices = function(previous, current, splices) {
+    splices.forEach(function(splice) {
+      var spliceArgs = [splice.index, splice.removed.length];
+      var addIndex = splice.index;
+      while (addIndex < splice.index + splice.addedCount) {
+        spliceArgs.push(current[addIndex]);
+        addIndex++;
+      }
+
+      Array.prototype.splice.apply(previous, spliceArgs);
+    });
+  };
+
+  function ObservedSet(callback) {
+    this.arr = [];
+    this.callback = callback;
+    this.isObserved = true;
+  }
+
+  var objProto = Object.getPrototypeOf({});
+  var arrayProto = Object.getPrototypeOf([]);
+  ObservedSet.prototype = {
+    reset: function() {
+      this.isObserved = !this.isObserved;
+    },
+
+    observe: function(obj) {
+      if (!isObject(obj) || obj === objProto || obj === arrayProto)
+        return;
+      var i = this.arr.indexOf(obj);
+      if (i >= 0 && this.arr[i+1] === this.isObserved)
+        return;
+
+      if (i < 0) {
+        i = this.arr.length;
+        this.arr[i] = obj;
+        Object.observe(obj, this.callback);
+      }
+
+      this.arr[i+1] = this.isObserved;
+      this.observe(Object.getPrototypeOf(obj));
+    },
+
+    cleanup: function() {
+      var i = 0, j = 0;
+      var isObserved = this.isObserved;
+      while(j < this.arr.length) {
+        var obj = this.arr[j];
+        if (this.arr[j + 1] == isObserved) {
+          if (i < j) {
+            this.arr[i] = obj;
+            this.arr[i + 1] = isObserved;
+          }
+          i += 2;
+        } else {
+          Object.unobserve(obj, this.callback);
+        }
+        j += 2;
+      }
+
+      this.arr.length = i;
+    }
+  };
+
+  function PathObserver(object, path, callback, target, token, valueFn,
+                        setValueFn) {
+    var path = path instanceof Path ? path : getPath(path);
+    if (!path || !path.length || !isObject(object)) {
+      this.value_ = path ? path.getValueFrom(object) : undefined;
+      this.value = valueFn ? valueFn(this.value_) : this.value_;
+      this.closed = true;
+      return;
+    }
+
+    Observer.call(this, object, callback, target, token);
+    this.valueFn = valueFn;
+    this.setValueFn = setValueFn;
+    this.path = path;
+
+    this.connect();
+    this.sync(true);
+  }
+
+  PathObserver.prototype = createObject({
+    __proto__: Observer.prototype,
+
+    connect: function() {
+      if (hasObserve)
+        this.observedSet = new ObservedSet(this.boundInternalCallback);
+    },
+
+    disconnect: function() {
+      this.value = undefined;
+      this.value_ = undefined;
+      if (this.observedSet) {
+        this.observedSet.reset();
+        this.observedSet.cleanup();
+        this.observedSet = undefined;
+      }
+    },
+
+    check: function() {
+      // Note: Extracting this to a member function for use here and below
+      // regresses dirty-checking path perf by about 25% =-(.
+      if (this.observedSet)
+        this.observedSet.reset();
+
+      this.value_ = this.path.getValueFrom(this.object, this.observedSet);
+
+      if (this.observedSet)
+        this.observedSet.cleanup();
+
+      if (areSameValue(this.value_, this.oldValue_))
+        return false;
+
+      this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
+      this.reportArgs = [this.value, this.oldValue];
+      return true;
+    },
+
+    sync: function(hard) {
+      if (hard) {
+        if (this.observedSet)
+          this.observedSet.reset();
+
+        this.value_ = this.path.getValueFrom(this.object, this.observedSet);
+        this.value = this.valueFn ? this.valueFn(this.value_) : this.value_;
+
+        if (this.observedSet)
+          this.observedSet.cleanup();
+      }
+
+      this.oldValue_ = this.value_;
+      this.oldValue = this.value;
+    },
+
+    setValue: function(newValue) {
+      if (!this.path)
+        return;
+      if (typeof this.setValueFn === 'function')
+        newValue = this.setValueFn(newValue);
+      this.path.setValueFrom(this.object, newValue);
+    }
+  });
+
+  function CompoundPathObserver(callback, target, token, valueFn) {
+    Observer.call(this, undefined, callback, target, token);
+    this.valueFn = valueFn;
+
+    this.observed = [];
+    this.values = [];
+    this.started = false;
+  }
+
+  CompoundPathObserver.prototype = createObject({
+    __proto__: PathObserver.prototype,
+
+    addPath: function(object, path) {
+      if (this.started)
+        throw Error('Cannot add more paths once started.');
+
+      var path = path instanceof Path ? path : getPath(path);
+      var value = path ? path.getValueFrom(object) : undefined;
+
+      this.observed.push(object, path);
+      this.values.push(value);
+    },
+
+    start: function() {
+      this.connect();
+      this.sync(true);
+    },
+
+    getValues: function() {
+      if (this.observedSet)
+        this.observedSet.reset();
+
+      var anyChanged = false;
+      for (var i = 0; i < this.observed.length; i = i+2) {
+        var path = this.observed[i+1];
+        if (!path)
+          continue;
+        var object = this.observed[i];
+        var value = path.getValueFrom(object, this.observedSet);
+        var oldValue = this.values[i/2];
+        if (!areSameValue(value, oldValue)) {
+          this.values[i/2] = value;
+          anyChanged = true;
+        }
+      }
+
+      if (this.observedSet)
+        this.observedSet.cleanup();
+
+      return anyChanged;
+    },
+
+    check: function() {
+      if (!this.getValues())
+        return;
+
+      this.value = this.valueFn(this.values);
+
+      if (areSameValue(this.value, this.oldValue))
+        return false;
+
+      this.reportArgs = [this.value, this.oldValue];
+      return true;
+    },
+
+    sync: function(hard) {
+      if (hard) {
+        this.getValues();
+        this.value = this.valueFn(this.values);
+      }
+
+      this.oldValue = this.value;
+    },
+
+    close: function() {
+      if (this.observed) {
+        for (var i = 0; i < this.observed.length; i = i + 2) {
+          var object = this.observed[i];
+          if (object && typeof object.close === 'function')
+            object.close();
+        }
+        this.observed = undefined;
+        this.values = undefined;
+      }
+
+      Observer.prototype.close.call(this);
+    }
+  });
+
+  var knownRecordTypes = {
+    'new': true,
+    'updated': true,
+    'deleted': true
+  };
+
+  function notifyFunction(object, name) {
+    if (typeof Object.observe !== 'function')
+      return;
+
+    var notifier = Object.getNotifier(object);
+    return function(type, oldValue) {
+      var changeRecord = {
+        object: object,
+        type: type,
+        name: name
+      };
+      if (arguments.length === 2)
+        changeRecord.oldValue = oldValue;
+      notifier.notify(changeRecord);
+    }
+  }
+
+  // TODO(rafaelw): It should be possible for the Object.observe case to have
+  // every PathObserver used by defineProperty share a single Object.observe
+  // callback, and thus get() can simply call observer.deliver() and any changes
+  // to any dependent value will be observed.
+  PathObserver.defineProperty = function(object, name, descriptor) {
+    // TODO(rafaelw): Validate errors
+    var obj = descriptor.object;
+    var path = getPath(descriptor.path);
+    var notify = notifyFunction(object, name);
+
+    var observer = new PathObserver(obj, descriptor.path,
+        function(newValue, oldValue) {
+          if (notify)
+            notify('updated', oldValue);
+        }
+    );
+
+    Object.defineProperty(object, name, {
+      get: function() {
+        return path.getValueFrom(obj);
+      },
+      set: function(newValue) {
+        path.setValueFrom(obj, newValue);
+      },
+      configurable: true
+    });
+
+    return {
+      close: function() {
+        var oldValue = path.getValueFrom(obj);
+        if (notify)
+          observer.deliver();
+        observer.close();
+        Object.defineProperty(object, name, {
+          value: oldValue,
+          writable: true,
+          configurable: true
+        });
+      }
+    };
+  }
+
+  function diffObjectFromChangeRecords(object, changeRecords, oldValues) {
+    var added = {};
+    var removed = {};
+
+    for (var i = 0; i < changeRecords.length; i++) {
+      var record = changeRecords[i];
+      if (!knownRecordTypes[record.type]) {
+        console.error('Unknown changeRecord type: ' + record.type);
+        console.error(record);
+        continue;
+      }
+
+      if (!(record.name in oldValues))
+        oldValues[record.name] = record.oldValue;
+
+      if (record.type == 'updated')
+        continue;
+
+      if (record.type == 'new') {
+        if (record.name in removed)
+          delete removed[record.name];
+        else
+          added[record.name] = true;
+
+        continue;
+      }
+
+      // type = 'deleted'
+      if (record.name in added) {
+        delete added[record.name];
+        delete oldValues[record.name];
+      } else {
+        removed[record.name] = true;
+      }
+    }
+
+    for (var prop in added)
+      added[prop] = object[prop];
+
+    for (var prop in removed)
+      removed[prop] = undefined;
+
+    var changed = {};
+    for (var prop in oldValues) {
+      if (prop in added || prop in removed)
+        continue;
+
+      var newValue = object[prop];
+      if (oldValues[prop] !== newValue)
+        changed[prop] = newValue;
+    }
+
+    return {
+      added: added,
+      removed: removed,
+      changed: changed
+    };
+  }
+
+  function newSplice(index, removed, addedCount) {
+    return {
+      index: index,
+      removed: removed,
+      addedCount: addedCount
+    };
+  }
+
+  var EDIT_LEAVE = 0;
+  var EDIT_UPDATE = 1;
+  var EDIT_ADD = 2;
+  var EDIT_DELETE = 3;
+
+  function ArraySplice() {}
+
+  ArraySplice.prototype = {
+
+    // Note: This function is *based* on the computation of the Levenshtein
+    // "edit" distance. The one change is that "updates" are treated as two
+    // edits - not one. With Array splices, an update is really a delete
+    // followed by an add. By retaining this, we optimize for "keeping" the
+    // maximum array items in the original array. For example:
+    //
+    //   'xxxx123' -> '123yyyy'
+    //
+    // With 1-edit updates, the shortest path would be just to update all seven
+    // characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
+    // leaves the substring '123' intact.
+    calcEditDistances: function(current, currentStart, currentEnd,
+                                old, oldStart, oldEnd) {
+      // "Deletion" columns
+      var rowCount = oldEnd - oldStart + 1;
+      var columnCount = currentEnd - currentStart + 1;
+      var distances = new Array(rowCount);
+
+      // "Addition" rows. Initialize null column.
+      for (var i = 0; i < rowCount; i++) {
+        distances[i] = new Array(columnCount);
+        distances[i][0] = i;
+      }
+
+      // Initialize null row
+      for (var j = 0; j < columnCount; j++)
+        distances[0][j] = j;
+
+      for (var i = 1; i < rowCount; i++) {
+        for (var j = 1; j < columnCount; j++) {
+          if (this.equals(current[currentStart + j - 1], old[oldStart + i - 1]))
+            distances[i][j] = distances[i - 1][j - 1];
+          else {
+            var north = distances[i - 1][j] + 1;
+            var west = distances[i][j - 1] + 1;
+            distances[i][j] = north < west ? north : west;
+          }
+        }
+      }
+
+      return distances;
+    },
+
+    // This starts at the final weight, and walks "backward" by finding
+    // the minimum previous weight recursively until the origin of the weight
+    // matrix.
+    spliceOperationsFromEditDistances: function(distances) {
+      var i = distances.length - 1;
+      var j = distances[0].length - 1;
+      var current = distances[i][j];
+      var edits = [];
+      while (i > 0 || j > 0) {
+        if (i == 0) {
+          edits.push(EDIT_ADD);
+          j--;
+          continue;
+        }
+        if (j == 0) {
+          edits.push(EDIT_DELETE);
+          i--;
+          continue;
+        }
+        var northWest = distances[i - 1][j - 1];
+        var west = distances[i - 1][j];
+        var north = distances[i][j - 1];
+
+        var min;
+        if (west < north)
+          min = west < northWest ? west : northWest;
+        else
+          min = north < northWest ? north : northWest;
+
+        if (min == northWest) {
+          if (northWest == current) {
+            edits.push(EDIT_LEAVE);
+          } else {
+            edits.push(EDIT_UPDATE);
+            current = northWest;
+          }
+          i--;
+          j--;
+        } else if (min == west) {
+          edits.push(EDIT_DELETE);
+          i--;
+          current = west;
+        } else {
+          edits.push(EDIT_ADD);
+          j--;
+          current = north;
+        }
+      }
+
+      edits.reverse();
+      return edits;
+    },
+
+    /**
+     * Splice Projection functions:
+     *
+     * A splice map is a representation of how a previous array of items
+     * was transformed into a new array of items. Conceptually it is a list of
+     * tuples of
+     *
+     *   <index, removed, addedCount>
+     *
+     * which are kept in ascending index order of. The tuple represents that at
+     * the |index|, |removed| sequence of items were removed, and counting forward
+     * from |index|, |addedCount| items were added.
+     */
+
+    /**
+     * Lacking individual splice mutation information, the minimal set of
+     * splices can be synthesized given the previous state and final state of an
+     * array. The basic approach is to calculate the edit distance matrix and
+     * choose the shortest path through it.
+     *
+     * Complexity: O(l * p)
+     *   l: The length of the current array
+     *   p: The length of the old array
+     */
+    calcSplices: function(current, currentStart, currentEnd,
+                          old, oldStart, oldEnd) {
+      var prefixCount = 0;
+      var suffixCount = 0;
+
+      var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
+      if (currentStart == 0 && oldStart == 0)
+        prefixCount = this.sharedPrefix(current, old, minLength);
+
+      if (currentEnd == current.length && oldEnd == old.length)
+        suffixCount = this.sharedSuffix(current, old, minLength - prefixCount);
+
+      currentStart += prefixCount;
+      oldStart += prefixCount;
+      currentEnd -= suffixCount;
+      oldEnd -= suffixCount;
+
+      if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0)
+        return [];
+
+      if (currentStart == currentEnd) {
+        var splice = newSplice(currentStart, [], 0);
+        while (oldStart < oldEnd)
+          splice.removed.push(old[oldStart++]);
+
+        return [ splice ];
+      } else if (oldStart == oldEnd)
+        return [ newSplice(currentStart, [], currentEnd - currentStart) ];
+
+      var ops = this.spliceOperationsFromEditDistances(
+          this.calcEditDistances(current, currentStart, currentEnd,
+                                 old, oldStart, oldEnd));
+
+      var splice = undefined;
+      var splices = [];
+      var index = currentStart;
+      var oldIndex = oldStart;
+      for (var i = 0; i < ops.length; i++) {
+        switch(ops[i]) {
+          case EDIT_LEAVE:
+            if (splice) {
+              splices.push(splice);
+              splice = undefined;
+            }
+
+            index++;
+            oldIndex++;
+            break;
+          case EDIT_UPDATE:
+            if (!splice)
+              splice = newSplice(index, [], 0);
+
+            splice.addedCount++;
+            index++;
+
+            splice.removed.push(old[oldIndex]);
+            oldIndex++;
+            break;
+          case EDIT_ADD:
+            if (!splice)
+              splice = newSplice(index, [], 0);
+
+            splice.addedCount++;
+            index++;
+            break;
+          case EDIT_DELETE:
+            if (!splice)
+              splice = newSplice(index, [], 0);
+
+            splice.removed.push(old[oldIndex]);
+            oldIndex++;
+            break;
+        }
+      }
+
+      if (splice) {
+        splices.push(splice);
+      }
+      return splices;
+    },
+
+    sharedPrefix: function(current, old, searchLength) {
+      for (var i = 0; i < searchLength; i++)
+        if (!this.equals(current[i], old[i]))
+          return i;
+      return searchLength;
+    },
+
+    sharedSuffix: function(current, old, searchLength) {
+      var index1 = current.length;
+      var index2 = old.length;
+      var count = 0;
+      while (count < searchLength && this.equals(current[--index1], old[--index2]))
+        count++;
+
+      return count;
+    },
+
+    calculateSplices: function(current, previous) {
+      return this.calcSplices(current, 0, current.length, previous, 0,
+                              previous.length);
+    },
+
+    equals: function(currentValue, previousValue) {
+      return currentValue === previousValue;
+    }
+  };
+
+  var arraySplice = new ArraySplice();
+
+  function calcSplices(current, currentStart, currentEnd,
+                       old, oldStart, oldEnd) {
+    return arraySplice.calcSplices(current, currentStart, currentEnd,
+                                   old, oldStart, oldEnd);
+  }
+
+  function intersect(start1, end1, start2, end2) {
+    // Disjoint
+    if (end1 < start2 || end2 < start1)
+      return -1;
+
+    // Adjacent
+    if (end1 == start2 || end2 == start1)
+      return 0;
+
+    // Non-zero intersect, span1 first
+    if (start1 < start2) {
+      if (end1 < end2)
+        return end1 - start2; // Overlap
+      else
+        return end2 - start2; // Contained
+    } else {
+      // Non-zero intersect, span2 first
+      if (end2 < end1)
+        return end2 - start1; // Overlap
+      else
+        return end1 - start1; // Contained
+    }
+  }
+
+  function mergeSplice(splices, index, removed, addedCount) {
+
+    var splice = newSplice(index, removed, addedCount);
+
+    var inserted = false;
+    var insertionOffset = 0;
+
+    for (var i = 0; i < splices.length; i++) {
+      var current = splices[i];
+      current.index += insertionOffset;
+
+      if (inserted)
+        continue;
+
+      var intersectCount = intersect(splice.index,
+                                     splice.index + splice.removed.length,
+                                     current.index,
+                                     current.index + current.addedCount);
+
+      if (intersectCount >= 0) {
+        // Merge the two splices
+
+        splices.splice(i, 1);
+        i--;
+
+        insertionOffset -= current.addedCount - current.removed.length;
+
+        splice.addedCount += current.addedCount - intersectCount;
+        var deleteCount = splice.removed.length +
+                          current.removed.length - intersectCount;
+
+        if (!splice.addedCount && !deleteCount) {
+          // merged splice is a noop. discard.
+          inserted = true;
+        } else {
+          var removed = current.removed;
+
+          if (splice.index < current.index) {
+            // some prefix of splice.removed is prepended to current.removed.
+            var prepend = splice.removed.slice(0, current.index - splice.index);
+            Array.prototype.push.apply(prepend, removed);
+            removed = prepend;
+          }
+
+          if (splice.index + splice.removed.length > current.index + current.addedCount) {
+            // some suffix of splice.removed is appended to current.removed.
+            var append = splice.removed.slice(current.index + current.addedCount - splice.index);
+            Array.prototype.push.apply(removed, append);
+          }
+
+          splice.removed = removed;
+          if (current.index < splice.index) {
+            splice.index = current.index;
+          }
+        }
+      } else if (splice.index < current.index) {
+        // Insert splice here.
+
+        inserted = true;
+
+        splices.splice(i, 0, splice);
+        i++;
+
+        var offset = splice.addedCount - splice.removed.length
+        current.index += offset;
+        insertionOffset += offset;
+      }
+    }
+
+    if (!inserted)
+      splices.push(splice);
+  }
+
+  function createInitialSplices(array, changeRecords) {
+    var splices = [];
+
+    for (var i = 0; i < changeRecords.length; i++) {
+      var record = changeRecords[i];
+      switch(record.type) {
+        case 'splice':
+          mergeSplice(splices, record.index, record.removed.slice(), record.addedCount);
+          break;
+        case 'new':
+        case 'updated':
+        case 'deleted':
+          if (!isIndex(record.name))
+            continue;
+          var index = toNumber(record.name);
+          if (index < 0)
+            continue;
+          mergeSplice(splices, index, [record.oldValue], 1);
+          break;
+        default:
+          console.error('Unexpected record type: ' + JSON.stringify(record));
+          break;
+      }
+    }
+
+    return splices;
+  }
+
+  function projectArraySplices(array, changeRecords) {
+    var splices = [];
+
+    createInitialSplices(array, changeRecords).forEach(function(splice) {
+      if (splice.addedCount == 1 && splice.removed.length == 1) {
+        if (splice.removed[0] !== array[splice.index])
+          splices.push(splice);
+
+        return
+      };
+
+      splices = splices.concat(calcSplices(array, splice.index, splice.index + splice.addedCount,
+                                           splice.removed, 0, splice.removed.length));
+    });
+
+    return splices;
+  }
+
+  global.Observer = Observer;
+  global.Observer.hasObjectObserve = hasObserve;
+  global.ArrayObserver = ArrayObserver;
+  global.ArrayObserver.calculateSplices = function(current, previous) {
+    return arraySplice.calculateSplices(current, previous);
+  };
+
+  global.ArraySplice = ArraySplice;
+  global.ObjectObserver = ObjectObserver;
+  global.PathObserver = PathObserver;
+  global.CompoundPathObserver = CompoundPathObserver;
+  global.Path = Path;
+})(typeof global !== 'undefined' && global ? global : this);
+
 /*
  * Copyright 2012 The Polymer Authors. All rights reserved.
- * Use of this source code is goverened by a BSD-style
+ * Use of this source code is governed by a BSD-style
  * license that can be found in the LICENSE file.
  */
 
-// SideTable is a weak map where possible. If WeakMap is not available the
-// association is stored as an expando property.
-var SideTable;
+// If WeakMap is not available, the association is stored as an expando property on the "key".
 // TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
-if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
-  SideTable = WeakMap;
-} else {
+if (typeof WeakMap === 'undefined' || navigator.userAgent.indexOf('Firefox/') > -1) {
   (function() {
     var defineProperty = Object.defineProperty;
     var counter = Date.now() % 1e9;
 
-    SideTable = function() {
+    var WeakMap = function() {
       this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
     };
 
-    SideTable.prototype = {
+    WeakMap.prototype = {
       set: function(key, value) {
         var entry = key[this.name];
         if (entry && entry[0] === key)
@@ -53,7 +1375,9 @@
       delete: function(key) {
         this.set(key, undefined);
       }
-    }
+    };
+
+    window.WeakMap = WeakMap;
   })();
 }
 
@@ -66,11 +1390,23 @@
 (function(scope) {
   'use strict';
 
-  var wrapperTable = new SideTable();
-  var constructorTable = new SideTable();
-  var nativePrototypeTable = new SideTable();
+  var constructorTable = new WeakMap();
+  var nativePrototypeTable = new WeakMap();
   var wrappers = Object.create(null);
 
+  // Don't test for eval if document has CSP securityPolicy object and we can
+  // see that eval is not supported. This avoids an error message in console
+  // even when the exception is caught
+  var hasEval = !('securityPolicy' in document) ||
+      document.securityPolicy.allowsEval;
+  if (hasEval) {
+    try {
+      var f = new Function('', 'return true;');
+      hasEval = f();
+    } catch (ex) {
+    }
+  }
+
   function assert(b) {
     if (!b)
       throw new Error('Assertion failed');
@@ -150,6 +1486,25 @@
     return /^on[a-z]+$/.test(name);
   }
 
+  function getGetter(name) {
+    return hasEval ?
+        new Function('return this.impl.' + name) :
+        function() { return this.impl[name]; };
+  }
+
+  function getSetter(name) {
+    return hasEval ?
+        new Function('v', 'this.impl.' + name + ' = v') :
+        function(v) { this.impl[name] = v; };
+  }
+
+  function getMethod(name) {
+    return hasEval ?
+        new Function('return this.impl.' + name +
+                     '.apply(this.impl, arguments)') :
+        function() { return this.impl[name].apply(this.impl, arguments); };
+  }
+
   function installProperty(source, target, allowMethod) {
     Object.getOwnPropertyNames(source).forEach(function(name) {
       if (name in target)
@@ -170,29 +1525,21 @@
       }
       var getter, setter;
       if (allowMethod && typeof descriptor.value === 'function') {
-        target[name] = function() {
-          return this.impl[name].apply(this.impl, arguments);
-        };
+        target[name] = getMethod(name);
         return;
       }
 
       var isEvent = isEventHandlerName(name);
-      if (isEvent) {
+      if (isEvent)
         getter = scope.getEventHandlerGetter(name);
-      } else {
-        getter = function() {
-          return this.impl[name];
-        };
-      }
+      else
+        getter = getGetter(name);
 
       if (descriptor.writable || descriptor.set) {
-        if (isEvent) {
+        if (isEvent)
           setter = scope.getEventHandlerSetter(name);
-        } else {
-          setter = function(value) {
-            this.impl[name] = value;
-          };
-        }
+        else
+          setter = getSetter(name);
       }
 
       Object.defineProperty(target, name, {
@@ -296,10 +1643,8 @@
       return null;
 
     assert(isNative(impl));
-    var wrapper = wrapperTable.get(impl);
-    if (!wrapper)
-      wrapperTable.set(impl, wrapper = new (getWrapperConstructor(impl))(impl));
-    return wrapper;
+    return impl.polymerWrapper_ ||
+        (impl.polymerWrapper_ = new (getWrapperConstructor(impl))(impl));
   }
 
   /**
@@ -343,7 +1688,7 @@
       return;
     assert(isNative(node));
     assert(wrapper === undefined || isWrapper(wrapper));
-    wrapperTable.set(node, wrapper);
+    node.polymerWrapper_ = wrapper;
   }
 
   function defineGetter(constructor, name, getter) {
@@ -411,17 +1756,17 @@
   var wrap = scope.wrap;
   var wrappers = scope.wrappers;
 
-  var wrappedFuns = new SideTable();
-  var listenersTable = new SideTable();
-  var handledEventsTable = new SideTable();
-  var targetTable = new SideTable();
-  var currentTargetTable = new SideTable();
-  var relatedTargetTable = new SideTable();
-  var eventPhaseTable = new SideTable();
-  var stopPropagationTable = new SideTable();
-  var stopImmediatePropagationTable = new SideTable();
-  var eventHandlersTable = new SideTable();
-  var eventPathTable = new SideTable();
+  var wrappedFuns = new WeakMap();
+  var listenersTable = new WeakMap();
+  var handledEventsTable = new WeakMap();
+  var targetTable = new WeakMap();
+  var currentTargetTable = new WeakMap();
+  var relatedTargetTable = new WeakMap();
+  var eventPhaseTable = new WeakMap();
+  var stopPropagationTable = new WeakMap();
+  var stopImmediatePropagationTable = new WeakMap();
+  var eventHandlersTable = new WeakMap();
+  var eventPathTable = new WeakMap();
 
   function isShadowRoot(node) {
     return node instanceof wrappers.ShadowRoot;
@@ -578,7 +1923,6 @@
       return enclosedBy(rootOfNode(host), b);
     }
     return false;
-
   }
 
   function isMutationEvent(type) {
@@ -1042,7 +2386,6 @@
       }
     },
     dispatchEvent: function(event) {
-      scope.renderAllPending();
       var target = getTargetToListenAt(this);
       return target.dispatchEvent_(unwrap(event));
     }
@@ -1211,7 +2554,7 @@
    * This updates the internal pointers for node, previousNode and nextNode.
    */
   function collectNodes(node, parentNode, previousNode, nextNode) {
-    if (node.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
+    if (!(node instanceof DocumentFragment)) {
       if (node.parentNode)
         node.parentNode.removeChild(node);
       node.parentNode_ = parentNode;
@@ -1245,6 +2588,24 @@
     return nodes;
   }
 
+  function collectNodesNoNeedToUpdatePointers(node) {
+    if (node instanceof DocumentFragment) {
+      var nodes = [];
+      var i = 0;
+      for (var child = node.firstChild; child; child = child.nextSibling) {
+        nodes[i++] = child;
+      }
+      return nodes;
+    }
+    return [node];
+  }
+
+  function nodesWereAdded(nodes) {
+    for (var i = 0; i < nodes.length; i++) {
+      nodes[i].nodeWasAdded_();
+    }
+  }
+
   function ensureSameOwnerDocument(parent, child) {
     var ownerDoc = parent.nodeType === Node.DOCUMENT_NODE ?
         parent : parent.ownerDocument;
@@ -1373,10 +2734,12 @@
     appendChild: function(childWrapper) {
       assertIsNodeWrapper(childWrapper);
 
+      var nodes;
+
       if (this.invalidateShadowRenderer() || invalidateParent(childWrapper)) {
         var previousNode = this.lastChild;
         var nextNode = null;
-        var nodes = collectNodes(childWrapper, this, previousNode, nextNode);
+        nodes = collectNodes(childWrapper, this, previousNode, nextNode);
 
         this.lastChild_ = nodes[nodes.length - 1];
         if (!previousNode)
@@ -1384,11 +2747,12 @@
 
         originalAppendChild.call(this.impl, unwrapNodesForInsertion(this, nodes));
       } else {
+        nodes = collectNodesNoNeedToUpdatePointers(childWrapper)
         ensureSameOwnerDocument(this, childWrapper);
         originalAppendChild.call(this.impl, unwrap(childWrapper));
       }
 
-      childWrapper.nodeWasAdded_();
+      nodesWereAdded(nodes);
 
       return childWrapper;
     },
@@ -1402,10 +2766,12 @@
       assertIsNodeWrapper(refWrapper);
       assert(refWrapper.parentNode === this);
 
+      var nodes;
+
       if (this.invalidateShadowRenderer() || invalidateParent(childWrapper)) {
         var previousNode = refWrapper.previousSibling;
         var nextNode = refWrapper;
-        var nodes = collectNodes(childWrapper, this, previousNode, nextNode);
+        nodes = collectNodes(childWrapper, this, previousNode, nextNode);
 
         if (this.firstChild === refWrapper)
           this.firstChild_ = nodes[0];
@@ -1423,12 +2789,13 @@
           adoptNodesIfNeeded(this, nodes);
         }
       } else {
+        nodes = collectNodesNoNeedToUpdatePointers(childWrapper);
         ensureSameOwnerDocument(this, childWrapper);
         originalInsertBefore.call(this.impl, unwrap(childWrapper),
                                   unwrap(refWrapper));
       }
 
-      childWrapper.nodeWasAdded_();
+      nodesWereAdded(nodes);
 
       return childWrapper;
     },
@@ -1485,6 +2852,7 @@
       }
 
       var oldChildNode = unwrap(oldChildWrapper);
+      var nodes;
 
       if (this.invalidateShadowRenderer() ||
           invalidateParent(newChildWrapper)) {
@@ -1492,8 +2860,7 @@
         var nextNode = oldChildWrapper.nextSibling;
         if (nextNode === newChildWrapper)
           nextNode = newChildWrapper.nextSibling;
-        var nodes = collectNodes(newChildWrapper, this,
-                                 previousNode, nextNode);
+        nodes = collectNodes(newChildWrapper, this, previousNode, nextNode);
 
         if (this.firstChild === oldChildWrapper)
           this.firstChild_ = nodes[0];
@@ -1511,12 +2878,13 @@
               oldChildNode);
         }
       } else {
+        nodes = collectNodesNoNeedToUpdatePointers(newChildWrapper);
         ensureSameOwnerDocument(this, newChildWrapper);
         originalReplaceChild.call(this.impl, unwrap(newChildWrapper),
                                   oldChildNode);
       }
 
-      newChildWrapper.nodeWasAdded_();
+      nodesWereAdded(nodes);
 
       return oldChildWrapper;
     },
@@ -1635,19 +3003,10 @@
       // This only wraps, it therefore only operates on the composed DOM and not
       // the logical DOM.
       return originalCompareDocumentPosition.call(this.impl, unwrap(otherNode));
-    },
-
-    // TODO(jmesserly): this is a workaround for
-    // https://github.com/Polymer/ShadowDOM/issues/200
-    get ownerDocument() {
-      scope.renderAllPending();
-      return wrap(this.impl.ownerDocument);
     }
   });
 
-  // TODO(jmesserly): this is commented out to workaround:
-  // https://github.com/Polymer/ShadowDOM/issues/200
-  //defineWrapGetter(Node, 'ownerDocument');
+  defineWrapGetter(Node, 'ownerDocument');
 
   // We use a DocumentFragment as a base and then delete the properties of
   // DocumentFragment.prototype from the wrapper Node. Since delete makes
@@ -1858,7 +3217,7 @@
   var registerWrapper = scope.registerWrapper;
   var wrappers = scope.wrappers;
 
-  var shadowRootTable = new SideTable();
+  var shadowRootTable = new WeakMap();
   var OriginalElement = window.Element;
 
 
@@ -2224,8 +3583,8 @@
   var unwrap = scope.unwrap;
   var wrap = scope.wrap;
 
-  var contentTable = new SideTable();
-  var templateContentsOwnerTable = new SideTable();
+  var contentTable = new WeakMap();
+  var templateContentsOwnerTable = new WeakMap();
 
   // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner
   function getTemplateContentsOwner(doc) {
@@ -2362,8 +3721,8 @@
   var setInnerHTML = scope.setInnerHTML;
   var unwrap = scope.unwrap;
 
-  var shadowHostTable = new SideTable();
-  var nextOlderShadowTreeTable = new SideTable();
+  var shadowHostTable = new WeakMap();
+  var nextOlderShadowTreeTable = new WeakMap();
 
   function ShadowRoot(hostWrapper) {
     var node = unwrap(hostWrapper.impl.ownerDocument.createDocumentFragment());
@@ -2417,6 +3776,7 @@
 (function(scope) {
   'use strict';
 
+  var Element = scope.wrappers.Element;
   var HTMLContentElement = scope.wrappers.HTMLContentElement;
   var HTMLShadowElement = scope.wrappers.HTMLShadowElement;
   var Node = scope.wrappers.Node;
@@ -2460,79 +3820,59 @@
     updateWrapperDown(parentNodeWrapper);
   }
 
-  // This object groups DOM operations. This is supposed to be the DOM as the
-  // browser/render tree sees it.
-  // When changes are done to the visual DOM the logical DOM needs to be updated
-  // to reflect the correct tree.
-  function removeAllChildNodes(parentNodeWrapper) {
+  function insertBefore(parentNodeWrapper, newChildWrapper, refChildWrapper) {
     var parentNode = unwrap(parentNodeWrapper);
-    updateAllChildNodes(parentNodeWrapper);
-    if (parentNode.firstChild)
-      parentNode.textContent = '';
-  }
+    var newChild = unwrap(newChildWrapper);
+    var refChild = refChildWrapper ? unwrap(refChildWrapper) : null;
 
-  function appendChild(parentNodeWrapper, childWrapper) {
-    var parentNode = unwrap(parentNodeWrapper);
-    var child = unwrap(childWrapper);
-    if (child.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      updateAllChildNodes(childWrapper);
+    remove(newChildWrapper);
+    updateWrapperUpAndSideways(newChildWrapper);
 
+    if (!refChildWrapper) {
+      parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
+      if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
+        parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
+
+      var lastChildWrapper = wrap(parentNode.lastChild);
+      if (lastChildWrapper)
+        lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
     } else {
-      remove(childWrapper);
-      updateWrapperUpAndSideways(childWrapper);
+      if (parentNodeWrapper.firstChild === refChildWrapper)
+        parentNodeWrapper.firstChild_ = refChildWrapper;
+
+      refChildWrapper.previousSibling_ = refChildWrapper.previousSibling;
     }
 
-    parentNodeWrapper.lastChild_ = parentNodeWrapper.lastChild;
-    if (parentNodeWrapper.lastChild === parentNodeWrapper.firstChild)
-      parentNodeWrapper.firstChild_ = parentNodeWrapper.firstChild;
-
-    var lastChildWrapper = wrap(parentNode.lastChild);
-    if (lastChildWrapper) {
-      lastChildWrapper.nextSibling_ = lastChildWrapper.nextSibling;
-    }
-
-    parentNode.appendChild(child);
-  }
-
-  function removeChild(parentNodeWrapper, childWrapper) {
-    var parentNode = unwrap(parentNodeWrapper);
-    var child = unwrap(childWrapper);
-
-    updateWrapperUpAndSideways(childWrapper);
-
-    if (childWrapper.previousSibling)
-      childWrapper.previousSibling.nextSibling_ = childWrapper;
-    if (childWrapper.nextSibling)
-      childWrapper.nextSibling.previousSibling_ = childWrapper;
-
-    if (parentNodeWrapper.lastChild === childWrapper)
-      parentNodeWrapper.lastChild_ = childWrapper;
-    if (parentNodeWrapper.firstChild === childWrapper)
-      parentNodeWrapper.firstChild_ = childWrapper;
-
-    parentNode.removeChild(child);
+    parentNode.insertBefore(newChild, refChild);
   }
 
   function remove(nodeWrapper) {
     var node = unwrap(nodeWrapper)
     var parentNode = node.parentNode;
-    if (parentNode)
-      removeChild(wrap(parentNode), nodeWrapper);
+    if (!parentNode)
+      return;
+
+    var parentNodeWrapper = wrap(parentNode);
+    updateWrapperUpAndSideways(nodeWrapper);
+
+    if (nodeWrapper.previousSibling)
+      nodeWrapper.previousSibling.nextSibling_ = nodeWrapper;
+    if (nodeWrapper.nextSibling)
+      nodeWrapper.nextSibling.previousSibling_ = nodeWrapper;
+
+    if (parentNodeWrapper.lastChild === nodeWrapper)
+      parentNodeWrapper.lastChild_ = nodeWrapper;
+    if (parentNodeWrapper.firstChild === nodeWrapper)
+      parentNodeWrapper.firstChild_ = nodeWrapper;
+
+    parentNode.removeChild(node);
   }
 
-  var distributedChildNodesTable = new SideTable();
-  var eventParentsTable = new SideTable();
-  var insertionParentTable = new SideTable();
-  var rendererForHostTable = new SideTable();
-  var shadowDOMRendererTable = new SideTable();
-
-  var reprCounter = 0;
-
-  function repr(node) {
-    if (!node.displayName)
-      node.displayName = node.nodeName + '-' + ++reprCounter;
-    return node.displayName;
-  }
+  var distributedChildNodesTable = new WeakMap();
+  var eventParentsTable = new WeakMap();
+  var insertionParentTable = new WeakMap();
+  var rendererForHostTable = new WeakMap();
+  var shadowDOMRendererTable = new WeakMap();
 
   function distributeChildToInsertionPoint(child, insertionPoint) {
     getDistributedChildNodes(insertionPoint).push(child);
@@ -2569,9 +3909,7 @@
    */
   function visit(tree, predicate, visitor) {
     // This operates on logical DOM.
-    var nodes = getChildNodesSnapshot(tree);
-    for (var i = 0; i < nodes.length; i++) {
-      var node = nodes[i];
+    for (var node = tree.firstChild; node; node = node.nextSibling) {
       if (predicate(node)) {
         if (visitor(node) === false)
           return;
@@ -2622,14 +3960,14 @@
     if (!select)
       return true;
 
-    if (node.nodeType !== Node.ELEMENT_NODE)
+    if (!(node instanceof Element))
       return false;
 
     // TODO(arv): This does not seem right. Need to check for a simple selector.
     if (!selectorMatchRegExp.test(select))
       return false;
 
-    if (select[0] === ':' &&!allowedPseudoRegExp.test(select))
+    if (select[0] === ':' && !allowedPseudoRegExp.test(select))
       return false;
 
     try {
@@ -2651,18 +3989,15 @@
   var renderTimer;
 
   function renderAllPending() {
-    renderTimer = null;
-    pendingDirtyRenderers.forEach(function(owner) {
-      owner.render();
-    });
+    for (var i = 0; i < pendingDirtyRenderers.length; i++) {
+      pendingDirtyRenderers[i].render();
+    }
     pendingDirtyRenderers = [];
   }
 
-  function ShadowRenderer(host) {
-    this.host = host;
-    this.dirty = false;
-    this.invalidateAttributes();
-    this.associateNode(host);
+  function handleRequestAnimationFrame() {
+    renderTimer = null;
+    renderAllPending();
   }
 
   /**
@@ -2691,10 +4026,92 @@
     return getRendererForHost(getHostForShadowRoot(shadowRoot));
   }
 
+  var spliceDiff = new ArraySplice();
+  spliceDiff.equals = function(renderNode, rawNode) {
+    return unwrap(renderNode.node) === rawNode;
+  };
+
+  /**
+   * RenderNode is used as an in memory "render tree". When we render the
+   * composed tree we create a tree of RenderNodes, then we diff this against
+   * the real DOM tree and make minimal changes as needed.
+   */
+  function RenderNode(node) {
+    this.skip = false;
+    this.node = node;
+    this.childNodes = [];
+  }
+
+  RenderNode.prototype = {
+    append: function(node) {
+      var rv = new RenderNode(node);
+      this.childNodes.push(rv);
+      return rv;
+    },
+
+    sync: function(opt_added) {
+      if (this.skip)
+        return;
+
+      var nodeWrapper = this.node;
+      // plain array of RenderNodes
+      var newChildren = this.childNodes;
+      // plain array of real nodes.
+      var oldChildren = getChildNodesSnapshot(unwrap(nodeWrapper));
+      var added = opt_added || new WeakMap();
+
+      var splices = spliceDiff.calculateSplices(newChildren, oldChildren);
+
+      var newIndex = 0, oldIndex = 0;
+      var lastIndex = 0;
+      for (var i = 0; i < splices.length; i++) {
+        var splice = splices[i];
+        for (; lastIndex < splice.index; lastIndex++) {
+          oldIndex++;
+          newChildren[newIndex++].sync(added);
+        }
+
+        var removedCount = splice.removed.length;
+        for (var j = 0; j < removedCount; j++) {
+          var wrapper = wrap(oldChildren[oldIndex++]);
+          if (!added.get(wrapper))
+            remove(wrapper);
+        }
+
+        var addedCount = splice.addedCount;
+        var refNode = oldChildren[oldIndex] && wrap(oldChildren[oldIndex]);
+        for (var j = 0; j < addedCount; j++) {
+          var newChildRenderNode = newChildren[newIndex++];
+          var newChildWrapper = newChildRenderNode.node;
+          insertBefore(nodeWrapper, newChildWrapper, refNode);
+
+          // Keep track of added so that we do not remove the node after it
+          // has been added.
+          added.set(newChildWrapper, true);
+
+          newChildRenderNode.sync(added);
+        }
+
+        lastIndex += addedCount;
+      }
+
+      for (var i = lastIndex; i < newChildren.length; i++) {
+        newChildren[i++].sync(added);
+      }
+    }
+  };
+
+  function ShadowRenderer(host) {
+    this.host = host;
+    this.dirty = false;
+    this.invalidateAttributes();
+    this.associateNode(host);
+  }
+
   ShadowRenderer.prototype = {
 
     // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#rendering-shadow-trees
-    render: function() {
+    render: function(opt_renderNode) {
       if (!this.dirty)
         return;
 
@@ -2702,14 +4119,18 @@
       this.treeComposition();
 
       var host = this.host;
-      var shadowDOM = host.shadowRoot;
+      var shadowRoot = host.shadowRoot;
 
-      this.removeAllChildNodes(this.host);
+      this.associateNode(host);
+      var topMostRenderer = !renderNode;
+      var renderNode = opt_renderNode || new RenderNode(host);
 
-      var shadowDOMChildNodes = getChildNodesSnapshot(shadowDOM);
-      shadowDOMChildNodes.forEach(function(node) {
-        this.renderNode(host, shadowDOM, node, false);
-      }, this);
+      for (var node = shadowRoot.firstChild; node; node = node.nextSibling) {
+        this.renderNode(shadowRoot, renderNode, node, false);
+      }
+
+      if (topMostRenderer)
+        renderNode.sync();
 
       this.dirty = false;
     },
@@ -2720,81 +4141,81 @@
         pendingDirtyRenderers.push(this);
         if (renderTimer)
           return;
-        renderTimer = window[request](renderAllPending, 0);
+        renderTimer = window[request](handleRequestAnimationFrame, 0);
       }
     },
 
-    renderNode: function(visualParent, tree, node, isNested) {
+    renderNode: function(shadowRoot, renderNode, node, isNested) {
       if (isShadowHost(node)) {
-        this.appendChild(visualParent, node);
+        renderNode = renderNode.append(node);
         var renderer = getRendererForHost(node);
         renderer.dirty = true;  // Need to rerender due to reprojection.
-        renderer.render();
+        renderer.render(renderNode);
       } else if (isInsertionPoint(node)) {
-        this.renderInsertionPoint(visualParent, tree, node, isNested);
+        this.renderInsertionPoint(shadowRoot, renderNode, node, isNested);
       } else if (isShadowInsertionPoint(node)) {
-        this.renderShadowInsertionPoint(visualParent, tree, node);
+        this.renderShadowInsertionPoint(shadowRoot, renderNode, node);
       } else {
-        this.renderAsAnyDomTree(visualParent, tree, node, isNested);
+        this.renderAsAnyDomTree(shadowRoot, renderNode, node, isNested);
       }
     },
 
-    renderAsAnyDomTree: function(visualParent, tree, node, isNested) {
-      this.appendChild(visualParent, node);
+    renderAsAnyDomTree: function(shadowRoot, renderNode, node, isNested) {
+      renderNode = renderNode.append(node);
 
       if (isShadowHost(node)) {
-        render(node);
+        var renderer = getRendererForHost(node);
+        renderNode.skip = !renderer.dirty;
+        renderer.render(renderNode);
       } else {
-        var parent = node;
-        var logicalChildNodes = getChildNodesSnapshot(parent);
-        // We associate the parent of a content/shadow with the renderer
-        // because we may need to remove stale childNodes.
-        if (shadowDOMRendererTable.get(parent))
-          this.removeAllChildNodes(parent);
-        logicalChildNodes.forEach(function(node) {
-          this.renderNode(parent, tree, node, isNested);
-        }, this);
+        for (var child = node.firstChild; child; child = child.nextSibling) {
+          this.renderNode(shadowRoot, renderNode, child, isNested);
+        }
       }
     },
 
-    renderInsertionPoint: function(visualParent, tree, insertionPoint, isNested) {
+    renderInsertionPoint: function(shadowRoot, renderNode, insertionPoint,
+                                   isNested) {
       var distributedChildNodes = getDistributedChildNodes(insertionPoint);
       if (distributedChildNodes.length) {
-        this.removeAllChildNodes(insertionPoint);
+        this.associateNode(insertionPoint);
 
-        distributedChildNodes.forEach(function(child) {
+        for (var i = 0; i < distributedChildNodes.length; i++) {
+          var child = distributedChildNodes[i];
           if (isInsertionPoint(child) && isNested)
-            this.renderInsertionPoint(visualParent, tree, child, isNested);
+            this.renderInsertionPoint(shadowRoot, renderNode, child, isNested);
           else
-            this.renderAsAnyDomTree(visualParent, tree, child, isNested);
-        }, this);
+            this.renderAsAnyDomTree(shadowRoot, renderNode, child, isNested);
+        }
       } else {
-        this.renderFallbackContent(visualParent, insertionPoint);
+        this.renderFallbackContent(shadowRoot, renderNode, insertionPoint);
       }
-      this.remove(insertionPoint);
+      this.associateNode(insertionPoint.parentNode);
     },
 
-    renderShadowInsertionPoint: function(visualParent, tree, shadowInsertionPoint) {
-      var nextOlderTree = tree.olderShadowRoot;
+    renderShadowInsertionPoint: function(shadowRoot, renderNode,
+                                         shadowInsertionPoint) {
+      var nextOlderTree = shadowRoot.olderShadowRoot;
       if (nextOlderTree) {
         assignToInsertionPoint(nextOlderTree, shadowInsertionPoint);
-        this.remove(shadowInsertionPoint);
-        var shadowDOMChildNodes = getChildNodesSnapshot(nextOlderTree);
-        shadowDOMChildNodes.forEach(function(node) {
-          this.renderNode(visualParent, nextOlderTree, node, true);
-        }, this);
+        this.associateNode(shadowInsertionPoint.parentNode);
+        for (var node = nextOlderTree.firstChild;
+             node;
+             node = node.nextSibling) {
+          this.renderNode(nextOlderTree, renderNode, node, true);
+        }
       } else {
-        this.renderFallbackContent(visualParent, shadowInsertionPoint);
+        this.renderFallbackContent(shadowRoot, renderNode,
+                                   shadowInsertionPoint);
       }
     },
 
-    renderFallbackContent: function (visualParent, fallbackHost) {
-      var logicalChildNodes = getChildNodesSnapshot(fallbackHost);
+    renderFallbackContent: function(shadowRoot, renderNode, fallbackHost) {
       this.associateNode(fallbackHost);
-      this.remove(fallbackHost);
-      logicalChildNodes.forEach(function(node) {
-        this.appendChild(visualParent, node);
-      }, this);
+      this.associateNode(fallbackHost.parentNode);
+      for (var node = fallbackHost.firstChild; node; node = node.nextSibling) {
+        this.renderAsAnyDomTree(shadowRoot, renderNode, node, false);
+      }
     },
 
     /**
@@ -2837,7 +4258,6 @@
 
     // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-distribution-algorithm
     distribute: function(tree, pool) {
-      var anyRemoved = false;
       var self = this;
 
       visit(tree, isActiveInsertionPoint,
@@ -2853,17 +4273,9 @@
               if (matchesCriteria(node, insertionPoint)) {  // 1.2.2
                 distributeChildToInsertionPoint(node, insertionPoint);  // 1.2.2.1
                 pool[i] = undefined;  // 1.2.2.2
-                anyRemoved = true;
               }
             }
           });
-
-      if (!anyRemoved)
-        return pool;
-
-      return pool.filter(function(item) {
-        return item !== undefined;
-      });
     },
 
     // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/shadow/index.html#dfn-tree-composition
@@ -2871,8 +4283,10 @@
       var shadowHost = this.host;
       var tree = shadowHost.shadowRoot;  // 1.
       var pool = [];  // 2.
-      var shadowHostChildNodes = getChildNodesSnapshot(shadowHost);
-      shadowHostChildNodes.forEach(function(child) {  // 3.
+
+      for (var child = shadowHost.firstChild;
+           child;
+           child = child.nextSibling) {  // 3.
         if (isInsertionPoint(child)) {  // 3.2.
           var reprojected = getDistributedChildNodes(child);  // 3.2.1.
           // if reprojected is undef... reset it?
@@ -2882,7 +4296,7 @@
         } else {
           pool.push(child); // 3.3.
         }
-      });
+      }
 
       var shadowInsertionPoint, point;
       while (tree) {  // 4.
@@ -2894,7 +4308,7 @@
         });
         point = shadowInsertionPoint;
 
-        pool = this.distribute(tree, pool);  // 4.2.
+        this.distribute(tree, pool);  // 4.2.
         if (point) {  // 4.3.
           var nextOlderTree = tree.olderShadowRoot;  // 4.3.1.
           if (!nextOlderTree) {
@@ -2910,23 +4324,6 @@
       }
     },
 
-    appendChild: function(parent, child) {
-      // this.associateNode(child);
-      this.associateNode(parent);
-      appendChild(parent, child);
-    },
-
-    remove: function(node) {
-      // this.associateNode(node);
-      this.associateNode(node.parentNode);
-      remove(node);
-    },
-
-    removeAllChildNodes: function(parent) {
-      this.associateNode(parent);
-      removeAllChildNodes(parent);
-    },
-
     associateNode: function(node) {
       shadowDOMRendererTable.set(node, this);
     }
@@ -2934,21 +4331,21 @@
 
   function isInsertionPoint(node) {
     // Should this include <shadow>?
-    return node.localName === 'content';
+    return node instanceof HTMLContentElement;
   }
 
   function isActiveInsertionPoint(node) {
     // <content> inside another <content> or <shadow> is considered inactive.
-    return node.localName === 'content';
+    return node instanceof HTMLContentElement;
   }
 
   function isShadowInsertionPoint(node) {
-    return node.localName === 'shadow';
+    return node instanceof HTMLShadowElement;
   }
 
   function isActiveShadowInsertionPoint(node) {
     // <shadow> inside another <content> or <shadow> is considered inactive.
-    return node.localName === 'shadow';
+    return node instanceof HTMLShadowElement;
   }
 
   function isShadowHost(shadowHost) {
@@ -3025,9 +4422,8 @@
 
   // Exposed for testing
   scope.visual = {
-    removeAllChildNodes: removeAllChildNodes,
-    appendChild: appendChild,
-    removeChild: removeChild
+    insertBefore: insertBefore,
+    remove: remove,
   };
 
 })(this.ShadowDOMPolyfill);
@@ -3109,7 +4505,7 @@
   var wrapEventTargetMethods = scope.wrapEventTargetMethods;
   var wrapNodeList = scope.wrapNodeList;
 
-  var implementationTable = new SideTable();
+  var implementationTable = new WeakMap();
 
   function Document(node) {
     Node.call(this, node);
@@ -3384,6 +4780,7 @@
   var unwrap = scope.unwrap;
   var unwrapIfNeeded = scope.unwrapIfNeeded;
   var wrap = scope.wrap;
+  var renderAllPending = scope.renderAllPending;
 
   var OriginalWindow = window.Window;
 
@@ -3394,6 +4791,7 @@
 
   var originalGetComputedStyle = window.getComputedStyle;
   OriginalWindow.prototype.getComputedStyle = function(el, pseudo) {
+    renderAllPending();
     return originalGetComputedStyle.call(this || window, unwrapIfNeeded(el),
                                          pseudo);
   };
@@ -3745,11 +5143,9 @@
         // Fix up class names for Firefox.
         // For some of them (like HTMLFormElement and HTMLInputElement),
         // the "constructor" property of the unwrapped nodes points at the
-        // wrapper.
-        // Note: it is safe to check for the GeneratedWrapper string because
-        // we know it is some kind of Shadow DOM wrapper object.
-        var ctor = obj.constructor;
-        if (ctor && ctor.name == 'GeneratedWrapper') {
+        // same constructor as the wrapper.
+        var ctor = obj.constructor
+        if (ctor === unwrapped.constructor) {
           var name = ctor._ShadowDOMPolyfill$cacheTag_;
           if (!name) {
             name = Object.prototype.toString.call(unwrapped);
diff --git a/pkg/shadow_dom/lib/shadow_dom.min.js b/pkg/shadow_dom/lib/shadow_dom.min.js
index 7d3ff1b..16bf09b 100644
--- a/pkg/shadow_dom/lib/shadow_dom.min.js
+++ b/pkg/shadow_dom/lib/shadow_dom.min.js
@@ -1,2 +1,2 @@
-if(!HTMLElement.prototype.createShadowRoot&&!HTMLElement.prototype.webkitCreateShadowRoot||window.__forceShadowDomPolyfill){!function(){Element.prototype.webkitCreateShadowRoot&&(Element.prototype.webkitCreateShadowRoot=function(){return window.ShadowDOMPolyfill.wrapIfNeeded(this).createShadowRoot()})}();var SideTable;"undefined"!=typeof WeakMap&&navigator.userAgent.indexOf("Firefox/")<0?SideTable=WeakMap:!function(){var a=Object.defineProperty,b=Date.now()%1e9;SideTable=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")},SideTable.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}}}();var ShadowDOMPolyfill={};!function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function d(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){switch(c){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":return}Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function e(a,b){for(var c=0;c<b.length;c++)if(b[c]in a)return b[c]}function f(a){var b=a.__proto__||Object.getPrototypeOf(a),c=A.get(b);if(c)return c;var d=f(b),e=o(d);return l(b,e,a),e}function g(a,b){j(a,b,!0)}function h(a,b){j(b,a,!1)}function i(a){return/^on[a-z]+$/.test(a)}function j(b,c,d){Object.getOwnPropertyNames(b).forEach(function(e){if(!(e in c)){D&&b.__lookupGetter__(e);var f;try{f=Object.getOwnPropertyDescriptor(b,e)}catch(g){f=E}var h,j;if(d&&"function"==typeof f.value)return c[e]=function(){return this.impl[e].apply(this.impl,arguments)},void 0;var k=i(e);h=k?a.getEventHandlerGetter(e):function(){return this.impl[e]},(f.writable||f.set)&&(j=k?a.getEventHandlerSetter(e):function(a){this.impl[e]=a}),Object.defineProperty(c,e,{get:h,set:j,configurable:f.configurable,enumerable:f.enumerable})}})}function k(a,b,c){var e=a.prototype;l(e,b,c),d(b,a)}function l(a,c,d){var e=c.prototype;b(void 0===A.get(a)),A.set(a,c),B.set(e,a),g(a,e),d&&h(e,d)}function m(a,b){return A.get(b.prototype)===a}function n(a){var b=Object.getPrototypeOf(a),c=f(b),d=o(c);return l(b,d,a),d}function o(a){function b(b){a.call(this,b)}return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b}function p(a){return a instanceof C.EventTarget||a instanceof C.Event||a instanceof C.Range||a instanceof C.DOMImplementation}function q(a){return a instanceof H||a instanceof G||a instanceof I||a instanceof J||a instanceof F}function r(a){if(null===a)return null;b(q(a));var c=z.get(a);return c||z.set(a,c=new(f(a))(a)),c}function s(a){return null===a?null:(b(p(a)),a.impl)}function t(a){return a&&p(a)?s(a):a}function u(a){return a&&!p(a)?r(a):a}function v(a,c){null!==c&&(b(q(a)),b(void 0===c||p(c)),z.set(a,c))}function w(a,b,c){Object.defineProperty(a.prototype,b,{get:c,configurable:!0,enumerable:!0})}function x(a,b){w(a,b,function(){return r(this.impl[b])})}function y(a,b){a.forEach(function(a){b.forEach(function(b){a.prototype[b]=function(){var a=u(this);return a[b].apply(a,arguments)}})})}var z=new SideTable,A=new SideTable,B=new SideTable,C=Object.create(null);Object.getOwnPropertyNames(window);var D=/Firefox/.test(navigator.userAgent),E={get:function(){},set:function(){},configurable:!0,enumerable:!0},F=DOMImplementation,G=Event,H=Node,I=Window,J=Range;a.assert=b,a.constructorTable=A,a.defineGetter=w,a.defineWrapGetter=x,a.forwardMethodsToWrapper=y,a.isWrapperFor=m,a.mixin=c,a.nativePrototypeTable=B,a.oneOf=e,a.registerObject=n,a.registerWrapper=k,a.rewrap=v,a.unwrap=s,a.unwrapIfNeeded=t,a.wrap=r,a.wrapIfNeeded=u,a.wrappers=C}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){return a instanceof N.ShadowRoot}function c(a){var b=a.localName;return"content"===b||"shadow"===b}function d(a){return!!a.shadowRoot}function e(a){var b;return a.parentNode||(b=a.defaultView)&&M(b)||null}function f(f,g,h){if(h.length)return h.shift();if(b(f))return j(f)||a.getHostForShadowRoot(f);var i=a.eventParentsTable.get(f);if(i){for(var k=1;k<i.length;k++)h[k-1]=i[k];return i[0]}if(g&&c(f)){var l=f.parentNode;if(l&&d(l))for(var m=a.getShadowTrees(l),n=j(g),k=0;k<m.length;k++)if(m[k].contains(n))return n}return e(f)}function g(a){for(var d=[],e=a,g=[],i=[];e;){var j=null;if(c(e)){j=h(d);var k=d[d.length-1]||e;d.push(k)}else d.length||d.push(e);var l=d[d.length-1];g.push({target:l,currentTarget:e}),b(e)&&d.pop(),e=f(e,j,i)}return g}function h(a){for(var b=a.length-1;b>=0;b--)if(!c(a[b]))return a[b];return null}function i(d,e){for(var g=[];d;){for(var i=[],j=e,l=void 0;j;){var n=null;if(i.length){if(c(j)&&(n=h(i),k(l))){var o=i[i.length-1];i.push(o)}}else i.push(j);if(m(j,d))return i[i.length-1];b(j)&&i.pop(),l=j,j=f(j,n,g)}d=b(d)?a.getHostForShadowRoot(d):d.parentNode}}function j(b){return a.insertionParentTable.get(b)}function k(a){return j(a)}function l(a){for(var b;b=a.parentNode;)a=b;return a}function m(a,b){return l(a)===l(b)}function n(b,c){if(b===c)return!0;if(b instanceof N.ShadowRoot){var d=a.getHostForShadowRoot(b);return n(l(d),c)}return!1}function o(a){switch(a){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function p(b){if(!P.get(b)){P.set(b,!0),o(b.type)||a.renderAllPending();var c=M(b.target),d=M(b);return q(d,c)}}function q(a,b){var c=g(b);return"load"===a.type&&2===c.length&&c[0].target instanceof N.Document&&c.shift(),X.set(a,c),r(a,c)&&s(a,c)&&t(a,c),T.set(a,w.NONE),R.set(a,null),a.defaultPrevented}function r(a,b){for(var c,d=b.length-1;d>0;d--){var e=b[d].target,f=b[d].currentTarget;if(e!==f&&(c=w.CAPTURING_PHASE,!u(b[d],a,c)))return!1}return!0}function s(a,b){var c=w.AT_TARGET;return u(b[0],a,c)}function t(a,b){for(var c,d=a.bubbles,e=1;e<b.length;e++){var f=b[e].target,g=b[e].currentTarget;if(f===g)c=w.AT_TARGET;else{if(!d||V.get(a))continue;c=w.BUBBLING_PHASE}if(!u(b[e],a,c))return}}function u(a,b,c){var d=a.target,e=a.currentTarget,f=O.get(e);if(!f)return!0;if("relatedTarget"in b){var g=L(b),h=M(g.relatedTarget),j=i(e,h);if(j===d)return!0;S.set(b,j)}T.set(b,c);var k=b.type,l=!1;Q.set(b,d),R.set(b,e);for(var m=0;m<f.length;m++){var n=f[m];if(n.removed)l=!0;else if(!(n.type!==k||!n.capture&&c===w.CAPTURING_PHASE||n.capture&&c===w.BUBBLING_PHASE))try{if("function"==typeof n.handler?n.handler.call(e,b):n.handler.handleEvent(b),V.get(b))return!1}catch(o){window.onerror?window.onerror(o.message):console.error(o)}}if(l){var p=f.slice();f.length=0;for(var m=0;m<p.length;m++)p[m].removed||f.push(p[m])}return!U.get(b)}function v(a,b,c){this.type=a,this.handler=b,this.capture=Boolean(c)}function w(a,b){return a instanceof Y?(this.impl=a,void 0):M(A(Y,"Event",a,b))}function x(a){return a&&a.relatedTarget?Object.create(a,{relatedTarget:{value:L(a.relatedTarget)}}):a}function y(a,b,c){var d=window[a],e=function(b,c){return b instanceof d?(this.impl=b,void 0):M(A(d,a,b,c))};return e.prototype=Object.create(b.prototype),c&&J(e.prototype,c),d&&(d.prototype["init"+a]?K(d,e,document.createEvent(a)):K(d,e,new d("temp"))),e}function z(a,b){return function(){arguments[b]=L(arguments[b]);var c=L(this);c[a].apply(c,arguments)}}function A(a,b,c,d){if(gb)return new a(c,x(d));var e=L(document.createEvent(b)),f=fb[b],g=[c];return Object.keys(f).forEach(function(a){var b=null!=d&&a in d?d[a]:f[a];"relatedTarget"===a&&(b=L(b)),g.push(b)}),e["init"+b].apply(e,g),e}function B(a){return"function"==typeof a?!0:a&&a.handleEvent}function C(a){this.impl=a}function D(b){return b instanceof N.ShadowRoot&&(b=a.getHostForShadowRoot(b)),L(b)}function E(a){I(a,jb)}function F(b,c,d,e){a.renderAllPending();for(var f=M(kb.call(c.impl,d,e)),h=g(f,this),i=0;i<h.length;i++){var j=h[i];if(j.currentTarget===b)return j.target}return null}function G(a){return function(){var b=W.get(this);return b&&b[a]&&b[a].value||null}}function H(a){var b=a.slice(2);return function(c){var d=W.get(this);d||(d=Object.create(null),W.set(this,d));var e=d[a];if(e&&this.removeEventListener(b,e.wrapped,!1),"function"==typeof c){var f=function(b){var d=c.call(this,b);d===!1?b.preventDefault():"onbeforeunload"===a&&"string"==typeof d&&(b.returnValue=d)};this.addEventListener(b,f,!1),d[a]={value:c,wrapped:f}}}}var I=a.forwardMethodsToWrapper,J=a.mixin,K=a.registerWrapper,L=a.unwrap,M=a.wrap,N=a.wrappers;new SideTable;var O=new SideTable,P=new SideTable,Q=new SideTable,R=new SideTable,S=new SideTable,T=new SideTable,U=new SideTable,V=new SideTable,W=new SideTable,X=new SideTable;v.prototype={equals:function(a){return this.handler===a.handler&&this.type===a.type&&this.capture===a.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var Y=window.Event;w.prototype={get target(){return Q.get(this)},get currentTarget(){return R.get(this)},get eventPhase(){return T.get(this)},get path(){var a=new N.NodeList,b=X.get(this);if(b){for(var c=0,d=b.length-1,e=l(R.get(this)),f=0;d>=f;f++){var g=b[f].currentTarget,h=l(g);n(e,h)&&(f!==d||g instanceof N.Node)&&(a[c++]=g)}a.length=c}return a},stopPropagation:function(){U.set(this,!0)},stopImmediatePropagation:function(){U.set(this,!0),V.set(this,!0)}},K(Y,w,document.createEvent("Event"));var Z=y("UIEvent",w),$=y("CustomEvent",w),_={get relatedTarget(){return S.get(this)||M(L(this).relatedTarget)}},ab=J({initMouseEvent:z("initMouseEvent",14)},_),bb=J({initFocusEvent:z("initFocusEvent",5)},_),cb=y("MouseEvent",Z,ab),db=y("FocusEvent",Z,bb),eb=y("MutationEvent",w,{initMutationEvent:z("initMutationEvent",3),get relatedNode(){return M(this.impl.relatedNode)}}),fb=Object.create(null),gb=function(){try{new window.MouseEvent("click")}catch(a){return!1}return!0}();if(!gb){var hb=function(a,b,c){if(c){var d=fb[c];b=J(J({},d),b)}fb[a]=b};hb("Event",{bubbles:!1,cancelable:!1}),hb("CustomEvent",{detail:null},"Event"),hb("UIEvent",{view:null,detail:0},"Event"),hb("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),hb("FocusEvent",{relatedTarget:null},"UIEvent")}var ib=window.EventTarget,jb=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(a){var b=a.prototype;jb.forEach(function(a){Object.defineProperty(b,a+"_",{value:b[a]})})}),C.prototype={addEventListener:function(a,b,c){if(B(b)){var d=new v(a,b,c),e=O.get(this);if(e){for(var f=0;f<e.length;f++)if(d.equals(e[f]))return}else e=[],O.set(this,e);e.push(d);var g=D(this);g.addEventListener_(a,p,!0)}},removeEventListener:function(a,b,c){c=Boolean(c);var d=O.get(this);if(d){for(var e=0,f=!1,g=0;g<d.length;g++)d[g].type===a&&d[g].capture===c&&(e++,d[g].handler===b&&(f=!0,d[g].remove()));if(f&&1===e){var h=D(this);h.removeEventListener_(a,p,!0)}}},dispatchEvent:function(b){a.renderAllPending();var c=D(this);return c.dispatchEvent_(L(b))}},ib&&K(ib,C);var kb=document.elementFromPoint;a.adjustRelatedTarget=i,a.elementFromPoint=F,a.getEventHandlerGetter=G,a.getEventHandlerSetter=H,a.wrapEventTargetMethods=E,a.wrappers.CustomEvent=$,a.wrappers.Event=w,a.wrappers.EventTarget=C,a.wrappers.FocusEvent=db,a.wrappers.MouseEvent=cb,a.wrappers.MutationEvent=eb,a.wrappers.UIEvent=Z}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,b){Object.defineProperty(a,b,{enumerable:!1})}function c(){this.length=0,b(this,"length")}function d(a){if(null==a)return a;for(var b=new c,d=0,e=a.length;e>d;d++)b[d]=f(a[d]);return b.length=e,b}function e(a,b){a.prototype[b]=function(){return d(this.impl[b].apply(this.impl,arguments))}}var f=a.wrap;c.prototype={item:function(a){return this[a]}},b(c.prototype,"item"),a.wrappers.NodeList=c,a.addWrapNodeListMethod=e,a.wrapNodeList=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){l(a instanceof i)}function c(a,b,c,d){if(a.nodeType!==i.DOCUMENT_FRAGMENT_NODE)return a.parentNode&&a.parentNode.removeChild(a),a.parentNode_=b,a.previousSibling_=c,a.nextSibling_=d,c&&(c.nextSibling_=a),d&&(d.previousSibling_=a),[a];for(var e,f=[];e=a.firstChild;)a.removeChild(e),f.push(e),e.parentNode_=b;for(var g=0;g<f.length;g++)f[g].previousSibling_=f[g-1]||c,f[g].nextSibling_=f[g+1]||d;return c&&(c.nextSibling_=f[0]),d&&(d.previousSibling_=f[f.length-1]),f}function d(a,b){var c=a.nodeType===i.DOCUMENT_NODE?a:a.ownerDocument;c!==b.ownerDocument&&c.adoptNode(b)}function e(b,c){if(c.length){var d=b.ownerDocument;if(d!==c[0].ownerDocument)for(var e=0;e<c.length;e++)a.adoptNodeNoRemove(c[e],d)}}function f(a,b){e(a,b);var c=b.length;if(1===c)return o(b[0]);for(var d=o(a.ownerDocument.createDocumentFragment()),f=0;c>f;f++)d.appendChild(o(b[f]));return d}function g(a){if(a.invalidateShadowRenderer()){for(var b=a.firstChild;b;){l(b.parentNode===a);var c=b.nextSibling,d=o(b),e=d.parentNode;e&&v.call(e,d),b.previousSibling_=b.nextSibling_=b.parentNode_=null,b=c}a.firstChild_=a.lastChild_=null}else for(var c,f=o(a),g=f.firstChild;g;)c=g.nextSibling,v.call(f,g),g=c}function h(a){var b=a.parentNode;return b&&b.invalidateShadowRenderer()}function i(a){l(a instanceof r),j.call(this,a),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0}var j=a.wrappers.EventTarget,k=a.wrappers.NodeList;a.defineWrapGetter;var l=a.assert,m=a.mixin,n=a.registerWrapper,o=a.unwrap,p=a.wrap,q=a.wrapIfNeeded,r=window.Node,s=r.prototype.appendChild,t=r.prototype.insertBefore,u=r.prototype.replaceChild,v=r.prototype.removeChild,w=r.prototype.compareDocumentPosition;i.prototype=Object.create(j.prototype),m(i.prototype,{appendChild:function(a){if(b(a),this.invalidateShadowRenderer()||h(a)){var e=this.lastChild,g=null,i=c(a,this,e,g);this.lastChild_=i[i.length-1],e||(this.firstChild_=i[0]),s.call(this.impl,f(this,i))}else d(this,a),s.call(this.impl,o(a));return a.nodeWasAdded_(),a},insertBefore:function(a,g){if(!g)return this.appendChild(a);if(b(a),b(g),l(g.parentNode===this),this.invalidateShadowRenderer()||h(a)){var i=g.previousSibling,j=g,k=c(a,this,i,j);this.firstChild===g&&(this.firstChild_=k[0]);var m=o(g),n=m.parentNode;n?t.call(n,f(this,k),m):e(this,k)}else d(this,a),t.call(this.impl,o(a),o(g));return a.nodeWasAdded_(),a},removeChild:function(a){if(b(a),a.parentNode!==this)throw new Error("NotFoundError");var c=o(a);if(this.invalidateShadowRenderer()){var d=this.firstChild,e=this.lastChild,f=a.nextSibling,g=a.previousSibling,h=c.parentNode;h&&v.call(h,c),d===a&&(this.firstChild_=f),e===a&&(this.lastChild_=g),g&&(g.nextSibling_=f),f&&(f.previousSibling_=g),a.previousSibling_=a.nextSibling_=a.parentNode_=void 0}else v.call(this.impl,c);return a},replaceChild:function(a,e){if(b(a),b(e),e.parentNode!==this)throw new Error("NotFoundError");var g=o(e);if(this.invalidateShadowRenderer()||h(a)){var i=e.previousSibling,j=e.nextSibling;j===a&&(j=a.nextSibling);var k=c(a,this,i,j);this.firstChild===e&&(this.firstChild_=k[0]),this.lastChild===e&&(this.lastChild_=k[k.length-1]),e.previousSibling_=e.nextSibling_=e.parentNode_=void 0,g.parentNode&&u.call(g.parentNode,f(this,k),g)}else d(this,a),u.call(this.impl,o(a),g);return a.nodeWasAdded_(),e},nodeWasAdded_:function(){},hasChildNodes:function(){return null===this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:p(this.impl.parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:p(this.impl.firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:p(this.impl.lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:p(this.impl.nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:p(this.impl.previousSibling)},get parentElement(){for(var a=this.parentNode;a&&a.nodeType!==i.ELEMENT_NODE;)a=a.parentNode;return a},get textContent(){for(var a="",b=this.firstChild;b;b=b.nextSibling)a+=b.textContent;return a},set textContent(a){if(this.invalidateShadowRenderer()){if(g(this),""!==a){var b=this.impl.ownerDocument.createTextNode(a);this.appendChild(b)}}else this.impl.textContent=a},get childNodes(){for(var a=new k,b=0,c=this.firstChild;c;c=c.nextSibling)a[b++]=c;return a.length=b,a},cloneNode:function(a){if(!this.invalidateShadowRenderer())return p(this.impl.cloneNode(a));var b=p(this.impl.cloneNode(!1));if(a)for(var c=this.firstChild;c;c=c.nextSibling)b.appendChild(c.cloneNode(!0));return b},contains:function(a){if(!a)return!1;if(a=q(a),a===this)return!0;var b=a.parentNode;return b?this.contains(b):!1},compareDocumentPosition:function(a){return w.call(this.impl,o(a))},get ownerDocument(){return a.renderAllPending(),p(this.impl.ownerDocument)}}),n(r,i,document.createDocumentFragment()),delete i.prototype.querySelector,delete i.prototype.querySelectorAll,i.prototype=m(Object.create(j.prototype),i.prototype),a.wrappers.Node=i}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,c){for(var d,e=a.firstElementChild;e;){if(e.matches(c))return e;if(d=b(e,c))return d;e=e.nextElementSibling}return null}function c(a,b,d){for(var e=a.firstElementChild;e;)e.matches(b)&&(d[d.length++]=e),c(e,b,d),e=e.nextElementSibling;return d}var d={querySelector:function(a){return b(this,a)},querySelectorAll:function(a){return c(this,a,new NodeList)}},e={getElementsByTagName:function(a){return this.querySelectorAll(a)},getElementsByClassName:function(a){return this.querySelectorAll("."+a)},getElementsByTagNameNS:function(a,b){if("*"===a)return this.getElementsByTagName(b);for(var c=new NodeList,d=this.getElementsByTagName(b),e=0,f=0;e<d.length;e++)d[e].namespaceURI===a&&(c[f++]=d[e]);return c.length=f,c}};a.GetElementsByInterface=e,a.SelectorsInterface=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}function c(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}var d=a.wrappers.NodeList,e={get firstElementChild(){return b(this.firstChild)},get lastElementChild(){return c(this.lastChild)},get childElementCount(){for(var a=0,b=this.firstElementChild;b;b=b.nextElementSibling)a++;return a},get children(){for(var a=new d,b=0,c=this.firstElementChild;c;c=c.nextElementSibling)a[b++]=c;return a.length=b,a}},f={get nextElementSibling(){return b(this.nextSibling)},get previousElementSibling(){return c(this.previousSibling)}};a.ChildNodeInterface=f,a.ParentNodeInterface=e}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}var c=a.ChildNodeInterface,d=a.wrappers.Node,e=a.mixin,f=a.registerWrapper,g=window.CharacterData;b.prototype=Object.create(d.prototype),e(b.prototype,{get textContent(){return this.data},set textContent(a){this.data=a}}),e(b.prototype,c),f(g,b,document.createTextNode("")),a.wrappers.CharacterData=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b,c){var d=b.parentNode;if(d&&d.shadowRoot){var e=a.getRendererForHost(d);e.dependsOnAttribute(c)&&e.invalidate()}}function c(a){g.call(this,a)}function d(a,c,d){var e=d||c;Object.defineProperty(a,c,{get:function(){return this.impl[c]},set:function(a){this.impl[c]=a,b(this,e)},configurable:!0,enumerable:!0})}var e=a.ChildNodeInterface,f=a.GetElementsByInterface,g=a.wrappers.Node,h=a.ParentNodeInterface,i=a.SelectorsInterface;a.addWrapNodeListMethod;var j=a.mixin,k=a.oneOf,l=a.registerWrapper,m=a.wrappers,n=new SideTable,o=window.Element,p=k(o.prototype,["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"]),q=o.prototype[p];c.prototype=Object.create(g.prototype),j(c.prototype,{createShadowRoot:function(){var b=new m.ShadowRoot(this);n.set(this,b);var c=a.getRendererForHost(this);return c.invalidate(),b},get shadowRoot(){return n.get(this)||null},setAttribute:function(a,c){this.impl.setAttribute(a,c),b(this,a)},removeAttribute:function(a){this.impl.removeAttribute(a),b(this,a)},matches:function(a){return q.call(this.impl,a)}}),c.prototype[p]=function(a){return this.matches(a)},o.prototype.webkitCreateShadowRoot&&(c.prototype.webkitCreateShadowRoot=c.prototype.createShadowRoot),d(c.prototype,"id"),d(c.prototype,"className","class"),j(c.prototype,e),j(c.prototype,f),j(c.prototype,h),j(c.prototype,i),l(o,c),a.matchesName=p,a.wrappers.Element=c}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a){case"&":return"&amp;";case"<":return"&lt;";case'"':return"&quot;"}}function c(a){return a.replace(p,b)}function d(a){switch(a.nodeType){case Node.ELEMENT_NODE:for(var b,d=a.tagName.toLowerCase(),f="<"+d,g=a.attributes,h=0;b=g[h];h++)f+=" "+b.name+'="'+c(b.value)+'"';return f+=">",q[d]?f:f+e(a)+"</"+d+">";case Node.TEXT_NODE:return c(a.nodeValue);case Node.COMMENT_NODE:return"<!--"+c(a.nodeValue)+"-->";default:throw console.error(a),new Error("not implemented")}}function e(a){for(var b="",c=a.firstChild;c;c=c.nextSibling)b+=d(c);return b}function f(a,b,c){var d=c||"div";a.textContent="";var e=n(a.ownerDocument.createElement(d));e.innerHTML=b;for(var f;f=e.firstChild;)a.appendChild(o(f))}function g(a){j.call(this,a)}function h(b){k(g,b,function(){return a.renderAllPending(),this.impl[b]})}function i(b){Object.defineProperty(g.prototype,b,{value:function(){return a.renderAllPending(),this.impl[b].apply(this.impl,arguments)},configurable:!0,enumerable:!0})}var j=a.wrappers.Element,k=a.defineGetter,l=a.mixin,m=a.registerWrapper,n=a.unwrap,o=a.wrap,p=/&|<|"/g,q={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},r=window.HTMLElement;g.prototype=Object.create(j.prototype),l(g.prototype,{get innerHTML(){return e(this)},set innerHTML(a){this.invalidateShadowRenderer()?f(this,a,this.tagName):this.impl.innerHTML=a},get outerHTML(){return d(this)},set outerHTML(a){var b=this.parentNode;b&&(b.invalidateShadowRenderer(),this.impl.outerHTML=a)}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollLeft","scrollTop","scrollWidth"].forEach(h),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(i),m(r,g,document.createElement("b")),a.wrappers.HTMLElement=g,a.getInnerHTML=e,a.setInnerHTML=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLContentElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get select(){return this.getAttribute("select")},set select(a){this.setAttribute("select",a)},setAttribute:function(a,b){c.prototype.setAttribute.call(this,a,b),"select"===String(a).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),f&&e(f,b),a.wrappers.HTMLContentElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLShadowElement;b.prototype=Object.create(c.prototype),d(b.prototype,{}),f&&e(f,b),a.wrappers.HTMLShadowElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){if(!a.defaultView)return a;var b=m.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);m.set(a,b)}return b}function c(a){for(var c,d=b(a.ownerDocument),e=j(d.createDocumentFragment());c=a.firstChild;)e.appendChild(c);return e}function d(a){if(e.call(this,a),!n){var b=c(a);l.set(this,k(b))}}var e=a.wrappers.HTMLElement,f=a.getInnerHTML,g=a.mixin,h=a.registerWrapper,i=a.setInnerHTML,j=a.unwrap,k=a.wrap,l=new SideTable,m=new SideTable,n=window.HTMLTemplateElement;d.prototype=Object.create(e.prototype),g(d.prototype,{get content(){return n?k(this.impl.content):l.get(this)},get innerHTML(){return f(this.content)},set innerHTML(a){i(this.content,a)}}),n&&h(n,d),a.wrappers.HTMLTemplateElement=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a.localName){case"content":return new c(a);case"shadow":return new e(a);case"template":return new f(a)}d.call(this,a)}var c=a.wrappers.HTMLContentElement,d=a.wrappers.HTMLElement,e=a.wrappers.HTMLShadowElement,f=a.wrappers.HTMLTemplateElement;a.mixin;var g=a.registerWrapper,h=window.HTMLUnknownElement;b.prototype=Object.create(d.prototype),g(h,b),a.wrappers.HTMLUnknownElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";var b=a.GetElementsByInterface,c=a.ParentNodeInterface,d=a.SelectorsInterface,e=a.mixin,f=a.registerObject,g=f(document.createDocumentFragment());e(g.prototype,c),e(g.prototype,d),e(g.prototype,b);var h=f(document.createTextNode("")),i=f(document.createComment(""));a.wrappers.Comment=i,a.wrappers.DocumentFragment=g,a.wrappers.Text=h}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=i(a.impl.ownerDocument.createDocumentFragment());c.call(this,b),g(b,this);var d=a.shadowRoot;k.set(this,d),j.set(this,a)}var c=a.wrappers.DocumentFragment,d=a.elementFromPoint,e=a.getInnerHTML,f=a.mixin,g=a.rewrap,h=a.setInnerHTML,i=a.unwrap,j=new SideTable,k=new SideTable;b.prototype=Object.create(c.prototype),f(b.prototype,{get innerHTML(){return e(this)},set innerHTML(a){h(this,a),this.invalidateShadowRenderer()},get olderShadowRoot(){return k.get(this)||null},invalidateShadowRenderer:function(){return j.get(this).invalidateShadowRenderer()},elementFromPoint:function(a,b){return d(this,this.ownerDocument,a,b)},getElementById:function(a){return this.querySelector("#"+a)}}),a.wrappers.ShadowRoot=b,a.getHostForShadowRoot=function(a){return j.get(a)}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){a.previousSibling_=a.previousSibling,a.nextSibling_=a.nextSibling,a.parentNode_=a.parentNode}function c(a){a.firstChild_=a.firstChild,a.lastChild_=a.lastChild}function d(a){F(a instanceof D);for(var d=a.firstChild;d;d=d.nextSibling)b(d);c(a)}function e(a){var b=J(a);d(a),b.firstChild&&(b.textContent="")}function f(a,c){var e=J(a),f=J(c);f.nodeType===D.DOCUMENT_FRAGMENT_NODE?d(c):(h(c),b(c)),a.lastChild_=a.lastChild,a.lastChild===a.firstChild&&(a.firstChild_=a.firstChild);var g=K(e.lastChild);g&&(g.nextSibling_=g.nextSibling),e.appendChild(f)}function g(a,c){var d=J(a),e=J(c);b(c),c.previousSibling&&(c.previousSibling.nextSibling_=c),c.nextSibling&&(c.nextSibling.previousSibling_=c),a.lastChild===c&&(a.lastChild_=c),a.firstChild===c&&(a.firstChild_=c),d.removeChild(e)}function h(a){var b=J(a),c=b.parentNode;c&&g(K(c),a)}function i(a,b){k(b).push(a),z(a,b);var c=M.get(a);c||M.set(a,c=[]),c.push(b)}function j(a){L.set(a,[])}function k(a){return L.get(a)}function l(a){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}function m(a,b,c){for(var d=l(a),e=0;e<d.length;e++){var f=d[e];if(b(f)){if(c(f)===!1)return}else m(f,b,c)}}function n(a,b){var c=b.getAttribute("select");if(!c)return!0;if(c=c.trim(),!c)return!0;if(a.nodeType!==D.ELEMENT_NODE)return!1;if(!Q.test(c))return!1;if(":"===c[0]&&!R.test(c))return!1;try{return a.matches(c)}catch(d){return!1}}function o(){H=null,T.forEach(function(a){a.render()}),T=[]}function p(a){this.host=a,this.dirty=!1,this.invalidateAttributes(),this.associateNode(a)}function q(a){var b=O.get(a);return b||(b=new p(a),O.set(a,b)),b}function r(a){for(;a;a=a.parentNode)if(a instanceof E)return a;return null}function s(a){return q(G(a))}function t(a){return"content"===a.localName}function u(a){return"content"===a.localName}function v(a){return"shadow"===a.localName}function w(a){return"shadow"===a.localName}function x(a){return a.shadowRoot}function y(a){for(var b=[],c=a.shadowRoot;c;c=c.olderShadowRoot)b.push(c);return b}function z(a,b){N.set(a,b)}function A(a){new p(a).render()}var B=a.wrappers.HTMLContentElement,C=a.wrappers.HTMLShadowElement,D=a.wrappers.Node,E=a.wrappers.ShadowRoot,F=a.assert,G=a.getHostForShadowRoot;a.mixin;var H,I=a.oneOf,J=a.unwrap,K=a.wrap,L=new SideTable,M=new SideTable,N=new SideTable,O=new SideTable,P=new SideTable,Q=/^[*.:#[a-zA-Z_|]/,R=new RegExp("^:("+["link","visited","target","enabled","disabled","checked","indeterminate","nth-child","nth-last-child","nth-of-type","nth-last-of-type","first-child","last-child","first-of-type","last-of-type","only-of-type"].join("|")+")"),S=I(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),T=[];p.prototype={render:function(){if(this.dirty){this.invalidateAttributes(),this.treeComposition();var a=this.host,b=a.shadowRoot;this.removeAllChildNodes(this.host);var c=l(b);c.forEach(function(c){this.renderNode(a,b,c,!1)},this),this.dirty=!1}},invalidate:function(){if(!this.dirty){if(this.dirty=!0,T.push(this),H)return;H=window[S](o,0)}},renderNode:function(a,b,c,d){if(x(c)){this.appendChild(a,c);var e=q(c);e.dirty=!0,e.render()}else t(c)?this.renderInsertionPoint(a,b,c,d):v(c)?this.renderShadowInsertionPoint(a,b,c):this.renderAsAnyDomTree(a,b,c,d)},renderAsAnyDomTree:function(a,b,c,d){if(this.appendChild(a,c),x(c))A(c);else{var e=c,f=l(e);P.get(e)&&this.removeAllChildNodes(e),f.forEach(function(a){this.renderNode(e,b,a,d)},this)}},renderInsertionPoint:function(a,b,c,d){var e=k(c);e.length?(this.removeAllChildNodes(c),e.forEach(function(c){t(c)&&d?this.renderInsertionPoint(a,b,c,d):this.renderAsAnyDomTree(a,b,c,d)},this)):this.renderFallbackContent(a,c),this.remove(c)},renderShadowInsertionPoint:function(a,b,c){var d=b.olderShadowRoot;if(d){z(d,c),this.remove(c);var e=l(d);e.forEach(function(b){this.renderNode(a,d,b,!0)},this)}else this.renderFallbackContent(a,c)},renderFallbackContent:function(a,b){var c=l(b);this.associateNode(b),this.remove(b),c.forEach(function(b){this.appendChild(a,b)},this)},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(a){if(a){var b=this.attributes;/\.\w+/.test(a)&&(b["class"]=!0),/#\w+/.test(a)&&(b.id=!0),a.replace(/\[\s*([^\s=\|~\]]+)/g,function(a,c){b[c]=!0})}},dependsOnAttribute:function(a){return this.attributes[a]},distribute:function(a,b){var c=!1,d=this;return m(a,u,function(a){j(a),d.updateDependentAttributes(a.getAttribute("select"));for(var e=0;e<b.length;e++){var f=b[e];void 0!==f&&n(f,a)&&(i(f,a),b[e]=void 0,c=!0)}}),c?b.filter(function(a){return void 0!==a}):b},treeComposition:function(){var a=this.host,b=a.shadowRoot,c=[],d=l(a);d.forEach(function(a){if(t(a)){var b=k(a);b&&b.length||(b=l(a)),c.push.apply(c,b)}else c.push(a)});for(var e,f;b;){if(e=void 0,m(b,w,function(a){return e=a,!1}),f=e,c=this.distribute(b,c),f){var g=b.olderShadowRoot;if(g){b=g,z(b,f);continue}break}break}},appendChild:function(a,b){this.associateNode(a),f(a,b)},remove:function(a){this.associateNode(a.parentNode),h(a)},removeAllChildNodes:function(a){this.associateNode(a),e(a)},associateNode:function(a){P.set(a,this)}},D.prototype.invalidateShadowRenderer=function(){var a=P.get(this);return a?(a.invalidate(),!0):!1},B.prototype.getDistributedNodes=function(){var a=P.get(this);return a&&a.render(),k(this)},C.prototype.nodeWasAdded_=B.prototype.nodeWasAdded_=function(){this.invalidateShadowRenderer();var a,b=r(this);b&&(a=s(b)),P.set(this,a),a&&a.invalidate()},a.eventParentsTable=M,a.getRendererForHost=q,a.getShadowTrees=y,a.insertionParentTable=N,a.renderAllPending=o,a.visual={removeAllChildNodes:e,appendChild:f,removeChild:g}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b){if(window[b]){d(!a.wrappers[b]);var i=function(a){c.call(this,a)};i.prototype=Object.create(c.prototype),e(i.prototype,{get form(){return h(g(this).form)}}),f(window[b],i,document.createElement(b.slice(4,-7))),a.wrappers[b]=i}}var c=a.wrappers.HTMLElement,d=a.assert,e=a.mixin,f=a.registerWrapper,g=a.unwrap,h=a.wrap,i=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOptionElement","HTMLOutputElement","HTMLSelectElement","HTMLTextAreaElement"];i.forEach(b)}(this.ShadowDOMPolyfill),function(a){"use strict";
-function b(a){k.call(this,a)}function c(a){var c=document[a];b.prototype[a]=function(){return v(c.apply(this.impl,arguments))}}function d(a,b){y.call(b.impl,u(a)),e(a,b)}function e(a,b){a.shadowRoot&&b.adoptNode(a.shadowRoot),a instanceof n&&f(a,b);for(var c=a.firstChild;c;c=c.nextSibling)e(c,b)}function f(a,b){var c=a.olderShadowRoot;c&&b.adoptNode(c)}function g(a){this.impl=a}function h(a,b){var c=document.implementation[b];a.prototype[b]=function(){return v(c.apply(this.impl,arguments))}}function i(a,b){var c=document.implementation[b];a.prototype[b]=function(){return c.apply(this.impl,arguments)}}var j=a.GetElementsByInterface,k=a.wrappers.Node,l=a.ParentNodeInterface,m=a.SelectorsInterface,n=a.wrappers.ShadowRoot,o=a.defineWrapGetter,p=a.elementFromPoint,q=a.forwardMethodsToWrapper,r=a.matchesName,s=a.mixin,t=a.registerWrapper,u=a.unwrap,v=a.wrap,w=a.wrapEventTargetMethods;a.wrapNodeList;var x=new SideTable;b.prototype=Object.create(k.prototype),o(b,"documentElement"),o(b,"body"),o(b,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(c);var y=document.adoptNode;if(s(b.prototype,{adoptNode:function(a){return a.parentNode&&a.parentNode.removeChild(a),d(a,this),a},elementFromPoint:function(a,b){return p(this,this,a,b)}}),document.register){var z=document.register;b.prototype.register=function(b,c){function d(a){return a?(this.impl=a,void 0):document.createElement(b)}var e=c.prototype;if(a.nativePrototypeTable.get(e))throw new Error("NotSupportedError");for(var f,g=Object.getPrototypeOf(e),h=[];g&&!(f=a.nativePrototypeTable.get(g));)h.push(g),g=Object.getPrototypeOf(g);if(!f)throw new Error("NotSupportedError");for(var i=Object.create(f),j=h.length-1;j>=0;j--)i=Object.create(i);return["createdCallback","enteredDocumentCallback","leftDocumentCallback","attributeChangedCallback"].forEach(function(a){var b=e[a];b&&(i[a]=function(){b.apply(v(this),arguments)})}),z.call(u(this),b,{prototype:i}),d.prototype=e,d.prototype.constructor=d,a.constructorTable.set(i,d),a.nativePrototypeTable.set(e,i),d},q([window.HTMLDocument||window.Document],["register"])}q([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild",r]),q([window.HTMLDocument||window.Document],["adoptNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById"]),s(b.prototype,j),s(b.prototype,l),s(b.prototype,m),s(b.prototype,{get implementation(){var a=x.get(this);return a?a:(a=new g(u(this).implementation),x.set(this,a),a)}}),t(window.Document,b,document.implementation.createHTMLDocument("")),window.HTMLDocument&&t(window.HTMLDocument,b),w([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),h(g,"createDocumentType"),h(g,"createDocument"),h(g,"createHTMLDocument"),i(g,"hasFeature"),t(window.DOMImplementation,g),q([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),a.adoptNodeNoRemove=d,a.wrappers.DOMImplementation=g,a.wrappers.Document=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.mixin,e=a.registerWrapper,f=a.unwrap,g=a.unwrapIfNeeded,h=a.wrap,i=window.Window;b.prototype=Object.create(c.prototype);var j=window.getComputedStyle;i.prototype.getComputedStyle=function(a,b){return j.call(this||window,g(a),b)},["addEventListener","removeEventListener","dispatchEvent"].forEach(function(a){i.prototype[a]=function(){var b=h(this||window);return b[a].apply(b,arguments)}}),d(b.prototype,{getComputedStyle:function(a,b){return j.call(f(this),g(a),b)}}),e(i,b),a.wrappers.Window=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}function c(a){return new b(a)}function d(a){return a.map(c)}function e(a){var b=this;this.impl=new k(function(c){a.call(b,d(c),b)})}var f=a.defineGetter,g=a.defineWrapGetter,h=a.registerWrapper,i=a.unwrapIfNeeded,j=a.wrapNodeList;a.wrappers;var k=window.MutationObserver||window.WebKitMutationObserver;if(k){var l=window.MutationRecord;b.prototype={get addedNodes(){return j(this.impl.addedNodes)},get removedNodes(){return j(this.impl.removedNodes)}},["target","previousSibling","nextSibling"].forEach(function(a){g(b,a)}),["type","attributeName","attributeNamespace","oldValue"].forEach(function(a){f(b,a,function(){return this.impl[a]})}),l&&h(l,b),window.Node,e.prototype={observe:function(a,b){this.impl.observe(i(a),b)},disconnect:function(){this.impl.disconnect()},takeRecords:function(){return d(this.impl.takeRecords())}},a.wrappers.MutationObserver=e,a.wrappers.MutationRecord=b}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.registerWrapper,d=a.unwrap,e=a.unwrapIfNeeded,f=a.wrap,g=window.Range;b.prototype={get startContainer(){return f(this.impl.startContainer)},get endContainer(){return f(this.impl.endContainer)},get commonAncestorContainer(){return f(this.impl.commonAncestorContainer)},setStart:function(a,b){this.impl.setStart(e(a),b)},setEnd:function(a,b){this.impl.setEnd(e(a),b)},setStartBefore:function(a){this.impl.setStartBefore(e(a))},setStartAfter:function(a){this.impl.setStartAfter(e(a))},setEndBefore:function(a){this.impl.setEndBefore(e(a))},setEndAfter:function(a){this.impl.setEndAfter(e(a))},selectNode:function(a){this.impl.selectNode(e(a))},selectNodeContents:function(a){this.impl.selectNodeContents(e(a))},compareBoundaryPoints:function(a,b){return this.impl.compareBoundaryPoints(a,d(b))},extractContents:function(){return f(this.impl.extractContents())},cloneContents:function(){return f(this.impl.cloneContents())},insertNode:function(a){this.impl.insertNode(e(a))},surroundContents:function(a){this.impl.surroundContents(e(a))},cloneRange:function(){return f(this.impl.cloneRange())},isPointInRange:function(a,b){return this.impl.isPointInRange(e(a),b)},comparePoint:function(a,b){return this.impl.comparePoint(e(a),b)},intersectsNode:function(a){return this.impl.intersectsNode(e(a))}},g.prototype.createContextualFragment&&(b.prototype.createContextualFragment=function(a){return f(this.impl.createContextualFragment(a))}),c(window.Range,b),a.wrappers.Range=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=c[a],d=window[b];if(d){var e=document.createElement(a),f=e.constructor;window[b]=f}}a.isWrapperFor;var c={a:"HTMLAnchorElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",br:"HTMLBRElement",base:"HTMLBaseElement",body:"HTMLBodyElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",dl:"HTMLDListElement",datalist:"HTMLDataListElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",hr:"HTMLHRElement",head:"HTMLHeadElement",h1:"HTMLHeadingElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",input:"HTMLInputElement",li:"HTMLLIElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",link:"HTMLLinkElement",map:"HTMLMapElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",del:"HTMLModElement",ol:"HTMLOListElement",object:"HTMLObjectElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",table:"HTMLTableElement",tr:"HTMLTableRowElement",thead:"HTMLTableSectionElement",tbody:"HTMLTableSectionElement",textarea:"HTMLTextAreaElement",title:"HTMLTitleElement",ul:"HTMLUListElement",video:"HTMLVideoElement"};Object.keys(c).forEach(b),Object.getOwnPropertyNames(a.wrappers).forEach(function(b){window[b]=a.wrappers[b]}),a.knownElements=c}(this.ShadowDOMPolyfill),function(){var a=window.ShadowDOMPolyfill;a.wrap,Object.defineProperties(HTMLElement.prototype,{webkitShadowRoot:{get:function(){return this.shadowRoot}}}),HTMLElement.prototype.webkitCreateShadowRoot=HTMLElement.prototype.createShadowRoot,window.dartExperimentalFixupGetTag=function(b){function c(a){if(a instanceof d)return"NodeList";if(a instanceof e)return"ShadowRoot";if(a instanceof MutationRecord)return"MutationRecord";if(a instanceof MutationObserver)return"MutationObserver";var c=f(a);if(a!==c){var g=a.constructor;if(g&&"GeneratedWrapper"==g.name){var h=g._ShadowDOMPolyfill$cacheTag_;return h||(h=Object.prototype.toString.call(c),h=h.substring(8,h.length-1),g._ShadowDOMPolyfill$cacheTag_=h),h}a=c}return b(a)}var d=a.wrappers.NodeList,e=a.wrappers.ShadowRoot,f=a.unwrapIfNeeded;return c}}();var Platform={};!function(a){function b(a,b){var c="";return Array.prototype.forEach.call(a,function(a){c+=a.textContent+"\n\n"}),b||(c=c.replace(m,"")),c}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}function e(a){a&&f().appendChild(document.createTextNode(a))}function f(){return g||(g=document.createElement("style"),g.setAttribute("ShadowCSSShim","")),g}var g,h={strictStyling:!1,registry:{},shimStyling:function(a,b,c){if(a){var d=this.registerDefinition(a,b,c);this.strictStyling&&this.applyScopeToContent(a,b),this.shimPolyfillDirectives(d.rootStyles,b),this.applyShimming(d.scopeStyles,b)}},shimShadowDOMStyling:function(a,b){this.shimPolyfillDirectives(a,b),this.applyShimming(a,b)},registerDefinition:function(a,b,c){var d=this.registry[b]={root:a,name:b,extendsName:c},e=a.querySelectorAll("style");e=e?Array.prototype.slice.call(e,0):[],d.rootStyles=e,d.scopeStyles=d.rootStyles;var f=this.registry[d.extendsName];return f&&(d.scopeStyles=d.scopeStyles.concat(f.scopeStyles)),d},applyScopeToContent:function(a,b){a&&(Array.prototype.forEach.call(a.querySelectorAll("*"),function(a){a.setAttribute(b,"")}),Array.prototype.forEach.call(a.querySelectorAll("template"),function(a){this.applyScopeToContent(a.content,b)},this))},shimPolyfillDirectives:function(a,b){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.convertPolyfillDirectives(a.textContent,b)},this)},convertPolyfillDirectives:function(a,b){for(var c,d,e="",f=0;c=n.exec(a);)e+=a.substring(f,c.index),d=c[1].slice(0,-2).replace(q,b),e+=this.scopeSelector(d,b)+"{",f=n.lastIndex;return e+=a.substring(f,a.length)},applyShimming:function(a,b){var c=this.shimAtHost(a,b);c+=this.shimScoping(a,b),e(c)},shimAtHost:function(a,b){return a?this.convertAtHostStyles(a,b):void 0},convertAtHostStyles:function(a,e){for(var f,g=b(a),h="",j=0;f=i.exec(g);)h+=g.substring(j,f.index),h+=this.scopeHostCss(f[1],e),j=i.lastIndex;h+=g.substring(j,g.length);var k=new RegExp("^"+e+p,"m"),g=d(this.findAtHostRules(c(h),k));return g},scopeHostCss:function(a,b){for(var c,d="";c=j.exec(a);)d+=this.scopeHostSelector(c[1],b)+" "+c[2]+"\n	";return d},scopeHostSelector:function(a,b){var c=[],d=a.split(","),e="[is="+b+"]";return d.forEach(function(a){a=a.trim(),a.match(k)?a=a.replace(k,b+"$1$3, "+e+"$1$3"):a.match(l)&&(a=b+a+", "+e+a),c.push(a)},this),c.join(", ")},findAtHostRules:function(a,b){return Array.prototype.filter.call(a,this.isHostRule.bind(this,b))},isHostRule:function(a,b){return b.selectorText&&b.selectorText.match(a)||b.cssRules&&this.findAtHostRules(b.cssRules,a).length||b.type==CSSRule.WEBKIT_KEYFRAMES_RULE},shimScoping:function(a,b){return a?this.convertScopedStyles(a,b):void 0},convertScopedStyles:function(a,d){Array.prototype.forEach.call(a,function(a){a.parentNode&&a.parentNode.removeChild(a)});var e=b(a).replace(i,"");e=this.convertPseudos(e);var f=c(e);return e=this.scopeRules(f,d)},convertPseudos:function(a){return a.replace(o," [pseudo=$1]")},scopeRules:function(a,b){var c="";return Array.prototype.forEach.call(a,function(a){a.selectorText&&a.style&&a.style.cssText?(c+=this.scopeSelector(a.selectorText,b,this.strictStyling)+" {\n	",c+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(c+="@media "+a.media.mediaText+" {\n",c+=this.scopeRules(a.cssRules,b),c+="\n}\n\n"):a.cssText&&(c+=a.cssText+"\n\n")},this),c},scopeSelector:function(a,b,c){var d=[],e=a.split(",");return e.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b)&&(a=c?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b)),d.push(a)},this),d.join(", ")},selectorNeedsScoping:function(a,b){var c="("+b+"|\\[is="+b+"\\])",d=new RegExp("^"+c+p,"m");return!a.match(d)},applySimpleSelectorScope:function(a,b){return b+" "+a+", "+"[is="+b+"] "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim();return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},propertiesFromRule:function(a){var b=a.style.cssText;return a.style.content&&!a.style.content.match(/['"]+/)&&(b="content: '"+a.style.content+"';\n"+a.style.cssText.replace(/content:[^;]*;/g,"")),b}},i=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,j=/([^{]*)({[\s\S]*?})/gim,k=/(.*)((?:\*)|(?:\:scope))(.*)/,l=/^[.\[:]/,m=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,n=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,o=/::(x-[^\s{,(]*)/gim,p="([>\\s~+[.,{:][\\s\\S]*)?$",q=/@host/gim;if(window.ShadowDOMPolyfill){e("style { display: none !important; }\n");var r=document.querySelector("head");r.insertBefore(f(),r.childNodes[0])}a.ShadowCSS=h}(window.Platform),function(a){function b(a,b){if(window.ShadowDOMPolyfill){for(var h,i=this.convertPolyfillDirectives(a,b),j="",k=0;h=e.exec(i);)j+=i.substring(k,h.index),j+=this.scopeHostCss(h[1],b),k=e.lastIndex;j+=i.substring(k,i.length);var l=new RegExp("^"+b+g,"m"),m=d(this.findAtHostRules(c(j),l));i=i.replace(f,""),i=this.convertPseudos(i);var n=c(i),o=this.scopeRules(n,b);return m+o}}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}var e=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,f=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,g="([>\\s~+[.,{:][\\s\\S]*)?$";a.ShadowCSS.shimShadowDOMStyling2=b}(window.Platform)}
\ No newline at end of file
+if(!HTMLElement.prototype.createShadowRoot&&!HTMLElement.prototype.webkitCreateShadowRoot||window.__forceShadowDomPolyfill){!function(){Element.prototype.webkitCreateShadowRoot&&(Element.prototype.webkitCreateShadowRoot=function(){return window.ShadowDOMPolyfill.wrapIfNeeded(this).createShadowRoot()})}(),function(a){"use strict";function b(){function a(a){"splice"===a[0].type&&"splice"===a[1].type&&(b=!0)}if("function"!=typeof Object.observe||"function"!=typeof Array.observe)return!1;var b=!1,c=[0];return Array.observe(c,a),c[1]=1,c.length=0,Object.deliverChangeRecords(a),b}function c(){if(a.document&&"securityPolicy"in a.document&&!a.document.securityPolicy.allowsEval)return!1;try{var b=new Function("","return true;");return b()}catch(c){return!1}}function d(a){return+a===a>>>0}function e(a){return+a}function f(a){return a===Object(a)}function g(a,b){return a===b?0!==a||1/a===1/b:H(a)&&H(b)?!0:a!==a&&b!==b}function h(a){return"string"!=typeof a?!1:(a=a.trim(),""==a?!0:"."==a[0]?!1:P.test(a))}function i(a,b){if(b!==Q)throw Error("Use Path.get to retrieve path objects");return""==a.trim()?this:d(a)?(this.push(a),this):(a.split(/\s*\.\s*/).filter(function(a){return a}).forEach(function(a){this.push(a)},this),G&&!F&&this.length&&(this.getValueFrom=this.compiledGetValueFromFn()),void 0)}function j(a){if(a instanceof i)return a;null==a&&(a=""),"string"!=typeof a&&(a=String(a));var b=R[a];if(b)return b;if(!h(a))return S;var b=new i(a,Q);return R[a]=b,b}function k(b){for(var c=0;T>c&&b.check();)b.report(),c++;a.testingExposeCycleCount&&(a.dirtyCheckCycleCount=c)}function l(a){for(var b in a)return!1;return!0}function m(a){return l(a.added)&&l(a.removed)&&l(a.changed)}function n(a,b){var c={},d={},e={};for(var f in b){var g=a[f];(void 0===g||g!==b[f])&&(f in a?g!==b[f]&&(e[f]=g):d[f]=void 0)}for(var f in a)f in b||(c[f]=a[f]);return Array.isArray(a)&&a.length!==b.length&&(e.length=a.length),{added:c,removed:d,changed:e}}function o(a,b){var c=b||(Array.isArray(a)?[]:{});for(var d in a)c[d]=a[d];return Array.isArray(a)&&(c.length=a.length),c}function p(a,b,c,d){if(this.closed=!1,this.object=a,this.callback=b,this.target=c,this.token=d,this.reporting=!0,F){var e=this;this.boundInternalCallback=function(a){e.internalCallback(a)}}q(this)}function q(a){V&&(U.push(a),p._allObserversCount++)}function r(a,b,c,d){p.call(this,a,b,c,d),this.connect(),this.sync(!0)}function s(a,b,c,d){if(!Array.isArray(a))throw Error("Provided object is not an Array");r.call(this,a,b,c,d)}function t(a){this.arr=[],this.callback=a,this.isObserved=!0}function u(a,b,c,d,e,g,h){var b=b instanceof i?b:j(b);return b&&b.length&&f(a)?(p.call(this,a,c,d,e),this.valueFn=g,this.setValueFn=h,this.path=b,this.connect(),this.sync(!0),void 0):(this.value_=b?b.getValueFrom(a):void 0,this.value=g?g(this.value_):this.value_,this.closed=!0,void 0)}function v(a,b,c,d){p.call(this,void 0,a,b,c),this.valueFn=d,this.observed=[],this.values=[],this.started=!1}function w(a,b){if("function"==typeof Object.observe){var c=Object.getNotifier(a);return function(d,e){var f={object:a,type:d,name:b};2===arguments.length&&(f.oldValue=e),c.notify(f)}}}function x(a,b,c){for(var d={},e={},f=0;f<b.length;f++){var g=b[f];$[g.type]?(g.name in c||(c[g.name]=g.oldValue),"updated"!=g.type&&("new"!=g.type?g.name in d?(delete d[g.name],delete c[g.name]):e[g.name]=!0:g.name in e?delete e[g.name]:d[g.name]=!0)):(console.error("Unknown changeRecord type: "+g.type),console.error(g))}for(var h in d)d[h]=a[h];for(var h in e)e[h]=void 0;var i={};for(var h in c)if(!(h in d||h in e)){var j=a[h];c[h]!==j&&(i[h]=j)}return{added:d,removed:e,changed:i}}function y(a,b,c){return{index:a,removed:b,addedCount:c}}function z(){}function A(a,b,c,d,e,f){return db.calcSplices(a,b,c,d,e,f)}function B(a,b,c,d){return c>b||a>d?-1:b==c||d==a?0:c>a?d>b?b-c:d-c:b>d?d-a:b-a}function C(a,b,c,d){for(var e=y(b,c,d),f=!1,g=0,h=0;h<a.length;h++){var i=a[h];if(i.index+=g,!f){var j=B(e.index,e.index+e.removed.length,i.index,i.index+i.addedCount);if(j>=0){a.splice(h,1),h--,g-=i.addedCount-i.removed.length,e.addedCount+=i.addedCount-j;var k=e.removed.length+i.removed.length-j;if(e.addedCount||k){var c=i.removed;if(e.index<i.index){var l=e.removed.slice(0,i.index-e.index);Array.prototype.push.apply(l,c),c=l}if(e.index+e.removed.length>i.index+i.addedCount){var m=e.removed.slice(i.index+i.addedCount-e.index);Array.prototype.push.apply(c,m)}e.removed=c,i.index<e.index&&(e.index=i.index)}else f=!0}else if(e.index<i.index){f=!0,a.splice(h,0,e),h++;var n=e.addedCount-e.removed.length;i.index+=n,g+=n}}}f||a.push(e)}function D(a,b){for(var c=[],f=0;f<b.length;f++){var g=b[f];switch(g.type){case"splice":C(c,g.index,g.removed.slice(),g.addedCount);break;case"new":case"updated":case"deleted":if(!d(g.name))continue;var h=e(g.name);if(0>h)continue;C(c,h,[g.oldValue],1);break;default:console.error("Unexpected record type: "+JSON.stringify(g))}}return c}function E(a,b){var c=[];return D(a,b).forEach(function(b){return 1==b.addedCount&&1==b.removed.length?(b.removed[0]!==a[b.index]&&c.push(b),void 0):(c=c.concat(A(a,b.index,b.index+b.addedCount,b.removed,0,b.removed.length)),void 0)}),c}var F=b(),G=c(),H=a.Number.isNaN||function(b){return"number"==typeof b&&a.isNaN(b)},I="__proto__"in{}?function(a){return a}:function(a){var b=a.__proto__;if(!b)return a;var c=Object.create(b);return Object.getOwnPropertyNames(a).forEach(function(b){Object.defineProperty(c,b,Object.getOwnPropertyDescriptor(a,b))}),c},J="[$_a-zA-Z]",K="[$_a-zA-Z0-9]",L=J+"+"+K+"*",M="(?:[0-9]|[1-9]+[0-9]+)",N="(?:"+L+"|"+M+")",O="(?:"+N+")(?:\\s*\\.\\s*"+N+")*",P=new RegExp("^"+O+"$"),Q={},R={};i.get=j,i.prototype=I({__proto__:[],valid:!0,toString:function(){return this.join(".")},getValueFrom:function(a,b){for(var c=0;c<this.length;c++){if(null==a)return;b&&b.observe(a),a=a[this[c]]}return a},compiledGetValueFromFn:function(){var a=this.map(function(a){return d(a)?'["'+a+'"]':"."+a}),b="",c="obj";b+="if (obj != null";for(var e=0;e<this.length-1;e++)this[e],c+=a[e],b+=" &&\n     "+c+" != null";return b+=")\n",c+=a[e],b+="  return "+c+";\nelse\n  return undefined;",new Function("obj",b)},setValueFrom:function(a,b){if(!this.length)return!1;for(var c=0;c<this.length-1;c++){if(!f(a))return!1;a=a[this[c]]}return f(a)?(a[this[c]]=b,!0):!1}});var S=new i("",Q);S.valid=!1,S.getValueFrom=S.setValueFrom=function(){};var T=1e3;p.prototype={internalCallback:function(a){this.closed||this.reporting&&this.check(a)&&(this.report(),this.testingResults&&(this.testingResults.anyChanged=!0))},close:function(){this.closed||(this.object&&"function"==typeof this.object.close&&this.object.close(),this.disconnect(),this.object=void 0,this.closed=!0)},deliver:function(a){this.closed||(F?(this.testingResults=a,Object.deliverChangeRecords(this.boundInternalCallback),this.testingResults=void 0):k(this))},report:function(){this.reporting&&(this.sync(!1),this.callback&&(this.reportArgs.push(this.token),this.invokeCallback(this.reportArgs)),this.reportArgs=void 0)},invokeCallback:function(a){try{this.callback.apply(this.target,a)}catch(b){p._errorThrownDuringCallback=!0,console.error("Exception caught during observer callback: "+(b.stack||b))}},reset:function(){this.closed||(F&&(this.reporting=!1,Object.deliverChangeRecords(this.boundInternalCallback),this.reporting=!0),this.sync(!0))}};var U,V=!F||a.forceCollectObservers;p._allObserversCount=0,V&&(U=[]);var W=!1,X="function"==typeof Object.deliverAllChangeRecords;a.Platform=a.Platform||{},a.Platform.performMicrotaskCheckpoint=function(){if(!W){if(X)return Object.deliverAllChangeRecords(),void 0;if(V){W=!0;var b=0,c={};do{b++;var d=U;U=[],c.anyChanged=!1;for(var e=0;e<d.length;e++){var f=d[e];f.closed||(F?f.deliver(c):f.check()&&(c.anyChanged=!0,f.report()),U.push(f))}}while(T>b&&c.anyChanged);a.testingExposeCycleCount&&(a.dirtyCheckCycleCount=b),p._allObserversCount=U.length,W=!1}}},V&&(a.Platform.clearObservers=function(){U=[]}),r.prototype=I({__proto__:p.prototype,connect:function(){F&&Object.observe(this.object,this.boundInternalCallback)},sync:function(){F||(this.oldObject=o(this.object))},check:function(a){var b,c;if(F){if(!a)return!1;c={},b=x(this.object,a,c)}else c=this.oldObject,b=n(this.object,this.oldObject);return m(b)?!1:(this.reportArgs=[b.added||{},b.removed||{},b.changed||{}],this.reportArgs.push(function(a){return c[a]}),!0)},disconnect:function(){F?this.object&&Object.unobserve(this.object,this.boundInternalCallback):this.oldObject=void 0}}),s.prototype=I({__proto__:r.prototype,connect:function(){F&&Array.observe(this.object,this.boundInternalCallback)},sync:function(){F||(this.oldObject=this.object.slice())},check:function(a){var b;if(F){if(!a)return!1;b=E(this.object,a)}else b=A(this.object,0,this.object.length,this.oldObject,0,this.oldObject.length);return b&&b.length?(this.reportArgs=[b],!0):!1}}),s.applySplices=function(a,b,c){c.forEach(function(c){for(var d=[c.index,c.removed.length],e=c.index;e<c.index+c.addedCount;)d.push(b[e]),e++;Array.prototype.splice.apply(a,d)})};var Y=Object.getPrototypeOf({}),Z=Object.getPrototypeOf([]);t.prototype={reset:function(){this.isObserved=!this.isObserved},observe:function(a){if(f(a)&&a!==Y&&a!==Z){var b=this.arr.indexOf(a);b>=0&&this.arr[b+1]===this.isObserved||(0>b&&(b=this.arr.length,this.arr[b]=a,Object.observe(a,this.callback)),this.arr[b+1]=this.isObserved,this.observe(Object.getPrototypeOf(a)))}},cleanup:function(){for(var a=0,b=0,c=this.isObserved;b<this.arr.length;){var d=this.arr[b];this.arr[b+1]==c?(b>a&&(this.arr[a]=d,this.arr[a+1]=c),a+=2):Object.unobserve(d,this.callback),b+=2}this.arr.length=a}},u.prototype=I({__proto__:p.prototype,connect:function(){F&&(this.observedSet=new t(this.boundInternalCallback))},disconnect:function(){this.value=void 0,this.value_=void 0,this.observedSet&&(this.observedSet.reset(),this.observedSet.cleanup(),this.observedSet=void 0)},check:function(){return this.observedSet&&this.observedSet.reset(),this.value_=this.path.getValueFrom(this.object,this.observedSet),this.observedSet&&this.observedSet.cleanup(),g(this.value_,this.oldValue_)?!1:(this.value=this.valueFn?this.valueFn(this.value_):this.value_,this.reportArgs=[this.value,this.oldValue],!0)},sync:function(a){a&&(this.observedSet&&this.observedSet.reset(),this.value_=this.path.getValueFrom(this.object,this.observedSet),this.value=this.valueFn?this.valueFn(this.value_):this.value_,this.observedSet&&this.observedSet.cleanup()),this.oldValue_=this.value_,this.oldValue=this.value},setValue:function(a){this.path&&("function"==typeof this.setValueFn&&(a=this.setValueFn(a)),this.path.setValueFrom(this.object,a))}}),v.prototype=I({__proto__:u.prototype,addPath:function(a,b){if(this.started)throw Error("Cannot add more paths once started.");var b=b instanceof i?b:j(b),c=b?b.getValueFrom(a):void 0;this.observed.push(a,b),this.values.push(c)},start:function(){this.connect(),this.sync(!0)},getValues:function(){this.observedSet&&this.observedSet.reset();for(var a=!1,b=0;b<this.observed.length;b+=2){var c=this.observed[b+1];if(c){var d=this.observed[b],e=c.getValueFrom(d,this.observedSet),f=this.values[b/2];g(e,f)||(this.values[b/2]=e,a=!0)}}return this.observedSet&&this.observedSet.cleanup(),a},check:function(){return this.getValues()?(this.value=this.valueFn(this.values),g(this.value,this.oldValue)?!1:(this.reportArgs=[this.value,this.oldValue],!0)):void 0},sync:function(a){a&&(this.getValues(),this.value=this.valueFn(this.values)),this.oldValue=this.value},close:function(){if(this.observed){for(var a=0;a<this.observed.length;a+=2){var b=this.observed[a];b&&"function"==typeof b.close&&b.close()}this.observed=void 0,this.values=void 0}p.prototype.close.call(this)}});var $={"new":!0,updated:!0,deleted:!0};u.defineProperty=function(a,b,c){var d=c.object,e=j(c.path),f=w(a,b),g=new u(d,c.path,function(a,b){f&&f("updated",b)});return Object.defineProperty(a,b,{get:function(){return e.getValueFrom(d)},set:function(a){e.setValueFrom(d,a)},configurable:!0}),{close:function(){var c=e.getValueFrom(d);f&&g.deliver(),g.close(),Object.defineProperty(a,b,{value:c,writable:!0,configurable:!0})}}};var _=0,ab=1,bb=2,cb=3;z.prototype={calcEditDistances:function(a,b,c,d,e,f){for(var g=f-e+1,h=c-b+1,i=new Array(g),j=0;g>j;j++)i[j]=new Array(h),i[j][0]=j;for(var k=0;h>k;k++)i[0][k]=k;for(var j=1;g>j;j++)for(var k=1;h>k;k++)if(this.equals(a[b+k-1],d[e+j-1]))i[j][k]=i[j-1][k-1];else{var l=i[j-1][k]+1,m=i[j][k-1]+1;i[j][k]=m>l?l:m}return i},spliceOperationsFromEditDistances:function(a){for(var b=a.length-1,c=a[0].length-1,d=a[b][c],e=[];b>0||c>0;)if(0!=b)if(0!=c){var f,g=a[b-1][c-1],h=a[b-1][c],i=a[b][c-1];f=i>h?g>h?h:g:g>i?i:g,f==g?(g==d?e.push(_):(e.push(ab),d=g),b--,c--):f==h?(e.push(cb),b--,d=h):(e.push(bb),c--,d=i)}else e.push(cb),b--;else e.push(bb),c--;return e.reverse(),e},calcSplices:function(a,b,c,d,e,f){var g=0,h=0,i=Math.min(c-b,f-e);if(0==b&&0==e&&(g=this.sharedPrefix(a,d,i)),c==a.length&&f==d.length&&(h=this.sharedSuffix(a,d,i-g)),b+=g,e+=g,c-=h,f-=h,0==c-b&&0==f-e)return[];if(b==c){for(var j=y(b,[],0);f>e;)j.removed.push(d[e++]);return[j]}if(e==f)return[y(b,[],c-b)];for(var k=this.spliceOperationsFromEditDistances(this.calcEditDistances(a,b,c,d,e,f)),j=void 0,l=[],m=b,n=e,o=0;o<k.length;o++)switch(k[o]){case _:j&&(l.push(j),j=void 0),m++,n++;break;case ab:j||(j=y(m,[],0)),j.addedCount++,m++,j.removed.push(d[n]),n++;break;case bb:j||(j=y(m,[],0)),j.addedCount++,m++;break;case cb:j||(j=y(m,[],0)),j.removed.push(d[n]),n++}return j&&l.push(j),l},sharedPrefix:function(a,b,c){for(var d=0;c>d;d++)if(!this.equals(a[d],b[d]))return d;return c},sharedSuffix:function(a,b,c){for(var d=a.length,e=b.length,f=0;c>f&&this.equals(a[--d],b[--e]);)f++;return f},calculateSplices:function(a,b){return this.calcSplices(a,0,a.length,b,0,b.length)},equals:function(a,b){return a===b}};var db=new z;a.Observer=p,a.Observer.hasObjectObserve=F,a.ArrayObserver=s,a.ArrayObserver.calculateSplices=function(a,b){return db.calculateSplices(a,b)},a.ArraySplice=z,a.ObjectObserver=r,a.PathObserver=u,a.CompoundPathObserver=v,a.Path=i}("undefined"!=typeof global&&global?global:this),("undefined"==typeof WeakMap||navigator.userAgent.indexOf("Firefox/")>-1)&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}();var ShadowDOMPolyfill={};!function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function d(a,b){return Object.getOwnPropertyNames(b).forEach(function(c){switch(c){case"arguments":case"caller":case"length":case"name":case"prototype":case"toString":return}Object.defineProperty(a,c,Object.getOwnPropertyDescriptor(b,c))}),a}function e(a,b){for(var c=0;c<b.length;c++)if(b[c]in a)return b[c]}function f(a){var b=a.__proto__||Object.getPrototypeOf(a),c=C.get(b);if(c)return c;var d=f(b),e=r(d);return o(b,e,a),e}function g(a,b){m(a,b,!0)}function h(a,b){m(b,a,!1)}function i(a){return/^on[a-z]+$/.test(a)}function j(a){return F?new Function("return this.impl."+a):function(){return this.impl[a]}}function k(a){return F?new Function("v","this.impl."+a+" = v"):function(b){this.impl[a]=b}}function l(a){return F?new Function("return this.impl."+a+".apply(this.impl, arguments)"):function(){return this.impl[a].apply(this.impl,arguments)}}function m(b,c,d){Object.getOwnPropertyNames(b).forEach(function(e){if(!(e in c)){I&&b.__lookupGetter__(e);var f;try{f=Object.getOwnPropertyDescriptor(b,e)}catch(g){f=J}var h,m;if(d&&"function"==typeof f.value)return c[e]=l(e),void 0;var n=i(e);h=n?a.getEventHandlerGetter(e):j(e),(f.writable||f.set)&&(m=n?a.getEventHandlerSetter(e):k(e)),Object.defineProperty(c,e,{get:h,set:m,configurable:f.configurable,enumerable:f.enumerable})}})}function n(a,b,c){var e=a.prototype;o(e,b,c),d(b,a)}function o(a,c,d){var e=c.prototype;b(void 0===C.get(a)),C.set(a,c),D.set(e,a),g(a,e),d&&h(e,d)}function p(a,b){return C.get(b.prototype)===a}function q(a){var b=Object.getPrototypeOf(a),c=f(b),d=r(c);return o(b,d,a),d}function r(a){function b(b){a.call(this,b)}return b.prototype=Object.create(a.prototype),b.prototype.constructor=b,b}function s(a){return a instanceof E.EventTarget||a instanceof E.Event||a instanceof E.Range||a instanceof E.DOMImplementation}function t(a){return a instanceof M||a instanceof L||a instanceof N||a instanceof O||a instanceof K}function u(a){return null===a?null:(b(t(a)),a.polymerWrapper_||(a.polymerWrapper_=new(f(a))(a)))}function v(a){return null===a?null:(b(s(a)),a.impl)}function w(a){return a&&s(a)?v(a):a}function x(a){return a&&!s(a)?u(a):a}function y(a,c){null!==c&&(b(t(a)),b(void 0===c||s(c)),a.polymerWrapper_=c)}function z(a,b,c){Object.defineProperty(a.prototype,b,{get:c,configurable:!0,enumerable:!0})}function A(a,b){z(a,b,function(){return u(this.impl[b])})}function B(a,b){a.forEach(function(a){b.forEach(function(b){a.prototype[b]=function(){var a=x(this);return a[b].apply(a,arguments)}})})}var C=new WeakMap,D=new WeakMap,E=Object.create(null),F=!("securityPolicy"in document)||document.securityPolicy.allowsEval;if(F)try{var G=new Function("","return true;");F=G()}catch(H){}Object.getOwnPropertyNames(window);var I=/Firefox/.test(navigator.userAgent),J={get:function(){},set:function(){},configurable:!0,enumerable:!0},K=DOMImplementation,L=Event,M=Node,N=Window,O=Range;a.assert=b,a.constructorTable=C,a.defineGetter=z,a.defineWrapGetter=A,a.forwardMethodsToWrapper=B,a.isWrapperFor=p,a.mixin=c,a.nativePrototypeTable=D,a.oneOf=e,a.registerObject=q,a.registerWrapper=n,a.rewrap=y,a.unwrap=v,a.unwrapIfNeeded=w,a.wrap=u,a.wrapIfNeeded=x,a.wrappers=E}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){return a instanceof N.ShadowRoot}function c(a){var b=a.localName;return"content"===b||"shadow"===b}function d(a){return!!a.shadowRoot}function e(a){var b;return a.parentNode||(b=a.defaultView)&&M(b)||null}function f(f,g,h){if(h.length)return h.shift();if(b(f))return j(f)||a.getHostForShadowRoot(f);var i=a.eventParentsTable.get(f);if(i){for(var k=1;k<i.length;k++)h[k-1]=i[k];return i[0]}if(g&&c(f)){var l=f.parentNode;if(l&&d(l))for(var m=a.getShadowTrees(l),n=j(g),k=0;k<m.length;k++)if(m[k].contains(n))return n}return e(f)}function g(a){for(var d=[],e=a,g=[],i=[];e;){var j=null;if(c(e)){j=h(d);var k=d[d.length-1]||e;d.push(k)}else d.length||d.push(e);var l=d[d.length-1];g.push({target:l,currentTarget:e}),b(e)&&d.pop(),e=f(e,j,i)}return g}function h(a){for(var b=a.length-1;b>=0;b--)if(!c(a[b]))return a[b];return null}function i(d,e){for(var g=[];d;){for(var i=[],j=e,l=void 0;j;){var n=null;if(i.length){if(c(j)&&(n=h(i),k(l))){var o=i[i.length-1];i.push(o)}}else i.push(j);if(m(j,d))return i[i.length-1];b(j)&&i.pop(),l=j,j=f(j,n,g)}d=b(d)?a.getHostForShadowRoot(d):d.parentNode}}function j(b){return a.insertionParentTable.get(b)}function k(a){return j(a)}function l(a){for(var b;b=a.parentNode;)a=b;return a}function m(a,b){return l(a)===l(b)}function n(b,c){if(b===c)return!0;if(b instanceof N.ShadowRoot){var d=a.getHostForShadowRoot(b);return n(l(d),c)}return!1}function o(a){switch(a){case"DOMAttrModified":case"DOMAttributeNameChanged":case"DOMCharacterDataModified":case"DOMElementNameChanged":case"DOMNodeInserted":case"DOMNodeInsertedIntoDocument":case"DOMNodeRemoved":case"DOMNodeRemovedFromDocument":case"DOMSubtreeModified":return!0}return!1}function p(b){if(!P.get(b)){P.set(b,!0),o(b.type)||a.renderAllPending();var c=M(b.target),d=M(b);return q(d,c)}}function q(a,b){var c=g(b);return"load"===a.type&&2===c.length&&c[0].target instanceof N.Document&&c.shift(),X.set(a,c),r(a,c)&&s(a,c)&&t(a,c),T.set(a,w.NONE),R.set(a,null),a.defaultPrevented}function r(a,b){for(var c,d=b.length-1;d>0;d--){var e=b[d].target,f=b[d].currentTarget;if(e!==f&&(c=w.CAPTURING_PHASE,!u(b[d],a,c)))return!1}return!0}function s(a,b){var c=w.AT_TARGET;return u(b[0],a,c)}function t(a,b){for(var c,d=a.bubbles,e=1;e<b.length;e++){var f=b[e].target,g=b[e].currentTarget;if(f===g)c=w.AT_TARGET;else{if(!d||V.get(a))continue;c=w.BUBBLING_PHASE}if(!u(b[e],a,c))return}}function u(a,b,c){var d=a.target,e=a.currentTarget,f=O.get(e);if(!f)return!0;if("relatedTarget"in b){var g=L(b),h=M(g.relatedTarget),j=i(e,h);if(j===d)return!0;S.set(b,j)}T.set(b,c);var k=b.type,l=!1;Q.set(b,d),R.set(b,e);for(var m=0;m<f.length;m++){var n=f[m];if(n.removed)l=!0;else if(!(n.type!==k||!n.capture&&c===w.CAPTURING_PHASE||n.capture&&c===w.BUBBLING_PHASE))try{if("function"==typeof n.handler?n.handler.call(e,b):n.handler.handleEvent(b),V.get(b))return!1}catch(o){window.onerror?window.onerror(o.message):console.error(o)}}if(l){var p=f.slice();f.length=0;for(var m=0;m<p.length;m++)p[m].removed||f.push(p[m])}return!U.get(b)}function v(a,b,c){this.type=a,this.handler=b,this.capture=Boolean(c)}function w(a,b){return a instanceof Y?(this.impl=a,void 0):M(A(Y,"Event",a,b))}function x(a){return a&&a.relatedTarget?Object.create(a,{relatedTarget:{value:L(a.relatedTarget)}}):a}function y(a,b,c){var d=window[a],e=function(b,c){return b instanceof d?(this.impl=b,void 0):M(A(d,a,b,c))};return e.prototype=Object.create(b.prototype),c&&J(e.prototype,c),d&&(d.prototype["init"+a]?K(d,e,document.createEvent(a)):K(d,e,new d("temp"))),e}function z(a,b){return function(){arguments[b]=L(arguments[b]);var c=L(this);c[a].apply(c,arguments)}}function A(a,b,c,d){if(gb)return new a(c,x(d));var e=L(document.createEvent(b)),f=fb[b],g=[c];return Object.keys(f).forEach(function(a){var b=null!=d&&a in d?d[a]:f[a];"relatedTarget"===a&&(b=L(b)),g.push(b)}),e["init"+b].apply(e,g),e}function B(a){return"function"==typeof a?!0:a&&a.handleEvent}function C(a){this.impl=a}function D(b){return b instanceof N.ShadowRoot&&(b=a.getHostForShadowRoot(b)),L(b)}function E(a){I(a,jb)}function F(b,c,d,e){a.renderAllPending();for(var f=M(kb.call(c.impl,d,e)),h=g(f,this),i=0;i<h.length;i++){var j=h[i];if(j.currentTarget===b)return j.target}return null}function G(a){return function(){var b=W.get(this);return b&&b[a]&&b[a].value||null}}function H(a){var b=a.slice(2);return function(c){var d=W.get(this);d||(d=Object.create(null),W.set(this,d));var e=d[a];if(e&&this.removeEventListener(b,e.wrapped,!1),"function"==typeof c){var f=function(b){var d=c.call(this,b);d===!1?b.preventDefault():"onbeforeunload"===a&&"string"==typeof d&&(b.returnValue=d)};this.addEventListener(b,f,!1),d[a]={value:c,wrapped:f}}}}var I=a.forwardMethodsToWrapper,J=a.mixin,K=a.registerWrapper,L=a.unwrap,M=a.wrap,N=a.wrappers;new WeakMap;var O=new WeakMap,P=new WeakMap,Q=new WeakMap,R=new WeakMap,S=new WeakMap,T=new WeakMap,U=new WeakMap,V=new WeakMap,W=new WeakMap,X=new WeakMap;v.prototype={equals:function(a){return this.handler===a.handler&&this.type===a.type&&this.capture===a.capture},get removed(){return null===this.handler},remove:function(){this.handler=null}};var Y=window.Event;w.prototype={get target(){return Q.get(this)},get currentTarget(){return R.get(this)},get eventPhase(){return T.get(this)},get path(){var a=new N.NodeList,b=X.get(this);if(b){for(var c=0,d=b.length-1,e=l(R.get(this)),f=0;d>=f;f++){var g=b[f].currentTarget,h=l(g);n(e,h)&&(f!==d||g instanceof N.Node)&&(a[c++]=g)}a.length=c}return a},stopPropagation:function(){U.set(this,!0)},stopImmediatePropagation:function(){U.set(this,!0),V.set(this,!0)}},K(Y,w,document.createEvent("Event"));var Z=y("UIEvent",w),$=y("CustomEvent",w),_={get relatedTarget(){return S.get(this)||M(L(this).relatedTarget)}},ab=J({initMouseEvent:z("initMouseEvent",14)},_),bb=J({initFocusEvent:z("initFocusEvent",5)},_),cb=y("MouseEvent",Z,ab),db=y("FocusEvent",Z,bb),eb=y("MutationEvent",w,{initMutationEvent:z("initMutationEvent",3),get relatedNode(){return M(this.impl.relatedNode)}}),fb=Object.create(null),gb=function(){try{new window.MouseEvent("click")}catch(a){return!1}return!0}();if(!gb){var hb=function(a,b,c){if(c){var d=fb[c];b=J(J({},d),b)}fb[a]=b};hb("Event",{bubbles:!1,cancelable:!1}),hb("CustomEvent",{detail:null},"Event"),hb("UIEvent",{view:null,detail:0},"Event"),hb("MouseEvent",{screenX:0,screenY:0,clientX:0,clientY:0,ctrlKey:!1,altKey:!1,shiftKey:!1,metaKey:!1,button:0,relatedTarget:null},"UIEvent"),hb("FocusEvent",{relatedTarget:null},"UIEvent")}var ib=window.EventTarget,jb=["addEventListener","removeEventListener","dispatchEvent"];[Node,Window].forEach(function(a){var b=a.prototype;jb.forEach(function(a){Object.defineProperty(b,a+"_",{value:b[a]})})}),C.prototype={addEventListener:function(a,b,c){if(B(b)){var d=new v(a,b,c),e=O.get(this);if(e){for(var f=0;f<e.length;f++)if(d.equals(e[f]))return}else e=[],O.set(this,e);e.push(d);var g=D(this);g.addEventListener_(a,p,!0)}},removeEventListener:function(a,b,c){c=Boolean(c);var d=O.get(this);if(d){for(var e=0,f=!1,g=0;g<d.length;g++)d[g].type===a&&d[g].capture===c&&(e++,d[g].handler===b&&(f=!0,d[g].remove()));if(f&&1===e){var h=D(this);h.removeEventListener_(a,p,!0)}}},dispatchEvent:function(a){var b=D(this);return b.dispatchEvent_(L(a))}},ib&&K(ib,C);var kb=document.elementFromPoint;a.adjustRelatedTarget=i,a.elementFromPoint=F,a.getEventHandlerGetter=G,a.getEventHandlerSetter=H,a.wrapEventTargetMethods=E,a.wrappers.CustomEvent=$,a.wrappers.Event=w,a.wrappers.EventTarget=C,a.wrappers.FocusEvent=db,a.wrappers.MouseEvent=cb,a.wrappers.MutationEvent=eb,a.wrappers.UIEvent=Z}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,b){Object.defineProperty(a,b,{enumerable:!1})}function c(){this.length=0,b(this,"length")}function d(a){if(null==a)return a;for(var b=new c,d=0,e=a.length;e>d;d++)b[d]=f(a[d]);return b.length=e,b}function e(a,b){a.prototype[b]=function(){return d(this.impl[b].apply(this.impl,arguments))}}var f=a.wrap;c.prototype={item:function(a){return this[a]}},b(c.prototype,"item"),a.wrappers.NodeList=c,a.addWrapNodeListMethod=e,a.wrapNodeList=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){o(a instanceof k)}function c(a,b,c,d){if(!(a instanceof DocumentFragment))return a.parentNode&&a.parentNode.removeChild(a),a.parentNode_=b,a.previousSibling_=c,a.nextSibling_=d,c&&(c.nextSibling_=a),d&&(d.previousSibling_=a),[a];for(var e,f=[];e=a.firstChild;)a.removeChild(e),f.push(e),e.parentNode_=b;for(var g=0;g<f.length;g++)f[g].previousSibling_=f[g-1]||c,f[g].nextSibling_=f[g+1]||d;return c&&(c.nextSibling_=f[0]),d&&(d.previousSibling_=f[f.length-1]),f}function d(a){if(a instanceof DocumentFragment){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}return[a]}function e(a){for(var b=0;b<a.length;b++)a[b].nodeWasAdded_()}function f(a,b){var c=a.nodeType===k.DOCUMENT_NODE?a:a.ownerDocument;c!==b.ownerDocument&&c.adoptNode(b)}function g(b,c){if(c.length){var d=b.ownerDocument;if(d!==c[0].ownerDocument)for(var e=0;e<c.length;e++)a.adoptNodeNoRemove(c[e],d)}}function h(a,b){g(a,b);var c=b.length;if(1===c)return r(b[0]);for(var d=r(a.ownerDocument.createDocumentFragment()),e=0;c>e;e++)d.appendChild(r(b[e]));return d}function i(a){if(a.invalidateShadowRenderer()){for(var b=a.firstChild;b;){o(b.parentNode===a);var c=b.nextSibling,d=r(b),e=d.parentNode;e&&y.call(e,d),b.previousSibling_=b.nextSibling_=b.parentNode_=null,b=c}a.firstChild_=a.lastChild_=null}else for(var c,f=r(a),g=f.firstChild;g;)c=g.nextSibling,y.call(f,g),g=c}function j(a){var b=a.parentNode;return b&&b.invalidateShadowRenderer()}function k(a){o(a instanceof u),l.call(this,a),this.parentNode_=void 0,this.firstChild_=void 0,this.lastChild_=void 0,this.nextSibling_=void 0,this.previousSibling_=void 0}var l=a.wrappers.EventTarget,m=a.wrappers.NodeList,n=a.defineWrapGetter,o=a.assert,p=a.mixin,q=a.registerWrapper,r=a.unwrap,s=a.wrap,t=a.wrapIfNeeded,u=window.Node,v=u.prototype.appendChild,w=u.prototype.insertBefore,x=u.prototype.replaceChild,y=u.prototype.removeChild,z=u.prototype.compareDocumentPosition;k.prototype=Object.create(l.prototype),p(k.prototype,{appendChild:function(a){b(a);var g;if(this.invalidateShadowRenderer()||j(a)){var i=this.lastChild,k=null;g=c(a,this,i,k),this.lastChild_=g[g.length-1],i||(this.firstChild_=g[0]),v.call(this.impl,h(this,g))}else g=d(a),f(this,a),v.call(this.impl,r(a));return e(g),a},insertBefore:function(a,i){if(!i)return this.appendChild(a);b(a),b(i),o(i.parentNode===this);var k;if(this.invalidateShadowRenderer()||j(a)){var l=i.previousSibling,m=i;k=c(a,this,l,m),this.firstChild===i&&(this.firstChild_=k[0]);var n=r(i),p=n.parentNode;p?w.call(p,h(this,k),n):g(this,k)}else k=d(a),f(this,a),w.call(this.impl,r(a),r(i));return e(k),a},removeChild:function(a){if(b(a),a.parentNode!==this)throw new Error("NotFoundError");var c=r(a);if(this.invalidateShadowRenderer()){var d=this.firstChild,e=this.lastChild,f=a.nextSibling,g=a.previousSibling,h=c.parentNode;h&&y.call(h,c),d===a&&(this.firstChild_=f),e===a&&(this.lastChild_=g),g&&(g.nextSibling_=f),f&&(f.previousSibling_=g),a.previousSibling_=a.nextSibling_=a.parentNode_=void 0}else y.call(this.impl,c);return a},replaceChild:function(a,g){if(b(a),b(g),g.parentNode!==this)throw new Error("NotFoundError");var i,k=r(g);if(this.invalidateShadowRenderer()||j(a)){var l=g.previousSibling,m=g.nextSibling;m===a&&(m=a.nextSibling),i=c(a,this,l,m),this.firstChild===g&&(this.firstChild_=i[0]),this.lastChild===g&&(this.lastChild_=i[i.length-1]),g.previousSibling_=g.nextSibling_=g.parentNode_=void 0,k.parentNode&&x.call(k.parentNode,h(this,i),k)}else i=d(a),f(this,a),x.call(this.impl,r(a),k);return e(i),g},nodeWasAdded_:function(){},hasChildNodes:function(){return null===this.firstChild},get parentNode(){return void 0!==this.parentNode_?this.parentNode_:s(this.impl.parentNode)},get firstChild(){return void 0!==this.firstChild_?this.firstChild_:s(this.impl.firstChild)},get lastChild(){return void 0!==this.lastChild_?this.lastChild_:s(this.impl.lastChild)},get nextSibling(){return void 0!==this.nextSibling_?this.nextSibling_:s(this.impl.nextSibling)},get previousSibling(){return void 0!==this.previousSibling_?this.previousSibling_:s(this.impl.previousSibling)},get parentElement(){for(var a=this.parentNode;a&&a.nodeType!==k.ELEMENT_NODE;)a=a.parentNode;return a},get textContent(){for(var a="",b=this.firstChild;b;b=b.nextSibling)a+=b.textContent;return a},set textContent(a){if(this.invalidateShadowRenderer()){if(i(this),""!==a){var b=this.impl.ownerDocument.createTextNode(a);this.appendChild(b)}}else this.impl.textContent=a},get childNodes(){for(var a=new m,b=0,c=this.firstChild;c;c=c.nextSibling)a[b++]=c;return a.length=b,a},cloneNode:function(a){if(!this.invalidateShadowRenderer())return s(this.impl.cloneNode(a));var b=s(this.impl.cloneNode(!1));if(a)for(var c=this.firstChild;c;c=c.nextSibling)b.appendChild(c.cloneNode(!0));return b},contains:function(a){if(!a)return!1;if(a=t(a),a===this)return!0;var b=a.parentNode;return b?this.contains(b):!1},compareDocumentPosition:function(a){return z.call(this.impl,r(a))}}),n(k,"ownerDocument"),q(u,k,document.createDocumentFragment()),delete k.prototype.querySelector,delete k.prototype.querySelectorAll,k.prototype=p(Object.create(l.prototype),k.prototype),a.wrappers.Node=k}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a,c){for(var d,e=a.firstElementChild;e;){if(e.matches(c))return e;if(d=b(e,c))return d;e=e.nextElementSibling}return null}function c(a,b,d){for(var e=a.firstElementChild;e;)e.matches(b)&&(d[d.length++]=e),c(e,b,d),e=e.nextElementSibling;return d}var d={querySelector:function(a){return b(this,a)},querySelectorAll:function(a){return c(this,a,new NodeList)}},e={getElementsByTagName:function(a){return this.querySelectorAll(a)},getElementsByClassName:function(a){return this.querySelectorAll("."+a)},getElementsByTagNameNS:function(a,b){if("*"===a)return this.getElementsByTagName(b);for(var c=new NodeList,d=this.getElementsByTagName(b),e=0,f=0;e<d.length;e++)d[e].namespaceURI===a&&(c[f++]=d[e]);
+return c.length=f,c}};a.GetElementsByInterface=e,a.SelectorsInterface=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.nextSibling;return a}function c(a){for(;a&&a.nodeType!==Node.ELEMENT_NODE;)a=a.previousSibling;return a}var d=a.wrappers.NodeList,e={get firstElementChild(){return b(this.firstChild)},get lastElementChild(){return c(this.lastChild)},get childElementCount(){for(var a=0,b=this.firstElementChild;b;b=b.nextElementSibling)a++;return a},get children(){for(var a=new d,b=0,c=this.firstElementChild;c;c=c.nextElementSibling)a[b++]=c;return a.length=b,a}},f={get nextElementSibling(){return b(this.nextSibling)},get previousElementSibling(){return c(this.previousSibling)}};a.ChildNodeInterface=f,a.ParentNodeInterface=e}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){d.call(this,a)}var c=a.ChildNodeInterface,d=a.wrappers.Node,e=a.mixin,f=a.registerWrapper,g=window.CharacterData;b.prototype=Object.create(d.prototype),e(b.prototype,{get textContent(){return this.data},set textContent(a){this.data=a}}),e(b.prototype,c),f(g,b,document.createTextNode("")),a.wrappers.CharacterData=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b,c){var d=b.parentNode;if(d&&d.shadowRoot){var e=a.getRendererForHost(d);e.dependsOnAttribute(c)&&e.invalidate()}}function c(a){g.call(this,a)}function d(a,c,d){var e=d||c;Object.defineProperty(a,c,{get:function(){return this.impl[c]},set:function(a){this.impl[c]=a,b(this,e)},configurable:!0,enumerable:!0})}var e=a.ChildNodeInterface,f=a.GetElementsByInterface,g=a.wrappers.Node,h=a.ParentNodeInterface,i=a.SelectorsInterface;a.addWrapNodeListMethod;var j=a.mixin,k=a.oneOf,l=a.registerWrapper,m=a.wrappers,n=new WeakMap,o=window.Element,p=k(o.prototype,["matches","mozMatchesSelector","msMatchesSelector","webkitMatchesSelector"]),q=o.prototype[p];c.prototype=Object.create(g.prototype),j(c.prototype,{createShadowRoot:function(){var b=new m.ShadowRoot(this);n.set(this,b);var c=a.getRendererForHost(this);return c.invalidate(),b},get shadowRoot(){return n.get(this)||null},setAttribute:function(a,c){this.impl.setAttribute(a,c),b(this,a)},removeAttribute:function(a){this.impl.removeAttribute(a),b(this,a)},matches:function(a){return q.call(this.impl,a)}}),c.prototype[p]=function(a){return this.matches(a)},o.prototype.webkitCreateShadowRoot&&(c.prototype.webkitCreateShadowRoot=c.prototype.createShadowRoot),d(c.prototype,"id"),d(c.prototype,"className","class"),j(c.prototype,e),j(c.prototype,f),j(c.prototype,h),j(c.prototype,i),l(o,c),a.matchesName=p,a.wrappers.Element=c}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a){case"&":return"&amp;";case"<":return"&lt;";case'"':return"&quot;"}}function c(a){return a.replace(p,b)}function d(a){switch(a.nodeType){case Node.ELEMENT_NODE:for(var b,d=a.tagName.toLowerCase(),f="<"+d,g=a.attributes,h=0;b=g[h];h++)f+=" "+b.name+'="'+c(b.value)+'"';return f+=">",q[d]?f:f+e(a)+"</"+d+">";case Node.TEXT_NODE:return c(a.nodeValue);case Node.COMMENT_NODE:return"<!--"+c(a.nodeValue)+"-->";default:throw console.error(a),new Error("not implemented")}}function e(a){for(var b="",c=a.firstChild;c;c=c.nextSibling)b+=d(c);return b}function f(a,b,c){var d=c||"div";a.textContent="";var e=n(a.ownerDocument.createElement(d));e.innerHTML=b;for(var f;f=e.firstChild;)a.appendChild(o(f))}function g(a){j.call(this,a)}function h(b){k(g,b,function(){return a.renderAllPending(),this.impl[b]})}function i(b){Object.defineProperty(g.prototype,b,{value:function(){return a.renderAllPending(),this.impl[b].apply(this.impl,arguments)},configurable:!0,enumerable:!0})}var j=a.wrappers.Element,k=a.defineGetter,l=a.mixin,m=a.registerWrapper,n=a.unwrap,o=a.wrap,p=/&|<|"/g,q={area:!0,base:!0,br:!0,col:!0,command:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0},r=window.HTMLElement;g.prototype=Object.create(j.prototype),l(g.prototype,{get innerHTML(){return e(this)},set innerHTML(a){this.invalidateShadowRenderer()?f(this,a,this.tagName):this.impl.innerHTML=a},get outerHTML(){return d(this)},set outerHTML(a){var b=this.parentNode;b&&(b.invalidateShadowRenderer(),this.impl.outerHTML=a)}}),["clientHeight","clientLeft","clientTop","clientWidth","offsetHeight","offsetLeft","offsetTop","offsetWidth","scrollHeight","scrollLeft","scrollTop","scrollWidth"].forEach(h),["getBoundingClientRect","getClientRects","scrollIntoView"].forEach(i),m(r,g,document.createElement("b")),a.wrappers.HTMLElement=g,a.getInnerHTML=e,a.setInnerHTML=f}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLContentElement;b.prototype=Object.create(c.prototype),d(b.prototype,{get select(){return this.getAttribute("select")},set select(a){this.setAttribute("select",a)},setAttribute:function(a,b){c.prototype.setAttribute.call(this,a,b),"select"===String(a).toLowerCase()&&this.invalidateShadowRenderer(!0)}}),f&&e(f,b),a.wrappers.HTMLContentElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.HTMLElement,d=a.mixin,e=a.registerWrapper,f=window.HTMLShadowElement;b.prototype=Object.create(c.prototype),d(b.prototype,{}),f&&e(f,b),a.wrappers.HTMLShadowElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){if(!a.defaultView)return a;var b=m.get(a);if(!b){for(b=a.implementation.createHTMLDocument("");b.lastChild;)b.removeChild(b.lastChild);m.set(a,b)}return b}function c(a){for(var c,d=b(a.ownerDocument),e=j(d.createDocumentFragment());c=a.firstChild;)e.appendChild(c);return e}function d(a){if(e.call(this,a),!n){var b=c(a);l.set(this,k(b))}}var e=a.wrappers.HTMLElement,f=a.getInnerHTML,g=a.mixin,h=a.registerWrapper,i=a.setInnerHTML,j=a.unwrap,k=a.wrap,l=new WeakMap,m=new WeakMap,n=window.HTMLTemplateElement;d.prototype=Object.create(e.prototype),g(d.prototype,{get content(){return n?k(this.impl.content):l.get(this)},get innerHTML(){return f(this.content)},set innerHTML(a){i(this.content,a)}}),n&&h(n,d),a.wrappers.HTMLTemplateElement=d}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){switch(a.localName){case"content":return new c(a);case"shadow":return new e(a);case"template":return new f(a)}d.call(this,a)}var c=a.wrappers.HTMLContentElement,d=a.wrappers.HTMLElement,e=a.wrappers.HTMLShadowElement,f=a.wrappers.HTMLTemplateElement;a.mixin;var g=a.registerWrapper,h=window.HTMLUnknownElement;b.prototype=Object.create(d.prototype),g(h,b),a.wrappers.HTMLUnknownElement=b}(this.ShadowDOMPolyfill),function(a){"use strict";var b=a.GetElementsByInterface,c=a.ParentNodeInterface,d=a.SelectorsInterface,e=a.mixin,f=a.registerObject,g=f(document.createDocumentFragment());e(g.prototype,c),e(g.prototype,d),e(g.prototype,b);var h=f(document.createTextNode("")),i=f(document.createComment(""));a.wrappers.Comment=i,a.wrappers.DocumentFragment=g,a.wrappers.Text=h}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=i(a.impl.ownerDocument.createDocumentFragment());c.call(this,b),g(b,this);var d=a.shadowRoot;k.set(this,d),j.set(this,a)}var c=a.wrappers.DocumentFragment,d=a.elementFromPoint,e=a.getInnerHTML,f=a.mixin,g=a.rewrap,h=a.setInnerHTML,i=a.unwrap,j=new WeakMap,k=new WeakMap;b.prototype=Object.create(c.prototype),f(b.prototype,{get innerHTML(){return e(this)},set innerHTML(a){h(this,a),this.invalidateShadowRenderer()},get olderShadowRoot(){return k.get(this)||null},invalidateShadowRenderer:function(){return j.get(this).invalidateShadowRenderer()},elementFromPoint:function(a,b){return d(this,this.ownerDocument,a,b)},getElementById:function(a){return this.querySelector("#"+a)}}),a.wrappers.ShadowRoot=b,a.getHostForShadowRoot=function(a){return j.get(a)}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){a.previousSibling_=a.previousSibling,a.nextSibling_=a.nextSibling,a.parentNode_=a.parentNode}function c(a,c,e){var f=G(a),g=G(c),h=e?G(e):null;if(d(c),b(c),e)a.firstChild===e&&(a.firstChild_=e),e.previousSibling_=e.previousSibling;else{a.lastChild_=a.lastChild,a.lastChild===a.firstChild&&(a.firstChild_=a.firstChild);var i=H(f.lastChild);i&&(i.nextSibling_=i.nextSibling)}f.insertBefore(g,h)}function d(a){var c=G(a),d=c.parentNode;if(d){var e=H(d);b(a),a.previousSibling&&(a.previousSibling.nextSibling_=a),a.nextSibling&&(a.nextSibling.previousSibling_=a),e.lastChild===a&&(e.lastChild_=a),e.firstChild===a&&(e.firstChild_=a),d.removeChild(c)}}function e(a,b){g(b).push(a),x(a,b);var c=J.get(a);c||J.set(a,c=[]),c.push(b)}function f(a){I.set(a,[])}function g(a){return I.get(a)}function h(a){for(var b=[],c=0,d=a.firstChild;d;d=d.nextSibling)b[c++]=d;return b}function i(a,b,c){for(var d=a.firstChild;d;d=d.nextSibling)if(b(d)){if(c(d)===!1)return}else i(d,b,c)}function j(a,b){var c=b.getAttribute("select");if(!c)return!0;if(c=c.trim(),!c)return!0;if(!(a instanceof y))return!1;if(!N.test(c))return!1;if(":"===c[0]&&!O.test(c))return!1;try{return a.matches(c)}catch(d){return!1}}function k(){for(var a=0;a<Q.length;a++)Q[a].render();Q=[]}function l(){E=null,k()}function m(a){var b=L.get(a);return b||(b=new q(a),L.set(a,b)),b}function n(a){for(;a;a=a.parentNode)if(a instanceof C)return a;return null}function o(a){return m(D(a))}function p(a){this.skip=!1,this.node=a,this.childNodes=[]}function q(a){this.host=a,this.dirty=!1,this.invalidateAttributes(),this.associateNode(a)}function r(a){return a instanceof z}function s(a){return a instanceof z}function t(a){return a instanceof A}function u(a){return a instanceof A}function v(a){return a.shadowRoot}function w(a){for(var b=[],c=a.shadowRoot;c;c=c.olderShadowRoot)b.push(c);return b}function x(a,b){K.set(a,b)}var y=a.wrappers.Element,z=a.wrappers.HTMLContentElement,A=a.wrappers.HTMLShadowElement,B=a.wrappers.Node,C=a.wrappers.ShadowRoot;a.assert;var D=a.getHostForShadowRoot;a.mixin;var E,F=a.oneOf,G=a.unwrap,H=a.wrap,I=new WeakMap,J=new WeakMap,K=new WeakMap,L=new WeakMap,M=new WeakMap,N=/^[*.:#[a-zA-Z_|]/,O=new RegExp("^:("+["link","visited","target","enabled","disabled","checked","indeterminate","nth-child","nth-last-child","nth-of-type","nth-last-of-type","first-child","last-child","first-of-type","last-of-type","only-of-type"].join("|")+")"),P=F(window,["requestAnimationFrame","mozRequestAnimationFrame","webkitRequestAnimationFrame","setTimeout"]),Q=[],R=new ArraySplice;R.equals=function(a,b){return G(a.node)===b},p.prototype={append:function(a){var b=new p(a);return this.childNodes.push(b),b},sync:function(a){if(!this.skip){for(var b=this.node,e=this.childNodes,f=h(G(b)),g=a||new WeakMap,i=R.calculateSplices(e,f),j=0,k=0,l=0,m=0;m<i.length;m++){for(var n=i[m];l<n.index;l++)k++,e[j++].sync(g);for(var o=n.removed.length,p=0;o>p;p++){var q=H(f[k++]);g.get(q)||d(q)}for(var r=n.addedCount,s=f[k]&&H(f[k]),p=0;r>p;p++){var t=e[j++],u=t.node;c(b,u,s),g.set(u,!0),t.sync(g)}l+=r}for(var m=l;m<e.length;m++)e[m++].sync(g)}}},q.prototype={render:function(a){if(this.dirty){this.invalidateAttributes(),this.treeComposition();var b=this.host,c=b.shadowRoot;this.associateNode(b);for(var d=!e,e=a||new p(b),f=c.firstChild;f;f=f.nextSibling)this.renderNode(c,e,f,!1);d&&e.sync(),this.dirty=!1}},invalidate:function(){if(!this.dirty){if(this.dirty=!0,Q.push(this),E)return;E=window[P](l,0)}},renderNode:function(a,b,c,d){if(v(c)){b=b.append(c);var e=m(c);e.dirty=!0,e.render(b)}else r(c)?this.renderInsertionPoint(a,b,c,d):t(c)?this.renderShadowInsertionPoint(a,b,c):this.renderAsAnyDomTree(a,b,c,d)},renderAsAnyDomTree:function(a,b,c,d){if(b=b.append(c),v(c)){var e=m(c);b.skip=!e.dirty,e.render(b)}else for(var f=c.firstChild;f;f=f.nextSibling)this.renderNode(a,b,f,d)},renderInsertionPoint:function(a,b,c,d){var e=g(c);if(e.length){this.associateNode(c);for(var f=0;f<e.length;f++){var h=e[f];r(h)&&d?this.renderInsertionPoint(a,b,h,d):this.renderAsAnyDomTree(a,b,h,d)}}else this.renderFallbackContent(a,b,c);this.associateNode(c.parentNode)},renderShadowInsertionPoint:function(a,b,c){var d=a.olderShadowRoot;if(d){x(d,c),this.associateNode(c.parentNode);for(var e=d.firstChild;e;e=e.nextSibling)this.renderNode(d,b,e,!0)}else this.renderFallbackContent(a,b,c)},renderFallbackContent:function(a,b,c){this.associateNode(c),this.associateNode(c.parentNode);for(var d=c.firstChild;d;d=d.nextSibling)this.renderAsAnyDomTree(a,b,d,!1)},invalidateAttributes:function(){this.attributes=Object.create(null)},updateDependentAttributes:function(a){if(a){var b=this.attributes;/\.\w+/.test(a)&&(b["class"]=!0),/#\w+/.test(a)&&(b.id=!0),a.replace(/\[\s*([^\s=\|~\]]+)/g,function(a,c){b[c]=!0})}},dependsOnAttribute:function(a){return this.attributes[a]},distribute:function(a,b){var c=this;i(a,s,function(a){f(a),c.updateDependentAttributes(a.getAttribute("select"));for(var d=0;d<b.length;d++){var g=b[d];void 0!==g&&j(g,a)&&(e(g,a),b[d]=void 0)}})},treeComposition:function(){for(var a=this.host,b=a.shadowRoot,c=[],d=a.firstChild;d;d=d.nextSibling)if(r(d)){var e=g(d);e&&e.length||(e=h(d)),c.push.apply(c,e)}else c.push(d);for(var f,j;b;){if(f=void 0,i(b,u,function(a){return f=a,!1}),j=f,this.distribute(b,c),j){var k=b.olderShadowRoot;if(k){b=k,x(b,j);continue}break}break}},associateNode:function(a){M.set(a,this)}},B.prototype.invalidateShadowRenderer=function(){var a=M.get(this);return a?(a.invalidate(),!0):!1},z.prototype.getDistributedNodes=function(){var a=M.get(this);return a&&a.render(),g(this)},A.prototype.nodeWasAdded_=z.prototype.nodeWasAdded_=function(){this.invalidateShadowRenderer();var a,b=n(this);b&&(a=o(b)),M.set(this,a),a&&a.invalidate()},a.eventParentsTable=J,a.getRendererForHost=m,a.getShadowTrees=w,a.insertionParentTable=K,a.renderAllPending=k,a.visual={insertBefore:c,remove:d}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(b){if(window[b]){d(!a.wrappers[b]);var i=function(a){c.call(this,a)};i.prototype=Object.create(c.prototype),e(i.prototype,{get form(){return h(g(this).form)}}),f(window[b],i,document.createElement(b.slice(4,-7))),a.wrappers[b]=i}}var c=a.wrappers.HTMLElement,d=a.assert,e=a.mixin,f=a.registerWrapper,g=a.unwrap,h=a.wrap,i=["HTMLButtonElement","HTMLFieldSetElement","HTMLInputElement","HTMLKeygenElement","HTMLLabelElement","HTMLLegendElement","HTMLObjectElement","HTMLOptionElement","HTMLOutputElement","HTMLSelectElement","HTMLTextAreaElement"];i.forEach(b)}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){k.call(this,a)}function c(a){var c=document[a];b.prototype[a]=function(){return v(c.apply(this.impl,arguments))}}function d(a,b){y.call(b.impl,u(a)),e(a,b)}function e(a,b){a.shadowRoot&&b.adoptNode(a.shadowRoot),a instanceof n&&f(a,b);for(var c=a.firstChild;c;c=c.nextSibling)e(c,b)}function f(a,b){var c=a.olderShadowRoot;c&&b.adoptNode(c)}function g(a){this.impl=a}function h(a,b){var c=document.implementation[b];a.prototype[b]=function(){return v(c.apply(this.impl,arguments))}}function i(a,b){var c=document.implementation[b];a.prototype[b]=function(){return c.apply(this.impl,arguments)}}var j=a.GetElementsByInterface,k=a.wrappers.Node,l=a.ParentNodeInterface,m=a.SelectorsInterface,n=a.wrappers.ShadowRoot,o=a.defineWrapGetter,p=a.elementFromPoint,q=a.forwardMethodsToWrapper,r=a.matchesName,s=a.mixin,t=a.registerWrapper,u=a.unwrap,v=a.wrap,w=a.wrapEventTargetMethods;a.wrapNodeList;var x=new WeakMap;b.prototype=Object.create(k.prototype),o(b,"documentElement"),o(b,"body"),o(b,"head"),["createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","getElementById"].forEach(c);var y=document.adoptNode;if(s(b.prototype,{adoptNode:function(a){return a.parentNode&&a.parentNode.removeChild(a),d(a,this),a},elementFromPoint:function(a,b){return p(this,this,a,b)}}),document.register){var z=document.register;b.prototype.register=function(b,c){function d(a){return a?(this.impl=a,void 0):document.createElement(b)}var e=c.prototype;if(a.nativePrototypeTable.get(e))throw new Error("NotSupportedError");for(var f,g=Object.getPrototypeOf(e),h=[];g&&!(f=a.nativePrototypeTable.get(g));)h.push(g),g=Object.getPrototypeOf(g);if(!f)throw new Error("NotSupportedError");for(var i=Object.create(f),j=h.length-1;j>=0;j--)i=Object.create(i);return["createdCallback","enteredDocumentCallback","leftDocumentCallback","attributeChangedCallback"].forEach(function(a){var b=e[a];b&&(i[a]=function(){b.apply(v(this),arguments)})}),z.call(u(this),b,{prototype:i}),d.prototype=e,d.prototype.constructor=d,a.constructorTable.set(i,d),a.nativePrototypeTable.set(e,i),d},q([window.HTMLDocument||window.Document],["register"])}q([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement,window.HTMLHtmlElement],["appendChild","compareDocumentPosition","contains","getElementsByClassName","getElementsByTagName","getElementsByTagNameNS","insertBefore","querySelector","querySelectorAll","removeChild","replaceChild",r]),q([window.HTMLDocument||window.Document],["adoptNode","contains","createComment","createDocumentFragment","createElement","createElementNS","createEvent","createEventNS","createRange","createTextNode","elementFromPoint","getElementById"]),s(b.prototype,j),s(b.prototype,l),s(b.prototype,m),s(b.prototype,{get implementation(){var a=x.get(this);return a?a:(a=new g(u(this).implementation),x.set(this,a),a)}}),t(window.Document,b,document.implementation.createHTMLDocument("")),window.HTMLDocument&&t(window.HTMLDocument,b),w([window.HTMLBodyElement,window.HTMLDocument||window.Document,window.HTMLHeadElement]),h(g,"createDocumentType"),h(g,"createDocument"),h(g,"createHTMLDocument"),i(g,"hasFeature"),t(window.DOMImplementation,g),q([window.DOMImplementation],["createDocumentType","createDocument","createHTMLDocument","hasFeature"]),a.adoptNodeNoRemove=d,a.wrappers.DOMImplementation=g,a.wrappers.Document=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){c.call(this,a)}var c=a.wrappers.EventTarget,d=a.mixin,e=a.registerWrapper,f=a.unwrap,g=a.unwrapIfNeeded,h=a.wrap,i=a.renderAllPending,j=window.Window;b.prototype=Object.create(c.prototype);var k=window.getComputedStyle;j.prototype.getComputedStyle=function(a,b){return i(),k.call(this||window,g(a),b)},["addEventListener","removeEventListener","dispatchEvent"].forEach(function(a){j.prototype[a]=function(){var b=h(this||window);return b[a].apply(b,arguments)}}),d(b.prototype,{getComputedStyle:function(a,b){return k.call(f(this),g(a),b)}}),e(j,b),a.wrappers.Window=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}function c(a){return new b(a)}function d(a){return a.map(c)}function e(a){var b=this;this.impl=new k(function(c){a.call(b,d(c),b)})}var f=a.defineGetter,g=a.defineWrapGetter,h=a.registerWrapper,i=a.unwrapIfNeeded,j=a.wrapNodeList;a.wrappers;var k=window.MutationObserver||window.WebKitMutationObserver;if(k){var l=window.MutationRecord;b.prototype={get addedNodes(){return j(this.impl.addedNodes)},get removedNodes(){return j(this.impl.removedNodes)}},["target","previousSibling","nextSibling"].forEach(function(a){g(b,a)}),["type","attributeName","attributeNamespace","oldValue"].forEach(function(a){f(b,a,function(){return this.impl[a]})}),l&&h(l,b),window.Node,e.prototype={observe:function(a,b){this.impl.observe(i(a),b)},disconnect:function(){this.impl.disconnect()},takeRecords:function(){return d(this.impl.takeRecords())}},a.wrappers.MutationObserver=e,a.wrappers.MutationRecord=b}}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){this.impl=a}var c=a.registerWrapper,d=a.unwrap,e=a.unwrapIfNeeded,f=a.wrap,g=window.Range;b.prototype={get startContainer(){return f(this.impl.startContainer)},get endContainer(){return f(this.impl.endContainer)},get commonAncestorContainer(){return f(this.impl.commonAncestorContainer)},setStart:function(a,b){this.impl.setStart(e(a),b)},setEnd:function(a,b){this.impl.setEnd(e(a),b)},setStartBefore:function(a){this.impl.setStartBefore(e(a))},setStartAfter:function(a){this.impl.setStartAfter(e(a))},setEndBefore:function(a){this.impl.setEndBefore(e(a))},setEndAfter:function(a){this.impl.setEndAfter(e(a))},selectNode:function(a){this.impl.selectNode(e(a))},selectNodeContents:function(a){this.impl.selectNodeContents(e(a))},compareBoundaryPoints:function(a,b){return this.impl.compareBoundaryPoints(a,d(b))},extractContents:function(){return f(this.impl.extractContents())},cloneContents:function(){return f(this.impl.cloneContents())},insertNode:function(a){this.impl.insertNode(e(a))},surroundContents:function(a){this.impl.surroundContents(e(a))},cloneRange:function(){return f(this.impl.cloneRange())},isPointInRange:function(a,b){return this.impl.isPointInRange(e(a),b)},comparePoint:function(a,b){return this.impl.comparePoint(e(a),b)},intersectsNode:function(a){return this.impl.intersectsNode(e(a))}},g.prototype.createContextualFragment&&(b.prototype.createContextualFragment=function(a){return f(this.impl.createContextualFragment(a))}),c(window.Range,b),a.wrappers.Range=b}(this.ShadowDOMPolyfill),function(a){"use strict";function b(a){var b=c[a],d=window[b];if(d){var e=document.createElement(a),f=e.constructor;window[b]=f}}a.isWrapperFor;var c={a:"HTMLAnchorElement",applet:"HTMLAppletElement",area:"HTMLAreaElement",audio:"HTMLAudioElement",br:"HTMLBRElement",base:"HTMLBaseElement",body:"HTMLBodyElement",button:"HTMLButtonElement",canvas:"HTMLCanvasElement",dl:"HTMLDListElement",datalist:"HTMLDataListElement",dir:"HTMLDirectoryElement",div:"HTMLDivElement",embed:"HTMLEmbedElement",fieldset:"HTMLFieldSetElement",font:"HTMLFontElement",form:"HTMLFormElement",frame:"HTMLFrameElement",frameset:"HTMLFrameSetElement",hr:"HTMLHRElement",head:"HTMLHeadElement",h1:"HTMLHeadingElement",html:"HTMLHtmlElement",iframe:"HTMLIFrameElement",input:"HTMLInputElement",li:"HTMLLIElement",label:"HTMLLabelElement",legend:"HTMLLegendElement",link:"HTMLLinkElement",map:"HTMLMapElement",menu:"HTMLMenuElement",menuitem:"HTMLMenuItemElement",meta:"HTMLMetaElement",meter:"HTMLMeterElement",del:"HTMLModElement",ol:"HTMLOListElement",object:"HTMLObjectElement",optgroup:"HTMLOptGroupElement",option:"HTMLOptionElement",output:"HTMLOutputElement",p:"HTMLParagraphElement",param:"HTMLParamElement",pre:"HTMLPreElement",progress:"HTMLProgressElement",q:"HTMLQuoteElement",script:"HTMLScriptElement",select:"HTMLSelectElement",source:"HTMLSourceElement",span:"HTMLSpanElement",style:"HTMLStyleElement",caption:"HTMLTableCaptionElement",col:"HTMLTableColElement",table:"HTMLTableElement",tr:"HTMLTableRowElement",thead:"HTMLTableSectionElement",tbody:"HTMLTableSectionElement",textarea:"HTMLTextAreaElement",title:"HTMLTitleElement",ul:"HTMLUListElement",video:"HTMLVideoElement"};Object.keys(c).forEach(b),Object.getOwnPropertyNames(a.wrappers).forEach(function(b){window[b]=a.wrappers[b]}),a.knownElements=c}(this.ShadowDOMPolyfill),function(){var a=window.ShadowDOMPolyfill;a.wrap,Object.defineProperties(HTMLElement.prototype,{webkitShadowRoot:{get:function(){return this.shadowRoot}}}),HTMLElement.prototype.webkitCreateShadowRoot=HTMLElement.prototype.createShadowRoot,window.dartExperimentalFixupGetTag=function(b){function c(a){if(a instanceof d)return"NodeList";if(a instanceof e)return"ShadowRoot";if(a instanceof MutationRecord)return"MutationRecord";if(a instanceof MutationObserver)return"MutationObserver";var c=f(a);if(a!==c){var g=a.constructor;if(g===c.constructor){var h=g._ShadowDOMPolyfill$cacheTag_;return h||(h=Object.prototype.toString.call(c),h=h.substring(8,h.length-1),g._ShadowDOMPolyfill$cacheTag_=h),h}a=c}return b(a)}var d=a.wrappers.NodeList,e=a.wrappers.ShadowRoot,f=a.unwrapIfNeeded;return c}}();var Platform={};!function(a){function b(a,b){var c="";return Array.prototype.forEach.call(a,function(a){c+=a.textContent+"\n\n"}),b||(c=c.replace(m,"")),c}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}function e(a){a&&f().appendChild(document.createTextNode(a))}function f(){return g||(g=document.createElement("style"),g.setAttribute("ShadowCSSShim","")),g}var g,h={strictStyling:!1,registry:{},shimStyling:function(a,b,c){if(a){var d=this.registerDefinition(a,b,c);this.strictStyling&&this.applyScopeToContent(a,b),this.shimPolyfillDirectives(d.rootStyles,b),this.applyShimming(d.scopeStyles,b)}},shimShadowDOMStyling:function(a,b){this.shimPolyfillDirectives(a,b),this.applyShimming(a,b)},registerDefinition:function(a,b,c){var d=this.registry[b]={root:a,name:b,extendsName:c},e=a.querySelectorAll("style");e=e?Array.prototype.slice.call(e,0):[],d.rootStyles=e,d.scopeStyles=d.rootStyles;var f=this.registry[d.extendsName];return f&&(d.scopeStyles=d.scopeStyles.concat(f.scopeStyles)),d},applyScopeToContent:function(a,b){a&&(Array.prototype.forEach.call(a.querySelectorAll("*"),function(a){a.setAttribute(b,"")}),Array.prototype.forEach.call(a.querySelectorAll("template"),function(a){this.applyScopeToContent(a.content,b)},this))},shimPolyfillDirectives:function(a,b){a&&Array.prototype.forEach.call(a,function(a){a.textContent=this.convertPolyfillDirectives(a.textContent,b)},this)},convertPolyfillDirectives:function(a,b){for(var c,d,e="",f=0;c=n.exec(a);)e+=a.substring(f,c.index),d=c[1].slice(0,-2).replace(q,b),e+=this.scopeSelector(d,b)+"{",f=n.lastIndex;return e+=a.substring(f,a.length)},applyShimming:function(a,b){var c=this.shimAtHost(a,b);c+=this.shimScoping(a,b),e(c)},shimAtHost:function(a,b){return a?this.convertAtHostStyles(a,b):void 0},convertAtHostStyles:function(a,e){for(var f,g=b(a),h="",j=0;f=i.exec(g);)h+=g.substring(j,f.index),h+=this.scopeHostCss(f[1],e),j=i.lastIndex;h+=g.substring(j,g.length);var k=new RegExp("^"+e+p,"m"),g=d(this.findAtHostRules(c(h),k));return g},scopeHostCss:function(a,b){for(var c,d="";c=j.exec(a);)d+=this.scopeHostSelector(c[1],b)+" "+c[2]+"\n	";return d},scopeHostSelector:function(a,b){var c=[],d=a.split(","),e="[is="+b+"]";return d.forEach(function(a){a=a.trim(),a.match(k)?a=a.replace(k,b+"$1$3, "+e+"$1$3"):a.match(l)&&(a=b+a+", "+e+a),c.push(a)},this),c.join(", ")},findAtHostRules:function(a,b){return Array.prototype.filter.call(a,this.isHostRule.bind(this,b))},isHostRule:function(a,b){return b.selectorText&&b.selectorText.match(a)||b.cssRules&&this.findAtHostRules(b.cssRules,a).length||b.type==CSSRule.WEBKIT_KEYFRAMES_RULE},shimScoping:function(a,b){return a?this.convertScopedStyles(a,b):void 0},convertScopedStyles:function(a,d){Array.prototype.forEach.call(a,function(a){a.parentNode&&a.parentNode.removeChild(a)});var e=b(a).replace(i,"");e=this.convertPseudos(e);var f=c(e);return e=this.scopeRules(f,d)},convertPseudos:function(a){return a.replace(o," [pseudo=$1]")},scopeRules:function(a,b){var c="";return Array.prototype.forEach.call(a,function(a){a.selectorText&&a.style&&a.style.cssText?(c+=this.scopeSelector(a.selectorText,b,this.strictStyling)+" {\n	",c+=this.propertiesFromRule(a)+"\n}\n\n"):a.media?(c+="@media "+a.media.mediaText+" {\n",c+=this.scopeRules(a.cssRules,b),c+="\n}\n\n"):a.cssText&&(c+=a.cssText+"\n\n")},this),c},scopeSelector:function(a,b,c){var d=[],e=a.split(",");return e.forEach(function(a){a=a.trim(),this.selectorNeedsScoping(a,b)&&(a=c?this.applyStrictSelectorScope(a,b):this.applySimpleSelectorScope(a,b)),d.push(a)},this),d.join(", ")},selectorNeedsScoping:function(a,b){var c="("+b+"|\\[is="+b+"\\])",d=new RegExp("^"+c+p,"m");return!a.match(d)},applySimpleSelectorScope:function(a,b){return b+" "+a+", "+"[is="+b+"] "+a},applyStrictSelectorScope:function(a,b){var c=[" ",">","+","~"],d=a,e="["+b+"]";return c.forEach(function(a){var b=d.split(a);d=b.map(function(a){var b=a.trim();return b&&c.indexOf(b)<0&&b.indexOf(e)<0&&(a=b.replace(/([^:]*)(:*)(.*)/,"$1"+e+"$2$3")),a}).join(a)}),d},propertiesFromRule:function(a){var b=a.style.cssText;return a.style.content&&!a.style.content.match(/['"]+/)&&(b="content: '"+a.style.content+"';\n"+a.style.cssText.replace(/content:[^;]*;/g,"")),b}},i=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,j=/([^{]*)({[\s\S]*?})/gim,k=/(.*)((?:\*)|(?:\:scope))(.*)/,l=/^[.\[:]/,m=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,n=/\/\*\s*@polyfill ([^*]*\*+([^/*][^*]*\*+)*\/)([^{]*?){/gim,o=/::(x-[^\s{,(]*)/gim,p="([>\\s~+[.,{:][\\s\\S]*)?$",q=/@host/gim;if(window.ShadowDOMPolyfill){e("style { display: none !important; }\n");var r=document.querySelector("head");r.insertBefore(f(),r.childNodes[0])}a.ShadowCSS=h}(window.Platform),function(a){function b(a,b){if(window.ShadowDOMPolyfill){for(var h,i=this.convertPolyfillDirectives(a,b),j="",k=0;h=e.exec(i);)j+=i.substring(k,h.index),j+=this.scopeHostCss(h[1],b),k=e.lastIndex;j+=i.substring(k,i.length);var l=new RegExp("^"+b+g,"m"),m=d(this.findAtHostRules(c(j),l));i=i.replace(f,""),i=this.convertPseudos(i);var n=c(i),o=this.scopeRules(n,b);return m+o}}function c(a){var b=document.createElement("style");b.textContent=a,document.head.appendChild(b);var c=b.sheet.cssRules;return b.parentNode.removeChild(b),c}function d(a){for(var b=0,c=[];b<a.length;b++)c.push(a[b].cssText);return c.join("\n\n")}var e=/@host[^{]*{(([^}]*?{[^{]*?}[\s\S]*?)+)}/gim,f=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//gim,g="([>\\s~+[.,{:][\\s\\S]*)?$";a.ShadowCSS.shimShadowDOMStyling2=b}(window.Platform)}
\ No newline at end of file
diff --git a/pkg/shadow_dom/lib/src/platform/patches-shadowdom-polyfill.js b/pkg/shadow_dom/lib/src/platform/patches-shadowdom-polyfill.js
index 828a4fc..57c8c59 100644
--- a/pkg/shadow_dom/lib/src/platform/patches-shadowdom-polyfill.js
+++ b/pkg/shadow_dom/lib/src/platform/patches-shadowdom-polyfill.js
@@ -38,11 +38,9 @@
         // Fix up class names for Firefox.
         // For some of them (like HTMLFormElement and HTMLInputElement),
         // the "constructor" property of the unwrapped nodes points at the
-        // wrapper.
-        // Note: it is safe to check for the GeneratedWrapper string because
-        // we know it is some kind of Shadow DOM wrapper object.
-        var ctor = obj.constructor;
-        if (ctor && ctor.name == 'GeneratedWrapper') {
+        // same constructor as the wrapper.
+        var ctor = obj.constructor
+        if (ctor === unwrapped.constructor) {
           var name = ctor._ShadowDOMPolyfill$cacheTag_;
           if (!name) {
             name = Object.prototype.toString.call(unwrapped);
diff --git a/pkg/shadow_dom/tool/build.sh b/pkg/shadow_dom/tool/build.sh
index 6e2adb7..b10ebe7 100755
--- a/pkg/shadow_dom/tool/build.sh
+++ b/pkg/shadow_dom/tool/build.sh
@@ -11,20 +11,24 @@
 set -e
 
 DIR=$( cd $( dirname "${BASH_SOURCE[0]}" ) && pwd )
-# Note: dartanalyzer and some tests needs to be run from the root directory
 pushd $DIR > /dev/null
 
-SHADOWDOM_REMOTE=https://github.com/dart-lang/ShadowDOM.git
-SHADOWDOM_DIR=../../../third_party/polymer/ShadowDOM
+POLYMER_REMOTE=https://github.com/Polymer
+POLYMER_DIR=../../../third_party/polymer
 
-echo "*** Syncing $SHADOWDOM_DIR from $SHADOWDOM_REMOTE"
-if [ -d "$SHADOWDOM_DIR" ]; then
-  pushd $SHADOWDOM_DIR > /dev/null
-  git pull
-  popd
-else
-  git clone --branch shadowdom_patches $SHADOWDOM_REMOTE $SHADOWDOM_DIR
-fi
+for NAME in ShadowDOM observe-js WeakMap; do
+  GIT_REMOTE="$POLYMER_REMOTE/$NAME.git"
+  GIT_DIR="$POLYMER_DIR/$NAME"
+  echo "*** Syncing $GIT_DIR from $GIT_REMOTE"
+  if [ -d "$GIT_DIR" ]; then
+    pushd $GIT_DIR > /dev/null
+    git remote set-url origin $GIT_REMOTE
+    git pull
+    popd
+  else
+    git clone $GIT_REMOTE $GIT_DIR
+  fi
+done
 
 echo '*** Installing NPM prerequisites'
 npm install
diff --git a/pkg/stack_trace/lib/stack_trace.dart b/pkg/stack_trace/lib/stack_trace.dart
index f031f95..dba95e9 100644
--- a/pkg/stack_trace/lib/stack_trace.dart
+++ b/pkg/stack_trace/lib/stack_trace.dart
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
+ * Stack trace generation and parsing.
+ *
  * ## Installing ##
  *
  * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
diff --git a/pkg/unittest/lib/matcher.dart b/pkg/unittest/lib/matcher.dart
index 09dd7eb..4830b8f 100644
--- a/pkg/unittest/lib/matcher.dart
+++ b/pkg/unittest/lib/matcher.dart
@@ -2,28 +2,21 @@
 // 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.
 /**
- * The matcher library provides a 3rd generation assertion mechanism, drawing
- * inspiration from [Hamcrest](http://code.google.com/p/hamcrest/).
+ * Support for specifying test expectations,
+ * such as for unit tests.
  *
- * ## Installing ##
- *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
- *
- *     dependencies:
- *       unittest: any
- *
- * Then run `pub install`.
- *
- * Import this into your Dart code with:
+ * This library is included in the
+ * [unittest package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/unittest).
+ * Import this library into your Dart code with:
  *
  *     import 'package:unittest/matcher.dart';
  *
- * For more information, see the [unittest package on pub.dartlang.org].
- * (http://pub.dartlang.org/packages/unittest).
- *
- * [pub]: http://pub.dartlang.org
- * [pkg]: http://pub.dartlang.org/packages/matcher
+ * The matcher library provides a third-generation assertion mechanism, drawing
+ * inspiration from [Hamcrest](http://code.google.com/p/hamcrest/).
+ * For more information, see
+ * [Unit Testing with Dart]
+ * (http://www.dartlang.org/articles/dart-unit-tests/).
  */
 library matcher;
 
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index e5923f3..4040870 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -3,38 +3,33 @@
 // BSD-style license that can be found in the LICENSE file.
 
 /**
- * A library for writing dart unit tests.
+ * Support for writing Dart unit tests.
  *
- * ## Installing ##
+ * For information on installing and importing this library, see the
+ * [unittest package on pub.dartlang.org]
+ * (http://pub.dartlang.org/packages/unittest).
  *
- * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
- * file.
+ * **See also:**
+ * [Unit Testing with Dart]
+ * (http://www.dartlang.org/articles/dart-unit-tests/)
  *
- *     dependencies:
- *       unittest: any
- *
- * Then run `pub install`.
- *
- * For more information, see the
- * [unittest package on pub.dartlang.org][pkg].
- *
- * See the [Getting Started](http://pub.dartlang.org/doc)
- * guide for more details.
- *
- * ##Concepts##
+ * ##Concepts
  *
  *  * __Tests__: Tests are specified via the top-level function [test], they can be
  *    organized together using [group].
+ *
  *  * __Checks__: Test expectations can be specified via [expect]
+ *
  *  * __Matchers__: [expect] assertions are written declaratively using the
  *    [Matcher] class.
+ *
  *  * __Configuration__: The framework can be adapted by setting
  *    [unittestConfiguration] with a [Configuration]. See the other libraries
  *    in the `unittest` package for alternative implementations of
  *    [Configuration] including `compact_vm_config.dart`, `html_config.dart` and
  *    `html_enhanced_config.dart`.
  *
- * ##Examples##
+ * ##Examples
  *
  * A trivial test:
  *
@@ -131,15 +126,12 @@
  * Timer.run()], as the Future exception handler may not capture exceptions
  * in such code.
  *
- * Note: due to some language limitations we have to use different functions
+ * Note: Due to some language limitations we have to use different functions
  * depending on the number of positional arguments of the callback. In the
  * future, we plan to expose a single `expectAsync` function that can be used
  * regardless of the number of positional arguments. This requires new langauge
  * features or fixes to the current spec (e.g. see
  * [Issue 2706](http://dartbug.com/2706)).
- *
- * [pub]: http://pub.dartlang.org
- * [pkg]: http://pub.dartlang.org/packages/unittest
  */
 library unittest;
 
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index a2fdf9d..94ca09e 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -918,7 +918,7 @@
 }
 
 
-Dart_CObject* CObject::NewString(int length) {
+Dart_CObject* CObject::NewString(intptr_t length) {
   Dart_CObject* cobject = New(Dart_CObject_kString, length + 1);
   cobject->value.as_string = reinterpret_cast<char*>(cobject + 1);
   return cobject;
@@ -933,7 +933,7 @@
 }
 
 
-Dart_CObject* CObject::NewArray(int length) {
+Dart_CObject* CObject::NewArray(intptr_t length) {
   Dart_CObject* cobject =
       New(Dart_CObject_kArray, length * sizeof(Dart_CObject*));  // NOLINT
   cobject->value.as_array.length = length;
@@ -943,7 +943,7 @@
 }
 
 
-Dart_CObject* CObject::NewUint8Array(int length) {
+Dart_CObject* CObject::NewUint8Array(intptr_t length) {
   Dart_CObject* cobject = New(Dart_CObject_kTypedData, length);
   cobject->value.as_typed_data.type = Dart_TypedData_kUint8;
   cobject->value.as_typed_data.length = length;
@@ -953,7 +953,7 @@
 
 
 Dart_CObject* CObject::NewExternalUint8Array(
-    int64_t length, uint8_t* data, void* peer,
+    intptr_t length, uint8_t* data, void* peer,
     Dart_WeakPersistentHandleFinalizer callback) {
   Dart_CObject* cobject = New(Dart_CObject_kExternalTypedData);
   cobject->value.as_external_typed_data.type = Dart_TypedData_kUint8;
@@ -966,8 +966,16 @@
 
 
 Dart_CObject* CObject::NewIOBuffer(int64_t length) {
+  // Make sure that we do not have an integer overflow here. Actual check
+  // against max elements will be done at the time of writing, as the constant
+  // is not part of the public API.
+  if (length > kIntptrMax) {
+    return NULL;
+  }
   uint8_t* data = IOBuffer::Allocate(length);
-  return NewExternalUint8Array(length, data, data, IOBuffer::Finalizer);
+  ASSERT(data != NULL);
+  return NewExternalUint8Array(
+      static_cast<intptr_t>(length), data, data, IOBuffer::Finalizer);
 }
 
 
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 85b5585..d4fc347 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -271,13 +271,14 @@
   static Dart_CObject* NewIntptr(intptr_t value);
   // TODO(sgjesse): Add support for kBigint.
   static Dart_CObject* NewDouble(double value);
-  static Dart_CObject* NewString(int length);
+  static Dart_CObject* NewString(intptr_t length);
   static Dart_CObject* NewString(const char* str);
-  static Dart_CObject* NewArray(int length);
-  static Dart_CObject* NewUint8Array(int length);
+  static Dart_CObject* NewArray(intptr_t length);
+  static Dart_CObject* NewUint8Array(intptr_t length);
   static Dart_CObject* NewExternalUint8Array(
-      int64_t length, uint8_t* data, void* peer,
+      intptr_t length, uint8_t* data, void* peer,
       Dart_WeakPersistentHandleFinalizer callback);
+
   static Dart_CObject* NewIOBuffer(int64_t length);
   static void FreeIOBufferData(Dart_CObject* object);
 
@@ -452,11 +453,11 @@
  public:
   DECLARE_COBJECT_CONSTRUCTORS(Array)
 
-  int Length() const { return cobject_->value.as_array.length; }
-  CObject* operator[](int index) const {
+  intptr_t Length() const { return cobject_->value.as_array.length; }
+  CObject* operator[](intptr_t index) const {
     return new CObject(cobject_->value.as_array.values[index]);
   }
-  void SetAt(int index, CObject* value) {
+  void SetAt(intptr_t index, CObject* value) {
     cobject_->value.as_array.values[index] = value->AsApiCObject();
   }
 
@@ -480,7 +481,7 @@
   Dart_TypedData_Type Type() const {
     return cobject_->value.as_typed_data.type;
   }
-  int Length() const { return cobject_->value.as_typed_data.length; }
+  intptr_t Length() const { return cobject_->value.as_typed_data.length; }
   uint8_t* Buffer() const { return cobject_->value.as_typed_data.values; }
 
  private:
@@ -492,7 +493,7 @@
  public:
   DECLARE_COBJECT_TYPED_DATA_CONSTRUCTORS(Uint8)
 
-  int Length() const { return cobject_->value.as_typed_data.length; }
+  intptr_t Length() const { return cobject_->value.as_typed_data.length; }
   uint8_t* Buffer() const { return cobject_->value.as_typed_data.values; }
 
  private:
@@ -504,8 +505,10 @@
  public:
   DECLARE_COBJECT_EXTERNAL_TYPED_DATA_CONSTRUCTORS(Uint8)
 
-  int Length() const { return cobject_->value.as_external_typed_data.length; }
-  void SetLength(uint64_t length) {
+  intptr_t Length() const {
+    return cobject_->value.as_external_typed_data.length;
+  }
+  void SetLength(intptr_t length) {
     cobject_->value.as_external_typed_data.length = length;
   }
   uint8_t* Data() const { return cobject_->value.as_external_typed_data.data; }
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index 739e82c..e03a337 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -415,7 +415,7 @@
   res = Dart_GetActivationFrame(trace, 0, &frame);
   ASSERT_NOT_ERROR(res);
   Dart_CodeLocation location;
-  res = Dart_ActivationFrameGetLocation(frame, NULL, &location);
+  res = Dart_ActivationFrameGetLocation(frame, NULL, NULL, &location);
   ASSERT_NOT_ERROR(res);
   if (!Dart_IsNull(location.script_url)) {
     ASSERT(Dart_IsString(location.script_url));
@@ -438,7 +438,7 @@
     ASSERT_NOT_ERROR(res);
     Dart_Handle func_name;
     Dart_CodeLocation location;
-    res = Dart_ActivationFrameGetLocation(frame, &func_name, &location);
+    res = Dart_ActivationFrameGetLocation(frame, &func_name, NULL, &location);
     ASSERT_NOT_ERROR(res);
     ASSERT(Dart_IsString(func_name));
     msg->Printf("%s{\"functionName\":", (i > 0) ? "," : "");
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index 0f771ee..c7b499a 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -26,6 +26,10 @@
   if (current != NULL) {
     Dart_SetReturnValue(args, DartUtils::NewString(current));
     free(current);
+  } else {
+    Dart_Handle err = DartUtils::NewDartOSError();
+    if (Dart_IsError(err)) Dart_PropagateError(err);
+    Dart_SetReturnValue(args, err);
   }
 }
 
diff --git a/runtime/bin/directory_patch.dart b/runtime/bin/directory_patch.dart
index 49eca55..314298d 100644
--- a/runtime/bin/directory_patch.dart
+++ b/runtime/bin/directory_patch.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 patch class _Directory {
-  /* patch */ static String _current() native "Directory_Current";
+  /* patch */ static _current() native "Directory_Current";
   /* patch */ static _setCurrent(path) native "Directory_SetCurrent";
   /* patch */ static _createTemp(String template) native "Directory_CreateTemp";
   /* patch */ static int _exists(String path) native "Directory_Exists";
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 22c7a3a..f5f77bd 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -351,6 +351,7 @@
 
 char* Directory::Current() {
   int length = GetCurrentDirectoryW(0, NULL);
+  if (length == 0) return NULL;
   wchar_t* current = new wchar_t[length + 1];
   GetCurrentDirectoryW(length + 1, current);
   char* result = StringUtils::WideToUtf8(current);
diff --git a/runtime/bin/eventhandler_android.cc b/runtime/bin/eventhandler_android.cc
index 975a6d1..9064be1 100644
--- a/runtime/bin/eventhandler_android.cc
+++ b/runtime/bin/eventhandler_android.cc
@@ -163,6 +163,7 @@
   // WriteToBlocking will write up to 512 bytes atomically, and since our msg
   // is smaller than 512, we don't need a thread lock.
   // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
+  ASSERT(kInterruptMessageSize < PIPE_BUF);
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index e95def6..a14f125 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -168,6 +168,7 @@
   // WriteToBlocking will write up to 512 bytes atomically, and since our msg
   // is smaller than 512, we don't need a thread lock.
   // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
+  ASSERT(kInterruptMessageSize < PIPE_BUF);
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index 20c6b61..8964e3b 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -186,7 +186,7 @@
   msg.data = data;
   // WriteToBlocking will write up to 512 bytes atomically, and since our msg
   // is smaller than 512, we don't need a thread lock.
-  // See: http://linux.die.net/man/7/pipe, section 'Pipe_buf'.
+  ASSERT(kInterruptMessageSize < PIPE_BUF);
   intptr_t result =
       FDUtils::WriteToBlocking(interrupt_fds_[1], &msg, kInterruptMessageSize);
   if (result != kInterruptMessageSize) {
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index bb68071..35ea5fc 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -919,6 +919,7 @@
     if (!file->IsClosed()) {
       int64_t length = CObjectInt32OrInt64ToInt64(request[2]);
       Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
+      ASSERT(io_buffer != NULL);
       uint8_t* data = io_buffer->value.as_external_typed_data.data;
       int64_t bytes_read = file->Read(data, length);
       if (bytes_read >= 0) {
@@ -950,6 +951,7 @@
     if (!file->IsClosed()) {
       int64_t length = CObjectInt32OrInt64ToInt64(request[2]);
       Dart_CObject* io_buffer = CObject::NewIOBuffer(length);
+      ASSERT(io_buffer != NULL);
       uint8_t* data = io_buffer->value.as_external_typed_data.data;
       int64_t bytes_read = file->Read(data, length);
       if (bytes_read >= 0) {
diff --git a/runtime/bin/platform_android.cc b/runtime/bin/platform_android.cc
index e069d5a..dfa2e27 100644
--- a/runtime/bin/platform_android.cc
+++ b/runtime/bin/platform_android.cc
@@ -26,14 +26,6 @@
     perror("Setting signal handler failed");
     return false;
   }
-  // Unblock SIGCHLD as waiting on spawned child process depends
-  // on successful interception of this signal.
-  sigset_t newset;
-  sigemptyset(&newset);
-  sigaddset(&newset, SIGCHLD);
-  if (sigprocmask(SIG_UNBLOCK, &newset, NULL) != 0) {
-    perror("Unblocking SIGCHLD signal failed");
-  }
   return true;
 }
 
diff --git a/runtime/bin/platform_linux.cc b/runtime/bin/platform_linux.cc
index 4a70ee5..af557af 100644
--- a/runtime/bin/platform_linux.cc
+++ b/runtime/bin/platform_linux.cc
@@ -26,14 +26,6 @@
     perror("Setting signal handler failed");
     return false;
   }
-  // Unblock SIGCHLD as waiting on spawned child process depends
-  // on successful interception of this signal.
-  sigset_t newset;
-  sigemptyset(&newset);
-  sigaddset(&newset, SIGCHLD);
-  if (sigprocmask(SIG_UNBLOCK, &newset, NULL) != 0) {
-    perror("Unblocking SIGCHLD signal failed");
-  }
   return true;
 }
 
diff --git a/runtime/bin/platform_macos.cc b/runtime/bin/platform_macos.cc
index e1b914b..0576c34 100644
--- a/runtime/bin/platform_macos.cc
+++ b/runtime/bin/platform_macos.cc
@@ -27,15 +27,6 @@
     perror("Setting signal handler failed");
     return false;
   }
-  // Unblock SIGCHLD as waiting on spawned child process depends
-  // on successful interception of this signal.
-  sigset_t newset;
-  sigemptyset(&newset);
-  sigaddset(&newset, SIGCHLD);
-  if (sigprocmask(SIG_UNBLOCK, &newset, NULL) != 0) {
-    perror("Unblocking SIGCHLD signal failed");
-  }
-
   return true;
 }
 
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index fd97e7a..378b9ba 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -10,7 +10,6 @@
 #include <errno.h>  // NOLINT
 #include <fcntl.h>  // NOLINT
 #include <poll.h>  // NOLINT
-#include <signal.h>  // NOLINT
 #include <stdio.h>  // NOLINT
 #include <stdlib.h>  // NOLINT
 #include <string.h>  // NOLINT
@@ -111,161 +110,121 @@
 dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
 
 
-// The exit code handler sets up a separate thread which is signalled
-// on SIGCHLD. That separate thread can then get the exit code from
+// The exit code handler sets up a separate thread which waits for child
+// processes to terminate. That separate thread can then get the exit code from
 // processes that have exited and communicate it to Dart through the
 // event loop.
 class ExitCodeHandler {
  public:
-  // Ensure that the ExitCodeHandler has been initialized.
-  static bool EnsureInitialized() {
+  // Notify the ExitCodeHandler that another process exists.
+  static void ProcessStarted() {
     // Multiple isolates could be starting processes at the same
-    // time. Make sure that only one of them initializes the
-    // ExitCodeHandler.
-    MutexLocker locker(mutex_);
-    if (initialized_) {
-      return true;
+    // time. Make sure that only one ExitCodeHandler thread exists.
+    MonitorLocker locker(monitor_);
+    process_count_++;
+
+    monitor_->Notify();
+
+    if (running_) {
+      return;
     }
 
-    // Allocate a pipe that the signal handler can write a byte to and
-    // that the exit handler thread can poll.
-    int result = TEMP_FAILURE_RETRY(pipe(sig_chld_fds_));
-    if (result < 0) {
-      return false;
-    }
-    FDUtils::SetCloseOnExec(sig_chld_fds_[0]);
-    FDUtils::SetCloseOnExec(sig_chld_fds_[1]);
-
-    // Start thread that polls the pipe and handles process exits when
-    // data is received on the pipe.
-    result = dart::Thread::Start(ExitCodeHandlerEntry, sig_chld_fds_[0]);
+    // Start thread that handles process exits when wait returns.
+    int result = dart::Thread::Start(ExitCodeHandlerEntry, 0);
     if (result != 0) {
       FATAL1("Failed to start exit code handler worker thread %d", result);
     }
 
-    // Mark write end non-blocking.
-    FDUtils::SetNonBlocking(sig_chld_fds_[1]);
-
-    // Thread started and the ExitCodeHandler is initialized.
-    initialized_ = true;
-    return true;
-  }
-
-  // Get the write end of the pipe.
-  static int WakeUpFd() {
-    return sig_chld_fds_[1];
+    running_ = true;
   }
 
   static void TerminateExitCodeThread() {
-    MutexLocker locker(mutex_);
-    if (!initialized_) {
+    MonitorLocker locker(monitor_);
+
+    if (!running_) {
       return;
     }
 
-    uint8_t data = kThreadTerminateByte;
-    ssize_t result =
-        TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), &data, 1));
-    if (result < 1) {
-      perror("Failed to write to wake-up fd to terminate exit code thread");
+    // Set terminate_done_ to false, so we can use it as a guard for our
+    // monitor.
+    running_ = false;
+
+    // Fork to wake up waitpid.
+    if (TEMP_FAILURE_RETRY(fork()) == 0) {
+      exit(0);
     }
 
-    {
-      MonitorLocker terminate_locker(thread_terminate_monitor_);
-      while (!thread_terminated_) {
-        terminate_locker.Wait();
-      }
-    }
-  }
+    monitor_->Notify();
 
-  static void ExitCodeThreadTerminated() {
-    MonitorLocker locker(thread_terminate_monitor_);
-    thread_terminated_ = true;
-    locker.Notify();
+    while (!terminate_done_) {
+      monitor_->Wait(dart::Monitor::kNoTimeout);
+    }
   }
 
  private:
-  static const uint8_t kThreadTerminateByte = 1;
-
-  // GetProcessExitCodes is called on a separate thread when a SIGCHLD
-  // signal is received to retrieve the exit codes and post them to
-  // dart.
-  static void GetProcessExitCodes() {
-    pid_t pid = 0;
-    int status = 0;
-    while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
-      int exit_code = 0;
-      int negative = 0;
-      if (WIFEXITED(status)) {
-        exit_code = WEXITSTATUS(status);
-      }
-      if (WIFSIGNALED(status)) {
-        exit_code = WTERMSIG(status);
-        negative = 1;
-      }
-      intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
-      if (exit_code_fd != 0) {
-        int message[2] = { exit_code, negative };
-        ssize_t result =
-            FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
-        // If the process has been closed, the read end of the exit
-        // pipe has been closed. It is therefore not a problem that
-        // write fails with a broken pipe error. Other errors should
-        // not happen.
-        if (result != -1 && result != sizeof(message)) {
-          FATAL("Failed to write entire process exit message");
-        } else if (result == -1 && errno != EPIPE) {
-          FATAL1("Failed to write exit code: %d", errno);
-        }
-        ProcessInfoList::RemoveProcess(pid);
-      }
-    }
-  }
-
-
   // Entry point for the separate exit code handler thread started by
   // the ExitCodeHandler.
   static void ExitCodeHandlerEntry(uword param) {
-    struct pollfd pollfds;
-    pollfds.fd = param;
-    pollfds.events = POLLIN;
+    pid_t pid = 0;
+    int status = 0;
     while (true) {
-      int result = TEMP_FAILURE_RETRY(poll(&pollfds, 1, -1));
-      if (result == -1) {
-        ASSERT(EAGAIN == EWOULDBLOCK);
-        if (errno != EWOULDBLOCK) {
-          perror("ExitCodeHandler poll failed");
+      {
+        MonitorLocker locker(monitor_);
+        while (running_ && process_count_ == 0) {
+          monitor_->Wait(dart::Monitor::kNoTimeout);
         }
-      } else {
-        // Read the byte from the wake-up fd.
-        ASSERT(result = 1);
-        intptr_t data = 0;
-        ssize_t read_bytes = FDUtils::ReadFromBlocking(pollfds.fd, &data, 1);
-        if (read_bytes < 1) {
-          perror("Failed to read from wake-up fd in exit-code handler");
-        }
-        if (data == ExitCodeHandler::kThreadTerminateByte) {
-          ExitCodeThreadTerminated();
+        if (!running_) {
+          terminate_done_ = true;
+          monitor_->Notify();
           return;
         }
-        // Get the exit code from all processes that have died.
-        GetProcessExitCodes();
+      }
+
+      if ((pid = TEMP_FAILURE_RETRY(wait(&status))) > 0) {
+        int exit_code = 0;
+        int negative = 0;
+        if (WIFEXITED(status)) {
+          exit_code = WEXITSTATUS(status);
+        }
+        if (WIFSIGNALED(status)) {
+          exit_code = WTERMSIG(status);
+          negative = 1;
+        }
+        intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
+        if (exit_code_fd != 0) {
+          int message[2] = { exit_code, negative };
+          ssize_t result =
+              FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
+          // If the process has been closed, the read end of the exit
+          // pipe has been closed. It is therefore not a problem that
+          // write fails with a broken pipe error. Other errors should
+          // not happen.
+          if (result != -1 && result != sizeof(message)) {
+            FATAL("Failed to write entire process exit message");
+          } else if (result == -1 && errno != EPIPE) {
+            FATAL1("Failed to write exit code: %d", errno);
+          }
+          ProcessInfoList::RemoveProcess(pid);
+          {
+            MonitorLocker locker(monitor_);
+            process_count_--;
+          }
+        }
       }
     }
   }
 
-  static dart::Mutex* mutex_;
-  static bool initialized_;
-  static int sig_chld_fds_[2];
-  static bool thread_terminated_;
-  static dart::Monitor* thread_terminate_monitor_;
+  static bool terminate_done_;
+  static int process_count_;
+  static bool running_;
+  static dart::Monitor* monitor_;
 };
 
 
-dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
-bool ExitCodeHandler::initialized_ = false;
-int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
-bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
+bool ExitCodeHandler::running_ = false;
+int ExitCodeHandler::process_count_ = 0;
+bool ExitCodeHandler::terminate_done_ = false;
+dart::Monitor* ExitCodeHandler::monitor_ = new dart::Monitor();
 
 
 static void SetChildOsErrorMessage(char** os_error_message) {
@@ -276,21 +235,6 @@
 }
 
 
-static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) {
-  // Save errno so it can be restored at the end.
-  int entry_errno = errno;
-  // Signal the exit code handler where the actual processing takes
-  // place.
-  ssize_t result =
-      TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1));
-  if (result < 1) {
-    perror("Failed to write to wake-up fd in SIGCHLD handler");
-  }
-  // Restore errno.
-  errno = entry_errno;
-}
-
-
 static void ReportChildError(int exec_control_fd) {
   // In the case of failure in the child process write the errno and
   // the OS error message to the exec control pipe and exit.
@@ -330,14 +274,6 @@
   int exec_control[2];  // Pipe to get the result from exec.
   int result;
 
-  bool initialized = ExitCodeHandler::EnsureInitialized();
-  if (!initialized) {
-    SetChildOsErrorMessage(os_error_message);
-    Log::PrintErr("Error initializing exit code handler: %s\n",
-                  *os_error_message);
-    return errno;
-  }
-
   result = TEMP_FAILURE_RETRY(pipe(read_in));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -413,13 +349,6 @@
     program_environment[environment_length] = NULL;
   }
 
-  struct sigaction act;
-  bzero(&act, sizeof(act));
-  act.sa_sigaction = SigChldHandler;
-  act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
-  if (sigaction(SIGCHLD, &act, 0) != 0) {
-    perror("Process start: setting signal handler failed");
-  }
   pid = TEMP_FAILURE_RETRY(fork());
   if (pid < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -477,6 +406,9 @@
     ReportChildError(exec_control[1]);
   }
 
+  // Be sure to listen for exit-codes, now we have a child-process.
+  ExitCodeHandler::ProcessStarted();
+
   // The arguments and environment for the spawned process are not needed
   // any longer.
   delete[] program_arguments;
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index adf5cd4..95d11cd 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -10,7 +10,6 @@
 #include <errno.h>  // NOLINT
 #include <fcntl.h>  // NOLINT
 #include <poll.h>  // NOLINT
-#include <signal.h>  // NOLINT
 #include <stdio.h>  // NOLINT
 #include <stdlib.h>  // NOLINT
 #include <string.h>  // NOLINT
@@ -111,161 +110,121 @@
 dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
 
 
-// The exit code handler sets up a separate thread which is signalled
-// on SIGCHLD. That separate thread can then get the exit code from
+// The exit code handler sets up a separate thread which waits for child
+// processes to terminate. That separate thread can then get the exit code from
 // processes that have exited and communicate it to Dart through the
 // event loop.
 class ExitCodeHandler {
  public:
-  // Ensure that the ExitCodeHandler has been initialized.
-  static bool EnsureInitialized() {
+  // Notify the ExitCodeHandler that another process exists.
+  static void ProcessStarted() {
     // Multiple isolates could be starting processes at the same
-    // time. Make sure that only one of them initializes the
-    // ExitCodeHandler.
-    MutexLocker locker(mutex_);
-    if (initialized_) {
-      return true;
+    // time. Make sure that only one ExitCodeHandler thread exists.
+    MonitorLocker locker(monitor_);
+    process_count_++;
+
+    monitor_->Notify();
+
+    if (running_) {
+      return;
     }
 
-    // Allocate a pipe that the signal handler can write a byte to and
-    // that the exit handler thread can poll.
-    int result = TEMP_FAILURE_RETRY(pipe(sig_chld_fds_));
-    if (result < 0) {
-      return false;
-    }
-    FDUtils::SetCloseOnExec(sig_chld_fds_[0]);
-    FDUtils::SetCloseOnExec(sig_chld_fds_[1]);
-
-    // Start thread that polls the pipe and handles process exits when
-    // data is received on the pipe.
-    result = dart::Thread::Start(ExitCodeHandlerEntry, sig_chld_fds_[0]);
+    // Start thread that handles process exits when wait returns.
+    int result = dart::Thread::Start(ExitCodeHandlerEntry, 0);
     if (result != 0) {
       FATAL1("Failed to start exit code handler worker thread %d", result);
     }
 
-    // Mark write end non-blocking.
-    FDUtils::SetNonBlocking(sig_chld_fds_[1]);
-
-    // Thread started and the ExitCodeHandler is initialized.
-    initialized_ = true;
-    return true;
-  }
-
-  // Get the write end of the pipe.
-  static int WakeUpFd() {
-    return sig_chld_fds_[1];
+    running_ = true;
   }
 
   static void TerminateExitCodeThread() {
-    MutexLocker locker(mutex_);
-    if (!initialized_) {
+    MonitorLocker locker(monitor_);
+
+    if (!running_) {
       return;
     }
 
-    uint8_t data = kThreadTerminateByte;
-    ssize_t result =
-        TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), &data, 1));
-    if (result < 1) {
-      perror("Failed to write to wake-up fd to terminate exit code thread");
+    // Set terminate_done_ to false, so we can use it as a guard for our
+    // monitor.
+    running_ = false;
+
+    // Fork to wake up waitpid.
+    if (TEMP_FAILURE_RETRY(fork()) == 0) {
+      exit(0);
     }
 
-    {
-      MonitorLocker terminate_locker(thread_terminate_monitor_);
-      while (!thread_terminated_) {
-        terminate_locker.Wait();
-      }
-    }
-  }
+    monitor_->Notify();
 
-  static void ExitCodeThreadTerminated() {
-    MonitorLocker locker(thread_terminate_monitor_);
-    thread_terminated_ = true;
-    locker.Notify();
+    while (!terminate_done_) {
+      monitor_->Wait(dart::Monitor::kNoTimeout);
+    }
   }
 
  private:
-  static const uint8_t kThreadTerminateByte = 1;
-
-  // GetProcessExitCodes is called on a separate thread when a SIGCHLD
-  // signal is received to retrieve the exit codes and post them to
-  // dart.
-  static void GetProcessExitCodes() {
-    pid_t pid = 0;
-    int status = 0;
-    while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
-      int exit_code = 0;
-      int negative = 0;
-      if (WIFEXITED(status)) {
-        exit_code = WEXITSTATUS(status);
-      }
-      if (WIFSIGNALED(status)) {
-        exit_code = WTERMSIG(status);
-        negative = 1;
-      }
-      intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
-      if (exit_code_fd != 0) {
-        int message[2] = { exit_code, negative };
-        ssize_t result =
-            FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
-        // If the process has been closed, the read end of the exit
-        // pipe has been closed. It is therefore not a problem that
-        // write fails with a broken pipe error. Other errors should
-        // not happen.
-        if (result != -1 && result != sizeof(message)) {
-          FATAL("Failed to write entire process exit message");
-        } else if (result == -1 && errno != EPIPE) {
-          FATAL1("Failed to write exit code: %d", errno);
-        }
-        ProcessInfoList::RemoveProcess(pid);
-      }
-    }
-  }
-
-
   // Entry point for the separate exit code handler thread started by
   // the ExitCodeHandler.
   static void ExitCodeHandlerEntry(uword param) {
-    struct pollfd pollfds;
-    pollfds.fd = param;
-    pollfds.events = POLLIN;
+    pid_t pid = 0;
+    int status = 0;
     while (true) {
-      int result = TEMP_FAILURE_RETRY(poll(&pollfds, 1, -1));
-      if (result == -1) {
-        ASSERT(EAGAIN == EWOULDBLOCK);
-        if (errno != EWOULDBLOCK) {
-          perror("ExitCodeHandler poll failed");
+      {
+        MonitorLocker locker(monitor_);
+        while (running_ && process_count_ == 0) {
+          monitor_->Wait(dart::Monitor::kNoTimeout);
         }
-      } else {
-        // Read the byte from the wake-up fd.
-        ASSERT(result = 1);
-        intptr_t data = 0;
-        ssize_t read_bytes = FDUtils::ReadFromBlocking(pollfds.fd, &data, 1);
-        if (read_bytes < 1) {
-          perror("Failed to read from wake-up fd in exit-code handler");
-        }
-        if (data == ExitCodeHandler::kThreadTerminateByte) {
-          ExitCodeThreadTerminated();
+        if (!running_) {
+          terminate_done_ = true;
+          monitor_->Notify();
           return;
         }
-        // Get the exit code from all processes that have died.
-        GetProcessExitCodes();
+      }
+
+      if ((pid = TEMP_FAILURE_RETRY(wait(&status))) > 0) {
+        int exit_code = 0;
+        int negative = 0;
+        if (WIFEXITED(status)) {
+          exit_code = WEXITSTATUS(status);
+        }
+        if (WIFSIGNALED(status)) {
+          exit_code = WTERMSIG(status);
+          negative = 1;
+        }
+        intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
+        if (exit_code_fd != 0) {
+          int message[2] = { exit_code, negative };
+          ssize_t result =
+              FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
+          // If the process has been closed, the read end of the exit
+          // pipe has been closed. It is therefore not a problem that
+          // write fails with a broken pipe error. Other errors should
+          // not happen.
+          if (result != -1 && result != sizeof(message)) {
+            FATAL("Failed to write entire process exit message");
+          } else if (result == -1 && errno != EPIPE) {
+            FATAL1("Failed to write exit code: %d", errno);
+          }
+          ProcessInfoList::RemoveProcess(pid);
+          {
+            MonitorLocker locker(monitor_);
+            process_count_--;
+          }
+        }
       }
     }
   }
 
-  static dart::Mutex* mutex_;
-  static bool initialized_;
-  static int sig_chld_fds_[2];
-  static bool thread_terminated_;
-  static dart::Monitor* thread_terminate_monitor_;
+  static bool terminate_done_;
+  static int process_count_;
+  static bool running_;
+  static dart::Monitor* monitor_;
 };
 
 
-dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
-bool ExitCodeHandler::initialized_ = false;
-int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
-bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
+bool ExitCodeHandler::running_ = false;
+int ExitCodeHandler::process_count_ = 0;
+bool ExitCodeHandler::terminate_done_ = false;
+dart::Monitor* ExitCodeHandler::monitor_ = new dart::Monitor();
 
 
 static void SetChildOsErrorMessage(char** os_error_message) {
@@ -275,21 +234,6 @@
 }
 
 
-static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) {
-  // Save errno so it can be restored at the end.
-  int entry_errno = errno;
-  // Signal the exit code handler where the actual processing takes
-  // place.
-  ssize_t result =
-      TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1));
-  if (result < 1) {
-    perror("Failed to write to wake-up fd in SIGCHLD handler");
-  }
-  // Restore errno.
-  errno = entry_errno;
-}
-
-
 static void ReportChildError(int exec_control_fd) {
   // In the case of failure in the child process write the errno and
   // the OS error message to the exec control pipe and exit.
@@ -329,14 +273,6 @@
   int exec_control[2];  // Pipe to get the result from exec.
   int result;
 
-  bool initialized = ExitCodeHandler::EnsureInitialized();
-  if (!initialized) {
-    SetChildOsErrorMessage(os_error_message);
-    Log::PrintErr("Error initializing exit code handler: %s\n",
-                  *os_error_message);
-    return errno;
-  }
-
   result = TEMP_FAILURE_RETRY(pipe(read_in));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -412,13 +348,6 @@
     program_environment[environment_length] = NULL;
   }
 
-  struct sigaction act;
-  bzero(&act, sizeof(act));
-  act.sa_sigaction = SigChldHandler;
-  act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
-  if (sigaction(SIGCHLD, &act, 0) != 0) {
-    perror("Process start: setting signal handler failed");
-  }
   pid = TEMP_FAILURE_RETRY(fork());
   if (pid < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -476,6 +405,9 @@
     ReportChildError(exec_control[1]);
   }
 
+  // Be sure to listen for exit-codes, now we have a child-process.
+  ExitCodeHandler::ProcessStarted();
+
   // The arguments and environment for the spawned process are not needed
   // any longer.
   delete[] program_arguments;
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index 1a15a39..edb222a 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -109,161 +109,121 @@
 dart::Mutex* ProcessInfoList::mutex_ = new dart::Mutex();
 
 
-// The exit code handler sets up a separate thread which is signalled
-// on SIGCHLD. That separate thread can then get the exit code from
+// The exit code handler sets up a separate thread which waits for child
+// processes to terminate. That separate thread can then get the exit code from
 // processes that have exited and communicate it to Dart through the
 // event loop.
 class ExitCodeHandler {
  public:
-  // Ensure that the ExitCodeHandler has been initialized.
-  static bool EnsureInitialized() {
+  // Notify the ExitCodeHandler that another process exists.
+  static void ProcessStarted() {
     // Multiple isolates could be starting processes at the same
-    // time. Make sure that only one of them initializes the
-    // ExitCodeHandler.
-    MutexLocker locker(mutex_);
-    if (initialized_) {
-      return true;
+    // time. Make sure that only one ExitCodeHandler thread exists.
+    MonitorLocker locker(monitor_);
+    process_count_++;
+
+    monitor_->Notify();
+
+    if (running_) {
+      return;
     }
 
-    // Allocate a pipe that the signal handler can write a byte to and
-    // that the exit handler thread can poll.
-    int result = TEMP_FAILURE_RETRY(pipe(sig_chld_fds_));
-    if (result < 0) {
-      return false;
-    }
-    FDUtils::SetCloseOnExec(sig_chld_fds_[0]);
-    FDUtils::SetCloseOnExec(sig_chld_fds_[1]);
-
-    // Start thread that polls the pipe and handles process exits when
-    // data is received on the pipe.
-    result = dart::Thread::Start(ExitCodeHandlerEntry, sig_chld_fds_[0]);
+    // Start thread that handles process exits when wait returns.
+    int result = dart::Thread::Start(ExitCodeHandlerEntry, 0);
     if (result != 0) {
       FATAL1("Failed to start exit code handler worker thread %d", result);
     }
 
-    // Mark write end non-blocking.
-    FDUtils::SetNonBlocking(sig_chld_fds_[1]);
-
-    // Thread started and the ExitCodeHandler is initialized.
-    initialized_ = true;
-    return true;
-  }
-
-  // Get the write end of the pipe.
-  static int WakeUpFd() {
-    return sig_chld_fds_[1];
+    running_ = true;
   }
 
   static void TerminateExitCodeThread() {
-    MutexLocker locker(mutex_);
-    if (!initialized_) {
+    MonitorLocker locker(monitor_);
+
+    if (!running_) {
       return;
     }
 
-    uint8_t data = kThreadTerminateByte;
-    ssize_t result =
-        TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), &data, 1));
-    if (result < 1) {
-      perror("Failed to write to wake-up fd to terminate exit code thread");
+    // Set terminate_done_ to false, so we can use it as a guard for our
+    // monitor.
+    running_ = false;
+
+    // Fork to wake up waitpid.
+    if (TEMP_FAILURE_RETRY(fork()) == 0) {
+      exit(0);
     }
 
-    {
-      MonitorLocker terminate_locker(thread_terminate_monitor_);
-      while (!thread_terminated_) {
-        terminate_locker.Wait();
-      }
-    }
-  }
+    monitor_->Notify();
 
-  static void ExitCodeThreadTerminated() {
-    MonitorLocker locker(thread_terminate_monitor_);
-    thread_terminated_ = true;
-    locker.Notify();
+    while (!terminate_done_) {
+      monitor_->Wait(dart::Monitor::kNoTimeout);
+    }
   }
 
  private:
-  static const uint8_t kThreadTerminateByte = 1;
-
-  // GetProcessExitCodes is called on a separate thread when a SIGCHLD
-  // signal is received to retrieve the exit codes and post them to
-  // dart.
-  static void GetProcessExitCodes() {
-    pid_t pid = 0;
-    int status = 0;
-    while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
-      int exit_code = 0;
-      int negative = 0;
-      if (WIFEXITED(status)) {
-        exit_code = WEXITSTATUS(status);
-      }
-      if (WIFSIGNALED(status)) {
-        exit_code = WTERMSIG(status);
-        negative = 1;
-      }
-      intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
-      if (exit_code_fd != 0) {
-        int message[2] = { exit_code, negative };
-        ssize_t result =
-            FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
-        // If the process has been closed, the read end of the exit
-        // pipe has been closed. It is therefore not a problem that
-        // writennnj fails with a broken pipe error. Other errors should
-        // not happen.
-        if (result != -1 && result != sizeof(message)) {
-          FATAL("Failed to write entire process exit message");
-        } else if (result == -1 && errno != EPIPE) {
-          FATAL1("Failed to write exit code: %d", errno);
-        }
-        ProcessInfoList::RemoveProcess(pid);
-      }
-    }
-  }
-
-
   // Entry point for the separate exit code handler thread started by
   // the ExitCodeHandler.
   static void ExitCodeHandlerEntry(uword param) {
-    struct pollfd pollfds;
-    pollfds.fd = param;
-    pollfds.events = POLLIN;
+    pid_t pid = 0;
+    int status = 0;
     while (true) {
-      int result = TEMP_FAILURE_RETRY(poll(&pollfds, 1, -1));
-      if (result == -1) {
-        ASSERT(EAGAIN == EWOULDBLOCK);
-        if (errno != EWOULDBLOCK) {
-          perror("ExitCodeHandler poll failed");
+      {
+        MonitorLocker locker(monitor_);
+        while (running_ && process_count_ == 0) {
+          monitor_->Wait(dart::Monitor::kNoTimeout);
         }
-      } else {
-        // Read the byte from the wake-up fd.
-        ASSERT(result = 1);
-        intptr_t data = 0;
-        ssize_t read_bytes = FDUtils::ReadFromBlocking(pollfds.fd, &data, 1);
-        if (read_bytes < 1) {
-          perror("Failed to read from wake-up fd in exit-code handler");
-        }
-        if (data == ExitCodeHandler::kThreadTerminateByte) {
-          ExitCodeThreadTerminated();
+        if (!running_) {
+          terminate_done_ = true;
+          monitor_->Notify();
           return;
         }
-        // Get the exit code from all processes that have died.
-        GetProcessExitCodes();
+      }
+
+      if ((pid = TEMP_FAILURE_RETRY(wait(&status))) > 0) {
+        int exit_code = 0;
+        int negative = 0;
+        if (WIFEXITED(status)) {
+          exit_code = WEXITSTATUS(status);
+        }
+        if (WIFSIGNALED(status)) {
+          exit_code = WTERMSIG(status);
+          negative = 1;
+        }
+        intptr_t exit_code_fd = ProcessInfoList::LookupProcessExitFd(pid);
+        if (exit_code_fd != 0) {
+          int message[2] = { exit_code, negative };
+          ssize_t result =
+              FDUtils::WriteToBlocking(exit_code_fd, &message, sizeof(message));
+          // If the process has been closed, the read end of the exit
+          // pipe has been closed. It is therefore not a problem that
+          // write fails with a broken pipe error. Other errors should
+          // not happen.
+          if (result != -1 && result != sizeof(message)) {
+            FATAL("Failed to write entire process exit message");
+          } else if (result == -1 && errno != EPIPE) {
+            FATAL1("Failed to write exit code: %d", errno);
+          }
+          ProcessInfoList::RemoveProcess(pid);
+          {
+            MonitorLocker locker(monitor_);
+            process_count_--;
+          }
+        }
       }
     }
   }
 
-  static dart::Mutex* mutex_;
-  static bool initialized_;
-  static int sig_chld_fds_[2];
-  static bool thread_terminated_;
-  static dart::Monitor* thread_terminate_monitor_;
+  static bool terminate_done_;
+  static int process_count_;
+  static bool running_;
+  static dart::Monitor* monitor_;
 };
 
 
-dart::Mutex* ExitCodeHandler::mutex_ = new dart::Mutex();
-bool ExitCodeHandler::initialized_ = false;
-int ExitCodeHandler::sig_chld_fds_[2] = { 0, 0 };
-bool ExitCodeHandler::thread_terminated_ = false;
-dart::Monitor* ExitCodeHandler::thread_terminate_monitor_ = new dart::Monitor();
+bool ExitCodeHandler::running_ = false;
+int ExitCodeHandler::process_count_ = 0;
+bool ExitCodeHandler::terminate_done_ = false;
+dart::Monitor* ExitCodeHandler::monitor_ = new dart::Monitor();
 
 
 static void SetChildOsErrorMessage(char** os_error_message) {
@@ -274,21 +234,6 @@
 }
 
 
-static void SigChldHandler(int process_signal, siginfo_t* siginfo, void* tmp) {
-  // Save errno so it can be restored at the end.
-  int entry_errno = errno;
-  // Signal the exit code handler where the actual processing takes
-  // place.
-  ssize_t result =
-      TEMP_FAILURE_RETRY(write(ExitCodeHandler::WakeUpFd(), "", 1));
-  if (result < 1) {
-    perror("Failed to write to wake-up fd in SIGCHLD handler");
-  }
-  // Restore errno.
-  errno = entry_errno;
-}
-
-
 static void ReportChildError(int exec_control_fd) {
   // In the case of failure in the child process write the errno and
   // the OS error message to the exec control pipe and exit.
@@ -328,14 +273,6 @@
   int exec_control[2];  // Pipe to get the result from exec.
   int result;
 
-  bool initialized = ExitCodeHandler::EnsureInitialized();
-  if (!initialized) {
-    SetChildOsErrorMessage(os_error_message);
-    Log::PrintErr("Error initializing exit code handler: %s\n",
-                       *os_error_message);
-    return errno;
-  }
-
   result = TEMP_FAILURE_RETRY(pipe(read_in));
   if (result < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -411,13 +348,6 @@
     program_environment[environment_length] = NULL;
   }
 
-  struct sigaction act;
-  bzero(&act, sizeof(act));
-  act.sa_sigaction = SigChldHandler;
-  act.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
-  if (sigaction(SIGCHLD, &act, 0) != 0) {
-    perror("Process start: setting signal handler failed");
-  }
   pid = TEMP_FAILURE_RETRY(fork());
   if (pid < 0) {
     SetChildOsErrorMessage(os_error_message);
@@ -475,6 +405,9 @@
     ReportChildError(exec_control[1]);
   }
 
+  // Be sure to listen for exit-codes, now we have a child-process.
+  ExitCodeHandler::ProcessStarted();
+
   // The arguments and environment for the spawned process are not needed
   // any longer.
   delete[] program_arguments;
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 441e75b..e0e8fc6 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -323,7 +323,7 @@
         _exitHandler._nativeSocket);
 
     getOutput(output, encoding) {
-      if (stderrEncoding == null) return output;
+      if (encoding == null) return output;
       return encoding.decode(output);
     }
 
diff --git a/runtime/include/dart_debugger_api.h b/runtime/include/dart_debugger_api.h
index 50bf9f0..bd47064 100755
--- a/runtime/include/dart_debugger_api.h
+++ b/runtime/include/dart_debugger_api.h
@@ -390,7 +390,7 @@
 
 
 /**
- * DEPRECATED -- Use Dart_ActivationframeGetLocation instead.
+ * DEPRECATED -- Use Dart_ActivationFrameGetLocation instead.
  *
  * Returns information about the given activation frame.
  * \function_name receives a string handle with the qualified
@@ -420,6 +420,7 @@
  *
  * \function_name receives a string handle with the qualified
  *    function name.
+ * \function receives a handle to the function.
  * \location.script_url receives a string handle with the url of
  *    the source script that contains the frame's function.
  *    Receives a null handle if there is no textual location
@@ -440,6 +441,7 @@
 DART_EXPORT Dart_Handle Dart_ActivationFrameGetLocation(
                             Dart_ActivationFrame activation_frame,
                             Dart_Handle* function_name,
+                            Dart_Handle* function,
                             Dart_CodeLocation* location);
 
 
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index 7691d5c..cdfc5df 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -53,17 +53,17 @@
     char* as_string;
     char* as_bigint;
     struct {
-      int length;
+      intptr_t length;
       struct _Dart_CObject** values;
     } as_array;
     struct {
       Dart_TypedData_Type type;
-      int length;
+      intptr_t length;
       uint8_t* values;
     } as_typed_data;
     struct {
       Dart_TypedData_Type type;
-      int length;
+      intptr_t length;
       uint8_t* data;
       void* peer;
       Dart_WeakPersistentHandleFinalizer callback;
diff --git a/runtime/lib/collection_patch.dart b/runtime/lib/collection_patch.dart
index 3b3bcc0..3716cca 100644
--- a/runtime/lib/collection_patch.dart
+++ b/runtime/lib/collection_patch.dart
@@ -4,27 +4,39 @@
 
 patch class HashMap<K, V> {
   /* patch */ factory HashMap({ bool equals(K key1, K key2),
-                                int hashCode(K key) }) {
-    if (hashCode == null) {
+                                int hashCode(K key),
+                                bool isValidKey(potentialKey) }) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _HashMap<K, V>();
+        }
+        if (identical(identical, equals)) {
+          return new _IdentityHashMap<K, V>();
+        }
+        hashCode = _defaultHashCode;
+      } else if (equals == null) {
+        equals = _defaultEquals;
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
       if (equals == null) {
-        return new _HashMapImpl<K, V>();
+        equals = _defaultEquals;
       }
-      if (identical(identical, equals)) {
-        return new _IdentityHashMap<K, V>();
-      }
-      hashCode = _defaultHashCode;
-    } else if (equals == null) {
-      equals = _defaultEquals;
     }
-    return new _CustomHashMap<K, V>(equals, hashCode);
+    return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);
   }
 }
 
 const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
 
-class _HashMapImpl<K, V> implements HashMap<K, V> {
+class _HashMap<K, V> implements HashMap<K, V> {
   static const int _INITIAL_CAPACITY = 8;
 
+  Type get runtimeType => HashMap;
+
   int _elementCount = 0;
   List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
   int _modificationCount = 0;
@@ -144,11 +156,7 @@
     while (entry != null) {
       _HashMapEntry next = entry.next;
       if (hashCode == entry.hashCode && entry.key == key) {
-        if (previous == null) {
-          buckets[index] = next;
-        } else {
-          previous.next = next;
-        }
+        _removeEntry(entry, previous, index);
         _elementCount--;
         _modificationCount =
             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
@@ -166,6 +174,16 @@
     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
   }
 
+  void _removeEntry(_HashMapEntry entry,
+                    _HashMapEntry previousInBucket,
+                    int bucketIndex) {
+    if (previousInBucket == null) {
+      _buckets[bucketIndex] = entry.next;
+    } else {
+      previousInBucket.next = entry.next;
+    }
+  }
+
   void _addEntry(List buckets, int index, int length,
                  K key, V value, int hashCode) {
     _HashMapEntry entry =
@@ -201,12 +219,17 @@
   String toString() => Maps.mapToString(this);
 }
 
-class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
+class _CustomHashMap<K, V> extends _HashMap<K, V> {
   final _Equality<K> _equals;
   final _Hasher<K> _hashCode;
-  _CustomHashMap(this._equals, this._hashCode);
+  final _Predicate _validKey;
+  _CustomHashMap(this._equals, this._hashCode, validKey)
+      : _validKey = (validKey != null) ? validKey : new _TypeTest<K>().test;
+
+  Type get runtimeType => HashMap;
 
   bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
     int hashCode = _hashCode(key);
     List buckets = _buckets;
     int index = hashCode & (buckets.length - 1);
@@ -219,6 +242,7 @@
   }
 
   V operator[](Object key) {
+    if (!_validKey(key)) return null;
     int hashCode = _hashCode(key);
     List buckets = _buckets;
     int index = hashCode & (buckets.length - 1);
@@ -271,6 +295,7 @@
   }
 
   V remove(Object key) {
+    if (!_validKey(key)) return null;
     int hashCode = _hashCode(key);
     List buckets = _buckets;
     int index = hashCode & (buckets.length - 1);
@@ -279,11 +304,7 @@
     while (entry != null) {
       _HashMapEntry next = entry.next;
       if (hashCode == entry.hashCode && _equals(entry.key, key)) {
-        if (previous == null) {
-          buckets[index] = next;
-        } else {
-          previous.next = next;
-        }
+        _removeEntry(entry, previous, index);
         _elementCount--;
         _modificationCount =
             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
@@ -298,7 +319,9 @@
   String toString() => Maps.mapToString(this);
 }
 
-class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> {
+class _IdentityHashMap<K, V> extends _HashMap<K, V> {
+  Type get runtimeType => HashMap;
+
   bool containsKey(Object key) {
     int hashCode = key.hashCode;
     List buckets = _buckets;
@@ -372,11 +395,7 @@
     while (entry != null) {
       _HashMapEntry next = entry.next;
       if (hashCode == entry.hashCode && identical(entry.key, key)) {
-        if (previous == null) {
-          buckets[index] = next;
-        } else {
-          previous.next = next;
-        }
+        _removeEntry(entry, previous, index);
         _elementCount--;
         _modificationCount =
             (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
@@ -596,11 +615,11 @@
 }
 
 abstract class _LinkedHashMapIterator<T> implements Iterator<T> {
-  final _LinkedHashMap _map;
+  final LinkedHashMap _map;
   var _next;
   T _current;
   int _modificationCount;
-  _LinkedHashMapIterator(_LinkedHashMap map)
+  _LinkedHashMapIterator(LinkedHashMap map)
       : _map = map,
         _current = null,
         _next = map._nextEntry,
@@ -626,12 +645,12 @@
 }
 
 class _LinkedHashMapKeyIterator<K> extends _LinkedHashMapIterator<K> {
-  _LinkedHashMapKeyIterator(_LinkedHashMap map) : super(map);
+  _LinkedHashMapKeyIterator(LinkedHashMap map) : super(map);
   K _getValue(_LinkedHashMapEntry entry) => entry.key;
 }
 
 class _LinkedHashMapValueIterator<V> extends _LinkedHashMapIterator<V> {
-  _LinkedHashMapValueIterator(_LinkedHashMap map) : super(map);
+  _LinkedHashMapValueIterator(LinkedHashMap map) : super(map);
   V _getValue(_LinkedHashMapEntry entry) => entry.value;
 }
 
@@ -640,153 +659,74 @@
  * A hash-based map that iterates keys and values in key insertion order.
  */
 patch class LinkedHashMap<K, V> {
-  static const int _INITIAL_CAPACITY = 8;
-  static const int _MODIFICATION_COUNT_MASK = 0x3fffffff;
-
-  int _elementCount = 0;
-  List<_HashMapEntry> _buckets = new List(_INITIAL_CAPACITY);
-  int _modificationCount = 0;
-
   var _nextEntry;
   var _previousEntry;
 
-  /* patch */ LinkedHashMap() {
-    _nextEntry = _previousEntry = this;
-  }
-
-  /* patch */ int get length => _elementCount;
-  /* patch */ bool get isEmpty => _elementCount == 0;
-  /* patch */ bool get isNotEmpty => _elementCount != 0;
-
-  /* patch */ Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
-  /* patch */ Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
-
-  /* patch */ bool containsKey(Object key) {
-    int hashCode = key.hashCode;
-    List buckets = _buckets;
-    int index = hashCode & (buckets.length - 1);
-    _HashMapEntry entry = buckets[index];
-    while (entry != null) {
-      if (hashCode == entry.hashCode && entry.key == key) return true;
-      entry = entry.next;
+  /* patch */ factory LinkedHashMap({ bool equals(K key1, K key2),
+                                      int hashCode(K key),
+                                      bool isValidKey(potentialKey) }) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _LinkedHashMap<K, V>();
+        }
+        if (identical(identical, equals)) {
+          return new _LinkedIdentityHashMap<K, V>();
+        }
+        hashCode = _defaultHashCode;
+      } else if (equals == null) {
+        equals = _defaultEquals;
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
     }
-    return false;
+    return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
   }
+}
 
-  /* patch */ bool containsValue(Object value) {
-    var cursor = _nextEntry;
+// Methods that are exactly the same in all three linked hash map variants.
+abstract class _LinkedHashMapMixin<K, V> implements LinkedHashMap<K, V> {
+  var _nextEntry;
+  var _previousEntry;
+
+  Type get runtimeType => LinkedHashMap;
+
+  bool containsValue(Object value) {
     int modificationCount = _modificationCount;
+    var cursor = _nextEntry;
     while (!identical(cursor, this)) {
       _HashMapEntry entry = cursor;
       if (entry.value == value) return true;
+      if (modificationCount != _modificationCount) {
+        throw new ConcurrentModificationError(this);
+      }
       cursor = cursor._nextEntry;
     }
     return false;
   }
 
-  /* patch */ V operator[](Object key) {
-    int hashCode = key.hashCode;
-    List buckets = _buckets;
-    int index = hashCode & (buckets.length - 1);
-    _HashMapEntry entry = buckets[index];
-    while (entry != null) {
-      if (hashCode == entry.hashCode && entry.key == key) {
-        return entry.value;
-      }
-      entry = entry.next;
-    }
-    return null;
-  }
-
-  /* patch */ void operator []=(K key, V value) {
-    int hashCode = key.hashCode;
-    List buckets = _buckets;
-    int length = buckets.length;
-    int index = hashCode & (length - 1);
-    _HashMapEntry entry = buckets[index];
-    while (entry != null) {
-      if (hashCode == entry.hashCode && entry.key == key) {
-        entry.value = value;
-        return;
-      }
-      entry = entry.next;
-    }
-    _addEntry(buckets, index, length, key, value, hashCode);
-  }
-
-  /* patch */ V putIfAbsent(K key, V ifAbsent()) {
-    int hashCode = key.hashCode;
-    List buckets = _buckets;
-    int length = buckets.length;
-    int index = hashCode & (length - 1);
-    _HashMapEntry entry = buckets[index];
-    while (entry != null) {
-      if (hashCode == entry.hashCode && entry.key == key) {
-        return entry.value;
-      }
-      entry = entry.next;
-    }
-    int stamp = _modificationCount;
-    V value = ifAbsent();
-    if (stamp == _modificationCount) {
-      _addEntry(buckets, index, length, key, value, hashCode);
-    } else {
-      this[key] = value;
-    }
-    return value;
-  }
-
-  /* patch */ void addAll(Map<K, V> other) {
-    other.forEach((K key, V value) {
-      this[key] = value;
-    });
-  }
-
-  /* patch */ void forEach(void action(K key, V value)) {
-    int stamp = _modificationCount;
+  void forEach(void action(K key, V value)) {
+    int modificationCount = _modificationCount;
     var cursor = _nextEntry;
     while (!identical(cursor, this)) {
       _HashMapEntry entry = cursor;
       action(entry.key, entry.value);
-      if (stamp != _modificationCount) {
+      if (modificationCount != _modificationCount) {
         throw new ConcurrentModificationError(this);
       }
       cursor = cursor._nextEntry;
     }
   }
 
-  /* patch */ V remove(Object key) {
-    int hashCode = key.hashCode;
-    List buckets = _buckets;
-    int index = hashCode & (buckets.length - 1);
-    _LinkedHashMapEntry entry = buckets[index];
-    _HashMapEntry previous = null;
-    while (entry != null) {
-      _HashMapEntry next = entry.next;
-      if (hashCode == entry.hashCode && entry.key == key) {
-        if (previous == null) {
-          buckets[index] = next;
-        } else {
-          previous.next = next;
-        }
-        entry._previousEntry._nextEntry = entry._nextEntry;
-        entry._nextEntry._previousEntry = entry._previousEntry;
-        entry._nextEntry = entry._previousEntry = null;
-        _elementCount--;
-        _modificationCount =
-            (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
-        return entry.value;
-      }
-      previous = entry;
-      entry = next;
-    }
-    return null;
-  }
-
-  /* patch */ void clear() {
-    _elementCount = 0;
+  void clear() {
     _nextEntry = _previousEntry = this;
-    _buckets = new List(_INITIAL_CAPACITY);
+    _elementCount = 0;
+    _buckets = new List(_HashMap._INITIAL_CAPACITY);
     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
   }
 
@@ -804,26 +744,50 @@
     _modificationCount = (_modificationCount + 1) & _MODIFICATION_COUNT_MASK;
   }
 
-  void _resize() {
-    List oldBuckets = _buckets;
-    int oldLength = oldBuckets.length;
-    int newLength = oldLength << 1;
-    List newBuckets = new List(newLength);
-    for (int i = 0; i < oldLength; i++) {
-      _HashMapEntry entry = oldBuckets[i];
-      while (entry != null) {
-        _HashMapEntry next = entry.next;
-        int hashCode = entry.hashCode;
-        int index = hashCode & (newLength - 1);
-        entry.next = newBuckets[index];
-        newBuckets[index] = entry;
-        entry = next;
-      }
+  void _removeEntry(_LinkedHashMapEntry entry,
+                    _HashMapEntry previousInBucket,
+                    int bucketIndex) {
+    var previousInChain = entry._previousEntry;
+    var nextInChain = entry._nextEntry;
+    previousInChain._nextEntry = nextInChain;
+    nextInChain._previousEntry = previousInChain;
+    if (previousInBucket == null) {
+      _buckets[bucketIndex] = entry.next;
+    } else {
+      previousInBucket.next = entry.next;
     }
-    _buckets = newBuckets;
+  }
+
+
+  Iterable<K> get keys => new _LinkedHashMapKeyIterable<K>(this);
+  Iterable<V> get values => new _LinkedHashMapValueIterable<V>(this);
+}
+
+class _LinkedHashMap<K, V> extends _HashMap<K, V>
+                           with _LinkedHashMapMixin<K, V> {
+  _LinkedHashMap() {
+    _nextEntry = _previousEntry = this;
   }
 }
 
+class _LinkedIdentityHashMap<K, V> extends _IdentityHashMap<K, V>
+                                   with _LinkedHashMapMixin<K, V> {
+  _LinkedIdentityHashMap() {
+    _nextEntry = _previousEntry = this;
+  }
+}
+
+class _LinkedCustomHashMap<K, V> extends _CustomHashMap<K, V>
+                                 with _LinkedHashMapMixin<K, V> {
+  _LinkedCustomHashMap(bool equals(K key1, K key2),
+                       int hashCode(K key),
+                       bool isValidKey(potentialKey))
+      : super(equals, hashCode, isValidKey) {
+    _nextEntry = _previousEntry = this;
+  }
+}
+
+
 patch class LinkedHashSet<E> extends _HashSetBase<E> {
   static const int _INITIAL_CAPACITY = 8;
   _LinkedHashTable<E> _table;
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index 5be23af..84dc9d6 100644
--- a/runtime/lib/integers.cc
+++ b/runtime/lib/integers.cc
@@ -35,6 +35,12 @@
 }
 
 
+static int BitLengthInt64(int64_t value) {
+  value ^= value >> (8 * sizeof(value) - 1);  // flip bits if negative.
+  return value == 0 ? 0 : Utils::HighestBit(value) + 1;
+}
+
+
 DEFINE_NATIVE_ENTRY(Integer_bitAndFromInteger, 2) {
   const Integer& right = Integer::CheckedHandle(arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, left, arguments->NativeArgAt(1));
@@ -327,6 +333,18 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Smi_bitLength, 1) {
+  const Smi& operand = Smi::CheckedHandle(arguments->NativeArgAt(0));
+  if (FLAG_trace_intrinsified_natives) {
+    OS::Print("Smi_bitLength: %s\n", operand.ToCString());
+  }
+  int64_t value = operand.AsInt64Value();
+  intptr_t result = BitLengthInt64(value);
+  ASSERT(Smi::IsValid(result));
+  return Smi::New(result);
+}
+
+
 // Mint natives.
 
 DEFINE_NATIVE_ENTRY(Mint_bitNegate, 1) {
@@ -340,6 +358,19 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Mint_bitLength, 1) {
+  const Mint& operand = Mint::CheckedHandle(arguments->NativeArgAt(0));
+  ASSERT(CheckInteger(operand));
+  if (FLAG_trace_intrinsified_natives) {
+    OS::Print("Mint_bitLength: %s\n", operand.ToCString());
+  }
+  int64_t value = operand.AsInt64Value();
+  intptr_t result = BitLengthInt64(value);
+  ASSERT(Smi::IsValid(result));
+  return Smi::New(result);
+}
+
+
 DEFINE_NATIVE_ENTRY(Mint_shlFromInt, 2) {
   // Use the preallocated out of memory exception to avoid calling
   // into dart code or allocating any code.
@@ -362,6 +393,12 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Bigint_bitLength, 1) {
+  const Bigint& value = Bigint::CheckedHandle(arguments->NativeArgAt(0));
+  return Integer::New(BigintOperations::BitLength(value));
+}
+
+
 DEFINE_NATIVE_ENTRY(Bigint_shlFromInt, 2) {
   // Use the preallocated out of memory exception to avoid calling
   // into dart code or allocating any code.
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index dca7ef8..7c242ef 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -95,6 +95,20 @@
   bool get isNegative => this < 0;
   bool get isInfinite => false;
 
+  int toUnsigned(int width) {
+    return this & ((1 << width) - 1);
+  }
+
+  int toSigned(int width) {
+    // The value of binary number weights each bit by a power of two.  The
+    // twos-complement value weights the sign bit negatively.  We compute the
+    // value of the negative weighting by isolating the sign bit with the
+    // correct power of two weighting and subtracting it from the value of the
+    // lower bits.
+    int signMask = 1 << (width - 1);
+    return (this & (signMask - 1)) - (this & signMask);
+  }
+
   int compareTo(num other) {
     final int EQUAL = 0, LESS = -1, GREATER = 1;
     if (other is double) {
@@ -212,6 +226,8 @@
     return this;
   }
   int operator ~() native "Smi_bitNegate";
+  int get bitLength native "Smi_bitLength";
+
   int _shrFromInt(int other) native "Smi_shrFromInt";
   int _shlFromInt(int other) native "Smi_shlFromInt";
 
@@ -252,6 +268,7 @@
     return this;
   }
   int operator ~() native "Mint_bitNegate";
+  int get bitLength native "Mint_bitLength";
 
   // Shift by mint exceeds range that can be handled by the VM.
   int _shrFromInt(int other) {
@@ -275,6 +292,7 @@
     return this;
   }
   int operator ~() native "Bigint_bitNegate";
+  int get bitLength native "Bigint_bitLength";
 
   // Shift by bigint exceeds range that can be handled by the VM.
   int _shrFromInt(int other) {
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 22b5634..8880d2306 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -61,8 +61,7 @@
                                    function_name,
                                    kNumArguments,
                                    Object::empty_array(),
-                                   Resolver::kIsQualified,
-                                   NULL);  // No ambiguity error expected.
+                                   Resolver::kIsQualified);
     ASSERT(!func.IsNull());
     isolate->object_store()->set_receive_port_create_function(func);
   }
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3f70c58..8bed356 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -29,15 +29,6 @@
 }
 
 
-// Note a "raw type" is not the same as a RawType.
-static RawAbstractType* RawTypeOfClass(const Class& cls) {
-  Type& type = Type::Handle(Type::New(cls,
-                                      Object::null_abstract_type_arguments(),
-                                      Scanner::kDummyTokenIndex));
-  return ClassFinalizer::FinalizeType(cls, type, ClassFinalizer::kCanonicalize);
-}
-
-
 static void ThrowMirroredCompilationError(const String& message) {
   Array& args = Array::Handle(Array::New(1));
   args.SetAt(0, message);
@@ -294,6 +285,7 @@
 
 static RawInstance* CreateClassMirror(const Class& cls,
                                       const AbstractType& type,
+                                      const Bool& is_declaration,
                                       const Instance& owner_mirror) {
   ASSERT(!cls.IsDynamicClass() && !cls.IsVoidClass());
 
@@ -307,16 +299,12 @@
     }
   }
 
+  ASSERT(!type.IsNull());
+
   const Bool& is_generic = Bool::Get(cls.NumTypeParameters() != 0);
   const Bool& is_mixin_typedef = Bool::Get(cls.is_mixin_typedef());
 
-  // If the class is not generic, the mirror must have a non-null runtime type.
-  // If the class is generic, the mirror will have a null runtime type if it
-  // represents the declaration or a non-null runtime type if it represents an
-  // instantiation.
-  ASSERT(!(cls.NumTypeParameters() == 0) || !type.IsNull());
-
-  const Array& args = Array::Handle(Array::New(5));
+  const Array& args = Array::Handle(Array::New(6));
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
   args.SetAt(1, type);
   // We do not set the names of anonymous mixin applications because the mirrors
@@ -327,6 +315,7 @@
   }
   args.SetAt(3, is_generic);
   args.SetAt(4, is_mixin_typedef);
+  args.SetAt(5, cls.NumTypeParameters() == 0 ? Bool::False() : is_declaration);
   return CreateMirror(Symbols::_LocalClassMirrorImpl(), args);
 }
 
@@ -359,7 +348,7 @@
       // TODO(mlippautz): Create once in the VM isolate and retrieve from there.
       return CreateMirror(Symbols::_SpecialTypeMirrorImpl(), args);
     }
-    return CreateClassMirror(cls, type, Object::null_instance());
+    return CreateClassMirror(cls, type, Bool::False(), Object::null_instance());
   } else if (type.IsTypeParameter()) {
     return CreateTypeVariableMirror(TypeParameter::Cast(type),
                                     Object::null_instance());
@@ -424,16 +413,11 @@
     Exceptions::ThrowByType(Exceptions::kArgument, args);
     UNREACHABLE();
   }
-  // Strip the type for generics only.
-  if (cls.NumTypeParameters() == 0) {
-    return CreateClassMirror(cls,
-                             type,
-                             Object::null_instance());
-  } else {
-    return CreateClassMirror(cls,
-                             AbstractType::Handle(),
-                             Object::null_instance());
-  }
+  const Type& stripped_type = Type::Handle(cls.RareType());
+  return CreateClassMirror(cls,
+                           stripped_type,
+                           Bool::True(),  // is_declaration
+                           Object::null_instance());
 }
 
 
@@ -523,13 +507,6 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(ClassMirror_name, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
-  const Class& klass = Class::Handle(ref.GetClassReferent());
-  return klass.UserVisibleName();
-}
-
-
 DEFINE_NATIVE_ENTRY(ClassMirror_library, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
   const Class& klass = Class::Handle(ref.GetClassReferent());
@@ -668,13 +645,11 @@
       if (!klass.IsCanonicalSignatureClass() &&
           !klass.IsDynamicClass() &&
           !RawObject::IsImplementationClassId(klass.id())) {
-        if (klass.NumTypeParameters() == 0) {
-          // Include runtime type for non-generics only.
-          type = RawTypeOfClass(klass);
-        } else {
-          type = AbstractType::null();
-        }
-        member_mirror = CreateClassMirror(klass, type, owner_mirror);
+        type = klass.RareType();
+        member_mirror = CreateClassMirror(klass,
+                                          type,
+                                          Bool::True(),  // is_declaration
+                                          owner_mirror);
         member_mirrors.Add(member_mirror);
       }
     } else if (entry.IsField()) {
@@ -745,11 +720,10 @@
 DEFINE_NATIVE_ENTRY(TypeVariableMirror_owner, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
   const Class& owner = Class::Handle(param.parameterized_class());
-  // The owner of a type variable must be a generic class: pass a null runtime
-  // type to get a mirror on the declaration.
-  ASSERT(owner.NumTypeParameters() != 0);
+  const Type& type = Type::Handle(owner.RareType());
   return CreateClassMirror(owner,
-                           AbstractType::Handle(),
+                           type,
+                           Bool::True(),  // is_declaration
                            Instance::null_instance());
 }
 
@@ -974,7 +948,7 @@
   if (function.IsNull() ||
       !function.AreValidArguments(args_descriptor, NULL) ||
       !function.is_visible()) {
-    ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)),
+    ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                       function_name,
                       function,
                       InvocationMirror::kStatic,
@@ -1009,7 +983,7 @@
         klass.LookupStaticFunctionAllowPrivate(internal_getter_name));
 
     if (getter.IsNull() || !getter.is_visible()) {
-      ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)),
+      ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                         getter_name,
                         getter,
                         InvocationMirror::kStatic,
@@ -1048,7 +1022,7 @@
       klass.LookupStaticFunctionAllowPrivate(internal_setter_name));
 
     if (setter.IsNull() || !setter.is_visible()) {
-      ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)),
+      ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                         setter_name,
                         setter,
                         InvocationMirror::kStatic,
@@ -1084,13 +1058,14 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 4) {
+DEFINE_NATIVE_ENTRY(ClassMirror_invokeConstructor, 5) {
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
   const Class& klass = Class::Handle(ref.GetClassReferent());
+  GET_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(
-      String, constructor_name, arguments->NativeArgAt(1));
-  GET_NON_NULL_NATIVE_ARGUMENT(Array, explicit_args, arguments->NativeArgAt(2));
-  GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(3));
+      String, constructor_name, arguments->NativeArgAt(2));
+  GET_NON_NULL_NATIVE_ARGUMENT(Array, explicit_args, arguments->NativeArgAt(3));
+  GET_NON_NULL_NATIVE_ARGUMENT(Array, arg_names, arguments->NativeArgAt(4));
 
   // By convention, the static function implementing a named constructor 'C'
   // for class 'A' is labeled 'A.C', and the static function implementing the
@@ -1113,7 +1088,7 @@
     // Pretend we didn't find the constructor at all when the arity is wrong
     // so as to produce the same NoSuchMethodError as the non-reflective case.
     lookup_constructor = Function::null();
-    ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)),
+    ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                       internal_constructor_name,
                       lookup_constructor,
                       InvocationMirror::kConstructor,
@@ -1154,7 +1129,7 @@
     // Pretend we didn't find the constructor at all when the arity is wrong
     // so as to produce the same NoSuchMethodError as the non-reflective case.
     redirected_constructor = Function::null();
-    ThrowNoSuchMethod(AbstractType::Handle(RawTypeOfClass(klass)),
+    ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                       internal_constructor_name,
                       redirected_constructor,
                       InvocationMirror::kConstructor,
@@ -1162,19 +1137,27 @@
     UNREACHABLE();
   }
 
+  ASSERT(!type.IsNull());
+  const AbstractTypeArguments& type_arguments =
+      AbstractTypeArguments::Handle(type.arguments());
+
   Instance& new_object = Instance::Handle();
   if (redirected_constructor.IsConstructor()) {
     // Constructors get the uninitialized object and a constructor phase. Note
     // we have delayed allocation until after the function type and argument
     // matching checks.
     new_object = Instance::New(redirected_klass);
+    if (!type_arguments.IsNull()) {
+      // The type arguments will be null if the class has no type parameters, in
+      // which case the following call would fail because there is no slot
+      // reserved in the object for the type vector.
+      new_object.SetTypeArguments(type_arguments);
+    }
     args.SetAt(0, new_object);
     args.SetAt(1, Smi::Handle(Smi::New(Function::kCtorPhaseAll)));
   } else {
     // Factories get type arguments.
-    // TODO(12921): Should we allow the user to specify type arguments? Use type
-    // arguments from the mirror?
-    args.SetAt(0, Object::null_abstract_type_arguments());
+    args.SetAt(0, type_arguments);
   }
 
   // Invoke the constructor and return the new object.
@@ -1183,7 +1166,8 @@
                                                args,
                                                args_descriptor_array));
   if (result.IsError()) {
-    return result.raw();
+    ThrowInvokeError(Error::Cast(result));
+    UNREACHABLE();
   }
 
   // Factories may return null.
@@ -1211,14 +1195,8 @@
   const Array& args_descriptor_array =
       Array::Handle(ArgumentsDescriptor::New(args.Length(), arg_names));
 
-  String& ambiguity_error_msg = String::Handle(isolate);
   const Function& function = Function::Handle(
-      library.LookupFunctionAllowPrivate(function_name, &ambiguity_error_msg));
-
-  if (function.IsNull() && !ambiguity_error_msg.IsNull()) {
-    ThrowMirroredCompilationError(ambiguity_error_msg);
-    UNREACHABLE();
-  }
+      library.LookupFunctionAllowPrivate(function_name));
 
   ArgumentsDescriptor args_descriptor(args_descriptor_array);
   if (function.IsNull() ||
@@ -1253,16 +1231,14 @@
   // To access a top-level we may need to use the Field or the
   // getter Function.  The getter function may either be in the
   // library or in the field's owner class, depending.
-  String& ambiguity_error_msg = String::Handle(isolate);
   const Field& field = Field::Handle(
-      library.LookupFieldAllowPrivate(getter_name, &ambiguity_error_msg));
+      library.LookupFieldAllowPrivate(getter_name));
   Function& getter = Function::Handle();
-  if (field.IsNull() && ambiguity_error_msg.IsNull()) {
+  if (field.IsNull()) {
     // No field found and no ambiguity error.  Check for a getter in the lib.
     const String& internal_getter_name =
         String::Handle(Field::GetterName(getter_name));
-    getter = library.LookupFunctionAllowPrivate(internal_getter_name,
-                                                &ambiguity_error_msg);
+    getter = library.LookupFunctionAllowPrivate(internal_getter_name);
   } else if (!field.IsNull() && FieldIsUninitialized(field)) {
     // A field was found.  Check for a getter in the field's owner classs.
     const Class& klass = Class::Handle(field.owner());
@@ -1284,15 +1260,11 @@
   if (!field.IsNull()) {
     return field.value();
   }
-  if (ambiguity_error_msg.IsNull()) {
-    ThrowNoSuchMethod(Instance::null_instance(),
-                      getter_name,
-                      getter,
-                      InvocationMirror::kTopLevel,
-                      InvocationMirror::kGetter);
-  } else {
-    ThrowMirroredCompilationError(ambiguity_error_msg);
-  }
+  ThrowNoSuchMethod(Instance::null_instance(),
+                    getter_name,
+                    getter,
+                    InvocationMirror::kTopLevel,
+                    InvocationMirror::kGetter);
   UNREACHABLE();
   return Instance::null();
 }
@@ -1310,26 +1282,20 @@
   // To access a top-level we may need to use the Field or the
   // setter Function.  The setter function may either be in the
   // library or in the field's owner class, depending.
-  String& ambiguity_error_msg = String::Handle(isolate);
   const Field& field = Field::Handle(
-      library.LookupFieldAllowPrivate(setter_name, &ambiguity_error_msg));
+      library.LookupFieldAllowPrivate(setter_name));
 
-  if (field.IsNull() && ambiguity_error_msg.IsNull()) {
+  if (field.IsNull()) {
     const String& internal_setter_name =
         String::Handle(Field::SetterName(setter_name));
     const Function& setter = Function::Handle(
-        library.LookupFunctionAllowPrivate(internal_setter_name,
-                                           &ambiguity_error_msg));
+        library.LookupFunctionAllowPrivate(internal_setter_name));
     if (setter.IsNull() || !setter.is_visible()) {
-      if (ambiguity_error_msg.IsNull()) {
-        ThrowNoSuchMethod(Instance::null_instance(),
-                          setter_name,
-                          setter,
-                          InvocationMirror::kTopLevel,
-                          InvocationMirror::kSetter);
-      } else {
-        ThrowMirroredCompilationError(ambiguity_error_msg);
-      }
+      ThrowNoSuchMethod(Instance::null_instance(),
+                        setter_name,
+                        setter,
+                        InvocationMirror::kTopLevel,
+                        InvocationMirror::kSetter);
       UNREACHABLE();
     }
 
@@ -1372,12 +1338,8 @@
     return CreateLibraryMirror(Library::Handle(owner.library()));
   }
 
-  AbstractType& type = AbstractType::Handle();
-  if (owner.NumTypeParameters() == 0) {
-    // Include runtime type for non-generics only.
-    type = RawTypeOfClass(owner);
-  }
-  return CreateClassMirror(owner, type, Object::null_instance());
+  Type& type = Type::Handle(owner.RareType());
+  return CreateClassMirror(owner, type, Bool::True(), Object::null_instance());
 }
 
 
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 844b6a8..534ded4 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -21,11 +21,8 @@
   return new_map;
 }
 
-Map _makeMemberMap(List mirrors) {
-  Map result = new Map<Symbol, dynamic>();
-  mirrors.forEach((mirror) => result[mirror.simpleName] = mirror);
-  return result;
-}
+Map _makeMemberMap(List mirrors) => new Map<Symbol, dynamic>.fromIterable(
+    mirrors, key: (e) => e.simpleName);
 
 String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
 
@@ -39,13 +36,6 @@
   return _s('${_n(owner.qualifiedName)}.${_n(simpleName)}');
 }
 
-Map<Symbol, dynamic> _convertStringToSymbolMap(Map<String, dynamic> map) {
-  if (map == null) return null;
-  Map<Symbol, dynamic> result = new Map<Symbol, dynamic>();
-  map.forEach((name, value) => result[_s(name)] = value);
-  return result;
-}
-
 String _makeSignatureString(TypeMirror returnType,
                             List<ParameterMirror> parameters) {
   StringBuffer buf = new StringBuffer();
@@ -83,18 +73,12 @@
   return buf.toString();
 }
 
-Map<Uri, LibraryMirror> _createLibrariesMap(List<LibraryMirror> list) {
-  var map = new Map<Uri, LibraryMirror>();
-  list.forEach((LibraryMirror mirror) => map[mirror.uri] = mirror);
-  return map;
-}
-
 List _metadata(reflectee)
   native 'DeclarationMirror_metadata';
 
 // This will verify the argument types, unwrap them, and ensure we have a fixed
 // array.
-List _unwarpAsyncPositionals(wrappedArgs) {
+List _unwrapAsyncPositionals(wrappedArgs) {
   List unwrappedArgs = new List(wrappedArgs.length);
   for(int i = 0; i < wrappedArgs.length; i++){
     var wrappedArg = wrappedArgs[i];
@@ -109,7 +93,8 @@
   }
   return unwrappedArgs;
 }
-Map _unwarpAsyncNamed(wrappedArgs) {
+
+Map _unwrapAsyncNamed(wrappedArgs) {
   if (wrappedArgs==null) return null;
   Map unwrappedArgs = new Map();
   wrappedArgs.forEach((name, wrappedArg){
@@ -128,13 +113,13 @@
 class _LocalMirrorSystemImpl extends MirrorSystem {
   // Change parameter back to "this.libraries" when native code is changed.
   _LocalMirrorSystemImpl(List<LibraryMirror> libraries, this.isolate)
-      : this.libraries = _createLibrariesMap(libraries);
+      : this.libraries = new Map<Uri, LibraryMirror>.fromIterable(
+            libraries, key: (e) => e.uri);
 
   final Map<Uri, LibraryMirror> libraries;
   final IsolateMirror isolate;
 
   TypeMirror _dynamicType = null;
-
   TypeMirror get dynamicType {
     if (_dynamicType == null) {
       _dynamicType = new _SpecialTypeMirrorImpl('dynamic');
@@ -143,7 +128,6 @@
   }
 
   TypeMirror _voidType = null;
-
   TypeMirror get voidType {
     if (_voidType == null) {
       _voidType = new _SpecialTypeMirrorImpl('void');
@@ -166,7 +150,7 @@
 
 class _LocalIsolateMirrorImpl extends _LocalMirrorImpl
     implements IsolateMirror {
-  _LocalIsolateMirrorImpl(this.debugName, this.rootLibrary) {}
+  _LocalIsolateMirrorImpl(this.debugName, this.rootLibrary);
 
   final String debugName;
   final bool isCurrent = true;
@@ -223,8 +207,8 @@
                                      [Map<Symbol, dynamic> namedArguments]) {
     return new Future(() {
       return this.invoke(memberName,
-                         _unwarpAsyncPositionals(positionalArguments),
-                         _unwarpAsyncNamed(namedArguments));
+                         _unwrapAsyncPositionals(positionalArguments),
+                         _unwrapAsyncNamed(namedArguments));
     });
   }
 
@@ -385,11 +369,6 @@
     return _function;
   }
 
-  String get source {
-    throw new UnimplementedError(
-        'ClosureMirror.source is not implemented');
-  }
-
   InstanceMirror apply(List<Object> positionalArguments,
                        [Map<Symbol, Object> namedArguments]) {
     // TODO(iposva): When closures get an ordinary call method, this can be
@@ -421,8 +400,8 @@
   Future<InstanceMirror> applyAsync(List positionalArguments,
                                     [Map<Symbol, dynamic> namedArguments]) {
     return new Future(() {
-      return this.apply(_unwarpAsyncPositionals(positionalArguments),
-                        _unwarpAsyncNamed(namedArguments));
+      return this.apply(_unwrapAsyncPositionals(positionalArguments),
+                        _unwrapAsyncNamed(namedArguments));
     });
   }
 
@@ -446,15 +425,17 @@
                         this._reflectedType,
                         String simpleName,
                         this._isGeneric,
-                        this._isMixinTypedef)
+                        this._isMixinTypedef,
+                        this._isGenericDeclaration)
       : this._simpleName = _s(simpleName),
         super(reflectee);
 
   final Type _reflectedType;
   final bool _isGeneric;
   final bool _isMixinTypedef;
+  final bool _isGenericDeclaration;
 
-  bool get hasReflectedType => _reflectedType != null;
+  bool get hasReflectedType => !_isGenericDeclaration;
   Type get reflectedType {
     if (!hasReflectedType) {
       throw new UnsupportedError(
@@ -465,15 +446,9 @@
 
   Symbol _simpleName;
   Symbol get simpleName {
-    // dynamic, void and the function types have their names set eagerly in the
-    // constructor.
+    // All but anonymous mixin applications have their name set at construction.
     if(_simpleName == null) {
-      var simpleString = _name(_reflectee);
-      if (simpleString.contains('&')) {
-        _simpleName = this._mixinApplicationName;
-      } else {
-        _simpleName = _s(simpleString);
-      }
+      _simpleName = this._mixinApplicationName;
     }
     return _simpleName;
   }
@@ -499,8 +474,7 @@
   final bool isTopLevel = true;
 
   SourceLocation get location {
-    throw new UnimplementedError(
-        'ClassMirror.location is not implemented');
+    throw new UnimplementedError('ClassMirror.location is not implemented');
   }
 
   // TODO(rmacnak): Remove these left-overs from the days of separate interfaces
@@ -565,7 +539,6 @@
   }
 
   Map<Symbol, Mirror> _members;
-
   Map<Symbol, Mirror> get members {
     if (_members == null) {
       var whoseMembers = _isMixinTypedef ? _trueSuperclass : this;
@@ -574,11 +547,7 @@
     return _members;
   }
 
-  Map<Symbol, MethodMirror> _methods = null;
-  Map<Symbol, MethodMirror> _getters = null;
-  Map<Symbol, MethodMirror> _setters = null;
-  Map<Symbol, VariableMirror> _variables = null;
-
+  Map<Symbol, MethodMirror> _methods;
   Map<Symbol, MethodMirror> get methods {
     if (_methods == null) {
       _methods = _filterMap(
@@ -588,6 +557,7 @@
     return _methods;
   }
 
+  Map<Symbol, MethodMirror> _getters;
   Map<Symbol, MethodMirror> get getters {
     if (_getters == null) {
       _getters = _filterMap(
@@ -597,6 +567,7 @@
     return _getters;
   }
 
+  Map<Symbol, MethodMirror> _setters;
   Map<Symbol, MethodMirror> get setters {
     if (_setters == null) {
       _setters = _filterMap(
@@ -606,6 +577,7 @@
     return _setters;
   }
 
+  Map<Symbol, VariableMirror> _variables;
   Map<Symbol, VariableMirror> get variables {
     if (_variables == null) {
       _variables = _filterMap(
@@ -616,7 +588,6 @@
   }
 
   Map<Symbol, MethodMirror> _constructors;
-
   Map<Symbol, MethodMirror> get constructors {
     if (_constructors == null) {
       var constructorsList = _computeConstructors(_reflectee);
@@ -628,7 +599,6 @@
   }
 
   Map<Symbol, TypeVariableMirror> _typeVariables = null;
-
   Map<Symbol, TypeVariableMirror> get typeVariables {
     if (_typeVariables == null) {
       List params = _ClassMirror_type_variables(_reflectee);
@@ -646,20 +616,18 @@
   Map<Symbol, TypeMirror> _typeArguments = null;
   Map<Symbol, TypeMirror> get typeArguments {
     if(_typeArguments == null) {
-      if(_reflectedType == null) {
+      if(_isGenericDeclaration) {
         _typeArguments = new LinkedHashMap<Symbol, TypeMirror>();
       } else {
         _typeArguments =
-            new LinkedHashMap<Symbol, TypeMirror>.fromIterables(typeVariables.keys,
-                                                                _computeTypeArguments(_reflectedType));
+            new LinkedHashMap<Symbol, TypeMirror>.fromIterables(
+                typeVariables.keys, _computeTypeArguments(_reflectedType));
       }
     }
     return _typeArguments;
   }
 
-  bool get isOriginalDeclaration {
-    return !_isGeneric || _reflectedType == null;
-  }
+  bool get isOriginalDeclaration => !_isGeneric || _isGenericDeclaration;
 
   ClassMirror get originalDeclaration {
     if (isOriginalDeclaration) {
@@ -669,9 +637,7 @@
     }
   }
 
-  String toString() {
-    return "ClassMirror on '${_n(simpleName)}'";
-  }
+  String toString() => "ClassMirror on '${_n(simpleName)}'";
 
   InstanceMirror newInstance(Symbol constructorName,
                              List positionalArguments,
@@ -694,6 +660,7 @@
     }
 
     return reflect(_invokeConstructor(_reflectee,
+                                      _reflectedType,
                                       _n(constructorName),
                                       arguments,
                                       names));
@@ -704,8 +671,8 @@
                                           [Map<Symbol, dynamic> namedArguments]) {
     return new Future(() {
       return this.newInstance(constructorName,
-                              _unwarpAsyncPositionals(positionalArguments),
-                              _unwarpAsyncNamed(namedArguments));
+                              _unwrapAsyncPositionals(positionalArguments),
+                              _unwrapAsyncNamed(namedArguments));
     });
   }
 
@@ -718,14 +685,12 @@
   bool operator ==(other) {
     return this.runtimeType == other.runtimeType &&
            this._reflectee == other._reflectee &&
-           this._reflectedType == other._reflectedType;
+           this._reflectedType == other._reflectedType &&
+           this._isGenericDeclaration == other._isGenericDeclaration;
   }
 
   int get hashCode => simpleName.hashCode;
 
-  static _name(reflectee)
-      native "ClassMirror_name";
-
   static _library(reflectee)
       native "ClassMirror_library";
 
@@ -753,7 +718,7 @@
   _invokeSetter(reflectee, setterName, value)
       native 'ClassMirror_invokeSetter';
 
-  static _invokeConstructor(reflectee, constructorName, arguments, argumentNames)
+  static _invokeConstructor(reflectee, type, constructorName, arguments, argumentNames)
       native 'ClassMirror_invokeConstructor';
 
   static _ClassMirror_type_variables(reflectee)
@@ -766,7 +731,7 @@
 class _LocalFunctionTypeMirrorImpl extends _LocalClassMirrorImpl
     implements FunctionTypeMirror {
   _LocalFunctionTypeMirrorImpl(reflectee, reflectedType)
-      : super(reflectee, reflectedType, null, false, false);
+      : super(reflectee, reflectedType, null, false, false, false);
 
   // FunctionTypeMirrors have a simpleName generated from their signature.
   Symbol _simpleName = null;
@@ -907,9 +872,13 @@
                           this._owner)
       : super(reflectee, _s(simpleName));
 
+  final bool isTopLevel = true;
+
   // TODO(12282): Deal with generic typedefs.
   bool get _isGeneric => false;
 
+  bool get isPrivate => false;
+
   DeclarationMirror _owner;
   DeclarationMirror get owner {
     if (_owner == null) {
@@ -918,13 +887,8 @@
     return _owner;
   }
 
-  bool get isPrivate => false;
-
-  final bool isTopLevel = true;
-
   SourceLocation get location {
-    throw new UnimplementedError(
-        'TypedefMirror.location is not implemented');
+    throw new UnimplementedError('TypedefMirror.location is not implemented');
   }
 
   TypeMirror _referent = null;
@@ -967,14 +931,12 @@
   final bool isTopLevel = false;
 
   SourceLocation get location {
-    throw new UnimplementedError(
-        'LibraryMirror.location is not implemented');
+    throw new UnimplementedError('LibraryMirror.location is not implemented');
   }
 
   final Uri uri;
 
   Map<Symbol, Mirror> _members;
-
   Map<Symbol, Mirror> get members {
     if (_members == null) {
       _members = _makeMemberMap(_computeMembers(_reflectee));
@@ -982,12 +944,7 @@
     return _members;
   }
 
-  Map<Symbol, ClassMirror> _classes = null;
-  Map<Symbol, MethodMirror> _functions = null;
-  Map<Symbol, MethodMirror> _getters = null;
-  Map<Symbol, MethodMirror> _setters = null;
-  Map<Symbol, VariableMirror> _variables = null;
-
+  Map<Symbol, ClassMirror> _classes;
   Map<Symbol, ClassMirror> get classes {
     if (_classes == null) {
       _classes = _filterMap(members,
@@ -996,30 +953,31 @@
     return _classes;
   }
 
+  Map<Symbol, MethodMirror> _functions;
   Map<Symbol, MethodMirror> get functions {
     if (_functions == null) {
-      _functions = _filterMap(members,
-                              (key, value) => (value is MethodMirror));
+      _functions = _filterMap(members, (key, value) => (value is MethodMirror));
     }
     return _functions;
   }
 
+  Map<Symbol, MethodMirror> _getters;
   Map<Symbol, MethodMirror> get getters {
     if (_getters == null) {
-      _getters = _filterMap(functions,
-                            (key, value) => (value.isGetter));
+      _getters = _filterMap(functions, (key, value) => (value.isGetter));
     }
     return _getters;
   }
 
+  Map<Symbol, MethodMirror> _setters;
   Map<Symbol, MethodMirror> get setters {
     if (_setters == null) {
-      _setters = _filterMap(functions,
-                            (key, value) => (value.isSetter));
+      _setters = _filterMap(functions, (key, value) => (value.isSetter));
     }
     return _setters;
   }
 
+  Map<Symbol, VariableMirror> _variables;
   Map<Symbol, VariableMirror> get variables {
     if (_variables == null) {
       _variables = _filterMap(members,
@@ -1034,8 +992,6 @@
     return _metadata(_reflectee).map(reflect).toList(growable:false);
   }
 
-  String toString() => "LibraryMirror on '${_n(simpleName)}'";
-
   bool operator ==(other) {
     return this.runtimeType == other.runtimeType &&
            this._reflectee == other._reflectee; 
@@ -1043,6 +999,8 @@
 
   int get hashCode => simpleName.hashCode;
 
+  String toString() => "LibraryMirror on '${_n(simpleName)}'";
+
   _invoke(reflectee, memberName, arguments, argumentNames)
       native 'LibraryMirror_invoke';
 
@@ -1097,16 +1055,13 @@
     return _owner;
   }
 
-  bool get isPrivate {
-    return _n(simpleName).startsWith('_') ||
-        _n(constructorName).startsWith('_');
-  }
+  bool get isPrivate => _n(simpleName).startsWith('_') ||
+                        _n(constructorName).startsWith('_');
 
   bool get isTopLevel =>  owner is LibraryMirror;
 
   SourceLocation get location {
-    throw new UnimplementedError(
-        'MethodMirror.location is not implemented');
+    throw new UnimplementedError('MethodMirror.location is not implemented');
   }
 
   TypeMirror _returnType = null;
@@ -1197,18 +1152,15 @@
       : super(reflectee, _s(simpleName));
 
   final DeclarationMirror owner;
+  final bool isStatic;
+  final bool isFinal;
 
-  bool get isPrivate {
-    return _n(simpleName).startsWith('_');
-  }
+  bool get isPrivate => _n(simpleName).startsWith('_');
 
-  bool get isTopLevel {
-    return owner is LibraryMirror;
-  }
+  bool get isTopLevel => owner is LibraryMirror;
 
   SourceLocation get location {
-    throw new UnimplementedError(
-        'VariableMirror.location is not implemented');
+    throw new UnimplementedError('VariableMirror.location is not implemented');
   }
 
   TypeMirror _type;
@@ -1219,9 +1171,6 @@
     return _type;
   }
 
-  final bool isStatic;
-  final bool isFinal;
-
   String toString() => "VariableMirror on '${_n(simpleName)}'";
 
   static _VariableMirror_type(reflectee)
@@ -1290,24 +1239,17 @@
   _SpecialTypeMirrorImpl(String name) : simpleName = _s(name);
 
   final bool isPrivate = false;
+  final DeclarationMirror owner = null;
+  final Symbol simpleName;
   final bool isTopLevel = true;
-
   // Fixed length 0, therefore immutable.
   final List<InstanceMirror> metadata = new List(0);
 
-  final DeclarationMirror owner = null;
-  final Symbol simpleName;
-
   SourceLocation get location {
-    throw new UnimplementedError(
-        'TypeMirror.location is not implemented');
+    throw new UnimplementedError('TypeMirror.location is not implemented');
   }
 
-  Symbol get qualifiedName {
-    return simpleName;
-  }
-
-  String toString() => "TypeMirror on '${_n(simpleName)}'";
+  Symbol get qualifiedName => simpleName;
 
   // TODO(11955): Remove once dynamicType and voidType are canonical objects in
   // the object store.
@@ -1319,6 +1261,8 @@
   }
 
   int get hashCode => simpleName.hashCode;
+
+  String toString() => "TypeMirror on '${_n(simpleName)}'";
 }
 
 class _Mirrors {
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index b9ec3c9..e4f959e 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -74,8 +74,6 @@
 
   String operator +(String other) native "String_concat";
 
-  String concat(String other) => this + other;
-
   String toString() {
     return this;
   }
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 0a8b0ef..1007c49 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -2325,6 +2325,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Int16List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Int16List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2376,6 +2377,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Uint16List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Uint16List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2427,6 +2429,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Int32List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Int32List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2478,6 +2481,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Uint32List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Uint32List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2529,6 +2533,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Int64List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Int64List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2580,6 +2585,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Uint64List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Uint64List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2631,6 +2637,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Float32List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Float32List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2682,6 +2689,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Float64List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Float64List.BYTES_PER_ELEMENT);
   }
 
 
@@ -2733,6 +2741,7 @@
     _rangeCheck(buffer.lengthInBytes,
                 offsetInBytes,
                 length * Float32x4List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Float32x4List.BYTES_PER_ELEMENT);
   }
 
 
@@ -3125,6 +3134,14 @@
 }
 
 
+void _offsetAlignmentCheck(int offset, int alignment) {
+  if ((offset % alignment) != 0) {
+    throw new RangeError('Offset ($offset) must be a multiple of '
+                         'BYTES_PER_ELEMENT ($alignment)');
+  }
+}
+
+
 int _defaultIfNull(object, value) {
   if (object == null) {
     return value;
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 6add296..1ed67c6 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -48,6 +48,9 @@
 # Skip until we stabilize language tests.
 *: Skip
 
+[ $arch == x64 && $mode == debug ]
+cc/FindCodeObject: Pass, Timeout  # Issue 13144
+
 [ $arch == simarm ]
 dart/isolate_mirror_local_test: Skip
 
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 3b9757c..0ee5ee7 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -1679,6 +1679,14 @@
 }
 
 
+void Assembler::bsrl(Register dst, Register src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0xBD);
+  EmitRegisterOperand(dst, src);
+}
+
+
 void Assembler::enter(const Immediate& imm) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xC8);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 4ddd90e..be28c74 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -595,6 +595,8 @@
   void negl(Register reg);
   void notl(Register reg);
 
+  void bsrl(Register dst, Register src);
+
   void enter(const Immediate& imm);
   void leave();
 
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 04c2915..5628494 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -294,6 +294,27 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(BitScanReverse, assembler) {
+  __ movl(ECX, Address(ESP, kWordSize));
+  __ movl(EAX, Immediate(666));  // Marker for conditional write.
+  __ bsrl(EAX, ECX);
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(BitScanReverse, test) {
+  typedef int (*Bsr)(int input);
+  Bsr call = reinterpret_cast<Bsr>(test->entry());
+  EXPECT_EQ(666, call(0));
+  EXPECT_EQ(0, call(1));
+  EXPECT_EQ(1, call(2));
+  EXPECT_EQ(1, call(3));
+  EXPECT_EQ(2, call(4));
+  EXPECT_EQ(5, call(42));
+  EXPECT_EQ(31, call(-1));
+}
+
+
 ASSEMBLER_TEST_GENERATE(MoveExtend, assembler) {
   __ pushl(EBX);  // preserve EBX.
   __ movl(EDX, Immediate(0x1234ffff));
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 15c02d8..e54e09c 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -859,9 +859,13 @@
   }
 
   void BranchEqual(Register rd, int32_t value, Label* l) {
-    ASSERT(rd != CMPRES2);
-    LoadImmediate(CMPRES2, value);
-    beq(rd, CMPRES2, l);
+    if (value == 0) {
+      beq(rd, ZR, l);
+    } else {
+      ASSERT(rd != CMPRES2);
+      LoadImmediate(CMPRES2, value);
+      beq(rd, CMPRES2, l);
+    }
   }
 
   void BranchEqual(Register rd, const Object& object, Label* l) {
@@ -871,9 +875,13 @@
   }
 
   void BranchNotEqual(Register rd, int32_t value, Label* l) {
-    ASSERT(rd != CMPRES2);
-    LoadImmediate(CMPRES2, value);
-    bne(rd, CMPRES2, l);
+    if (value == 0) {
+      bne(rd, ZR, l);
+    } else {
+      ASSERT(rd != CMPRES2);
+      LoadImmediate(CMPRES2, value);
+      bne(rd, CMPRES2, l);
+    }
   }
 
   void BranchNotEqual(Register rd, const Object& object, Label* l) {
@@ -888,9 +896,13 @@
   }
 
   void BranchSignedGreater(Register rd, int32_t value, Label* l) {
-    ASSERT(rd != CMPRES2);
-    LoadImmediate(CMPRES2, value);
-    BranchSignedGreater(rd, CMPRES2, l);
+    if (value == 0) {
+      bgtz(rd, l);
+    } else {
+      ASSERT(rd != CMPRES2);
+      LoadImmediate(CMPRES2, value);
+      BranchSignedGreater(rd, CMPRES2, l);
+    }
   }
 
   void BranchUnsignedGreater(Register rd, Register rs, Label* l) {
@@ -899,9 +911,13 @@
   }
 
   void BranchUnsignedGreater(Register rd, int32_t value, Label* l) {
-    ASSERT(rd != CMPRES2);
-    LoadImmediate(CMPRES2, value);
-    BranchUnsignedGreater(rd, CMPRES2, l);
+    if (value == 0) {
+      BranchNotEqual(rd, 0, l);
+    } else {
+      ASSERT(rd != CMPRES2);
+      LoadImmediate(CMPRES2, value);
+      BranchUnsignedGreater(rd, CMPRES2, l);
+    }
   }
 
   void BranchSignedGreaterEqual(Register rd, Register rs, Label* l) {
@@ -910,13 +926,17 @@
   }
 
   void BranchSignedGreaterEqual(Register rd, int32_t value, Label* l) {
-    if (Utils::IsInt(kImmBits, value)) {
-      slti(CMPRES2, rd, Immediate(value));
-      beq(CMPRES2, ZR, l);
+    if (value == 0) {
+      bgez(rd, l);
     } else {
-      ASSERT(rd != CMPRES2);
-      LoadImmediate(CMPRES2, value);
-      BranchSignedGreaterEqual(rd, CMPRES2, l);
+      if (Utils::IsInt(kImmBits, value)) {
+        slti(CMPRES2, rd, Immediate(value));
+        beq(CMPRES2, ZR, l);
+      } else {
+        ASSERT(rd != CMPRES2);
+        LoadImmediate(CMPRES2, value);
+        BranchSignedGreaterEqual(rd, CMPRES2, l);
+      }
     }
   }
 
@@ -926,13 +946,17 @@
   }
 
   void BranchUnsignedGreaterEqual(Register rd, int32_t value, Label* l) {
-    if (Utils::IsUint(kImmBits, value)) {
-      sltiu(CMPRES2, rd, Immediate(value));
-      beq(CMPRES2, ZR, l);
+    if (value == 0) {
+      b(l);
     } else {
-      ASSERT(rd != CMPRES2);
-      LoadImmediate(CMPRES2, value);
-      BranchUnsignedGreaterEqual(rd, CMPRES2, l);
+      if (Utils::IsUint(kImmBits, value)) {
+        sltiu(CMPRES2, rd, Immediate(value));
+        beq(CMPRES2, ZR, l);
+      } else {
+        ASSERT(rd != CMPRES2);
+        LoadImmediate(CMPRES2, value);
+        BranchUnsignedGreaterEqual(rd, CMPRES2, l);
+      }
     }
   }
 
@@ -941,13 +965,17 @@
   }
 
   void BranchSignedLess(Register rd, int32_t value, Label* l) {
-    if (Utils::IsInt(kImmBits, value)) {
-      slti(CMPRES2, rd, Immediate(value));
-      bne(CMPRES2, ZR, l);
+    if (value == 0) {
+      bltz(rd, l);
     } else {
-      ASSERT(rd != CMPRES2);
-      LoadImmediate(CMPRES2, value);
-      BranchSignedGreater(CMPRES2, rd, l);
+      if (Utils::IsInt(kImmBits, value)) {
+        slti(CMPRES2, rd, Immediate(value));
+        bne(CMPRES2, ZR, l);
+      } else {
+        ASSERT(rd != CMPRES2);
+        LoadImmediate(CMPRES2, value);
+        BranchSignedGreater(CMPRES2, rd, l);
+      }
     }
   }
 
@@ -956,6 +984,7 @@
   }
 
   void BranchUnsignedLess(Register rd, int32_t value, Label* l) {
+    ASSERT(value != 0);
     if (Utils::IsUint(kImmBits, value)) {
       sltiu(CMPRES2, rd, Immediate(value));
       bne(CMPRES2, ZR, l);
@@ -971,9 +1000,13 @@
   }
 
   void BranchSignedLessEqual(Register rd, int32_t value, Label* l) {
-    ASSERT(rd != CMPRES2);
-    LoadImmediate(CMPRES2, value);
-    BranchSignedGreaterEqual(CMPRES2, rd, l);
+    if (value == 0) {
+      blez(rd, l);
+    } else {
+      ASSERT(rd != CMPRES2);
+      LoadImmediate(CMPRES2, value);
+      BranchSignedGreaterEqual(CMPRES2, rd, l);
+    }
   }
 
   void BranchUnsignedLessEqual(Register rd, Register rs, Label* l) {
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 7b1315d..efdb624 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -65,6 +65,47 @@
 #undef __
 
 
+Assembler::Assembler(bool use_far_branches)
+    : buffer_(),
+      object_pool_(GrowableObjectArray::Handle()),
+      patchable_pool_entries_(),
+      prologue_offset_(-1),
+      comments_() {
+  // Far branching mode is only needed and implemented for MIPS and ARM.
+  ASSERT(!use_far_branches);
+  if (Isolate::Current() != Dart::vm_isolate()) {
+    object_pool_ = GrowableObjectArray::New(Heap::kOld);
+
+    // These objects and labels need to be accessible through every pool-pointer
+    // at the same index.
+    object_pool_.Add(Object::Handle(), Heap::kOld);
+    patchable_pool_entries_.Add(kNotPatchable);
+
+    object_pool_.Add(Bool::True(), Heap::kOld);
+    patchable_pool_entries_.Add(kNotPatchable);
+
+    object_pool_.Add(Bool::False(), Heap::kOld);
+    patchable_pool_entries_.Add(kNotPatchable);
+
+    if (StubCode::UpdateStoreBuffer_entry() != NULL) {
+      FindExternalLabel(&StubCode::UpdateStoreBufferLabel(), kNotPatchable);
+      patchable_pool_entries_.Add(kNotPatchable);
+    } else {
+      object_pool_.Add(Object::Handle(), Heap::kOld);
+      patchable_pool_entries_.Add(kNotPatchable);
+    }
+
+    if (StubCode::CallToRuntime_entry() != NULL) {
+      FindExternalLabel(&StubCode::CallToRuntimeLabel(), kNotPatchable);
+      patchable_pool_entries_.Add(kNotPatchable);
+    } else {
+      object_pool_.Add(Object::Handle(), Heap::kOld);
+      patchable_pool_entries_.Add(kNotPatchable);
+    }
+  }
+}
+
+
 void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) {
   memset(reinterpret_cast<void*>(data), Instr::kBreakPointInstruction, length);
 }
@@ -95,25 +136,45 @@
 }
 
 
+void Assembler::LoadExternalLabel(Register dst,
+                                  const ExternalLabel* label,
+                                  Patchability patchable,
+                                  Register pp) {
+  const int32_t offset =
+      Array::element_offset(FindExternalLabel(label, patchable));
+  LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
+}
+
+
 void Assembler::call(const ExternalLabel* label) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  {  // Encode movq(TMP, Immediate(label->address())), but always as imm64.
+    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+    EmitRegisterREX(TMP, REX_W);
+    EmitUint8(0xB8 | (TMP & 7));
+    EmitInt64(label->address());
+  }
+  call(TMP);
+}
+
+
+void Assembler::CallPatchable(const ExternalLabel* label) {
   intptr_t call_start = buffer_.GetPosition();
-
-  // Encode movq(TMP, Immediate(label->address())), but always as imm64.
-  EmitRegisterREX(TMP, REX_W);
-  EmitUint8(0xB8 | (TMP & 7));
-  EmitInt64(label->address());
-
-  // Encode call(TMP).
-  Operand operand(TMP);
-  EmitOperandREX(2, operand, REX_NONE);
-  EmitUint8(0xFF);
-  EmitOperand(2, operand);
-
+  LoadExternalLabel(TMP, label, kPatchable, PP);
+  call(TMP);
   ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
 }
 
 
+void Assembler::Call(const ExternalLabel* label, Register pp) {
+  if (Isolate::Current() == Dart::vm_isolate()) {
+    call(label);
+  } else {
+    LoadExternalLabel(TMP, label, kNotPatchable, pp);
+    call(TMP);
+  }
+}
+
+
 void Assembler::pushq(Register reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitRegisterREX(reg, REX_NONE);
@@ -1960,6 +2021,15 @@
 }
 
 
+void Assembler::J(Condition condition, const ExternalLabel* label,
+                  Register pp) {
+  Label no_jump;
+  j(static_cast<Condition>(condition ^ 1), &no_jump);  // Negate condition.
+  Jmp(label, pp);
+  Bind(&no_jump);
+}
+
+
 void Assembler::jmp(Register reg) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   Operand operand(reg);
@@ -1994,24 +2064,30 @@
 
 
 void Assembler::jmp(const ExternalLabel* label) {
-  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  {  // Encode movq(TMP, Immediate(label->address())), but always as imm64.
+    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+    EmitRegisterREX(TMP, REX_W);
+    EmitUint8(0xB8 | (TMP & 7));
+    EmitInt64(label->address());
+  }
+  jmp(TMP);
+}
+
+
+void Assembler::JmpPatchable(const ExternalLabel* label, Register pp) {
   intptr_t call_start = buffer_.GetPosition();
-
-  // Encode movq(TMP, Immediate(label->address())), but always as imm64.
-  EmitRegisterREX(TMP, REX_W);
-  EmitUint8(0xB8 | (TMP & 7));
-  EmitInt64(label->address());
-
-  // Encode jmp(TMP).
-  Operand operand(TMP);
-  EmitOperandREX(4, operand, REX_NONE);
-  EmitUint8(0xFF);
-  EmitOperand(4, operand);
-
+  LoadExternalLabel(TMP, label, kPatchable, pp);
+  jmp(TMP);
   ASSERT((buffer_.GetPosition() - call_start) == kCallExternalLabelSize);
 }
 
 
+void Assembler::Jmp(const ExternalLabel* label, Register pp) {
+  LoadExternalLabel(TMP, label, kNotPatchable, pp);
+  jmp(TMP);
+}
+
+
 void Assembler::lock() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xF0);
@@ -2091,49 +2167,111 @@
 }
 
 
-void Assembler::LoadObject(Register dst, const Object& object) {
-  if (object.IsSmi() || object.InVMHeap()) {
-    movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
+intptr_t Assembler::FindObject(const Object& obj, Patchability patchable) {
+  // The object pool cannot be used in the vm isolate.
+  ASSERT(Isolate::Current() != Dart::vm_isolate());
+  ASSERT(!object_pool_.IsNull());
+
+  // TODO(zra): This can be slow. Add a hash map from obj.raw() to
+  // object pool indexes to speed lookup.
+  for (int i = 0; i < object_pool_.Length(); i++) {
+    if ((object_pool_.At(i) == obj.raw()) &&
+        (patchable_pool_entries_[i] != kPatchable)) {
+      return i;
+    }
+  }
+  object_pool_.Add(obj, Heap::kOld);
+  patchable_pool_entries_.Add(patchable);
+  return object_pool_.Length() - 1;
+}
+
+
+intptr_t Assembler::FindExternalLabel(const ExternalLabel* label,
+                                      Patchability patchable) {
+  // The object pool cannot be used in the vm isolate.
+  ASSERT(Isolate::Current() != Dart::vm_isolate());
+  ASSERT(!object_pool_.IsNull());
+  const uword address = label->address();
+  ASSERT(Utils::IsAligned(address, 4));
+  // The address is stored in the object array as a RawSmi.
+  const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(address));
+  if (patchable == kNotPatchable) {
+    return FindObject(smi, kNotPatchable);
+  }
+  // If the call is patchable, do not reuse an existing entry since each
+  // reference may be patched independently.
+  object_pool_.Add(smi, Heap::kOld);
+  patchable_pool_entries_.Add(patchable);
+  return object_pool_.Length() - 1;
+}
+
+
+bool Assembler::CanLoadFromObjectPool(const Object& object) {
+  // TODO(zra, kmillikin): Move the use of large Smis into the constant pool.
+  if (object.IsSmi()) {
+    return false;
+  }
+  ASSERT(object.IsNotTemporaryScopedHandle());
+  ASSERT(object.IsOld());
+  return (Isolate::Current() != Dart::vm_isolate()) &&
+         // Not in the VMHeap, OR is one of the VMHeap objects we put in every
+         // object pool.
+         // TODO(zra): Evaluate putting all VM heap objects into the pool.
+         (!object.InVMHeap() || (object.raw() == Object::null()) ||
+                                (object.raw() == Bool::True().raw()) ||
+                                (object.raw() == Bool::False().raw()));
+}
+
+
+void Assembler::LoadWordFromPoolOffset(Register dst, Register pp,
+                                       int32_t offset) {
+  // This sequence must be of fixed size. AddressBaseImm32
+  // forces the address operand to use a fixed-size imm32 encoding.
+  movq(dst, Address::AddressBaseImm32(pp, offset));
+}
+
+
+void Assembler::LoadObject(Register dst, const Object& object, Register pp) {
+  if (CanLoadFromObjectPool(object)) {
+    const int32_t offset =
+        Array::element_offset(FindObject(object, kNotPatchable));
+    LoadWordFromPoolOffset(dst, pp, offset - kHeapObjectTag);
   } else {
-    ASSERT(object.IsNotTemporaryScopedHandle());
-    ASSERT(object.IsOld());
-    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
-    EmitRegisterREX(dst, REX_W);
-    EmitUint8(0xB8 | (dst & 7));
-    buffer_.EmitObject(object);
+    ASSERT((Isolate::Current() == Dart::vm_isolate()) ||
+           object.IsSmi() ||
+           object.InVMHeap());
+    movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
 
 
 void Assembler::StoreObject(const Address& dst, const Object& object) {
-  if (object.IsSmi() || object.InVMHeap()) {
-    movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
-  } else {
-    ASSERT(object.IsNotTemporaryScopedHandle());
-    ASSERT(object.IsOld());
-    LoadObject(TMP, object);
+  if (CanLoadFromObjectPool(object)) {
+    LoadObject(TMP, object, PP);
     movq(dst, TMP);
+  } else {
+    movq(dst, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
 
 
 void Assembler::PushObject(const Object& object) {
-  if (object.IsSmi() || object.InVMHeap()) {
-    pushq(Immediate(reinterpret_cast<int64_t>(object.raw())));
-  } else {
-    LoadObject(TMP, object);
+  if (CanLoadFromObjectPool(object)) {
+    LoadObject(TMP, object, PP);
     pushq(TMP);
+  } else {
+    pushq(Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
 
 
 void Assembler::CompareObject(Register reg, const Object& object) {
-  if (object.IsSmi() || object.InVMHeap()) {
-    cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
-  } else {
+  if (CanLoadFromObjectPool(object)) {
     ASSERT(reg != TMP);
-    LoadObject(TMP, object);
+    LoadObject(TMP, object, PP);
     cmpq(reg, TMP);
+  } else {
+    cmpq(reg, Immediate(reinterpret_cast<int64_t>(object.raw())));
   }
 }
 
@@ -2196,7 +2334,7 @@
   if (object != RAX) {
     movq(RAX, object);
   }
-  call(&StubCode::UpdateStoreBufferLabel());
+  Call(&StubCode::UpdateStoreBufferLabel(), PP);
   if (value != RAX) popq(RAX);
   Bind(&done);
 }
@@ -2298,6 +2436,23 @@
 }
 
 
+void Assembler::LeaveFrameWithPP() {
+  movq(PP, Address(RBP, -2 * kWordSize));
+  LeaveFrame();
+}
+
+
+void Assembler::ReturnPatchable() {
+  // This sequence must have a fixed size so that it can be patched by the
+  // debugger.
+  intptr_t start = buffer_.GetPosition();
+  LeaveFrameWithPP();
+  ret();
+  nop(4);
+  ASSERT((buffer_.GetPosition() - start) == 13);
+}
+
+
 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
   // Reserve space for arguments and align frame before entering
   // the C++ world.
@@ -2378,18 +2533,59 @@
 }
 
 
+void Assembler::LoadPoolPointer(Register pp) {
+  Label next;
+  call(&next);
+  Bind(&next);
+
+  // Load new pool pointer.
+  const intptr_t object_pool_pc_dist =
+      Instructions::HeaderSize() - Instructions::object_pool_offset() +
+      CodeSize();
+  popq(pp);
+  movq(pp, Address(pp, -object_pool_pc_dist));
+}
+
+
 void Assembler::EnterDartFrame(intptr_t frame_size) {
   EnterFrame(0);
+
   Label dart_entry;
   call(&dart_entry);
   Bind(&dart_entry);
   // The runtime system assumes that the code marker address is
   // kEntryPointToPcMarkerOffset bytes from the entry.  If there is any code
   // generated before entering the frame, the address needs to be adjusted.
+  const intptr_t object_pool_pc_dist =
+      Instructions::HeaderSize() - Instructions::object_pool_offset() +
+      CodeSize();
   const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
   if (offset != 0) {
     addq(Address(RSP, 0), Immediate(offset));
   }
+  // Save caller's pool pointer
+  pushq(PP);
+
+  // Load callee's pool pointer.
+  movq(PP, Address(RSP, 1 * kWordSize));
+  movq(PP, Address(PP, -object_pool_pc_dist - offset));
+
+  if (frame_size != 0) {
+    subq(RSP, Immediate(frame_size));
+  }
+}
+
+
+void Assembler::EnterDartFrameWithInfo(intptr_t frame_size,
+                                       Register new_pp, Register new_pc) {
+  if (new_pc == kNoRegister) {
+    EnterDartFrame(0);
+  } else {
+    EnterFrame(0);
+    pushq(new_pc);
+    pushq(PP);
+    movq(PP, new_pp);
+  }
   if (frame_size != 0) {
     subq(RSP, Immediate(frame_size));
   }
@@ -2401,18 +2597,32 @@
 // pointer is already set up.  The PC marker is not correct for the
 // optimized function and there may be extra space for spill slots to
 // allocate.
-void Assembler::EnterOsrFrame(intptr_t extra_size) {
-  Label dart_entry;
-  call(&dart_entry);
-  Bind(&dart_entry);
-  // The runtime system assumes that the code marker address is
-  // kEntryPointToPcMarkerOffset bytes from the entry.  Since there is no
-  // code to set up the frame pointer, the address needs to be adjusted.
-  const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
-  if (offset != 0) {
-    addq(Address(RSP, 0), Immediate(offset));
+void Assembler::EnterOsrFrame(intptr_t extra_size,
+                              Register new_pp, Register new_pc) {
+  if (new_pc == kNoRegister) {
+    Label dart_entry;
+    call(&dart_entry);
+    Bind(&dart_entry);
+    // The runtime system assumes that the code marker address is
+    // kEntryPointToPcMarkerOffset bytes from the entry.  Since there is no
+    // code to set up the frame pointer, the address needs to be adjusted.
+    const intptr_t object_pool_pc_dist =
+        Instructions::HeaderSize() - Instructions::object_pool_offset() +
+        CodeSize();
+    const intptr_t offset = kEntryPointToPcMarkerOffset - CodeSize();
+    if (offset != 0) {
+      addq(Address(RSP, 0), Immediate(offset));
+    }
+
+    // Load callee's pool pointer.
+    movq(PP, Address(RSP, 0));
+    movq(PP, Address(PP, -object_pool_pc_dist - offset));
+
+    popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize));
+  } else {
+    movq(Address(RBP, kPcMarkerSlotFromFp * kWordSize), new_pc);
+    movq(PP, new_pp);
   }
-  popq(Address(RBP, kPcMarkerSlotFromFp * kWordSize));
   if (extra_size != 0) {
     subq(RSP, Immediate(extra_size));
   }
@@ -2425,6 +2635,14 @@
 }
 
 
+void Assembler::EnterStubFrameWithPP() {
+  EnterFrame(0);
+  pushq(Immediate(0));  // Push 0 in the saved PC area for stub frames.
+  pushq(PP);  // Save caller's pool pointer
+  LoadPoolPointer(PP);
+}
+
+
 void Assembler::TryAllocate(const Class& cls,
                             Label* failure,
                             bool near_jump,
@@ -2647,7 +2865,6 @@
   return xmm_reg_names[reg];
 }
 
-
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_X64
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index f4c945f..96921ee 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -212,6 +212,20 @@
     Operand::operator=(other);
     return *this;
   }
+
+  static Address AddressBaseImm32(Register base, int32_t disp) {
+    return Address(base, disp, true);
+  }
+
+ private:
+  Address(Register base, int32_t disp, bool fixed) {
+    ASSERT(fixed);
+    SetModRM(2, base);
+    if ((base & 7) == RSP) {
+      SetSIB(TIMES_1, RSP, base);
+    }
+    SetDisp32(disp);
+  }
 };
 
 
@@ -321,14 +335,8 @@
 
 class Assembler : public ValueObject {
  public:
-  explicit Assembler(bool use_far_branches = false)
-      : buffer_(),
-        object_pool_(GrowableObjectArray::Handle()),
-        prologue_offset_(-1),
-        comments_() {
-    // This mode is only needed and implemented for MIPS and ARM.
-    ASSERT(!use_far_branches);
-  }
+  explicit Assembler(bool use_far_branches = false);
+
   ~Assembler() { }
 
   static const bool kNearJump = true;
@@ -342,7 +350,7 @@
   void call(Label* label);
   void call(const ExternalLabel* label);
 
-  static const intptr_t kCallExternalLabelSize = 13;
+  static const intptr_t kCallExternalLabelSize = 10;
 
   void pushq(Register reg);
   void pushq(const Address& address);
@@ -652,7 +660,17 @@
 
   void Drop(intptr_t stack_elements);
 
-  void LoadObject(Register dst, const Object& object);
+  enum Patchability {
+    kPatchable,
+    kNotPatchable,
+  };
+
+  void LoadObject(Register dst, const Object& obj, Register pp);
+  void JmpPatchable(const ExternalLabel* label, Register pp);
+  void Jmp(const ExternalLabel* label, Register pp);
+  void J(Condition condition, const ExternalLabel* label, Register pp);
+  void CallPatchable(const ExternalLabel* label);
+  void Call(const ExternalLabel* label, Register pp);
   void StoreObject(const Address& dst, const Object& obj);
   void PushObject(const Object& object);
   void CompareObject(Register reg, const Object& object);
@@ -680,6 +698,8 @@
 
   void EnterFrame(intptr_t frame_space);
   void LeaveFrame();
+  void LeaveFrameWithPP();
+  void ReturnPatchable();
   void ReserveAlignedFrameSpace(intptr_t frame_space);
 
   // Create a frame for calling into runtime that preserves all volatile
@@ -731,6 +751,8 @@
     buffer_.FinalizeInstructions(region);
   }
 
+  void LoadPoolPointer(Register pp);
+
   // Set up a Dart frame on entry with a frame pointer and PC information to
   // enable easy access to the RawInstruction object of code corresponding
   // to this frame.
@@ -739,6 +761,7 @@
   //   ret PC
   //   saved RBP     <=== RBP
   //   pc (used to derive the RawInstruction Object of the dart code)
+  //   saved PP
   //   locals space  <=== RSP
   //   .....
   // This code sets this up with the sequence:
@@ -746,13 +769,17 @@
   //   movq rbp, rsp
   //   call L
   //   L: <code to adjust saved pc if there is any intrinsification code>
+  //   ...
+  //   pushq r15
   //   .....
   void EnterDartFrame(intptr_t frame_size);
+  void EnterDartFrameWithInfo(intptr_t frame_size,
+                              Register new_pp, Register new_pc);
 
   // Set up a Dart frame for a function compiled for on-stack replacement.
   // The frame layout is a normal Dart frame, but the frame is partially set
   // up on entry (it is the frame of the unoptimized code).
-  void EnterOsrFrame(intptr_t extra_size);
+  void EnterOsrFrame(intptr_t extra_size, Register new_pp, Register new_pc);
 
   // Set up a stub frame so that the stack traversal code can easily identify
   // a stub frame.
@@ -768,8 +795,9 @@
   //   pushq immediate(0)
   //   .....
   void EnterStubFrame();
+  void EnterStubFrameWithPP();
 
-  // Instruction pattern from entrypoint is used in dart frame prologs
+  // Instruction pattern from entrypoint is used in dart frame prologues
   // to set up the frame and save a PC which can be used to figure out the
   // RawInstruction object corresponding to the code running in the frame.
   // entrypoint:
@@ -802,7 +830,13 @@
 
  private:
   AssemblerBuffer buffer_;
-  GrowableObjectArray& object_pool_;  // Object pool is not used on x64.
+
+  // Objects and jump targets.
+  GrowableObjectArray& object_pool_;
+
+  // Patchability of pool entries.
+  GrowableArray<Patchability> patchable_pool_entries_;
+
   int prologue_offset_;
 
   class CodeComment : public ZoneAllocated {
@@ -822,6 +856,16 @@
 
   GrowableArray<CodeComment*> comments_;
 
+  intptr_t FindObject(const Object& obj, Patchability patchable);
+  intptr_t FindExternalLabel(const ExternalLabel* label,
+                             Patchability patchable);
+  void LoadExternalLabel(Register dst,
+                         const ExternalLabel* label,
+                         Patchability patchable,
+                         Register pp);
+  bool CanLoadFromObjectPool(const Object& object);
+  void LoadWordFromPoolOffset(Register dst, Register pp, int32_t offset);
+
   inline void EmitUint8(uint8_t value);
   inline void EmitInt32(int32_t value);
   inline void EmitInt64(int64_t value);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index cbad36f..2d148cd 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -200,6 +200,28 @@
   __ movq(RAX, Address(R13, R10, TIMES_2, 256 * kWordSize));
   __ movq(RAX, Address(R13, R12, TIMES_2, 256 * kWordSize));
   __ movq(RAX, Address(R13, R13, TIMES_2, 256 * kWordSize));
+
+  __ movq(RAX, Address::AddressBaseImm32(RSP, 0));
+  __ movq(RAX, Address::AddressBaseImm32(RBP, 0));
+  __ movq(RAX, Address::AddressBaseImm32(RAX, 0));
+  __ movq(RAX, Address::AddressBaseImm32(R10, 0));
+  __ movq(RAX, Address::AddressBaseImm32(R12, 0));
+  __ movq(RAX, Address::AddressBaseImm32(R13, 0));
+  __ movq(R10, Address::AddressBaseImm32(RAX, 0));
+
+  __ movq(RAX, Address::AddressBaseImm32(RSP, kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(RBP, kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(RAX, kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R10, kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R12, kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R13, kWordSize));
+
+  __ movq(RAX, Address::AddressBaseImm32(RSP, -kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(RBP, -kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(RAX, -kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R10, -kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R12, -kWordSize));
+  __ movq(RAX, Address::AddressBaseImm32(R13, -kWordSize));
 }
 
 
@@ -2159,14 +2181,15 @@
   ObjectStore* object_store = Isolate::Current()->object_store();
   const Object& obj = Object::ZoneHandle(object_store->smi_class());
   Label fail;
-  __ LoadObject(RAX, obj);
+  __ EnterDartFrame(0);
+  __ LoadObject(RAX, obj, PP);
   __ CompareObject(RAX, obj);
   __ j(NOT_EQUAL, &fail);
-  __ LoadObject(RCX, obj);
+  __ LoadObject(RCX, obj, PP);
   __ CompareObject(RCX, obj);
   __ j(NOT_EQUAL, &fail);
   const Smi& smi = Smi::ZoneHandle(Smi::New(15));
-  __ LoadObject(RCX, smi);
+  __ LoadObject(RCX, smi, PP);
   __ CompareObject(RCX, smi);
   __ j(NOT_EQUAL, &fail);
   __ pushq(RAX);
@@ -2180,9 +2203,11 @@
   __ CompareObject(RCX, smi);
   __ j(NOT_EQUAL, &fail);
   __ movl(RAX, Immediate(1));  // OK
+  __ LeaveFrameWithPP();
   __ ret();
   __ Bind(&fail);
   __ movl(RAX, Immediate(0));  // Fail.
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -2393,12 +2418,14 @@
 
 // Called from assembler_test.cc.
 ASSEMBLER_TEST_GENERATE(StoreIntoObject, assembler) {
+  __ EnterDartFrame(0);
   __ pushq(CTX);
   __ movq(CTX, RDI);
   __ StoreIntoObject(RDX,
                      FieldAddress(RDX, GrowableObjectArray::data_offset()),
                      RSI);
   __ popq(CTX);
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 467de8c..2c911eb 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -12,19 +12,21 @@
 
 namespace dart {
 
-#define DEFINE_VISIT_FUNCTION(type, name)                                      \
-  void type::Visit(AstNodeVisitor* visitor) {                                  \
-    visitor->Visit##type(this);                                                \
-  }
-NODE_LIST(DEFINE_VISIT_FUNCTION)
+#define DEFINE_VISIT_FUNCTION(BaseName)                                        \
+void BaseName##Node::Visit(AstNodeVisitor* visitor) {                          \
+  visitor->Visit##BaseName##Node(this);                                        \
+}
+
+FOR_EACH_NODE(DEFINE_VISIT_FUNCTION)
 #undef DEFINE_VISIT_FUNCTION
 
 
-#define DEFINE_NAME_FUNCTION(type, name)                                       \
-  const char* type::ShortName() const {                                        \
-    return name;                                                               \
-  }
-NODE_LIST(DEFINE_NAME_FUNCTION)
+#define DEFINE_NAME_FUNCTION(BaseName)                                         \
+const char* BaseName##Node::PrettyName() const {                               \
+  return #BaseName;                                                            \
+}
+
+FOR_EACH_NODE(DEFINE_NAME_FUNCTION)
 #undef DEFINE_NAME_FUNCTION
 
 
@@ -35,12 +37,13 @@
   explicit AstNodeCollector(GrowableArray<AstNode*>* nodes)
     : nodes_(nodes) { }
 
-#define DEFINE_VISITOR_FUNCTION(type, name)                                    \
-  virtual void Visit##type(type* node) {                                       \
+#define DEFINE_VISITOR_FUNCTION(BaseName)                                      \
+  virtual void Visit##BaseName##Node(BaseName##Node* node) {                   \
     nodes_->Add(node);                                                         \
     node->VisitChildren(this);                                                 \
   }
-NODE_LIST(DEFINE_VISITOR_FUNCTION)
+
+FOR_EACH_NODE(DEFINE_VISITOR_FUNCTION)
 #undef DEFINE_VISITOR_FUNCTION
 
  private:
@@ -137,7 +140,7 @@
 }
 
 
-const char* TypeNode::Name() const {
+const char* TypeNode::TypeName() const {
   return String::Handle(type().UserVisibleName()).ToCString();
 }
 
@@ -150,8 +153,8 @@
 }
 
 
-const char* ComparisonNode::Name() const {
-  return Token::Str(kind_);
+const char* ComparisonNode::TokenName() const {
+  return (kind_ == Token::kAS) ? "as" : Token::Str(kind_);
 }
 
 
@@ -239,12 +242,12 @@
 }
 
 
-const char* BinaryOpNode::Name() const {
+const char* BinaryOpNode::TokenName() const {
   return Token::Str(kind_);
 }
 
 
-const char* BinaryOpWithMask32Node::Name() const {
+const char* BinaryOpWithMask32Node::TokenName() const {
   return Token::Str(kind());
 }
 
@@ -405,21 +408,16 @@
 }
 
 
-const char* UnaryOpNode::Name() const {
+const char* UnaryOpNode::TokenName() const {
   return Token::Str(kind_);
 }
 
 
-const char* JumpNode::Name() const {
+const char* JumpNode::TokenName() const {
   return Token::Str(kind_);
 }
 
 
-const char* LoadLocalNode::Name() const {
-  return local().name().ToCString();
-}
-
-
 bool LoadLocalNode::IsPotentiallyConst() const {
   // Parameters of const constructors are implicitly final and can be
   // used in initializer expressions.
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 4b40760..2f7af98 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -15,56 +15,56 @@
 
 namespace dart {
 
-#define NODE_LIST(V)                                                           \
-  V(ReturnNode, "return")                                                      \
-  V(LiteralNode, "literal")                                                    \
-  V(TypeNode, "type")                                                          \
-  V(AssignableNode, "assignable")                                              \
-  V(BinaryOpNode, "binop")                                                     \
-  V(BinaryOpWithMask32Node, "binop with mask 32")                              \
-  V(ComparisonNode, "compare")                                                 \
-  V(UnaryOpNode, "unaryop")                                                    \
-  V(ConditionalExprNode, "?:")                                                 \
-  V(IfNode, "if")                                                              \
-  V(SwitchNode, "switch")                                                      \
-  V(CaseNode, "case")                                                          \
-  V(WhileNode, "while")                                                        \
-  V(DoWhileNode, "dowhile")                                                    \
-  V(ForNode, "for")                                                            \
-  V(JumpNode, "jump")                                                          \
-  V(ArgumentListNode, "args")                                                  \
-  V(ArrayNode, "array")                                                        \
-  V(ClosureNode, "closure")                                                    \
-  V(InstanceCallNode, "instance call")                                         \
-  V(StaticCallNode, "static call")                                             \
-  V(ClosureCallNode, "closure call")                                           \
-  V(CloneContextNode, "clone context")                                         \
-  V(ConstructorCallNode, "constructor call")                                   \
-  V(InstanceGetterNode, "instance getter call")                                \
-  V(InstanceSetterNode, "instance setter call")                                \
-  V(StaticGetterNode, "static getter")                                         \
-  V(StaticSetterNode, "static setter")                                         \
-  V(NativeBodyNode, "native body")                                             \
-  V(PrimaryNode, "primary")                                                    \
-  V(LoadLocalNode, "load local")                                               \
-  V(StoreLocalNode, "store local")                                             \
-  V(LoadInstanceFieldNode, "load field")                                       \
-  V(StoreInstanceFieldNode, "store field")                                     \
-  V(LoadStaticFieldNode, "load static field")                                  \
-  V(StoreStaticFieldNode, "store static field")                                \
-  V(LoadIndexedNode, "load indexed")                                           \
-  V(StoreIndexedNode, "store indexed")                                         \
-  V(SequenceNode, "seq")                                                       \
-  V(LetNode, "let")                                                            \
-  V(CatchClauseNode, "catch clause block")                                     \
-  V(TryCatchNode, "try catch block")                                           \
-  V(ThrowNode, "throw")                                                        \
-  V(InlinedFinallyNode, "inlined finally")                                     \
+#define FOR_EACH_NODE(V)                                                       \
+  V(Return)                                                                    \
+  V(Literal)                                                                   \
+  V(Type)                                                                      \
+  V(Assignable)                                                                \
+  V(BinaryOp)                                                                  \
+  V(BinaryOpWithMask32)                                                        \
+  V(Comparison)                                                                \
+  V(UnaryOp)                                                                   \
+  V(ConditionalExpr)                                                           \
+  V(If)                                                                        \
+  V(Switch)                                                                    \
+  V(Case)                                                                      \
+  V(While)                                                                     \
+  V(DoWhile)                                                                   \
+  V(For)                                                                       \
+  V(Jump)                                                                      \
+  V(ArgumentList)                                                              \
+  V(Array)                                                                     \
+  V(Closure)                                                                   \
+  V(InstanceCall)                                                              \
+  V(StaticCall)                                                                \
+  V(ClosureCall)                                                               \
+  V(CloneContext)                                                              \
+  V(ConstructorCall)                                                           \
+  V(InstanceGetter)                                                            \
+  V(InstanceSetter)                                                            \
+  V(StaticGetter)                                                              \
+  V(StaticSetter)                                                              \
+  V(NativeBody)                                                                \
+  V(Primary)                                                                   \
+  V(LoadLocal)                                                                 \
+  V(StoreLocal)                                                                \
+  V(LoadInstanceField)                                                         \
+  V(StoreInstanceField)                                                        \
+  V(LoadStaticField)                                                           \
+  V(StoreStaticField)                                                          \
+  V(LoadIndexed)                                                               \
+  V(StoreIndexed)                                                              \
+  V(Sequence)                                                                  \
+  V(Let)                                                                       \
+  V(CatchClause)                                                               \
+  V(TryCatch)                                                                  \
+  V(Throw)                                                                     \
+  V(InlinedFinally)                                                            \
 
 
-#define DEFINE_FORWARD_DECLARATION(type, name) class type;
-NODE_LIST(DEFINE_FORWARD_DECLARATION)
-#undef DEFINE_FORWARD_DECLARATION
+#define FORWARD_DECLARATION(BaseName) class BaseName##Node;
+FOR_EACH_NODE(FORWARD_DECLARATION)
+#undef FORWARD_DECLARATION
 
 
 // Abstract class to implement an AST node visitor. An example is AstPrinter.
@@ -73,9 +73,10 @@
   AstNodeVisitor() {}
   virtual ~AstNodeVisitor() {}
 
-#define DEFINE_VISITOR_FUNCTION(type, name)                                    \
-  virtual void Visit##type(type* node) { }
-NODE_LIST(DEFINE_VISITOR_FUNCTION)
+#define DEFINE_VISITOR_FUNCTION(BaseName)                                      \
+  virtual void Visit##BaseName##Node(BaseName##Node* node) { }
+
+  FOR_EACH_NODE(DEFINE_VISITOR_FUNCTION)
 #undef DEFINE_VISITOR_FUNCTION
 
  private:
@@ -85,7 +86,7 @@
 
 #define DECLARE_COMMON_NODE_FUNCTIONS(type)                                    \
   virtual void Visit(AstNodeVisitor* visitor);                                 \
-  virtual const char* ShortName() const;                                       \
+  virtual const char* PrettyName() const;                                      \
   virtual bool Is##type() const { return true; }                               \
   virtual type* As##type() { return this; }
 
@@ -99,22 +100,16 @@
 
   intptr_t token_pos() const { return token_pos_; }
 
-#define AST_TYPE_CHECK(type, name)                                             \
-  virtual bool Is##type() const { return false; }                              \
-  virtual type* As##type() { return NULL; }
-NODE_LIST(AST_TYPE_CHECK)
+#define AST_TYPE_CHECK(BaseName)                                               \
+  virtual bool Is##BaseName##Node() const { return false; }                    \
+  virtual BaseName##Node* As##BaseName##Node() { return NULL; }
+
+  FOR_EACH_NODE(AST_TYPE_CHECK)
 #undef AST_TYPE_CHECK
 
   virtual void Visit(AstNodeVisitor* visitor) = 0;
   virtual void VisitChildren(AstNodeVisitor* visitor) const = 0;
-  virtual const char* ShortName() const = 0;
-
-  // 'ShortName' is predefined for each AstNode and is the default
-  // implementation of "Name()". Each AST node can override the function
-  // "Name" to do more complex name composition.
-  virtual const char* Name() const {
-    return ShortName();
-  }
+  virtual const char* PrettyName() const = 0;
 
   // Convert the node into an assignment node using the rhs which is passed in,
   // this is typically used for converting nodes like LoadLocalNode,
@@ -358,7 +353,7 @@
 
   const AbstractType& type() const { return type_; }
 
-  virtual const char* Name() const;
+  const char* TypeName() const;
 
   virtual const Instance* EvalConstExpr() const {
     // TODO(regis): What if the type is malbounded?
@@ -547,7 +542,7 @@
     right()->Visit(visitor);
   }
 
-  virtual const char* Name() const;
+  const char* TokenName() const;
   virtual bool IsPotentiallyConst() const;
   virtual const Instance* EvalConstExpr() const;
 
@@ -591,7 +586,7 @@
     right()->Visit(visitor);
   }
 
-  virtual const char* Name() const;
+  const char* TokenName() const;
   virtual bool IsPotentiallyConst() const;
   virtual const Instance* EvalConstExpr() const;
 
@@ -627,7 +622,7 @@
     return mask32_;
   }
 
-  virtual const char* Name() const;
+  const char* TokenName() const;
   DECLARE_COMMON_NODE_FUNCTIONS(BinaryOpWithMask32Node);
 
  private:
@@ -660,7 +655,7 @@
     operand()->Visit(visitor);
   }
 
-  virtual const char* Name() const;
+  const char* TokenName() const;
   virtual bool IsPotentiallyConst() const;
   virtual const Instance* EvalConstExpr() const;
 
@@ -900,7 +895,7 @@
 };
 
 
-// initializer, condition, increment expressions can be NULL.
+// The condition can be NULL.
 class ForNode : public AstNode {
  public:
   ForNode(intptr_t token_pos,
@@ -978,7 +973,7 @@
     inlined_finally_list_.Add(finally_node);
   }
 
-  virtual const char* Name() const;
+  const char* TokenName() const;
 
   virtual void VisitChildren(AstNodeVisitor* visitor) const { }
 
@@ -1003,7 +998,6 @@
 
   virtual void VisitChildren(AstNodeVisitor* visitor) const { }
 
-  virtual const char* Name() const;
   virtual const Instance* EvalConstExpr() const;
   virtual bool IsPotentiallyConst() const;
   virtual AstNode* MakeAssignmentNode(AstNode* rhs);
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 21ff734..2847085 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -18,23 +18,22 @@
 
 
 void AstPrinter::VisitGenericAstNode(AstNode* node) {
-  OS::Print("(%s ", node->Name());
+  OS::Print("(%s ", node->PrettyName());
   node->VisitChildren(this);
   OS::Print(")");
 }
 
 
-void AstPrinter::VisitSequenceNode(SequenceNode* node_sequence) {
+void AstPrinter::VisitSequenceNode(SequenceNode* node) {
   // TODO(regis): Make the output more readable by indenting the nested
   // sequences. This could be achieved using a AstPrinterContext similar to the
   // CodeGeneratorContext.
-  ASSERT(node_sequence != NULL);
-  for (int i = 0; i < node_sequence->length(); i++) {
-    OS::Print("scope %p: ",
-              node_sequence->scope());
-    node_sequence->NodeAt(i)->Visit(this);
+  OS::Print("(%s (scope \"%p\")", node->PrettyName(), node->scope());
+  for (int i = 0; i < node->length(); ++i) {
     OS::Print("\n");
+    node->NodeAt(i)->Visit(this);
   }
+  OS::Print(")");
 }
 
 
@@ -55,17 +54,19 @@
 
 void AstPrinter::VisitGenericLocalNode(AstNode* node,
                                        const LocalVariable& var) {
-  OS::Print("(%s %s%s '%s'",
-            node->Name(),
+  OS::Print("(%s %s%s \"%s\"",
+            node->PrettyName(),
             var.is_final() ? "final " : "",
             String::Handle(var.type().Name()).ToCString(),
             var.name().ToCString());
   if (var.HasIndex()) {
-    OS::Print(" @%d", var.index());
     if (var.is_captured()) {
-      OS::Print(" ctx %d", var.owner()->context_level());
+      OS::Print(" (context %d %d)", var.owner()->context_level(), var.index());
+    } else {
+      OS::Print(" (stack %d)", var.index());
     }
   }
+  OS::Print(" ");
   node->VisitChildren(this);
   OS::Print(")");
 }
@@ -82,8 +83,8 @@
 
 
 void AstPrinter::VisitGenericFieldNode(AstNode* node, const Field& field) {
-  OS::Print("(%s %s%s '%s' ",
-            node->Name(),
+  OS::Print("(%s %s%s \"%s\" ",
+            node->PrettyName(),
             field.is_final() ? "final " : "",
             String::Handle(AbstractType::Handle(field.type()).Name()).
                 ToCString(),
@@ -125,59 +126,63 @@
 
 void AstPrinter::VisitLiteralNode(LiteralNode* node) {
   const Instance& literal = node->literal();
-  OS::Print("'%s'", literal.ToCString());
+  OS::Print("(%s \"%s\")", node->PrettyName(), literal.ToCString());
 }
 
 
 void AstPrinter::VisitTypeNode(TypeNode* node) {
   const AbstractType& type = node->type();
-  OS::Print("'%s'", String::Handle(type.Name()).ToCString());
+  OS::Print("(%s \"%s\")",
+            node->PrettyName(),
+            String::Handle(type.Name()).ToCString());
 }
 
 
 void AstPrinter::VisitAssignableNode(AssignableNode* node) {
-  OS::Print("(assignable ");
-  node->expr()->Visit(this);
   const AbstractType& type = node->type();
   const String& dst_name = node->dst_name();
-  OS::Print(" to type '%s' of '%s')",
+  OS::Print("(%s (type \"%s\") (of \"%s\") ",
+            node->PrettyName(),
             String::Handle(type.Name()).ToCString(),
             dst_name.ToCString());
-}
-
-
-void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
-  OS::Print("***** PRIMARY NODE IN AST ***** (%s '%s')",
-      node->Name(), node->primary().ToCString());
-}
-
-
-void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
-  if (node->kind() == Token::kAS) {
-    OS::Print("(as ");
-    node->VisitChildren(this);
-    OS::Print(")");
-  } else {
-    VisitGenericAstNode(node);
-  }
-}
-
-
-void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
-  VisitGenericAstNode(node);
-}
-
-
-void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
-  OS::Print("(%s ", node->Name());
   node->VisitChildren(this);
-  OS::Print(" & 0x%" Px64 "", node->mask32());
   OS::Print(")");
 }
 
 
+void AstPrinter::VisitPrimaryNode(PrimaryNode* node) {
+  OS::Print("*****%s***** \"%s\")",
+            node->PrettyName(),
+            node->primary().ToCString());
+}
+
+
+void AstPrinter::VisitComparisonNode(ComparisonNode* node) {
+  OS::Print("(%s %s ", node->PrettyName(), node->TokenName());
+  node->VisitChildren(this);
+  OS::Print(")");
+}
+
+
+void AstPrinter::VisitBinaryOpNode(BinaryOpNode* node) {
+  OS::Print("(%s %s ", node->PrettyName(), node->TokenName());
+  node->VisitChildren(this);
+  OS::Print(")");
+}
+
+
+void AstPrinter::VisitBinaryOpWithMask32Node(BinaryOpWithMask32Node* node) {
+  OS::Print("(%s %s ", node->PrettyName(), node->TokenName());
+  node->VisitChildren(this);
+  OS::Print(" & \"0x%" Px64 "", node->mask32());
+  OS::Print("\")");
+}
+
+
 void AstPrinter::VisitUnaryOpNode(UnaryOpNode* node) {
-  VisitGenericAstNode(node);
+  OS::Print("(%s %s ", node->PrettyName(), node->TokenName());
+  node->VisitChildren(this);
+  OS::Print(")");
 }
 
 
@@ -187,25 +192,17 @@
 
 
 void AstPrinter::VisitIfNode(IfNode* node) {
-  OS::Print("(if ");
-  node->condition()->Visit(this);
-  OS::Print(" then ");
-  node->true_branch()->Visit(this);
-  OS::Print(" else ");
-  if (node->false_branch() != NULL) {
-    node->false_branch()->Visit(this);
-  }
-  OS::Print(")");
+  VisitGenericAstNode(node);
 }
 
 
 void AstPrinter::VisitCaseNode(CaseNode* node) {
-  OS::Print("(case (");
+  OS::Print("(%s (", node->PrettyName());
   for (int i = 0; i < node->case_expressions()->length(); i++) {
     node->case_expressions()->NodeAt(i)->Visit(this);
   }
   if (node->contains_default()) {
-    OS::Print(" default ");
+    OS::Print(" default");
   }
   OS::Print(")");
   node->statements()->Visit(this);
@@ -214,71 +211,66 @@
 
 
 void AstPrinter::VisitSwitchNode(SwitchNode* node) {
-  OS::Print("(switch ");
-  node->body()->Visit(this);
-  OS::Print(")");
+  VisitGenericAstNode(node);
 }
 
 
 void AstPrinter::VisitWhileNode(WhileNode* node) {
-  OS::Print("(while ");
-  node->condition()->Visit(this);
-  OS::Print(" do ");
-  node->body()->Visit(this);
-  OS::Print(")");
+  VisitGenericAstNode(node);
 }
 
 
 void AstPrinter::VisitForNode(ForNode* node) {
-  OS::Print("(for (init: ");
+  // Complicated because the condition is optional and so we clearly want to
+  // indicate the subparts.
+  OS::Print("(%s (init ", node->PrettyName());
   node->initializer()->Visit(this);
-  OS::Print("; cond:");
   if (node->condition() != NULL) {
+    OS::Print(") (cond ");
     node->condition()->Visit(this);
   }
-  OS::Print("; incr:");
+  OS::Print(") (update ");
   node->increment()->Visit(this);
-  OS::Print(") body:");
+  OS::Print(") ");
   node->body()->Visit(this);
-  OS::Print("endfor)");
-}
-
-
-void AstPrinter::VisitDoWhileNode(DoWhileNode* node) {
-  OS::Print("(do ");
-  node->body()->Visit(this);
-  OS::Print(" while ");
-  node->condition()->Visit(this);
   OS::Print(")");
 }
 
 
+void AstPrinter::VisitDoWhileNode(DoWhileNode* node) {
+  VisitGenericAstNode(node);
+}
+
+
 void AstPrinter::VisitJumpNode(JumpNode* node) {
-  OS::Print("(%s %s in scope %p)",
-            node->Name(),
+  OS::Print("(%s %s %s (scope \"%p\"))",
+            node->PrettyName(),
+            node->TokenName(),
             node->label()->name().ToCString(),
             node->label()->owner());
 }
 
 
 void AstPrinter::VisitInstanceCallNode(InstanceCallNode* node) {
-  OS::Print("(%s '%s'(", node->Name(), node->function_name().ToCString());
+  OS::Print("(%s \"%s\" ",
+            node->PrettyName(),
+            node->function_name().ToCString());
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitStaticCallNode(StaticCallNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  OS::Print("(%s '%s'(", node->Name(), function_fullname);
+  OS::Print("(%s \"%s\" ", node->PrettyName(), function_fullname);
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitClosureNode(ClosureNode* node) {
   const char* function_fullname = node->function().ToFullyQualifiedCString();
-  OS::Print("(%s '%s')", node->Name(), function_fullname);
+  OS::Print("(%s \"%s\")", node->PrettyName(), function_fullname);
 }
 
 
@@ -290,93 +282,88 @@
 void AstPrinter::VisitConstructorCallNode(ConstructorCallNode* node) {
   const char* kind = node->constructor().IsFactory() ? "factory " : "";
   const char* constructor_name = node->constructor().ToFullyQualifiedCString();
-  OS::Print("(%s %s'%s' ((this)", node->Name(), kind, constructor_name);
+  OS::Print("(%s %s \"%s\" ", node->PrettyName(), kind, constructor_name);
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitInstanceGetterNode(InstanceGetterNode* node) {
-  OS::Print("(%s 'get %s'(", node->Name(), node->field_name().ToCString());
+  OS::Print("(%s \"%s\" ",
+            node->PrettyName(),
+            node->field_name().ToCString());
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitInstanceSetterNode(InstanceSetterNode* node) {
-  OS::Print("(%s 'set %s'(", node->Name(), node->field_name().ToCString());
+  OS::Print("(%s \"%s\" ",
+            node->PrettyName(),
+            node->field_name().ToCString());
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitStaticGetterNode(StaticGetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
-  OS::Print("(%s '%s.%s'(",
-            node->Name(),
+  OS::Print("(%s \"%s.%s\")",
+            node->PrettyName(),
             class_name.ToCString(),
             node->field_name().ToCString());
-  OS::Print("))");
 }
 
 
 void AstPrinter::VisitStaticSetterNode(StaticSetterNode* node) {
   String& class_name = String::Handle(node->cls().Name());
-  OS::Print("(%s '%s.%s'(",
-      node->Name(), class_name.ToCString(), node->field_name().ToCString());
+  OS::Print("(%s \"%s.%s\" ",
+            node->PrettyName(),
+            class_name.ToCString(),
+            node->field_name().ToCString());
   node->VisitChildren(this);
-  OS::Print("))");
+  OS::Print(")");
 }
 
 
 void AstPrinter::VisitLoadIndexedNode(LoadIndexedNode* node) {
-  OS::Print("(%s%s ", node->Name(), node->IsSuperLoad() ? " super" : "");
+  OS::Print("(%s%s ", node->PrettyName(), node->IsSuperLoad() ? " super" : "");
   node->VisitChildren(this);
   OS::Print(")");
 }
 
 
 void AstPrinter::VisitStoreIndexedNode(StoreIndexedNode* node) {
-  OS::Print("(%s%s ", node->Name(), node->IsSuperStore() ? " super" : "");
+  OS::Print("(%s%s ", node->PrettyName(), node->IsSuperStore() ? " super" : "");
   node->VisitChildren(this);
   OS::Print(")");
 }
 
 
 void AstPrinter::VisitNativeBodyNode(NativeBodyNode* node) {
-  OS::Print("(native_c call '%s'(%d args))",
+  OS::Print("(%s \"%s\" (%d args))",
+            node->PrettyName(),
             node->native_c_function_name().ToCString(),
             NativeArguments::ParameterCountForResolution(node->function()));
 }
 
 
 void AstPrinter::VisitCatchClauseNode(CatchClauseNode* node) {
-  node->VisitChildren(this);
+  VisitGenericAstNode(node);
 }
 
 
 void AstPrinter::VisitTryCatchNode(TryCatchNode* node) {
-  OS::Print("(");
-
-  // First visit the try block.
-  OS::Print("(try block (");
+  OS::Print("(%s ", node->PrettyName());
   node->try_block()->Visit(this);
-  OS::Print("))");
-
-  // Now visit the catch block if it exists.
   if (node->catch_block() != NULL) {
-    OS::Print("(catch block () (");
     node->catch_block()->Visit(this);
-    OS::Print("))");
   }
-
-  // Now visit the finally block if it exists.
   if (node->finally_block() != NULL) {
-    OS::Print("(finally block () (");
+    OS::Print("(finally ");
     node->finally_block()->Visit(this);
-    OS::Print("))");
+    OS::Print(")");
   }
-
   OS::Print(")");
 }
 
diff --git a/runtime/vm/ast_printer.h b/runtime/vm/ast_printer.h
index d61a802b..f64d979 100644
--- a/runtime/vm/ast_printer.h
+++ b/runtime/vm/ast_printer.h
@@ -21,10 +21,11 @@
   static void PrintLocalScope(const LocalScope* scope, int variable_index);
 
 
-#define DEFINE_VISITOR_FUNCTION(type, name)                                    \
-  virtual void Visit##type(type* node);
-NODE_LIST(DEFINE_VISITOR_FUNCTION)
-#undef DEFINE_VISITOR_FUNCTION
+#define DECLARE_VISITOR_FUNCTION(BaseName)                                     \
+  virtual void Visit##BaseName##Node(BaseName##Node* node);
+
+  FOR_EACH_NODE(DECLARE_VISITOR_FUNCTION)
+#undef DECLARE_VISITOR_FUNCTION
 
  private:
   AstPrinter();
diff --git a/runtime/vm/bigint_operations.cc b/runtime/vm/bigint_operations.cc
index 7fba196e..b7c7a69 100644
--- a/runtime/vm/bigint_operations.cc
+++ b/runtime/vm/bigint_operations.cc
@@ -1291,6 +1291,34 @@
 }
 
 
+int64_t BigintOperations::BitLength(const Bigint& bigint) {
+  ASSERT(IsClamped(bigint));
+  intptr_t length = bigint.Length();
+  if (length == 0) return 0;
+  intptr_t last = length - 1;
+
+  Chunk high_chunk = bigint.GetChunkAt(last);
+  ASSERT(high_chunk != 0);
+  int64_t bit_length =
+      static_cast<int64_t>(kDigitBitSize) * last + CountBits(high_chunk);
+
+  if (bigint.IsNegative()) {
+    // We are calculating the 2's complement bitlength but we have a sign and
+    // magnitude representation.  The length is the same except when the
+    // magnitude is an exact power of two, 2^k.  In 2's complement format,
+    // -(2^k) takes one fewer bit than (2^k).
+
+    if ((high_chunk & (high_chunk - 1)) == 0) {  // Single bit set?
+      for (intptr_t i = 0; i < last; i++) {
+        if (bigint.GetChunkAt(i) != 0) return bit_length;
+      }
+      bit_length -= 1;
+    }
+  }
+  return bit_length;
+}
+
+
 int BigintOperations::Compare(const Bigint& a, const Bigint& b) {
   bool a_is_negative = a.IsNegative();
   bool b_is_negative = b.IsNegative();
diff --git a/runtime/vm/bigint_operations.h b/runtime/vm/bigint_operations.h
index 892ee6c..b38bc41 100644
--- a/runtime/vm/bigint_operations.h
+++ b/runtime/vm/bigint_operations.h
@@ -92,6 +92,7 @@
   static RawBigint* BitOr(const Bigint& a, const Bigint& b);
   static RawBigint* BitXor(const Bigint& a, const Bigint& b);
   static RawBigint* BitNot(const Bigint& bigint);
+  static int64_t BitLength(const Bigint& bigint);
 
   static int Compare(const Bigint& a, const Bigint& b);
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 8d807f4..826222b 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -45,9 +45,12 @@
   V(Smi_shlFromInt, 2)                                                         \
   V(Smi_shrFromInt, 2)                                                         \
   V(Smi_bitNegate, 1)                                                          \
+  V(Smi_bitLength, 1)                                                          \
   V(Mint_bitNegate, 1)                                                         \
+  V(Mint_bitLength, 1)                                                         \
   V(Mint_shlFromInt, 2)                                                        \
   V(Bigint_bitNegate, 1)                                                       \
+  V(Bigint_bitLength, 1)                                                       \
   V(Bigint_shlFromInt, 2)                                                      \
   V(Double_getIsNegative, 1)                                                   \
   V(Double_getIsInfinite, 1)                                                   \
@@ -259,7 +262,6 @@
   V(InstanceMirror_invokeSetter, 4)                                            \
   V(ClosureMirror_function, 1)                                                 \
   V(ClosureMirror_apply, 3)                                                    \
-  V(ClassMirror_name, 1)                                                       \
   V(ClassMirror_library, 1)                                                    \
   V(ClassMirror_supertype, 1)                                                  \
   V(ClassMirror_interfaces, 1)                                                 \
@@ -270,7 +272,7 @@
   V(ClassMirror_invoke, 5)                                                     \
   V(ClassMirror_invokeGetter, 3)                                               \
   V(ClassMirror_invokeSetter, 4)                                               \
-  V(ClassMirror_invokeConstructor, 4)                                          \
+  V(ClassMirror_invokeConstructor, 5)                                          \
   V(ClassMirror_type_variables, 1)                                             \
   V(ClassMirror_type_arguments, 1)                                             \
   V(LibraryMirror_invoke, 5)                                                   \
diff --git a/runtime/vm/cha_test.cc b/runtime/vm/cha_test.cc
index d63bf6a..e0bfc6c 100644
--- a/runtime/vm/cha_test.cc
+++ b/runtime/vm/cha_test.cc
@@ -33,24 +33,23 @@
   const Library& lib = Library::Handle(Library::LookupLibrary(name));
   EXPECT(!lib.IsNull());
 
-  String& ambiguity_error_msg = String::Handle();
   const Class& class_a = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
   EXPECT(!class_a.IsNull());
   const intptr_t class_a_id = class_a.id();
 
   const Class& class_b = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("B")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("B"))));
   EXPECT(!class_b.IsNull());
   const intptr_t class_b_id = class_b.id();
 
   const Class& class_c = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("C")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("C"))));
   EXPECT(!class_c.IsNull());
   const intptr_t class_c_id = class_c.id();
 
   const Class& class_d = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("D")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("D"))));
   EXPECT(!class_d.IsNull());
   const intptr_t class_d_id = class_d.id();
 
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 7b216f2..2214422 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -253,28 +253,21 @@
 
 
 // Resolve unresolved_class in the library of cls, or return null.
-RawClass* ClassFinalizer::ResolveClass(const Class& cls,
-                                       const UnresolvedClass& unresolved_class,
-                                       Error* ambiguity_error) {
+RawClass* ClassFinalizer::ResolveClass(
+      const Class& cls,
+      const UnresolvedClass& unresolved_class) {
   const String& class_name = String::Handle(unresolved_class.ident());
   Library& lib = Library::Handle();
   Class& resolved_class = Class::Handle();
-  String& ambiguity_error_msg = String::Handle();
   if (unresolved_class.library_prefix() == LibraryPrefix::null()) {
     lib = cls.library();
     ASSERT(!lib.IsNull());
-    resolved_class = lib.LookupClass(class_name, &ambiguity_error_msg);
+    resolved_class = lib.LookupClass(class_name);
   } else {
     LibraryPrefix& lib_prefix = LibraryPrefix::Handle();
     lib_prefix = unresolved_class.library_prefix();
     ASSERT(!lib_prefix.IsNull());
-    resolved_class = lib_prefix.LookupClass(class_name, &ambiguity_error_msg);
-  }
-  if (resolved_class.IsNull() && !ambiguity_error_msg.IsNull()) {
-    const Script& script = Script::Handle(cls.script());
-    *ambiguity_error = Parser::FormatErrorMsg(
-        script, unresolved_class.token_pos(), "Error",
-        "%s", ambiguity_error_msg.ToCString());
+    resolved_class = lib_prefix.LookupClass(class_name);
   }
   return resolved_class.raw();
 }
@@ -467,9 +460,8 @@
     // Lookup the type class.
     const UnresolvedClass& unresolved_class =
         UnresolvedClass::Handle(type.unresolved_class());
-    Error& ambiguous_error = Error::Handle();
     const Class& type_class =
-        Class::Handle(ResolveClass(cls, unresolved_class, &ambiguous_error));
+        Class::Handle(ResolveClass(cls, unresolved_class));
 
     // Replace unresolved class with resolved type class.
     const Type& parameterized_type = Type::Cast(type);
@@ -478,7 +470,7 @@
           FLAG_error_on_bad_type) {
         // The type class could not be resolved. The type is malformed.
         FinalizeMalformedType(
-            ambiguous_error,  // May be null.
+            Error::Handle(),  // No previous error.
             cls,
             parameterized_type,
             "cannot resolve class '%s' from '%s'",
@@ -1861,25 +1853,27 @@
       type_args.IsNull() ? 0 : type_args.Length();
   AbstractType& arg = AbstractType::Handle();
   if (num_type_arguments > 0) {
-    if (num_type_arguments != num_type_parameters) {
+    if (num_type_arguments == num_type_parameters) {
+      for (int i = 0; i < num_type_arguments; i++) {
+        arg = type_args.TypeAt(i);
+        collected_args.Add(arg);
+      }
+      return;
+    }
+    if (FLAG_error_on_bad_type) {
       const Script& script = Script::Handle(cls.script());
       const String& type_class_name = String::Handle(type_class.Name());
-      // TODO(regis): This should not be a compile time error anymore.
       ReportError(Error::Handle(),  // No previous error.
                   script, type.token_pos(),
                   "wrong number of type arguments for class '%s'",
                   type_class_name.ToCString());
     }
-    for (int i = 0; i < num_type_arguments; i++) {
-      arg = type_args.TypeAt(i);
-      collected_args.Add(arg);
-    }
-  } else {
-    // Fill arguments with type dynamic.
-    for (int i = 0; i < num_type_parameters; i++) {
-      arg = Type::DynamicType();
-      collected_args.Add(arg);
-    }
+    // Discard provided type arguments and treat type as raw.
+  }
+  // Fill arguments with type dynamic.
+  for (int i = 0; i < num_type_parameters; i++) {
+    arg = Type::DynamicType();
+    collected_args.Add(arg);
   }
 }
 
@@ -1889,18 +1883,16 @@
   // Resolve super type and all mixin types.
   const GrowableObjectArray& type_args =
       GrowableObjectArray::Handle(GrowableObjectArray::New());
-  AbstractType& type = AbstractType::Handle(mixin_app.super_type());
+  AbstractType& type = AbstractType::Handle(mixin_app.SuperType());
   ResolveType(cls, type, kCanonicalizeWellFormed);
   ASSERT(type.HasResolvedTypeClass());
   // TODO(hausner): May need to handle BoundedType here.
   ASSERT(type.IsType());
   CollectTypeArguments(cls, Type::Cast(type), type_args);
-  const Array& mixins = Array::Handle(mixin_app.mixin_types());
   Class& mixin_app_class = Class::Handle();
-  for (int i = 0; i < mixins.Length(); i++) {
-    type ^= mixins.At(i);
-    ASSERT(type.HasResolvedTypeClass());  // Newly created class in parser.
-    mixin_app_class ^= type.type_class();
+  const intptr_t depth = mixin_app.Depth();
+  for (int i = 0; i < depth; i++) {
+    mixin_app_class = mixin_app.MixinAppAt(i);
     type = mixin_app_class.mixin();
     ASSERT(!type.IsNull());
     ResolveType(cls, type, kCanonicalizeWellFormed);
@@ -1918,16 +1910,13 @@
     OS::Print("ResolveMixinAppType: mixin appl type args: %s\n",
               mixin_app_args.ToCString());
   }
-  // The last element in the mixins array is the lowest mixin application
-  // type in the mixin chain. Build a new super type with its type class
-  // and the collected type arguments from the super type and all
-  // mixin types. This super type replaces the MixinAppType object
-  // in the class that extends the mixin application.
-  type ^= mixins.At(mixins.Length() - 1);
-  mixin_app_class ^= type.type_class();
-  return Type::New(mixin_app_class,
-                   mixin_app_args,
-                   mixin_app.token_pos());
+  // The mixin application class at depth k is a subclass of mixin application
+  // class at depth k - 1. Build a new super type with the class at the highest
+  // depth (the last one processed by the loop above) as the type class and the
+  // collected type arguments from the super type and all mixin types.
+  // This super type replaces the MixinAppType object in the class that extends
+  // the mixin application.
+  return Type::New(mixin_app_class, mixin_app_args, mixin_app.token_pos());
 }
 
 
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 5221a2a..2d632e8 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -105,8 +105,7 @@
                                GrowableArray<intptr_t>* visited);
   static void CheckForLegalConstClass(const Class& cls);
   static RawClass* ResolveClass(const Class& cls,
-                                const UnresolvedClass& unresolved_class,
-                                Error* ambiguity_error);
+                                const UnresolvedClass& unresolved_class);
   static void ResolveRedirectingFactoryTarget(
       const Class& cls,
       const Function& factory,
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index f1c41db..8d33ebd 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -223,10 +223,9 @@
   const String& name = String::Handle(String::New(TestCase::url()));
   const Library& lib = Library::Handle(Library::LookupLibrary(name));
   EXPECT(!lib.IsNull());
-  String& ambiguity_error_msg = String::Handle();
   Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
+  EXPECT(!cls.IsNull());
 
   // Now compile the two functions 'A.foo' and 'A.moo'
   String& function_moo_name = String::Handle(String::New("moo"));
diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index cac140a..34ac993 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -275,8 +275,7 @@
 
 static RawClass* LookupClass(const Library& lib, const char* name) {
   const String& cls_name = String::ZoneHandle(Symbols::New(name));
-  String& ambiguity_error_msg = String::Handle();
-  return lib.LookupClass(cls_name, &ambiguity_error_msg);
+  return lib.LookupClass(cls_name);
 }
 
 
@@ -296,7 +295,7 @@
   EXPECT(CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
   Class& cls = Class::Handle(LookupClass(lib, "A"));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  EXPECT(!cls.IsNull());
 
   // 'bar' will not be compiled.
   String& function_bar_name = String::Handle(String::New("bar"));
@@ -343,7 +342,7 @@
   EXPECT(CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
   Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  EXPECT(!cls.IsNull());
 
   String& constructor_name = String::Handle(String::New("A."));
   Function& constructor =
@@ -535,7 +534,7 @@
   EXPECT(CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
   Class& cls = Class::ZoneHandle(LookupClass(lib, "A"));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  EXPECT(!cls.IsNull());
 
   String& constructor_name = String::Handle(String::New("A."));
   Function& constructor =
@@ -561,11 +560,9 @@
   Library& app_lib = Library::Handle();
   app_lib ^= libs.At(num_libs - 1);
   ASSERT(!app_lib.IsNull());
-  String& ambiguity_error_msg = String::Handle();
   const Class& cls = Class::Handle(
-      app_lib.LookupClass(String::Handle(Symbols::New("A")),
-                          &ambiguity_error_msg));
-  EXPECT_EQ(cls.raw(), result.clazz());  // No ambiguity error expected.
+      app_lib.LookupClass(String::Handle(Symbols::New("A"))));
+  EXPECT_EQ(cls.raw(), result.clazz());
 }
 
 }  // namespace dart
diff --git a/runtime/vm/code_patcher.cc b/runtime/vm/code_patcher.cc
index 986ade4..6fda035 100644
--- a/runtime/vm/code_patcher.cc
+++ b/runtime/vm/code_patcher.cc
@@ -29,11 +29,11 @@
   const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                 PcDescriptors::kEntryPatch);
   ASSERT(patch_addr != 0);
-  JumpPattern jmp_entry(patch_addr);
+  JumpPattern jmp_entry(patch_addr, code);
   ASSERT(!jmp_entry.IsValid());
   const uword patch_buffer = code.GetPatchCodePc();
   ASSERT(patch_buffer != 0);
-  JumpPattern jmp_patch(patch_buffer);
+  JumpPattern jmp_patch(patch_buffer, code);
   ASSERT(jmp_patch.IsValid());
   const uword jump_target = jmp_patch.TargetAddress();
   SwapCode(jmp_patch.pattern_length_in_bytes(),
@@ -49,13 +49,13 @@
   const uword patch_addr = code.GetPcForDeoptId(Isolate::kNoDeoptId,
                                                 PcDescriptors::kEntryPatch);
   ASSERT(patch_addr != 0);
-  JumpPattern jmp_entry(patch_addr);
+  JumpPattern jmp_entry(patch_addr, code);
   ASSERT(jmp_entry.IsValid());
   const uword jump_target = jmp_entry.TargetAddress();
   const uword patch_buffer = code.GetPatchCodePc();
   ASSERT(patch_buffer != 0);
   // 'patch_buffer' contains original entry code.
-  JumpPattern jmp_patch(patch_buffer);
+  JumpPattern jmp_patch(patch_buffer, code);
   ASSERT(!jmp_patch.IsValid());
   SwapCode(jmp_patch.pattern_length_in_bytes(),
            reinterpret_cast<char*>(patch_addr),
@@ -72,7 +72,7 @@
   if (patch_addr == 0) {
     return true;
   }
-  JumpPattern jmp_entry(patch_addr);
+  JumpPattern jmp_entry(patch_addr, code);
   if (code.Size() < (jmp_entry.pattern_length_in_bytes() * 2)) {
     return false;
   }
diff --git a/runtime/vm/code_patcher_x64.cc b/runtime/vm/code_patcher_x64.cc
index ae307d57..5782527 100644
--- a/runtime/vm/code_patcher_x64.cc
+++ b/runtime/vm/code_patcher_x64.cc
@@ -16,53 +16,60 @@
 namespace dart {
 
 // The expected pattern of a Dart unoptimized call (static and instance):
-//  00: 48 bb imm64  mov RBX, ic-data
-//  10: 49 bb imm64  mov R11, target_address
-//  20: 41 ff d3   call R11
-//  23 <- return address
+//  00: 49 8b 9f imm32  mov RBX, [PP + off]
+//  07: 4d 8b 9f imm32  mov R11, [PP + off]
+//  14: 41 ff d3        call R11
+//  17 <- return address
 class UnoptimizedCall : public ValueObject {
  public:
-  explicit UnoptimizedCall(uword return_address)
-      : start_(return_address - kCallPatternSize) {
+  UnoptimizedCall(uword return_address, const Code& code)
+      : start_(return_address - kCallPatternSize),
+        object_pool_(Array::Handle(code.ObjectPool())) {
     ASSERT(IsValid(return_address));
-    ASSERT((kCallPatternSize - 10) == Assembler::kCallExternalLabelSize);
+    ASSERT((kCallPatternSize - 7) == Assembler::kCallExternalLabelSize);
   }
 
-  static const int kCallPatternSize = 23;
+  static const int kCallPatternSize = 17;
 
   static bool IsValid(uword return_address) {
     uint8_t* code_bytes =
         reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
-    return (code_bytes[00] == 0x48) && (code_bytes[01] == 0xBB) &&
-           (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
-           (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
-           (code_bytes[22] == 0xD3);
+    return (code_bytes[0] == 0x49) && (code_bytes[1] == 0x8B) &&
+           (code_bytes[2] == 0x9F) &&
+           (code_bytes[7] == 0x4D) && (code_bytes[8] == 0x8B) &&
+           (code_bytes[9] == 0x9F) &&
+           (code_bytes[14] == 0x41) && (code_bytes[15] == 0xFF) &&
+           (code_bytes[16] == 0xD3);
   }
 
   RawObject* ic_data() const {
-    return *reinterpret_cast<RawObject**>(start_ + 0 + 2);
+    int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
+    return object_pool_.At(index);
   }
 
   uword target() const {
-    return *reinterpret_cast<uword*>(start_ + 10 + 2);
+    int index = InstructionPattern::IndexFromPPLoad(start_ + 10);
+    return reinterpret_cast<uword>(object_pool_.At(index));
   }
 
   void set_target(uword target) const {
-    uword* target_addr = reinterpret_cast<uword*>(start_ + 10 + 2);
-    *target_addr = target;
-    CPU::FlushICache(start_ + 10, 2 + 8);
+    int index = InstructionPattern::IndexFromPPLoad(start_ + 10);
+    const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
+    object_pool_.SetAt(index, smi);
+    // No need to flush the instruction cache, since the code is not modified.
   }
 
  private:
   uword start_;
+  const Array& object_pool_;
   DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall);
 };
 
 
 class InstanceCall : public UnoptimizedCall {
  public:
-  explicit InstanceCall(uword return_address)
-      : UnoptimizedCall(return_address) {
+  InstanceCall(uword return_address, const Code& code)
+      : UnoptimizedCall(return_address, code) {
 #if defined(DEBUG)
     ICData& test_ic_data = ICData::Handle();
     test_ic_data ^= ic_data();
@@ -77,8 +84,8 @@
 
 class UnoptimizedStaticCall : public UnoptimizedCall {
  public:
-  explicit UnoptimizedStaticCall(uword return_address)
-      : UnoptimizedCall(return_address) {
+  UnoptimizedStaticCall(uword return_address, const Code& code)
+      : UnoptimizedCall(return_address, code) {
 #if defined(DEBUG)
     ICData& test_ic_data = ICData::Handle();
     test_ic_data ^= ic_data();
@@ -92,50 +99,54 @@
 
 
 // The expected pattern of a dart static call:
-//  mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls)
-//  mov R11, target_address (10 bytes)
-//  call R11  (3 bytes)
+//  00 mov R10, arguments_descriptor_array (10 bytes) (optional in polym. calls)
+//  11: 4d 8b 9f imm32  mov R11, [PP + off]
+//  16: call R11  (3 bytes)
 //  <- return address
 class StaticCall : public ValueObject {
  public:
-  explicit StaticCall(uword return_address)
-      : start_(return_address - kCallPatternSize) {
+  explicit StaticCall(uword return_address, const Code& code)
+      : start_(return_address - kCallPatternSize),
+        object_pool_(Array::Handle(code.ObjectPool())) {
     ASSERT(IsValid(return_address));
     ASSERT(kCallPatternSize == Assembler::kCallExternalLabelSize);
   }
 
-  static const int kCallPatternSize = 13;
+  static const int kCallPatternSize = 10;
 
   static bool IsValid(uword return_address) {
     uint8_t* code_bytes =
         reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
-    return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBB) &&
-           (code_bytes[10] == 0x41) && (code_bytes[11] == 0xFF) &&
-           (code_bytes[12] == 0xD3);
+    return (code_bytes[0] == 0x4D) && (code_bytes[1] == 0x8B) &&
+           (code_bytes[2] == 0x9F) &&
+           (code_bytes[7] == 0x41) && (code_bytes[8] == 0xFF) &&
+           (code_bytes[9] == 0xD3);
   }
 
   uword target() const {
-    return *reinterpret_cast<uword*>(start_ + 2);
+    int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
+    return reinterpret_cast<uword>(object_pool_.At(index));
   }
 
   void set_target(uword target) const {
-    uword* target_addr = reinterpret_cast<uword*>(start_ + 2);
-    *target_addr = target;
-    CPU::FlushICache(start_, 2 + 8);
+    int index = InstructionPattern::IndexFromPPLoad(start_ + 3);
+    const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
+    object_pool_.SetAt(index, smi);
+    // No need to flush the instruction cache, since the code is not modified.
   }
 
  private:
   uword start_;
-
+  const Array& object_pool_;
   DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCall);
 };
 
 
 // The expected code pattern of a dart closure call:
-//  00: 49 ba imm64  mov R10, immediate 2      ; 10 bytes
-//  10: 49 bb imm64  mov R11, target_address   ; 10 bytes
-//  20: 41 ff d3     call R11                  ; 3 bytes
-//  23: <- return_address
+//  00: 49 ba imm64     mov R10, immediate 2      ; 10 bytes
+//  10: 4d 8b 9f imm32  mov R11, [PP + off]
+//  17: 41 ff d3        call R11                  ; 3 bytes
+//  20: <- return_address
 class ClosureCall : public ValueObject {
  public:
   explicit ClosureCall(uword return_address)
@@ -147,9 +158,10 @@
     uint8_t* code_bytes =
         reinterpret_cast<uint8_t*>(return_address - kCallPatternSize);
     return (code_bytes[00] == 0x49) && (code_bytes[01] == 0xBA) &&
-           (code_bytes[10] == 0x49) && (code_bytes[11] == 0xBB) &&
-           (code_bytes[20] == 0x41) && (code_bytes[21] == 0xFF) &&
-           (code_bytes[22] == 0xD3);
+           (code_bytes[10] == 0x4D) && (code_bytes[11] == 0x8B) &&
+           (code_bytes[12] == 0x9F) &&
+           (code_bytes[17] == 0x41) && (code_bytes[18] == 0xFF) &&
+           (code_bytes[19] == 0xD3);
   }
 
   RawArray* arguments_descriptor() const {
@@ -157,7 +169,7 @@
   }
 
  private:
-  static const int kCallPatternSize = 10 + 10 + 3;
+  static const int kCallPatternSize = 10 + 7 + 3;
   uword start_;
   DISALLOW_IMPLICIT_CONSTRUCTORS(ClosureCall);
 };
@@ -174,7 +186,7 @@
 uword CodePatcher::GetStaticCallTargetAt(uword return_address,
                                          const Code& code) {
   ASSERT(code.ContainsInstructionAt(return_address));
-  StaticCall call(return_address);
+  StaticCall call(return_address, code);
   return call.target();
 }
 
@@ -183,7 +195,7 @@
                                     const Code& code,
                                     uword new_target) {
   ASSERT(code.ContainsInstructionAt(return_address));
-  StaticCall call(return_address);
+  StaticCall call(return_address, code);
   call.set_target(new_target);
 }
 
@@ -192,7 +204,7 @@
                                       const Code& code,
                                       uword new_target) {
   ASSERT(code.ContainsInstructionAt(return_address));
-  InstanceCall call(return_address);
+  InstanceCall call(return_address, code);
   call.set_target(new_target);
 }
 
@@ -201,7 +213,7 @@
                                      const Code& code,
                                      ICData* ic_data) {
   ASSERT(code.ContainsInstructionAt(return_address));
-  InstanceCall call(return_address);
+  InstanceCall call(return_address, code);
   if (ic_data != NULL) {
     *ic_data ^= call.ic_data();
   }
@@ -227,7 +239,7 @@
 RawFunction* CodePatcher::GetUnoptimizedStaticCallAt(
     uword return_address, const Code& code, ICData* ic_data_result) {
   ASSERT(code.ContainsInstructionAt(return_address));
-  UnoptimizedStaticCall static_call(return_address);
+  UnoptimizedStaticCall static_call(return_address, code);
   ICData& ic_data = ICData::Handle();
   ic_data ^= static_call.ic_data();
   if (ic_data_result != NULL) {
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 202c27a..67561db 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -39,10 +39,10 @@
                                                          15,
                                                          1));
 
-  __ LoadObject(RBX, ic_data);
+  __ LoadObject(RBX, ic_data, PP);
   ExternalLabel target_label(
       "InlineCache", StubCode::OneArgCheckInlineCacheEntryPoint());
-  __ call(&target_label);
+  __ CallPatchable(&target_label);
   __ ret();
 }
 
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 1e6ce14..1f2d1c2 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -46,7 +46,7 @@
     "Do loop invariant code motion.");
 DEFINE_FLAG(bool, propagate_types, true, "Do static type propagation.");
 DEFINE_FLAG(bool, allocation_sinking, true,
-    "attempt to sink temporary allocations to side exits");
+    "Attempt to sink temporary allocations to side exits");
 DEFINE_FLAG(int, deoptimization_counter_threshold, 16,
     "How many times we allow deoptimization before we disallow optimization.");
 DEFINE_FLAG(int, deoptimization_counter_licm_threshold, 8,
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index e962155..fcee41e 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -43,10 +43,9 @@
   Library& lib = Library::Handle(Library::CoreLibrary());
   EXPECT(CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
-  String& ambiguity_error_msg = String::Handle();
   Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
+  EXPECT(!cls.IsNull());
   String& function_foo_name = String::Handle(String::New("foo"));
   Function& function_foo =
       Function::Handle(cls.LookupStaticFunction(function_foo_name));
diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h
index 3fa9526..6839b67 100644
--- a/runtime/vm/constants_x64.h
+++ b/runtime/vm/constants_x64.h
@@ -85,8 +85,9 @@
 
 // Register aliases.
 const Register TMP = R11;  // Used as scratch register by the assembler.
-const Register CTX = R15;  // Caches current context in generated code.
-const Register PP = kNoRegister;  // No object pool pointer.
+const Register CTX = R14;  // Caches current context in generated code.
+// Caches object pool pointer in generated code.
+const Register PP = R15;
 const Register SPREG = RSP;  // Stack pointer register.
 const Register FPREG = RBP;  // Frame pointer register.
 const Register ICREG = RBX;  // IC data register.
diff --git a/runtime/vm/coverage.cc b/runtime/vm/coverage.cc
new file mode 100644
index 0000000..be99d26
--- /dev/null
+++ b/runtime/vm/coverage.cc
@@ -0,0 +1,95 @@
+// 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.
+
+#include "vm/coverage.h"
+
+#include "vm/isolate.h"
+#include "vm/json_stream.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, print_coverage, false, "Print code coverage.");
+
+void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) {
+  const Array& functions = Array::Handle(cls.functions());
+  ASSERT(!functions.IsNull());
+  Function& function = Function::Handle();
+  Code& code = Code::Handle();
+  Script& script = Script::Handle();
+  String& url = String::Handle();
+  String& name = String::Handle();
+  PcDescriptors& descriptors = PcDescriptors::Handle();
+  Array& ic_array = Array::Handle();
+  ICData& ic_data = ICData::Handle();
+  for (int i = 0; i < functions.Length(); i++) {
+    function ^= functions.At(i);
+    if (function.HasCode()) {
+      JSONObject jsobj(&jsarr);
+
+      script = function.script();
+      url = script.url();
+      name = function.QualifiedUserVisibleName();
+      jsobj.AddProperty("source", url.ToCString());
+      jsobj.AddProperty("function", name.ToCString());
+
+      code = function.unoptimized_code();
+      ic_array = code.ExtractTypeFeedbackArray();
+      descriptors = code.pc_descriptors();
+
+      JSONArray jsarr(&jsobj, "hits");
+      for (int j = 0; j < descriptors.Length(); j++) {
+        PcDescriptors::Kind kind = descriptors.DescriptorKind(j);
+        // Only IC based calls have counting.
+        if ((kind == PcDescriptors::kIcCall) ||
+            (kind == PcDescriptors::kUnoptStaticCall)) {
+          intptr_t deopt_id = descriptors.DeoptId(j);
+          ic_data ^= ic_array.At(deopt_id);
+          if (!ic_data.IsNull() && (ic_data.AggregateCount() > 0)) {
+            intptr_t token_pos = descriptors.TokenPos(j);
+            intptr_t line = -1;
+            intptr_t col = -1;
+            script.GetTokenLocation(token_pos, &line, &col);
+            JSONObject ic_info(&jsarr);
+            ic_info.AddProperty("line", line);
+            ic_info.AddProperty("col", col);
+            ic_info.AddProperty("count", ic_data.AggregateCount());
+          }
+        }
+      }
+    }
+  }
+}
+
+
+void CodeCoverage::Print(Isolate* isolate) {
+  JSONStream stream;
+
+  {
+    const GrowableObjectArray& libs = GrowableObjectArray::Handle(
+        isolate, isolate->object_store()->libraries());
+    Library& lib = Library::Handle();
+    Class& cls = Class::Handle();
+    JSONArray jsarr(&stream);
+    for (int i = 0; i < libs.Length(); i++) {
+      lib ^= libs.At(i);
+      ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+      while (it.HasNext()) {
+        cls = it.GetNextClass();
+        if (cls.is_finalized()) {
+          // Only classes that have been finalized do have a meaningful list of
+          // functions.
+          PrintClass(cls, jsarr);
+        }
+      }
+    }
+  }
+
+  OS::Print("### COVERAGE DATA ###\n"
+            "%s\n"
+            "### END ###\n", stream.ToCString());
+}
+
+}  // namespace dart
diff --git a/runtime/vm/coverage.h b/runtime/vm/coverage.h
new file mode 100644
index 0000000..9819105
--- /dev/null
+++ b/runtime/vm/coverage.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef VM_COVERAGE_H_
+#define VM_COVERAGE_H_
+
+#include "vm/allocation.h"
+#include "vm/flags.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, print_coverage);
+
+// Forward declarations.
+class Class;
+class Isolate;
+class JSONArray;
+
+class CodeCoverage : public AllStatic {
+ public:
+  static void Print(Isolate* isolate);
+
+ private:
+  static void PrintClass(const Class& cls, const JSONArray& arr);
+};
+
+}  // namespace dart
+
+#endif  // VM_COVERAGE_H_
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 350efa0..7a673f9 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -60,7 +60,7 @@
   if (obj.IsInstance()) {
     const Library& core_lib = Library::Handle(Library::CoreLibrary());
     const Class& list_class =
-        Class::Handle(core_lib.LookupClass(Symbols::List(), NULL));
+        Class::Handle(core_lib.LookupClass(Symbols::List()));
     ASSERT(!list_class.IsNull());
     const Instance& instance = Instance::Cast(obj);
     const Class& obj_class = Class::Handle(isolate, obj.clazz());
@@ -1073,8 +1073,7 @@
                               function_name,
                               kNumArguments,
                               Object::empty_array(),
-                              Resolver::kIsQualified,
-                              NULL));  // No ambiguity error expected.
+                              Resolver::kIsQualified));
   ASSERT(!function.IsNull());
   const Array& args = Array::Handle(isolate, Array::New(kNumArguments));
   args.SetAt(0, Integer::Handle(isolate, Integer::New(port_id)));
@@ -2102,7 +2101,7 @@
     return ApiError::New(message);
   }
   const Class& cls = Class::Handle(
-      isolate, lib.LookupClassAllowPrivate(class_name, NULL));
+      isolate, lib.LookupClassAllowPrivate(class_name));
   ASSERT(!cls.IsNull());
   Object& result = Object::Handle(isolate);
   String& dot_name = String::Handle(String::New("."));
@@ -2488,7 +2487,7 @@
       Library::Handle(isolate->object_store()->typed_data_library());
   ASSERT(!lib.IsNull());
   const Class& cls = Class::Handle(
-      isolate, lib.LookupClassAllowPrivate(Symbols::ByteData(), NULL));
+      isolate, lib.LookupClassAllowPrivate(Symbols::ByteData()));
   ASSERT(!cls.IsNull());
   return ResolveConstructor(CURRENT_FUNC,
                             cls,
@@ -2847,13 +2846,18 @@
     RETURN_TYPE_ERROR(isolate, type, Type);
   }
   Class& cls = Class::Handle(isolate);
+  AbstractTypeArguments& type_arguments =
+      AbstractTypeArguments::Handle(isolate);
+
   if (result.IsType()) {
     cls = Type::Cast(result).type_class();
+    type_arguments = Type::Cast(result).arguments();
   } else if (result.IsClass()) {
     // For backwards compatibility we allow class objects to be passed in
     // for now. This needs to be removed once all code that uses class
     // objects to invoke Dart_New is removed.
     cls ^= result.raw();
+    type_arguments = Type::Handle(cls.RareType()).arguments();
   } else {
     RETURN_TYPE_ERROR(isolate, type, Type);
   }
@@ -2914,12 +2918,18 @@
       Array::Handle(isolate, Array::New(number_of_arguments + extra_args));
   if (constructor.IsConstructor()) {
     // Constructors get the uninitialized object and a constructor phase.
+    if (!type_arguments.IsNull()) {
+      // The type arguments will be null if the class has no type parameters, in
+      // which case the following call would fail because there is no slot
+      // reserved in the object for the type vector.
+      new_object.SetTypeArguments(type_arguments);
+    }
     args.SetAt(arg_index++, new_object);
     args.SetAt(arg_index++,
                Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll)));
   } else {
     // Factories get type arguments.
-    args.SetAt(arg_index++, TypeArguments::Handle(isolate));
+    args.SetAt(arg_index++, type_arguments);
   }
   Object& argument = Object::Handle(isolate);
   for (int i = 0; i < number_of_arguments; i++) {
@@ -3082,14 +3092,9 @@
       return state;
     }
 
-    String& ambiguity_error_msg = String::Handle(isolate);
     Function& function = Function::Handle(isolate);
-    function = lib.LookupFunctionAllowPrivate(function_name,
-                                              &ambiguity_error_msg);
+    function = lib.LookupFunctionAllowPrivate(function_name);
     if (function.IsNull()) {
-      if (!ambiguity_error_msg.IsNull()) {
-        return Api::NewError("%s.", ambiguity_error_msg.ToCString());
-      }
       return Api::NewError("%s: did not find top-level function '%s'.",
                            CURRENT_FUNC,
                            function_name.ToCString());
@@ -3248,15 +3253,13 @@
     // To access a top-level we may need to use the Field or the
     // getter Function.  The getter function may either be in the
     // library or in the field's owner class, depending.
-    String& ambiguity_error_msg = String::Handle(isolate);
     const Library& lib = Library::Cast(obj);
-    field = lib.LookupFieldAllowPrivate(field_name, &ambiguity_error_msg);
-    if (field.IsNull() && ambiguity_error_msg.IsNull()) {
+    field = lib.LookupFieldAllowPrivate(field_name);
+    if (field.IsNull()) {
       // No field found and no ambiguity error.  Check for a getter in the lib.
       const String& getter_name =
           String::Handle(isolate, Field::GetterName(field_name));
-      getter = lib.LookupFunctionAllowPrivate(getter_name,
-                                              &ambiguity_error_msg);
+      getter = lib.LookupFunctionAllowPrivate(getter_name);
     } else if (!field.IsNull() && FieldIsUninitialized(isolate, field)) {
       // A field was found.  Check for a getter in the field's owner classs.
       const Class& cls = Class::Handle(isolate, field.owner());
@@ -3273,9 +3276,6 @@
     if (!field.IsNull()) {
       return Api::NewHandle(isolate, field.value());
     }
-    if (!ambiguity_error_msg.IsNull()) {
-      return Api::NewError("%s.",  ambiguity_error_msg.ToCString());
-    }
     return Api::NewError("%s: did not find top-level variable '%s'.",
                          CURRENT_FUNC, field_name.ToCString());
 
@@ -3405,14 +3405,12 @@
     // To access a top-level we may need to use the Field or the
     // setter Function.  The setter function may either be in the
     // library or in the field's owner class, depending.
-    String& ambiguity_error_msg = String::Handle(isolate);
     const Library& lib = Library::Cast(obj);
-    field = lib.LookupFieldAllowPrivate(field_name, &ambiguity_error_msg);
-    if (field.IsNull() && ambiguity_error_msg.IsNull()) {
+    field = lib.LookupFieldAllowPrivate(field_name);
+    if (field.IsNull()) {
       const String& setter_name =
           String::Handle(isolate, Field::SetterName(field_name));
-      setter ^= lib.LookupFunctionAllowPrivate(setter_name,
-                                               &ambiguity_error_msg);
+      setter ^= lib.LookupFunctionAllowPrivate(setter_name);
     }
 
     if (!setter.IsNull()) {
@@ -3435,9 +3433,6 @@
       field.set_value(value_instance);
       return Api::Success();
     }
-    if (!ambiguity_error_msg.IsNull()) {
-      return Api::NewError("%s.", ambiguity_error_msg.ToCString());
-    }
     return Api::NewError("%s: did not find top-level variable '%s'.",
                          CURRENT_FUNC, field_name.ToCString());
 
@@ -4031,13 +4026,9 @@
   if (cls_name.IsNull()) {
     RETURN_TYPE_ERROR(isolate, class_name, String);
   }
-  String& ambiguity_error_msg = String::Handle(isolate);
   const Class& cls = Class::Handle(
-      isolate, lib.LookupClassAllowPrivate(cls_name, &ambiguity_error_msg));
+      isolate, lib.LookupClassAllowPrivate(cls_name));
   if (cls.IsNull()) {
-    if (!ambiguity_error_msg.IsNull()) {
-      return Api::NewError("%s.", ambiguity_error_msg.ToCString());
-    }
     // TODO(turnidge): Return null or error in this case?
     const String& lib_name = String::Handle(isolate, lib.name());
     return Api::NewError("Class '%s' not found in library '%s'.",
@@ -4068,14 +4059,9 @@
   if (::Dart_IsError(state)) {
     return state;
   }
-  String& ambiguity_error_msg = String::Handle(isolate);
   const Class& cls =
-      Class::Handle(isolate, lib.LookupClassAllowPrivate(name_str,
-                                                         &ambiguity_error_msg));
+      Class::Handle(isolate, lib.LookupClassAllowPrivate(name_str));
   if (cls.IsNull()) {
-    if (!ambiguity_error_msg.IsNull()) {
-      return Api::NewError("%s.", ambiguity_error_msg.ToCString());
-    }
     const String& lib_name = String::Handle(isolate, lib.name());
     return Api::NewError("Type '%s' not found in library '%s'.",
                          name_str.ToCString(), lib_name.ToCString());
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index a9def3f..dda6809 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -5296,8 +5296,13 @@
   "  external B.named(x);\n"
   "  external B(v);\n"
   "}\n"
+  "class C {\n"
+  "  external int method();\n"
+  "}\n"
+  "\n"
   "external int unpatched();\n"
   "external int topLevel(var value);\n"
+  "external int topLevel2(var value);\n"
   "external int get topLevelGetter;\n"
   "external void set topLevelSetter(int value);\n";
 
@@ -5322,7 +5327,19 @@
   "patch int set topLevelSetter(value) { _topLevelValue = value; }\n"
   "patch int get topLevelGetter => 2 * _topLevelValue;\n"
   // Allow top level methods named patch.
-  "patch(x) => x*3;\n";
+  "patch(x) => x*3;\n"
+  ;  // NOLINT
+
+  const char* kPatchClassOnlyChars =
+  "patch class C {\n"
+  "  /*patch*/ int method() {\n"
+  "    return 42;\n"
+  "  }\n"
+  "}\n"
+  ;  // NOLINT
+
+  const char* kPatchNoClassChars =
+  "patch topLevel2(x) => x * 2;\n";
 
   const char* kScriptChars =
   "import 'theLibrary';\n"
@@ -5356,17 +5373,27 @@
   result = Dart_LoadLibrary(url, source);
   EXPECT_VALID(result);
 
-  const String& patch_url = String::Handle(String::New("theLibrary patch"));
-  const String& patch_source = String::Handle(String::New(kPatchChars));
-  const Script& patch_script = Script::Handle(Script::New(
-      patch_url, patch_source, RawScript::kPatchTag));
-
+  const char* patchNames[] = { "main library patch",
+                               "patch class only",
+                               "patch no class" };
+  const char* patches[] = { kPatchChars,
+                            kPatchClassOnlyChars,
+                            kPatchNoClassChars };
   const String& lib_url = String::Handle(String::New("theLibrary"));
+
   const Library& lib = Library::Handle(Library::LookupLibrary(lib_url));
-  const Error& err = Error::Handle(lib.Patch(patch_script));
-  if (!err.IsNull()) {
-    OS::Print("Patching error: %s\n", err.ToErrorCString());
-    EXPECT(false);
+
+  for (int i = 0; i < 3; i++) {
+    const String& patch_url = String::Handle(String::New(patchNames[i]));
+    const String& patch_source = String::Handle(String::New(patches[i]));
+    const Script& patch_script = Script::Handle(Script::New(
+        patch_url, patch_source, RawScript::kPatchTag));
+
+    const Error& err = Error::Handle(lib.Patch(patch_script));
+    if (!err.IsNull()) {
+      OS::Print("Patching error: %s\n", err.ToErrorCString());
+      EXPECT(false);
+    }
   }
   result = Dart_SetNativeResolver(result, &PatchNativeResolver);
   EXPECT_VALID(result);
@@ -5421,6 +5448,10 @@
   EXPECT(Dart_IsInteger(result));
   EXPECT_VALID(Dart_IntegerToInt64(result, &value));
   EXPECT_EQ(8, value);
+
+  // Make sure all source files show up in the patched library.
+  const Array& lib_scripts = Array::Handle(lib.LoadedScripts());
+  EXPECT_EQ(4, lib_scripts.Length());
 }
 
 
@@ -5597,7 +5628,7 @@
 
   result = Dart_Invoke(result, NewString("main"), 0, NULL);
   EXPECT(Dart_IsError(result));
-  EXPECT_SUBSTRING("ambiguous reference: 'foo'", Dart_GetError(result));
+  EXPECT_SUBSTRING("NoSuchMethodError", Dart_GetError(result));
 }
 
 
@@ -6889,9 +6920,9 @@
 
 
 TEST_CASE(MakeExternalString) {
-  int peer8 = 40;
-  int peer16 = 41;
-  int canonical_str_peer = 42;
+  static int peer8 = 40;
+  static int peer16 = 41;
+  static int canonical_str_peer = 42;
   intptr_t length = 0;
   intptr_t expected_length = 0;
   {
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 390e9fb..c8484f9 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -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.
 
+#include "vm/bigint_operations.h"
 #include "vm/dart_api_message.h"
 #include "vm/object.h"
 #include "vm/snapshot_ids.h"
@@ -887,17 +888,23 @@
 
   Dart_CObject_Type type = object->type;
   if (type == Dart_CObject_kArray) {
+    const intptr_t array_length = object->value.as_array.length;
+    if (array_length < 0 ||
+        array_length > Array::kMaxElements) {
+      return false;
+    }
+
     // Write out the serialization header value for this object.
     WriteInlinedHeader(object);
     // Write out the class and tags information.
     WriteIndexedObject(kArrayCid);
     WriteIntptrValue(0);
-
-    WriteSmi(object->value.as_array.length);
+    // Write out the length information.
+    WriteSmi(array_length);
     // Write out the type arguments.
     WriteNullObject();
     // Write out array elements.
-    for (int i = 0; i < object->value.as_array.length; i++) {
+    for (int i = 0; i < array_length; i++) {
       bool success = WriteCObjectRef(object->value.as_array.values[i]);
       if (!success) return false;
     }
@@ -916,12 +923,17 @@
 
   Dart_CObject_Type type = object->type;
   if (type == Dart_CObject_kArray) {
+    const intptr_t array_length = object->value.as_array.length;
+    if (array_length < 0 ||
+        array_length > Array::kMaxElements) {
+      return false;
+    }
     // Write out the serialization header value for this object.
     WriteInlinedHeader(object);
     // Write out the class information.
     WriteIndexedObject(kArrayCid);
     // Write out the length information.
-    WriteSmi(object->value.as_array.length);
+    WriteSmi(array_length);
     // Add object to forward list so that this object is serialized later.
     AddToForwardList(object);
     return true;
@@ -935,6 +947,11 @@
   Dart_CObject_Type type =
       static_cast<Dart_CObject_Type>(object->type & kDartCObjectTypeMask);
   ASSERT(type == Dart_CObject_kArray);
+  const intptr_t array_length = object->value.as_array.length;
+  if (array_length < 0 ||
+      array_length > Array::kMaxElements) {
+    return false;
+  }
 
   // Write out the serialization header value for this object.
   intptr_t object_id = GetMarkedCObjectMark(object);
@@ -942,12 +959,12 @@
   // Write out the class and tags information.
   WriteIndexedObject(kArrayCid);
   WriteIntptrValue(0);
-
-  WriteSmi(object->value.as_array.length);
+  // Write out the length information.
+  WriteSmi(array_length);
   // Write out the type arguments.
   WriteNullObject();
   // Write out array elements.
-  for (int i = 0; i < object->value.as_array.length; i++) {
+  for (int i = 0; i < array_length; i++) {
     bool success = WriteCObjectRef(object->value.as_array.values[i]);
     if (!success) return false;
   }
@@ -975,13 +992,19 @@
       WriteInt64(object);
       break;
     case Dart_CObject_kBigint: {
+      char* hex_string = object->value.as_bigint;
+      const intptr_t chunk_len =
+          BigintOperations::ComputeChunkLength(hex_string);
+      if (chunk_len < 0 ||
+          chunk_len > Bigint::kMaxElements) {
+        return false;
+      }
       // Write out the serialization header value for this object.
       WriteInlinedHeader(object);
       // Write out the class and tags information.
       WriteIndexedObject(kBigintCid);
       WriteIntptrValue(0);
       // Write hex string length and content
-      char* hex_string = object->value.as_bigint;
       intptr_t len = strlen(hex_string);
       WriteIntptrValue(len);
       for (intptr_t i = 0; i < len; i++) {
@@ -1008,6 +1031,10 @@
 
       Utf8::Type type;
       intptr_t len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type);
+      ASSERT(len > 0);
+      if (len > String::kMaxElements) {
+        return false;
+      }
 
       // Write out the serialization header value for this object.
       WriteInlinedHeader(object);
@@ -1059,11 +1086,16 @@
           UNIMPLEMENTED();
       }
 
+      intptr_t len = object->value.as_typed_data.length;
+      if (len < 0 ||
+          len > TypedData::MaxElements(class_id)) {
+        return false;
+      }
+
       WriteIndexedObject(class_id);
       WriteIntptrValue(RawObject::ClassIdTag::update(class_id, 0));
-      uint8_t* bytes = object->value.as_typed_data.values;
-      intptr_t len = object->value.as_typed_data.length;
       WriteSmi(len);
+      uint8_t* bytes = object->value.as_typed_data.values;
       for (intptr_t i = 0; i < len; i++) {
         Write<uint8_t>(bytes[i]);
       }
@@ -1081,7 +1113,12 @@
       WriteIndexedObject(kExternalTypedDataUint8ArrayCid);
       WriteIntptrValue(RawObject::ClassIdTag::update(
           kExternalTypedDataUint8ArrayCid, 0));
-      int length = object->value.as_external_typed_data.length;
+      intptr_t length = object->value.as_external_typed_data.length;
+      if (length < 0 ||
+          length > ExternalTypedData::MaxElements(
+              kExternalTypedDataUint8ArrayCid)) {
+        return false;
+      }
       uint8_t* data = object->value.as_external_typed_data.data;
       void* peer = object->value.as_external_typed_data.peer;
       Dart_WeakPersistentHandleFinalizer callback =
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 2c018c8..cb40979 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -118,8 +118,7 @@
 
   Class& invocation_mirror_class = Class::Handle(
       core_lib.LookupClass(
-          String::Handle(core_lib.PrivateName(Symbols::InvocationMirror())),
-          NULL));  // No ambiguity error expected.
+          String::Handle(core_lib.PrivateName(Symbols::InvocationMirror()))));
   ASSERT(!invocation_mirror_class.IsNull());
   const String& function_name =
       String::Handle(core_lib.PrivateName(Symbols::AllocateInvocationMirror()));
@@ -302,8 +301,7 @@
                                             const String& class_name,
                                             const String& constructor_name,
                                             const Array& arguments) {
-  const Class& cls = Class::Handle(
-      lib.LookupClassAllowPrivate(class_name, NULL));  // No ambiguity expected.
+  const Class& cls = Class::Handle(lib.LookupClassAllowPrivate(class_name));
   ASSERT(!cls.IsNull());
   // For now, we only support a non-parameterized or raw type.
   const int kNumExtraArgs = 2;  // implicit rcvr and construction phase args.
@@ -392,8 +390,7 @@
                                        function_name,
                                        kNumArguments,
                                        Object::empty_array(),
-                                       Resolver::kIsQualified,
-                                       NULL);  // No ambiguity error expected.
+                                       Resolver::kIsQualified);
     ASSERT(!function.IsNull());
     isolate->object_store()->set_lookup_receive_port_function(function);
   }
@@ -425,8 +422,7 @@
                                        function_name,
                                        kNumArguments,
                                        Object::empty_array(),
-                                       Resolver::kIsQualified,
-                                       NULL);  // No ambiguity error expected.
+                                       Resolver::kIsQualified);
     ASSERT(!function.IsNull());
     isolate->object_store()->set_handle_message_function(function);
   }
@@ -461,8 +457,7 @@
                               function_name,
                               kNumArguments,
                               Object::empty_array(),
-                              Resolver::kIsQualified,
-                              NULL));  // No ambiguity error expected.
+                              Resolver::kIsQualified));
   ASSERT(!function.IsNull());
   const Array& args = Array::Handle(Array::New(kNumArguments));
   args.SetAt(0, Integer::Handle(Integer::New(port_id)));
diff --git a/runtime/vm/dart_entry_test.cc b/runtime/vm/dart_entry_test.cc
index 0983efb..fa8cc81 100644
--- a/runtime/vm/dart_entry_test.cc
+++ b/runtime/vm/dart_entry_test.cc
@@ -27,9 +27,8 @@
   Library& lib = Library::Handle(Library::CoreLibrary());
   EXPECT_EQ(true, CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
-  String& ambiguity_error_msg = String::Handle();
   Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
   EXPECT(!cls.IsNull());  // No ambiguity error expected.
   String& name = String::Handle(String::New("foo"));
   Function& function = Function::Handle(cls.LookupStaticFunction(name));
@@ -56,9 +55,8 @@
   Library& lib = Library::Handle(Library::CoreLibrary());
   EXPECT_EQ(true, CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
-  String& ambiguity_error_msg = String::Handle();
   Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
   EXPECT(!cls.IsNull());  // No ambiguity error expected.
   String& name = String::Handle(String::New("foo"));
   Function& function = Function::Handle(cls.LookupStaticFunction(name));
@@ -84,9 +82,8 @@
   Library& lib = Library::Handle(Library::CoreLibrary());
   EXPECT_EQ(true, CompilerTest::TestCompileScript(lib, script));
   EXPECT(ClassFinalizer::FinalizePendingClasses());
-  String& ambiguity_error_msg = String::Handle();
   Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
   EXPECT(!cls.IsNull());  // No ambiguity error expected.
 
   // Invoke the constructor.
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index fae125c..9e02f77 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -829,9 +829,7 @@
                         const Library& library,
                         const String& fname) {
   ASSERT(!library.IsNull());
-  String& ambiguity_error_msg = String::Handle();
-  const Object& object = Object::Handle(
-      library.LookupObject(fname, &ambiguity_error_msg));
+  const Object& object = Object::Handle(library.LookupObject(fname));
   if (!object.IsNull() && object.IsFunction()) {
     return Function::Cast(object).raw();
   }
@@ -862,9 +860,7 @@
   if (class_name.Length() == 0) {
     return ResolveLibraryFunction(library, function_name);
   }
-  String& ambiguity_error_msg = String::Handle();
-  const Class& cls = Class::Handle(
-      library.LookupClass(class_name, &ambiguity_error_msg));
+  const Class& cls = Class::Handle(library.LookupClass(class_name));
   Function& function = Function::Handle();
   if (!cls.IsNull()) {
     function = cls.LookupStaticFunction(function_name);
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index f9bbe1c..09e24c0 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -255,6 +255,7 @@
 DART_EXPORT Dart_Handle Dart_ActivationFrameGetLocation(
                             Dart_ActivationFrame activation_frame,
                             Dart_Handle* function_name,
+                            Dart_Handle* function,
                             Dart_CodeLocation* location) {
   // TODO(hausner): Implement a way to recognize when there
   // is no source code for the code in the frame.
@@ -264,6 +265,9 @@
   if (function_name != NULL) {
     *function_name = Api::NewHandle(isolate, frame->QualifiedFunctionName());
   }
+  if (function != NULL) {
+    *function = Api::NewHandle(isolate, frame->function().raw());
+  }
 
   if (location != NULL) {
     location->script_url = Api::NewHandle(isolate, frame->SourceUrl());
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index b56bc15..2426b3f 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "include/dart_debugger_api.h"
+#include "include/dart_mirrors_api.h"
 #include "platform/assert.h"
 #include "vm/dart_api_impl.h"
 #include "vm/thread.h"
@@ -235,8 +236,9 @@
                              Dart_Handle expected_locals,
                              bool skip_null_expects) {
   Dart_Handle func_name;
+  Dart_Handle func;
   Dart_Handle res;
-  res = Dart_ActivationFrameInfo(frame, &func_name, NULL, NULL, NULL);
+  res = Dart_ActivationFrameGetLocation(frame, &func_name, &func, NULL);
   EXPECT_TRUE(res);
   EXPECT(Dart_IsString(func_name));
   const char* func_name_chars;
@@ -244,6 +246,11 @@
   if (expected_name != NULL) {
     EXPECT_SUBSTRING(expected_name, func_name_chars);
   }
+  EXPECT(Dart_IsFunction(func));
+  const char* func_name_chars_from_func_handle;
+  Dart_StringToCString(Dart_FunctionName(func),
+                       &func_name_chars_from_func_handle);
+  EXPECT_STREQ(func_name_chars, func_name_chars_from_func_handle);
 
   if (!Dart_IsNull(expected_locals)) {
     Dart_Handle locals = Dart_GetLocalVariables(frame);
@@ -1558,6 +1565,19 @@
   EXPECT(Dart_IsDouble(r));
   EXPECT_EQ(50.0, ToDouble(r));
 
+  Dart_Handle closure =
+      Dart_EvaluateExpr(point, NewString("() => _factor * sqrt(x*x + y*y))"));
+  EXPECT_VALID(closure);
+  EXPECT(Dart_IsClosure(closure));
+  r = Dart_InvokeClosure(closure, 0, NULL);
+  EXPECT_EQ(50.0, ToDouble(r));
+
+  r = Dart_EvaluateExpr(point,
+                        NewString("(() => _factor * sqrt(x*x + y*y))()"));
+  EXPECT_VALID(r);
+  EXPECT(Dart_IsDouble(r));
+  EXPECT_EQ(50.0, ToDouble(r));
+
   Dart_Handle len = Dart_EvaluateExpr(point, NewString("l.length"));
   EXPECT_VALID(len);
   EXPECT(Dart_IsNumber(len));
@@ -1583,6 +1603,20 @@
   EXPECT_VALID(len);
   EXPECT(Dart_IsNumber(len));
   EXPECT_EQ(6, ToInt64(len));
+
+  closure = Dart_EvaluateExpr(script_lib, NewString("(x) => l.length + x"));
+  EXPECT_VALID(closure);
+  EXPECT(Dart_IsClosure(closure));
+  Dart_Handle args[1] = { Dart_NewInteger(1) };
+  len = Dart_InvokeClosure(closure, 1, args);
+  EXPECT_VALID(len);
+  EXPECT(Dart_IsNumber(len));
+  EXPECT_EQ(6, ToInt64(len));
+
+  len = Dart_EvaluateExpr(script_lib, NewString("((x) => l.length + x)(1)"));
+  EXPECT_VALID(len);
+  EXPECT(Dart_IsNumber(len));
+  EXPECT_EQ(6, ToInt64(len));
 }
 
 
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index 29d3b33..f9b31c7 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -7,6 +7,7 @@
 
 #include "vm/debugger.h"
 
+#include "vm/assembler.h"
 #include "vm/cpu.h"
 #include "vm/stub_code.h"
 
@@ -42,16 +43,15 @@
 
 void CodeBreakpoint::PatchFunctionReturn() {
   uint8_t* code = reinterpret_cast<uint8_t*>(pc_ - 13);
-  // movq %rbp,%rsp
-  ASSERT((code[0] == 0x48) && (code[1] == 0x89) && (code[2] == 0xec));
-  ASSERT(code[3] == 0x5d);  // popq %rbp
-  ASSERT(code[4] == 0xc3);  // ret
-  // Next 8 bytes are nop instructions
-  ASSERT((code[5] == 0x90) && (code[6] == 0x90) &&
-         (code[7] == 0x90) && (code[8] == 0x90) &&
-         (code[9] == 0x90) && (code[10] == 0x90) &&
-         (code[11] == 0x90) && (code[12] == 0x90));
-         // Smash code with call instruction and relative target address.
+  ASSERT((code[0] == 0x4c) && (code[1] == 0x8b) && (code[2] == 0x7d) &&
+         (code[3] == 0xf0));  // movq r15,[rbp-0x10]
+  ASSERT((code[4] == 0x48) && (code[5] == 0x89) &&
+         (code[6] == 0xec));  // mov rsp, rbp
+  ASSERT(code[7] == 0x5d);  // pop rbp
+  ASSERT(code[8] == 0xc3);  // ret
+  ASSERT((code[9] == 0x0F) && (code[10] == 0x1F) && (code[11] == 0x40) &&
+         (code[12] == 0x00));  // nops
+  // Smash code with call instruction and relative target address.
   uword stub_addr = StubCode::BreakpointReturnEntryPoint();
   code[0] = 0x49;
   code[1] = 0xbb;
@@ -66,19 +66,13 @@
 void CodeBreakpoint::RestoreFunctionReturn() {
   uint8_t* code = reinterpret_cast<uint8_t*>(pc_ - 13);
   ASSERT((code[0] == 0x49) && (code[1] == 0xbb));
-  code[0] = 0x48;  // movq %rbp,%rsp
-  code[1] = 0x89;
-  code[2] = 0xec;
-  code[3] = 0x5d;  // popq %rbp
-  code[4] = 0xc3;  // ret
-  code[5] = 0x90;  // nop
-  code[6] = 0x90;  // nop
-  code[7] = 0x90;  // nop
-  code[8] = 0x90;  // nop
-  code[9] = 0x90;  // nop
-  code[10] = 0x90;  // nop
-  code[11] = 0x90;  // nop
-  code[12] = 0x90;  // nop
+
+  MemoryRegion code_region(reinterpret_cast<void*>(pc_ - 13), 13);
+  Assembler assembler;
+
+  assembler.ReturnPatchable();
+  assembler.FinalizeInstructions(code_region);
+
   CPU::FlushICache(pc_ - 13, 13);
 }
 
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 1db657e..54fbb01 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -449,7 +449,7 @@
       : reg_(static_cast<FpuRegister>(reg_as_int)) {}
 
   virtual intptr_t from_index() const { return static_cast<intptr_t>(reg_); }
-  virtual DeoptInstr::Kind kind() const { return kFloat32x4FpuRegister; }
+  virtual DeoptInstr::Kind kind() const { return kUint32x4FpuRegister; }
 
   virtual const char* ToCString() const {
     return Isolate::Current()->current_zone()->PrintToString(
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index 627f0de..121b01e 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -44,12 +44,11 @@
                                                  intptr_t human_size,
                                                  uword pc) {
   uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
-  stream_->OpenObject();
-  stream_->PrintProperty("type", "DisassembledInstruction");
-  stream_->PrintfProperty("pc", "%p", pc_ptr);
-  stream_->PrintProperty("hex", hex_buffer);
-  stream_->PrintProperty("human", human_buffer);
-  stream_->CloseObject();
+  JSONObject jsobj(&jsarr_);
+  jsobj.AddProperty("type", "DisassembledInstruction");
+  jsobj.AddPropertyF("pc", "%p", pc_ptr);
+  jsobj.AddProperty("hex", hex_buffer);
+  jsobj.AddProperty("human", human_buffer);
 }
 
 
@@ -68,10 +67,9 @@
       p[i] = ' ';
     }
   }
-  stream_->OpenObject();
-  stream_->PrintProperty("type", "DisassembledInstructionComment");
-  stream_->PrintProperty("comment", p);
-  stream_->CloseObject();
+  JSONObject jsobj(&jsarr_);
+  jsobj.AddProperty("type", "DisassembledInstructionComment");
+  jsobj.AddProperty("comment", p);
   free(p);
 }
 
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index 893f0e8..c7772a5 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -13,7 +13,7 @@
 
 // Froward declaration.
 class MemoryRegion;
-class JSONStream;
+class JSONArray;
 
 // Disassembly formatter interface, which consumes the
 // disassembled instructions in any desired form.
@@ -58,8 +58,8 @@
 // Disassemble into a JSONStream.
 class DisassembleToJSONStream : public DisassemblyFormatter {
  public:
-  explicit DisassembleToJSONStream(JSONStream* stream) : DisassemblyFormatter(),
-      stream_(stream) { }
+  explicit DisassembleToJSONStream(const JSONArray& jsarr)
+      : DisassemblyFormatter(), jsarr_(jsarr) { }
   ~DisassembleToJSONStream() { }
 
   virtual void ConsumeInstruction(char* hex_buffer,
@@ -71,7 +71,7 @@
   virtual void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
 
  private:
-  JSONStream* stream_;
+  const JSONArray& jsarr_;
   DISALLOW_ALLOCATION();
   DISALLOW_COPY_AND_ASSIGN(DisassembleToJSONStream);
 };
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 7aefeb5..0055f6f 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1442,8 +1442,8 @@
              opcode == 0x16 || opcode == 0x51 || opcode == 0x52 ||
              opcode == 0x53 || opcode == 0x54 || opcode == 0x56 ||
              opcode == 0x57 || opcode == 0x58 || opcode == 0x59 ||
-             opcode == 0x5C || opcode == 0x5D || opcode == 0x5E ||
-             opcode == 0x5F) {
+             opcode == 0x5A || opcode == 0x5C || opcode == 0x5D ||
+             opcode == 0x5E || opcode == 0x5F) {
     const char* mnemonic = NULL;
     switch (opcode) {
       case 0x12: mnemonic = "movhlps"; break;
@@ -1458,6 +1458,7 @@
       case 0x57: mnemonic = "xorps"; break;
       case 0x58: mnemonic = "addps"; break;
       case 0x59: mnemonic = "mulps"; break;
+      case 0x5A: mnemonic = "cvtsd2ss"; break;
       case 0x5C: mnemonic = "subps"; break;
       case 0x5D: mnemonic = "minps"; break;
       case 0x5E: mnemonic = "divps"; break;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 68c2654..04cf4f5 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -323,7 +323,7 @@
                                      isolate->object_store()->error_class());
   if (error_class.IsNull()) {
     const Library& core_lib = Library::Handle(isolate, Library::CoreLibrary());
-    error_class = core_lib.LookupClass(Symbols::Error(), NULL);
+    error_class = core_lib.LookupClass(Symbols::Error());
     ASSERT(!error_class.IsNull());
     isolate->object_store()->set_error_class(error_class);
   }
@@ -483,7 +483,7 @@
   const String& cls_name = String::Handle(Symbols::New(class_name));
   const Library& core_lib = Library::Handle(Library::CoreLibrary());
   // No ambiguity error expected: passing NULL.
-  Class& cls = Class::Handle(core_lib.LookupClass(cls_name, NULL));
+  Class& cls = Class::Handle(core_lib.LookupClass(cls_name));
   ASSERT(!cls.IsNull());
   // There are no parameterized error types, so no need to set type arguments.
   return Instance::New(cls);
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index ea82a810..cd390dc 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -14,7 +14,7 @@
 namespace dart {
 
 TEST_CASE(FindCodeObject) {
-#if defined(TARGET_ARCH_IA32)
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
   const int kLoopCount = 50000;
 #else
   const int kLoopCount = 25000;
@@ -53,9 +53,7 @@
   source = String::New(scriptChars);
   script = Script::New(url, source, RawScript::kScriptTag);
   EXPECT(CompilerTest::TestCompileScript(lib, script));
-  String& ambiguity_error_msg = String::Handle();
-  clsA = lib.LookupClass(String::Handle(Symbols::New("A")),
-                         &ambiguity_error_msg);
+  clsA = lib.LookupClass(String::Handle(Symbols::New("A")));
   EXPECT(!clsA.IsNull());
   ClassFinalizer::FinalizePendingClasses();
   for (int i = 0; i < kNumFunctions; i++) {
@@ -103,8 +101,7 @@
   source = String::New(scriptChars);
   script = Script::New(url, source, RawScript::kScriptTag);
   EXPECT(CompilerTest::TestCompileScript(lib, script));
-  clsB = lib.LookupClass(String::Handle(Symbols::New("B")),
-                         &ambiguity_error_msg);
+  clsB = lib.LookupClass(String::Handle(Symbols::New("B")));
   EXPECT(!clsB.IsNull());
   ClassFinalizer::FinalizePendingClasses();
   for (int i = 0; i < kNumFunctions; i++) {
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 36c148d..e7f4293 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -12,6 +12,7 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, reorder_basic_blocks);
 DECLARE_FLAG(bool, trace_optimization);
 DECLARE_FLAG(bool, verify_compiler);
 DEFINE_FLAG(bool, optimize_try_catch, true, "Optimization of try-catch");
@@ -41,6 +42,14 @@
 }
 
 
+GrowableArray<BlockEntryInstr*>* FlowGraph::codegen_block_order(
+    bool is_optimized) {
+  return (is_optimized && FLAG_reorder_basic_blocks)
+      ? &optimized_block_order_
+      : &reverse_postorder_;
+}
+
+
 ConstantInstr* FlowGraph::GetConstant(const Object& object) {
   // Check if the constant is already in the pool.
   GrowableArray<Definition*>* pool = graph_entry_->initial_definitions();
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 4a84196..34112c6 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -78,9 +78,7 @@
   const GrowableArray<BlockEntryInstr*>& reverse_postorder() const {
     return reverse_postorder_;
   }
-  GrowableArray<BlockEntryInstr*>* codegen_block_order(bool is_optimized) {
-    return is_optimized ? &optimized_block_order_ : &reverse_postorder_;
-  }
+  GrowableArray<BlockEntryInstr*>* codegen_block_order(bool is_optimized);
 
   // Iterators.
   BlockIterator reverse_postorder_iterator() const {
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 46f98b3..78efd46 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -993,7 +993,7 @@
       new ZoneGrowableArray<PushArgumentInstr*>(2);
   arguments->Add(push_left);
   arguments->Add(push_right);
-  const String& name = String::ZoneHandle(Symbols::New(node->Name()));
+  const String& name = String::ZoneHandle(Symbols::New(node->TokenName()));
   const intptr_t kNumArgsChecked = 2;
   InstanceCallInstr* call = new InstanceCallInstr(node->token_pos(),
                                                   name,
@@ -1438,7 +1438,7 @@
   ASSERT(Token::IsRelationalOperator(node->kind()));
   InstanceCallInstr* comp =
       new InstanceCallInstr(node->token_pos(),
-                            String::ZoneHandle(Symbols::New(node->Name())),
+                            String::ZoneHandle(Symbols::New(node->TokenName())),
                             node->kind(),
                             arguments,
                             Object::null_array(),
@@ -1473,7 +1473,7 @@
   arguments->Add(push_value);
   InstanceCallInstr* call =
       new InstanceCallInstr(node->token_pos(),
-                            String::ZoneHandle(Symbols::New(node->Name())),
+                            String::ZoneHandle(Symbols::New(node->TokenName())),
                             node->kind(),
                             arguments,
                             Object::null_array(),
@@ -3061,12 +3061,6 @@
                                        dst_name);
   }
 
-  if (!node->field().is_final()) {
-    // For now, disable list length guarding on non-final fields by specifying
-    // that the field doesn't have a length. See issue #12485.
-    node->field().set_guarded_list_length(Field::kNoFixedLength);
-  }
-
   store_value = Bind(BuildStoreExprTemp(store_value));
   GuardFieldInstr* guard =
       new GuardFieldInstr(store_value,
@@ -3680,7 +3674,7 @@
   // Resolve and call NoSuchMethodError._throwNew.
   const Library& core_lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::Handle(
-      core_lib.LookupClass(Symbols::NoSuchMethodError(), NULL));
+      core_lib.LookupClass(Symbols::NoSuchMethodError()));
   ASSERT(!cls.IsNull());
   const Function& func = Function::ZoneHandle(
       Resolver::ResolveStatic(cls,
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 4a8457b..e3d01c3 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -208,9 +208,11 @@
         entry_(NULL),
         exit_(NULL) { }
 
-#define DEFINE_VISIT(type, name) virtual void Visit##type(type* node);
-  NODE_LIST(DEFINE_VISIT)
-#undef DEFINE_VISIT
+#define DECLARE_VISIT(BaseName)                                                \
+  virtual void Visit##BaseName##Node(BaseName##Node* node);
+
+  FOR_EACH_NODE(DECLARE_VISIT)
+#undef DECLARE_VISIT
 
   FlowGraphBuilder* owner() const { return owner_; }
   intptr_t temp_index() const { return temp_index_; }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 834d0ef..fbe3484 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -89,7 +89,7 @@
           Isolate::Current()->object_store()->uint32x4_class())),
       list_class_(Class::ZoneHandle(
           Library::Handle(Library::CoreLibrary()).
-              LookupClass(Symbols::List(), NULL))),
+              LookupClass(Symbols::List()))),
       parallel_move_resolver_(this),
       pending_deoptimization_env_(NULL) {
   ASSERT(assembler != NULL);
@@ -180,12 +180,15 @@
 void FlowGraphCompiler::CompactBlock(BlockEntryInstr* block) {
   BlockInfo* block_info = block_info_[block->postorder_number()];
 
+  // Break out of cycles in the control flow graph.
   if (block_info->is_marked()) {
     return;
   }
   block_info->mark();
 
   if (IsEmptyBlock(block)) {
+    // For empty blocks, record a corresponding nonempty target as their
+    // jump label.
     BlockEntryInstr* target = block->next()->AsGoto()->successor();
     CompactBlock(target);
     block_info->set_jump_label(GetJumpLabel(target));
@@ -194,7 +197,10 @@
 
 
 void FlowGraphCompiler::CompactBlocks() {
-  Label* fallthrough_label = NULL;
+  // This algorithm does not garbage collect blocks in place, but merely
+  // records forwarding label information.  In this way it avoids having to
+  // change join and target entries.
+  Label* nonempty_label = NULL;
   for (intptr_t i = block_order().length() - 1; i >= 1; --i) {
     BlockEntryInstr* block = block_order()[i];
 
@@ -203,16 +209,19 @@
       CompactBlock(block);
     }
 
+    // For nonempty blocks, record the next nonempty block in the block
+    // order.  Since no code is emitted for empty blocks, control flow is
+    // eligible to fall through to the next nonempty one.
     if (!WasCompacted(block)) {
       BlockInfo* block_info = block_info_[block->postorder_number()];
-      block_info->set_fallthrough_label(fallthrough_label);
-      fallthrough_label = GetJumpLabel(block);
+      block_info->set_next_nonempty_label(nonempty_label);
+      nonempty_label = GetJumpLabel(block);
     }
   }
 
   ASSERT(block_order()[0]->IsGraphEntry());
   BlockInfo* block_info = block_info_[block_order()[0]->postorder_number()];
-  block_info->set_fallthrough_label(fallthrough_label);
+  block_info->set_next_nonempty_label(nonempty_label);
 }
 
 
@@ -289,8 +298,8 @@
 
 bool FlowGraphCompiler::CanFallThroughTo(BlockEntryInstr* block_entry) const {
   const intptr_t current_index = current_block()->postorder_number();
-  Label* fallthrough_label = block_info_[current_index]->fallthrough_label();
-  return fallthrough_label == GetJumpLabel(block_entry);
+  Label* next_nonempty = block_info_[current_index]->next_nonempty_label();
+  return next_nonempty == GetJumpLabel(block_entry);
 }
 
 
@@ -633,48 +642,6 @@
 }
 
 
-void FlowGraphCompiler::EmitUnoptimizedStaticCall(
-    const Function& target_function,
-    const Array& arguments_descriptor,
-    intptr_t argument_count,
-    intptr_t deopt_id,
-    intptr_t token_pos,
-    LocationSummary* locs) {
-  // TODO(srdjan): Improve performance of function recognition.
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target_function);
-  int num_args_checked = 0;
-  if ((recognized_kind == MethodRecognizer::kMathMin) ||
-      (recognized_kind == MethodRecognizer::kMathMax)) {
-    num_args_checked = 2;
-  }
-  const ICData& ic_data = ICData::ZoneHandle(
-      ICData::New(parsed_function().function(),  // Caller function.
-                  String::Handle(target_function.name()),
-                  arguments_descriptor,
-                  deopt_id,
-                  num_args_checked));  // No arguments checked.
-  ic_data.AddTarget(target_function);
-  uword label_address = 0;
-  if (ic_data.num_args_tested() == 0) {
-    label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
-  } else if (ic_data.num_args_tested() == 2) {
-    label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
-  } else {
-    UNIMPLEMENTED();
-  }
-  ExternalLabel target_label("StaticCallICStub", label_address);
-  assembler()->LoadObject(ICREG, ic_data);
-  GenerateDartCall(deopt_id,
-                   token_pos,
-                   &target_label,
-                   PcDescriptors::kUnoptStaticCall,
-                   locs);
-  assembler()->Drop(argument_count);
-}
-
-
-
 void FlowGraphCompiler::GenerateNumberTypeCheck(Register kClassIdReg,
                                                 const AbstractType& type,
                                                 Label* is_instance_lbl,
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index a5369ec..3d174c2 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -202,33 +202,36 @@
   class BlockInfo : public ZoneAllocated {
    public:
     BlockInfo()
-        : jump_label_(&block_label_),
-          block_label_(),
-          fallthrough_label_(NULL),
+        : block_label_(),
+          jump_label_(&block_label_),
+          next_nonempty_label_(NULL),
           is_marked_(false) {}
 
+    // The label to jump to when control is transferred to this block.  For
+    // nonempty blocks it is the label of the block itself.  For empty
+    // blocks it is the label of the first nonempty successor block.
     Label* jump_label() const { return jump_label_; }
     void set_jump_label(Label* label) { jump_label_ = label; }
 
-    // Label of the block that will follow this block in the generated code.
-    // Can be NULL if the block is the last block.
-    Label* fallthrough_label() const { return fallthrough_label_; }
-    void set_fallthrough_label(Label* fallthrough_label) {
-      fallthrough_label_ = fallthrough_label;
-    }
+    // The label of the first nonempty block after this one in the block
+    // order, or NULL if there is no nonempty block following this one.
+    Label* next_nonempty_label() const { return next_nonempty_label_; }
+    void set_next_nonempty_label(Label* label) { next_nonempty_label_ = label; }
 
     bool WasCompacted() const {
       return jump_label_ != &block_label_;
     }
 
+    // Block compaction is recursive.  Block info for already-compacted
+    // blocks is marked so as to avoid cycles in the graph.
     bool is_marked() const { return is_marked_; }
     void mark() { is_marked_ = true; }
 
    private:
-    Label* jump_label_;
     Label block_label_;
 
-    Label* fallthrough_label_;
+    Label* jump_label_;
+    Label* next_nonempty_label_;
 
     bool is_marked_;
   };
@@ -241,7 +244,6 @@
   ~FlowGraphCompiler();
 
   static bool SupportsUnboxedMints();
-  static bool SupportsInlinedTrigonometrics();
 
   // Accessors.
   Assembler* assembler() const { return assembler_; }
@@ -383,9 +385,6 @@
                                  Register right,
                                  bool needs_number_check,
                                  intptr_t token_pos);
-  // Implement equality: if any of the arguments is null do identity check.
-  // Fallthrough calls super equality.
-  void EmitSuperEqualityCallPrologue(Register result, Label* skip_call);
 
   void EmitTrySync(Instruction* instr, intptr_t try_index);
 
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index b65b83b..0854649 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -43,12 +43,6 @@
 }
 
 
-// TODO(srdjan): Enable by calling C-functions.
-bool FlowGraphCompiler::SupportsInlinedTrigonometrics() {
-  return false;
-}
-
-
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder) {
   if (deopt_env_ == NULL) return DeoptInfo::null();
@@ -1391,6 +1385,47 @@
 }
 
 
+void FlowGraphCompiler::EmitUnoptimizedStaticCall(
+    const Function& target_function,
+    const Array& arguments_descriptor,
+    intptr_t argument_count,
+    intptr_t deopt_id,
+    intptr_t token_pos,
+    LocationSummary* locs) {
+  // TODO(srdjan): Improve performance of function recognition.
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target_function);
+  int num_args_checked = 0;
+  if ((recognized_kind == MethodRecognizer::kMathMin) ||
+      (recognized_kind == MethodRecognizer::kMathMax)) {
+    num_args_checked = 2;
+  }
+  const ICData& ic_data = ICData::ZoneHandle(
+      ICData::New(parsed_function().function(),  // Caller function.
+                  String::Handle(target_function.name()),
+                  arguments_descriptor,
+                  deopt_id,
+                  num_args_checked));  // No arguments checked.
+  ic_data.AddTarget(target_function);
+  uword label_address = 0;
+  if (ic_data.num_args_tested() == 0) {
+    label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
+  } else if (ic_data.num_args_tested() == 2) {
+    label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
+  } else {
+    UNIMPLEMENTED();
+  }
+  ExternalLabel target_label("StaticCallICStub", label_address);
+  __ LoadObject(R5, ic_data);
+  GenerateDartCall(deopt_id,
+                   token_pos,
+                   &target_label,
+                   PcDescriptors::kUnoptStaticCall,
+                   locs);
+  __ Drop(argument_count);
+}
+
+
 void FlowGraphCompiler::EmitOptimizedStaticCall(
     const Function& function,
     const Array& arguments_descriptor,
@@ -1460,31 +1495,6 @@
 }
 
 
-// Implement equality spec: if any of the arguments is null do identity check.
-// Fallthrough calls super equality.
-void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
-                                                      Label* skip_call) {
-  Label check_identity, fall_through;
-  __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
-  __ ldr(result, Address(SP, 0 * kWordSize));  // Load right operand.
-  __ cmp(result, ShifterOperand(IP));  // Is right null?
-  __ ldr(result, Address(SP, 1 * kWordSize));  // Load left operand.
-  __ b(&check_identity, EQ);  // Branch if right (IP) is null; left in result.
-  __ cmp(result, ShifterOperand(IP));  // Right is non-null; is left null?
-  __ b(&fall_through, NE);
-  // Right is non-null, left is null. We could return false, but we save code
-  // by falling through with an IP different than null.
-  __ mov(IP, ShifterOperand(0));
-  __ Bind(&check_identity);
-  __ cmp(result, ShifterOperand(IP));
-  __ LoadObject(result, Bool::True(), EQ);
-  __ LoadObject(result, Bool::False(), NE);
-  __ Drop(2);
-  __ b(skip_call);
-  __ Bind(&fall_through);
-}
-
-
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   // TODO(vegorov): consider saving only caller save (volatile) registers.
   const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 9ca6baa..151ca9f 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -47,11 +47,6 @@
 }
 
 
-bool FlowGraphCompiler::SupportsInlinedTrigonometrics() {
-  return true;
-}
-
-
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder) {
   if (deopt_env_ == NULL) return DeoptInfo::null();
@@ -1285,6 +1280,47 @@
 }
 
 
+void FlowGraphCompiler::EmitUnoptimizedStaticCall(
+    const Function& target_function,
+    const Array& arguments_descriptor,
+    intptr_t argument_count,
+    intptr_t deopt_id,
+    intptr_t token_pos,
+    LocationSummary* locs) {
+  // TODO(srdjan): Improve performance of function recognition.
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target_function);
+  int num_args_checked = 0;
+  if ((recognized_kind == MethodRecognizer::kMathMin) ||
+      (recognized_kind == MethodRecognizer::kMathMax)) {
+    num_args_checked = 2;
+  }
+  const ICData& ic_data = ICData::ZoneHandle(
+      ICData::New(parsed_function().function(),  // Caller function.
+                  String::Handle(target_function.name()),
+                  arguments_descriptor,
+                  deopt_id,
+                  num_args_checked));  // No arguments checked.
+  ic_data.AddTarget(target_function);
+  uword label_address = 0;
+  if (ic_data.num_args_tested() == 0) {
+    label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
+  } else if (ic_data.num_args_tested() == 2) {
+    label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
+  } else {
+    UNIMPLEMENTED();
+  }
+  ExternalLabel target_label("StaticCallICStub", label_address);
+  __ LoadObject(ECX, ic_data);
+  GenerateDartCall(deopt_id,
+                   token_pos,
+                   &target_label,
+                   PcDescriptors::kUnoptStaticCall,
+                   locs);
+  __ Drop(argument_count);
+}
+
+
 void FlowGraphCompiler::EmitOptimizedInstanceCall(
     ExternalLabel* target_label,
     const ICData& ic_data,
@@ -1474,34 +1510,6 @@
 }
 
 
-// Implement equality spec: if any of the arguments is null do identity check.
-// Fallthrough calls super equality.
-void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
-                                                      Label* skip_call) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  Label check_identity, fall_through;
-  __ cmpl(Address(ESP, 0 * kWordSize), raw_null);
-  __ j(EQUAL, &check_identity, Assembler::kNearJump);
-  __ cmpl(Address(ESP, 1 * kWordSize), raw_null);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-
-  __ Bind(&check_identity);
-  __ popl(result);
-  __ cmpl(result, Address(ESP, 0 * kWordSize));
-  Label is_false;
-  __ j(NOT_EQUAL, &is_false, Assembler::kNearJump);
-  __ LoadObject(result, Bool::True());
-  __ Drop(1);
-  __ jmp(skip_call);
-  __ Bind(&is_false);
-  __ LoadObject(result, Bool::False());
-  __ Drop(1);
-  __ jmp(skip_call);
-  __ Bind(&fall_through);
-}
-
-
 // This function must be in sync with FlowGraphCompiler::RecordSafepoint.
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   // TODO(vegorov): consider saving only caller save (volatile) registers.
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index f3bbf2f..8e51051 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -43,12 +43,6 @@
 }
 
 
-// TODO(srdjan): Enable by calling C-functions.
-bool FlowGraphCompiler::SupportsInlinedTrigonometrics() {
-  return false;
-}
-
-
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder) {
   if (deopt_env_ == NULL) return DeoptInfo::null();
@@ -1438,6 +1432,47 @@
 }
 
 
+void FlowGraphCompiler::EmitUnoptimizedStaticCall(
+    const Function& target_function,
+    const Array& arguments_descriptor,
+    intptr_t argument_count,
+    intptr_t deopt_id,
+    intptr_t token_pos,
+    LocationSummary* locs) {
+  // TODO(srdjan): Improve performance of function recognition.
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target_function);
+  int num_args_checked = 0;
+  if ((recognized_kind == MethodRecognizer::kMathMin) ||
+      (recognized_kind == MethodRecognizer::kMathMax)) {
+    num_args_checked = 2;
+  }
+  const ICData& ic_data = ICData::ZoneHandle(
+      ICData::New(parsed_function().function(),  // Caller function.
+                  String::Handle(target_function.name()),
+                  arguments_descriptor,
+                  deopt_id,
+                  num_args_checked));  // No arguments checked.
+  ic_data.AddTarget(target_function);
+  uword label_address = 0;
+  if (ic_data.num_args_tested() == 0) {
+    label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
+  } else if (ic_data.num_args_tested() == 2) {
+    label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
+  } else {
+    UNIMPLEMENTED();
+  }
+  ExternalLabel target_label("StaticCallICStub", label_address);
+  __ LoadObject(S5, ic_data);
+  GenerateDartCall(deopt_id,
+                   token_pos,
+                   &target_label,
+                   PcDescriptors::kUnoptStaticCall,
+                   locs);
+  __ Drop(argument_count);
+}
+
+
 void FlowGraphCompiler::EmitOptimizedStaticCall(
     const Function& function,
     const Array& arguments_descriptor,
@@ -1517,32 +1552,6 @@
 }
 
 
-// Implement equality spec: if any of the arguments is null do identity check.
-// Fallthrough calls super equality.
-void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
-                                                      Label* skip_call) {
-  Label check_identity, is_false, fall_through;
-  __ TraceSimMsg("SuperEqualityCallPrologue");
-  __ lw(result, Address(SP, 0 * kWordSize));  // Load right operand.
-  __ lw(CMPRES1, Address(SP, 1 * kWordSize));  // Load left operand.
-  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
-  __ beq(result, TMP, &check_identity);  // Is right null?
-  __ LoadImmediate(TMP, reinterpret_cast<int32_t>(Object::null()));
-  __ bne(TMP, CMPRES1, &fall_through);  // If right is non-null, check left.
-
-  __ Bind(&check_identity);
-  __ bne(result, CMPRES1, &is_false);
-  __ LoadObject(result, Bool::True());
-  __ Drop(2);
-  __ b(skip_call);
-  __ Bind(&is_false);
-  __ LoadObject(result, Bool::False());
-  __ Drop(2);
-  __ b(skip_call);
-  __ Bind(&fall_through);
-}
-
-
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   __ TraceSimMsg("SaveLiveRegisters");
   // TODO(vegorov): consider saving only caller save (volatile) registers.
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 3d9b852d..e08d1ab 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -44,11 +44,6 @@
 }
 
 
-bool FlowGraphCompiler::SupportsInlinedTrigonometrics() {
-  return true;
-}
-
-
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder) {
   if (deopt_env_ == NULL) return DeoptInfo::null();
@@ -66,10 +61,9 @@
   // The real frame starts here.
   builder->MarkFrameStart();
 
-  // Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
+  // Current PP, FP, and PC.
+  builder->AddPp(current->function(), slot_ix++);
   builder->AddPcMarker(Function::Handle(), slot_ix++);
-
-  // Current FP and PC.
   builder->AddCallerFp(slot_ix++);
   builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++);
 
@@ -85,13 +79,14 @@
     builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++);
   }
 
-  // Current PC marker and caller FP.
-  builder->AddPcMarker(current->function(), slot_ix++);
-  builder->AddCallerFp(slot_ix++);
-
   Environment* previous = current;
   current = current->outer();
   while (current != NULL) {
+    // PP, FP, and PC.
+    builder->AddPp(current->function(), slot_ix++);
+    builder->AddPcMarker(previous->function(), slot_ix++);
+    builder->AddCallerFp(slot_ix++);
+
     // For any outer environment the deopt id is that of the call instruction
     // which is recorded in the outer environment.
     builder->AddReturnAddress(current->function(),
@@ -115,10 +110,6 @@
                        slot_ix++);
     }
 
-    // PC marker and caller FP.
-    builder->AddPcMarker(current->function(), slot_ix++);
-    builder->AddCallerFp(slot_ix++);
-
     // Iterate on the outer environment.
     previous = current;
     current = current->outer();
@@ -126,7 +117,11 @@
   // The previous pointer is now the outermost environment.
   ASSERT(previous != NULL);
 
-  // For the outermost environment, set caller PC.
+  // For the outermost environment, set caller PC, caller PP, and caller FP.
+  builder->AddCallerPp(slot_ix++);
+  // PC marker.
+  builder->AddPcMarker(previous->function(), slot_ix++);
+  builder->AddCallerFp(slot_ix++);
   builder->AddCallerPc(slot_ix++);
 
   // For the outermost environment, set the incoming arguments.
@@ -151,7 +146,7 @@
 
   ASSERT(deopt_env() != NULL);
 
-  __ call(&StubCode::DeoptimizeLabel());
+  __ Call(&StubCode::DeoptimizeLabel(), PP);
   set_pc_offset(assem->CodeSize());
   __ int3();
 #undef __
@@ -165,10 +160,8 @@
 void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
                                            Label* is_true,
                                            Label* is_false) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label fall_through;
-  __ cmpq(bool_register, raw_null);
+  __ CompareObject(bool_register, Object::null_object());
   __ j(EQUAL, &fall_through, Assembler::kNearJump);
   __ CompareObject(bool_register, Bool::True());
   __ j(EQUAL, is_true);
@@ -187,22 +180,20 @@
     Label* is_not_instance_lbl) {
   const SubtypeTestCache& type_test_cache =
       SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ LoadObject(temp_reg, type_test_cache);
+  __ LoadObject(temp_reg, type_test_cache, PP);
   __ pushq(temp_reg);  // Subtype test cache.
   __ pushq(instance_reg);  // Instance.
   if (test_kind == kTestTypeOneArg) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ pushq(raw_null);
-    __ call(&StubCode::Subtype1TestCacheLabel());
+    __ PushObject(Object::null_object());
+    __ Call(&StubCode::Subtype1TestCacheLabel(), PP);
   } else if (test_kind == kTestTypeTwoArgs) {
     ASSERT(type_arguments_reg == kNoRegister);
-    __ pushq(raw_null);
-    __ call(&StubCode::Subtype2TestCacheLabel());
+    __ PushObject(Object::null_object());
+    __ Call(&StubCode::Subtype2TestCacheLabel(), PP);
   } else if (test_kind == kTestTypeThreeArgs) {
     __ pushq(type_arguments_reg);
-    __ call(&StubCode::Subtype3TestCacheLabel());
+    __ Call(&StubCode::Subtype3TestCacheLabel(), PP);
   } else {
     UNREACHABLE();
   }
@@ -347,11 +338,9 @@
   }
   if (type.IsFunctionType()) {
     // Check if instance is a closure.
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
     __ LoadClassById(R13, kClassIdReg);
     __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
-    __ cmpq(R13, raw_null);
+    __ CompareObject(R13, Object::null_object());
     __ j(NOT_EQUAL, is_instance_lbl);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
@@ -414,15 +403,13 @@
   __ Comment("UninstantiatedTypeTest");
   ASSERT(!type.IsInstantiated());
   // Skip check if destination is a dynamic type.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   if (type.IsTypeParameter()) {
     const TypeParameter& type_param = TypeParameter::Cast(type);
     // Load instantiator (or null) and instantiator type arguments on stack.
     __ movq(RDX, Address(RSP, 0));  // Get instantiator type arguments.
     // RDX: instantiator type arguments.
     // Check if type argument is dynamic.
-    __ cmpq(RDX, raw_null);
+    __ CompareObject(RDX, Object::null_object());
     __ j(EQUAL, is_instance_lbl);
     // Can handle only type arguments that are instances of TypeArguments.
     // (runtime checks canonicalize type arguments).
@@ -435,7 +422,7 @@
     // Check if type argument is dynamic.
     __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
     __ j(EQUAL,  is_instance_lbl);
-    __ cmpq(RDI, raw_null);
+    __ CompareObject(RDI, Object::null_object());
     __ j(EQUAL,  is_instance_lbl);
     const Type& object_type = Type::ZoneHandle(Type::ObjectType());
     __ CompareObject(RDI, object_type);
@@ -575,8 +562,6 @@
                                            LocationSummary* locs) {
   ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
 
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label is_instance, is_not_instance;
   __ pushq(RCX);  // Store instantiator on stack.
   __ pushq(RDX);  // Store instantiator type arguments.
@@ -590,7 +575,7 @@
     // We can only inline this null check if the type is instantiated at compile
     // time, since an uninstantiated type at compile time could be Object or
     // dynamic at run time.
-    __ cmpq(RAX, raw_null);
+    __ CompareObject(RAX, Object::null_object());
     __ j(EQUAL, &is_not_instance);
   }
 
@@ -610,7 +595,7 @@
     __ PushObject(type);  // Push the type.
     __ pushq(RCX);  // TODO(srdjan): Pass instantiator instead of null.
     __ pushq(RDX);  // Instantiator type arguments.
-    __ LoadObject(RAX, test_cache);
+    __ LoadObject(RAX, test_cache, PP);
     __ pushq(RAX);
     GenerateCallRuntime(token_pos,
                         deopt_id,
@@ -622,21 +607,21 @@
     __ Drop(5);
     if (negate_result) {
       __ popq(RDX);
-      __ LoadObject(RAX, Bool::True());
+      __ LoadObject(RAX, Bool::True(), PP);
       __ cmpq(RDX, RAX);
       __ j(NOT_EQUAL, &done, Assembler::kNearJump);
-      __ LoadObject(RAX, Bool::False());
+      __ LoadObject(RAX, Bool::False(), PP);
     } else {
       __ popq(RAX);
     }
     __ jmp(&done, Assembler::kNearJump);
   }
   __ Bind(&is_not_instance);
-  __ LoadObject(RAX, Bool::Get(negate_result));
+  __ LoadObject(RAX, Bool::Get(negate_result), PP);
   __ jmp(&done, Assembler::kNearJump);
 
   __ Bind(&is_instance);
-  __ LoadObject(RAX, Bool::Get(!negate_result));
+  __ LoadObject(RAX, Bool::Get(!negate_result), PP);
   __ Bind(&done);
   __ popq(RDX);  // Remove pushed instantiator type arguments.
   __ popq(RCX);  // Remove pushed instantiator.
@@ -669,10 +654,8 @@
   __ pushq(RCX);  // Store instantiator.
   __ pushq(RDX);  // Store instantiator type arguments.
   // A null object is always assignable and is returned as result.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label is_assignable, runtime_call;
-  __ cmpq(RAX, raw_null);
+  __ CompareObject(RAX, Object::null_object());
   __ j(EQUAL, &is_assignable);
 
   if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) {
@@ -725,7 +708,7 @@
   __ pushq(RCX);  // Instantiator.
   __ pushq(RDX);  // Instantiator type arguments.
   __ PushObject(dst_name);  // Push the name of the destination.
-  __ LoadObject(RAX, test_cache);
+  __ LoadObject(RAX, test_cache, PP);
   __ pushq(RAX);
   GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs);
   // Pop the parameters supplied to the runtime entry. The result of the
@@ -770,7 +753,7 @@
       __ pushq(RAX);
       *push_emitted = true;
     }
-    __ LoadObject(RAX, loc.constant());
+    __ LoadObject(RAX, loc.constant(), PP);
     __ movq(dest, RAX);
   } else if (loc.IsRegister()) {
     if (*push_emitted && loc.reg() == RAX) {
@@ -900,8 +883,6 @@
   __ j(POSITIVE, &loop, Assembler::kNearJump);
 
   // Copy or initialize optional named arguments.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label all_arguments_processed;
 #ifdef DEBUG
     const bool check_correct_named_args = true;
@@ -963,7 +944,7 @@
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(
               param_pos - num_fixed_params));
-      __ LoadObject(RAX, value);
+      __ LoadObject(RAX, value, PP);
       __ Bind(&assign_optional_parameter);
       // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
@@ -978,7 +959,8 @@
     if (check_correct_named_args) {
       // Check that RDI now points to the null terminator in the arguments
       // descriptor.
-      __ cmpq(Address(RDI, 0), raw_null);
+      __ LoadObject(TMP, Object::null_object(), PP);
+      __ cmpq(Address(RDI, 0), TMP);
       __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
     }
   } else {
@@ -997,7 +979,7 @@
       // Load RAX with default argument.
       const Object& value = Object::ZoneHandle(
           parsed_function().default_parameter_values().At(i));
-      __ LoadObject(RAX, value);
+      __ LoadObject(RAX, value, PP);
       // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos].
       // We do not use the final allocation index of the variable here, i.e.
       // scope->VariableAt(i)->index(), because captured variables still need
@@ -1023,8 +1005,8 @@
     const ICData& ic_data = ICData::ZoneHandle(
         ICData::New(function, Symbols::Call(), Object::empty_array(),
                     Isolate::kNoDeoptId, kNumArgsChecked));
-    __ LoadObject(RBX, ic_data);
-    __ LeaveFrame();  // The arguments are still on the stack.
+    __ LoadObject(RBX, ic_data, PP);
+    __ LeaveFrameWithPP();  // The arguments are still on the stack.
     __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
     // The noSuchMethod call may return to the caller, but not here.
     __ int3();
@@ -1042,12 +1024,13 @@
   // R10 : arguments descriptor array.
   __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
   __ SmiUntag(RCX);
+  __ LoadObject(R12, Object::null_object(), PP);
   Label null_args_loop, null_args_loop_condition;
   __ jmp(&null_args_loop_condition, Assembler::kNearJump);
   const Address original_argument_addr(
       RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize);
   __ Bind(&null_args_loop);
-  __ movq(original_argument_addr, raw_null);
+  __ movq(original_argument_addr, R12);
   __ Bind(&null_args_loop_condition);
   __ decq(RCX);
   __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
@@ -1072,20 +1055,43 @@
   __ movq(RAX, Address(RSP, 2 * kWordSize));  // Receiver.
   __ movq(RBX, Address(RSP, 1 * kWordSize));  // Value.
   __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX);
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ movq(RAX, raw_null);
+  __ LoadObject(RAX, Object::null_object(), PP);
   __ ret();
 }
 
 
 void FlowGraphCompiler::EmitFrameEntry() {
   const Function& function = parsed_function().function();
+  Register new_pp = kNoRegister;
+  Register new_pc = kNoRegister;
   if (CanOptimizeFunction() &&
       function.is_optimizable() &&
       (!is_optimizing() || may_reoptimize())) {
     const Register function_reg = RDI;
-    __ LoadObject(function_reg, function);
+    new_pp = R13;
+    new_pc = R12;
+
+    Label next;
+    __ nop(4);  // Need a fixed size sequence on frame entry.
+    __ call(&next);
+    __ Bind(&next);
+
+    const intptr_t object_pool_pc_dist =
+        Instructions::HeaderSize() - Instructions::object_pool_offset() +
+        __ CodeSize();
+    const intptr_t offset =
+        Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
+    __ popq(new_pc);
+    if (offset != 0) {
+      __ addq(new_pc, Immediate(offset));
+    }
+
+    // Load callee's pool pointer.
+    __ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
+
+    // Load function object using the callee's pool pointer.
+    __ LoadObject(function_reg, function, new_pp);
+
     // Patch point is after the eventually inlined function object.
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
                          Isolate::kNoDeoptId,
@@ -1101,8 +1107,30 @@
               Immediate(FLAG_optimization_counter_threshold));
     }
     ASSERT(function_reg == RDI);
-    __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
+    __ J(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel(), R13);
   } else if (!flow_graph().IsCompiledForOsr()) {
+    // We have to load the PP here too because a load of an external label
+    // may be patched at the AddCurrentDescriptor below.
+    new_pp = R13;
+    new_pc = R12;
+
+    Label next;
+    __ nop(4);  // Need a fixed size sequence on frame entry.
+    __ call(&next);
+    __ Bind(&next);
+
+    const intptr_t object_pool_pc_dist =
+        Instructions::HeaderSize() - Instructions::object_pool_offset() +
+        __ CodeSize();
+    const intptr_t offset =
+        Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
+    __ popq(new_pc);
+    if (offset != 0) {
+      __ addq(new_pc, Immediate(offset));
+    }
+
+    // Load callee's pool pointer.
+    __ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
     AddCurrentDescriptor(PcDescriptors::kEntryPatch,
                          Isolate::kNoDeoptId,
                          0);  // No token position.
@@ -1113,10 +1141,10 @@
         - flow_graph().num_stack_locals()
         - flow_graph().num_copied_params();
     ASSERT(extra_slots >= 0);
-    __ EnterOsrFrame(extra_slots * kWordSize);
+    __ EnterOsrFrame(extra_slots * kWordSize, new_pp, new_pc);
   } else {
     ASSERT(StackSize() >= 0);
-    __ EnterDartFrame(StackSize() * kWordSize);
+    __ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp, new_pc);
   }
 }
 
@@ -1170,8 +1198,8 @@
         const ICData& ic_data = ICData::ZoneHandle(
             ICData::New(function, name, Object::empty_array(),
                         Isolate::kNoDeoptId, kNumArgsChecked));
-        __ LoadObject(RBX, ic_data);
-        __ LeaveFrame();  // The arguments are still on the stack.
+        __ LoadObject(RBX, ic_data, PP);
+        __ LeaveFrameWithPP();  // The arguments are still on the stack.
         __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
         // The noSuchMethod call may return to the caller, but not here.
         __ int3();
@@ -1189,9 +1217,7 @@
   if (!is_optimizing() && (num_locals > 0)) {
     __ Comment("Initialize spill slots");
     const intptr_t slot_base = parsed_function().first_stack_local_index();
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
-    __ movq(RAX, raw_null);
+    __ LoadObject(RAX, Object::null_object(), PP);
     for (intptr_t i = 0; i < num_locals; ++i) {
       // Subtract index i (locals lie at lower addresses than RBP).
       __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX);
@@ -1218,11 +1244,15 @@
   AddCurrentDescriptor(PcDescriptors::kPatchCode,
                        Isolate::kNoDeoptId,
                        0);  // No token position.
-  __ jmp(&StubCode::FixCallersTargetLabel());
+  // This is patched up to a point in FrameEntry where the PP for the
+  // current function is in R13 instead of PP.
+  __ JmpPatchable(&StubCode::FixCallersTargetLabel(), R13);
+
+  // TOOD(zra): Is this descriptor used?
   AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump,
                        Isolate::kNoDeoptId,
                        0);  // No token position.
-  __ jmp(&StubCode::DeoptimizeLazyLabel());
+  __ Jmp(&StubCode::DeoptimizeLazyLabel(), PP);
 }
 
 
@@ -1230,7 +1260,7 @@
                                      const ExternalLabel* label,
                                      PcDescriptors::Kind kind,
                                      LocationSummary* locs) {
-  __ call(label);
+  __ Call(label, PP);
   AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
   RecordSafepoint(locs);
 }
@@ -1241,7 +1271,7 @@
                                          const ExternalLabel* label,
                                          PcDescriptors::Kind kind,
                                          LocationSummary* locs) {
-  __ call(label);
+  __ CallPatchable(label);
   AddCurrentDescriptor(kind, deopt_id, token_pos);
   RecordSafepoint(locs);
   // Marks either the continuation point in unoptimized code or the
@@ -1280,6 +1310,47 @@
 }
 
 
+void FlowGraphCompiler::EmitUnoptimizedStaticCall(
+    const Function& target_function,
+    const Array& arguments_descriptor,
+    intptr_t argument_count,
+    intptr_t deopt_id,
+    intptr_t token_pos,
+    LocationSummary* locs) {
+  // TODO(srdjan): Improve performance of function recognition.
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target_function);
+  int num_args_checked = 0;
+  if ((recognized_kind == MethodRecognizer::kMathMin) ||
+      (recognized_kind == MethodRecognizer::kMathMax)) {
+    num_args_checked = 2;
+  }
+  const ICData& ic_data = ICData::ZoneHandle(
+      ICData::New(parsed_function().function(),  // Caller function.
+                  String::Handle(target_function.name()),
+                  arguments_descriptor,
+                  deopt_id,
+                  num_args_checked));  // No arguments checked.
+  ic_data.AddTarget(target_function);
+  uword label_address = 0;
+  if (ic_data.num_args_tested() == 0) {
+    label_address = StubCode::ZeroArgsUnoptimizedStaticCallEntryPoint();
+  } else if (ic_data.num_args_tested() == 2) {
+    label_address = StubCode::TwoArgsUnoptimizedStaticCallEntryPoint();
+  } else {
+    UNIMPLEMENTED();
+  }
+  ExternalLabel target_label("StaticCallICStub", label_address);
+  __ LoadObject(RBX, ic_data, PP);
+  GenerateDartCall(deopt_id,
+                   token_pos,
+                   &target_label,
+                   PcDescriptors::kUnoptStaticCall,
+                   locs);
+  __ Drop(argument_count);
+}
+
+
 void FlowGraphCompiler::EmitOptimizedInstanceCall(
     ExternalLabel* target_label,
     const ICData& ic_data,
@@ -1293,8 +1364,8 @@
   // top-level function (parsed_function().function()) which could be
   // reoptimized and which counter needs to be incremented.
   // Pass the function explicitly, it is used in IC stub.
-  __ LoadObject(RDI, parsed_function().function());
-  __ LoadObject(RBX, ic_data);
+  __ LoadObject(RDI, parsed_function().function(), PP);
+  __ LoadObject(RBX, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1310,7 +1381,7 @@
                                          intptr_t deopt_id,
                                          intptr_t token_pos,
                                          LocationSummary* locs) {
-  __ LoadObject(RBX, ic_data);
+  __ LoadObject(RBX, ic_data, PP);
   GenerateDartCall(deopt_id,
                    token_pos,
                    target_label,
@@ -1346,7 +1417,7 @@
 
   // RAX: class ID of the receiver (smi).
   __ Bind(&load_cache);
-  __ LoadObject(RBX, cache);
+  __ LoadObject(RBX, cache, PP);
   __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset()));
   __ movq(RBX, FieldAddress(RBX, MegamorphicCache::mask_offset()));
   // RDI: cache buckets array.
@@ -1378,8 +1449,8 @@
   __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize));
   __ movq(RAX, FieldAddress(RAX, Function::code_offset()));
   __ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
-  __ LoadObject(RBX, ic_data);
-  __ LoadObject(R10, arguments_descriptor);
+  __ LoadObject(RBX, ic_data, PP);
+  __ LoadObject(R10, arguments_descriptor, PP);
   __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
   __ call(RAX);
   AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos);
@@ -1396,7 +1467,7 @@
     intptr_t deopt_id,
     intptr_t token_pos,
     LocationSummary* locs) {
-  __ LoadObject(R10, arguments_descriptor);
+  __ LoadObject(R10, arguments_descriptor, PP);
   // Do not use the code from the function, but let the code be patched so that
   // we can record the outgoing edges to other code.
   GenerateDartCall(deopt_id,
@@ -1429,9 +1500,9 @@
     __ pushq(reg);
     __ PushObject(obj);
     if (is_optimizing()) {
-      __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+      __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
     } else {
-      __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+      __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
     }
     AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
                          Isolate::kNoDeoptId,
@@ -1453,9 +1524,9 @@
     __ pushq(left);
     __ pushq(right);
     if (is_optimizing()) {
-      __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
+      __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
     } else {
-      __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
+      __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
     }
     AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
                          Isolate::kNoDeoptId,
@@ -1469,34 +1540,6 @@
 }
 
 
-// Implement equality spec: if any of the arguments is null do identity check.
-// Fallthrough calls super equality.
-void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
-                                                      Label* skip_call) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  Label check_identity, fall_through;
-  __ cmpq(Address(RSP, 0 * kWordSize), raw_null);
-  __ j(EQUAL, &check_identity, Assembler::kNearJump);
-  __ cmpq(Address(RSP, 1 * kWordSize), raw_null);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
-
-  __ Bind(&check_identity);
-  __ popq(result);
-  __ cmpq(result, Address(RSP, 0 * kWordSize));
-  Label is_false;
-  __ j(NOT_EQUAL, &is_false, Assembler::kNearJump);
-  __ LoadObject(result, Bool::True());
-  __ Drop(1);
-  __ jmp(skip_call);
-  __ Bind(&is_false);
-  __ LoadObject(result, Bool::False());
-  __ Drop(1);
-  __ jmp(skip_call);
-  __ Bind(&fall_through);
-}
-
-
 // This function must be in sync with FlowGraphCompiler::RecordSafepoint.
 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
   // TODO(vegorov): consider saving only caller save (volatile) registers.
@@ -1573,7 +1616,7 @@
   const Array& arguments_descriptor =
       Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
                                                  argument_names));
-  __ LoadObject(R10, arguments_descriptor);
+  __ LoadObject(R10, arguments_descriptor, PP);
   for (intptr_t i = 0; i < len; i++) {
     const bool is_last_check = (i == (len - 1));
     Label next_test;
@@ -1615,7 +1658,6 @@
 }
 
 
-
 void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition,
                                               FpuRegister left,
                                               FpuRegister right,
@@ -1625,10 +1667,10 @@
   assembler()->j(PARITY_EVEN, &is_false, Assembler::kNearJump);  // NaN false;
   assembler()->j(true_condition, &is_true, Assembler::kNearJump);
   assembler()->Bind(&is_false);
-  assembler()->LoadObject(result, Bool::False());
+  assembler()->LoadObject(result, Bool::False(), PP);
   assembler()->jmp(&done);
   assembler()->Bind(&is_true);
-  assembler()->LoadObject(result, Bool::True());
+  assembler()->LoadObject(result, Bool::True(), PP);
   assembler()->Bind(&done);
 }
 
@@ -1749,7 +1791,7 @@
       if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) {
         __ xorq(destination.reg(), destination.reg());
       } else {
-        __ LoadObject(destination.reg(), constant);
+        __ LoadObject(destination.reg(), constant, PP);
       }
     } else {
       ASSERT(destination.IsStackSlot());
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 6ecb193..692c0f8 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -77,9 +77,12 @@
 class ChildrenVisitor : public AstNodeVisitor {
  public:
   ChildrenVisitor() { }
-#define DEFINE_VISIT(type, name)                                               \
-  virtual void Visit##type(type* node) { node->VisitChildren(this); }
-  NODE_LIST(DEFINE_VISIT);
+#define DEFINE_VISIT(BaseName)                                                 \
+  virtual void Visit##BaseName##Node(BaseName##Node* node) {                   \
+    node->VisitChildren(this);                                                 \
+  }
+
+  FOR_EACH_NODE(DEFINE_VISIT);
 #undef DEFINE_VISIT
 };
 
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 41385e4..53f4450 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -770,51 +770,24 @@
                call->env(),
                Definition::kEffect);
 
-  bool emit_bounds_check = true;
-  // Get the field for the array.
-  const Field* field = NULL;
-  if ((*array)->IsLoadField()) {
-    LoadFieldInstr* load_field_instr = (*array)->AsLoadField();
-    field = load_field_instr->field();
-  }
-  // Extract the guarded array length.
-  intptr_t guarded_array_length = -1;
-  if (field != NULL) {
-    if (field->guarded_list_length() >= 0) {
-      guarded_array_length = field->guarded_list_length();
-    }
-  }
-  Definition* i = *index;
-  // Check if we can skip emitting the bounds check.
-  if (i->IsConstant() && guarded_array_length >= 0) {
-    ConstantInstr* constant = i->AsConstant();
-    ASSERT(constant != NULL);
-    intptr_t ci = Smi::Cast(constant->value()).Value();
-    if (ci < guarded_array_length) {
-      emit_bounds_check = false;
-    }
-  }
-
-  if (emit_bounds_check) {
-    // Insert array length load and bounds check.
-    const bool is_immutable =
-        CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
-    LoadFieldInstr* length =
-        new LoadFieldInstr(new Value(*array),
-                           CheckArrayBoundInstr::LengthOffsetFor(class_id),
-                           Type::ZoneHandle(Type::SmiType()),
-                           is_immutable);
-    length->set_result_cid(kSmiCid);
-    length->set_recognized_kind(
-        LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
-    InsertBefore(call, length, NULL, Definition::kValue);
-    InsertBefore(call,
-                 new CheckArrayBoundInstr(new Value(length),
-                                          new Value(*index),
-                                          call->deopt_id()),
-                 call->env(),
-                 Definition::kEffect);
-  }
+  // Insert array length load and bounds check.
+  const bool is_immutable =
+      CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
+  LoadFieldInstr* length =
+      new LoadFieldInstr(new Value(*array),
+                         CheckArrayBoundInstr::LengthOffsetFor(class_id),
+                         Type::ZoneHandle(Type::SmiType()),
+                         is_immutable);
+  length->set_result_cid(kSmiCid);
+  length->set_recognized_kind(
+      LoadFieldInstr::RecognizedKindFromArrayCid(class_id));
+  InsertBefore(call, length, NULL, Definition::kValue);
+  InsertBefore(call,
+               new CheckArrayBoundInstr(new Value(length),
+                                        new Value(*index),
+                                        call->deopt_id()),
+               call->env(),
+               Definition::kEffect);
 
 
   if (class_id == kGrowableObjectArrayCid) {
@@ -1732,8 +1705,8 @@
 
 
 void FlowGraphOptimizer::ReplaceWithMathCFunction(
-  InstanceCallInstr* call,
-  MethodRecognizer::Kind recognized_kind) {
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
   AddReceiverCheck(call);
   ZoneGrowableArray<Value*>* args =
       new ZoneGrowableArray<Value*>(call->ArgumentCount());
@@ -2735,14 +2708,11 @@
   if ((recognized_kind == MethodRecognizer::kMathSqrt) ||
       (recognized_kind == MethodRecognizer::kMathSin) ||
       (recognized_kind == MethodRecognizer::kMathCos)) {
-    if ((recognized_kind == MethodRecognizer::kMathSqrt) ||
-        FlowGraphCompiler::SupportsInlinedTrigonometrics()) {
-      MathUnaryInstr* math_unary =
-          new MathUnaryInstr(recognized_kind,
-                             new Value(call->ArgumentAt(0)),
-                             call->deopt_id());
-      ReplaceCall(call, math_unary);
-    }
+    MathUnaryInstr* math_unary =
+        new MathUnaryInstr(recognized_kind,
+                           new Value(call->ArgumentAt(0)),
+                           call->deopt_id());
+    ReplaceCall(call, math_unary);
   } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) ||
              (recognized_kind == MethodRecognizer::kFloat32x4Splat) ||
              (recognized_kind == MethodRecognizer::kFloat32x4Constructor)) {
diff --git a/runtime/vm/guard_field_test.cc b/runtime/vm/guard_field_test.cc
new file mode 100644
index 0000000..193d4b7
--- /dev/null
+++ b/runtime/vm/guard_field_test.cc
@@ -0,0 +1,272 @@
+// 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.
+
+#include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
+#include "vm/intermediate_language.h"
+#include "vm/object.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+RawField* LookupField(Dart_Handle library, const char* class_name,
+                      const char* field_name) {
+  RawLibrary* raw_library = Library::RawCast(Api::UnwrapHandle(library));
+  Library& lib = Library::ZoneHandle(raw_library);
+  const String& classname = String::Handle(Symbols::New(class_name));
+  Class& cls = Class::Handle(lib.LookupClass(classname));
+  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+
+  String& fieldname = String::Handle(String::New(field_name));
+  Field& field = Field::ZoneHandle(cls.LookupInstanceField(fieldname));
+  EXPECT(!field.IsNull());
+  return field.raw();
+}
+
+
+TEST_CASE(GuardFieldSimpleTest) {
+  const char* script_chars =
+      "class A {\n"
+      "  var f1 = 3.0;\n"
+      "  var f2 = 3;\n"
+      "  var f3 = new List(4);\n"
+      "  foo() {\n"
+      "    f1 = f1 + f1;\n"
+      "  }\n"
+      "  bar() {\n"
+      "    f2 = null;\n"
+      "    f2 = 3.0;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runFoo() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.foo();\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runBar() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.bar();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  runFoo();\n"
+      "  runBar();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(script_chars, NULL);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+  Field& f1 = Field::ZoneHandle(LookupField(lib, "A", "f1"));
+  Field& f2 = Field::ZoneHandle(LookupField(lib, "A", "f2"));
+  Field& f3 = Field::ZoneHandle(LookupField(lib, "A", "f3"));
+  const intptr_t no_length = Field::kNoFixedLength;
+  EXPECT_EQ(no_length, f1.guarded_list_length());
+  EXPECT_EQ(kDoubleCid, f1.guarded_cid());
+  EXPECT_EQ(false, f1.is_nullable());
+  EXPECT_EQ(no_length, f2.guarded_list_length());
+  EXPECT_EQ(kDynamicCid, f2.guarded_cid());
+  EXPECT_EQ(true, f2.is_nullable());
+  EXPECT_EQ(no_length, f3.guarded_list_length());
+}
+
+
+TEST_CASE(GuardFieldFinalListTest) {
+  const char* script_chars =
+      "class A {\n"
+      "  var f1 = 3.0;\n"
+      "  var f2 = 3;\n"
+      "  final f3 = new List(4);\n"
+      "  foo() {\n"
+      "    f1 = f1 + f1;\n"
+      "  }\n"
+      "  bar() {\n"
+      "    f2 = null;\n"
+      "    f2 = 3.0;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runFoo() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.foo();\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runBar() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.bar();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  runFoo();\n"
+      "  runBar();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(script_chars, NULL);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+  Field& f1 = Field::ZoneHandle(LookupField(lib, "A", "f1"));
+  Field& f2 = Field::ZoneHandle(LookupField(lib, "A", "f2"));
+  Field& f3 = Field::ZoneHandle(LookupField(lib, "A", "f3"));
+  const intptr_t no_length = Field::kNoFixedLength;
+  EXPECT_EQ(no_length, f1.guarded_list_length());
+  EXPECT_EQ(kDoubleCid, f1.guarded_cid());
+  EXPECT_EQ(false, f1.is_nullable());
+  EXPECT_EQ(no_length, f2.guarded_list_length());
+  EXPECT_EQ(kDynamicCid, f2.guarded_cid());
+  EXPECT_EQ(true, f2.is_nullable());
+  EXPECT_EQ(4, f3.guarded_list_length());
+  EXPECT_EQ(kArrayCid, f3.guarded_cid());
+  EXPECT_EQ(false, f3.is_nullable());
+}
+
+
+TEST_CASE(GuardFieldFinalVariableLengthListTest) {
+  const char* script_chars =
+      "class A {\n"
+      "  var f1 = 3.0;\n"
+      "  var f2 = 3;\n"
+      "  final f3 = new List();\n"
+      "  foo() {\n"
+      "    f1 = f1 + f1;\n"
+      "  }\n"
+      "  bar() {\n"
+      "    f2 = null;\n"
+      "    f2 = 3.0;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runFoo() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.foo();\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runBar() {\n"
+      "  var a = new A();\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.bar();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  runFoo();\n"
+      "  runBar();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(script_chars, NULL);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+  Field& f1 = Field::ZoneHandle(LookupField(lib, "A", "f1"));
+  Field& f2 = Field::ZoneHandle(LookupField(lib, "A", "f2"));
+  Field& f3 = Field::ZoneHandle(LookupField(lib, "A", "f3"));
+  const intptr_t no_length = Field::kNoFixedLength;
+  EXPECT_EQ(no_length, f1.guarded_list_length());
+  EXPECT_EQ(kDoubleCid, f1.guarded_cid());
+  EXPECT_EQ(false, f1.is_nullable());
+  EXPECT_EQ(no_length, f2.guarded_list_length());
+  EXPECT_EQ(kDynamicCid, f2.guarded_cid());
+  EXPECT_EQ(true, f2.is_nullable());
+  EXPECT_EQ(no_length, f3.guarded_list_length());
+  EXPECT_EQ(kGrowableObjectArrayCid, f3.guarded_cid());
+  EXPECT_EQ(false, f3.is_nullable());
+}
+
+
+TEST_CASE(GuardFieldConstructorTest) {
+  const char* script_chars =
+      "import 'dart:typed_data';\n"
+      "class A {\n"
+      "  var f1 = 3.0;\n"
+      "  var f2 = 3;\n"
+      "  final f3;\n"
+      "  A(x) : f3 = x;\n"
+      "  foo() {\n"
+      "    f1 = f1 + f1;\n"
+      "  }\n"
+      "  bar() {\n"
+      "    f2 = null;\n"
+      "    f2 = 3.0;\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runFoo() {\n"
+      "  var l = new Float32List(5);\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    var a = new A(l);\n"
+      "    a.foo();\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runBar() {\n"
+      "  var l = new Float32List(5);\n"
+      "  var a = new A(l);\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    a.bar();\n"
+      "  }\n"
+      "}\n"
+      "main() {\n"
+      "  runFoo();\n"
+      "  runBar();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(script_chars, NULL);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+  Field& f1 = Field::ZoneHandle(LookupField(lib, "A", "f1"));
+  Field& f2 = Field::ZoneHandle(LookupField(lib, "A", "f2"));
+  Field& f3 = Field::ZoneHandle(LookupField(lib, "A", "f3"));
+  const intptr_t no_length = Field::kNoFixedLength;
+  EXPECT_EQ(no_length, f1.guarded_list_length());
+  EXPECT_EQ(kDoubleCid, f1.guarded_cid());
+  EXPECT_EQ(false, f1.is_nullable());
+  EXPECT_EQ(no_length, f2.guarded_list_length());
+  EXPECT_EQ(kDynamicCid, f2.guarded_cid());
+  EXPECT_EQ(true, f2.is_nullable());
+  const intptr_t length = 5;
+  EXPECT_EQ(length, f3.guarded_list_length());
+  EXPECT_EQ(kTypedDataFloat32ArrayCid, f3.guarded_cid());
+  EXPECT_EQ(false, f3.is_nullable());
+}
+
+
+TEST_CASE(GuardFieldConstructor2Test) {
+  const char* script_chars =
+      "import 'dart:typed_data';\n"
+      "class A {\n"
+      "  final f3;\n"
+      "  A(x) : f3 = x;\n"
+      "  foo() {\n"
+      "  }\n"
+      "  bar() {\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runFoo() {\n"
+      "  var l = new Float32List(5);\n"
+      "  for (int i = 0; i < 2000; i++) {\n"
+      "    var a = new A(l);\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "runBar() {\n"
+      "  var l = new Float32List(99);\n"
+      "  var a = new A(l);\n"
+      "}\n"
+      "main() {\n"
+      "  runFoo();\n"
+      "  runBar();\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(script_chars, NULL);
+  Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+  EXPECT_VALID(result);
+  Field& f3 = Field::ZoneHandle(LookupField(lib, "A", "f3"));
+  const intptr_t no_length = Field::kNoFixedLength;
+  EXPECT_EQ(no_length, f3.guarded_list_length());
+  EXPECT_EQ(kTypedDataFloat32ArrayCid, f3.guarded_cid());
+  EXPECT_EQ(false, f3.is_nullable());
+}
+
+}  // namespace dart
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 6dd4419..2502674 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -55,7 +55,8 @@
   };
 
   // Default allocation sizes in MB for the old gen and code heaps.
-  static const intptr_t kHeapSizeInMB = 512;
+  static const intptr_t kHeapSizeInMWords = 128;
+  static const intptr_t kHeapSizeInMB = kHeapSizeInMWords * kWordSize;
   static const intptr_t kCodeHeapSizeInMB = 18;
 
   ~Heap();
diff --git a/runtime/vm/heap_histogram.cc b/runtime/vm/heap_histogram.cc
index 0ea4139..8f6123d 100644
--- a/runtime/vm/heap_histogram.cc
+++ b/runtime/vm/heap_histogram.cc
@@ -158,44 +158,47 @@
 
   intptr_t size_sum = 0;
   intptr_t count_sum = 0;
-  stream->OpenObject();
-  stream->PrintProperty("type", "ObjectHistogram");
-  stream->OpenArray("properties");
-  stream->PrintValue("size");
-  stream->PrintValue("count");
-  stream->CloseArray();
-  stream->OpenArray("members");
-  for (intptr_t pos = 0; pos < length; pos++) {
-    Element* e = array[pos];
-    if (e->count_ > 0) {
-      cls = isolate_->class_table()->At(e->class_id_);
-      str = cls.Name();
-      lib = cls.library();
-      stream->OpenObject();
-      stream->PrintProperty("type", "ObjectHistogramEntry");
-      // It should not be possible to overflow here because the total
-      // size of the heap is bounded and we are dividing the value
-      // by the number of major gcs that have occurred.
-      size_sum += (e->size_ / major_gc_count_);
-      count_sum += (e->count_ / major_gc_count_);
-      stream->PrintProperty("size", e->size_ / major_gc_count_);
-      stream->PrintProperty("count", e->count_ / major_gc_count_);
-      stream->PrintProperty("name", str.ToCString());
-      if (lib.IsNull()) {
-        stream->PrintProperty("category", "");
-      } else {
-        str = lib.url();
-        stream->PrintProperty("category", str.ToCString());
+  JSONObject jsobj(stream);
+  jsobj.AddProperty("type", "ObjectHistogram");
+  {  // TODO(johnmccutchan): Why is this empty array needed here?
+    JSONArray jsarr(&jsobj, "properties");
+    jsarr.AddValue("size");
+    jsarr.AddValue("count");
+  }
+  {
+    JSONArray jsarr(&jsobj, "members");
+    for (intptr_t pos = 0; pos < length; pos++) {
+      Element* e = array[pos];
+      if (e->count_ > 0) {
+        cls = isolate_->class_table()->At(e->class_id_);
+        str = cls.Name();
+        lib = cls.library();
+        JSONObject jsobj(&jsarr);
+        jsobj.AddProperty("type", "ObjectHistogramEntry");
+        // It should not be possible to overflow here because the total
+        // size of the heap is bounded and we are dividing the value
+        // by the number of major gcs that have occurred.
+        size_sum += (e->size_ / major_gc_count_);
+        count_sum += (e->count_ / major_gc_count_);
+        jsobj.AddProperty("size", e->size_ / major_gc_count_);
+        jsobj.AddProperty("count", e->count_ / major_gc_count_);
+        jsobj.AddProperty("class", cls, true);
+        jsobj.AddProperty("lib", lib, true);
+        // TODO(johnmccutchan): Update the UI to use the class and lib object
+        // properties above instead of name and category strings.
+        jsobj.AddProperty("name", str.ToCString());
+        if (lib.IsNull()) {
+          jsobj.AddProperty("category", "");
+        } else {
+          str = lib.url();
+          jsobj.AddProperty("category", str.ToCString());
+        }
       }
-      stream->CloseObject();
     }
   }
-  stream->CloseArray();
-  stream->OpenObject("sums");
-  stream->PrintProperty("size", size_sum);
-  stream->PrintProperty("count", count_sum);
-  stream->CloseObject();
-  stream->CloseObject();
+  JSONObject sums(&jsobj, "sums");
+  sums.AddProperty("size", size_sum);
+  sums.AddProperty("count", count_sum);
 
   // Deallocate the array for sorting.
   free(array);
diff --git a/runtime/vm/instructions_arm.cc b/runtime/vm/instructions_arm.cc
index c896e11..4ae5936 100644
--- a/runtime/vm/instructions_arm.cc
+++ b/runtime/vm/instructions_arm.cc
@@ -163,7 +163,7 @@
 }
 
 
-JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
+JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
 
 
 bool JumpPattern::IsValid() const {
diff --git a/runtime/vm/instructions_arm.h b/runtime/vm/instructions_arm.h
index 98230ae..59cb259 100644
--- a/runtime/vm/instructions_arm.h
+++ b/runtime/vm/instructions_arm.h
@@ -50,7 +50,7 @@
 
 class JumpPattern : public ValueObject {
  public:
-  explicit JumpPattern(uword pc);
+  JumpPattern(uword pc, const Code& code);
 
   static const int kLengthInBytes = 3 * Instr::kInstrSize;
 
diff --git a/runtime/vm/instructions_arm_test.cc b/runtime/vm/instructions_arm_test.cc
index 0b23884..dec458d 100644
--- a/runtime/vm/instructions_arm_test.cc
+++ b/runtime/vm/instructions_arm_test.cc
@@ -38,10 +38,11 @@
 
 
 ASSEMBLER_TEST_RUN(Jump, test) {
-  JumpPattern jump1(test->entry());
+  JumpPattern jump1(test->entry(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
+                    test->code());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_ia32.h b/runtime/vm/instructions_ia32.h
index 6f8af00..365ac26 100644
--- a/runtime/vm/instructions_ia32.h
+++ b/runtime/vm/instructions_ia32.h
@@ -11,6 +11,7 @@
 #endif
 
 #include "vm/allocation.h"
+#include "vm/object.h"
 
 namespace dart {
 
@@ -85,7 +86,7 @@
 
 class JumpPattern : public CallOrJumpPattern {
  public:
-  explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
+  JumpPattern(uword pc, const Code& code) : CallOrJumpPattern(pc) {}
 
  private:
   virtual const int* pattern() const;
diff --git a/runtime/vm/instructions_ia32_test.cc b/runtime/vm/instructions_ia32_test.cc
index 3ceade7..e449e21 100644
--- a/runtime/vm/instructions_ia32_test.cc
+++ b/runtime/vm/instructions_ia32_test.cc
@@ -35,10 +35,11 @@
 
 
 ASSEMBLER_TEST_RUN(Jump, test) {
-  JumpPattern jump1(test->entry());
+  JumpPattern jump1(test->entry(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
+                    test->code());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_mips.cc b/runtime/vm/instructions_mips.cc
index 1f79afd..7215ec0 100644
--- a/runtime/vm/instructions_mips.cc
+++ b/runtime/vm/instructions_mips.cc
@@ -177,7 +177,7 @@
 }
 
 
-JumpPattern::JumpPattern(uword pc) : pc_(pc) { }
+JumpPattern::JumpPattern(uword pc, const Code& code) : pc_(pc) { }
 
 
 bool JumpPattern::IsValid() const {
diff --git a/runtime/vm/instructions_mips.h b/runtime/vm/instructions_mips.h
index fc2ef10..7cecc70 100644
--- a/runtime/vm/instructions_mips.h
+++ b/runtime/vm/instructions_mips.h
@@ -50,7 +50,7 @@
 
 class JumpPattern : public ValueObject {
  public:
-  explicit JumpPattern(uword pc);
+  JumpPattern(uword pc, const Code& code);
 
   // lui; ori; jr; nop (in delay slot) = 4.
   static const int kLengthInBytes = 4*Instr::kInstrSize;
diff --git a/runtime/vm/instructions_mips_test.cc b/runtime/vm/instructions_mips_test.cc
index 4add9ef..7348db8 100644
--- a/runtime/vm/instructions_mips_test.cc
+++ b/runtime/vm/instructions_mips_test.cc
@@ -39,10 +39,11 @@
 
 
 ASSEMBLER_TEST_RUN(Jump, test) {
-  JumpPattern jump1(test->entry());
+  JumpPattern jump1(test->entry(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes(),
+                    test->code());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/instructions_x64.cc b/runtime/vm/instructions_x64.cc
index 62a4aa4..0f788073 100644
--- a/runtime/vm/instructions_x64.cc
+++ b/runtime/vm/instructions_x64.cc
@@ -11,6 +11,13 @@
 
 namespace dart {
 
+intptr_t InstructionPattern::IndexFromPPLoad(uword start) {
+  int32_t offset = *reinterpret_cast<int32_t*>(start);
+  offset +=  kHeapObjectTag;
+  return (offset - Array::data_offset()) / kWordSize;
+}
+
+
 bool InstructionPattern::TestBytesWith(const int* data, int num_bytes) const {
   ASSERT(data != NULL);
   const uint8_t* byte_array = reinterpret_cast<const uint8_t*>(start_);
@@ -24,13 +31,13 @@
 }
 
 
-uword CallOrJumpPattern::TargetAddress() const {
+uword CallPattern::TargetAddress() const {
   ASSERT(IsValid());
   return *reinterpret_cast<uword*>(start() + 2);
 }
 
 
-void CallOrJumpPattern::SetTargetAddress(uword target) const {
+void CallPattern::SetTargetAddress(uword target) const {
   ASSERT(IsValid());
   *reinterpret_cast<uword*>(start() + 2) = target;
   CPU::FlushICache(start() + 2, kWordSize);
@@ -46,11 +53,27 @@
 }
 
 
+uword JumpPattern::TargetAddress() const {
+  ASSERT(IsValid());
+  int index = InstructionPattern::IndexFromPPLoad(start() + 3);
+  return reinterpret_cast<uword>(object_pool_.At(index));
+}
+
+
+void JumpPattern::SetTargetAddress(uword target) const {
+  ASSERT(IsValid());
+  int index = InstructionPattern::IndexFromPPLoad(start() + 3);
+  const Smi& smi = Smi::Handle(reinterpret_cast<RawSmi*>(target));
+  object_pool_.SetAt(index, smi);
+  // No need to flush the instruction cache, since the code is not modified.
+}
+
+
 const int* JumpPattern::pattern() const {
-  // movq $target, TMP
-  // jmpq TMP
+  //  00: 4d 8b 9d imm32  mov R11, [R13 + off]
+  //  07: 41 ff e3        jmpq R11
   static const int kJumpPattern[kLengthInBytes] =
-      {0x49, 0xBB, -1, -1, -1, -1, -1, -1, -1, -1, 0x41, 0xFF, 0xE3};
+      {0x4D, 0x8B, -1, -1, -1, -1, -1, 0x41, 0xFF, 0xE3};
   return kJumpPattern;
 }
 
diff --git a/runtime/vm/instructions_x64.h b/runtime/vm/instructions_x64.h
index c4fc155..8b91e7d 100644
--- a/runtime/vm/instructions_x64.h
+++ b/runtime/vm/instructions_x64.h
@@ -11,6 +11,7 @@
 #endif
 
 #include "vm/allocation.h"
+#include "vm/object.h"
 
 namespace dart {
 
@@ -37,6 +38,8 @@
   virtual const int* pattern() const = 0;
   virtual int pattern_length_in_bytes() const = 0;
 
+  static intptr_t IndexFromPPLoad(uword start);
+
  protected:
   uword start() const { return start_; }
 
@@ -52,46 +55,47 @@
 };
 
 
-class CallOrJumpPattern : public InstructionPattern {
+class CallPattern : public InstructionPattern {
  public:
-  virtual int pattern_length_in_bytes() const {
+  CallPattern(uword pc, const Code& code)
+      : InstructionPattern(pc),
+        code_(code) {}
+  static int InstructionLength() {
     return kLengthInBytes;
   }
   uword TargetAddress() const;
   void SetTargetAddress(uword new_target) const;
-
- protected:
-  explicit CallOrJumpPattern(uword pc) : InstructionPattern(pc) {}
-  static const int kLengthInBytes = 13;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(CallOrJumpPattern);
-};
-
-
-class CallPattern : public CallOrJumpPattern {
- public:
-  explicit CallPattern(uword pc) : CallOrJumpPattern(pc) {}
-  static int InstructionLength() {
+  virtual int pattern_length_in_bytes() const {
     return kLengthInBytes;
   }
 
  private:
+  static const int kLengthInBytes = 13;
   virtual const int* pattern() const;
+  const Code& code_;
 
   DISALLOW_COPY_AND_ASSIGN(CallPattern);
 };
 
 
-class JumpPattern : public CallOrJumpPattern {
+class JumpPattern : public InstructionPattern {
  public:
-  explicit JumpPattern(uword pc) : CallOrJumpPattern(pc) {}
+  JumpPattern(uword pc, const Code& code)
+      : InstructionPattern(pc),
+        object_pool_(Array::Handle(code.ObjectPool())) {}
   static int InstructionLength() {
     return kLengthInBytes;
   }
+  uword TargetAddress() const;
+  void SetTargetAddress(uword new_target) const;
+  virtual int pattern_length_in_bytes() const {
+    return kLengthInBytes;
+  }
 
  private:
+  static const int kLengthInBytes = 10;
   virtual const int* pattern() const;
+  const Array& object_pool_;
 
   DISALLOW_COPY_AND_ASSIGN(JumpPattern);
 };
diff --git a/runtime/vm/instructions_x64_test.cc b/runtime/vm/instructions_x64_test.cc
index fb46518..72d41ea 100644
--- a/runtime/vm/instructions_x64_test.cc
+++ b/runtime/vm/instructions_x64_test.cc
@@ -21,25 +21,28 @@
 
 
 ASSEMBLER_TEST_RUN(Call, test) {
-  CallPattern call(test->entry());
+  CallPattern call(test->entry(), test->code());
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             call.TargetAddress());
 }
 
 
 ASSEMBLER_TEST_GENERATE(Jump, assembler) {
-  __ jmp(&StubCode::InstanceFunctionLookupLabel());
-  __ jmp(&StubCode::AllocateArrayLabel());
+  __ EnterDartFrame(0);  // 20 bytes
+  __ JmpPatchable(&StubCode::InstanceFunctionLookupLabel(), PP);
+  __ JmpPatchable(&StubCode::AllocateArrayLabel(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
 
 ASSEMBLER_TEST_RUN(Jump, test) {
-  JumpPattern jump1(test->entry());
+  JumpPattern jump1(test->entry() + 20, test->code());
   jump1.IsValid();
   EXPECT_EQ(StubCode::InstanceFunctionLookupLabel().address(),
             jump1.TargetAddress());
-  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes());
+  JumpPattern jump2(test->entry() + jump1.pattern_length_in_bytes() + 20,
+                    test->code());
   EXPECT_EQ(StubCode::AllocateArrayLabel().address(),
             jump2.TargetAddress());
   uword target1 = jump1.TargetAddress();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index dfa6cd4..355949f 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1368,6 +1368,16 @@
       IsFixedLengthArrayCid(call->Type()->ToCid())) {
     return call->ArgumentAt(1);
   }
+  // For arrays with guarded lengths, replace the length load
+  // with a constant.
+  LoadFieldInstr* load_array = instance()->definition()->AsLoadField();
+  if (load_array != NULL) {
+    const Field* field = load_array->field();
+    if ((field != NULL) && (field->guarded_list_length() >= 0)) {
+      return flow_graph->GetConstant(
+          Smi::Handle(Smi::New(field->guarded_list_length())));
+    }
+  }
   return this;
 }
 
@@ -1569,6 +1579,11 @@
     return NULL;  // Nothing to guard.
   }
 
+  if (field().guarded_list_length() != Field::kNoFixedLength) {
+    // We are still guarding the list length.
+    return this;
+  }
+
   if (field().is_nullable() && value()->Type()->IsNull()) {
     return NULL;
   }
@@ -1610,11 +1625,6 @@
 }
 
 
-void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-  // Nothing to do.
-}
-
-
 LocationSummary* JoinEntryInstr::MakeLocationSummary() const {
   UNREACHABLE();
   return NULL;
@@ -1835,9 +1845,6 @@
                                    deopt_id(),
                                    token_pos());
   }
-  if (function().name() == Symbols::EqualOperator().raw()) {
-    compiler->EmitSuperEqualityCallPrologue(locs()->out().reg(), &skip_call);
-  }
   compiler->GenerateStaticCall(deopt_id(),
                                token_pos(),
                                function(),
@@ -2644,6 +2651,27 @@
 }
 
 
+extern const RuntimeEntry kCosRuntimeEntry(
+    "libc_cos", reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&cos)), 1, true, true);
+
+extern const RuntimeEntry kSinRuntimeEntry(
+    "libc_sin", reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&sin)), 1, true, true);
+
+
+const RuntimeEntry& MathUnaryInstr::TargetFunction() const {
+  switch (kind()) {
+    case MethodRecognizer::kMathSin:
+      return kSinRuntimeEntry;
+    case MethodRecognizer::kMathCos:
+      return kCosRuntimeEntry;
+    default:
+      UNREACHABLE();
+  }
+  return kSinRuntimeEntry;
+}
+
 #undef __
 
 }  // namespace dart
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index bf09939..33cde45 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -69,7 +69,7 @@
   V(_StringBase, get:length, StringBaseLength, 1483460481)                     \
   V(_StringBase, get:isEmpty, StringBaseIsEmpty, 1588094430)                   \
   V(_StringBase, codeUnitAt, StringBaseCodeUnitAt, 1958436584)                 \
-  V(_StringBase, [], StringBaseCharAt, 539412735)                              \
+  V(_StringBase, [], StringBaseCharAt, 1799392702)                             \
   V(_OneByteString, _setAt, OneByteStringSetAt, 1754827784)                    \
   V(_IntegerImplementation, toDouble, IntegerToDouble, 2141284842)             \
   V(_IntegerImplementation, _leftShiftWithMask32, IntegerLeftShiftWithMask32,  \
@@ -4660,8 +4660,8 @@
   }
 
   Value* value() const { return inputs_[0]; }
-
   MethodRecognizer::Kind kind() const { return kind_; }
+  const RuntimeEntry& TargetFunction() const;
 
   virtual bool CanDeoptimize() const { return false; }
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index e8c1f2c..9ed4e93 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1443,13 +1443,8 @@
       new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
   summary->set_in(0, Location::RequiresRegister());
   const bool field_has_length = field().needs_length_check();
-  const bool need_value_temp_reg =
-      (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
-                            (field().guarded_cid() != kSmiCid)));
-  if (need_value_temp_reg) {
-    summary->AddTemp(Location::RequiresRegister());
-    summary->AddTemp(Location::RequiresRegister());
-  }
+  summary->AddTemp(Location::RequiresRegister());
+  summary->AddTemp(Location::RequiresRegister());
   const bool need_field_temp_reg =
       field_has_length || (field().guarded_cid() == kIllegalCid);
   if (need_field_temp_reg) {
@@ -1464,9 +1459,6 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
   const intptr_t field_length = field().guarded_list_length();
   const bool field_has_length = field().needs_length_check();
-  const bool needs_value_temp_reg =
-      (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
-                            (field().guarded_cid() != kSmiCid)));
   const bool needs_field_temp_reg =
       field_has_length || (field().guarded_cid() == kIllegalCid);
   if (field_has_length) {
@@ -1483,10 +1475,9 @@
 
   Register value_reg = locs()->in(0).reg();
 
-  Register value_cid_reg = needs_value_temp_reg ?
-      locs()->temp(0).reg() : kNoRegister;
-  Register temp_reg = needs_value_temp_reg ?
-      locs()->temp(1).reg() : kNoRegister;
+  Register value_cid_reg = locs()->temp(0).reg();
+
+  Register temp_reg = locs()->temp(1).reg();
 
   Register field_reg = needs_field_temp_reg ?
       locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
@@ -1518,11 +1509,8 @@
     FieldAddress field_length_operand(
         field_reg, Field::guarded_list_length_offset());
 
-    if (value_cid_reg == kNoRegister) {
-      ASSERT(!compiler->is_optimizing());
-      value_cid_reg = R3;
-      ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-    }
+    ASSERT(value_cid_reg != kNoRegister);
+    ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
 
     if (value_cid == kDynamicCid) {
       LoadValueCid(compiler, value_cid_reg, value_reg);
@@ -1536,13 +1524,53 @@
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
           __ ldr(temp_reg,
                  FieldAddress(value_reg, Array::length_offset()));
-          __ CompareImmediate(temp_reg, field_length);
+          __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
         } else if (RawObject::IsTypedDataClassId(field_cid)) {
           __ ldr(temp_reg,
                  FieldAddress(value_reg, TypedData::length_offset()));
-          __ CompareImmediate(temp_reg, field_length);
+          __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
         } else {
           ASSERT(field_cid == kIllegalCid);
+          ASSERT(field_length == Field::kUnknownFixedLength);
+          // At compile time we do not know the type of the field nor its
+          // length. At execution time we may have set the class id and
+          // list length so we compare the guarded length with the
+          // list length here, without this check the list length could change
+          // without triggering a deoptimization.
+          Label check_array, length_compared, no_fixed_length;
+          // If length is negative the length guard is either disabled or
+          // has not been initialized, either way it is safe to skip the
+          // length check.
+          __ ldr(IP, field_length_operand);
+          __ CompareImmediate(IP, 0);
+          __ b(&skip_length_check, LT);
+          __ CompareImmediate(value_cid_reg, kNullCid);
+          __ b(&no_fixed_length, EQ);
+          // Check for typed data array.
+          __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid);
+          __ b(&no_fixed_length, GT);
+          __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid);
+          // Could still be a regular array.
+          __ b(&check_array, LT);
+          __ ldr(temp_reg,
+                 FieldAddress(value_reg, TypedData::length_offset()));
+          __ ldr(IP, field_length_operand);
+          __ cmp(temp_reg, ShifterOperand(IP));
+          __ b(&length_compared);
+          // Check for regular array.
+          __ Bind(&check_array);
+          __ CompareImmediate(value_cid_reg, kImmutableArrayCid);
+          __ b(&no_fixed_length, GT);
+          __ CompareImmediate(value_cid_reg, kArrayCid);
+          __ b(&no_fixed_length, LT);
+          __ ldr(temp_reg,
+                 FieldAddress(value_reg, Array::length_offset()));
+          __ ldr(IP, field_length_operand);
+          __ cmp(temp_reg, ShifterOperand(IP));
+          __ b(&length_compared);
+          __ Bind(&no_fixed_length);
+          __ b(fail);
+          __ Bind(&length_compared);
           // Following branch cannot not occur, fall through.
         }
         __ b(fail, NE);
@@ -1561,18 +1589,26 @@
       if (field_has_length) {
         ASSERT(value_cid_reg != kNoRegister);
         ASSERT(temp_reg != kNoRegister);
-        if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
           __ ldr(temp_reg,
                   FieldAddress(value_reg, Array::length_offset()));
-          __ CompareImmediate(temp_reg, field_length);
-        } else if (RawObject::IsTypedDataClassId(field_cid)) {
+          __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
           __ ldr(temp_reg,
                   FieldAddress(value_reg, TypedData::length_offset()));
-          __ CompareImmediate(temp_reg, field_length);
+          __ CompareImmediate(temp_reg, Smi::RawValue(field_length));
+        } else if (field_cid != kIllegalCid) {
+          ASSERT(field_cid != value_cid);
+          ASSERT(field_length >= 0);
+          // Field has a known class id and length. At compile time it is
+          // known that the value's class id is not a fixed length list.
+          __ b(fail);
         } else {
           ASSERT(field_cid == kIllegalCid);
+          ASSERT(field_length == Field::kUnknownFixedLength);
           // Following jump cannot not occur, fall through.
         }
+        __ b(fail, NE);
       }
       // Not identical, possibly null.
       __ Bind(&skip_length_check);
@@ -1587,57 +1623,58 @@
       __ str(value_cid_reg, field_cid_operand);
       __ str(value_cid_reg, field_nullability_operand);
       if (field_has_length) {
-        Label check_array, local_exit, local_fail;
+        Label check_array, length_set, no_fixed_length;
         __ CompareImmediate(value_cid_reg, kNullCid);
-        __ b(&local_fail, EQ);
+        __ b(&no_fixed_length, EQ);
         // Check for typed data array.
         __ CompareImmediate(value_cid_reg, kTypedDataFloat32x4ArrayCid);
-        __ b(&local_fail, GT);
+        __ b(&no_fixed_length, GT);
         __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid);
-        __ b(&check_array, LT);  // Could still be a regular array.
+        // Could still be a regular array.
+        __ b(&check_array, LT);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ ldr(value_cid_reg,
                FieldAddress(value_reg, TypedData::length_offset()));
         __ str(value_cid_reg, field_length_operand);
-        __ b(&local_exit);  // Updated field length typed data array.
+        __ b(&length_set);  // Updated field length typed data array.
         // Check for regular array.
         __ Bind(&check_array);
         __ CompareImmediate(value_cid_reg, kImmutableArrayCid);
-        __ b(&local_fail, GT);
+        __ b(&no_fixed_length, GT);
         __ CompareImmediate(value_cid_reg, kArrayCid);
-        __ b(&local_fail, LT);
+        __ b(&no_fixed_length, LT);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ ldr(value_cid_reg,
                FieldAddress(value_reg, Array::length_offset()));
         __ str(value_cid_reg, field_length_operand);
-        __ b(&local_exit);  // Updated field length from regular array.
-
-        __ Bind(&local_fail);
-        __ LoadImmediate(IP, Field::kNoFixedLength);
+        // Updated field length from regular array.
+        __ b(&length_set);
+        __ Bind(&no_fixed_length);
+        __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength));
         __ str(IP, field_length_operand);
-
-        __ Bind(&local_exit);
+        __ Bind(&length_set);
       }
     } else {
       __ LoadImmediate(IP, value_cid);
       __ str(IP, field_cid_operand);
       __ str(IP, field_nullability_operand);
-      if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ ldr(value_cid_reg,
-               FieldAddress(value_reg, Array::length_offset()));
-        __ str(value_cid_reg, field_length_operand);
-      } else if (RawObject::IsTypedDataClassId(value_cid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ ldr(value_cid_reg,
-                FieldAddress(value_reg, TypedData::length_offset()));
-        __ str(value_cid_reg, field_length_operand);
-      } else {
-        __ LoadImmediate(IP, Field::kNoFixedLength);
-        __ str(IP, field_length_operand);
+      if (field_has_length) {
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ ldr(value_cid_reg,
+                 FieldAddress(value_reg, Array::length_offset()));
+          __ str(value_cid_reg, field_length_operand);
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ ldr(value_cid_reg,
+                  FieldAddress(value_reg, TypedData::length_offset()));
+          __ str(value_cid_reg, field_length_operand);
+        } else {
+          __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength));
+          __ str(IP, field_length_operand);
+        }
       }
     }
-
     if (!ok_is_fall_through) {
       __ b(&ok);
     }
@@ -3760,6 +3797,16 @@
 
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+  if ((kind() == MethodRecognizer::kMathSin) ||
+      (kind() == MethodRecognizer::kMathCos)) {
+    const intptr_t kNumInputs = 1;
+    const intptr_t kNumTemps = 0;
+    LocationSummary* summary =
+        new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+    summary->set_in(0, Location::FpuRegisterLocation(Q0));
+    summary->set_out(Location::FpuRegisterLocation(Q0));
+    return summary;
+  }
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
   LocationSummary* summary =
@@ -3776,7 +3823,7 @@
     DRegister result = EvenDRegisterOf(locs()->out().fpu_reg());
     __ vsqrtd(result, val);
   } else {
-    UNIMPLEMENTED();
+    __ CallRuntime(TargetFunction(), InputCount());
   }
 }
 
@@ -4388,6 +4435,13 @@
 }
 
 
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (!compiler->CanFallThroughTo(normal_entry())) {
+    __ b(compiler->GetJumpLabel(normal_entry()));
+  }
+}
+
+
 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ Bind(compiler->GetJumpLabel(this));
   if (!compiler->is_optimizing()) {
@@ -4444,8 +4498,7 @@
     // If the next block is the false successor we will fall through to it.
     __ b(compiler->GetJumpLabel(true_successor()), true_condition);
   } else {
-    // If the next block is the true successor we negate comparison and fall
-    // through to it.
+    // If the next block is not the false successor we will branch to it.
     Condition false_condition = NegateCondition(true_condition);
     __ b(compiler->GetJumpLabel(false_successor()), false_condition);
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 9341603..279051c 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1539,7 +1539,6 @@
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
-
   const intptr_t value_cid = value()->Type()->ToCid();
 
   Register value_reg = locs()->in(0).reg();
@@ -1585,7 +1584,6 @@
       }
 
       LoadValueCid(compiler, value_cid_reg, value_reg);
-
       Label skip_length_check;
       __ cmpl(value_cid_reg, field_cid_operand);
       // Value CID != Field guard CID, skip length check.
@@ -1596,17 +1594,58 @@
           __ pushl(value_cid_reg);
           __ movl(value_cid_reg,
                   FieldAddress(value_reg, Array::length_offset()));
-          __ cmpl(value_cid_reg, Immediate(field_length));
+          __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length)));
           __ popl(value_cid_reg);
         } else if (RawObject::IsTypedDataClassId(field_cid)) {
           __ pushl(value_cid_reg);
           __ movl(value_cid_reg,
                   FieldAddress(value_reg, TypedData::length_offset()));
-          __ cmpl(value_cid_reg, Immediate(field_length));
+          __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length)));
           __ popl(value_cid_reg);
         } else {
           ASSERT(field_cid == kIllegalCid);
-          // Following jump cannot not occur, fall through.
+          ASSERT(field_length == Field::kUnknownFixedLength);
+          // At compile time we do not know the type of the field nor its
+          // length. At execution time we may have set the class id and
+          // list length so we compare the guarded length with the
+          // list length here, without this check the list length could change
+          // without triggering a deoptimization.
+          Label check_array, length_compared, no_fixed_length;
+          // If length is negative the length guard is either disabled or
+          // has not been initialized, either way it is safe to skip the
+          // length check.
+          __ cmpl(field_length_operand, Immediate(Smi::RawValue(0)));
+          __ j(LESS, &skip_length_check);
+          __ cmpl(value_cid_reg, Immediate(kNullCid));
+          __ j(EQUAL, &no_fixed_length, Assembler::kNearJump);
+          // Check for typed data array.
+          __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
+          // Not a typed array or a regular array.
+          __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
+          __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
+          // Could still be a regular array.
+          __ j(LESS, &check_array, Assembler::kNearJump);
+          __ pushl(value_cid_reg);
+          __ movl(value_cid_reg,
+                  FieldAddress(value_reg, TypedData::length_offset()));
+          __ cmpl(field_length_operand, value_cid_reg);
+          __ popl(value_cid_reg);
+          __ jmp(&length_compared, Assembler::kNearJump);
+          // Check for regular array.
+          __ Bind(&check_array);
+          __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
+          __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
+          __ cmpl(value_cid_reg, Immediate(kArrayCid));
+          __ j(LESS, &no_fixed_length, Assembler::kNearJump);
+          __ pushl(value_cid_reg);
+          __ movl(value_cid_reg,
+                  FieldAddress(value_reg, Array::length_offset()));
+          __ cmpl(field_length_operand, value_cid_reg);
+          __ popl(value_cid_reg);
+          __ jmp(&length_compared, Assembler::kNearJump);
+          __ Bind(&no_fixed_length);
+          __ jmp(fail);
+          __ Bind(&length_compared);
         }
         __ j(NOT_EQUAL, fail);
       }
@@ -1625,28 +1664,25 @@
       __ j(NOT_EQUAL, &skip_length_check);
       // Insert length check.
       if (field_has_length) {
-        if (value_cid_reg == kNoRegister) {
-          ASSERT(!compiler->is_optimizing());
-          value_cid_reg = EDX;
-          ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-        }
         ASSERT(value_cid_reg != kNoRegister);
-        if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
-          __ pushl(value_cid_reg);
-          __ movl(value_cid_reg,
-                  FieldAddress(value_reg, Array::length_offset()));
-          __ cmpl(value_cid_reg, Immediate(field_length));
-          __ popl(value_cid_reg);
-        } else if (RawObject::IsTypedDataClassId(field_cid)) {
-          __ pushl(value_cid_reg);
-          __ movl(value_cid_reg,
-                  FieldAddress(value_reg, TypedData::length_offset()));
-          __ cmpl(value_cid_reg, Immediate(field_length));
-          __ popl(value_cid_reg);
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          __ cmpl(FieldAddress(value_reg, Array::length_offset()),
+                  Immediate(Smi::RawValue(field_length)));
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          __ cmpl(FieldAddress(value_reg, TypedData::length_offset()),
+                  Immediate(Smi::RawValue(field_length)));
+        } else if (field_cid != kIllegalCid) {
+          ASSERT(field_cid != value_cid);
+          ASSERT(field_length >= 0);
+          // Field has a known class id and length. At compile time it is
+          // known that the value's class id is not a fixed length list.
+          __ jmp(fail);
         } else {
           ASSERT(field_cid == kIllegalCid);
+          ASSERT(field_length == Field::kUnknownFixedLength);
           // Following jump cannot not occur, fall through.
         }
+        __ j(NOT_EQUAL, fail);
       }
       // Not identical, possibly null.
       __ Bind(&skip_length_check);
@@ -1654,7 +1690,6 @@
     // Jump when class id guard and list length guard are okay.
     __ j(EQUAL, &ok);
 
-
     // Check if guard field is uninitialized.
     __ cmpl(field_cid_operand, Immediate(kIllegalCid));
     // Jump to failure path when guard field has been initialized and
@@ -1667,58 +1702,59 @@
       __ movl(field_cid_operand, value_cid_reg);
       __ movl(field_nullability_operand, value_cid_reg);
       if (field_has_length) {
-        Label check_array, local_exit, local_fail;
+        Label check_array, length_set, no_fixed_length;
         __ cmpl(value_cid_reg, Immediate(kNullCid));
-        __ j(EQUAL, &local_fail);
+        __ j(EQUAL, &no_fixed_length, Assembler::kNearJump);
         // Check for typed data array.
         __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
-        __ j(GREATER, &local_fail);  // Not a typed array or a regular array.
+        // Not a typed array or a regular array.
+        __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
         __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
-        __ j(LESS, &check_array);  // Could still be a regular array.
+        // Could still be a regular array.
+        __ j(LESS, &check_array, Assembler::kNearJump);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ movl(value_cid_reg,
                 FieldAddress(value_reg, TypedData::length_offset()));
         __ movl(field_length_operand, value_cid_reg);
-        __ jmp(&local_exit);  // Updated field length typed data array.
+        // Updated field length typed data array.
+        __ jmp(&length_set, Assembler::kNearJump);
         // Check for regular array.
         __ Bind(&check_array);
         __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
-        __ j(GREATER, &local_fail);
+        __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
         __ cmpl(value_cid_reg, Immediate(kArrayCid));
-        __ j(LESS, &local_fail);
+        __ j(LESS, &no_fixed_length, Assembler::kNearJump);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ movl(value_cid_reg,
                 FieldAddress(value_reg, Array::length_offset()));
         __ movl(field_length_operand, value_cid_reg);
-        __ jmp(&local_exit);  // Updated field length from regular array.
-
-        __ Bind(&local_fail);
-        __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
-
-        __ Bind(&local_exit);
+        // Updated field length from regular array.
+        __ jmp(&length_set, Assembler::kNearJump);
+        __ Bind(&no_fixed_length);
+        __ movl(field_length_operand,
+                Immediate(Smi::RawValue(Field::kNoFixedLength)));
+        __ Bind(&length_set);
       }
     } else {
-      if (value_cid_reg == kNoRegister) {
-          ASSERT(!compiler->is_optimizing());
-          value_cid_reg = EDX;
-          ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-      }
-      ASSERT(value_cid_reg != kNoRegister);
       ASSERT(field_reg != kNoRegister);
       __ movl(field_cid_operand, Immediate(value_cid));
       __ movl(field_nullability_operand, Immediate(value_cid));
-      if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ movl(value_cid_reg,
-                FieldAddress(value_reg, Array::length_offset()));
-        __ movl(field_length_operand, value_cid_reg);
-      } else if (RawObject::IsTypedDataClassId(value_cid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ movl(value_cid_reg,
-                FieldAddress(value_reg, TypedData::length_offset()));
-        __ movl(field_length_operand, value_cid_reg);
-      } else {
-        __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
+      if (field_has_length) {
+        ASSERT(value_cid_reg != kNoRegister);
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ movl(value_cid_reg,
+                  FieldAddress(value_reg, Array::length_offset()));
+          __ movl(field_length_operand, value_cid_reg);
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ movl(value_cid_reg,
+                  FieldAddress(value_reg, TypedData::length_offset()));
+          __ movl(field_length_operand, value_cid_reg);
+        } else {
+          __ movl(field_length_operand,
+                  Immediate(Smi::RawValue(Field::kNoFixedLength)));
+        }
       }
     }
 
@@ -1727,7 +1763,6 @@
     }
   } else {
     // Field guard class has been initialized and is known.
-
     if (field_reg != kNoRegister) {
       __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
     }
@@ -3827,6 +3862,16 @@
 
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+  if ((kind() == MethodRecognizer::kMathSin) ||
+      (kind() == MethodRecognizer::kMathCos)) {
+    const intptr_t kNumInputs = 1;
+    const intptr_t kNumTemps = 0;
+    LocationSummary* summary =
+        new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+    summary->set_in(0, Location::FpuRegisterLocation(XMM1));
+    summary->set_out(Location::FpuRegisterLocation(XMM1));
+    return summary;
+  }
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
   LocationSummary* summary =
@@ -3840,23 +3885,14 @@
 void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (kind() == MethodRecognizer::kMathSqrt) {
     __ sqrtsd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg());
-  } else if ((kind() == MethodRecognizer::kMathCos) ||
-             (kind() == MethodRecognizer::kMathSin)) {
-    __ pushl(EAX);
-    __ pushl(EAX);
+  } else {
+    __ EnterFrame(0);
+    __ ReserveAlignedFrameSpace(kDoubleSize * InputCount());
     __ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
-    __ fldl(Address(ESP, 0));
-    if (kind() == MethodRecognizer::kMathSin) {
-      __ fsin();
-    } else {
-      ASSERT(kind() == MethodRecognizer::kMathCos);
-      __ fcos();
-    }
+    __ CallRuntime(TargetFunction(), InputCount());
     __ fstpl(Address(ESP, 0));
     __ movsd(locs()->out().fpu_reg(), Address(ESP, 0));
-    __ addl(ESP, Immediate(2 * kWordSize));
-  } else {
-    UNREACHABLE();
+    __ leave();
   }
 }
 
@@ -4734,6 +4770,13 @@
 }
 
 
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (!compiler->CanFallThroughTo(normal_entry())) {
+    __ jmp(compiler->GetJumpLabel(normal_entry()));
+  }
+}
+
+
 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ Bind(compiler->GetJumpLabel(this));
   if (!compiler->is_optimizing()) {
@@ -4828,11 +4871,10 @@
 void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler,
                                                Condition true_condition) {
   if (compiler->CanFallThroughTo(false_successor())) {
-    // If the next block is the false successor we will fall through to it.
+    // If the next block is the false successor, fall through to it.
     __ j(true_condition, compiler->GetJumpLabel(true_successor()));
   } else {
-    // If the next block is the true successor we negate comparison and fall
-    // through to it.
+    // If the next block is not the false successor, branch to it.
     Condition false_condition = NegateCondition(true_condition);
     __ j(false_condition, compiler->GetJumpLabel(false_successor()));
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 8fc1040..a1d5b18 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1591,15 +1591,48 @@
         // Field guard may have remembered list length, check it.
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
           __ lw(TMP, FieldAddress(value_reg, Array::length_offset()));
-          __ LoadImmediate(CMPRES1, field_length);
+          __ LoadImmediate(CMPRES1, Smi::RawValue(field_length));
           __ subu(CMPRES1, TMP, CMPRES1);
         } else if (RawObject::IsTypedDataClassId(field_cid)) {
           __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset()));
-          __ LoadImmediate(CMPRES1, field_length);
+          __ LoadImmediate(CMPRES1, Smi::RawValue(field_length));
           __ subu(CMPRES1, TMP, CMPRES1);
         } else {
           ASSERT(field_cid == kIllegalCid);
-          __ LoadImmediate(CMPRES1, 0x1);
+          ASSERT(field_length == Field::kUnknownFixedLength);
+          // At compile time we do not know the type of the field nor its
+          // length. At execution time we may have set the class id and
+          // list length so we compare the guarded length with the
+          // list length here, without this check the list length could change
+          // without triggering a deoptimization.
+          Label check_array, length_compared, no_fixed_length;
+          // If length is negative the length guard is either disabled or
+          // has not been initialized, either way it is safe to skip the
+          // length check.
+          __ lw(CMPRES1, field_length_operand);
+          __ BranchSignedLess(CMPRES1, 0, &skip_length_check);
+          __ BranchEqual(value_cid_reg, kNullCid, &no_fixed_length);
+          // Check for typed data array.
+          __ BranchSignedGreater(value_cid_reg, kTypedDataFloat32x4ArrayCid,
+                                 &no_fixed_length);
+          __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid,
+                              &check_array);
+          __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset()));
+          __ lw(CMPRES1, field_length_operand);
+          __ subu(CMPRES1, TMP, CMPRES1);
+          __ b(&length_compared);
+          // Check for regular array.
+          __ Bind(&check_array);
+          __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid,
+                                 &no_fixed_length);
+          __ BranchSignedLess(value_cid_reg, kArrayCid, &no_fixed_length);
+          __ lw(TMP, FieldAddress(value_reg, Array::length_offset()));
+          __ lw(CMPRES1, field_length_operand);
+          __ subu(CMPRES1, TMP, CMPRES1);
+          __ b(&length_compared);
+          __ Bind(&no_fixed_length);
+          __ b(fail);
+          __ Bind(&length_compared);
         }
         __ bne(CMPRES1, ZR, fail);
       }
@@ -1620,24 +1653,27 @@
       __ bne(CMPRES, ZR, &skip_length_check);
       // Insert length check.
       if (field_has_length) {
-        if (value_cid_reg == kNoRegister) {
-          ASSERT(!compiler->is_optimizing());
-          value_cid_reg = A1;
-          ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-        }
         ASSERT(value_cid_reg != kNoRegister);
-        if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
           __ lw(TMP, FieldAddress(value_reg, Array::length_offset()));
-          __ LoadImmediate(CMPRES, field_length);
+          __ LoadImmediate(CMPRES, Smi::RawValue(field_length));
           __ subu(CMPRES, TMP, CMPRES);
-        } else if (RawObject::IsTypedDataClassId(field_cid)) {
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
           __ lw(TMP, FieldAddress(value_reg, TypedData::length_offset()));
-          __ LoadImmediate(CMPRES, field_length);
+          __ LoadImmediate(CMPRES, Smi::RawValue(field_length));
           __ subu(CMPRES, TMP, CMPRES);
+        } else if (field_cid != kIllegalCid) {
+          ASSERT(field_cid != value_cid);
+          ASSERT(field_length >= 0);
+          // Field has a known class id and length. At compile time it is
+          // known that the value's class id is not a fixed length list.
+          __ b(fail);
         } else {
           ASSERT(field_cid == kIllegalCid);
-          __ LoadImmediate(CMPRES, 0x1);
+          ASSERT(field_length == Field::kUnknownFixedLength);
+          // Following jump cannot not occur, fall through.
         }
+        __ bne(CMPRES, ZR, fail);
       }
       __ Bind(&skip_length_check);
     }
@@ -1650,64 +1686,60 @@
       __ sw(value_cid_reg, field_cid_operand);
       __ sw(value_cid_reg, field_nullability_operand);
       if (field_has_length) {
-        Label check_array, local_exit, local_fail;
-        __ BranchEqual(value_cid_reg, kNullCid, &local_fail);
+        Label check_array, length_set, no_fixed_length;
+        __ BranchEqual(value_cid_reg, kNullCid, &no_fixed_length);
         // Check for typed data array.
         __ BranchSignedGreater(value_cid_reg, kTypedDataFloat32x4ArrayCid,
-                               &local_fail);
+                               &no_fixed_length);
         __ BranchSignedLess(value_cid_reg, kTypedDataInt8ArrayCid,
                             &check_array);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ lw(value_cid_reg,
               FieldAddress(value_reg, TypedData::length_offset()));
         __ sw(value_cid_reg, field_length_operand);
-        __ b(&local_exit);  // Updated field length typed data array.
+        // Updated field length typed data array.
+        __ b(&length_set);
         // Check for regular array.
         __ Bind(&check_array);
         __ BranchSignedGreater(value_cid_reg, kImmutableArrayCid,
-                               &local_fail);
-        __ BranchSignedLess(value_cid_reg, kArrayCid, &local_fail);
+                               &no_fixed_length);
+        __ BranchSignedLess(value_cid_reg, kArrayCid, &no_fixed_length);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ lw(value_cid_reg,
                 FieldAddress(value_reg, Array::length_offset()));
         __ sw(value_cid_reg, field_length_operand);
-        __ b(&local_exit);  // Updated field length from regular array.
-
-        __ Bind(&local_fail);
+        // Updated field length from regular array.
+        __ b(&length_set);
+        __ Bind(&no_fixed_length);
         // TODO(regis): TMP1 may conflict. Revisit.
-        __ LoadImmediate(TMP1, Field::kNoFixedLength);
+        __ LoadImmediate(TMP1, Smi::RawValue(Field::kNoFixedLength));
         __ sw(TMP1, field_length_operand);
-
-        __ Bind(&local_exit);
+        __ Bind(&length_set);
       }
     } else {
-      if (value_cid_reg == kNoRegister) {
-        ASSERT(!compiler->is_optimizing());
-        value_cid_reg = A1;
-        ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-      }
-      ASSERT(value_cid_reg != kNoRegister);
       ASSERT(field_reg != kNoRegister);
       __ LoadImmediate(TMP1, value_cid);
       __ sw(TMP1, field_cid_operand);
       __ sw(TMP1, field_nullability_operand);
-      if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ lw(value_cid_reg,
-              FieldAddress(value_reg, Array::length_offset()));
-        __ sw(value_cid_reg, field_length_operand);
-      } else if (RawObject::IsTypedDataClassId(value_cid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ lw(value_cid_reg,
-              FieldAddress(value_reg, TypedData::length_offset()));
-        __ sw(value_cid_reg, field_length_operand);
-      } else {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ LoadImmediate(value_cid_reg, Field::kNoFixedLength);
-        __ sw(value_cid_reg, field_length_operand);
+      if (field_has_length) {
+        ASSERT(value_cid_reg != kNoRegister);
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ lw(value_cid_reg,
+                FieldAddress(value_reg, Array::length_offset()));
+          __ sw(value_cid_reg, field_length_operand);
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ lw(value_cid_reg,
+                FieldAddress(value_reg, TypedData::length_offset()));
+          __ sw(value_cid_reg, field_length_operand);
+        } else {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ LoadImmediate(value_cid_reg, Smi::RawValue(Field::kNoFixedLength));
+          __ sw(value_cid_reg, field_length_operand);
+        }
       }
     }
-
     if (!ok_is_fall_through) {
       __ b(&ok);
     }
@@ -1775,7 +1807,7 @@
           __ lw(value_cid_reg,
                 FieldAddress(value_reg, TypedData::length_offset()));
         }
-        __ LoadImmediate(TMP1, field_length);
+        __ LoadImmediate(TMP1, Smi::RawValue(field_length));
         __ subu(CMPRES, value_cid_reg, TMP1);
         if (ok_is_fall_through) {
           __ bne(CMPRES, ZR, fail);
@@ -3184,6 +3216,16 @@
 
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+  if ((kind() == MethodRecognizer::kMathSin) ||
+      (kind() == MethodRecognizer::kMathCos)) {
+    const intptr_t kNumInputs = 1;
+    const intptr_t kNumTemps = 0;
+    LocationSummary* summary =
+        new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+    summary->set_in(0, Location::FpuRegisterLocation(D6));
+    summary->set_out(Location::FpuRegisterLocation(D0));
+    return summary;
+  }
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
   LocationSummary* summary =
@@ -3198,7 +3240,7 @@
   if (kind() == MethodRecognizer::kMathSqrt) {
     __ sqrtd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg());
   } else {
-    UNIMPLEMENTED();
+    __ CallRuntime(TargetFunction(), InputCount());
   }
 }
 
@@ -3786,6 +3828,13 @@
 }
 
 
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (!compiler->CanFallThroughTo(normal_entry())) {
+    __ b(compiler->GetJumpLabel(normal_entry()));
+  }
+}
+
+
 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ Bind(compiler->GetJumpLabel(this));
   if (!compiler->is_optimizing()) {
@@ -3863,12 +3912,11 @@
                                                Condition true_condition) {
   __ TraceSimMsg("ControlInstruction::EmitBranchOnCondition");
   if (compiler->CanFallThroughTo(false_successor())) {
-    // If the next block is the false successor we will fall through to it.
+    // If the next block is the false successor, fall through to it.
     Label* label = compiler->GetJumpLabel(true_successor());
     EmitBranchAfterCompare(compiler, true_condition, label);
   } else {
-    // If the next block is the true successor we negate comparison and fall
-    // through to it.
+    // If the next block is not the false successor, branch to it.
     Condition false_condition = NegateCondition(true_condition);
     Label* label = compiler->GetJumpLabel(false_successor());
     EmitBranchAfterCompare(compiler, false_condition, label);
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index d03bbb9..de1647a 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -96,20 +96,8 @@
     __ Bind(&done);
   }
 #endif
-  __ LeaveFrame();
-  __ ret();
 
-  // Generate 8 bytes of NOPs so that the debugger can patch the
-  // return pattern with a call to the debug stub.
-  // Note that the nop(8) byte pattern is not recognized by the debugger.
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
-  __ nop(1);
+  __ ReturnPatchable();
   compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
                                  Isolate::kNoDeoptId,
                                  token_pos());
@@ -315,7 +303,7 @@
   // The register allocator drops constant definitions that have no uses.
   if (!locs()->out().IsInvalid()) {
     Register result = locs()->out().reg();
-    __ LoadObject(result, value());
+    __ LoadObject(result, value(), PP);
   }
 }
 
@@ -465,12 +453,11 @@
   const Array& kNoArgumentNames = Object::null_array();
   const int kNumArgumentsChecked = 2;
 
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label check_identity;
-  __ cmpq(Address(RSP, 0 * kWordSize), raw_null);
+  __ LoadObject(TMP, Object::null_object(), PP);
+  __ cmpq(Address(RSP, 0 * kWordSize), TMP);
   __ j(EQUAL, &check_identity);
-  __ cmpq(Address(RSP, 1 * kWordSize), raw_null);
+  __ cmpq(Address(RSP, 1 * kWordSize), TMP);
   __ j(EQUAL, &check_identity);
 
   ICData& equality_ic_data = ICData::ZoneHandle(original_ic_data.raw());
@@ -511,10 +498,10 @@
     __ popq(RDX);
     __ cmpq(RAX, RDX);
     __ j(EQUAL, &is_true);
-    __ LoadObject(RAX, Bool::Get(kind != Token::kEQ));
+    __ LoadObject(RAX, Bool::Get(kind != Token::kEQ), PP);
     __ jmp(&equality_done);
     __ Bind(&is_true);
-    __ LoadObject(RAX, Bool::Get(kind == Token::kEQ));
+    __ LoadObject(RAX, Bool::Get(kind == Token::kEQ), PP);
     if (kind == Token::kNE) {
       // Skip not-equal result conversion.
       __ jmp(&equality_done);
@@ -524,7 +511,7 @@
     // necessary.
     Register ic_data_reg = locs->temp(0).reg();
     ASSERT(ic_data_reg == RBX);  // Stub depends on it.
-    __ LoadObject(ic_data_reg, equality_ic_data);
+    __ LoadObject(ic_data_reg, equality_ic_data, PP);
     compiler->GenerateCall(token_pos,
                            &StubCode::EqualityWithNullArgLabel(),
                            PcDescriptors::kRuntimeCall,
@@ -537,10 +524,10 @@
     // Negate the condition: true label returns false and vice versa.
     __ CompareObject(RAX, Bool::True());
     __ j(EQUAL, &true_label, Assembler::kNearJump);
-    __ LoadObject(RAX, Bool::True());
+    __ LoadObject(RAX, Bool::True(), PP);
     __ jmp(&done, Assembler::kNearJump);
     __ Bind(&true_label);
-    __ LoadObject(RAX, Bool::False());
+    __ LoadObject(RAX, Bool::False(), PP);
     __ Bind(&done);
   }
   __ Bind(&equality_done);
@@ -610,10 +597,10 @@
         Register result = locs->out().reg();
         Label load_true;
         __ j(cond, &load_true, Assembler::kNearJump);
-        __ LoadObject(result, Bool::False());
+        __ LoadObject(result, Bool::False(), PP);
         __ jmp(&done);
         __ Bind(&load_true);
-        __ LoadObject(result, Bool::True());
+        __ LoadObject(result, Bool::True(), PP);
       }
     } else {
       const int kNumberOfArguments = 2;
@@ -629,10 +616,10 @@
           Label false_label;
           __ CompareObject(RAX, Bool::True());
           __ j(EQUAL, &false_label, Assembler::kNearJump);
-          __ LoadObject(RAX, Bool::True());
+          __ LoadObject(RAX, Bool::True(), PP);
           __ jmp(&done);
           __ Bind(&false_label);
-          __ LoadObject(RAX, Bool::False());
+          __ LoadObject(RAX, Bool::False(), PP);
         }
       } else {
         if (branch->is_checked()) {
@@ -666,12 +653,11 @@
   __ testq(left, Immediate(kSmiTagMask));
   __ j(ZERO, deopt);
   // 'left' is not Smi.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
   Label identity_compare;
-  __ cmpq(right, raw_null);
+  __ CompareObject(right, Object::null_object());
   __ j(EQUAL, &identity_compare);
-  __ cmpq(left, raw_null);
+  __ CompareObject(left, Object::null_object());
   __ j(EQUAL, &identity_compare);
 
   __ LoadClassId(temp, left);
@@ -692,10 +678,10 @@
     Register result = locs.out().reg();
     __ j(EQUAL, &is_equal, Assembler::kNearJump);
     // Not equal.
-    __ LoadObject(result, Bool::Get(kind != Token::kEQ));
+    __ LoadObject(result, Bool::Get(kind != Token::kEQ), PP);
     __ jmp(&done, Assembler::kNearJump);
     __ Bind(&is_equal);
-    __ LoadObject(result, Bool::Get(kind == Token::kEQ));
+    __ LoadObject(result, Bool::Get(kind == Token::kEQ), PP);
     __ Bind(&done);
   } else {
     Condition cond = TokenKindToSmiCondition(kind);
@@ -718,12 +704,11 @@
   ASSERT(!ic_data.IsNull() && (ic_data.NumberOfChecks() > 0));
   Register left = locs->in(0).reg();
   Register right = locs->in(1).reg();
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
   Label done, identity_compare, non_null_compare;
-  __ cmpq(right, raw_null);
+  __ CompareObject(right, Object::null_object());
   __ j(EQUAL, &identity_compare, Assembler::kNearJump);
-  __ cmpq(left, raw_null);
+  __ CompareObject(left, Object::null_object());
   __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump);
   // Comparison with NULL is "===".
   __ Bind(&identity_compare);
@@ -735,10 +720,10 @@
     Register result = locs->out().reg();
     Label load_true;
     __ j(cond, &load_true, Assembler::kNearJump);
-    __ LoadObject(result, Bool::False());
+    __ LoadObject(result, Bool::False(), PP);
     __ jmp(&done);
     __ Bind(&load_true);
-    __ LoadObject(result, Bool::True());
+    __ LoadObject(result, Bool::True(), PP);
   }
   __ jmp(&done);
   __ Bind(&non_null_compare);  // Receiver is not null.
@@ -796,10 +781,10 @@
     Register result = locs.out().reg();
     Label done, is_true;
     __ j(true_condition, &is_true);
-    __ LoadObject(result, Bool::False());
+    __ LoadObject(result, Bool::False(), PP);
     __ jmp(&done);
     __ Bind(&is_true);
-    __ LoadObject(result, Bool::True());
+    __ LoadObject(result, Bool::True(), PP);
     __ Bind(&done);
   }
 }
@@ -1527,7 +1512,7 @@
       ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
     }
 
-    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+    __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
 
     FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(
@@ -1553,17 +1538,58 @@
           __ pushq(value_cid_reg);
           __ movq(value_cid_reg,
                   FieldAddress(value_reg, Array::length_offset()));
-          __ cmpq(value_cid_reg, Immediate(field_length));
+          __ cmpq(value_cid_reg, Immediate(Smi::RawValue(field_length)));
           __ popq(value_cid_reg);
         } else if (RawObject::IsTypedDataClassId(field_cid)) {
           __ pushq(value_cid_reg);
           __ movq(value_cid_reg,
                   FieldAddress(value_reg, TypedData::length_offset()));
-          __ cmpq(value_cid_reg, Immediate(field_length));
+          __ cmpq(value_cid_reg, Immediate(Smi::RawValue(field_length)));
           __ popq(value_cid_reg);
         } else {
           ASSERT(field_cid == kIllegalCid);
-          // Following jump cannot not occur, fall through.
+          ASSERT(field_length == Field::kUnknownFixedLength);
+          // At compile time we do not know the type of the field nor its
+          // length. At execution time we may have set the class id and
+          // list length so we compare the guarded length with the
+          // list length here, without this check the list length could change
+          // without triggering a deoptimization.
+          Label check_array, length_compared, no_fixed_length;
+          // If length is negative the length guard is either disabled or
+          // has not been initialized, either way it is safe to skip the
+          // length check.
+          __ cmpq(field_length_operand, Immediate(Smi::RawValue(0)));
+          __ j(LESS, &skip_length_check);
+          __ cmpq(value_cid_reg, Immediate(kNullCid));
+          __ j(EQUAL, &no_fixed_length, Assembler::kNearJump);
+          // Check for typed data array.
+          __ cmpq(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
+          // Not a typed array or a regular array.
+          __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
+          __ cmpq(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
+          // Could still be a regular array.
+          __ j(LESS, &check_array, Assembler::kNearJump);
+          __ pushq(value_cid_reg);
+          __ movq(value_cid_reg,
+                  FieldAddress(value_reg, TypedData::length_offset()));
+          __ cmpq(field_length_operand, value_cid_reg);
+          __ popq(value_cid_reg);
+          __ jmp(&length_compared, Assembler::kNearJump);
+          // Check for regular array.
+          __ Bind(&check_array);
+          __ cmpq(value_cid_reg, Immediate(kImmutableArrayCid));
+          __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
+          __ cmpq(value_cid_reg, Immediate(kArrayCid));
+          __ j(LESS, &no_fixed_length, Assembler::kNearJump);
+          __ pushq(value_cid_reg);
+          __ movq(value_cid_reg,
+                  FieldAddress(value_reg, Array::length_offset()));
+          __ cmpq(field_length_operand, value_cid_reg);
+          __ popq(value_cid_reg);
+          __ jmp(&length_compared, Assembler::kNearJump);
+          __ Bind(&no_fixed_length);
+          __ jmp(fail);
+          __ Bind(&length_compared);
         }
         __ j(NOT_EQUAL, fail);
       }
@@ -1578,28 +1604,25 @@
       __ j(NOT_EQUAL, &skip_length_check);
       // Insert length check.
       if (field_has_length) {
-        if (value_cid_reg == kNoRegister) {
-          ASSERT(!compiler->is_optimizing());
-          value_cid_reg = RDX;
-          ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-        }
         ASSERT(value_cid_reg != kNoRegister);
-        if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
-          __ pushq(value_cid_reg);
-          __ movq(value_cid_reg,
-                  FieldAddress(value_reg, Array::length_offset()));
-          __ cmpq(value_cid_reg, Immediate(field_length));
-          __ popq(value_cid_reg);
-        } else if (RawObject::IsTypedDataClassId(field_cid)) {
-          __ pushq(value_cid_reg);
-          __ movq(value_cid_reg,
-                  FieldAddress(value_reg, TypedData::length_offset()));
-          __ cmpq(value_cid_reg, Immediate(field_length));
-          __ popq(value_cid_reg);
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          __ cmpq(FieldAddress(value_reg, Array::length_offset()),
+                  Immediate(Smi::RawValue(field_length)));
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          __ cmpq(FieldAddress(value_reg, TypedData::length_offset()),
+                  Immediate(Smi::RawValue(field_length)));
+        } else if (field_cid != kIllegalCid) {
+          ASSERT(field_cid != value_cid);
+          ASSERT(field_length >= 0);
+          // Field has a known class id and length. At compile time it is
+          // known that the value's class id is not a fixed length list.
+          __ jmp(fail);
         } else {
           ASSERT(field_cid == kIllegalCid);
+          ASSERT(field_length == Field::kUnknownFixedLength);
           // Following jump cannot not occur, fall through.
         }
+        __ j(NOT_EQUAL, fail);
       }
       // Not identical, possibly null.
       __ Bind(&skip_length_check);
@@ -1613,67 +1636,67 @@
       __ movq(field_cid_operand, value_cid_reg);
       __ movq(field_nullability_operand, value_cid_reg);
       if (field_has_length) {
-        Label check_array, local_exit, local_fail;
+        Label check_array, length_set, no_fixed_length;
         __ cmpq(value_cid_reg, Immediate(kNullCid));
-        __ j(EQUAL, &local_fail);
+        __ j(EQUAL, &no_fixed_length, Assembler::kNearJump);
         // Check for typed data array.
         __ cmpq(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
-        __ j(GREATER, &local_fail);  // Not a typed array or a regular array.
+        // Not a typed array or a regular array.
+        __ j(GREATER, &no_fixed_length);
         __ cmpq(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
-        __ j(LESS, &check_array);  // Could still be a regular array.
+        // Could still be a regular array.
+        __ j(LESS, &check_array, Assembler::kNearJump);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ movq(value_cid_reg,
                 FieldAddress(value_reg, TypedData::length_offset()));
         __ movq(field_length_operand, value_cid_reg);
-        __ jmp(&local_exit);  // Updated field length typed data array.
+        // Updated field length typed data array.
+        __ jmp(&length_set);
         // Check for regular array.
         __ Bind(&check_array);
         __ cmpq(value_cid_reg, Immediate(kImmutableArrayCid));
-        __ j(GREATER, &local_fail);
+        __ j(GREATER, &no_fixed_length, Assembler::kNearJump);
         __ cmpq(value_cid_reg, Immediate(kArrayCid));
-        __ j(LESS, &local_fail);
+        __ j(LESS, &no_fixed_length, Assembler::kNearJump);
         // Destroy value_cid_reg (safe because we are finished with it).
         __ movq(value_cid_reg,
                 FieldAddress(value_reg, Array::length_offset()));
         __ movq(field_length_operand, value_cid_reg);
-        __ jmp(&local_exit);  // Updated field length from regular array.
-
-        __ Bind(&local_fail);
-        __ movq(field_length_operand, Immediate(Field::kNoFixedLength));
-
-        __ Bind(&local_exit);
+        // Updated field length from regular array.
+        __ jmp(&length_set, Assembler::kNearJump);
+        __ Bind(&no_fixed_length);
+        __ movq(field_length_operand,
+                Immediate(Smi::RawValue(Field::kNoFixedLength)));
+        __ Bind(&length_set);
       }
     } else {
-      if (value_cid_reg == kNoRegister) {
-          ASSERT(!compiler->is_optimizing());
-          value_cid_reg = RDX;
-          ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
-      }
-      ASSERT(value_cid_reg != kNoRegister);
       ASSERT(field_reg != kNoRegister);
       __ movq(field_cid_operand, Immediate(value_cid));
       __ movq(field_nullability_operand, Immediate(value_cid));
-      if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ movq(value_cid_reg,
-                FieldAddress(value_reg, Array::length_offset()));
-        __ movq(field_length_operand, value_cid_reg);
-      } else if (RawObject::IsTypedDataClassId(value_cid)) {
-        // Destroy value_cid_reg (safe because we are finished with it).
-        __ movq(value_cid_reg,
-                FieldAddress(value_reg, TypedData::length_offset()));
-        __ movq(field_length_operand, value_cid_reg);
-      } else {
-        __ movq(field_length_operand, Immediate(Field::kNoFixedLength));
+      if (field_has_length) {
+        ASSERT(value_cid_reg != kNoRegister);
+        if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ movq(value_cid_reg,
+                  FieldAddress(value_reg, Array::length_offset()));
+          __ movq(field_length_operand, value_cid_reg);
+        } else if (RawObject::IsTypedDataClassId(value_cid)) {
+          // Destroy value_cid_reg (safe because we are finished with it).
+          __ movq(value_cid_reg,
+                  FieldAddress(value_reg, TypedData::length_offset()));
+          __ movq(field_length_operand, value_cid_reg);
+        } else {
+          __ movq(field_length_operand,
+                  Immediate(Smi::RawValue(Field::kNoFixedLength)));
+        }
       }
     }
-
     if (!ok_is_fall_through) {
       __ jmp(&ok);
     }
   } else {
     if (field_reg != kNoRegister) {
-      __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
+      __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
     }
 
     if (value_cid == kDynamicCid) {
@@ -1709,9 +1732,7 @@
 
       if (field().is_nullable() && (field_cid != kNullCid)) {
         __ j(EQUAL, &ok);
-        const Immediate& raw_null =
-            Immediate(reinterpret_cast<intptr_t>(Object::null()));
-        __ cmpq(value_reg, raw_null);
+        __ CompareObject(value_reg, Object::null_object());
       }
 
       if (ok_is_fall_through) {
@@ -1736,7 +1757,7 @@
           __ movq(value_cid_reg,
                   FieldAddress(value_reg, TypedData::length_offset()));
         }
-        __ cmpq(value_cid_reg, Immediate(field_length));
+        __ cmpq(value_cid_reg, Immediate(Smi::RawValue(field_length)));
         if (ok_is_fall_through) {
           __ j(NOT_EQUAL, fail);
         }
@@ -1836,7 +1857,7 @@
   Register value = locs()->in(0).reg();
   Register temp = locs()->temp(0).reg();
 
-  __ LoadObject(temp, field());
+  __ LoadObject(temp, field(), PP);
   if (this->value()->NeedsStoreBuffer()) {
     __ StoreIntoObject(temp,
         FieldAddress(temp, Field::value_offset()), value, CanValueBeSmi());
@@ -1990,9 +2011,7 @@
   Label type_arguments_instantiated;
   const intptr_t len = type_arguments().Length();
   if (type_arguments().IsRawInstantiatedRaw(len)) {
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
-    __ cmpq(instantiator_reg, raw_null);
+    __ CompareObject(instantiator_reg, Object::null_object());
     __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
   }
   // Instantiate non-null type arguments.
@@ -2040,14 +2059,13 @@
   // the type arguments.
   Label type_arguments_instantiated;
   ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ cmpq(instantiator_reg, raw_null);
+
+  __ CompareObject(instantiator_reg, Object::null_object());
   __ j(EQUAL, &type_arguments_instantiated, Assembler::kNearJump);
   // Instantiate non-null type arguments.
   // In the non-factory case, we rely on the allocation stub to
   // instantiate the type arguments.
-  __ LoadObject(result_reg, type_arguments());
+  __ LoadObject(result_reg, type_arguments(), PP);
   // result_reg: uninstantiated type arguments.
 
   __ Bind(&type_arguments_instantiated);
@@ -2082,10 +2100,9 @@
   // instantiated from null becomes a vector of dynamic, then use null as
   // the type arguments and do not pass the instantiator.
   ASSERT(type_arguments().IsRawInstantiatedRaw(type_arguments().Length()));
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+
   Label instantiator_not_null;
-  __ cmpq(instantiator_reg, raw_null);
+  __ CompareObject(instantiator_reg, Object::null_object());
   __ j(NOT_EQUAL, &instantiator_not_null, Assembler::kNearJump);
   // Null was used in VisitExtractConstructorTypeArguments as the
   // instantiated type arguments, no proper instantiator needed.
@@ -2161,6 +2178,10 @@
                                 compiler->assembler()->CodeSize(),
                                 catch_handler_types_,
                                 needs_stacktrace());
+
+  // Restore the pool pointer.
+  __ LoadPoolPointer(PP);
+
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
   }
@@ -2241,7 +2262,7 @@
     // In unoptimized code check the usage counter to trigger OSR at loop
     // stack checks.  Use progressively higher thresholds for more deeply
     // nested loops to attempt to hit outer loops with OSR when possible.
-    __ LoadObject(temp, compiler->parsed_function().function());
+    __ LoadObject(temp, compiler->parsed_function().function(), PP);
     intptr_t threshold =
         FLAG_optimization_counter_threshold * (loop_depth() + 1);
     __ cmpq(FieldAddress(temp, Function::usage_counter_offset()),
@@ -3688,10 +3709,10 @@
   __ addq(RSP, Immediate(16));
   __ testl(result, result);
   __ j(NOT_ZERO, &non_zero, Assembler::kNearJump);
-  __ LoadObject(result, Bool::False());
+  __ LoadObject(result, Bool::False(), PP);
   __ jmp(&done);
   __ Bind(&non_zero);
-  __ LoadObject(result, Bool::True());
+  __ LoadObject(result, Bool::True(), PP);
   __ Bind(&done);
 }
 
@@ -3853,6 +3874,20 @@
 
 
 LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+  if ((kind() == MethodRecognizer::kMathSin) ||
+      (kind() == MethodRecognizer::kMathCos)) {
+    // Calling convention on x64 uses XMM0 and XMM1 to pass the first two
+    // double arguments and XMM0 to return the result. Unfortunately
+    // currently we can't specify these registers because ParallelMoveResolver
+    // assumes that XMM0 is free at all times.
+    // TODO(vegorov): allow XMM0 to be used.
+    const intptr_t kNumTemps = 0;
+    LocationSummary* summary =
+        new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall);
+    summary->set_in(0, Location::FpuRegisterLocation(XMM1));
+    summary->set_out(Location::FpuRegisterLocation(XMM1));
+    return summary;
+  }
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps = 0;
   LocationSummary* summary =
@@ -3866,23 +3901,13 @@
 void MathUnaryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (kind() == MethodRecognizer::kMathSqrt) {
     __ sqrtsd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg());
-  } else if ((kind() == MethodRecognizer::kMathCos) ||
-             (kind() == MethodRecognizer::kMathSin)) {
-    __ pushq(RAX);
-    __ movsd(Address(RSP, 0), locs()->in(0).fpu_reg());
-    __ fldl(Address(RSP, 0));
-    if (kind() == MethodRecognizer::kMathSin) {
-      __ fsin();
-    } else {
-      ASSERT(kind() == MethodRecognizer::kMathCos);
-      __ fcos();
-    }
-    __ fstpl(Address(RSP, 0));
-    __ movsd(locs()->out().fpu_reg(), Address(RSP, 0));
-    __ addq(RSP, Immediate(kWordSize));
-    return;
   } else {
-    UNREACHABLE();
+    __ EnterFrame(0);
+    __ ReserveAlignedFrameSpace(0);
+    __ movaps(XMM0, locs()->in(0).fpu_reg());
+    __ CallRuntime(TargetFunction(), InputCount());
+    __ movaps(locs()->out().fpu_reg(), XMM0);
+    __ leave();
   }
 }
 
@@ -4205,9 +4230,9 @@
 
     Label check_base_is_one;
     // Check if exponent is 0.0 -> return 1.0;
-    __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0)));
+    __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(0)), PP);
     __ movsd(zero_temp, FieldAddress(temp, Double::value_offset()));
-    __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)));
+    __ LoadObject(temp, Double::ZoneHandle(Double::NewCanonical(1)), PP);
     __ movsd(result, FieldAddress(temp, Double::value_offset()));
     // 'result' contains 1.0.
     __ comisd(exp, zero_temp);
@@ -4305,9 +4330,8 @@
   if (IsNullCheck()) {
     Label* deopt = compiler->AddDeoptStub(deopt_id(),
                                           kDeoptCheckClass);
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
-    __ cmpq(locs()->in(0).reg(), raw_null);
+    __ CompareObject(locs()->in(0).reg(),
+                     Object::null_object());
     __ j(EQUAL, deopt);
     return;
   }
@@ -4506,6 +4530,13 @@
 }
 
 
+void GraphEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+  if (!compiler->CanFallThroughTo(normal_entry())) {
+    __ jmp(compiler->GetJumpLabel(normal_entry()));
+  }
+}
+
+
 void TargetEntryInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   __ Bind(compiler->GetJumpLabel(this));
   if (!compiler->is_optimizing()) {
@@ -4517,7 +4548,7 @@
     counter.SetAt(0, Smi::Handle(Smi::New(0)));
     Label done;
     __ Comment("Edge counter");
-    __ LoadObject(RAX, counter);
+    __ LoadObject(RAX, counter, PP);
     __ addq(FieldAddress(RAX, Array::element_offset(0)),
             Immediate(Smi::RawValue(1)));
     __ j(NO_OVERFLOW, &done);
@@ -4548,7 +4579,7 @@
     counter.SetAt(0, Smi::Handle(Smi::New(0)));
     Label done;
     __ Comment("Edge counter");
-    __ LoadObject(RAX, counter);
+    __ LoadObject(RAX, counter, PP);
     __ addq(FieldAddress(RAX, Array::element_offset(0)),
             Immediate(Smi::RawValue(1)));
     __ j(NO_OVERFLOW, &done);
@@ -4581,11 +4612,10 @@
 void ControlInstruction::EmitBranchOnCondition(FlowGraphCompiler* compiler,
                                                Condition true_condition) {
   if (compiler->CanFallThroughTo(false_successor())) {
-    // If the next block is the false successor we will fall through to it.
+    // If the next block is the false successor, fall through to it.
     __ j(true_condition, compiler->GetJumpLabel(true_successor()));
   } else {
-    // If the next block is the true successor we negate comparison and fall
-    // through to it.
+    // If the next block is not the false successor, branch to it.
     Condition false_condition = NegateCondition(true_condition);
     __ j(false_condition, compiler->GetJumpLabel(false_successor()));
 
@@ -4631,7 +4661,7 @@
     const bool result = (kind() == Token::kEQ_STRICT) ?
         left.constant().raw() == right.constant().raw() :
         left.constant().raw() != right.constant().raw();
-    __ LoadObject(locs()->out().reg(), Bool::Get(result));
+    __ LoadObject(locs()->out().reg(), Bool::Get(result), PP);
     return;
   }
   if (left.IsConstant()) {
@@ -4655,10 +4685,10 @@
   Label load_true, done;
   Condition true_condition = (kind() == Token::kEQ_STRICT) ? EQUAL : NOT_EQUAL;
   __ j(true_condition, &load_true, Assembler::kNearJump);
-  __ LoadObject(result, Bool::False());
+  __ LoadObject(result, Bool::False(), PP);
   __ jmp(&done, Assembler::kNearJump);
   __ Bind(&load_true);
-  __ LoadObject(result, Bool::True());
+  __ LoadObject(result, Bool::True(), PP);
   __ Bind(&done);
 }
 
@@ -4717,7 +4747,7 @@
   const Array& arguments_descriptor =
       Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
                                                  argument_names()));
-  __ LoadObject(temp_reg, arguments_descriptor);
+  __ LoadObject(temp_reg, arguments_descriptor, PP);
   ASSERT(temp_reg == R10);
   compiler->GenerateDartCall(deopt_id(),
                              token_pos(),
@@ -4740,10 +4770,10 @@
   Register result = locs()->out().reg();
 
   Label done;
-  __ LoadObject(result, Bool::True());
+  __ LoadObject(result, Bool::True(), PP);
   __ CompareRegisters(result, value);
   __ j(NOT_EQUAL, &done, Assembler::kNearJump);
-  __ LoadObject(result, Bool::False());
+  __ LoadObject(result, Bool::False(), PP);
   __ Bind(&done);
 }
 
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 12c15ec..e7edd62 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -102,10 +102,10 @@
 #define SETUP_FUNCTION(class_name, function_name, destination, fp)             \
   if (strcmp(#class_name, "::") == 0) {                                        \
     str = String::New(#function_name);                                         \
-    func = lib.LookupFunctionAllowPrivate(str, NULL);                          \
+    func = lib.LookupFunctionAllowPrivate(str);                                \
   } else {                                                                     \
     str = String::New(#class_name);                                            \
-    cls = lib.LookupClassAllowPrivate(str, NULL);                              \
+    cls = lib.LookupClassAllowPrivate(str);                                    \
     ASSERT(!cls.IsNull());                                                     \
     error = cls.EnsureIsFinalized(isolate);                                    \
     ASSERT(error.IsNull());                                                    \
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index 04d4199..9b54c7f 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -17,6 +17,7 @@
 // build and run to get the correct fingerprint from the mismatch error.
 #define CORE_LIB_INTRINSIC_LIST(V)                                             \
   V(_Smi, ~, Smi_bitNegate, 635678453)                                         \
+  V(_Smi, get:bitLength, Smi_bitLength, 383357874)                             \
   V(_Double, >, Double_greaterThan, 1021232334)                                \
   V(_Double, >=, Double_greaterEqualThan, 324955595)                           \
   V(_Double, <, Double_lessThan, 978151157)                                    \
@@ -32,17 +33,17 @@
   V(_Double, .fromInteger, Double_fromInteger, 475441744)                      \
   V(_ObjectArray, ., ObjectArray_Allocate, 1930677134)                         \
   V(_ObjectArray, get:length, Array_getLength, 259323113)                      \
-  V(_ObjectArray, [], Array_getIndexed, 93386978)                              \
-  V(_ObjectArray, []=, Array_setIndexed, 1296046137)                           \
+  V(_ObjectArray, [], Array_getIndexed, 1353366945)                            \
+  V(_ObjectArray, []=, Array_setIndexed, 1492559642)                           \
   V(_GrowableObjectArray, .withData, GrowableArray_Allocate, 1012992871)       \
   V(_GrowableObjectArray, get:length, GrowableArray_getLength, 1160357614)     \
   V(_GrowableObjectArray, get:_capacity, GrowableArray_getCapacity, 1509781988)\
-  V(_GrowableObjectArray, [], GrowableArray_getIndexed, 500679426)             \
-  V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 211112998)            \
+  V(_GrowableObjectArray, [], GrowableArray_getIndexed, 1760659393)            \
+  V(_GrowableObjectArray, []=, GrowableArray_setIndexed, 407626503)            \
   V(_GrowableObjectArray, _setLength, GrowableArray_setLength, 1922121178)     \
   V(_GrowableObjectArray, _setData, GrowableArray_setData, 236295352)          \
   V(_GrowableObjectArray, add, GrowableArray_add, 1442410650)                  \
-  V(_ImmutableArray, [], ImmutableArray_getIndexed, 894753724)                 \
+  V(_ImmutableArray, [], ImmutableArray_getIndexed, 7250043)                   \
   V(_ImmutableArray, get:length, ImmutableArray_getLength, 1341942416)         \
   V(Object, ==, Object_equal, 677817295)                                       \
   V(_StringBase, get:hashCode, String_getHashCode, 654483446)                  \
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 6bae006..734b889 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -168,7 +168,7 @@
 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
   const Library& core_lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL));
+      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray()));
   ASSERT(!cls.IsNull());
   ASSERT(cls.HasTypeArguments());
   ASSERT(cls.NumTypeArguments() == 1);
@@ -1071,6 +1071,11 @@
 }
 
 
+void Intrinsifier::Smi_bitLength(Assembler* assembler) {
+  // TODO(sra): Implement as word-length - CLZ.
+}
+
+
 // Check if the last argument is a double, jump to label 'is_smi' if smi
 // (easy to convert to double), otherwise jump to label 'not_double_smi',
 // Returns the last argument in R0.
@@ -1332,7 +1337,7 @@
   const Library& math_lib = Library::Handle(Library::MathLibrary());
   ASSERT(!math_lib.IsNull());
   const Class& random_class = Class::Handle(
-      math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
+      math_lib.LookupClassAllowPrivate(Symbols::_Random()));
   ASSERT(!random_class.IsNull());
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceField(Symbols::_state()));
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 251ba78..64758e6 100644
--- a/runtime/vm/intrinsifier_ia32.cc
+++ b/runtime/vm/intrinsifier_ia32.cc
@@ -173,7 +173,7 @@
 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
   const Library& core_lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL));
+      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray()));
   ASSERT(!cls.IsNull());
   ASSERT(cls.HasTypeArguments());
   ASSERT(cls.NumTypeArguments() == 1);
@@ -1087,6 +1087,22 @@
 }
 
 
+void Intrinsifier::Smi_bitLength(Assembler* assembler) {
+  ASSERT(kSmiTagShift == 1);
+  __ movl(EAX, Address(ESP, + 1 * kWordSize));  // Index.
+  // XOR with sign bit to complement bits if value is negative.
+  __ movl(ECX, EAX);
+  __ sarl(ECX, Immediate(31));  // All 0 or all 1.
+  __ xorl(EAX, ECX);
+  // BSR does not write the destination register if source is zero.  Put a 1 in
+  // the Smi tag bit to ensure BSR writes to destination register.
+  __ orl(EAX, Immediate(kSmiTagMask));
+  __ bsrl(EAX, EAX);
+  __ SmiTag(EAX);
+  __ ret();
+}
+
+
 // Check if the last argument is a double, jump to label 'is_smi' if smi
 // (easy to convert to double), otherwise jump to label 'not_double_smi',
 // Returns the last argument in EAX.
@@ -1393,7 +1409,7 @@
   const Library& math_lib = Library::Handle(Library::MathLibrary());
   ASSERT(!math_lib.IsNull());
   const Class& random_class = Class::Handle(
-      math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
+      math_lib.LookupClassAllowPrivate(Symbols::_Random()));
   ASSERT(!random_class.IsNull());
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceField(Symbols::_state()));
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 6eb52e8..de39ced8 100644
--- a/runtime/vm/intrinsifier_mips.cc
+++ b/runtime/vm/intrinsifier_mips.cc
@@ -176,7 +176,7 @@
 static intptr_t ComputeObjectArrayTypeArgumentsOffset() {
   const Library& core_lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::Handle(
-      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray(), NULL));
+      core_lib.LookupClassAllowPrivate(Symbols::ObjectArray()));
   ASSERT(!cls.IsNull());
   ASSERT(cls.HasTypeArguments());
   ASSERT(cls.NumTypeArguments() == 1);
@@ -1093,6 +1093,11 @@
 }
 
 
+void Intrinsifier::Smi_bitLength(Assembler* assembler) {
+  // TODO(sra): Implement.
+}
+
+
 // Check if the last argument is a double, jump to label 'is_smi' if smi
 // (easy to convert to double), otherwise jump to label 'not_double_smi',
 // Returns the last argument in T0.
@@ -1394,7 +1399,7 @@
   const Library& math_lib = Library::Handle(Library::MathLibrary());
   ASSERT(!math_lib.IsNull());
   const Class& random_class = Class::Handle(
-      math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
+      math_lib.LookupClassAllowPrivate(Symbols::_Random()));
   ASSERT(!random_class.IsNull());
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceField(Symbols::_state()));
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index 8b23532..cdfa888 100644
--- a/runtime/vm/intrinsifier_x64.cc
+++ b/runtime/vm/intrinsifier_x64.cc
@@ -117,15 +117,14 @@
   // RCX: new object end address.
   // RDI: iterator which initially points to the start of the variable
   // data area to be initialized.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R12, Object::null_object(), PP);
   __ leaq(RDI, FieldAddress(RAX, sizeof(RawArray)));
   Label done;
   Label init_loop;
   __ Bind(&init_loop);
   __ cmpq(RDI, RCX);
   __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
-  __ movq(Address(RDI, 0), raw_null);
+  __ movq(Address(RDI, 0), R12);
   __ addq(RDI, Immediate(kWordSize));
   __ jmp(&init_loop, Assembler::kNearJump);
   __ Bind(&done);
@@ -392,9 +391,7 @@
   __ StoreIntoObject(RDX,
                      FieldAddress(RDX, RCX, TIMES_4, Array::data_offset()),
                      RAX);
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<int64_t>(Object::null()));
-  __ movq(RAX, raw_null);
+  __ LoadObject(RAX, Object::null_object(), PP);
   __ ret();
   __ Bind(&fall_through);
 }
@@ -879,10 +876,10 @@
   // RAX contains the right argument.
   __ cmpq(Address(RSP, + 2 * kWordSize), RAX);
   __ j(true_condition, &true_label, Assembler::kNearJump);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&true_label);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
   __ Bind(&fall_through);
 }
@@ -919,34 +916,39 @@
 void Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
   Label fall_through, true_label, check_for_mint;
   // For integer receiver '===' check first.
-  __ movq(RAX, Address(RSP, + 1 * kWordSize));
-  __ movq(RCX, Address(RSP, + 2 * kWordSize));
+  // Entering a dart frame so we can use the PP for loading True and False.
+  __ EnterDartFrame(0);
+  __ movq(RAX, Address(RSP, + 4 * kWordSize));
+  __ movq(RCX, Address(RSP, + 5 * kWordSize));
   __ cmpq(RAX, RCX);
   __ j(EQUAL, &true_label, Assembler::kNearJump);
   __ orq(RAX, RCX);
   __ testq(RAX, Immediate(kSmiTagMask));
   __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump);
   // Both arguments are smi, '===' is good enough.
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
   __ Bind(&true_label);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
 
   // At least one of the arguments was not Smi.
   Label receiver_not_smi;
   __ Bind(&check_for_mint);
-  __ movq(RAX, Address(RSP, + 2 * kWordSize));  // Receiver.
+  __ movq(RAX, Address(RSP, + 5 * kWordSize));  // Receiver.
   __ testq(RAX, Immediate(kSmiTagMask));
   __ j(NOT_ZERO, &receiver_not_smi);
 
   // Left (receiver) is Smi, return false if right is not Double.
   // Note that an instance of Mint or Bigint never contains a value that can be
   // represented by Smi.
-  __ movq(RAX, Address(RSP, + 1 * kWordSize));
+  __ movq(RAX, Address(RSP, + 4 * kWordSize));
   __ CompareClassId(RAX, kDoubleCid);
   __ j(EQUAL, &fall_through);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
 
   __ Bind(&receiver_not_smi);
@@ -954,14 +956,17 @@
   __ CompareClassId(RAX, kMintCid);
   __ j(NOT_EQUAL, &fall_through);
   // Receiver is Mint, return false if right is Smi.
-  __ movq(RAX, Address(RSP, + 1 * kWordSize));  // Right argument.
+  __ movq(RAX, Address(RSP, + 4 * kWordSize));  // Right argument.
   __ testq(RAX, Immediate(kSmiTagMask));
   __ j(NOT_ZERO, &fall_through);
-  __ LoadObject(RAX, Bool::False());  // Smi == Mint -> false.
+  // Smi == Mint -> false.
+  __ LoadObject(RAX, Bool::False(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
   // TODO(srdjan): Implement Mint == Mint comparison.
 
   __ Bind(&fall_through);
+  __ LeaveFrameWithPP();
 }
 
 
@@ -1004,6 +1009,11 @@
 }
 
 
+void Intrinsifier::Smi_bitLength(Assembler* assembler) {
+  // TODO(sra): Implement using bsrq.
+}
+
+
 // Check if the last argument is a double, jump to label 'is_smi' if smi
 // (easy to convert to double), otherwise jump to label 'not_double_smi',
 // Returns the last argument in RAX.
@@ -1036,10 +1046,10 @@
   __ j(true_condition, &is_true, Assembler::kNearJump);
   // Fall through false.
   __ Bind(&is_false);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&is_true);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
   __ Bind(&is_smi);
   __ SmiUntag(RAX);
@@ -1173,10 +1183,10 @@
   __ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
   __ comisd(XMM0, XMM0);
   __ j(PARITY_EVEN, &is_true, Assembler::kNearJump);  // NaN -> true;
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&is_true);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
 }
 
@@ -1191,10 +1201,10 @@
   __ j(EQUAL, &is_zero, Assembler::kNearJump);  // Check for negative zero.
   __ j(ABOVE_EQUAL, &is_false, Assembler::kNearJump);  // >= 0 -> false.
   __ Bind(&is_true);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
   __ Bind(&is_false);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&is_zero);
   // Check for negative zero (get the sign bit).
@@ -1305,7 +1315,7 @@
   const Library& math_lib = Library::Handle(Library::MathLibrary());
   ASSERT(!math_lib.IsNull());
   const Class& random_class = Class::Handle(
-      math_lib.LookupClassAllowPrivate(Symbols::_Random(), NULL));
+      math_lib.LookupClassAllowPrivate(Symbols::_Random()));
   ASSERT(!random_class.IsNull());
   const Field& state_field = Field::ZoneHandle(
       random_class.LookupInstanceField(Symbols::_state()));
@@ -1342,17 +1352,23 @@
 }
 
 
-
 // Identity comparison.
 void Intrinsifier::Object_equal(Assembler* assembler) {
   Label is_true;
-  __ movq(RAX, Address(RSP, + 1 * kWordSize));
-  __ cmpq(RAX, Address(RSP, + 2 * kWordSize));
+  // This intrinsic is used from the API even when we have not entered any
+  // Dart frame, yet, so the PP would otherwise be null in this case unless
+  // we enter a Dart frame here.
+  __ EnterDartFrame(0);
+  __ movq(RAX, Address(RSP, + 4 * kWordSize));
+  __ cmpq(RAX, Address(RSP, + 5 * kWordSize));
   __ j(EQUAL, &is_true, Assembler::kNearJump);
-  __ LoadObject(RAX, Bool::False());
+  __ movq(RAX, Immediate(reinterpret_cast<int64_t>(Bool::False().raw())));
+  __ LoadObject(RAX, Bool::False(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
   __ Bind(&is_true);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -1412,10 +1428,10 @@
   __ movq(RAX, FieldAddress(RAX, String::length_offset()));
   __ cmpq(RAX, Immediate(Smi::RawValue(0)));
   __ j(EQUAL, &is_true, Assembler::kNearJump);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&is_true);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
 }
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index a572e76..3673b92 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -10,6 +10,7 @@
 #include "lib/mirrors.h"
 #include "vm/code_observers.h"
 #include "vm/compiler_stats.h"
+#include "vm/coverage.h"
 #include "vm/dart_api_state.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
@@ -712,8 +713,6 @@
 
 void Isolate::PrintInvokedFunctions() {
   ASSERT(this == Isolate::Current());
-  StackZone zone(this);
-  HandleScope handle_scope(this);
   const GrowableObjectArray& libraries =
       GrowableObjectArray::Handle(object_store()->libraries());
   Library& library = Library::Handle();
@@ -758,51 +757,54 @@
   ASSERT(top_resource() == NULL);
   ASSERT((heap_ == NULL) || heap_->Verify());
 
-  if (FLAG_print_object_histogram) {
+  // Create an area where we do have a zone and a handle scope so that we can
+  // call VM functions while tearing this isolate down.
+  {
     StackZone stack_zone(this);
     HandleScope handle_scope(this);
-    heap()->CollectAllGarbage();
-    object_histogram()->Print();
+
+    if (FLAG_print_object_histogram) {
+      heap()->CollectAllGarbage();
+      object_histogram()->Print();
+    }
+
+    // Clean up debugger resources.
+    debugger()->Shutdown();
+
+    // Close all the ports owned by this isolate.
+    PortMap::ClosePorts(message_handler());
+
+    // Fail fast if anybody tries to post any more messsages to this isolate.
+    delete message_handler();
+    set_message_handler(NULL);
+
+    // Dump all accumalated timer data for the isolate.
+    timer_list_.ReportTimers();
+    if (FLAG_report_usage_count) {
+      PrintInvokedFunctions();
+    }
+
+    if (FLAG_print_coverage) {
+      CodeCoverage::Print(this);
+    }
+
+    // Finalize any weak persistent handles with a non-null referent.
+    FinalizeWeakPersistentHandlesVisitor visitor;
+    api_state()->weak_persistent_handles().VisitHandles(&visitor);
+
+    CompilerStats::Print();
+    // TODO(asiva): Move this code to Dart::Cleanup when we have that method
+    // as the cleanup for Dart::InitOnce.
+    CodeObservers::DeleteAll();
+    if (FLAG_trace_isolates) {
+      heap()->PrintSizes();
+      megamorphic_cache_table()->PrintSizes();
+      Symbols::DumpStats();
+      OS::Print("[-] Stopping isolate:\n"
+                "\tisolate:    %s\n", name());
+    }
   }
 
-  // Clean up debugger resources. Shutting down the debugger
-  // requires a handle zone. We must set up a temporary zone because
-  // Isolate::Shutdown is called without a zone.
-  {
-    StackZone zone(this);
-    HandleScope handle_scope(this);
-    debugger_->Shutdown();
-  }
-
-  // Close all the ports owned by this isolate.
-  PortMap::ClosePorts(message_handler());
-
-  // Fail fast if anybody tries to post any more messsages to this isolate.
-  delete message_handler();
-  set_message_handler(NULL);
-
-  // Finalize any weak persistent handles with a non-null referent.
-  FinalizeWeakPersistentHandlesVisitor visitor;
-  api_state()->weak_persistent_handles().VisitHandles(&visitor);
-
-  // Dump all accumalated timer data for the isolate.
-  timer_list_.ReportTimers();
-  if (FLAG_report_usage_count) {
-    PrintInvokedFunctions();
-  }
-  CompilerStats::Print();
-  // TODO(asiva): Move this code to Dart::Cleanup when we have that method
-  // as the cleanup for Dart::InitOnce.
-  CodeObservers::DeleteAll();
-  if (FLAG_trace_isolates) {
-    StackZone zone(this);
-    HandleScope handle_scope(this);
-    heap()->PrintSizes();
-    megamorphic_cache_table()->PrintSizes();
-    Symbols::DumpStats();
-    OS::Print("[-] Stopping isolate:\n"
-              "\tisolate:    %s\n", name());
-  }
   // TODO(5411455): For now just make sure there are no current isolates
   // as we are shutting down the isolate.
   SetCurrent(NULL);
@@ -918,7 +920,7 @@
   intptr_t frame_index = isolate->stack_frame_index_;
   if (frame_index >= stack->Length()) {
     // Frame no longer available.
-    return NULL;
+    return false;
   }
   ActivationFrame* frame = stack->FrameAt(frame_index);
   TextBuffer buffer(256);
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index ace783e..1b89e24 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -9,9 +9,7 @@
 
 namespace dart {
 
-JSONStream::JSONStream(TextBuffer* buffer) {
-  ASSERT(buffer != NULL);
-  buffer_ = buffer;
+JSONStream::JSONStream(intptr_t buf_size) : buffer_(buf_size) {
   open_objects_ = 0;
   arguments_ = NULL;
   num_arguments_ = 0;
@@ -26,7 +24,7 @@
 
 
 void JSONStream::Clear() {
-  buffer_->Clear();
+  buffer_.Clear();
   open_objects_ = 0;
 }
 
@@ -37,14 +35,14 @@
   if (property_name != NULL) {
     PrintPropertyName(property_name);
   }
-  buffer_->AddChar('{');
+  buffer_.AddChar('{');
 }
 
 
 void JSONStream::CloseObject() {
   ASSERT(open_objects_ > 0);
   open_objects_--;
-  buffer_->AddChar('}');
+  buffer_.AddChar('}');
 }
 
 
@@ -54,40 +52,40 @@
     PrintPropertyName(property_name);
   }
   open_objects_++;
-  buffer_->AddChar('[');
+  buffer_.AddChar('[');
 }
 
 
 void JSONStream::CloseArray() {
   ASSERT(open_objects_ > 0);
   open_objects_--;
-  buffer_->AddChar(']');
+  buffer_.AddChar(']');
 }
 
 
 void JSONStream::PrintValueBool(bool b) {
   PrintCommaIfNeeded();
-  buffer_->Printf("%s", b ? "true" : "false");
+  buffer_.Printf("%s", b ? "true" : "false");
 }
 
 
 void JSONStream::PrintValue(intptr_t i) {
   PrintCommaIfNeeded();
-  buffer_->Printf("%" Pd "", i);
+  buffer_.Printf("%" Pd "", i);
 }
 
 
 void JSONStream::PrintValue(double d) {
   PrintCommaIfNeeded();
-  buffer_->Printf("%f", d);
+  buffer_.Printf("%f", d);
 }
 
 
 void JSONStream::PrintValue(const char* s) {
   PrintCommaIfNeeded();
-  buffer_->AddChar('"');
-  buffer_->AddEscapedString(s);
-  buffer_->AddChar('"');
+  buffer_.AddChar('"');
+  buffer_.AddEscapedString(s);
+  buffer_.AddChar('"');
 }
 
 
@@ -103,9 +101,9 @@
   intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
   va_end(args);
   ASSERT(len == len2);
-  buffer_->AddChar('"');
-  buffer_->AddEscapedString(p);
-  buffer_->AddChar('"');
+  buffer_.AddChar('"');
+  buffer_.AddEscapedString(p);
+  buffer_.AddChar('"');
   free(p);
 }
 
@@ -151,9 +149,9 @@
   intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
   va_end(args);
   ASSERT(len == len2);
-  buffer_->AddChar('"');
-  buffer_->AddEscapedString(p);
-  buffer_->AddChar('"');
+  buffer_.AddChar('"');
+  buffer_.AddEscapedString(p);
+  buffer_.AddChar('"');
   free(p);
 }
 
@@ -182,28 +180,70 @@
 void JSONStream::PrintPropertyName(const char* name) {
   ASSERT(name != NULL);
   PrintCommaIfNeeded();
-  buffer_->AddChar('"');
-  buffer_->AddEscapedString(name);
-  buffer_->AddChar('"');
-  buffer_->AddChar(':');
+  buffer_.AddChar('"');
+  buffer_.AddEscapedString(name);
+  buffer_.AddChar('"');
+  buffer_.AddChar(':');
 }
 
 
 void JSONStream::PrintCommaIfNeeded() {
   if (NeedComma()) {
-    buffer_->AddChar(',');
+    buffer_.AddChar(',');
   }
 }
 
 
 bool JSONStream::NeedComma() {
-  const char* buffer = buffer_->buf();
-  intptr_t length = buffer_->length();
+  const char* buffer = buffer_.buf();
+  intptr_t length = buffer_.length();
   if (length == 0) {
     return false;
   }
   char ch = buffer[length-1];
-  return ch != '[' && ch != '{' && ch != ':' && ch != ',';
+  return (ch != '[') && (ch != '{') && (ch != ':') && (ch != ',');
+}
+
+
+JSONObject::JSONObject(const JSONArray* arr) : stream_(arr->stream_) {
+  stream_->OpenObject();
+}
+
+
+void JSONObject::AddPropertyF(const char* name,
+                                      const char* format, ...) const {
+  stream_->PrintPropertyName(name);
+  va_list args;
+  va_start(args, format);
+  intptr_t len = OS::VSNPrint(NULL, 0, format, args);
+  va_end(args);
+  char* p = reinterpret_cast<char*>(malloc(len+1));
+  va_start(args, format);
+  intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
+  va_end(args);
+  ASSERT(len == len2);
+  stream_->buffer_.AddChar('"');
+  stream_->buffer_.AddEscapedString(p);
+  stream_->buffer_.AddChar('"');
+  free(p);
+}
+
+
+void JSONArray::AddValueF(const char* format, ...) const {
+  stream_->PrintCommaIfNeeded();
+  va_list args;
+  va_start(args, format);
+  intptr_t len = OS::VSNPrint(NULL, 0, format, args);
+  va_end(args);
+  char* p = reinterpret_cast<char*>(malloc(len+1));
+  va_start(args, format);
+  intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
+  va_end(args);
+  ASSERT(len == len2);
+  stream_->buffer_.AddChar('"');
+  stream_->buffer_.AddEscapedString(p);
+  stream_->buffer_.AddChar('"');
+  free(p);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 79b1c69..ebbd8ae 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -6,16 +6,38 @@
 #define VM_JSON_STREAM_H_
 
 #include "platform/json.h"
+#include "vm/allocation.h"
 
 namespace dart {
 
 class Object;
+class JSONObject;
+class JSONArray;
 
 class JSONStream : ValueObject {
  public:
-  explicit JSONStream(TextBuffer* buffer);
+  explicit JSONStream(intptr_t buf_size = 256);
   ~JSONStream();
 
+  const char* ToCString() { return buffer_.buf(); }
+
+  void SetArguments(const char** arguments, intptr_t num_arguments);
+  void SetOptions(const char** option_keys, const char** option_values,
+                  intptr_t num_options);
+
+  intptr_t num_arguments() const { return num_arguments_; }
+  const char* GetArgument(intptr_t i) const {
+    return arguments_[i];
+  }
+  intptr_t num_options() const { return num_options_; }
+  const char* GetOptionKey(intptr_t i) const {
+    return option_keys_[i];
+  }
+  const char* GetOptionValue(intptr_t i) const {
+    return option_values_[i];
+  }
+
+ private:
   void Clear();
 
   void OpenObject(const char* property_name = NULL);
@@ -36,36 +58,101 @@
   void PrintProperty(const char* name, double d);
   void PrintProperty(const char* name, const char* s);
   void PrintfProperty(const char* name, const char* format, ...)
-      PRINTF_ATTRIBUTE(3, 4);
+  PRINTF_ATTRIBUTE(3, 4);
   void PrintProperty(const char* name, const Object& o, bool ref = true);
 
-  void SetArguments(const char** arguments, intptr_t num_arguments);
-  void SetOptions(const char** option_keys, const char** option_values,
-                  intptr_t num_options);
-
-  intptr_t num_arguments() const { return num_arguments_; }
-  const char* GetArgument(intptr_t i) const {
-    return arguments_[i];
-  }
-  intptr_t num_options() const { return num_options_; }
-  const char* GetOptionKey(intptr_t i) const {
-    return option_keys_[i];
-  }
-  const char* GetOptionValue(intptr_t i) const {
-    return option_values_[i];
-  }
-
- private:
   void PrintPropertyName(const char* name);
   void PrintCommaIfNeeded();
   bool NeedComma();
+
+  intptr_t nesting_level() const { return open_objects_; }
+
   intptr_t open_objects_;
-  TextBuffer* buffer_;
+  TextBuffer buffer_;
   const char** arguments_;
   intptr_t num_arguments_;
   const char** option_keys_;
   const char** option_values_;
   intptr_t num_options_;
+
+  friend class JSONObject;
+  friend class JSONArray;
+};
+
+
+class JSONObject : public ValueObject {
+ public:
+  explicit JSONObject(JSONStream* stream) : stream_(stream) {
+    stream_->OpenObject();
+  }
+  JSONObject(const JSONObject* obj, const char* name) : stream_(obj->stream_) {
+    stream_->OpenObject(name);
+  }
+  explicit JSONObject(const JSONArray* arr);
+
+  ~JSONObject() {
+    stream_->CloseObject();
+  }
+
+  void AddProperty(const char* name, bool b) const {
+    stream_->PrintPropertyBool(name, b);
+  }
+  void AddProperty(const char* name, intptr_t i) const {
+    stream_->PrintProperty(name, i);
+  }
+  void AddProperty(const char* name, double d) const {
+    stream_->PrintProperty(name, d);
+  }
+  void AddProperty(const char* name, const char* s) const {
+    stream_->PrintProperty(name, s);
+  }
+  void AddProperty(const char* name, const Object& obj, bool ref = true) const {
+    stream_->PrintProperty(name, obj, ref);
+  }
+  void AddPropertyF(const char* name, const char* format, ...) const
+      PRINTF_ATTRIBUTE(3, 4);
+
+ private:
+  JSONStream* stream_;
+
+  friend class JSONArray;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(JSONObject);
+};
+
+
+class JSONArray : public ValueObject {
+ public:
+  explicit JSONArray(JSONStream* stream) : stream_(stream) {
+    stream_->OpenArray();
+  }
+  JSONArray(const JSONObject* obj, const char* name) : stream_(obj->stream_) {
+    stream_->OpenArray(name);
+  }
+  explicit JSONArray(const JSONArray* arr) : stream_(arr->stream_) {
+    stream_->OpenArray();
+  }
+  ~JSONArray() {
+    stream_->CloseArray();
+  }
+
+  void AddValue(bool b) const { stream_->PrintValueBool(b); }
+  void AddValue(intptr_t i) const { stream_->PrintValue(i); }
+  void AddValue(double d) const { stream_->PrintValue(d); }
+  void AddValue(const char* s) const { stream_->PrintValue(s); }
+  void AddValue(const Object& obj, bool ref = true) const {
+    stream_->PrintValue(obj, ref);
+  }
+  void AddValueF(const char* format, ...) const PRINTF_ATTRIBUTE(2, 3);
+
+ private:
+  JSONStream* stream_;
+
+  friend class JSONObject;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(JSONArray);
 };
 
 }  // namespace dart
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 89a1b5b..efe7a67 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -139,143 +139,176 @@
 
 
 TEST_CASE(JSON_JSONStream_Primitives) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-
-  js.OpenObject();
-  js.CloseObject();
-
-  EXPECT_STREQ("{}", tb.buf());
-
-  js.Clear();
-  js.OpenArray();
-  js.CloseArray();
-  EXPECT_STREQ("[]", tb.buf());
-
-  js.Clear();
-  js.PrintValueBool(true);
-  EXPECT_STREQ("true", tb.buf());
-
-  js.Clear();
-  js.PrintValueBool(false);
-  EXPECT_STREQ("false", tb.buf());
-
-  js.Clear();
-  js.PrintValue(static_cast<intptr_t>(4));
-  EXPECT_STREQ("4", tb.buf());
-
-  js.Clear();
-  js.PrintValue(1.0);
-  EXPECT_STREQ("1.000000", tb.buf());
-
-  js.Clear();
-  js.PrintValue("hello");
-  EXPECT_STREQ("\"hello\"", tb.buf());
+  {
+    JSONStream js;
+    {
+      JSONObject jsobj(&js);
+    }
+    EXPECT_STREQ("{}", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+    }
+    EXPECT_STREQ("[]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValue(true);
+    }
+    EXPECT_STREQ("[true]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValue(false);
+    }
+    EXPECT_STREQ("[false]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValue(static_cast<intptr_t>(4));
+    }
+    EXPECT_STREQ("[4]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValue(1.0);
+    }
+    EXPECT_STREQ("[1.000000]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValue("hello");
+    }
+    EXPECT_STREQ("[\"hello\"]", js.ToCString());
+  }
+  {
+    JSONStream js;
+    {
+      JSONArray jsarr(&js);
+      jsarr.AddValueF("h%s", "elo");
+    }
+    EXPECT_STREQ("[\"helo\"]", js.ToCString());
+  }
 }
 
 
 TEST_CASE(JSON_JSONStream_Array) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.Clear();
-  js.OpenArray();
-  js.PrintValueBool(true);
-  js.PrintValueBool(false);
-  js.CloseArray();
-  EXPECT_STREQ("[true,false]", tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    jsarr.AddValue(true);
+    jsarr.AddValue(false);
+  }
+  EXPECT_STREQ("[true,false]", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_Object) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.Clear();
-  js.OpenObject();
-  js.PrintProperty("key1", "a");
-  js.PrintProperty("key2", "b");
-  js.CloseObject();
-  EXPECT_STREQ("{\"key1\":\"a\",\"key2\":\"b\"}", tb.buf());
+  JSONStream js;
+  {
+    JSONObject jsobj(&js);
+    jsobj.AddProperty("key1", "a");
+    jsobj.AddProperty("key2", "b");
+  }
+  EXPECT_STREQ("{\"key1\":\"a\",\"key2\":\"b\"}", js.ToCString());
 }
 
 TEST_CASE(JSON_JSONStream_NestedObject) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenObject();
-  js.OpenObject("key");
-  js.PrintProperty("key1", "d");
-  js.CloseObject();
-  js.CloseObject();
-  EXPECT_STREQ("{\"key\":{\"key1\":\"d\"}}", tb.buf());
+  JSONStream js;
+  {
+    JSONObject jsobj(&js);
+    JSONObject jsobj1(&jsobj, "key");
+    jsobj1.AddProperty("key1", "d");
+  }
+  EXPECT_STREQ("{\"key\":{\"key1\":\"d\"}}", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_ObjectArray) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenArray();
-  js.OpenObject();
-  js.PrintProperty("key", "e");
-  js.CloseObject();
-  js.OpenObject();
-  js.PrintProperty("yek", "f");
-  js.CloseObject();
-  js.CloseArray();
-  EXPECT_STREQ("[{\"key\":\"e\"},{\"yek\":\"f\"}]", tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    {
+      JSONObject jsobj(&jsarr);
+      jsobj.AddProperty("key", "e");
+    }
+    {
+      JSONObject jsobj(&jsarr);
+      jsobj.AddProperty("yek", "f");
+    }
+  }
+  EXPECT_STREQ("[{\"key\":\"e\"},{\"yek\":\"f\"}]", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_ArrayArray) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenArray();
-  js.OpenArray();
-  js.PrintValue((intptr_t)4);
-  js.CloseArray();
-  js.OpenArray();
-  js.PrintValueBool(false);
-  js.CloseArray();
-  js.CloseArray();
-  EXPECT_STREQ("[[4],[false]]", tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    {
+      JSONArray jsarr1(&jsarr);
+      jsarr1.AddValue(static_cast<intptr_t>(4));
+    }
+    {
+      JSONArray jsarr1(&jsarr);
+      jsarr1.AddValue(false);
+    }
+  }
+  EXPECT_STREQ("[[4],[false]]", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_Printf) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenArray();
-  js.PrintfValue("%d %s", 2, "hello");
-  js.CloseArray();
-  EXPECT_STREQ("[\"2 hello\"]", tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    jsarr.AddValueF("%d %s", 2, "hello");
+  }
+  EXPECT_STREQ("[\"2 hello\"]", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_ObjectPrintf) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenObject();
-  js.PrintfProperty("key", "%d %s", 2, "hello");
-  js.CloseObject();
-  EXPECT_STREQ("{\"key\":\"2 hello\"}", tb.buf());
+  JSONStream js;
+  {
+    JSONObject jsobj(&js);
+    jsobj.AddPropertyF("key", "%d %s", 2, "hello");
+  }
+  EXPECT_STREQ("{\"key\":\"2 hello\"}", js.ToCString());
 }
 
 
 TEST_CASE(JSON_JSONStream_DartObject) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.OpenArray();
-  js.PrintValue(Object::Handle(Object::null()));
-  js.OpenObject();
-  js.PrintProperty("object_key", Object::Handle(Object::null()));
-  js.CloseArray();
-  EXPECT_STREQ("[{\"type\":\"null\"},{\"object_key\":{\"type\":\"null\"}]",
-               tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    jsarr.AddValue(Object::Handle(Object::null()));
+    JSONObject jsobj(&jsarr);
+    jsobj.AddProperty("object_key", Object::Handle(Object::null()));
+  }
+  EXPECT_STREQ("[{\"type\":\"null\"},{\"object_key\":{\"type\":\"null\"}}]",
+               js.ToCString());
 }
 
 TEST_CASE(JSON_JSONStream_EscapedString) {
-  TextBuffer tb(256);
-  JSONStream js(&tb);
-  js.PrintValue("Hel\"\"lo\r\n\t");
-  EXPECT_STREQ("\"Hel\\\"\\\"lo\\r\\n\\t\"", tb.buf());
+  JSONStream js;
+  {
+    JSONArray jsarr(&js);
+    jsarr.AddValue("Hel\"\"lo\r\n\t");
+  }
+  EXPECT_STREQ("[\"Hel\\\"\\\"lo\\r\\n\\t\"]", js.ToCString());
 }
 
 
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index e463b20..4fd535f 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -163,26 +163,21 @@
     const Library& lib = Library::Cast(obj);
 
     // Case 1.  Lookup the unmodified function name.
-    String& ambiguity_error_msg = String::Handle(isolate);
-    func = lib.LookupFunctionAllowPrivate(func_name, &ambiguity_error_msg);
+    func = lib.LookupFunctionAllowPrivate(func_name);
 
     // Case 2.  Lookup the function without the external setter suffix
     // '='.  Make sure to do this check after the regular lookup, so
     // that we don't interfere with operator lookups (like ==).
-    if (func.IsNull() && ambiguity_error_msg.IsNull() &&
-        HasExternalSetterSuffix(func_name)) {
+    if (func.IsNull() && HasExternalSetterSuffix(func_name)) {
       tmp_name = RemoveExternalSetterSuffix(func_name);
       tmp_name = Field::SetterName(tmp_name);
-      func = lib.LookupFunctionAllowPrivate(tmp_name, &ambiguity_error_msg);
+      func = lib.LookupFunctionAllowPrivate(tmp_name);
     }
 
     // Case 3.  Lookup the function with the getter prefix prepended.
-    if (func.IsNull() && ambiguity_error_msg.IsNull()) {
+    if (func.IsNull()) {
       tmp_name = Field::GetterName(func_name);
-      func = lib.LookupFunctionAllowPrivate(tmp_name, &ambiguity_error_msg);
-    }
-    if (!ambiguity_error_msg.IsNull()) {
-      return Api::NewError("%s.", ambiguity_error_msg.ToCString());
+      func = lib.LookupFunctionAllowPrivate(tmp_name);
     }
   } else {
     return Api::NewError(
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 29725c7..bdfac3c 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -64,6 +64,7 @@
 DECLARE_FLAG(bool, trace_deoptimization);
 DECLARE_FLAG(bool, trace_deoptimization_verbose);
 DECLARE_FLAG(bool, verbose_stacktrace);
+DECLARE_FLAG(bool, print_coverage);
 
 static const char* kGetterPrefix = "get:";
 static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
@@ -169,8 +170,7 @@
                                     const char* function_name) {
   ASSERT(!lib.IsNull());
   const Class& cls = Class::Handle(
-      lib.LookupClassAllowPrivate(String::Handle(String::New(class_name)),
-                                  NULL));  // No ambiguity error expected.
+      lib.LookupClassAllowPrivate(String::Handle(String::New(class_name))));
   ASSERT(!cls.IsNull());
   const Function& function =
       Function::Handle(
@@ -1512,6 +1512,16 @@
 }
 
 
+RawType* Class::RareType() const {
+  const Type& type = Type::Handle(Type::New(
+      *this,
+      Object::null_abstract_type_arguments(),
+      Scanner::kDummyTokenIndex));
+  return Type::RawCast(
+      ClassFinalizer::FinalizeType(*this, type, ClassFinalizer::kCanonicalize));
+}
+
+
 template <class FakeObject>
 RawClass* Class::New() {
   ASSERT(Object::class_class() != Class::null());
@@ -2223,12 +2233,8 @@
 RawClass* Class::NewNativeWrapper(const Library& library,
                                   const String& name,
                                   int field_count) {
-  String& ambiguity_error_msg = String::Handle();
-  Class& cls = Class::Handle(library.LookupClass(name, &ambiguity_error_msg));
+  Class& cls = Class::Handle(library.LookupClass(name));
   if (cls.IsNull()) {
-    if (!ambiguity_error_msg.IsNull()) {
-      return Class::null();
-    }
     cls = New(name, Script::Handle(), Scanner::kDummyTokenIndex);
     cls.SetFields(Object::empty_array());
     cls.SetFunctions(Object::empty_array());
@@ -2923,20 +2929,13 @@
   const char* class_name = String::Handle(UserVisibleName()).ToCString();
   ObjectIdRing* ring = Isolate::Current()->object_id_ring();
   intptr_t id = ring->GetIdForObject(raw());
-  if (ref) {
-    stream->OpenObject();
-    stream->PrintProperty("type", "@Class");
-    stream->PrintProperty("id", id);
-    stream->PrintProperty("name", class_name);
-    stream->CloseObject();
-    return;
+  JSONObject jsobj(stream);
+  jsobj.AddProperty("type", JSONType(ref));
+  jsobj.AddProperty("id", id);
+  jsobj.AddProperty("name", class_name);
+  if (!ref) {
+    jsobj.AddProperty("library", Object::Handle(library()));
   }
-  stream->OpenObject();
-  stream->PrintProperty("type", "Class");
-  stream->PrintProperty("id", id);
-  stream->PrintProperty("name", class_name);
-  stream->PrintProperty("library", Object::Handle(library()));
-  stream->CloseObject();
 }
 
 
@@ -3020,8 +3019,7 @@
 
 
 void UnresolvedClass::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -3244,8 +3242,7 @@
 
 void AbstractTypeArguments::PrintToJSONStream(JSONStream* stream,
                                               bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -3585,8 +3582,7 @@
 
 
 void TypeArguments::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -3674,8 +3670,7 @@
 
 void InstantiatedTypeArguments::PrintToJSONStream(JSONStream* stream,
                                                   bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -3691,8 +3686,7 @@
 
 
 void PatchClass::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -4139,6 +4133,9 @@
 
 
 bool Function::is_optimizable() const {
+  if (FLAG_print_coverage) {
+    return false;
+  }
   if (OptimizableBit::decode(raw_ptr()->kind_tag_) &&
       (script() != Script::null()) &&
       ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
@@ -4181,10 +4178,7 @@
 
 
 bool Function::IsInlineable() const {
-  // '==' call is handled specially.
-  return InlinableBit::decode(raw_ptr()->kind_tag_) &&
-         HasCode() &&
-         name() != Symbols::EqualOperator().raw();
+  return InlinableBit::decode(raw_ptr()->kind_tag_) && HasCode();
 }
 
 
@@ -5100,22 +5094,15 @@
       String::Handle(QualifiedUserVisibleName()).ToCString();
   ObjectIdRing* ring = Isolate::Current()->object_id_ring();
   intptr_t id = ring->GetIdForObject(raw());
-  if (ref) {
-    stream->OpenObject();
-    stream->PrintProperty("type", "@Function");
-    stream->PrintProperty("id", id);
-    stream->PrintProperty("name", function_name);
-    stream->CloseObject();
-    return;
-  }
-  stream->OpenObject();
-  stream->PrintProperty("type", "Function");
-  stream->PrintProperty("name", function_name);
-  stream->PrintProperty("id", id);
-  stream->PrintPropertyBool("is_static", is_static());
-  stream->PrintPropertyBool("is_const", is_const());
-  stream->PrintPropertyBool("is_optimizable", is_optimizable());
-  stream->PrintPropertyBool("is_inlinable", IsInlineable());
+  JSONObject jsobj(stream);
+  jsobj.AddProperty("type", JSONType(ref));
+  jsobj.AddProperty("id", id);
+  jsobj.AddProperty("name", function_name);
+  if (ref) return;
+  jsobj.AddProperty("is_static", is_static());
+  jsobj.AddProperty("is_const", is_const());
+  jsobj.AddProperty("is_optimizable", is_optimizable());
+  jsobj.AddProperty("is_inlinable", IsInlineable());
   const char* kind_string = NULL;
   switch (kind()) {
       case RawFunction::kRegularFunction:
@@ -5151,15 +5138,13 @@
       default:
         UNREACHABLE();
   }
-  stream->PrintProperty("kind", kind_string);
-  stream->PrintProperty("unoptimized_code", Object::Handle(unoptimized_code()));
-  stream->PrintProperty("usage_counter", usage_counter());
-  stream->PrintProperty("optimized_call_site_count",
-                        optimized_call_site_count());
-  stream->PrintProperty("code", Object::Handle(CurrentCode()));
-  stream->PrintProperty("deoptimizations",
-                        static_cast<intptr_t>(deoptimization_counter()));
-  stream->CloseObject();
+  jsobj.AddProperty("kind", kind_string);
+  jsobj.AddProperty("unoptimized_code", Object::Handle(unoptimized_code()));
+  jsobj.AddProperty("usage_counter", usage_counter());
+  jsobj.AddProperty("optimized_call_site_count", optimized_call_site_count());
+  jsobj.AddProperty("code", Object::Handle(CurrentCode()));
+  jsobj.AddProperty("deoptimizations",
+                    static_cast<intptr_t>(deoptimization_counter()));
 }
 
 
@@ -5207,8 +5192,7 @@
 
 
 void ClosureData::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -5243,8 +5227,7 @@
 
 
 void RedirectionData::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -5365,7 +5348,12 @@
   result.set_has_initializer(false);
   result.set_guarded_cid(kIllegalCid);
   result.set_is_nullable(false);
-  result.set_guarded_list_length(Field::kUnknownFixedLength);
+  // Presently, we only attempt to remember the list length for final fields.
+  if (is_final) {
+    result.set_guarded_list_length(Field::kUnknownFixedLength);
+  } else {
+    result.set_guarded_list_length(Field::kNoFixedLength);
+  }
   result.set_dependent_code(Object::null_array());
   return result.raw();
 }
@@ -5393,6 +5381,16 @@
 }
 
 
+intptr_t Field::guarded_list_length() const {
+  return Smi::Value(raw_ptr()->guarded_list_length_);
+}
+
+
+void Field::set_guarded_list_length(intptr_t list_length) const {
+  raw_ptr()->guarded_list_length_ = Smi::New(list_length);
+}
+
+
 const char* Field::ToCString() const {
   if (IsNull()) {
     return "Field::null";
@@ -5413,8 +5411,7 @@
 
 
 void Field::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -5585,7 +5582,6 @@
     // List length unchanged.
     return;
   }
-
   // Multiple list lengths assigned here, stop tracking length.
   set_guarded_list_length(Field::kNoFixedLength);
   DeoptimizeDependentCode();
@@ -5637,8 +5633,7 @@
 
 
 void LiteralToken::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -6053,8 +6048,7 @@
 
 
 void TokenStream::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -6405,8 +6399,7 @@
 
 
 void Script::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -6724,8 +6717,9 @@
 }
 
 
-// Lookup a name in the library's export namespace.
-RawObject* Library::LookupExport(const String& name) const {
+// Lookup a name in the library's re-export namespace. The name is
+// unmangled, i.e. no getter or setter names should be looked up.
+RawObject* Library::LookupReExport(const String& name) const {
   if (HasExports()) {
     const Array& exports = Array::Handle(this->exports());
     // Break potential export cycle while looking up name.
@@ -6789,6 +6783,23 @@
   cls.set_library(*this);
 }
 
+static void AddScriptIfUnique(const GrowableObjectArray& scripts,
+                              Script& candidate) {
+  if (candidate.IsNull()) {
+    return;
+  }
+  Script& script_obj = Script::Handle();
+
+  for (int i = 0; i < scripts.Length(); i++) {
+    script_obj ^= scripts.At(i);
+    if (script_obj.raw() == candidate.raw()) {
+      // We already have a reference to this script.
+      return;
+    }
+  }
+  // Add script to the list of scripts.
+  scripts.Add(candidate);
+}
 
 RawArray* Library::LoadedScripts() const {
   // We compute the list of loaded scripts lazily. The result is
@@ -6799,13 +6810,19 @@
         GrowableObjectArray::Handle(GrowableObjectArray::New(8));
     Object& entry = Object::Handle();
     Class& cls = Class::Handle();
+    Class& patch_cls = Class::Handle();
     Script& owner_script = Script::Handle();
+    Script& patch_script = Script::Handle();
     DictionaryIterator it(*this);
-    Script& script_obj = Script::Handle();
     while (it.HasNext()) {
       entry = it.GetNext();
       if (entry.IsClass()) {
         owner_script = Class::Cast(entry).script();
+        patch_cls = Class::Cast(entry).patch_class();
+        if (!patch_cls.IsNull()) {
+          patch_script = patch_cls.script();
+          AddScriptIfUnique(scripts, patch_script);
+        }
       } else if (entry.IsFunction()) {
         owner_script = Function::Cast(entry).script();
       } else if (entry.IsField()) {
@@ -6814,22 +6831,7 @@
       } else {
         continue;
       }
-      if (owner_script.IsNull()) {
-        continue;
-      }
-      bool is_unique = true;
-      for (int i = 0; i < scripts.Length(); i++) {
-        script_obj ^= scripts.At(i);
-        if (script_obj.raw() == owner_script.raw()) {
-          // We already have a reference to this script.
-          is_unique = false;
-          break;
-        }
-      }
-      if (is_unique) {
-        // Add script to the list of scripts.
-        scripts.Add(owner_script);
-      }
+      AddScriptIfUnique(scripts, owner_script);
     }
 
     // Create the array of scripts and cache it in loaded_scripts_.
@@ -6895,10 +6897,8 @@
 }
 
 
-RawField* Library::LookupFieldAllowPrivate(const String& name,
-                                           String* ambiguity_error_msg) const {
-  Object& obj = Object::Handle(
-      LookupObjectAllowPrivate(name, ambiguity_error_msg));
+RawField* Library::LookupFieldAllowPrivate(const String& name) const {
+  Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
   if (obj.IsField()) {
     return Field::Cast(obj).raw();
   }
@@ -6915,11 +6915,8 @@
 }
 
 
-RawFunction* Library::LookupFunctionAllowPrivate(
-    const String& name,
-    String* ambiguity_error_msg) const {
-  Object& obj = Object::Handle(
-      LookupObjectAllowPrivate(name, ambiguity_error_msg));
+RawFunction* Library::LookupFunctionAllowPrivate(const String& name) const {
+  Object& obj = Object::Handle(LookupObjectAllowPrivate(name));
   if (obj.IsFunction()) {
     return Function::Cast(obj).raw();
   }
@@ -6948,9 +6945,7 @@
 }
 
 
-RawObject* Library::LookupObjectAllowPrivate(
-    const String& name,
-    String* ambiguity_error_msg) const {
+RawObject* Library::LookupObjectAllowPrivate(const String& name) const {
   // First check if name is found in the local scope of the library.
   Object& obj = Object::Handle(LookupLocalObjectAllowPrivate(name));
   if (!obj.IsNull()) {
@@ -6962,30 +6957,27 @@
     return Object::null();
   }
 
-  // Now check if name is found in any imported libs. It is a compile-time error
-  // if the name is found in more than one import and actually used.
-  return LookupImportedObject(name, ambiguity_error_msg);
+  // Now check if name is found in any imported libs.
+  return LookupImportedObject(name);
 }
 
 
-RawObject* Library::LookupObject(const String& name,
-                                 String* ambiguity_error_msg) const {
+RawObject* Library::LookupObject(const String& name) const {
   // First check if name is found in the local scope of the library.
   Object& obj = Object::Handle(LookupLocalObject(name));
   if (!obj.IsNull()) {
     return obj.raw();
   }
-  // Now check if name is found in any imported libs. It is a compile-time error
-  // if the name is found in more than one import and actually used.
-  return LookupImportedObject(name, ambiguity_error_msg);
+  // Now check if name is found in any imported libs.
+  return LookupImportedObject(name);
 }
 
 
-RawObject* Library::LookupImportedObject(const String& name,
-                                         String* ambiguity_error_msg) const {
+RawObject* Library::LookupImportedObject(const String& name) const {
   Object& obj = Object::Handle();
   Namespace& import = Namespace::Handle();
   Library& import_lib = Library::Handle();
+  String& import_lib_url = String::Handle();
   String& first_import_lib_url = String::Handle();
   Object& found_obj = Object::Handle();
   for (intptr_t i = 0; i < num_imports(); i++) {
@@ -6993,46 +6985,33 @@
     obj = import.Lookup(name);
     if (!obj.IsNull()) {
       import_lib = import.library();
-      if (!first_import_lib_url.IsNull()) {
-        // Found duplicate definition.
-        const intptr_t kMessageBufferSize = 512;
-        char message_buffer[kMessageBufferSize];
-        if (first_import_lib_url.raw() == url()) {
-          OS::SNPrint(message_buffer,
-                      kMessageBufferSize,
-                      "ambiguous reference to '%s', "
-                      "as library '%s' is imported multiple times",
-                      name.ToCString(),
-                      first_import_lib_url.ToCString());
+      import_lib_url = import_lib.url();
+      if (found_obj.raw() != obj.raw()) {
+        if (first_import_lib_url.IsNull() ||
+            first_import_lib_url.StartsWith(Symbols::DartScheme())) {
+          // This is the first object we found, or the
+          // previously found object is exported from a Dart
+          // system library. The newly found object hides the one
+          // from the Dart library.
+          first_import_lib_url = import_lib.url();
+          found_obj = obj.raw();
+        } else if (import_lib_url.StartsWith(Symbols::DartScheme())) {
+          // The newly found object is exported from a Dart system
+          // library. It is hidden by the previously found object.
+          // We continue to search.
         } else {
-          OS::SNPrint(message_buffer,
-                      kMessageBufferSize,
-                      "ambiguous reference: "
-                      "'%s' is defined in library '%s' and also in '%s'",
-                      name.ToCString(),
-                      first_import_lib_url.ToCString(),
-                      String::Handle(url()).ToCString());
+          // We found two different objects with the same name.
+          return Object::null();
         }
-        // If the caller does not expect an ambiguity error, it may pass NULL as
-        // ambiguity_error_msg in order to avoid the allocation of a handle.
-        // It typically does so when looking up an object in the core library,
-        // which is guaranteed not to contain ambiguities, unless the core lib
-        // is under development, in which case the assert below may fail.
-        ASSERT(ambiguity_error_msg != NULL);  // No ambiguity error expected.
-        *ambiguity_error_msg = String::New(message_buffer);
-        return Object::null();
       }
-      first_import_lib_url = url();
-      found_obj = obj.raw();
     }
   }
   return found_obj.raw();
 }
 
 
-RawClass* Library::LookupClass(const String& name,
-                               String* ambiguity_error_msg) const {
-  Object& obj = Object::Handle(LookupObject(name, ambiguity_error_msg));
+RawClass* Library::LookupClass(const String& name) const {
+  Object& obj = Object::Handle(LookupObject(name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -7049,13 +7028,11 @@
 }
 
 
-RawClass* Library::LookupClassAllowPrivate(const String& name,
-                                           String* ambiguity_error_msg) const {
+RawClass* Library::LookupClassAllowPrivate(const String& name) const {
   // See if the class is available in this library or in the top level
   // scope of any imported library.
   Isolate* isolate = Isolate::Current();
-  const Class& cls = Class::Handle(isolate, LookupClass(name,
-                                                        ambiguity_error_msg));
+  const Class& cls = Class::Handle(isolate, LookupClass(name));
   if (!cls.IsNull()) {
     return cls.raw();
   }
@@ -7265,6 +7242,7 @@
   Class& temp_class =
       Class::Handle(Class::New(Symbols::TopLevel(), script, 0));
   temp_class.set_library(*this);
+  temp_class.set_is_finalized();
   return temp_class.Evaluate(expr);
 }
 
@@ -7457,36 +7435,29 @@
   const char* library_url = String::Handle(url()).ToCString();
   ObjectIdRing* ring = Isolate::Current()->object_id_ring();
   intptr_t id = ring->GetIdForObject(raw());
-  if (ref) {
-    // Print a reference
-    stream->OpenObject();
-    stream->PrintProperty("type", "@Library");
-    stream->PrintProperty("id", id);
-    stream->PrintProperty("name", library_name);
-    stream->CloseObject();
-    return;
+  JSONObject jsobj(stream);
+  jsobj.AddProperty("type", JSONType(ref));
+  jsobj.AddProperty("id", id);
+  jsobj.AddProperty("name", library_name);
+  if (ref) return;
+  jsobj.AddProperty("url", library_url);
+  {
+    JSONArray jsarr(&jsobj, "classes");
+    ClassDictionaryIterator class_iter(*this);
+    Class& klass = Class::Handle();
+    while (class_iter.HasNext()) {
+      klass = class_iter.GetNextClass();
+      jsarr.AddValue(klass);
+    }
   }
-  stream->OpenObject();
-  stream->PrintProperty("type", "Library");
-  stream->PrintProperty("id", id);
-  stream->PrintProperty("name", library_name);
-  stream->PrintProperty("url", library_url);
-  ClassDictionaryIterator class_iter(*this);
-  stream->OpenArray("classes");
-  Class& klass = Class::Handle();
-  while (class_iter.HasNext()) {
-    klass = class_iter.GetNextClass();
-    stream->PrintValue(klass);
+  {
+    JSONArray jsarr(&jsobj, "libraries");
+    Library& lib = Library::Handle();
+    for (intptr_t i = 0; i < num_imports(); i++) {
+      lib = ImportLibraryAt(i);
+      jsarr.AddValue(lib);
+    }
   }
-  stream->CloseArray();
-  stream->OpenArray("libraries");
-  Library& lib = Library::Handle();
-  for (intptr_t i = 0; i < num_imports(); i++) {
-    lib = ImportLibraryAt(i);
-    stream->PrintValue(lib);
-  }
-  stream->CloseArray();
-  stream->CloseObject();
 }
 
 
@@ -7537,58 +7508,48 @@
 }
 
 
-RawClass* LibraryPrefix::LookupClass(const String& class_name,
-                                     String* ambiguity_error_msg) const {
+RawObject* LibraryPrefix::LookupObject(const String& name) const {
   Array& imports = Array::Handle(this->imports());
   Object& obj = Object::Handle();
   Namespace& import = Namespace::Handle();
   Library& import_lib = Library::Handle();
+  String& import_lib_url = String::Handle();
   String& first_import_lib_url = String::Handle();
   Object& found_obj = Object::Handle();
   for (intptr_t i = 0; i < num_imports(); i++) {
     import ^= imports.At(i);
-    obj = import.Lookup(class_name);
+    obj = import.Lookup(name);
     if (!obj.IsNull()) {
       import_lib = import.library();
-      if (!first_import_lib_url.IsNull()) {
-        // Found duplicate definition.
-        const intptr_t kMessageBufferSize = 512;
-        char message_buffer[kMessageBufferSize];
-        if (first_import_lib_url.raw() == import_lib.url()) {
-          OS::SNPrint(message_buffer,
-                      kMessageBufferSize,
-                      "ambiguous reference to '%s', "
-                      "as library '%s' is imported multiple times via "
-                      "prefix '%s'",
-                      class_name.ToCString(),
-                      first_import_lib_url.ToCString(),
-                      String::Handle(name()).ToCString());
+      import_lib_url = import_lib.url();
+      if (found_obj.raw() != obj.raw()) {
+        if (first_import_lib_url.IsNull() ||
+            first_import_lib_url.StartsWith(Symbols::DartScheme())) {
+          // This is the first object we found, or the
+          // previously found object is exported from a Dart
+          // system library. The newly found object hides the one
+          // from the Dart library.
+          first_import_lib_url = import_lib.url();
+          found_obj = obj.raw();
+        } else if (import_lib_url.StartsWith(Symbols::DartScheme())) {
+          // The newly found object is exported from a Dart system
+          // library. It is hidden by the previously found object.
+          // We continue to search.
         } else {
-          OS::SNPrint(message_buffer,
-                      kMessageBufferSize,
-                      "ambiguous reference: "
-                      "'%s' is defined in library '%s' and also in '%s', "
-                      "both imported via prefix '%s'",
-                      class_name.ToCString(),
-                      first_import_lib_url.ToCString(),
-                      String::Handle(import_lib.url()).ToCString(),
-                      String::Handle(name()).ToCString());
+          // We found two different objects with the same name.
+          return Object::null();
         }
-        // If the caller does not expect an ambiguity error, it may pass NULL as
-        // ambiguity_error_msg in order to avoid the allocation of a handle.
-        // It typically does so when looking up a class in the core library,
-        // which is guaranteed not to contain ambiguities, unless the core lib
-        // is under development, in which case the assert below may fail.
-        ASSERT(ambiguity_error_msg != NULL);  // No ambiguity error expected.
-        *ambiguity_error_msg = String::New(message_buffer);
-        return Class::null();
       }
-      first_import_lib_url = import_lib.url();
-      found_obj = obj.raw();
     }
   }
-  if (found_obj.IsClass()) {
-    return Class::Cast(found_obj).raw();
+  return found_obj.raw();
+}
+
+
+RawClass* LibraryPrefix::LookupClass(const String& class_name) const {
+  const Object& obj = Object::Handle(LookupObject(class_name));
+  if (obj.IsClass()) {
+    return Class::Cast(obj).raw();
   }
   return Class::null();
 }
@@ -7641,8 +7602,7 @@
 
 
 void LibraryPrefix::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -7657,8 +7617,7 @@
 
 
 void Namespace::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -7707,18 +7666,35 @@
 }
 
 
+// Look up object with given name in library and filter out hidden
+// names. Also look up getters and setters.
 RawObject* Namespace::Lookup(const String& name) const {
   Isolate* isolate = Isolate::Current();
   const Library& lib = Library::Handle(isolate, library());
   intptr_t ignore = 0;
+
   // Lookup the name in the library's symbols.
+  const String* filter_name = &name;
   Object& obj = Object::Handle(isolate, lib.LookupEntry(name, &ignore));
+  if (Field::IsGetterName(name)) {
+    filter_name = &String::Handle(Field::NameFromGetter(name));
+  } else if (Field::IsSetterName(name)) {
+    filter_name = &String::Handle(Field::NameFromGetter(name));
+  } else {
+    if (obj.IsNull() || obj.IsLibraryPrefix()) {
+      obj = lib.LookupEntry(String::Handle(Field::GetterName(name)), &ignore);
+      if (obj.IsNull()) {
+        obj = lib.LookupEntry(String::Handle(Field::SetterName(name)), &ignore);
+      }
+    }
+  }
+
   // Library prefixes are not exported.
   if (obj.IsNull() || obj.IsLibraryPrefix()) {
     // Lookup in the re-exported symbols.
-    obj = lib.LookupExport(name);
+    obj = lib.LookupReExport(name);
   }
-  if (obj.IsNull() || HidesName(name) || obj.IsLibraryPrefix()) {
+  if (obj.IsNull() || HidesName(*filter_name) || obj.IsLibraryPrefix()) {
     return Object::null();
   }
   return obj.raw();
@@ -7792,10 +7768,10 @@
     const Library& lib = *libs[l];
     if (strcmp(class_name, "::") == 0) {
       func_str = Symbols::New(function_name);
-      func = lib.LookupFunctionAllowPrivate(func_str, NULL);
+      func = lib.LookupFunctionAllowPrivate(func_str);
     } else {
       class_str = String::New(class_name);
-      cls = lib.LookupClassAllowPrivate(class_str, NULL);
+      cls = lib.LookupClassAllowPrivate(class_str);
       if (!cls.IsNull()) {
         func_str = String::New(function_name);
         if (function_name[0] == '.') {
@@ -7905,8 +7881,7 @@
 
 
 void Instructions::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8060,8 +8035,7 @@
 
 
 void PcDescriptors::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8216,8 +8190,7 @@
 
 
 void Stackmap::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8287,8 +8260,7 @@
 
 void LocalVarDescriptors::PrintToJSONStream(JSONStream* stream,
                                             bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8472,8 +8444,7 @@
 
 void ExceptionHandlers::PrintToJSONStream(JSONStream* stream,
                                           bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8571,8 +8542,7 @@
 
 
 void DeoptInfo::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -8967,27 +8937,23 @@
 void Code::PrintToJSONStream(JSONStream* stream, bool ref) const {
   ObjectIdRing* ring = Isolate::Current()->object_id_ring();
   intptr_t id = ring->GetIdForObject(raw());
+  JSONObject jsobj(stream);
   if (ref) {
-    stream->OpenObject();
-    stream->PrintProperty("type", "@Code");
-    stream->PrintProperty("id", id);
-    stream->CloseObject();
+    jsobj.AddProperty("type", "@Code");
+    jsobj.AddProperty("id", id);
     return;
   }
-  stream->OpenObject();
-  stream->PrintProperty("type", "Code");
-  stream->PrintProperty("id", id);
-  stream->PrintPropertyBool("is_optimized", is_optimized());
-  stream->PrintPropertyBool("is_alive", is_alive());
-  stream->PrintProperty("function", Object::Handle(function()));
-  stream->OpenArray("disassembly");
-  DisassembleToJSONStream formatter(stream);
+  jsobj.AddProperty("type", "Code");
+  jsobj.AddProperty("id", id);
+  jsobj.AddProperty("is_optimized", is_optimized());
+  jsobj.AddProperty("is_alive", is_alive());
+  jsobj.AddProperty("function", Object::Handle(function()));
+  JSONArray jsarr(&jsobj, "disassembly");
+  DisassembleToJSONStream formatter(jsarr);
   const Instructions& instr = Instructions::Handle(instructions());
   uword start = instr.EntryPoint();
   Disassembler::Disassemble(start, start + instr.size(), &formatter,
                             comments());
-  stream->CloseArray();
-  stream->CloseObject();
 }
 
 
@@ -9118,8 +9084,7 @@
 
 
 void Context::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9238,8 +9203,7 @@
 
 
 void ContextScope::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9711,8 +9675,7 @@
 
 
 void ICData::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9828,8 +9791,7 @@
 
 
 void MegamorphicCache::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9905,8 +9867,7 @@
 
 
 void SubtypeTestCache::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9924,8 +9885,7 @@
 
 
 void Error::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -9970,8 +9930,7 @@
 
 
 void ApiError::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -10016,8 +9975,7 @@
 
 
 void LanguageError::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -10091,8 +10049,7 @@
 
 void UnhandledException::PrintToJSONStream(JSONStream* stream,
                                            bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -10128,8 +10085,7 @@
 
 
 void UnwindError::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -10483,8 +10439,7 @@
 
 
 void Instance::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -10842,8 +10797,7 @@
 
 
 void AbstractType::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -11290,8 +11244,7 @@
 
 
 void Type::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -11478,8 +11431,7 @@
 
 
 void TypeParameter::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -11647,34 +11599,59 @@
 
 
 void BoundedType::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
+}
+
+
+intptr_t MixinAppType::token_pos() const {
+  return Class::Handle(MixinAppAt(0)).token_pos();
+}
+
+
+intptr_t MixinAppType::Depth() const {
+  const Array& mixin_apps = Array::Handle(mixins());
+  return mixin_apps.Length();
 }
 
 
 RawString* MixinAppType::Name() const {
-  return String::New("MixinApplication");
+  return String::New("MixinAppType");
 }
 
 
 const char* MixinAppType::ToCString() const {
-  return "MixinAppType";
+  const char* format = "MixinAppType: super type: %s; first mixin app: %s";
+  const char* super_type_cstr = String::Handle(AbstractType::Handle(
+      SuperType()).Name()).ToCString();
+  const char* first_mixin_app_cstr = String::Handle(Class::Handle(
+      MixinAppAt(0)).Name()).ToCString();
+  intptr_t len = OS::SNPrint(
+      NULL, 0, format, super_type_cstr, first_mixin_app_cstr) + 1;
+  char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+  OS::SNPrint(chars, len, format, super_type_cstr, first_mixin_app_cstr);
+  return chars;
 }
 
 
 void MixinAppType::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
-void MixinAppType::set_super_type(const AbstractType& value) const {
-  StorePointer(&raw_ptr()->super_type_, value.raw());
+RawAbstractType* MixinAppType::SuperType() const {
+  return Class::Handle(MixinAppAt(0)).super_type();
 }
 
 
-void MixinAppType::set_mixin_types(const Array& value) const {
-  StorePointer(&raw_ptr()->mixin_types_, value.raw());
+RawClass* MixinAppType::MixinAppAt(intptr_t depth) const {
+  Class& mixin_app = Class::Handle();
+  mixin_app ^= Array::Handle(mixins()).At(depth);
+  return mixin_app.raw();
+}
+
+
+void MixinAppType::set_mixins(const Array& value) const {
+  StorePointer(&raw_ptr()->mixins_, value.raw());
 }
 
 
@@ -11690,11 +11667,9 @@
 }
 
 
-RawMixinAppType* MixinAppType::New(const AbstractType& super_type,
-                                   const Array& mixin_types) {
+RawMixinAppType* MixinAppType::New(const Array& mixins) {
   const MixinAppType& result = MixinAppType::Handle(MixinAppType::New());
-  result.set_super_type(super_type);
-  result.set_mixin_types(mixin_types);
+  result.set_mixins(mixins);
   return result.raw();
 }
 
@@ -11707,8 +11682,7 @@
 
 
 void Number::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -11720,8 +11694,7 @@
 
 
 void Integer::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -12139,8 +12112,7 @@
 
 
 void Smi::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -12259,8 +12231,7 @@
 
 
 void Mint::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -12366,8 +12337,7 @@
 
 
 void Double::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -12538,8 +12508,7 @@
 
 
 void Bigint::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -13142,8 +13111,7 @@
 
 
 void String::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -13864,8 +13832,7 @@
 
 
 void Bool::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -13948,8 +13915,7 @@
 
 
 void Array::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14160,8 +14126,7 @@
 
 void GrowableObjectArray::PrintToJSONStream(JSONStream* stream,
                                             bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14266,8 +14231,7 @@
 
 
 void Float32x4::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14372,8 +14336,7 @@
 
 
 void Uint32x4::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14422,8 +14385,7 @@
 
 
 void TypedData::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14459,8 +14421,7 @@
 
 void ExternalTypedData::PrintToJSONStream(JSONStream* stream,
                                           bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14647,8 +14608,7 @@
 
 
 void Stacktrace::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14845,8 +14805,7 @@
 
 
 void JSRegExp::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
@@ -14866,8 +14825,7 @@
 
 
 void WeakProperty::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 RawAbstractType* MirrorReference::GetAbstractTypeReferent() const {
@@ -14929,8 +14887,7 @@
 
 
 void MirrorReference::PrintToJSONStream(JSONStream* stream, bool ref) const {
-  stream->OpenObject();
-  stream->CloseObject();
+  JSONObject jsobj(stream);
 }
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index dd06b66..a23c441 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -126,6 +126,9 @@
   /* with an object id is printed. If ref is false the object is fully   */    \
   /* printed.                                                            */    \
   virtual void PrintToJSONStream(JSONStream* stream, bool ref = true) const;   \
+  virtual const char* JSONType(bool ref) const {                               \
+    return ref ? "@"#object : ""#object;                                       \
+  }                                                                            \
   static const ClassId kClassId = k##object##Cid;                              \
  private:  /* NOLINT */                                                        \
   /* Initialize the handle based on the raw_ptr in the presence of null. */    \
@@ -254,16 +257,12 @@
   }
 
   virtual void PrintToJSONStream(JSONStream* stream, bool ref = true) const {
-    if (IsNull()) {
-      stream->OpenObject();
-      stream->PrintProperty("type", "null");
-      stream->CloseObject();
-      return;
-    }
-    ASSERT(!IsNull());
-    stream->OpenObject();
-    stream->PrintProperty("type", "Object");
-    stream->CloseObject();
+    JSONObject jsobj(stream);
+    jsobj.AddProperty("type", JSONType(ref));
+  }
+
+  virtual const char* JSONType(bool ref) const {
+    return IsNull() ? "null" : "Object";
   }
 
   // Returns the name that is used to identify an object in the
@@ -703,6 +702,11 @@
   // function.
   RawType* SignatureType() const;
 
+  // Return the Type with type parameters declared by this class filled in with
+  // dynamic and type parameters declared in superclasses filled in as declared
+  // in superclass clauses.
+  RawType* RareType() const;
+
   RawLibrary* library() const { return raw_ptr()->library_; }
   void set_library(const Library& value) const;
 
@@ -2013,12 +2017,8 @@
   // to have. If length is kUnknownFixedLength the length has not
   // been determined. If length is kNoFixedLength this field has multiple
   // list lengths associated with it and cannot be predicted.
-  intptr_t guarded_list_length() const {
-    return raw_ptr()->guarded_list_length_;
-  }
-  void set_guarded_list_length(intptr_t list_length) const {
-    raw_ptr()->guarded_list_length_ = list_length;
-  }
+  intptr_t guarded_list_length() const;
+  void set_guarded_list_length(intptr_t list_length) const;
   static intptr_t guarded_list_length_offset() {
     return OFFSET_OF(RawField, guarded_list_length_);
   }
@@ -2370,24 +2370,18 @@
   void AddClass(const Class& cls) const;
   void AddObject(const Object& obj, const String& name) const;
   void ReplaceObject(const Object& obj, const String& name) const;
-  RawObject* LookupExport(const String& name) const;
-  RawObject* LookupObject(const String& name,
-                          String* ambiguity_error_msg) const;
-  RawObject* LookupObjectAllowPrivate(const String& name,
-                                      String* ambiguity_error_msg) const;
+  RawObject* LookupReExport(const String& name) const;
+  RawObject* LookupObject(const String& name) const;
+  RawObject* LookupObjectAllowPrivate(const String& name) const;
   RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
   RawObject* LookupLocalObject(const String& name) const;
-  RawObject* LookupImportedObject(const String& name,
-                                  String* ambiguity_error_msg) const;
-  RawClass* LookupClass(const String& name, String* ambiguity_error_msg) const;
-  RawClass* LookupClassAllowPrivate(const String& name,
-                                    String* ambiguity_error_msg) const;
+  RawObject* LookupImportedObject(const String& name) const;
+  RawClass* LookupClass(const String& name) const;
+  RawClass* LookupClassAllowPrivate(const String& name) const;
   RawClass* LookupLocalClass(const String& name) const;
-  RawField* LookupFieldAllowPrivate(const String& name,
-                                    String* ambiguity_error_msg) const;
+  RawField* LookupFieldAllowPrivate(const String& name) const;
   RawField* LookupLocalField(const String& name) const;
-  RawFunction* LookupFunctionAllowPrivate(const String& name,
-                                          String* ambiguity_error_msg) const;
+  RawFunction* LookupFunctionAllowPrivate(const String& name) const;
   RawFunction* LookupLocalFunction(const String& name) const;
   RawLibraryPrefix* LookupLocalLibraryPrefix(const String& name) const;
   RawScript* LookupScript(const String& url) const;
@@ -2525,8 +2519,8 @@
   bool ContainsLibrary(const Library& library) const;
   RawLibrary* GetLibrary(int index) const;
   void AddImport(const Namespace& import) const;
-  RawClass* LookupClass(const String& class_name,
-                        String* ambiguity_error_msg) const;
+  RawObject* LookupObject(const String& name) const;
+  RawClass* LookupClass(const String& class_name) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawLibraryPrefix));
@@ -2548,6 +2542,8 @@
 };
 
 
+// A Namespace contains the names in a library dictionary, filtered by
+// the show/hide combinators.
 class Namespace : public Object {
  public:
   RawLibrary* library() const { return raw_ptr()->library_; }
@@ -4170,13 +4166,14 @@
 
 
 // A MixinAppType represents a mixin application clause, e.g.
-// "S<T> with M<U, N>". The class finalizer builds the type
+// "S<T> with M<U>, N<V>". The class finalizer builds the type
 // parameters and arguments at finalization time.
-// MixinType objects do not survive finalization, so they do not
+// MixinAppType objects do not survive finalization, so they do not
 // need to be written to and read from snapshots.
 class MixinAppType : public AbstractType {
  public:
-  // MixinAppType objects are replaced with their actual finalized type.
+  // A MixinAppType object is replaced at class finalization time with a
+  // finalized Type or BoundedType object.
   virtual bool IsFinalized() const { return false; }
   // TODO(regis): Handle malformed and malbounded MixinAppType.
   virtual bool IsMalformed() const { return false; }
@@ -4184,28 +4181,32 @@
   virtual bool IsResolved() const { return false; }
   virtual bool HasResolvedTypeClass() const { return false; }
   virtual RawString* Name() const;
+  virtual intptr_t token_pos() const;
 
-  virtual intptr_t token_pos() const {
-    return AbstractType::Handle(super_type()).token_pos();
-  }
+  // Returns the mixin composition depth of this mixin application type.
+  intptr_t Depth() const;
 
-  virtual RawAbstractTypeArguments* arguments() const {
-    return AbstractTypeArguments::null();
-  }
+  // Returns the declared super type of the mixin application, which is also
+  // the super type of the first synthesized class, e.g. "S&M" refers to
+  // super type "S<T>".
+  RawAbstractType* SuperType() const;
 
-  RawAbstractType* super_type() const { return raw_ptr()->super_type_; }
-  RawArray* mixin_types() const { return raw_ptr()->mixin_types_; }
+  // Returns the synthesized class representing the mixin application at
+  // the given mixin composition depth, e.g. class "S&M" at depth 0, class
+  // "S&M&N" at depth 1.
+  // Each class refers to its mixin type, e.g. "S&M" refers to mixin type "M<U>"
+  // and "S&M&N" refers to mixin type "N<V>".
+  RawClass* MixinAppAt(intptr_t depth) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawMixinAppType));
   }
 
-  static RawMixinAppType* New(const AbstractType& super_type,
-                              const Array& mixin_types);
+  static RawMixinAppType* New(const Array& mixins);
 
  private:
-  void set_super_type(const AbstractType& value) const;
-  void set_mixin_types(const Array& value) const;
+  RawArray* mixins() const { return raw_ptr()->mixins_; }
+  void set_mixins(const Array& value) const;
 
   static RawMixinAppType* New();
 
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 8158e58..82a5d8d 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3252,10 +3252,8 @@
 
 
 static RawClass* GetClass(const Library& lib, const char* name) {
-  String& ambiguity_error_msg = String::Handle();
   const Class& cls = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New(name)),
-                      &ambiguity_error_msg));
+      lib.LookupClass(String::Handle(Symbols::New(name))));
   EXPECT(!cls.IsNull());  // No ambiguity error expected.
   return cls.raw();
 }
@@ -3396,9 +3394,9 @@
   EXPECT(!lib.IsNull());
 
   const Class& class_a = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("A")), NULL));
+      lib.LookupClass(String::Handle(Symbols::New("A"))));
   const Class& class_b = Class::Handle(
-      lib.LookupClass(String::Handle(Symbols::New("B")), NULL));
+      lib.LookupClass(String::Handle(Symbols::New("B"))));
   const Function& a_test1 =
       Function::Handle(GetStaticFunction(class_a, "test1"));
   const Function& b_test1 =
diff --git a/runtime/vm/object_x64_test.cc b/runtime/vm/object_x64_test.cc
index 74c0e5c..42e872c 100644
--- a/runtime/vm/object_x64_test.cc
+++ b/runtime/vm/object_x64_test.cc
@@ -34,7 +34,9 @@
 void GenerateEmbedStringInCode(Assembler* assembler, const char* str) {
   const String& string_object =
       String::ZoneHandle(String::New(str, Heap::kOld));
-  __ LoadObject(RAX, string_object);
+  __ EnterDartFrame(0);
+  __ LoadObject(RAX, string_object, PP);
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -43,7 +45,7 @@
 // This is used to test Embedded Smi objects in the instructions.
 void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value) {
   const Smi& smi_object = Smi::ZoneHandle(Smi::New(value));
-  __ LoadObject(RAX, smi_object);
+  __ LoadObject(RAX, smi_object, PP);
   __ ret();
 }
 
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 5a6219a..2cd3f23 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -775,9 +775,9 @@
     const Script& script = Script::Handle(isolate, func.script());
     const Class& owner = Class::Handle(isolate, func.Owner());
     ASSERT(!owner.IsNull());
-    const Library& lib = Library::Handle(isolate, owner.library());
-    Parser parser(script, lib, func.token_pos());
-    parser.set_current_class(owner);
+    ParsedFunction* parsed_function = new ParsedFunction(
+        Function::ZoneHandle(func.raw()));
+    Parser parser(script, parsed_function, func.token_pos());
     parser.SkipFunctionPreamble();
     ParamList params;
     parser.ParseFormalParameterList(true, true, &params);
@@ -1700,7 +1700,7 @@
     name = String::Concat(name, String::Handle(core_lib.private_key()));
     name = Symbols::New(name);
   }
-  return core_lib.LookupClass(name, NULL);  // No ambiguity error expected.
+  return core_lib.LookupClass(name);
 }
 
 
@@ -1904,7 +1904,55 @@
       op_arguments = BuildNoSuchMethodArguments(
           operator_pos, operator_function_name, *op_arguments);
     }
-    super_op = new StaticCallNode(operator_pos, super_operator, op_arguments);
+    if (super_operator.name() == Symbols::EqualOperator().raw()) {
+      // Expand super.== call to match correct == semantics into:
+      // Let t1 = left, t2 = right {
+      //   (t1 === null  || t2 === null) ? t1 === t2
+      //                                 : static_call(super.==, t1, t2)
+      // }
+      // Normal == calls are not expanded at the AST level to produce
+      // more compact code and enable more optimization opportunities.
+      ASSERT(!is_no_such_method);  // == is always found.
+      EnsureExpressionTemp();  // Needed for ConditionalExprNode.
+      LetNode* result = new LetNode(operator_pos);
+      AstNode* left =
+          new LoadLocalNode(operator_pos,
+                            result->AddInitializer(op_arguments->NodeAt(0)));
+      AstNode* right =
+          new LoadLocalNode(operator_pos,
+                            result->AddInitializer(op_arguments->NodeAt(1)));
+      LiteralNode* null_operand =
+          new LiteralNode(operator_pos, Instance::ZoneHandle());
+      ComparisonNode* is_left_null = new ComparisonNode(operator_pos,
+                                                        Token::kEQ_STRICT,
+                                                        left,
+                                                        null_operand);
+      ComparisonNode* is_right_null = new ComparisonNode(operator_pos,
+                                                         Token::kEQ_STRICT,
+                                                         right,
+                                                         null_operand);
+      BinaryOpNode* null_check = new BinaryOpNode(operator_pos,
+                                                  Token::kOR,
+                                                  is_left_null,
+                                                  is_right_null);
+      ArgumentListNode* new_arguments = new ArgumentListNode(operator_pos);
+      new_arguments->Add(left);
+      new_arguments->Add(right);
+      StaticCallNode* call = new StaticCallNode(operator_pos,
+                                                super_operator,
+                                                new_arguments);
+      ComparisonNode* strict_eq = new ComparisonNode(operator_pos,
+                                                     Token::kEQ_STRICT,
+                                                     left,
+                                                     right);
+      result->AddNode(new ConditionalExprNode(operator_pos,
+                                              null_check,
+                                              strict_eq,
+                                              call));
+      super_op = result;
+    } else {
+      super_op = new StaticCallNode(operator_pos, super_operator, op_arguments);
+    }
     if (negate_result) {
       super_op = new UnaryOpNode(operator_pos, Token::kNOT, super_op);
     }
@@ -3569,6 +3617,13 @@
   }
 
   ASSERT(member.name != NULL);
+  if (member.kind != RawFunction::kConstructor) {
+    if (member.name->Equals(members->class_name())) {
+      ErrorMsg(member.name_pos,
+               "class member must not have the same name as its class");
+    }
+  }
+
   if (CurrentToken() == Token::kLPAREN || member.IsGetter()) {
     // Constructor or method.
     if (member.type == NULL) {
@@ -4306,18 +4361,16 @@
 RawAbstractType* Parser::ParseMixins(const AbstractType& super_type) {
   TRACE_PARSER("ParseMixins");
   ASSERT(CurrentToken() == Token::kWITH);
+  ASSERT(super_type.IsType());  // TODO(regis): Could be a BoundedType.
+  AbstractType& mixin_super_type = AbstractType::Handle(super_type.raw());
 
   const GrowableObjectArray& mixin_apps =
       GrowableObjectArray::Handle(GrowableObjectArray::New());
   AbstractType& mixin_type = AbstractType::Handle();
-  AbstractTypeArguments& mixin_type_arguments =
-      AbstractTypeArguments::Handle();
-  Class& mixin_application = Class::Handle();
-  Type& mixin_application_type = Type::Handle();
-  Type& mixin_super_type = Type::Handle();
-  ASSERT(super_type.IsType());
-  mixin_super_type ^= super_type.raw();
-  Array& mixin_application_interfaces = Array::Handle();
+  Class& mixin_app_class = Class::Handle();
+  Array& mixin_app_interfaces = Array::Handle();
+  String& mixin_app_class_name = String::Handle();
+  String& mixin_type_class_name = String::Handle();
   do {
     ConsumeToken();
     const intptr_t mixin_pos = TokenPos();
@@ -4329,42 +4382,38 @@
     }
 
     // The name of the mixin application class is a combination of
-    // the superclass and mixin class.
-    String& mixin_app_name = String::Handle();
-    mixin_app_name = mixin_super_type.ClassName();
-    mixin_app_name = String::Concat(mixin_app_name, Symbols::Ampersand());
-    mixin_app_name = String::Concat(mixin_app_name,
-                                    String::Handle(mixin_type.ClassName()));
-    mixin_app_name = Symbols::New(mixin_app_name);
+    // the super class name and mixin class name.
+    mixin_app_class_name = mixin_super_type.ClassName();
+    mixin_app_class_name = String::Concat(mixin_app_class_name,
+                                          Symbols::Ampersand());
+    mixin_type_class_name = mixin_type.ClassName();
+    mixin_app_class_name = String::Concat(mixin_app_class_name,
+                                          mixin_type_class_name);
+    mixin_app_class_name = Symbols::New(mixin_app_class_name);
 
-    mixin_application = Class::New(mixin_app_name, script_, mixin_pos);
-    mixin_application.set_super_type(mixin_super_type);
-    mixin_application.set_mixin(Type::Cast(mixin_type));
-    mixin_application.set_library(library_);
-    mixin_application.set_is_synthesized_class();
+    mixin_app_class = Class::New(mixin_app_class_name, script_, mixin_pos);
+    mixin_app_class.set_super_type(mixin_super_type);
+    mixin_app_class.set_mixin(Type::Cast(mixin_type));
+    mixin_app_class.set_library(library_);
+    mixin_app_class.set_is_synthesized_class();
 
     // Add the mixin type to the interfaces that the mixin application
     // class implements. This is necessary so that type tests work.
-    mixin_application_interfaces = Array::New(1);
-    mixin_application_interfaces.SetAt(0, mixin_type);
-    mixin_application.set_interfaces(mixin_application_interfaces);
+    mixin_app_interfaces = Array::New(1);
+    mixin_app_interfaces.SetAt(0, mixin_type);
+    mixin_app_class.set_interfaces(mixin_app_interfaces);
 
-    // For the type arguments of the mixin application type, we need
-    // a copy of the type arguments to the mixin type. The simplest way
-    // to get the copy is to rewind the parser, parse the mixin type
-    // again and steal its type arguments.
-    SetPosition(mixin_pos);
-    mixin_type = ParseType(ClassFinalizer::kResolveTypeParameters);
-    mixin_type_arguments = mixin_type.arguments();
+    // Add the synthesized class to the list of mixin apps.
+    mixin_apps.Add(mixin_app_class);
 
-    mixin_application_type = Type::New(mixin_application,
-                                       mixin_type_arguments,
-                                       mixin_pos);
-    mixin_super_type = mixin_application_type.raw();
-    mixin_apps.Add(mixin_application_type);
+    // This mixin application class becomes the type class of the super type of
+    // the next mixin application class. It is however too early to provide the
+    // correct super type arguments. We use the raw type for now.
+    mixin_super_type = Type::New(mixin_app_class,
+                                 Object::null_abstract_type_arguments(),
+                                 mixin_pos);
   } while (CurrentToken() == Token::kCOMMA);
-  return MixinAppType::New(super_type,
-                           Array::Handle(Array::MakeArray(mixin_apps)));
+  return MixinAppType::New(Array::Handle(Array::MakeArray(mixin_apps)));
 }
 
 
@@ -4759,7 +4808,7 @@
   }
   ConsumeToken();
   String& prefix = String::Handle();
-  if (is_import && IsLiteral("as")) {
+  if (is_import && (CurrentToken() == Token::kAS)) {
     ConsumeToken();
     prefix = ExpectIdentifier("prefix identifier expected")->raw();
   }
@@ -7291,9 +7340,6 @@
       (left_operand->AsPrimaryNode()->IsSuper())) {
     ErrorMsg(left_operand->token_pos(), "illegal use of 'super'");
   }
-  if (IsLiteral("as")) {  // Not a reserved word.
-    token_kind_ = Token::kAS;
-  }
   int current_preced = Token::Precedence(CurrentToken());
   while (current_preced >= min_preced) {
     while (Token::Precedence(CurrentToken()) == current_preced) {
@@ -7552,7 +7598,7 @@
   if (result == NULL) {
     String& name = String::ZoneHandle();
     if (original->IsTypeNode()) {
-      name = Symbols::New(original->Name());
+      name = Symbols::New(original->AsTypeNode()->TypeName());
     } else if ((left_ident != NULL) &&
                (original->IsLiteralNode() ||
                 original->IsLoadLocalNode() ||
@@ -8226,8 +8272,10 @@
             selector = ParseInstanceCall(receiver, name);
           }
         } else if (primary->primary().IsTypeParameter()) {
+          // TODO(regis): Issue 13134.  Make sure the error message is the
+          // one we want here and add a test covering this code.
           const String& name = String::ZoneHandle(
-              Symbols::New(primary->Name()));
+              TypeParameter::Cast(primary->primary()).name());
           selector = ThrowNoSuchMethodError(primary->token_pos(),
                                             current_class(),
                                             name,
@@ -8402,52 +8450,15 @@
       // to resolve it too early to an imported class of the same name.
       if (finalization > ClassFinalizer::kResolveTypeParameters) {
         // Resolve classname in the scope of the current library.
-        Error& error = Error::Handle();
         resolved_type_class = ResolveClassInCurrentLibraryScope(
-            unresolved_class.token_pos(),
-            unresolved_class_name,
-            &error);
-        if (!error.IsNull()) {
-          if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
-              FLAG_error_on_bad_type) {
-            *type = ClassFinalizer::NewFinalizedMalformedType(
-                error,
-                scope_class,
-                unresolved_class.token_pos(),
-                "cannot resolve class '%s'",
-                unresolved_class_name.ToCString());
-          } else {
-            // Map the malformed type to dynamic and ignore type arguments.
-            *type = Type::DynamicType();
-          }
-          return;
-        }
+            unresolved_class_name);
       }
     } else {
       LibraryPrefix& lib_prefix =
           LibraryPrefix::Handle(unresolved_class.library_prefix());
       // Resolve class name in the scope of the library prefix.
-      Error& error = Error::Handle();
-      resolved_type_class = ResolveClassInPrefixScope(
-          unresolved_class.token_pos(),
-          lib_prefix,
-          unresolved_class_name,
-          &error);
-      if (!error.IsNull()) {
-        if ((finalization == ClassFinalizer::kCanonicalizeWellFormed) ||
-            FLAG_error_on_bad_type) {
-          *type = ClassFinalizer::NewFinalizedMalformedType(
-              error,
-              scope_class,
-              unresolved_class.token_pos(),
-              "cannot resolve class '%s'",
-              unresolved_class_name.ToCString());
-        } else {
-          // Map the malformed type to dynamic and ignore type arguments.
-          *type = Type::DynamicType();
-        }
-        return;
-      }
+      resolved_type_class =
+          ResolveClassInPrefixScope(lib_prefix, unresolved_class_name);
     }
     // At this point, we can only have a parameterized_type.
     const Type& parameterized_type = Type::Cast(*type);
@@ -8835,98 +8846,24 @@
 }
 
 
-static RawObject* LookupNameInImport(Isolate* isolate,
-                                     const Namespace& ns,
-                                     const String& name) {
-  // If the given name is filtered out by the import, don't look it up, nor its
-  // getter and setter names.
-  if (ns.HidesName(name)) {
-    return Object::null();
-  }
-  Object& obj = Object::Handle(isolate);
-  obj = ns.Lookup(name);
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  String& accessor_name = String::Handle(isolate, Field::GetterName(name));
-  obj = ns.Lookup(accessor_name);
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  accessor_name = Field::SetterName(name);
-  obj = ns.Lookup(accessor_name);
-  return obj.raw();
-}
-
-
 // Resolve a name by checking the global scope of the current
 // library. If not found in the current library, then look in the scopes
 // of all libraries that are imported without a library prefix.
-// Issue an error if the name is not found in the global scope
-// of the current library, but is defined in more than one imported
-// library, i.e. if the name cannot be resolved unambiguously.
-RawObject* Parser::ResolveNameInCurrentLibraryScope(intptr_t ident_pos,
-                                                    const String& name,
-                                                    Error* error) {
+RawObject* Parser::ResolveNameInCurrentLibraryScope(const String& name) {
   TRACE_PARSER("ResolveNameInCurrentLibraryScope");
   HANDLESCOPE(isolate());
   Object& obj = Object::Handle(isolate(),
                                LookupNameInLibrary(isolate(), library_, name));
-  if (obj.IsNull()) {
-    // Name is not found in current library. Check scope of all
-    // imported libraries.
-    String& first_lib_url = String::Handle(isolate());
-    Namespace& import = Namespace::Handle(isolate());
-    intptr_t num_imports = library_.num_imports();
-    Object& imported_obj = Object::Handle(isolate());
-    Library& lib = Library::Handle(isolate());
-    for (int i = 0; i < num_imports; i++) {
-      import = library_.ImportAt(i);
-      imported_obj = LookupNameInImport(isolate(), import, name);
-      if (!imported_obj.IsNull()) {
-        lib ^= import.library();
-        if (!first_lib_url.IsNull()) {
-          // Found duplicate definition.
-          Error& ambiguous_ref_error = Error::Handle();
-          if (first_lib_url.raw() == lib.url()) {
-            ambiguous_ref_error = FormatErrorMsg(
-                script_, ident_pos, "Error",
-                "ambiguous reference to '%s', "
-                "as library '%s' is imported multiple times",
-                name.ToCString(),
-                first_lib_url.ToCString());
-          } else {
-            ambiguous_ref_error = FormatErrorMsg(
-                script_, ident_pos, "Error",
-                "ambiguous reference: "
-                "'%s' is defined in library '%s' and also in '%s'",
-                name.ToCString(),
-                first_lib_url.ToCString(),
-                String::Handle(lib.url()).ToCString());
-          }
-          if (error == NULL) {
-            // Report a compile time error since the caller is not interested
-            // in the error.
-            ErrorMsg(ambiguous_ref_error);
-          }
-          *error = ambiguous_ref_error.raw();
-          return Object::null();
-        } else {
-          first_lib_url = lib.url();
-          obj = imported_obj.raw();
-        }
-      }
-    }
+  if (!obj.IsNull()) {
+    return obj.raw();
   }
-  return obj.raw();
+  return library_.LookupImportedObject(name);
 }
 
 
-RawClass* Parser::ResolveClassInCurrentLibraryScope(intptr_t ident_pos,
-                                                    const String& name,
-                                                    Error* error) {
+RawClass* Parser::ResolveClassInCurrentLibraryScope(const String& name) {
   const Object& obj =
-      Object::Handle(ResolveNameInCurrentLibraryScope(ident_pos, name, error));
+      Object::Handle(ResolveNameInCurrentLibraryScope(name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -8937,14 +8874,11 @@
 // Resolve an identifier by checking the global scope of the current
 // library. If not found in the current library, then look in the scopes
 // of all libraries that are imported without a library prefix.
-// Issue an error if the identifier is not found in the global scope
-// of the current library, but is defined in more than one imported
-// library, i.e. if the identifier cannot be resolved unambiguously.
 AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
                                                    const String& ident) {
   TRACE_PARSER("ResolveIdentInCurrentLibraryScope");
   const Object& obj =
-    Object::Handle(ResolveNameInCurrentLibraryScope(ident_pos, ident, NULL));
+    Object::Handle(ResolveNameInCurrentLibraryScope(ident));
   if (obj.IsClass()) {
     const Class& cls = Class::Cast(obj);
     return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw()));
@@ -8973,64 +8907,17 @@
 }
 
 
-RawObject* Parser::ResolveNameInPrefixScope(intptr_t ident_pos,
-                                            const LibraryPrefix& prefix,
-                                            const String& name,
-                                            Error* error) {
-  TRACE_PARSER("ResolveNameInPrefixScope");
+RawObject* Parser::ResolveNameInPrefixScope(const LibraryPrefix& prefix,
+                                            const String& name) {
   HANDLESCOPE(isolate());
-  Namespace& import = Namespace::Handle(isolate());
-  String& first_lib_url = String::Handle(isolate());
-  Object& obj = Object::Handle(isolate());
-  Object& resolved_obj = Object::Handle(isolate());
-  const Array& imports = Array::Handle(isolate(), prefix.imports());
-  Library& lib = Library::Handle(isolate());
-  for (intptr_t i = 0; i < prefix.num_imports(); i++) {
-    import ^= imports.At(i);
-    resolved_obj = LookupNameInImport(isolate(), import, name);
-    if (!resolved_obj.IsNull()) {
-      obj = resolved_obj.raw();
-      lib = import.library();
-      if (first_lib_url.IsNull()) {
-        first_lib_url = lib.url();
-      } else {
-        // Found duplicate definition.
-        Error& ambiguous_ref_error = Error::Handle();
-        if (first_lib_url.raw() == lib.url()) {
-          ambiguous_ref_error = FormatErrorMsg(
-              script_, ident_pos, "Error",
-              "ambiguous reference: '%s.%s' is imported multiple times",
-              String::Handle(prefix.name()).ToCString(),
-              name.ToCString());
-        } else {
-          ambiguous_ref_error = FormatErrorMsg(
-              script_, ident_pos, "Error",
-              "ambiguous reference: '%s.%s' is defined in '%s' and '%s'",
-              String::Handle(prefix.name()).ToCString(),
-              name.ToCString(),
-              first_lib_url.ToCString(),
-              String::Handle(lib.url()).ToCString());
-        }
-        if (error == NULL) {
-          // Report a compile time error since the caller is not interested
-          // in the error.
-          ErrorMsg(ambiguous_ref_error);
-        }
-        *error = ambiguous_ref_error.raw();
-        return Object::null();
-      }
-    }
-  }
-  return obj.raw();
+  return prefix.LookupObject(name);
 }
 
 
-RawClass* Parser::ResolveClassInPrefixScope(intptr_t ident_pos,
-                                            const LibraryPrefix& prefix,
-                                            const String& name,
-                                            Error* error) {
+RawClass* Parser::ResolveClassInPrefixScope(const LibraryPrefix& prefix,
+                                            const String& name) {
   const Object& obj =
-      Object::Handle(ResolveNameInPrefixScope(ident_pos, prefix, name, error));
+      Object::Handle(ResolveNameInPrefixScope(prefix, name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -9040,21 +8927,20 @@
 
 // Do a lookup for the identifier in the scope of the specified
 // library prefix. This means trying to resolve it locally in all of the
-// libraries present in the library prefix. If there are multiple libraries
-// with the name, issue an ambiguous reference error.
+// libraries present in the library prefix.
 AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
                                            const LibraryPrefix& prefix,
                                            const String& ident) {
   TRACE_PARSER("ResolveIdentInPrefixScope");
-  Object& obj =
-      Object::Handle(ResolveNameInPrefixScope(ident_pos, prefix, ident, NULL));
+  Object& obj = Object::Handle(ResolveNameInPrefixScope(prefix, ident));
   if (obj.IsNull()) {
     // Unresolved prefixed primary identifier.
-    ErrorMsg(ident_pos, "identifier '%s.%s' cannot be resolved",
-             String::Handle(prefix.name()).ToCString(),
-             ident.ToCString());
-  }
-  if (obj.IsClass()) {
+    String& qualified_name = String::ZoneHandle(prefix.name());
+    qualified_name = String::Concat(qualified_name, Symbols::Dot());
+    qualified_name = String::Concat(qualified_name, ident);
+    qualified_name = Symbols::New(qualified_name);
+    return new PrimaryNode(ident_pos, qualified_name);
+  } else if (obj.IsClass()) {
     const Class& cls = Class::Cast(obj);
     return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw()));
   } else if (obj.IsField()) {
@@ -9074,21 +8960,18 @@
     } else {
       return new PrimaryNode(ident_pos, Function::ZoneHandle(func.raw()));
     }
-  } else {
-    // TODO(hausner): Should this be an error? It is not meaningful to
-    // reference a library prefix defined in an imported library.
-    ASSERT(obj.IsLibraryPrefix());
   }
-  // Lexically unresolved primary identifiers are referenced by their name.
-  return new PrimaryNode(ident_pos, ident);
+  // All possible object types are handled above.
+  UNREACHABLE();
+  return NULL;
 }
 
 
 // Resolve identifier. Issue an error message if
 // the ident refers to a method and allow_closure_names is false.
 // If the name cannot be resolved, turn it into an instance field access
-// if we're compiling an instance method, or issue an error message
-// if we're compiling a static method.
+// if we're compiling an instance method, or generate
+// throw NoSuchMethodError if we're compiling a static method.
 AstNode* Parser::ResolveIdent(intptr_t ident_pos,
                               const String& ident,
                               bool allow_closure_names) {
@@ -10074,6 +9957,34 @@
       primary = ResolveIdentInPrefixScope(qual_ident.ident_pos,
                                           *qual_ident.lib_prefix,
                                           *qual_ident.ident);
+      // If the identifier could not be resolved, throw a NoSuchMethodError.
+      // Note: unlike in the case of an unqualified identifier, do not
+      // interpret the unresolved identifier as an instance method or
+      // instance getter call when compiling an instance method.
+      // TODO(hausner): Ideally we should generate the NoSuchMethodError
+      // later, when we know more about how the unresolved name is used.
+      // For example, we don't know yet whether the unresolved name
+      // refers to a getter or a setter. However, it is more awkward
+      // to distinuish four NoSuchMethodError cases all over the place
+      // in the parser. The four cases are: prefixed vs non-prefixed
+      // name, static vs dynamic context in which the unresolved name
+      // is used. We cheat a little here by looking at the next token
+      // to determine whether we have an unresolved method call or
+      // field access.
+      if (primary->IsPrimaryNode() &&
+          primary->AsPrimaryNode()->primary().IsString()) {
+        InvocationMirror::Type call_type =
+            CurrentToken() == Token::kLPAREN ?
+               InvocationMirror::kMethod : InvocationMirror::kGetter;
+        const String& unresolved_name =
+            String::Cast(primary->AsPrimaryNode()->primary());
+        primary = ThrowNoSuchMethodError(primary->token_pos(),
+                                        current_class(),
+                                        unresolved_name,
+                                        NULL,  // No arguments.
+                                        InvocationMirror::kTopLevel,
+                                        call_type);
+      }
     }
     ASSERT(primary != NULL);
   } else if (CurrentToken() == Token::kTHIS) {
@@ -10449,18 +10360,18 @@
   const int min_prec = Token::Precedence(Token::kOR);
   const int max_prec = Token::Precedence(Token::kMUL);
   while (((min_prec <= Token::Precedence(CurrentToken())) &&
-      (Token::Precedence(CurrentToken()) <= max_prec)) ||
-      IsLiteral("as")) {
-    Token::Kind last_token = IsLiteral("as") ? Token::kAS : CurrentToken();
-    ConsumeToken();
-    if (last_token == Token::kIS) {
+      (Token::Precedence(CurrentToken()) <= max_prec))) {
+    if (CurrentToken() == Token::kIS) {
+      ConsumeToken();
       if (CurrentToken() == Token::kNOT) {
         ConsumeToken();
       }
       SkipType(false);
-    } else if (last_token == Token::kAS) {
+    } else if (CurrentToken() == Token::kAS) {
+      ConsumeToken();
       SkipType(false);
     } else {
+      ConsumeToken();
       SkipUnaryExpr();
     }
   }
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 832cd99..b286b69 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -598,23 +598,15 @@
                                      const String& ident);
 
   // Find class with the given name in the library or prefix scope.
-  RawClass* ResolveClassInCurrentLibraryScope(intptr_t ident_pos,
-                                              const String& name,
-                                              Error* error);
-  RawClass* ResolveClassInPrefixScope(intptr_t ident_pos,
-                                      const LibraryPrefix& prefix,
-                                      const String& name,
-                                      Error* error);
+  RawClass* ResolveClassInCurrentLibraryScope(const String& name);
+  RawClass* ResolveClassInPrefixScope(const LibraryPrefix& prefix,
+                                      const String& name);
 
   // Find name in the library or prefix scope and return the corresponding
   // object (field, class, function etc).
-  RawObject* ResolveNameInCurrentLibraryScope(intptr_t ident_pos,
-                                              const String& ident,
-                                              Error* error);
-  RawObject* ResolveNameInPrefixScope(intptr_t ident_pos,
-                                      const LibraryPrefix& prefix,
-                                      const String& name,
-                                      Error* error);
+  RawObject* ResolveNameInCurrentLibraryScope(const String& ident);
+  RawObject* ResolveNameInPrefixScope(const LibraryPrefix& prefix,
+                                      const String& name);
 
   AstNode* ResolveIdent(intptr_t ident_pos,
                         const String& ident,
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index b8e9412..2e4c4b7 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -16,9 +16,8 @@
 
 void DumpFunction(const Library& lib, const char* cname, const char* fname) {
   const String& classname = String::Handle(Symbols::New(cname));
-  String& ambiguity_error_msg = String::Handle();
-  Class& cls = Class::Handle(lib.LookupClass(classname, &ambiguity_error_msg));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  Class& cls = Class::Handle(lib.LookupClass(classname));
+  EXPECT(!cls.IsNull());
 
   String& funcname = String::Handle(String::New(fname));
   Function& function = Function::ZoneHandle(cls.LookupStaticFunction(funcname));
@@ -51,9 +50,8 @@
                 bool expect_static,
                 bool is_final) {
   const String& classname = String::Handle(Symbols::New(class_name));
-  String& ambiguity_error_msg = String::Handle();
-  Class& cls = Class::Handle(lib.LookupClass(classname, &ambiguity_error_msg));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  Class& cls = Class::Handle(lib.LookupClass(classname));
+  EXPECT(!cls.IsNull());
 
   String& fieldname = String::Handle(String::New(field_name));
   String& functionname = String::Handle();
@@ -87,9 +85,8 @@
                    const char* function_name,
                    bool expect_static) {
   const String& classname = String::Handle(Symbols::New(class_name));
-  String& ambiguity_error_msg = String::Handle();
-  Class& cls = Class::Handle(lib.LookupClass(classname, &ambiguity_error_msg));
-  EXPECT(!cls.IsNull());  // No ambiguity error expected.
+  Class& cls = Class::Handle(lib.LookupClass(classname));
+  EXPECT(!cls.IsNull());
 
   String& functionname = String::Handle(String::New(function_name));
   Function& function = Function::Handle();
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 8bbd4b2..32f5d83 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -680,15 +680,15 @@
   RawAbstractType* type_;
   RawInstance* value_;  // Offset in words for instance and value for static.
   RawArray* dependent_code_;
+  RawSmi* guarded_list_length_;
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->dependent_code_);
+    return reinterpret_cast<RawObject**>(&ptr()->guarded_list_length_);
   }
 
   intptr_t token_pos_;
   intptr_t guarded_cid_;
   intptr_t is_nullable_;  // kNullCid if field can contain null value and
                           // any other value otherwise.
-  intptr_t guarded_list_length_;
   uint8_t kind_bits_;  // static, final, const, has initializer.
 };
 
@@ -1201,12 +1201,11 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(MixinAppType);
 
   RawObject** from() {
-    return reinterpret_cast<RawObject**>(&ptr()->super_type_);
+    return reinterpret_cast<RawObject**>(&ptr()->mixins_);
   }
-  RawAbstractType* super_type_;
-  RawArray* mixin_types_;
+  RawArray* mixins_;  // Array of synthesized mixin application classes.
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->mixin_types_);
+    return reinterpret_cast<RawObject**>(&ptr()->mixins_);
   }
 };
 
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index bf7f27e..21cb797 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -821,7 +821,6 @@
   field.set_token_pos(reader->ReadIntptrValue());
   field.set_guarded_cid(reader->ReadIntptrValue());
   field.set_is_nullable(reader->ReadIntptrValue());
-  field.set_guarded_list_length(reader->ReadIntptrValue());
   field.set_kind_bits(reader->Read<uint8_t>());
 
   // Set all the object fields.
@@ -855,7 +854,6 @@
   writer->WriteIntptrValue(ptr()->token_pos_);
   writer->WriteIntptrValue(ptr()->guarded_cid_);
   writer->WriteIntptrValue(ptr()->is_nullable_);
-  writer->WriteIntptrValue(ptr()->guarded_list_length_);
   writer->Write<uint8_t>(ptr()->kind_bits_);
 
   // Write out all the object pointer fields.
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 1150b81..4021d71 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -143,14 +143,12 @@
                                      const String& function_name,
                                      intptr_t num_arguments,
                                      const Array& argument_names,
-                                     StaticResolveType resolve_type,
-                                     String* ambiguity_error_msg) {
+                                     StaticResolveType resolve_type) {
   ASSERT(!library.IsNull());
   Function& function = Function::Handle();
   if (class_name.IsNull() || (class_name.Length() == 0)) {
     // Check if we are referring to a top level function.
-    const Object& object = Object::Handle(
-        library.LookupObject(function_name, ambiguity_error_msg));
+    const Object& object = Object::Handle(library.LookupObject(function_name));
     if (!object.IsNull() && object.IsFunction()) {
       function ^= object.raw();
       if (!function.AreValidArguments(num_arguments, argument_names, NULL)) {
@@ -168,18 +166,15 @@
       }
     } else {
       if (FLAG_trace_resolving) {
-        OS::Print("ResolveStatic error '%s': %s.\n",
-                  function_name.ToCString(),
-                  ambiguity_error_msg->IsNull() ? "top level function not found"
-                      : ambiguity_error_msg->ToCString());
+        OS::Print("ResolveStatic error: function '%s' not found.\n",
+                  function_name.ToCString());
       }
     }
   } else {
     // Lookup class_name in the library's class dictionary to get at
     // the dart class object. If class_name is not found in the dictionary
     // ResolveStatic will return a NULL function object.
-    const Class& cls = Class::Handle(
-        library.LookupClass(class_name, ambiguity_error_msg));
+    const Class& cls = Class::Handle(library.LookupClass(class_name));
     if (!cls.IsNull()) {
       function = ResolveStatic(cls,
                                function_name,
@@ -188,11 +183,9 @@
                                resolve_type);
     }
     if (FLAG_trace_resolving && function.IsNull()) {
-      OS::Print("ResolveStatic error '%s.%s': %s.\n",
+      OS::Print("ResolveStatic error: function '%s.%s' not found.\n",
                 class_name.ToCString(),
-                function_name.ToCString(),
-                ambiguity_error_msg->IsNull() ? "static function not found"
-                    : ambiguity_error_msg->ToCString());
+                function_name.ToCString());
     }
   }
   return function.raw();
diff --git a/runtime/vm/resolver.h b/runtime/vm/resolver.h
index df8158a..a0f2b33 100644
--- a/runtime/vm/resolver.h
+++ b/runtime/vm/resolver.h
@@ -53,8 +53,7 @@
                                     const String& function_name,
                                     intptr_t num_arguments,
                                     const Array& argument_names,
-                                    StaticResolveType resolve_type,
-                                    String* ambiguity_error_msg);
+                                    StaticResolveType resolve_type);
 
   // Resolve specified dart static function.
   static RawFunction* ResolveStaticByName(const Class&  cls,
diff --git a/runtime/vm/resolver_test.cc b/runtime/vm/resolver_test.cc
index 83017a4..6ede57c 100644
--- a/runtime/vm/resolver_test.cc
+++ b/runtime/vm/resolver_test.cc
@@ -92,7 +92,6 @@
   const String& class_name = String::Handle(String::New(test_class_name));
   const String& static_function_name =
       String::Handle(String::New(test_static_function_name));
-  String& ambiguity_error_msg = String::Handle();
 
   // Now try to resolve and invoke the static function in this class.
   {
@@ -103,8 +102,7 @@
                                 static_function_name,
                                 kNumArguments,
                                 Object::empty_array(),
-                                kResolveType,
-                                &ambiguity_error_msg));
+                                kResolveType));
     EXPECT(!function.IsNull());  // No ambiguity error expected.
     const Array& args = Array::Handle(Array::New(kNumArguments));
     const String& arg0 = String::Handle(String::New("junk"));
@@ -125,8 +123,7 @@
                                 static_function_name,
                                 kNumArguments,
                                 Object::empty_array(),
-                                kResolveType,
-                                &ambiguity_error_msg));
+                                kResolveType));
     EXPECT(bad_function.IsNull());  // No ambiguity error expected.
   }
 
@@ -142,8 +139,7 @@
                                 super_static_function_name,
                                 kNumArguments,
                                 Object::empty_array(),
-                                kResolveType,
-                                &ambiguity_error_msg));
+                                kResolveType));
     EXPECT(!super_function.IsNull());  // No ambiguity error expected.
   }
 }
@@ -165,9 +161,8 @@
   const String& lib_name = String::Handle(String::New(test_library_name));
   const Library& lib = Library::Handle(Library::LookupLibrary(lib_name));
   ASSERT(!lib.IsNull());
-  String& ambiguity_error_msg = String::Handle();
   const Class& cls = Class::Handle(lib.LookupClass(
-      String::Handle(Symbols::New(test_class_name)), &ambiguity_error_msg));
+      String::Handle(Symbols::New(test_class_name))));
   EXPECT(!cls.IsNull());  // No ambiguity error expected.
 
   Instance& receiver = Instance::Handle(Instance::New(cls));
diff --git a/runtime/vm/runtime_entry_x64.cc b/runtime/vm/runtime_entry_x64.cc
index 13fa2a1..5683738 100644
--- a/runtime/vm/runtime_entry_x64.cc
+++ b/runtime/vm/runtime_entry_x64.cc
@@ -30,7 +30,7 @@
     // informative error message.
     __ movq(RBX, Immediate(GetEntryPoint()));
     __ movq(R10, Immediate(argument_count));
-    __ call(&StubCode::CallToRuntimeLabel());
+    __ Call(&StubCode::CallToRuntimeLabel(), PP);
   }
 }
 
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 687f2e5..d7cea49 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -77,8 +77,7 @@
         FindServiceMessageHandler(pathSegment.ToCString());
     ASSERT(handler != NULL);
     {
-      TextBuffer buffer(256);
-      JSONStream js(&buffer);
+      JSONStream js;
 
       // Setup JSONStream arguments and options. The arguments and options
       // are zone allocated and will be freed immediately after handling the
@@ -110,7 +109,7 @@
       }
 
       handler(isolate, &js);
-      const String& reply = String::Handle(String::New(buffer.buf()));
+      const String& reply = String::Handle(String::New(js.ToCString()));
       ASSERT(!reply.IsNull());
       PostReply(reply, reply_port);
     }
@@ -118,51 +117,51 @@
 }
 
 
-static void PrintArgumentsAndOptions(JSONStream* js) {
-  js->OpenObject("message");
-  js->OpenArray("arguments");
-  for (intptr_t i = 0; i < js->num_arguments(); i++) {
-    js->PrintValue(js->GetArgument(i));
+static void PrintArgumentsAndOptions(const JSONObject& obj, JSONStream* js) {
+  JSONObject jsobj(&obj, "message");
+  {
+    JSONArray jsarr(&jsobj, "arguments");
+    for (intptr_t i = 0; i < js->num_arguments(); i++) {
+      jsarr.AddValue(js->GetArgument(i));
+    }
   }
-  js->CloseArray();
-  js->OpenArray("option_keys");
-  for (intptr_t i = 0; i < js->num_options(); i++) {
-    js->PrintValue(js->GetOptionKey(i));
+  {
+    JSONArray jsarr(&jsobj, "option_keys");
+    for (intptr_t i = 0; i < js->num_options(); i++) {
+      jsarr.AddValue(js->GetOptionKey(i));
+    }
   }
-  js->CloseArray();
-  js->OpenArray("option_values");
-  for (intptr_t i = 0; i < js->num_options(); i++) {
-    js->PrintValue(js->GetOptionValue(i));
+  {
+    JSONArray jsarr(&jsobj, "option_values");
+    for (intptr_t i = 0; i < js->num_options(); i++) {
+      jsarr.AddValue(js->GetOptionValue(i));
+    }
   }
-  js->CloseArray();
-  js->CloseObject();
 }
 
 
 static void PrintCollectionErrorResponse(const char* collection_name,
                                          JSONStream* js) {
-  js->OpenObject();
-  js->PrintProperty("type", "error");
-  js->PrintfProperty("text", "Must specify collection object id: /%s/id",
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "error");
+  jsobj.AddPropertyF("text", "Must specify collection object id: /%s/id",
                      collection_name);
-  js->CloseObject();
 }
 
 
 static void HandleName(Isolate* isolate, JSONStream* js) {
-  js->OpenObject();
-  js->PrintProperty("type", "IsolateName");
-  js->PrintProperty("id", static_cast<intptr_t>(isolate->main_port()));
-  js->PrintProperty("name", isolate->name());
-  js->CloseObject();
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "IsolateName");
+  jsobj.AddProperty("id", static_cast<intptr_t>(isolate->main_port()));
+  jsobj.AddProperty("name", isolate->name());
 }
 
 
 static void HandleStackTrace(Isolate* isolate, JSONStream* js) {
   DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
-  js->OpenObject();
-  js->PrintProperty("type", "StackTrace");
-  js->OpenArray("members");
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "StackTrace");
+  JSONArray jsarr(&jsobj, "members");
   intptr_t n_frames = stack->Length();
   String& url = String::Handle();
   String& function = String::Handle();
@@ -170,26 +169,22 @@
     ActivationFrame* frame = stack->FrameAt(i);
     url ^= frame->SourceUrl();
     function ^= frame->function().UserVisibleName();
-    js->OpenObject();
-    js->PrintProperty("name", function.ToCString());
-    js->PrintProperty("url", url.ToCString());
-    js->PrintProperty("line", frame->LineNumber());
-    js->PrintProperty("function", frame->function());
-    js->PrintProperty("code", frame->code());
-    js->CloseObject();
+    JSONObject jsobj(&jsarr);
+    jsobj.AddProperty("name", function.ToCString());
+    jsobj.AddProperty("url", url.ToCString());
+    jsobj.AddProperty("line", frame->LineNumber());
+    jsobj.AddProperty("function", frame->function());
+    jsobj.AddProperty("code", frame->code());
   }
-  js->CloseArray();
-  js->CloseObject();
 }
 
 
 static void HandleObjectHistogram(Isolate* isolate, JSONStream* js) {
   ObjectHistogram* histogram = Isolate::Current()->object_histogram();
   if (histogram == NULL) {
-    js->OpenObject();
-    js->PrintProperty("type", "error");
-    js->PrintProperty("text", "Run with --print_object_histogram");
-    js->CloseObject();
+    JSONObject jsobj(js);
+    jsobj.AddProperty("type", "error");
+    jsobj.AddProperty("text", "Run with --print_object_histogram");
     return;
   }
   histogram->PrintToJSONStream(js);
@@ -197,10 +192,9 @@
 
 
 static void HandleEcho(Isolate* isolate, JSONStream* js) {
-  js->OpenObject();
-  js->PrintProperty("type", "message");
-  PrintArgumentsAndOptions(js);
-  js->CloseObject();
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "message");
+  PrintArgumentsAndOptions(jsobj, js);
 }
 
 // Print an error message if there is no ID argument.
@@ -221,15 +215,17 @@
     /* Object is not type, replace with null. */                               \
     obj = Object::null();                                                      \
   }                                                                            \
-  js->PrintValue(obj, false)
+  obj.PrintToJSONStream(js, false)
 
 
 static void HandleLibraries(Isolate* isolate, JSONStream* js) {
   if (js->num_arguments() == 1) {
-    js->PrintValue(Library::Handle(isolate->object_store()->root_library()));
-    return;
+    const Library& lib =
+        Library::Handle(isolate->object_store()->root_library());
+    lib.PrintToJSONStream(js, true);
+  } else {
+    PRINT_RING_OBJ(Library);
   }
-  PRINT_RING_OBJ(Library);
 }
 
 
@@ -264,11 +260,10 @@
 
 
 static void HandleFallthrough(Isolate* isolate, JSONStream* js) {
-  js->OpenObject();
-  js->PrintProperty("type", "error");
-  js->PrintProperty("text", "request not understood.");
-  PrintArgumentsAndOptions(js);
-  js->CloseObject();
+  JSONObject jsobj(js);
+  jsobj.AddProperty("type", "error");
+  jsobj.AddProperty("text", "request not understood.");
+  PrintArgumentsAndOptions(jsobj, js);
 }
 
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index d7e551b..560d803 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -206,7 +206,7 @@
   library_ = Library::LookupLibrary(str_);
   ASSERT(!library_.IsNull());
   str_ ^= ReadObjectImpl();
-  cls = library_.LookupClass(str_, NULL);  // No ambiguity error expected.
+  cls = library_.LookupClass(str_);
   cls.EnsureIsFinalized(isolate());
   ASSERT(!cls.IsNull());
   return cls.raw();
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 0aac461..fdcf6c0 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -131,6 +131,15 @@
   CompareDartCObjects(root, new_root);
 }
 
+
+static void ExpectEncodeFail(Dart_CObject* root) {
+  uint8_t* buffer = NULL;
+  ApiMessageWriter writer(&buffer, &malloc_allocator);
+  const bool result = writer.WriteCMessage(root);
+  EXPECT_EQ(false, result);
+}
+
+
 TEST_CASE(SerializeNull) {
   StackZone zone(Isolate::Current());
 
@@ -580,6 +589,58 @@
 }
 
 
+TEST_CASE(FailSerializeLargeArray) {
+  Dart_CObject root;
+  root.type = Dart_CObject_kArray;
+  root.value.as_array.length = Array::kMaxElements + 1;
+  root.value.as_array.values = NULL;
+  ExpectEncodeFail(&root);
+}
+
+
+TEST_CASE(FailSerializeLargeNestedArray) {
+  Dart_CObject parent;
+  Dart_CObject child;
+  Dart_CObject* values[1] = { &child };
+
+  parent.type = Dart_CObject_kArray;
+  parent.value.as_array.length = 1;
+  parent.value.as_array.values = values;
+  child.type = Dart_CObject_kArray;
+  child.value.as_array.length = Array::kMaxElements + 1;
+  ExpectEncodeFail(&parent);
+}
+
+
+TEST_CASE(FailSerializeLargeTypedDataInt8) {
+  Dart_CObject root;
+  root.type = Dart_CObject_kTypedData;
+  root.value.as_typed_data.type = Dart_TypedData_kInt8;
+  root.value.as_typed_data.length =
+      TypedData::MaxElements(kTypedDataInt8ArrayCid) + 1;
+  ExpectEncodeFail(&root);
+}
+
+
+TEST_CASE(FailSerializeLargeTypedDataUint8) {
+  Dart_CObject root;
+  root.type = Dart_CObject_kTypedData;
+  root.value.as_typed_data.type = Dart_TypedData_kUint8;
+  root.value.as_typed_data.length =
+      TypedData::MaxElements(kTypedDataUint8ArrayCid) + 1;
+  ExpectEncodeFail(&root);
+}
+
+
+TEST_CASE(FailSerializeLargeExternalTypedData) {
+  Dart_CObject root;
+  root.type = Dart_CObject_kExternalTypedData;
+  root.value.as_typed_data.length =
+      ExternalTypedData::MaxElements(kExternalTypedDataUint8ArrayCid) + 1;
+  ExpectEncodeFail(&root);
+}
+
+
 TEST_CASE(SerializeEmptyArray) {
   StackZone zone(Isolate::Current());
 
diff --git a/runtime/vm/stack_frame_x64.h b/runtime/vm/stack_frame_x64.h
index fb6e11e..33c87b6 100644
--- a/runtime/vm/stack_frame_x64.h
+++ b/runtime/vm/stack_frame_x64.h
@@ -11,11 +11,14 @@
 
                |                    | <- TOS
 Callee frame   | ...                |
+               | saved PP           |
+               | callee's PC marker |
                | saved RBP          |    (RBP of current frame)
                | saved PC           |    (PC of current frame)
                +--------------------+
 Current frame  | ...                | <- RSP of current frame
                | first local        |
+               | caller's PP        |
                | PC marker          |    (current frame's code entry + offset)
                | caller's RBP       | <- RBP of current frame
                | caller's ret addr  |    (PC of caller frame)
@@ -24,21 +27,22 @@
                |  ...               |
 */
 
-static const int kDartFrameFixedSize = 3;  // PC marker, RBP, PC.
+static const int kDartFrameFixedSize = 4;  // PC marker, RBP, PP, PC.
 static const int kSavedPcSlotFromSp = -1;
-static const int kFirstLocalSlotFromFp = -2;
+
+static const int kFirstLocalSlotFromFp = -3;
+static const int kSavedCallerPpSlotFromFp = -2;
 static const int kPcMarkerSlotFromFp = -1;
 static const int kSavedCallerFpSlotFromFp = 0;
 static const int kSavedCallerPcSlotFromFp = 1;
+
 static const int kParamEndSlotFromFp = 1;  // One slot past last parameter.
 static const int kCallerSpSlotFromFp = 2;
-
-// No pool pointer on X64 (indicated by aliasing saved fp).
-static const int kSavedCallerPpSlotFromFp = kSavedCallerFpSlotFromFp;
+static const int kSavedAboveReturnAddress = 3;  // Saved above return address.
 
 // Entry and exit frame layout.
-static const int kSavedContextSlotFromEntryFp = -9;
-static const int kExitLinkSlotFromEntryFp = -8;
+static const int kSavedContextSlotFromEntryFp = -10;
+static const int kExitLinkSlotFromEntryFp = -9;
 
 }  // namespace dart
 
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index e4f18a2..3e185ee 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -182,7 +182,8 @@
   StubEntry* name##_entry_;
   STUB_CODE_LIST(STUB_CODE_ENTRY);
 #undef STUB_CODE_ENTRY
-  // This dummy field is needed so that we can intialize the stubs from a macro.
+  // This dummy field is needed so that we can initialize
+  // the stubs from a macro.
   void* dummy_;
 
   // Generate the stub and finalize the generated code into the stub
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 3039a97..a9d3777 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -83,9 +83,8 @@
   __ movq(RBX, Address(CTX, Isolate::top_context_offset()));
 
   // Reset Context pointer in Isolate structure.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ movq(Address(CTX, Isolate::top_context_offset()), raw_null);
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ movq(Address(CTX, Isolate::top_context_offset()), R12);
 
   // Cache Context pointer into CTX while executing Dart code.
   __ movq(CTX, RBX);
@@ -172,9 +171,8 @@
   __ movq(R8, Address(CTX, Isolate::top_context_offset()));
 
   // Reset Context pointer in Isolate structure.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ movq(Address(CTX, Isolate::top_context_offset()), raw_null);
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ movq(Address(CTX, Isolate::top_context_offset()), R12);
 
   // Cache Context pointer into CTX while executing Dart code.
   __ movq(CTX, R8);
@@ -240,9 +238,8 @@
   __ movq(R8, Address(CTX, Isolate::top_context_offset()));
 
   // Reset Context pointer in Isolate structure.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ movq(Address(CTX, Isolate::top_context_offset()), raw_null);
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ movq(Address(CTX, Isolate::top_context_offset()), R12);
 
   // Cache Context pointer into CTX while executing Dart code.
   __ movq(CTX, R8);
@@ -255,11 +252,10 @@
 // Input parameters:
 //   R10: arguments descriptor array.
 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   __ EnterStubFrame();
   __ pushq(R10);  // Preserve arguments descriptor array.
-  __ pushq(raw_null);  // Setup space on stack for return value.
+  // Setup space on stack for return value.
+  __ PushObject(Object::null_object());
   __ CallRuntime(kPatchStaticCallRuntimeEntry, 0);
   __ popq(RAX);  // Get Code object result.
   __ popq(R10);  // Restore arguments descriptor array.
@@ -276,11 +272,10 @@
 // (invalid because its function was optimized or deoptimized).
 // R10: arguments descriptor array.
 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   __ EnterStubFrame();
   __ pushq(R10);  // Preserve arguments descriptor array.
-  __ pushq(raw_null);  // Setup space on stack for return value.
+  // Setup space on stack for return value.
+  __ PushObject(Object::null_object());
   __ CallRuntime(kFixCallersTargetRuntimeEntry, 0);
   __ popq(RAX);  // Get Code object.
   __ popq(R10);  // Restore arguments descriptor array.
@@ -296,11 +291,9 @@
 //   R10: smi-tagged argument count, may be zero.
 //   RBP[kParamEndSlotFromFp + 1]: last argument.
 static void PushArgumentsArray(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
+  __ LoadObject(R12, Object::null_object(), PP);
   // Allocate array to store arguments of caller.
-  __ movq(RBX, raw_null);  // Null element type for raw Array.
+  __ movq(RBX, R12);  // Null element type for raw Array.
   __ call(&StubCode::AllocateArrayLabel());
   __ SmiUntag(R10);
   // RAX: newly allocated array.
@@ -330,18 +323,15 @@
 //       called, the stub accesses the receiver from this location directly
 //       when trying to resolve the call.
 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
-  __ EnterStubFrame();
-
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ pushq(raw_null);  // Space for the return value.
+  __ EnterStubFrameWithPP();
+  __ PushObject(Object::null_object());  // Space for the return value.
 
   // Push the receiver as an argument.  Load the smi-tagged argument
   // count into R13 to index the receiver in the stack.  There are
-  // three words (null, stub's pc marker, saved fp) above the return
+  // four words (null, stub's pc marker, saved pp, saved fp) above the return
   // address.
   __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-  __ pushq(Address(RSP, R13, TIMES_4, (3 * kWordSize)));
+  __ pushq(Address(RSP, R13, TIMES_4, (4 * kWordSize)));
 
   __ pushq(RBX);  // Pass IC data object.
   __ pushq(R10);  // Pass arguments descriptor array.
@@ -355,7 +345,7 @@
   // Remove arguments.
   __ Drop(4);
   __ popq(RAX);  // Get result into RAX.
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -378,7 +368,9 @@
 // - Fill the unoptimized frame.
 // - Materialize objects that require allocation (e.g. Double instances).
 // GC can occur only after frame is fully rewritten.
-// Stack after EnterDartFrame(0) below:
+// Stack after EnterDartFrame(0, PP, kNoRegister) below:
+//   +------------------+
+//   | Saved PP         | <- PP
 //   +------------------+
 //   | PC marker        | <- TOS
 //   +------------------+
@@ -391,8 +383,12 @@
 // Parts of the code cannot GC, part of the code can GC.
 static void GenerateDeoptimizationSequence(Assembler* assembler,
                                            bool preserve_result) {
-  // Leaf runtime function DeoptimizeCopyFrame expects a Dart frame.
-  __ EnterDartFrame(0);
+  // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
+  // is no need to set the correct PC marker or load PP, since they get patched.
+  __ EnterFrame(0);
+  __ pushq(Immediate(0));
+  __ pushq(PP);
+
   // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry
   // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls.
   const intptr_t saved_result_slot_from_fp =
@@ -422,14 +418,21 @@
     __ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize));
   }
 
+  // There is a Dart Frame on the stack. We just need the PP.
+  __ movq(PP, Address(RBP, -2 * kWordSize));
   __ LeaveFrame();
+
   __ popq(RCX);   // Preserve return address.
   __ movq(RSP, RBP);  // Discard optimized frame.
   __ subq(RSP, RAX);  // Reserve space for deoptimized frame.
   __ pushq(RCX);  // Restore return address.
 
-  // Leaf runtime function DeoptimizeFillFrame expects a Dart frame.
-  __ EnterDartFrame(0);
+  // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there
+  // is no need to set the correct PC marker or load PP, since they get patched.
+  __ EnterFrame(0);
+  __ pushq(Immediate(0));
+  __ pushq(PP);
+
   if (preserve_result) {
     __ pushq(RBX);  // Preserve result as first local.
   }
@@ -441,6 +444,8 @@
     __ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize));
   }
   // Code above cannot cause GC.
+  // There is a Dart Frame on the stack. We just need the PP.
+  __ movq(PP, Address(RBP, -2 * kWordSize));
   __ LeaveFrame();
 
   // Frame is fully rewritten at this point and it is safe to perform a GC.
@@ -486,20 +491,20 @@
 
 
 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) {
-  __ EnterStubFrame();
+  __ EnterStubFrameWithPP();
   // Load the receiver into RAX.  The argument count in the arguments
   // descriptor in R10 is a smi.
   __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
-  // Two words (saved fp, stub's pc marker) in the stack above the return
-  // address.
-  __ movq(RAX, Address(RSP, RAX, TIMES_4, 2 * kWordSize));
+  // Three words (saved pp, saved fp, stub's pc marker)
+  // in the stack above the return address.
+  __ movq(RAX, Address(RSP, RAX, TIMES_4,
+                       kSavedAboveReturnAddress * kWordSize));
   // Preserve IC data and arguments descriptor.
   __ pushq(RBX);
   __ pushq(R10);
 
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Instructions::null()));
-  __ pushq(raw_null);  // Space for the result of the runtime call.
+  // Space for the result of the runtime call.
+  __ PushObject(Object::null_object());
   __ pushq(RAX);  // Receiver.
   __ pushq(RBX);  // IC data.
   __ pushq(R10);  // Arguments descriptor.
@@ -511,10 +516,10 @@
   __ popq(RAX);  // Return value from the runtime call (instructions).
   __ popq(R10);  // Restore arguments descriptor.
   __ popq(RBX);  // Restore IC data.
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
 
   Label lookup;
-  __ cmpq(RAX, raw_null);
+  __ CompareObject(RAX, Object::null_object());
   __ j(EQUAL, &lookup, Assembler::kNearJump);
   __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
   __ jmp(RAX);
@@ -532,8 +537,6 @@
 // The newly allocated object is returned in RAX.
 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
   Label slow_case;
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
 
   if (FLAG_inline_alloc) {
     // Compute the size to be allocated, it is based on the array length
@@ -622,13 +625,14 @@
     __ leaq(RBX, FieldAddress(RAX, Array::data_offset()));
     // RBX: iterator which initially points to the start of the variable
     // data area to be initialized.
+    __ LoadObject(R13, Object::null_object(), PP);
     Label done;
     Label init_loop;
     __ Bind(&init_loop);
     __ cmpq(RBX, R12);
     __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
     // TODO(cshapiro): StoreIntoObjectNoBarrier
-    __ movq(Address(RBX, 0), raw_null);
+    __ movq(Address(RBX, 0), R13);
     __ addq(RBX, Immediate(kWordSize));
     __ jmp(&init_loop, Assembler::kNearJump);
     __ Bind(&done);
@@ -645,7 +649,8 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();
-  __ pushq(raw_null);  // Setup space on stack for return value.
+  // Setup space on stack for return value.
+  __ PushObject(Object::null_object());
   __ pushq(R10);  // Array length as Smi.
   __ pushq(RBX);  // Element type.
   __ CallRuntime(kAllocateArrayRuntimeEntry, 2);
@@ -663,17 +668,16 @@
 //       called, the stub accesses the closure from this location directly
 //       when trying to resolve the call.
 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
   // Load num_args.
   __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
   // Load closure object in R13.
   __ movq(R13, Address(RSP, RAX, TIMES_4, 0));  // RAX is a Smi.
 
+  __ LoadObject(R12, Object::null_object(), PP);
+
   // Verify that R13 is a closure by checking its class.
   Label not_closure;
-  __ cmpq(R13, raw_null);
+  __ cmpq(R13, R12);
   // Not a closure, but null object.
   __ j(EQUAL, &not_closure);
   __ testq(R13, Immediate(kSmiTagMask));
@@ -682,7 +686,7 @@
   // class.signature_function() is not null.
   __ LoadClass(RAX, R13);
   __ movq(RAX, FieldAddress(RAX, Class::signature_function_offset()));
-  __ cmpq(RAX, raw_null);
+  __ cmpq(RAX, R12);
   // Actual class is not a closure class.
   __ j(EQUAL, &not_closure, Assembler::kNearJump);
 
@@ -694,7 +698,7 @@
 
   // Load closure function code in RAX.
   __ movq(RAX, FieldAddress(RBX, Function::code_offset()));
-  __ cmpq(RAX, raw_null);
+  __ cmpq(RAX, R12);
   Label function_compiled;
   __ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump);
 
@@ -733,8 +737,8 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();
-
-  __ pushq(raw_null);  // Setup space on stack for result from call.
+  // Setup space on stack for result from call.
+  __ pushq(R12);
   __ pushq(R10);  // Arguments descriptor.
   // Load smi-tagged arguments array length, including the non-closure.
   __ movq(R10, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
@@ -761,12 +765,12 @@
 //   RCX : new context containing the current isolate pointer.
 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
   // Save frame pointer coming in.
-  __ EnterFrame(0);
+  __ EnterStubFrame();
 
   // Save arguments descriptor array and new context.
-  const intptr_t kArgumentsDescOffset = -1 * kWordSize;
+  const intptr_t kArgumentsDescOffset = -2 * kWordSize;
   __ pushq(RSI);
-  const intptr_t kNewContextOffset = -2 * kWordSize;
+  const intptr_t kNewContextOffset = -3 * kWordSize;
   __ pushq(RCX);
 
   // Save C++ ABI callee-saved registers.
@@ -792,7 +796,7 @@
   // StackFrameIterator reads the top exit frame info saved in this frame.
   // The constant kExitLinkSlotFromEntryFp must be kept in sync with the
   // code below.
-  ASSERT(kExitLinkSlotFromEntryFp == -8);
+  ASSERT(kExitLinkSlotFromEntryFp == -9);
   __ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
   __ pushq(RAX);
   __ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
@@ -804,7 +808,7 @@
   // EntryFrame::SavedContext reads the context saved in this frame.
   // The constant kSavedContextSlotFromEntryFp must be kept in sync with
   // the code below.
-  ASSERT(kSavedContextSlotFromEntryFp == -9);
+  ASSERT(kSavedContextSlotFromEntryFp == -10);
   __ movq(RAX, Address(R8, Isolate::top_context_offset()));
   __ pushq(RAX);
 
@@ -881,8 +885,7 @@
 // Output:
 // RAX: new allocated RawContext object.
 void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R12, Object::null_object(), PP);
   if (FLAG_inline_alloc) {
     const Class& context_class = Class::ZoneHandle(Object::context_class());
     Label slow_case;
@@ -957,12 +960,10 @@
     // R13: Isolate, not an object.
     __ movq(FieldAddress(RAX, Context::isolate_offset()), R13);
 
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
     // Setup the parent field.
     // RAX: new object.
     // R10: number of context variables.
-    __ movq(FieldAddress(RAX, Context::parent_offset()), raw_null);
+    __ movq(FieldAddress(RAX, Context::parent_offset()), R12);
 
     // Initialize the context variables.
     // RAX: new object.
@@ -974,7 +975,7 @@
       __ jmp(&entry, Assembler::kNearJump);
       __ Bind(&loop);
       __ decq(R10);
-      __ movq(Address(R13, R10, TIMES_8, 0), raw_null);
+      __ movq(Address(R13, R10, TIMES_8, 0), R12);
       __ Bind(&entry);
       __ cmpq(R10, Immediate(0));
       __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
@@ -988,7 +989,7 @@
   }
   // Create a stub frame.
   __ EnterStubFrame();
-  __ pushq(raw_null);  // Setup space on stack for the return value.
+  __ pushq(R12);  // Setup space on stack for the return value.
   __ SmiTag(R10);
   __ pushq(R10);  // Push number of context variables.
   __ CallRuntime(kAllocateContextRuntimeEntry, 1);  // Allocate context.
@@ -1072,8 +1073,6 @@
                                               const Class& cls) {
   const intptr_t kObjectTypeArgumentsOffset = 2 * kWordSize;
   const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize;
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   // The generated code is different if the class is parameterized.
   const bool is_cls_parameterized = cls.HasTypeArguments();
   ASSERT(!cls.HasTypeArguments() ||
@@ -1085,6 +1084,7 @@
   const intptr_t instance_size = cls.instance_size();
   ASSERT(instance_size > 0);
   const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize();
+  __ LoadObject(R12, Object::null_object(), PP);
   if (FLAG_inline_alloc &&
       Heap::IsAllocatableInNewSpace(instance_size + type_args_size)) {
     Label slow_case;
@@ -1168,9 +1168,6 @@
     __ movq(Address(RAX, Instance::tags_offset()), Immediate(tags));
 
     // Initialize the remaining words of the object.
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
-
     // RAX: new object start.
     // RBX: next object start.
     // RDI: new object type arguments (if is_cls_parameterized).
@@ -1181,7 +1178,7 @@
       for (intptr_t current_offset = sizeof(RawObject);
            current_offset < instance_size;
            current_offset += kWordSize) {
-        __ movq(Address(RAX, current_offset), raw_null);
+        __ movq(Address(RAX, current_offset), R12);
       }
     } else {
       __ leaq(RCX, Address(RAX, sizeof(RawObject)));
@@ -1195,7 +1192,7 @@
       __ Bind(&init_loop);
       __ cmpq(RCX, RBX);
       __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
-      __ movq(Address(RCX, 0), raw_null);
+      __ movq(Address(RCX, 0), R12);
       __ addq(RCX, Immediate(kWordSize));
       __ jmp(&init_loop, Assembler::kNearJump);
       __ Bind(&done);
@@ -1217,14 +1214,14 @@
     __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset));
   }
   // Create a stub frame.
-  __ EnterStubFrame();
-  __ pushq(raw_null);  // Setup space on stack for return value.
+  __ EnterStubFrameWithPP();
+  __ pushq(R12);  // Setup space on stack for return value.
   __ PushObject(cls);  // Push class of object to be allocated.
   if (is_cls_parameterized) {
     __ pushq(RAX);  // Push type arguments of object to be allocated.
     __ pushq(RDX);  // Push type arguments of instantiator.
   } else {
-    __ pushq(raw_null);  // Push null type arguments.
+    __ pushq(R12);  // Push null type arguments.
     __ pushq(Immediate(Smi::RawValue(StubCode::kNoInstantiator)));
   }
   __ CallRuntime(kAllocateObjectRuntimeEntry, 3);  // Allocate object.
@@ -1234,7 +1231,7 @@
   __ popq(RAX);  // Pop result (newly allocated object).
   // RAX: new object
   // Restore the frame pointer.
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -1246,16 +1243,17 @@
 //   RSP : points to return address.
 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
                                                 const Function& func) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   ASSERT(func.IsClosureFunction());
   ASSERT(!func.IsImplicitStaticClosureFunction());
   const bool is_implicit_instance_closure =
       func.IsImplicitInstanceClosureFunction();
   const Class& cls = Class::ZoneHandle(func.signature_class());
   const bool has_type_arguments = cls.HasTypeArguments();
-  const intptr_t kTypeArgumentsOffset = 1 * kWordSize;
-  const intptr_t kReceiverOffset = 2 * kWordSize;
+
+  __ EnterStubFrameWithPP();  // Uses pool pointer to refer to function.
+  __ LoadObject(R12, Object::null_object(), PP);
+  const intptr_t kTypeArgumentsOffset = 4 * kWordSize;
+  const intptr_t kReceiverOffset = 5 * kWordSize;
   const intptr_t closure_size = Closure::InstanceSize();
   const intptr_t context_size = Context::InstanceSize(1);  // Captured receiver.
   if (FLAG_inline_alloc &&
@@ -1298,7 +1296,8 @@
     // RAX: new closure object.
     // RBX: new context object (only if is_implicit_closure).
     // R13: next object start.
-    __ LoadObject(R10, func);  // Load function of closure to be allocated.
+    // Load function of closure to be allocated.
+    __ LoadObject(R10, func, PP);
     __ movq(Address(RAX, Closure::function_offset()), R10);
 
     // Setup the context for this closure.
@@ -1320,7 +1319,7 @@
       __ movq(Address(RBX, Context::isolate_offset()), R10);
 
       // Set the parent to null.
-      __ movq(Address(RBX, Context::parent_offset()), raw_null);
+      __ movq(Address(RBX, Context::parent_offset()), R12);
 
       // Initialize the context variable to the receiver.
       __ movq(R10, Address(RSP, kReceiverOffset));
@@ -1340,6 +1339,7 @@
     // Done allocating and initializing the instance.
     // RAX: new object.
     __ addq(RAX, Immediate(kHeapObjectTag));
+    __ LeaveFrameWithPP();
     __ ret();
 
     __ Bind(&slow_case);
@@ -1350,9 +1350,8 @@
   if (is_implicit_instance_closure) {
     __ movq(RAX, Address(RSP, kReceiverOffset));
   }
-  // Create the stub frame.
-  __ EnterStubFrame();
-  __ pushq(raw_null);  // Setup space on stack for the return value.
+
+  __ pushq(R12);  // Setup space on stack for the return value.
   __ PushObject(func);
   if (is_implicit_instance_closure) {
     __ pushq(RAX);  // Receiver.
@@ -1360,7 +1359,7 @@
   if (has_type_arguments) {
     __ pushq(RCX);  // Push type arguments of closure to be allocated.
   } else {
-    __ pushq(raw_null);  // Push null type arguments.
+    __ pushq(R12);  // Push null type arguments.
   }
   if (is_implicit_instance_closure) {
     __ CallRuntime(kAllocateImplicitInstanceClosureRuntimeEntry, 3);
@@ -1375,7 +1374,7 @@
   __ popq(RAX);  // Pop the result.
   // RAX: New closure object.
   // Restore the calling frame.
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -1395,9 +1394,8 @@
   __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
   __ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize));
 
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ pushq(raw_null);  // Setup space on stack for result from noSuchMethod.
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ pushq(R12);  // Setup space on stack for result from noSuchMethod.
   __ pushq(RAX);  // Receiver.
   __ pushq(RBX);  // IC data array.
   __ pushq(R10);  // Arguments descriptor array.
@@ -1545,8 +1543,7 @@
   __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
 
   // IC miss.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
+  __ LoadObject(R12, Object::null_object(), PP);
   // Compute address of arguments (first read number of arguments from
   // arguments descriptor array and then compute address on the stack).
   __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
@@ -1554,7 +1551,7 @@
   __ EnterStubFrame();
   __ pushq(R10);  // Preserve arguments descriptor array.
   __ pushq(RBX);  // Preserve IC data object.
-  __ pushq(raw_null);  // Setup space on stack for result (target code object).
+  __ pushq(R12);  // Setup space on stack for result (target code object).
   // Push call arguments.
   for (intptr_t i = 0; i < num_args; i++) {
     __ movq(RCX, Address(RAX, -kWordSize * i));
@@ -1571,7 +1568,7 @@
   __ popq(R10);  // Restore arguments descriptor array.
   __ LeaveFrame();
   Label call_target_function;
-  __ cmpq(RAX, raw_null);
+  __ cmpq(RAX, R12);
   __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump);
   // NoSuchMethod or closure.
   // Mark IC call that it may be a closure call that does not collect
@@ -1737,13 +1734,12 @@
           Immediate(Smi::RawValue(Smi::kMaxValue)));
   __ Bind(&increment_done);
 
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   Label target_is_compiled;
   // Get function and call it, if possible.
   __ movq(R13, Address(R12, target_offset));
   __ movq(RAX, FieldAddress(R13, Function::code_offset()));
-  __ cmpq(RAX, raw_null);
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ cmpq(RAX, R12);
   __ j(NOT_EQUAL, &target_is_compiled, Assembler::kNearJump);
 
   __ EnterStubFrame();
@@ -1783,9 +1779,8 @@
   __ pushq(R10);
   // Room for result. Debugger stub returns address of the
   // unpatched runtime stub.
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ pushq(raw_null);  // Room for result.
+  __ LoadObject(R12, Object::null_object(), PP);
+  __ pushq(R12);  // Room for result.
   __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0);
   __ popq(RAX);  // Address of original.
   __ popq(R10);  // Restore arguments.
@@ -1798,11 +1793,10 @@
 //  RBX: ICData (unoptimized static call)
 //  TOS(0): return address (Dart code).
 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   __ EnterStubFrame();
+  __ LoadObject(R12, Object::null_object(), PP);
   __ pushq(RBX);  // Preserve IC data for unoptimized call.
-  __ pushq(raw_null);  // Room for result.
+  __ pushq(R12);  // Room for result.
   __ CallRuntime(kBreakpointStaticHandlerRuntimeEntry, 0);
   __ popq(RAX);  // Code object.
   __ popq(RBX);  // Restore IC data.
@@ -1827,7 +1821,7 @@
   __ LeaveFrame();
 
   __ popq(R11);  // discard return address of call to this stub.
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -1868,17 +1862,16 @@
 // Result in RCX: null -> not found, otherwise result (true or false).
 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
   ASSERT((1 <= n) && (n <= 3));
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
   const intptr_t kInstantiatorTypeArgumentsInBytes = 1 * kWordSize;
   const intptr_t kInstanceOffsetInBytes = 2 * kWordSize;
   const intptr_t kCacheOffsetInBytes = 3 * kWordSize;
   __ movq(RAX, Address(RSP, kInstanceOffsetInBytes));
+  __ LoadObject(R12, Object::null_object(), PP);
   if (n > 1) {
     __ LoadClass(R10, RAX);
     // Compute instance type arguments into R13.
     Label has_no_type_arguments;
-    __ movq(R13, raw_null);
+    __ movq(R13, R12);
     __ movq(RDI, FieldAddress(R10,
         Class::type_arguments_field_offset_in_words_offset()));
     __ cmpq(RDI, Immediate(Class::kNoTypeArguments));
@@ -1900,7 +1893,7 @@
   __ SmiTag(R10);
   __ Bind(&loop);
   __ movq(RDI, Address(RDX, kWordSize * SubtypeTestCache::kInstanceClassId));
-  __ cmpq(RDI, raw_null);
+  __ cmpq(RDI, R12);
   __ j(EQUAL, &not_found, Assembler::kNearJump);
   __ cmpq(RDI, R10);
   if (n == 1) {
@@ -1927,7 +1920,7 @@
   __ jmp(&loop, Assembler::kNearJump);
   // Fall through to not found.
   __ Bind(&not_found);
-  __ movq(RCX, raw_null);
+  __ movq(RCX, R12);
   __ ret();
 
   __ Bind(&found);
@@ -2060,10 +2053,10 @@
   __ movq(RAX, Address(RSP, 1 * kWordSize));
   __ cmpq(RAX, Address(RSP, 2 * kWordSize));
   __ j(EQUAL, &true_label, Assembler::kNearJump);
-  __ LoadObject(RAX, Bool::False());
+  __ LoadObject(RAX, Bool::False(), PP);
   __ ret();
   __ Bind(&true_label);
-  __ LoadObject(RAX, Bool::True());
+  __ LoadObject(RAX, Bool::True(), PP);
   __ ret();
 
   __ Bind(&get_class_id_as_smi);
@@ -2081,7 +2074,7 @@
 
   __ Bind(&update_ic_data);
 
-  // RCX: ICData
+  // RBX: ICData
   __ movq(RAX, Address(RSP, 1 * kWordSize));
   __ movq(R13, Address(RSP, 2 * kWordSize));
   __ EnterStubFrame();
@@ -2100,11 +2093,10 @@
 // RDI: function to be reoptimized.
 // R10: argument descriptor (preserved).
 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ EnterStubFrame();
+  __ EnterStubFrameWithPP();
+  __ LoadObject(R12, Object::null_object(), PP);
   __ pushq(R10);
-  __ pushq(raw_null);  // Setup space on stack for return value.
+  __ pushq(R12);  // Setup space on stack for return value.
   __ pushq(RDI);
   __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1);
   __ popq(RAX);  // Disard argument.
@@ -2112,7 +2104,7 @@
   __ popq(R10);  // Restore argument descriptor.
   __ movq(RAX, FieldAddress(RAX, Code::instructions_offset()));
   __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
-  __ LeaveFrame();
+  __ LeaveFrameWithPP();
   __ jmp(RAX);
   __ int3();
 }
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index 769134d..3efc152 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -45,8 +45,8 @@
   const Object& result = Object::ZoneHandle();
   const Context& context = Context::ZoneHandle(Context::New(0, Heap::kOld));
   ASSERT(context.isolate() == Isolate::Current());
-  __ enter(Immediate(0));
-  __ LoadObject(CTX, context);
+  __ EnterStubFrameWithPP();
+  __ LoadObject(CTX, context, PP);
   __ PushObject(result);  // Push Null object for return value.
   __ PushObject(smi1);  // Push argument 1 smi1.
   __ PushObject(smi2);  // Push argument 2 smi2.
@@ -54,7 +54,7 @@
   __ CallRuntime(kTestSmiSubRuntimeEntry, argc);  // Call SmiSub runtime func.
   __ AddImmediate(RSP, Immediate(argc * kWordSize));
   __ popq(RAX);  // Pop return value from return slot.
-  __ leave();
+  __ LeaveFrameWithPP();
   __ ret();
 }
 
@@ -84,8 +84,8 @@
   const Smi& smi2 = Smi::ZoneHandle(Smi::New(value2));
   __ enter(Immediate(0));
   __ ReserveAlignedFrameSpace(0);
-  __ LoadObject(RDI, smi1);  // Set up argument 1 smi1.
-  __ LoadObject(RSI, smi2);  // Set up argument 2 smi2.
+  __ LoadObject(RDI, smi1, PP);  // Set up argument 1 smi1.
+  __ LoadObject(RSI, smi2, PP);  // Set up argument 2 smi2.
   __ CallRuntime(kTestLeafSmiAddRuntimeEntry, 2);  // Call SmiAdd runtime func.
   __ leave();
   __ ret();  // Return value is in RAX.
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index 1b58858..a52c97a 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -108,9 +108,6 @@
   /* Internal token for !(expr is Type) negative type test operator */         \
   TOK(kISNOT, "", 10, kNoAttribute)                                            \
                                                                                \
-  /* Internal token for (expr as Type) type cast operator */                   \
-  TOK(kAS, "", 10, kNoAttribute)                                               \
-                                                                               \
   TOK(kINDEX, "[]", 0, kNoAttribute)                                           \
   TOK(kASSIGN_INDEX, "[]=", 0, kNoAttribute)                                   \
   TOK(kNEGATE, "unary-", 0, kNoAttribute)                                      \
@@ -139,7 +136,8 @@
 // to update kFirstKeyword and kLastKeyword below.
 #define DART_KEYWORD_LIST(KW)                                                  \
   KW(kABSTRACT, "abstract", 0, kPseudoKeyword) /* == kFirstKeyword */          \
-  KW(kASSERT, "assert", 0, kKeyword)                                           \
+  KW(kAS, "as", 10, kPseudoKeyword)                                            \
+  KW(kASSERT, "assert", 10, kKeyword)                                          \
   KW(kBREAK, "break", 0, kKeyword)                                             \
   KW(kCASE, "case", 0, kKeyword)                                               \
   KW(kCATCH, "catch", 0, kKeyword)                                             \
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 34348f8..edcd75d 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -87,6 +87,8 @@
     'constants_ia32.h',
     'constants_mips.h',
     'constants_x64.h',
+    'coverage.cc',
+    'coverage.h',
     'cpu.h',
     'cpu_arm.cc',
     'cpu_ia32.cc',
@@ -164,6 +166,7 @@
     'globals.h',
     'growable_array.h',
     'growable_array_test.cc',
+    'guard_field_test.cc',
     'handles.cc',
     'handles.h',
     'handles_impl.h',
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index d211e94..5832103 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -176,7 +176,8 @@
     // TODO(johnniwinther): Wrap the result from [provider] in a specialized
     // [Future] to ensure that we never execute an asynchronous action without setting
     // up the current element of the compiler.
-    return new Future.sync(() => provider(resourceUri)).then((String text) {
+    return new Future.sync(() => callUserProvider(resourceUri))
+        .then((String text) {
       SourceFile sourceFile = new SourceFile(resourceUri.toString(), text);
       // We use [readableUri] as the URI for the script since need to preserve
       // the scheme in the script because [Script.uri] is used for resolving
@@ -283,10 +284,10 @@
     // [:span.uri:] might be [:null:] in case of a [Script] with no [uri]. For
     // instance in the [Types] constructor in typechecker.dart.
     if (span == null || span.uri == null) {
-      handler(null, null, null, message, kind);
+      callUserHandler(null, null, null, message, kind);
     } else {
-      handler(translateUri(span.uri, null), span.begin, span.end,
-              message, kind);
+      callUserHandler(
+          translateUri(span.uri, null), span.begin, span.end, message, kind);
     }
   }
 
@@ -294,4 +295,30 @@
     return mockableLibraryUsed
       && (options.indexOf('--allow-mock-compilation') != -1);
   }
+
+  void callUserHandler(Uri uri, int begin, int end,
+                       String message, api.Diagnostic kind) {
+    try {
+      handler(uri, begin, end, message, kind);
+    } catch (ex, s) {
+      diagnoseCrashInUserCode(
+          'Uncaught exception in diagnostic handler', ex, s);
+      rethrow;
+    }
+  }
+
+  Future callUserProvider(Uri uri) {
+    try {
+      return provider(uri);
+    } catch (ex, s) {
+      diagnoseCrashInUserCode('Uncaught exception in input provider', ex, s);
+      rethrow;
+    }
+  }
+
+  void diagnoseCrashInUserCode(String message, exception, stackTrace) {
+    hasCrashed = true;
+    print('$message: ${tryToString(exception)}');
+    print(tryToString(stackTrace));
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 4d43a2a..f9339f0 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -487,7 +487,8 @@
 
   Constant makeTypeConstant(Element element) {
     DartType elementType = element.computeType(compiler).asRaw();
-    compiler.backend.registerTypeLiteral(element, elements);
+    compiler.backend.registerTypeLiteral(
+        element, compiler.enqueuer.codegen, elements);
     DartType constantType =
         compiler.backend.typeImplementation.computeType(compiler);
     Constant constant = new TypeConstant(elementType, constantType);
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index fe2403e..daf9daf 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -152,7 +152,9 @@
 
   /// Called during resolution to notify to the backend that the
   /// program uses a type literal.
-  void registerTypeLiteral(Element element, TreeElements elements) {}
+  void registerTypeLiteral(Element element,
+                           Enqueuer enqueuer,
+                           TreeElements elements) {}
 
   /// Called during resolution to notify to the backend that the
   /// program has a catch statement with a stack trace.
@@ -164,7 +166,9 @@
                        TreeElements elements) {}
 
   /// Register an as check to the backend.
-  void registerAsCheck(DartType type, TreeElements elements) {}
+  void registerAsCheck(DartType type,
+                       Enqueuer enqueuer,
+                       TreeElements elements) {}
 
   /// Register that the application may throw a [NoSuchMethodError].
   void registerThrowNoSuchMethod(TreeElements elements) {}
@@ -459,6 +463,14 @@
 
   Element get currentElement => _currentElement;
 
+  String tryToString(object) {
+    try {
+      return object.toString();
+    } catch (_) {
+      return '<exception in toString()>';
+    }
+  }
+
   /**
    * Perform an operation, [f], returning the return value from [f].  If an
    * error occurs then report it as having occurred during compilation of
@@ -469,27 +481,31 @@
     _currentElement = element;
     try {
       return f();
-    } on SpannableAssertionFailure catch (ex) {
+    } on SpannableAssertionFailure catch (ex, s) {
       if (!hasCrashed) {
+        String message = (ex.message != null) ? tryToString(ex.message)
+                                              : tryToString(ex);
         SourceSpan span = spanFromSpannable(ex.node);
-        reportError(ex.node, MessageKind.GENERIC, {'text': ex.message});
-        pleaseReportCrash();
+        reportError(ex.node, MessageKind.GENERIC, {'text': message});
+        pleaseReportCrash(s, 'The compiler crashed: $message.');
       }
       hasCrashed = true;
-      rethrow;
+      throw new CompilerCancelledException('The compiler crashed.');
     } on CompilerCancelledException catch (ex) {
       rethrow;
     } on StackOverflowError catch (ex) {
       // We cannot report anything useful in this case, because we
       // do not have enough stack space.
       rethrow;
-    } catch (ex) {
+    } catch (ex, s) {
+      if (hasCrashed) rethrow;
+      String message = 'The compiler crashed: ${tryToString(ex)}.';
       try {
-        unhandledExceptionOnElement(element);
+        unhandledExceptionOnElement(element, s, message);
       } catch (doubleFault) {
         // Ignoring exceptions in exception handling.
       }
-      rethrow;
+      throw new CompilerCancelledException(message);
     } finally {
       _currentElement = old;
     }
@@ -668,17 +684,25 @@
     internalError(message, element: element);
   }
 
-  void unhandledExceptionOnElement(Element element) {
+  void unhandledExceptionOnElement(Element element,
+                                   StackTrace stackTrace,
+                                   String message) {
     if (hasCrashed) return;
     hasCrashed = true;
     reportDiagnostic(spanFromElement(element),
                      MessageKind.COMPILER_CRASHED.error().toString(),
                      api.Diagnostic.CRASH);
-    pleaseReportCrash();
+    pleaseReportCrash(stackTrace, message);
   }
 
-  void pleaseReportCrash() {
+  void pleaseReportCrash(StackTrace stackTrace, String message) {
     print(MessageKind.PLEASE_REPORT_THE_CRASH.message({'buildId': buildId}));
+    if (message != null) {
+      print(message);
+    }
+    if (stackTrace != null) {
+      print(stackTrace);
+    }
   }
 
   void cancel(String reason, {Node node, Token token,
@@ -742,7 +766,8 @@
           reportDiagnostic(new SourceSpan(uri, 0, 0),
                            MessageKind.COMPILER_CRASHED.error().toString(),
                            api.Diagnostic.CRASH);
-          pleaseReportCrash();
+          String message = 'The compiler crashed.';
+          pleaseReportCrash(getAttachedStackTrace(error), message);
         }
       } catch (doubleFault) {
         // Ignoring exceptions in exception handling.
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index c97e070..eb211bb 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -314,9 +314,7 @@
       return;
     }
     if (element == compiler.dynamicClass) {
-      internalError(
-          'Should never make element placeholder for dynamic type element',
-          node: node);
+      return;
     }
     elementNodes.putIfAbsent(element, () => new Set<Node>()).add(node);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index cf456b6..6aa85be 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -680,6 +680,7 @@
 
 abstract class TypedefElement extends Element
     implements TypeDeclarationElement {
+  TypedefType get thisType;
   TypedefType get rawType;
   DartType get alias;
   FunctionSignature get functionSignature;
@@ -790,6 +791,7 @@
  * declarations and typedefs.
  */
 abstract class TypeDeclarationElement extends Element {
+  GenericType get thisType;
   GenericType get rawType;
 
   /**
@@ -823,6 +825,7 @@
 
   int get supertypeLoadState;
   int get resolutionState;
+  bool get isResolved;
   SourceString get nativeTagInfo;
 
   bool get isMixinApplication;
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 3ab0a44..bacfc87 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -849,14 +849,24 @@
 
 class TypedefElementX extends ElementX implements TypedefElement {
   Typedef cachedNode;
-  TypedefType cachedType;
 
   /**
-   * Canonicalize raw version of [cachedType].
+   * The type of this typedef in which the type arguments are the type
+   * variables.
+   *
+   * This resembles the [ClassElement.thisType] though a typedef has no notion
+   * of [:this:].
+   *
+   * This type is computed in [computeType].
+   */
+  TypedefType thisType;
+
+  /**
+   * Canonicalized raw version of [thisType].
    *
    * See [ClassElement.rawType] for motivation.
    *
-   * The [rawType] is computed together with [cachedType] in [computeType].
+   * The [rawType] is computed together with [thisType] in [computeType].
    */
   TypedefType rawType;
 
@@ -884,13 +894,13 @@
   FunctionSignature functionSignature;
 
   TypedefType computeType(Compiler compiler) {
-    if (cachedType != null) return cachedType;
+    if (thisType != null) return thisType;
     Typedef node = parseNode(compiler);
     Link<DartType> parameters =
         TypeDeclarationElementX.createTypeVariables(this, node.typeParameters);
-    cachedType = new TypedefType(this, parameters);
+    thisType = new TypedefType(this, parameters);
     if (parameters.isEmpty) {
-      rawType = cachedType;
+      rawType = thisType;
     } else {
       var dynamicParameters = const Link<DartType>();
       parameters.forEach((_) {
@@ -900,10 +910,10 @@
       rawType = new TypedefType(this, dynamicParameters);
     }
     compiler.resolveTypedef(this);
-    return cachedType;
+    return thisType;
   }
 
-  Link<DartType> get typeVariables => cachedType.typeArguments;
+  Link<DartType> get typeVariables => thisType.typeArguments;
 
   Scope buildScope() {
     return new TypeDeclarationScope(enclosingElement.buildScope(), this);
@@ -1510,6 +1520,7 @@
   SourceString nativeTagInfo;
   int supertypeLoadState;
   int resolutionState;
+  bool get isResolved => resolutionState == STATE_DONE;
 
   // backendMembers are members that have been added by the backend to simplify
   // compilation. They don't have any user-side counter-part.
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index 22f8351..622c20a 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -117,7 +117,12 @@
       elements.registerDependency(cls);
       cls.ensureResolved(compiler);
       universe.instantiatedTypes.add(type);
-      if (!cls.isAbstract(compiler)) {
+      if (!cls.isAbstract(compiler)
+          // We can't use the closed-world assumption with native abstract
+          // classes; a native abstract class may have non-abstract subclasses
+          // not declared to the program.  Instances of these classes are
+          // indistinguishable from the abstract class.
+          || cls.isNative()) {
         universe.instantiatedClasses.add(cls);
       }
       onRegisterInstantiatedClass(cls);
@@ -131,7 +136,7 @@
 
   void registerTypeLiteral(Element element, TreeElements elements) {
     registerInstantiatedClass(compiler.typeClass, elements);
-    compiler.backend.registerTypeLiteral(element, elements);
+    compiler.backend.registerTypeLiteral(element, this, elements);
   }
 
   bool checkNoEnqueuedInvokedInstanceMethods() {
@@ -495,7 +500,7 @@
 
   void registerAsCheck(DartType type, TreeElements elements) {
     registerIsCheck(type, elements);
-    compiler.backend.registerAsCheck(type, elements);
+    compiler.backend.registerAsCheck(type, this, elements);
   }
 
   void registerGenericCallMethod(Element element, TreeElements elements) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index e834e1a..35e7b10 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -90,7 +90,10 @@
 
     if (type.containsTypeVariables) {
       ClassElement contextClass = Types.getClassContext(type);
-      String contextName = codegen.backend.namer.getName(contextClass);
+      // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
+      // string concatenation in the implementation), and may prevent
+      // segmentation of '$'.
+      String contextName = codegen.backend.namer.getNameForRti(contextClass);
       arguments.add(js.string(contextName));
 
       if (node.contextIsTypeArguments) {
@@ -190,8 +193,8 @@
   Element jsArrayRemoveLast;
   Element jsArrayAdd;
   Element jsStringSplit;
-  Element jsStringConcat;
   Element jsStringToString;
+  Element jsStringOperatorAdd;
   Element objectEquals;
 
   ClassElement typeLiteralClass;
@@ -341,9 +344,76 @@
   /// List of elements that the backend may use.
   final Set<Element> helpersUsed = new Set<Element>();
 
+
   /// Set of typedefs that are used as type literals.
   final Set<TypedefElement> typedefTypeLiterals = new Set<TypedefElement>();
 
+  /// All the checked mode helpers.
+  static const checkedModeHelpers = const [
+      const CheckedModeHelper(const SourceString('voidTypeCheck')),
+      const CheckedModeHelper(const SourceString('stringTypeCast')),
+      const CheckedModeHelper(const SourceString('stringTypeCheck')),
+      const CheckedModeHelper(const SourceString('doubleTypeCast')),
+      const CheckedModeHelper(const SourceString('doubleTypeCheck')),
+      const CheckedModeHelper(const SourceString('numTypeCast')),
+      const CheckedModeHelper(const SourceString('numTypeCheck')),
+      const CheckedModeHelper(const SourceString('boolTypeCast')),
+      const CheckedModeHelper(const SourceString('boolTypeCheck')),
+      const CheckedModeHelper(const SourceString('intTypeCast')),
+      const CheckedModeHelper(const SourceString('intTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('numberOrStringSuperNativeTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('numberOrStringSuperNativeTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('numberOrStringSuperTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('numberOrStringSuperTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('stringSuperNativeTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('stringSuperNativeTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('stringSuperTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('stringSuperTypeCheck')),
+      const CheckedModeHelper(const SourceString('listTypeCast')),
+      const CheckedModeHelper(const SourceString('listTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('listSuperNativeTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('listSuperNativeTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('listSuperTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('listSuperTypeCheck')),
+      const PropertyCheckedModeHelper(
+          const SourceString('interceptedTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('interceptedTypeCheck')),
+      const SubtypeCheckedModeHelper(
+          const SourceString('subtypeCast')),
+      const SubtypeCheckedModeHelper(
+          const SourceString('assertSubtype')),
+      const TypeVariableCheckedModeHelper(
+          const SourceString('subtypeOfRuntimeTypeCast')),
+      const TypeVariableCheckedModeHelper(
+          const SourceString('assertSubtypeOfRuntimeType')),
+      const FunctionTypeCheckedModeHelper(
+          const SourceString('functionSubtypeCast')),
+      const FunctionTypeCheckedModeHelper(
+          const SourceString('assertFunctionSubtype')),
+      const PropertyCheckedModeHelper(
+          const SourceString('propertyTypeCast')),
+      const PropertyCheckedModeHelper(
+          const SourceString('propertyTypeCheck')) ];
+
+  // Checked mode helpers indexed by name.
+  Map<String, CheckedModeHelper> checkedModeHelperByName =
+      new Map<String, CheckedModeHelper>.fromIterable(
+          checkedModeHelpers,
+          key: (helper) => helper.name.slowToString());
+
   JavaScriptBackend(Compiler compiler, bool generateSourceMap, bool disableEval)
       : namer = determineNamer(compiler),
         oneShotInterceptors = new Map<String, Selector>(),
@@ -547,8 +617,8 @@
     jsStringClass.ensureResolved(compiler);
     jsStringSplit = compiler.lookupElementIn(
         jsStringClass, const SourceString('split'));
-    jsStringConcat = compiler.lookupElementIn(
-        jsStringClass, const SourceString('concat'));
+    jsStringOperatorAdd = compiler.lookupElementIn(
+        jsStringClass, const SourceString('+'));
     jsStringToString = compiler.lookupElementIn(
         jsStringClass, const SourceString('toString'));
 
@@ -609,14 +679,16 @@
         Set<Element> set = interceptedElements.putIfAbsent(
             member.name, () => new Set<Element>());
         set.add(member);
-        if (classElement == jsInterceptorClass) return;
-        if (classElement.isMixinApplication) {
-          MixinApplicationElement mixinApplication = classElement;
-          assert(member.getEnclosingClass() == mixinApplication.mixin);
-          classesMixedIntoNativeClasses.add(mixinApplication.mixin);
-        }
       },
       includeSuperAndInjectedMembers: true);
+
+      // Walk superclass chain to find mixins.
+      for (; cls != null; cls = cls.superclass) {
+        if (cls.isMixinApplication) {
+          MixinApplicationElement mixinApplication = cls;
+          classesMixedIntoNativeClasses.add(mixinApplication.mixin);
+        }
+      }
     }
   }
 
@@ -777,6 +849,7 @@
           compiler.findHelper(const SourceString('boolConversionCheck'));
       if (e != null) enqueue(world, e, elements);
     }
+    registerCheckedModeHelpers(elements);
   }
 
   onResolutionComplete() => rti.computeClassesNeedingRti();
@@ -808,7 +881,10 @@
     enqueueInResolution(getCyclicThrowHelper(), elements);
   }
 
-  void registerTypeLiteral(Element element, TreeElements elements) {
+  void registerTypeLiteral(Element element,
+                           Enqueuer enqueuer,
+                           TreeElements elements) {
+    enqueuer.registerInstantiatedClass(typeImplementation, elements);
     enqueueInResolution(getCreateRuntimeType(), elements);
     // TODO(ahe): Might want to register [element] as an instantiated class
     // when reflection is used.  However, as long as we disable tree-shaking
@@ -879,11 +955,21 @@
     // [registerIsCheck] is also called for checked mode checks, so we
     // need to register checked mode helpers.
     if (inCheckedMode) {
-      CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: false);
-      if (helper != null) enqueue(world, helper.getElement(compiler), elements);
-      // We also need the native variant of the check (for DOM types).
-      helper = getNativeCheckedModeHelper(type, typeCast: false);
-      if (helper != null) enqueue(world, helper.getElement(compiler), elements);
+      if (!world.isResolutionQueue) {
+        // All helpers are added to resolution queue in enqueueHelpers. These
+        // calls to enqueueInResolution serve as assertions that the helper was
+        // in fact added.
+        // TODO(13155): Find a way to enqueue helpers lazily.
+        CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: false);
+        if (helper != null) {
+          enqueue(world, helper.getElement(compiler), elements);
+        }
+        // We also need the native variant of the check (for DOM types).
+        helper = getNativeCheckedModeHelper(type, typeCast: false);
+        if (helper != null) {
+          enqueue(world, helper.getElement(compiler), elements);
+        }
+      }
     }
     bool isTypeVariable = type.kind == TypeKind.TYPE_VARIABLE;
     if (!type.isRaw || type.containsTypeVariables) {
@@ -913,16 +999,22 @@
               compiler.findHelper(const SourceString('defineProperty')),
               elements);
     }
-   }
+  }
 
-  void registerAsCheck(DartType type, TreeElements elements) {
+  void registerAsCheck(DartType type, Enqueuer world, TreeElements elements) {
     type = type.unalias(compiler);
-    CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: true);
-    enqueueInResolution(helper.getElement(compiler), elements);
-    // We also need the native variant of the check (for DOM types).
-    helper = getNativeCheckedModeHelper(type, typeCast: true);
-    if (helper != null) {
+    if (!world.isResolutionQueue) {
+      // All helpers are added to resolution queue in enqueueHelpers. These
+      // calls to enqueueInResolution serve as assertions that the helper was in
+      // fact added.
+      // TODO(13155): Find a way to enqueue helpers lazily.
+      CheckedModeHelper helper = getCheckedModeHelper(type, typeCast: true);
       enqueueInResolution(helper.getElement(compiler), elements);
+      // We also need the native variant of the check (for DOM types).
+      helper = getNativeCheckedModeHelper(type, typeCast: true);
+      if (helper != null) {
+        enqueueInResolution(helper.getElement(compiler), elements);
+      }
     }
   }
 
@@ -1172,6 +1264,17 @@
   CheckedModeHelper getCheckedModeHelperInternal(DartType type,
                                                  {bool typeCast,
                                                   bool nativeCheckOnly}) {
+    String name = getCheckedModeHelperNameInternal(type,
+        typeCast: typeCast, nativeCheckOnly: nativeCheckOnly);
+    if (name == null) return null;
+    CheckedModeHelper helper = checkedModeHelperByName[name];
+    assert(helper != null);
+    return helper;
+  }
+
+  String getCheckedModeHelperNameInternal(DartType type,
+                                          {bool typeCast,
+                                           bool nativeCheckOnly}) {
     assert(type.kind != TypeKind.TYPEDEF);
     Element element = type.element;
     bool nativeCheck = nativeCheckOnly ||
@@ -1179,121 +1282,107 @@
     if (type == compiler.types.voidType) {
       assert(!typeCast); // Cannot cast to void.
       if (nativeCheckOnly) return null;
-      return const CheckedModeHelper(const SourceString('voidTypeCheck'));
+      return 'voidTypeCheck';
     } else if (element == jsStringClass || element == compiler.stringClass) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("stringTypeCast"))
-          : const CheckedModeHelper(const SourceString('stringTypeCheck'));
+          ? 'stringTypeCast'
+          : 'stringTypeCheck';
     } else if (element == jsDoubleClass || element == compiler.doubleClass) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("doubleTypeCast"))
-          : const CheckedModeHelper(const SourceString('doubleTypeCheck'));
+          ? 'doubleTypeCast'
+          : 'doubleTypeCheck';
     } else if (element == jsNumberClass || element == compiler.numClass) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("numTypeCast"))
-          : const CheckedModeHelper(const SourceString('numTypeCheck'));
+          ? 'numTypeCast'
+          : 'numTypeCheck';
     } else if (element == jsBoolClass || element == compiler.boolClass) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("boolTypeCast"))
-          : const CheckedModeHelper(const SourceString('boolTypeCheck'));
+          ? 'boolTypeCast'
+          : 'boolTypeCheck';
     } else if (element == jsIntClass || element == compiler.intClass) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("intTypeCast"))
-          : const CheckedModeHelper(const SourceString('intTypeCheck'));
+          ? 'intTypeCast'
+          : 'intTypeCheck';
     } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
       if (nativeCheck) {
         return typeCast
-            ? const PropertyCheckedModeHelper(
-                const SourceString("numberOrStringSuperNativeTypeCast"))
-            : const PropertyCheckedModeHelper(
-                const SourceString('numberOrStringSuperNativeTypeCheck'));
+            ? 'numberOrStringSuperNativeTypeCast'
+            : 'numberOrStringSuperNativeTypeCheck';
       } else {
         return typeCast
-          ? const PropertyCheckedModeHelper(
-              const SourceString("numberOrStringSuperTypeCast"))
-          : const PropertyCheckedModeHelper(
-              const SourceString('numberOrStringSuperTypeCheck'));
+          ? 'numberOrStringSuperTypeCast'
+          : 'numberOrStringSuperTypeCheck';
       }
     } else if (Elements.isStringOnlySupertype(element, compiler)) {
       if (nativeCheck) {
         return typeCast
-            ? const PropertyCheckedModeHelper(
-                const SourceString("stringSuperNativeTypeCast"))
-            : const PropertyCheckedModeHelper(
-                const SourceString('stringSuperNativeTypeCheck'));
+            ? 'stringSuperNativeTypeCast'
+            : 'stringSuperNativeTypeCheck';
       } else {
         return typeCast
-            ? const PropertyCheckedModeHelper(
-                const SourceString("stringSuperTypeCast"))
-            : const PropertyCheckedModeHelper(
-                const SourceString('stringSuperTypeCheck'));
+            ? 'stringSuperTypeCast'
+            : 'stringSuperTypeCheck';
       }
     } else if ((element == compiler.listClass || element == jsArrayClass) &&
                type.isRaw) {
       if (nativeCheckOnly) return null;
       return typeCast
-          ? const CheckedModeHelper(const SourceString("listTypeCast"))
-          : const CheckedModeHelper(const SourceString('listTypeCheck'));
+          ? 'listTypeCast'
+          : 'listTypeCheck';
     } else {
       if (Elements.isListSupertype(element, compiler)) {
         if (nativeCheck) {
           return typeCast
-              ? const PropertyCheckedModeHelper(
-                  const SourceString("listSuperNativeTypeCast"))
-              : const PropertyCheckedModeHelper(
-                  const SourceString('listSuperNativeTypeCheck'));
+              ? 'listSuperNativeTypeCast'
+              : 'listSuperNativeTypeCheck';
         } else {
           return typeCast
-              ? const PropertyCheckedModeHelper(
-                  const SourceString("listSuperTypeCast"))
-              : const PropertyCheckedModeHelper(
-                  const SourceString('listSuperTypeCheck'));
+              ? 'listSuperTypeCast'
+              : 'listSuperTypeCheck';
         }
       } else {
         if (nativeCheck) {
           // TODO(karlklose): can we get rid of this branch when we use
           // interceptors?
           return typeCast
-              ? const PropertyCheckedModeHelper(
-                  const SourceString("interceptedTypeCast"))
-              : const PropertyCheckedModeHelper(
-                  const SourceString('interceptedTypeCheck'));
+              ? 'interceptedTypeCast'
+              : 'interceptedTypeCheck';
         } else {
           if (type.kind == TypeKind.INTERFACE && !type.isRaw) {
             return typeCast
-                ? const SubtypeCheckedModeHelper(
-                    const SourceString('subtypeCast'))
-                : const SubtypeCheckedModeHelper(
-                    const SourceString('assertSubtype'));
+                ? 'subtypeCast'
+                : 'assertSubtype';
           } else if (type.kind == TypeKind.TYPE_VARIABLE) {
             return typeCast
-                ? const TypeVariableCheckedModeHelper(
-                    const SourceString('subtypeOfRuntimeTypeCast'))
-                : const TypeVariableCheckedModeHelper(
-                    const SourceString('assertSubtypeOfRuntimeType'));
+                ? 'subtypeOfRuntimeTypeCast'
+                : 'assertSubtypeOfRuntimeType';
           } else if (type.kind == TypeKind.FUNCTION) {
             return typeCast
-                ? const FunctionTypeCheckedModeHelper(
-                    const SourceString('functionSubtypeCast'))
-                : const FunctionTypeCheckedModeHelper(
-                    const SourceString('assertFunctionSubtype'));
+                ? 'functionSubtypeCast'
+                : 'assertFunctionSubtype';
           } else {
             return typeCast
-                ? const PropertyCheckedModeHelper(
-                    const SourceString('propertyTypeCast'))
-                : const PropertyCheckedModeHelper(
-                    const SourceString('propertyTypeCheck'));
+                ? 'propertyTypeCast'
+                : 'propertyTypeCheck';
           }
         }
       }
     }
   }
 
+  void registerCheckedModeHelpers(TreeElements elements) {
+    // We register all the helpers in the resolution queue.
+    // TODO(13155): Find a way to register fewer helpers.
+    for (CheckedModeHelper helper in checkedModeHelpers) {
+      enqueueInResolution(helper.getElement(compiler), elements);
+    }
+  }
+
   /**
    * Returns [:true:] if the checking of [type] is performed directly on the
    * object and not on an interceptor.
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index ae5c1f0..9ed0647 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -277,10 +277,7 @@
   JavaScriptBackend get backend => compiler.backend;
 
   jsAst.PropertyAccess getHelperProperty(Element helper) {
-    String helperName = backend.namer.getName(helper);
-    return new jsAst.PropertyAccess.field(
-        new jsAst.VariableUse(namer.CURRENT_ISOLATE),
-        helperName);
+    return backend.namer.elementAccess(helper);
   }
 
   jsAst.Expression visitType(TypeConstant constant) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 3118874..8804282 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -4,6 +4,9 @@
 
 part of js_backend;
 
+/// Enables debugging of fast/slow objects using V8-specific primitives.
+const DEBUG_FAST_OBJECTS = false;
+
 /**
  * A function element that represents a closure call. The signature is copied
  * from the given element.
@@ -584,7 +587,7 @@
     // Startup code that loops over the method names and puts handlers on the
     // Object class to catch noSuchMethod invocations.
     ClassElement objectClass = compiler.objectClass;
-    String createInvocationMirror = namer.getName(
+    String createInvocationMirror = namer.isolateAccess(
         backend.getCreateInvocationMirror());
     String noSuchMethodName = namer.publicInstanceMethodNameByArity(
         Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
@@ -592,11 +595,13 @@
     if (useDiffEncoding) {
       statements.addAll([
         js('var objectClassObject = '
-           '        collectedClasses["${namer.getName(objectClass)}"],'
+           '        collectedClasses["${namer.getNameOfClass(objectClass)}"],'
            '    shortNames = "$diffEncoding".split(","),'
            '    nameNumber = 0,'
            '    diffEncodedString = shortNames[0],'
            '    calculatedShortNames = [0, 1]'),  // 0, 1 are args for splice.
+        js.if_('objectClassObject instanceof Array',
+               js('objectClassObject = objectClassObject[1]')),
         js.for_('var i = 0', 'i < diffEncodedString.length', 'i++', [
           js('var codes = [],'
              '    diff = 0,'
@@ -631,9 +636,12 @@
           ',longNames = "${longs.join(",")}".split(",")';
       statements.add(
         js('var objectClassObject = '
-           '        collectedClasses["${namer.getName(objectClass)}"],'
+           '        collectedClasses["${namer.getNameOfClass(objectClass)}"],'
            '    shortNames = "$diffEncoding".split(",")'
            '    $longNamesConstant'));
+      statements.add(
+          js.if_('objectClassObject instanceof Array',
+                 js('objectClassObject = objectClassObject[1]')));
     }
 
     String sliceOffset = ', (j < $firstNormalSelector) ? 1 : 0';
@@ -666,7 +674,7 @@
                [js.return_(js(
                    'this.$noSuchMethodName('
                        'this, '
-                       '${namer.CURRENT_ISOLATE}.$createInvocationMirror('
+                       '$createInvocationMirror('
                            'name, short, type, '
                            '$slice(arguments$sliceOffsetParam), []))'))]))]))
       ])
@@ -689,12 +697,24 @@
 
     List<jsAst.Node> statements = [
       js('var pendingClasses = {}'),
+      js.if_('!init.allClasses', js('init.allClasses = {}')),
+      js('var allClasses = init.allClasses'),
 
       js('var hasOwnProperty = Object.prototype.hasOwnProperty'),
 
+      optional(
+          DEBUG_FAST_OBJECTS,
+          js('print("Number of classes: "'
+             r' + Object.getOwnPropertyNames($$).length)')),
+
       js.forIn('cls', 'collectedClasses', [
         js.if_('hasOwnProperty.call(collectedClasses, cls)', [
           js('var desc = collectedClasses[cls]'),
+          js('var globalObject = isolateProperties'),
+          js.if_('desc instanceof Array', [
+              js('globalObject = desc[0] || isolateProperties'),
+              js('desc = desc[1]')
+          ]),
 
           /* The 'fields' are either a constructor function or a
            * string encoding fields, constructor and superclass.  Get
@@ -733,6 +753,7 @@
             js('s = supr.split("+")'),
             js('supr = s[0]'),
             js('var mixin = collectedClasses[s[1]]'),
+            js.if_('mixin instanceof Array', js('mixin = mixin[1]')),
             js.forIn('d', 'mixin', [
               js.if_('hasOwnProperty.call(mixin, d)'
                      '&& !hasOwnProperty.call(desc, d)',
@@ -743,7 +764,8 @@
           js('var constructor = defineClass(name, cls, fields, desc)'),
           optional(backend.isTreeShakingDisabled,
                    js('constructor["${namer.metadataField}"] = desc')),
-          js('isolateProperties[cls] = constructor'),
+          js('allClasses[cls] = constructor'),
+          js('globalObject[cls] = constructor'),
           js.if_('supr', js('pendingClasses[cls] = supr'))
         ])
       ]),
@@ -792,8 +814,8 @@
       // we have a string.
       js.if_('!superclass || typeof superclass != "string"', js.return_()),
       js('finishClass(superclass)'),
-      js('var constructor = isolateProperties[cls]'),
-      js('var superConstructor = isolateProperties[superclass]'),
+      js('var constructor = allClasses[cls]'),
+      js('var superConstructor = allClasses[superclass]'),
 
       js.if_(js('!superConstructor'),
              js('superConstructor ='
@@ -888,10 +910,6 @@
 
       js('str += "}\\n"'),
 
-      js('var Constants = #', js.fun('', [])),
-      // Install 'C' as a prototype to ensure it has a hidden class.
-      js('Constants.prototype = ${namer.globalObjectForConstant(null)}'),
-
       js('var newIsolate = new Function(str)'),
       js('newIsolate.prototype = isolatePrototype'),
       js('isolatePrototype.constructor = newIsolate'),
@@ -907,8 +925,6 @@
   }
 
   jsAst.Fun get lazyInitializerFunction {
-    String isolate = namer.CURRENT_ISOLATE;
-
     // function(prototype, staticName, fieldName, getterName, lazyValue) {
     var parameters = <String>['prototype', 'staticName', 'fieldName',
                               'getterName', 'lazyValue'];
@@ -1103,7 +1119,8 @@
           parametersBuffer, argumentsBuffer,
           indexOfLastOptionalArgumentInParameters);
     } else {
-      body = [js.return_(js('this')[namer.getName(member)](argumentsBuffer))];
+      body = [js.return_(
+          js('this')[namer.getNameOfInstanceMember(member)](argumentsBuffer))];
     }
 
     jsAst.Fun function = js.fun(parametersBuffer, body);
@@ -1270,7 +1287,7 @@
       if (member.isAbstract(compiler)) return;
       jsAst.Expression code = backend.generatedCode[member];
       if (code == null) return;
-      String name = namer.getName(member);
+      String name = namer.getNameOfInstanceMember(member);
       if (backend.isInterceptedMethod(member)) {
         interceptorInvocationNames.add(name);
       }
@@ -1490,6 +1507,7 @@
   }
 
   void emitRuntimeTypeSupport(CodeBuffer buffer) {
+    addComment('Runtime type support', buffer);
     RuntimeTypes rti = backend.rti;
     TypeChecks typeChecks = rti.requiredChecks;
 
@@ -1612,7 +1630,7 @@
           || needsSetter) {
         String accessorName = isShadowed
             ? namer.shadowedFieldName(field)
-            : namer.getName(field);
+            : namer.getNameOfField(field);
         String fieldName = field.hasFixedBackendName()
             ? field.fixedBackendName()
             : (isMixinNativeField ? name.slowToString() : accessorName);
@@ -1952,18 +1970,18 @@
     assert(invariant(classElement, !classElement.isNative() || onlyForRti));
 
     needsDefineClass = true;
-    String className = namer.getName(classElement);
+    String className = namer.getNameOfClass(classElement);
 
     ClassElement superclass = classElement.superclass;
     String superName = "";
     if (superclass != null) {
-      superName = namer.getName(superclass);
+      superName = namer.getNameOfClass(superclass);
     }
     String runtimeName =
         namer.getPrimitiveInterceptorRuntimeName(classElement);
 
     if (classElement.isMixinApplication) {
-      String mixinName = namer.getName(computeMixinClass(classElement));
+      String mixinName = namer.getNameOfClass(computeMixinClass(classElement));
       superName = '$superName+$mixinName';
       needsMixinSupport = true;
     }
@@ -2332,7 +2350,7 @@
     for (Element element in Elements.sortedByPosition(elements)) {
       CodeBuffer buffer = bufferForElement(element, eagerBuffer);
       jsAst.Expression code = backend.generatedCode[element];
-      String name = namer.getName(element);
+      String name = namer.getNameOfGlobalFunction(element);
       code = extendWithMetadata(element, code);
       emitStaticFunction(buffer, name, code);
       String reflectionName = getReflectionName(element, name);
@@ -2362,17 +2380,20 @@
   final Map<Element, Element> staticGetters = new Map<Element, Element>();
 
   void emitStaticFunctionGetters(CodeBuffer eagerBuffer) {
+    addComment('Static function getters', mainBuffer);
     for (FunctionElement element in
              Elements.sortedByPosition(staticGetters.keys)) {
       Element closure = staticGetters[element];
       CodeBuffer buffer = isDeferred(element) ? deferredConstants : eagerBuffer;
       String closureClass = namer.isolateAccess(closure);
       String name = namer.getStaticClosureName(element);
-      String staticName = namer.getName(element);
 
       String closureName = namer.getStaticClosureName(element);
-      jsAst.Node assignment = js('$isolateProperties.$name = '
-          'new $closureClass($isolateProperties.$staticName, "$closureName")');
+      jsAst.Node assignment = js(
+          'init.globalFunctions["$closureName"] ='
+          ' ${namer.globalObjectFor(element)}.$name ='
+          ' new $closureClass(#, "$closureName")',
+          namer.elementAccess(element));
       buffer.write(jsAst.prettyPrint(assignment, compiler));
       buffer.write('$N');
     }
@@ -2383,8 +2404,7 @@
         compiler.codegenWorld.staticFunctionsNeedingGetter;
     for (FunctionElement element in
              Elements.sortedByPosition(functionsNeedingGetter)) {
-      String staticName = namer.getName(element);
-      String superName = namer.getName(compiler.closureClass);
+      String superName = namer.getNameOfClass(compiler.closureClass);
       String name = 'Closure\$${element.name.slowToString()}';
       assert(instantiatedClasses.contains(compiler.closureClass));
 
@@ -2400,7 +2420,7 @@
                                        element);
 
       String invocationName = namer.instanceMethodName(callElement);
-      String mangledName = namer.getName(closureClassElement);
+      String mangledName = namer.getNameOfClass(closureClassElement);
 
       // Define the constructor with a name so that Object.toString can
       // find the class name of the closure class.
@@ -2418,7 +2438,8 @@
       // closures, and static closures that have common type checks.
       boundClosures.add(
           js('$classesCollector.$mangledName = #',
-              closureBuilder.toObjectInitializer()));
+             js('[${namer.globalObjectFor(closureClassElement)}, #]',
+                closureBuilder.toObjectInitializer())));
 
       staticGetters[element] = closureClassElement;
 
@@ -2497,7 +2518,7 @@
     }
     List<String> fieldNames = <String>[];
     compiler.boundClosureClass.forEachInstanceField((_, Element field) {
-      fieldNames.add(namer.getName(field));
+      fieldNames.add(namer.getNameOfInstanceMember(field));
     });
 
     DartType memberType = member.computeType(compiler);
@@ -2527,8 +2548,8 @@
       ClassElement closureClassElement = new ClosureClassElement(
           null, new SourceString(name), compiler, member,
           member.getCompilationUnit());
-      String mangledName = namer.getName(closureClassElement);
-      String superName = namer.getName(closureClassElement.superclass);
+      String mangledName = namer.getNameOfClass(closureClassElement);
+      String superName = namer.getNameOfClass(closureClassElement.superclass);
 
       // Define the constructor with a name so that Object.toString can
       // find the class name of the closure class.
@@ -2582,7 +2603,8 @@
 
       boundClosures.add(
           js('$classesCollector.$mangledName = #',
-              boundClosureBuilder.toObjectInitializer()));
+             js('[${namer.globalObjectFor(closureClassElement)}, #]',
+                boundClosureBuilder.toObjectInitializer())));
 
       closureClass = namer.isolateAccess(closureClassElement);
 
@@ -2693,7 +2715,7 @@
       compiler.withCurrentElement(element, () {
         Constant initialValue = handler.getInitialValueFor(element);
         jsAst.Expression init =
-          js('$isolateProperties.${namer.getName(element)} = #',
+          js('$isolateProperties.${namer.getNameOfGlobalField(element)} = #',
               constantEmitter.referenceInInitializationContext(initialValue));
         buffer.write(jsAst.prettyPrint(init, compiler));
         buffer.write('$N');
@@ -2722,7 +2744,7 @@
         List<jsAst.Expression> arguments = <jsAst.Expression>[];
         arguments.add(js(isolateProperties));
         arguments.add(js.string(element.name.slowToString()));
-        arguments.add(js.string(namer.getName(element)));
+        arguments.add(js.string(namer.getNameX(element)));
         arguments.add(js.string(namer.getLazyInitializerName(element)));
         arguments.add(code);
         jsAst.Expression getter = buildLazyInitializedGetter(element);
@@ -2746,7 +2768,6 @@
     List<Constant> constants = handler.getConstantsForEmission(
         compareConstants);
     bool addedMakeConstantList = false;
-    eagerBuffer.write('var ${namer.globalObjectForConstant(null)}$_=$_{}$N');
     for (Constant constant in constants) {
       if (isConstantInlinedOrAlreadyEmitted(constant)) continue;
       String name = namer.constantName(constant);
@@ -2847,10 +2868,6 @@
     String noSuchMethodName = namer.publicInstanceMethodNameByArity(
         Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
 
-    Element createInvocationMirrorElement = backend.getCreateInvocationMirror();
-    String createInvocationMirrorName =
-        namer.getName(createInvocationMirrorElement);
-
     // Keep track of the JavaScript names we've already added so we
     // do not introduce duplicates (bad for code size).
     Map<String, Selector> addedJsNames = new Map<String, Selector>();
@@ -2909,13 +2926,10 @@
         return null;
       }
 
-      String createInvocationMirror = namer.getName(
-          backend.getCreateInvocationMirror());
-
       assert(backend.isInterceptedName(Compiler.NO_SUCH_METHOD));
       jsAst.Expression expression = js('this.$noSuchMethodName')(
           [js('this'),
-           js(namer.CURRENT_ISOLATE)[createInvocationMirror]([
+           namer.elementAccess(backend.getCreateInvocationMirror())([
                js.string(compiler.enableMinification ?
                          internalName : methodName),
                js.string(internalName),
@@ -2948,7 +2962,6 @@
                            Element appMain,
                            Element isolateMain) {
     String mainAccess = "${namer.isolateStaticClosureAccess(appMain)}";
-    String currentIsolate = "${namer.CURRENT_ISOLATE}";
     // Since we pass the closurized version of the main method to
     // the isolate method, we must make sure that it exists.
     return "${namer.isolateAccess(isolateMain)}($mainAccess)";
@@ -3016,12 +3029,6 @@
 })(function(currentScript) {
   init.currentScript = currentScript;
 
-  if (typeof console !== "undefined" && typeof document !== "undefined" &&
-      document.readyState == "loading") {
-    console.warn("Dart script executed synchronously, use <script src='" +
-        currentScript.src + "' defer></scr" + "ipt> to execute after parsing " +
-        "has completed. See also http://dartbug.com/12281.");
-  }
   if (typeof dartMainRunner === "function") {
     dartMainRunner(function() { ${mainCall}; });
   } else {
@@ -3189,7 +3196,8 @@
     }
 
     buffer.write(jsAst.prettyPrint(
-        js('$isolateProperties.$key = #', js.fun(['receiver'], block)),
+        js('${namer.globalObjectFor(compiler.interceptorsLibrary)}.$key = #',
+           js.fun(['receiver'], block)),
         compiler));
     buffer.write(N);
   }
@@ -3198,6 +3206,7 @@
    * Emit all versions of the [:getInterceptor:] method.
    */
   void emitGetInterceptorMethods(CodeBuffer buffer) {
+    addComment('getInterceptor methods', buffer);
     Map<String, Set<ClassElement>> specializedGetInterceptors =
         backend.specializedGetInterceptors;
     for (String name in specializedGetInterceptors.keys.toList()..sort()) {
@@ -3519,12 +3528,13 @@
       }
 
       String invocationName = backend.namer.invocationName(selector);
+      String globalObject = namer.globalObjectFor(compiler.interceptorsLibrary);
       body.add(js.return_(
-          js(isolateProperties)[getInterceptorName]('receiver')[invocationName](
+          js(globalObject)[getInterceptorName]('receiver')[invocationName](
               arguments)));
 
       jsAst.Expression assignment =
-          js('$isolateProperties.$name = #', js.fun(parameters, body));
+          js('${globalObject}.$name = #', js.fun(parameters, body));
 
       buffer.write(jsAst.prettyPrint(assignment, compiler));
       buffer.write(N);
@@ -3543,7 +3553,10 @@
     // compile time, it can be generated automatically at runtime given
     // subclasses of Interceptor (which can easily be identified).
     if (!compiler.enabledInvokeOn) return;
-    String name = backend.namer.getName(backend.interceptedNames);
+
+    // TODO(ahe): We should roll this into
+    // [emitStaticNonFinalFieldInitializations].
+    String name = backend.namer.getNameOfGlobalField(backend.interceptedNames);
 
     int index = 0;
     var invocationNames = interceptorInvocationNames.toList()..sort();
@@ -3585,7 +3598,8 @@
     }
 
     jsAst.ArrayInitializer array = new jsAst.ArrayInitializer.from(elements);
-    String name = backend.namer.getName(backend.mapTypeToInterceptor);
+    String name =
+        backend.namer.getNameOfGlobalField(backend.mapTypeToInterceptor);
     jsAst.Expression assignment = js('$isolateProperties.$name = #', array);
 
     buffer.write(jsAst.prettyPrint(assignment, compiler));
@@ -3696,7 +3710,7 @@
     Elements.sortedByPosition(literals);
     var properties = [];
     for (TypedefElement literal in literals) {
-      var key = namer.getName(literal);
+      var key = namer.getNameX(literal);
       var value = js.toExpression(reifyType(literal.rawType));
       properties.add(new jsAst.Property(js.string(key), value));
     }
@@ -3718,6 +3732,26 @@
     buffer.write('];$n');
   }
 
+  void emitConvertToFastObjectFunction() {
+    mainBuffer.add(r'''
+function convertToFastObject(properties) {
+  function makeConstructor() {
+    var str = "{\n";
+    var hasOwnProperty = Object.prototype.hasOwnProperty;
+    for (var property in properties) {
+      if (hasOwnProperty.call(properties, property)) {
+        str += "this." + property + "= properties." + property + ";\n";
+      }
+    }
+    str += "}\n";
+    return new Function("properties", str);
+  };
+  var constructor = makeConstructor();
+  return makeConstructor.prototype = new constructor(properties);
+}
+''');
+  }
+
   String assembleProgram() {
     measure(() {
       // Compute the required type checks to know which classes need a
@@ -3733,6 +3767,17 @@
         mainBuffer.add('(function(${namer.CURRENT_ISOLATE})$_{$n');
       }
 
+      for (String globalObject in Namer.reservedGlobalObjectNames) {
+        // The global objects start as so-called "slow objects". For V8, this
+        // means that it won't try to make map transitions as we add properties
+        // to these objects. Later on, we attempt to turn these objects into
+        // fast objects by calling "convertToFastObject" (see
+        // [emitConvertToFastObjectFunction]).
+        mainBuffer
+            ..write('var ${globalObject}$_=$_{}$N')
+            ..write('delete ${globalObject}.x$N');
+      }
+
       mainBuffer.add('function ${namer.isolateName}()$_{}\n');
       mainBuffer.add('init()$N$n');
       // Shorten the code by using [namer.CURRENT_ISOLATE] as temporary.
@@ -3894,6 +3939,8 @@
                 ..write(metadata == null
                         ? "" : jsAst.prettyPrint(metadata, compiler))
                 ..write(',$_')
+                ..write(namer.globalObjectFor(library))
+                ..write(',$_')
                 ..write('{$n')
                 ..addBuffer(buffer)
                 ..write('}');
@@ -3908,6 +3955,8 @@
                 ..write('["${library.getLibraryOrScriptName()}",$_')
                 ..write('"${uri}",$_')
                 ..write('[],$_')
+                ..write(namer.globalObjectFor(library))
+                ..write(',$_')
                 ..write('{$n')
                 ..addBuffer(buffer)
                 ..write('}],$n');
@@ -3952,6 +4001,53 @@
       mainBuffer.add(
           '${namer.CURRENT_ISOLATE}$_=${_}new ${namer.isolateName}()$N');
 
+      emitConvertToFastObjectFunction();
+      for (String globalObject in Namer.reservedGlobalObjectNames) {
+        mainBuffer.add('$globalObject = convertToFastObject($globalObject)$N');
+      }
+      if (DEBUG_FAST_OBJECTS) {
+        ClassElement primitives =
+            compiler.findHelper(const SourceString('Primitives'));
+        FunctionElement printHelper =
+            compiler.lookupElementIn(
+                primitives, const SourceString('printString'));
+        String printHelperName = namer.isolateAccess(printHelper);
+
+        mainBuffer.add('''
+// The following only works on V8 when run with option "--allow-natives-syntax".
+if (typeof $printHelperName === "function") {
+  $printHelperName("Size of global helper object: "
+                   + String(Object.getOwnPropertyNames(H).length)
+                   + ", fast properties " + %HasFastProperties(H));
+  $printHelperName("Size of global platform object: "
+                   + String(Object.getOwnPropertyNames(P).length)
+                   + ", fast properties " + %HasFastProperties(P));
+  $printHelperName("Size of global dart:html object: "
+                   + String(Object.getOwnPropertyNames(W).length)
+                   + ", fast properties " + %HasFastProperties(W));
+  $printHelperName("Size of isolate properties object: "
+                   + String(Object.getOwnPropertyNames(\$).length)
+                   + ", fast properties " + %HasFastProperties(\$));
+  $printHelperName("Size of constant object: "
+                   + String(Object.getOwnPropertyNames(C).length)
+                   + ", fast properties " + %HasFastProperties(C));
+  var names = Object.getOwnPropertyNames(\$);
+  for (var i = 0; i < names.length; i++) {
+    $printHelperName("\$." + names[i]);
+  }
+}
+''');
+        for (String object in Namer.userGlobalObjects) {
+        mainBuffer.add('''
+if (typeof $printHelperName === "function") {
+  $printHelperName("Size of $object: "
+                   + String(Object.getOwnPropertyNames($object).length)
+                   + ", fast properties " + %HasFastProperties($object));
+}
+''');
+        }
+      }
+
       emitMain(mainBuffer);
       emitInitFunction(mainBuffer);
       if (!areAnyElementsDeferred) {
@@ -4119,6 +4215,7 @@
   if (!init.mangledGlobalNames) init.mangledGlobalNames = map();
   if (!init.statics) init.statics = map();
   if (!init.interfaces) init.interfaces = map();
+  if (!init.globalFunctions) init.globalFunctions = map();
   var libraries = init.libraries;
   var mangledNames = init.mangledNames;
   var mangledGlobalNames = init.mangledGlobalNames;
@@ -4131,8 +4228,9 @@
 // 0. The library name (not unique).
 // 1. The library URI (unique).
 // 2. A function returning the metadata associated with this library.
-// 3. An object literal listing the members of the library.
-// 4. This element is optional and if present it is true and signals that this
+// 3. The global object to use for this library.
+// 4. An object literal listing the members of the library.
+// 5. This element is optional and if present it is true and signals that this
 // library is the root library (see dart:mirrors IsolateMirror.rootLibrary).
 //
 // The entries of [data] are built in [assembleProgram] above.
@@ -4140,8 +4238,9 @@
     var name = data[0];
     var uri = data[1];
     var metadata = data[2];
-    var descriptor = data[3];
-    var isRoot = !!data[4];
+    var globalObject = data[3];
+    var descriptor = data[4];
+    var isRoot = !!data[5];
     var fields = descriptor && descriptor[""];
     var classes = [];
     var functions = [];
@@ -4162,8 +4261,9 @@
           property = property.substring(1);
           ${namer.CURRENT_ISOLATE}[property][$metadataField] = element;
         } else if (typeof element === "function") {
-          ${namer.CURRENT_ISOLATE}[previousProperty = property] = element;
+          globalObject[previousProperty = property] = element;
           functions.push(property);
+          init.globalFunctions[property] = element;
         } else {
           previousProperty = property;
           var newDesc = {};
@@ -4183,13 +4283,14 @@
               newDesc[previousProp = prop] = element[prop];
             }
           }
-          $classesCollector[property] = newDesc;
+          $classesCollector[property] = [globalObject, newDesc];
           classes.push(property);
         }
       }
     }
     processStatics(descriptor);
-    libraries.push([name, uri, classes, functions, metadata, fields, isRoot]);
+    libraries.push([name, uri, classes, functions, metadata, fields, isRoot,
+                    globalObject]);
   }
 })''';
   }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
index ff65688..ae6c90e 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
@@ -113,9 +113,7 @@
   }
 
   jsAst.Expression buildLazyInitializedGetter(VariableElement element) {
-    String isolate = namer.CURRENT_ISOLATE;
-    String name = namer.getName(element);
-    return js.fun([], js.return_(js('$isolate.$name')));
+    return js.fun([], js.return_(namer.elementAccess(element)));
   }
 
   jsAst.Fun get lazyInitializerFunction {
@@ -154,4 +152,34 @@
       js('Isolate.${namer.isolatePropertiesName} = isolateProperties'),
       js.return_('Isolate')]);
   }
+
+  void emitConvertToFastObjectFunction() {
+    // Create an instance that uses 'properties' as prototype. This should make
+    // 'properties' a fast object.
+    mainBuffer.add(r'''function convertToFastObject(properties) {
+  function MyClass() {};
+  MyClass.prototype = properties;
+  new MyClass();
+''');
+    if (DEBUG_FAST_OBJECTS) {
+      ClassElement primitives =
+          compiler.findHelper(const SourceString('Primitives'));
+      FunctionElement printHelper =
+          compiler.lookupElementIn(
+              primitives, const SourceString('printString'));
+      String printHelperName = namer.isolateAccess(printHelper);
+      mainBuffer.add('''
+// The following only works on V8 when run with option "--allow-natives-syntax".
+if (typeof $printHelperName === "function") {
+  $printHelperName("Size of global object: "
+                   + String(Object.getOwnPropertyNames(properties).length)
+                   + ", fast properties " + %HasFastProperties(properties));
+}
+''');
+    }
+mainBuffer.add(r'''
+  return properties;
+}
+''');
+  }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index cfb179c..10c423d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -146,11 +146,44 @@
     // next-generation plugin, this results in starting a new Java process.
     "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass",
     "JavaArray", "JavaMember",
-
-    // Global object for constants.
-    "C",
   ];
 
+  static const reservedGlobalObjectNames = const <String>[
+      "A",
+      "B",
+      "C", // Global object for *C*onstants.
+      "D",
+      "E",
+      "F",
+      "G",
+      "H", // Global object for internal (*H*elper) libraries.
+      // I is used for used for the Isolate function.
+      "J", // Global object for the interceptor library.
+      "K",
+      "L",
+      "M",
+      "N",
+      "O",
+      "P", // Global object for other *P*latform libraries.
+      "Q",
+      "R",
+      "S",
+      "T",
+      "U",
+      "V",
+      "W", // Global object for *W*eb libraries (dart:html).
+      "X",
+      "Y",
+      "Z",
+  ];
+
+  static final userGlobalObjects = new List.from(reservedGlobalObjectNames)
+      ..remove('C')
+      ..remove('H')
+      ..remove('J')
+      ..remove('P')
+      ..remove('W');
+
   Set<String> _jsReserved = null;
   /// Names that cannot be used by members, top level and static
   /// methods.
@@ -171,6 +204,9 @@
       _jsVariableReserved.addAll(javaScriptKeywords);
       _jsVariableReserved.addAll(reservedPropertySymbols);
       _jsVariableReserved.addAll(reservedGlobalSymbols);
+      _jsVariableReserved.addAll(reservedGlobalObjectNames);
+      // 26 letters in the alphabet, 25 not counting I.
+      assert(reservedGlobalObjectNames.length == 25);
     }
     return _jsVariableReserved;
   }
@@ -324,7 +360,7 @@
 
     // If a library name does not start with the [LIBRARY_PREFIX] then our
     // assumptions about clashing with mangled private members do not hold.
-    String libraryName = getName(library);
+    String libraryName = getNameOfLibrary(library);
     assert(shouldMinify || libraryName.startsWith(LIBRARY_PREFIX));
     // TODO(erikcorry): Fix this with other manglings to avoid clashes.
     return '_lib$libraryName\$$nameString';
@@ -425,8 +461,8 @@
     // classes.
     assert (!fieldElement.hasFixedBackendName());
 
-    String libraryName = getName(fieldElement.getLibrary());
-    String className = getName(fieldElement.getEnclosingClass());
+    String libraryName = getNameOfLibrary(fieldElement.getLibrary());
+    String className = getNameOfClass(fieldElement.getEnclosingClass());
     String instanceName = instanceFieldName(fieldElement);
     return getMappedInstanceName('$libraryName\$$className\$$instanceName');
   }
@@ -591,7 +627,7 @@
       // If the base Interceptor class is in the set of intercepted classes, we
       // need to go through the generic getInterceptorMethod, since any subclass
       // of the base Interceptor could match.
-      return getName(element);
+      return getNameOfInstanceMember(element);
     }
     String suffix = getInterceptorSuffix(classes);
     return getMappedGlobalName("${element.name.slowToString()}\$$suffix");
@@ -630,7 +666,7 @@
     // are minifying, but it doesn't really make much difference.  The
     // important thing is that it is a unique name.  We add $bailout and, if we
     // are minifying, we minify the minified name and '$bailout'.
-    String unminifiedName = '${getName(element)}\$bailout';
+    String unminifiedName = '${getNameX(element)}\$bailout';
     if (global) {
       name = getMappedGlobalName(unminifiedName);
     } else {
@@ -657,10 +693,14 @@
 
   /// Returns the runtime name for [element].  The result is not safe as an id.
   String getRuntimeTypeName(Element element) {
+    if (identical(element, compiler.dynamicClass)) return 'dynamic';
     JavaScriptBackend backend = compiler.backend;
     element = backend.getImplementationClass(element);
     String name = getPrimitiveInterceptorRuntimeName(element);
-    return name != null ? name : getName(element);
+    // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
+    // string concatenation in the implementation), and may prevent
+    // segmentation of '$'.
+    return name != null ? name : getNameForRti(element);
   }
 
   /**
@@ -694,7 +734,9 @@
    * For accessing statics consider calling
    * [isolateAccess]/[isolateBailoutAccess] or [isolatePropertyAccess] instead.
    */
-  String getName(Element element) {
+  // TODO(ahe): This is an internal method to the Namer (and its subclasses)
+  // and should not be call from outside.
+  String getNameX(Element element) {
     if (element.isInstanceMember()) {
       if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY
           || element.kind == ElementKind.FUNCTION) {
@@ -750,35 +792,84 @@
     }
   }
 
+  String getNameForRti(Element element) => getNameX(element);
+
+  String getNameOfLibrary(LibraryElement library) => getNameX(library);
+
+  String getNameOfClass(ClassElement cls) => getNameX(cls);
+
+  String getNameOfField(VariableElement field) => getNameX(field);
+
+  String getNameOfInstanceMember(Element member) => getNameX(member);
+
+  String getNameOfGlobalField(VariableElement field) => getNameX(field);
+
+  String getNameOfGlobalFunction(FunctionElement element) => getNameX(element);
+
+  /// Returns true if [element] is stored on CURRENT_ISOLATE ('$').  We intend
+  /// to store only mutable static state in [CURRENT_ISOLATE], constants are
+  /// stored in 'C', and functions, accessors, classes, etc. are stored in one
+  /// of the other objects in [reservedGlobalObjectNames].
+  bool isPropertyOfCurrentIsolate(Element element) {
+    // TODO(ahe): Make sure this method's documentation is always true and
+    // remove the word "intend".
+    return
+        // TODO(ahe): Re-write these tests to be positive (so it only returns
+        // true for static/top-level mutable fields). Right now, a number of
+        // other elements, such as bound closures also live in CURRENT_ISOLATE.
+        !element.isAccessor() &&
+        !element.isClass() &&
+        !element.isConstructor() &&
+        !element.isFunction() &&
+        !element.isLibrary();
+  }
+
+  /// Returns [CURRENT_ISOLATE] or one of [reservedGlobalObjectNames].
+  String globalObjectFor(Element element) {
+    if (isPropertyOfCurrentIsolate(element)) return CURRENT_ISOLATE;
+    LibraryElement library = element.getLibrary();
+    if (library == compiler.interceptorsLibrary) return 'J';
+    if (library.isInternalLibrary) return 'H';
+    if (library.isPlatformLibrary) {
+      if ('${library.canonicalUri}' == 'dart:html') return 'W';
+      return 'P';
+    }
+    return userGlobalObjects[
+        library.getLibraryOrScriptName().hashCode % userGlobalObjects.length];
+  }
+
+  jsAst.PropertyAccess elementAccess(Element element) {
+    String name = getNameX(element);
+    return new jsAst.PropertyAccess.field(
+        new jsAst.VariableUse(globalObjectFor(element)),
+        name);
+  }
+
   String getLazyInitializerName(Element element) {
     assert(Elements.isStaticOrTopLevelField(element));
-    return getMappedGlobalName("$getterPrefix${getName(element)}");
+    return getMappedGlobalName("$getterPrefix${getNameX(element)}");
   }
 
   String getStaticClosureName(Element element) {
     assert(Elements.isStaticOrTopLevelFunction(element));
-    return getMappedGlobalName("${getName(element)}\$closure");
-  }
-
-  String isolatePropertiesAccess(Element element) {
-    return "$isolateName.$isolatePropertiesName.${getName(element)}";
+    return getMappedGlobalName("${getNameX(element)}\$closure");
   }
 
   String isolateAccess(Element element) {
-    return "$CURRENT_ISOLATE.${getName(element)}";
+    return "${globalObjectFor(element)}.${getNameX(element)}";
   }
 
   String isolateBailoutAccess(Element element) {
-    String newName = getMappedGlobalName('${getName(element)}\$bailout');
-    return '$CURRENT_ISOLATE.$newName';
+    String newName = getMappedGlobalName('${getNameX(element)}\$bailout');
+    return '${globalObjectFor(element)}.$newName';
   }
 
   String isolateLazyInitializerAccess(Element element) {
-    return "$CURRENT_ISOLATE.${getLazyInitializerName(element)}";
+    return "${globalObjectFor(element)}.${getLazyInitializerName(element)}";
   }
 
   String isolateStaticClosureAccess(Element element) {
-    return "$CURRENT_ISOLATE.${getStaticClosureName(element)}";
+    return "${globalObjectFor(element)}.${getStaticClosureName(element)}";
   }
 
   String globalObjectForConstant(Constant constant) => 'C';
@@ -840,7 +931,10 @@
   }
 
   String substitutionName(Element element) {
-    return '${operatorAsPrefix()}${getName(element)}';
+    // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
+    // string concatenation in the implementation), and may prevent
+    // segmentation of '$'.
+    return '${operatorAsPrefix()}${getNameForRti(element)}';
   }
 
   String signatureLocation(FunctionType type) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
index c5ccf96..67401f6 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/native_emitter.dart
@@ -105,11 +105,25 @@
     return backend.namer.isolateAccess(element);
   }
 
-  List<String> nativeTagsOfClass(ClassElement cls) {
+  // The tags string contains comma-separated 'words' which are either dispatch
+  // tags (having JavaScript identifier syntax) and directives that begin with
+  // `!`.
+  List<String> nativeTagsOfClassRaw(ClassElement cls) {
     String quotedName = cls.nativeTagInfo.slowToString();
     return quotedName.substring(1, quotedName.length - 1).split(',');
   }
 
+  List<String> nativeTagsOfClass(ClassElement cls) {
+    return nativeTagsOfClassRaw(cls).where((s) => !s.startsWith('!')).toList();
+  }
+
+  bool nativeHasTagsMarker(ClassElement cls, String marker) {
+    return nativeTagsOfClassRaw(cls).contains(marker);
+  }
+
+  bool nativeForcedNonLeaf(ClassElement cls) =>
+      nativeHasTagsMarker(cls, '!nonleaf');
+
   /**
    * Writes the class definitions for the interceptors to [mainBuffer].
    * Writes code to associate dispatch tags with interceptors to [nativeBuffer].
@@ -197,6 +211,10 @@
       } else if (extensionPoints.containsKey(classElement)) {
         needed = true;
       }
+      if (classElement.isNative() && nativeForcedNonLeaf(classElement)) {
+        needed = true;
+        nonleafClasses.add(classElement);
+      }
 
       if (needed || neededClasses.contains(classElement)) {
         neededClasses.add(classElement);
@@ -266,7 +284,7 @@
       if (neededClasses.contains(classElement)) {
         // Define interceptor class for [classElement].
         emitter.emitClassBuilderWithReflectionData(
-            backend.namer.getName(classElement),
+            backend.namer.getNameOfClass(classElement),
             classElement, builders[classElement],
             emitter.bufferForElement(classElement, mainBuffer));
         emitter.needsDefineClass = true;
@@ -318,7 +336,7 @@
       superclass = backend.jsInterceptorClass;
     }
 
-    String superName = backend.namer.getName(superclass);
+    String superName = backend.namer.getNameOfClass(superclass);
 
     ClassBuilder builder = new ClassBuilder();
     emitter.emitClassConstructor(classElement, builder);
@@ -464,19 +482,21 @@
       return false;
     }
 
+    if (backend.classesMixedIntoNativeClasses.contains(element)) return true;
+
     return subtypes[element] != null;
   }
 
   bool requiresNativeIsCheck(Element element) {
     // TODO(sra): Remove this function.  It determines if a native type may
-    // satisfy a check against [element], in whcih case an interceptor must be
+    // satisfy a check against [element], in which case an interceptor must be
     // used.  We should also use an interceptor if the check can't be satisfied
-    // by a native class in case we get a natibe instance that tries to spoof
+    // by a native class in case we get a native instance that tries to spoof
     // the type info.  i.e the criteria for whether or not to use an interceptor
     // is whether the receiver can be native, not the type of the test.
     if (!element.isClass()) return false;
     ClassElement cls = element;
-    if (cls.isNative()) return true;
+    if (Elements.isNativeOrExtendsNative(cls)) return true;
     return isSupertypeOfNativeClass(element);
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index 9308bec..5f9041f 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -231,6 +231,8 @@
       }
       // Find all supertypes of [element] in [checkedArguments] and add checks
       // and precompute the substitutions for them.
+      assert(invariant(element, element.allSupertypes != null,
+             message: 'Supertypes have not been computed for $element.'));
       for (DartType supertype in element.allSupertypes) {
         ClassElement superelement = supertype.element;
         if (checked.contains(superelement)) {
@@ -516,14 +518,12 @@
         getTypeEncoding(type, alwaysGenerateFunction: true);
     if (contextClass != null) {
       JavaScriptBackend backend = compiler.backend;
-      String computeSignature =
-          backend.namer.getName(backend.getComputeSignature());
-      String contextName = backend.namer.getName(contextClass);
+      String contextName = backend.namer.getNameOfClass(contextClass);
       List<jsAst.Expression> arguments =
           <jsAst.Expression>[encoding, this_, js.string(contextName)];
       return js.fun([], js.return_(
           new jsAst.Call(
-              js(backend.namer.GLOBAL_OBJECT)[js.string(computeSignature)],
+              backend.namer.elementAccess(backend.getComputeSignature()),
               arguments)));
     } else {
       return encoding;
@@ -820,11 +820,13 @@
 
   jsAst.Expression getCode(RuntimeTypes rti, bool ensureIsFunction) {
     jsAst.Expression declaration(TypeVariableType variable) {
-      return new jsAst.Parameter(variable.name.slowToString());
+      return new jsAst.Parameter(
+          rti.backend.namer.safeVariableName(variable.name.slowToString()));
     }
 
     jsAst.Expression use(TypeVariableType variable) {
-      return new jsAst.VariableUse(variable.name.slowToString());
+      return new jsAst.VariableUse(
+          rti.backend.namer.safeVariableName(variable.name.slowToString()));
     }
 
     jsAst.Expression value =
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 5fc7944..553f9de 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -501,7 +501,11 @@
   }
 
   onFirstNativeClass() {
-    staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
+    staticUse(name) {
+      JavaScriptBackend backend = compiler.backend;
+      backend.enqueue(
+          world, compiler.findHelper(name), compiler.globalDependencies);
+    }
 
     staticUse(const SourceString('dynamicFunction'));
     staticUse(const SourceString('dynamicSetMetadata'));
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 4aed80b..130943c 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -26,6 +26,14 @@
   Selector setMoveNextSelector(ForIn node, Selector selector);
   Selector setCurrentSelector(ForIn node, Selector selector);
 
+  /**
+   * Returns [:true:] if [node] is a type literal.
+   *
+   * Resolution marks this by setting the type on the node to be the
+   * [:Type:] type.
+   */
+  bool isTypeLiteral(Send node);
+
   /// Register additional dependencies required by [currentElement].
   /// For example, elements that are used by a backend.
   void registerDependency(Element element);
@@ -132,6 +140,10 @@
     return selectors[node.inToken];
   }
 
+  bool isTypeLiteral(Send node) {
+    return getType(node) != null;
+  }
+
   void registerDependency(Element element) {
     otherDependencies.add(element.implementation);
   }
@@ -1544,6 +1556,7 @@
       type = reportFailureAndCreateType(
           MessageKind.NOT_A_TYPE, {'node': node.typeName});
     } else {
+      bool addTypeVariableBoundsCheck = false;
       if (identical(element, compiler.types.voidType.element) ||
           identical(element, compiler.dynamicClass)) {
         type = checkNoTypeArguments(element.computeType(compiler));
@@ -1563,6 +1576,7 @@
             type = cls.rawType;
           } else {
             type = new InterfaceType(cls.declaration, arguments.toLink());
+            addTypeVariableBoundsCheck = true;
           }
         }
       } else if (element.isTypedef()) {
@@ -1580,7 +1594,8 @@
           if (arguments.isEmpty) {
             type = typdef.rawType;
           } else {
-           type = new TypedefType(typdef, arguments.toLink());
+            type = new TypedefType(typdef, arguments.toLink());
+            addTypeVariableBoundsCheck = true;
           }
         }
       } else if (element.isTypeVariable()) {
@@ -1605,11 +1620,43 @@
         compiler.cancel("unexpected element kind ${element.kind}",
                         node: node);
       }
+      // TODO(johnniwinther): We should not resolve type annotations after the
+      // resolution queue has been closed. Currently the dart backend does so.
+      // Remove the guarded when this is fixed.
+      if (!compiler.enqueuer.resolution.queueIsClosed &&
+          addTypeVariableBoundsCheck) {
+        compiler.enqueuer.resolution.addPostProcessAction(
+            visitor.enclosingElement,
+            () => checkTypeVariableBounds(node, type));
+      }
     }
     visitor.useType(node, type);
     return type;
   }
 
+  /// Checks the type arguments of [type] against the type variable bounds.
+  void checkTypeVariableBounds(TypeAnnotation node, GenericType type) {
+    TypeDeclarationElement element = type.element;
+    Link<DartType> typeArguments = type.typeArguments;
+    Link<DartType> typeVariables = element.typeVariables;
+    while (!typeVariables.isEmpty && !typeArguments.isEmpty) {
+      TypeVariableType typeVariable = typeVariables.head;
+      DartType bound = typeVariable.element.bound.subst(
+          type.typeArguments, element.typeVariables);
+      DartType typeArgument = typeArguments.head;
+      if (!compiler.types.isSubtype(typeArgument, bound)) {
+        compiler.reportWarningCode(node,
+            MessageKind.INVALID_TYPE_VARIABLE_BOUND,
+            {'typeVariable': typeVariable,
+             'bound': bound,
+             'typeArgument': typeArgument,
+             'thisType': element.thisType});
+      }
+      typeVariables = typeVariables.tail;
+      typeArguments = typeArguments.tail;
+    }
+  }
+
   /**
    * Resolves the type arguments of [node] and adds these to [arguments].
    *
@@ -1751,8 +1798,7 @@
 
   ResolutionEnqueuer get world => compiler.enqueuer.resolution;
 
-  Element lookup(Node node, SourceString name) {
-    Element result = scope.lookup(name);
+  Element reportLookupErrorIfAny(Element result, Node node, SourceString name) {
     if (!Elements.isUnresolved(result)) {
       if (!inInstanceContext && result.isInstanceMember()) {
         compiler.reportError(
@@ -1828,7 +1874,12 @@
       }
       return null;
     } else {
-      Element element = lookup(node, node.source);
+      SourceString name = node.source;
+      Element element = scope.lookup(name);
+      if (Elements.isUnresolved(element) && name.slowToString() == 'dynamic') {
+        element = compiler.dynamicClass;
+      }
+      element = reportLookupErrorIfAny(element, node, node.source);
       if (element == null) {
         if (!inInstanceContext) {
           element = warnAndCreateErroneousElement(
@@ -2309,7 +2360,7 @@
         // Set the type of the node to [Type] to mark this send as a
         // type variable expression.
         mapping.setType(node, compiler.typeClass.computeType(compiler));
-        world.registerInstantiatedClass(compiler.typeClass, mapping);
+        world.registerTypeLiteral(target, mapping);
       } else if (target.impliesType() && !sendIsMemberAccess) {
         // Set the type of the node to [Type] to mark this send as a
         // type literal.
@@ -2473,8 +2524,10 @@
       }
       if (identical(source, '++')) {
         registerBinaryOperator(const SourceString('+'));
+        world.registerInstantiatedClass(compiler.intClass, mapping);
       } else if (identical(source, '--')) {
         registerBinaryOperator(const SourceString('-'));
+        world.registerInstantiatedClass(compiler.intClass, mapping);
       } else if (source.endsWith('=')) {
         registerBinaryOperator(Elements.mapToUserOperator(operatorName));
       }
@@ -3281,7 +3334,8 @@
     resolveTypeVariableBounds(node.typeParameters);
 
     element.functionSignature = SignatureResolver.analyze(
-        compiler, node.formals, node.returnType, element);
+        compiler, node.formals, node.returnType, element,
+        defaultValuesAllowed: false);
 
     element.alias = compiler.computeFunctionType(
         element, element.functionSignature);
@@ -3753,7 +3807,15 @@
 
   SourceString visitSendSet(SendSet node) {
     assert(node.arguments.tail.isEmpty); // Sanity check
-    resolver.visit(node.arguments.head);
+    Identifier identifier = node.selector;
+    SourceString name = identifier.source;
+    VariableDefinitionScope scope =
+        new VariableDefinitionScope(resolver.scope, name);
+    resolver.visitIn(node.arguments.head, scope);
+    if (scope.variableReferencedInInitializer) {
+      resolver.error(identifier, MessageKind.REFERENCE_IN_INITIALIZATION,
+                     {'variableName': name.toString()});
+    }
     return visit(node.selector);
   }
 
@@ -3779,12 +3841,16 @@
  */
 class SignatureResolver extends CommonResolverVisitor<Element> {
   final Element enclosingElement;
+  final bool defaultValuesAllowed;
   Link<Element> optionalParameters = const Link<Element>();
   int optionalParameterCount = 0;
   bool optionalParametersAreNamed = false;
   VariableDefinitions currentDefinitions;
 
-  SignatureResolver(Compiler compiler, this.enclosingElement) : super(compiler);
+  SignatureResolver(Compiler compiler,
+                    this.enclosingElement,
+                    {this.defaultValuesAllowed: true})
+      : super(compiler);
 
   Element visitNodeList(NodeList node) {
     // This must be a list of optional arguments.
@@ -3876,6 +3942,7 @@
     return element;
   }
 
+  /// A [SendSet] node is an optional parameter with a default value.
   Element visitSendSet(SendSet node) {
     Element element;
     if (node.receiver != null) {
@@ -3890,9 +3957,13 @@
       element = new VariableElementX(source, variables,
           ElementKind.PARAMETER, node);
     }
+    Node defaultValue = node.arguments.head;
+    if (!defaultValuesAllowed) {
+      error(defaultValue, MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT);
+    }
     // Visit the value. The compile time constant handler will
     // make sure it's a compile time constant.
-    resolveExpression(node.arguments.head);
+    resolveExpression(defaultValue);
     return element;
   }
 
@@ -3925,8 +3996,10 @@
   static FunctionSignature analyze(Compiler compiler,
                                    NodeList formalParameters,
                                    Node returnNode,
-                                   Element element) {
-    SignatureResolver visitor = new SignatureResolver(compiler, element);
+                                   Element element,
+                                   {bool defaultValuesAllowed: true}) {
+    SignatureResolver visitor = new SignatureResolver(compiler, element,
+            defaultValuesAllowed: defaultValuesAllowed);
     Link<Element> parameters = const Link<Element>();
     int requiredParameterCount = 0;
     if (formalParameters == null) {
@@ -4128,7 +4201,8 @@
 
   Element visitIdentifier(Identifier node) {
     SourceString name = node.source;
-    Element e = resolver.lookup(node, name);
+    Element e = resolver.reportLookupErrorIfAny(
+        resolver.scope.lookup(name), node, name);
     // TODO(johnniwinther): Change errors to warnings, cf. 11.11.1.
     if (e == null) {
       return failOrReturnErroneousElement(resolver.enclosingElement, node, name,
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
index 0af9fd7..81eadae 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
@@ -41,6 +41,24 @@
   }
 }
 
+class VariableDefinitionScope extends NestedScope {
+  final SourceString variableName;
+  bool variableReferencedInInitializer = false;
+
+  VariableDefinitionScope(Scope parent, this.variableName) : super(parent);
+
+  Element localLookup(SourceString name) {
+    if (name == variableName) {
+      variableReferencedInInitializer = true;
+    }
+    return null;
+  }
+
+  Element add(Element newElement) {
+    throw "Cannot add element to VariableDefinitionScope";
+  }
+}
+
 /**
  * [TypeDeclarationScope] defines the outer scope of a type declaration in
  * which the declared type variables and the entities in the enclosing scope are
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
index 75b9cb5..16c2384 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
@@ -464,12 +464,15 @@
       next = advance();
       if ($0 <= next && next <= $9) {
         continue;
-      } else if (identical(next, $PERIOD)) {
-        return tokenizeFractionPart(advance(), start);
-      } else if (identical(next, $e) || identical(next, $E)
-          || identical(next, $d) || identical(next, $D)) {
+      } else if (identical(next, $e) || identical(next, $E)) {
         return tokenizeFractionPart(next, start);
       } else {
+        if (identical(next, $PERIOD)) {
+          int nextnext = peek();
+          if ($0 <= nextnext && nextnext <= $9) {
+            return tokenizeFractionPart(advance(), start);
+          }
+        }
         appendByteStringToken(INT_INFO, asciiString(start, 0));
         return next;
       }
@@ -543,9 +546,6 @@
       appendPrecedenceToken(PERIOD_INFO);
       return bigSwitch(next);
     }
-    if (identical(next, $d) || identical(next, $D)) {
-      next = advance();
-    }
     appendByteStringToken(DOUBLE_INFO, asciiString(start, 0));
     return next;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index a747014..d2a303d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -2815,7 +2815,7 @@
       if (type.containsTypeVariables) {
         ClassElement contextClass = Types.getClassContext(type);
         contextName = graph.addConstantString(
-            new DartString.literal(backend.namer.getName(contextClass)),
+            new DartString.literal(backend.namer.getNameOfClass(contextClass)),
             node, compiler);
         if (currentElement.isInstanceMember()) {
           context = localsHandler.readThis();
@@ -3060,18 +3060,6 @@
                 argument, string.dartString.slowToString())));
   }
 
-  void handleForeignJsSetupObject(Send node) {
-    if (!node.arguments.isEmpty) {
-      compiler.cancel(
-          'Too many arguments to JS_GLOBAL_OBJECT', node: node);
-    }
-
-    String name = backend.namer.GLOBAL_OBJECT;
-    push(new HForeign(new js.LiteralString(name),
-                      HType.UNKNOWN,
-                      <HInstruction>[]));
-  }
-
   void handleForeignJsCallInIsolate(Send node) {
     Link<Node> link = node.arguments;
     if (!compiler.hasIsolateSupport()) {
@@ -3183,8 +3171,6 @@
       handleForeignJs(node);
     } else if (name == const SourceString('JS_CURRENT_ISOLATE_CONTEXT')) {
       handleForeignJsCurrentIsolateContext(node);
-    } else if (name == const SourceString('JS_GLOBAL_OBJECT')) {
-      handleForeignJsSetupObject(node);
     } else if (name == const SourceString('JS_CALL_IN_ISOLATE')) {
       handleForeignJsCallInIsolate(node);
     } else if (name == const SourceString('DART_CLOSURE_TO_JS')) {
@@ -3350,7 +3336,10 @@
                                 TypeVariableElement variable) {
     assert(currentElement.isInstanceMember());
     int index = RuntimeTypes.getTypeVariableIndex(variable);
-    String substitutionNameString = backend.namer.getName(cls);
+    // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
+    // string concatenation in the implementation), and may prevent
+    // segmentation of '$'.
+    String substitutionNameString = backend.namer.getNameForRti(cls);
     HInstruction substitutionName = graph.addConstantString(
         new LiteralDartString(substitutionNameString), null, compiler);
     HInstruction target = localsHandler.readThis();
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 868b361..6f1fe66 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -1480,7 +1480,8 @@
     backend.registerSpecializedGetInterceptor(node.interceptedClasses);
     String name = backend.namer.getInterceptorName(
         backend.getInterceptorMethod, node.interceptedClasses);
-    var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
+    var isolate = new js.VariableUse(
+        backend.namer.globalObjectFor(compiler.interceptorsLibrary));
     use(node.receiver);
     List<js.Expression> arguments = <js.Expression>[pop()];
     push(jsPropertyCall(isolate, name, arguments), node);
@@ -1506,7 +1507,7 @@
         // list class is instantiated.
         world.registerInstantiatedClass(
             compiler.listClass, work.resolutionTree);
-      } else if (target == backend.jsStringConcat) {
+      } else if (target == backend.jsStringOperatorAdd) {
         push(new js.Binary('+', object, arguments[0]), node);
         return;
       } else if (target.isNative() && target.isFunction()
@@ -1528,7 +1529,7 @@
   void visitInvokeConstructorBody(HInvokeConstructorBody node) {
     use(node.inputs[0]);
     js.Expression object = pop();
-    String methodName = backend.namer.getName(node.element);
+    String methodName = backend.namer.getNameOfInstanceMember(node.element);
     List<js.Expression> arguments = visitArguments(node.inputs);
     push(jsPropertyCall(object, methodName, arguments), node);
     world.registerStaticUse(node.element);
@@ -1536,7 +1537,8 @@
 
   void visitOneShotInterceptor(HOneShotInterceptor node) {
     List<js.Expression> arguments = visitArguments(node.inputs);
-    var isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
+    var isolate = new js.VariableUse(
+        backend.namer.globalObjectFor(compiler.interceptorsLibrary));
     Selector selector = getOptimizedSelectorFor(node, node.selector);
     String methodName = backend.registerOneShotInterceptor(selector);
     push(jsPropertyCall(isolate, methodName, arguments), node);
@@ -1654,7 +1656,7 @@
         push(access, node);
       }
     } else {
-      String methodName = backend.namer.getName(superMethod);
+      String methodName = backend.namer.getNameOfInstanceMember(superMethod);
       String className = backend.namer.isolateAccess(superClass);
       js.VariableUse classReference = new js.VariableUse(className);
       js.PropertyAccess prototype =
@@ -1708,7 +1710,7 @@
 
   String _fieldPropertyName(Element element) => element.hasFixedBackendName()
       ? element.fixedBackendName()
-      : backend.namer.getName(element);
+      : backend.namer.getNameOfInstanceMember(element);
 
   visitLocalGet(HLocalGet node) {
     use(node.receiver);
@@ -2039,12 +2041,7 @@
 
   void visitStaticStore(HStaticStore node) {
     world.registerStaticUse(node.element);
-    js.VariableUse isolate = new js.VariableUse(backend.namer.CURRENT_ISOLATE);
-    // Create a property access to make sure expressions and variable
-    // declarations recognizers don't see this assignment as a local
-    // assignment.
-    js.Node variable = new js.PropertyAccess.field(
-        isolate, backend.namer.getName(node.element));
+    js.Node variable = backend.namer.elementAccess(node.element);
     use(node.inputs[0]);
     push(new js.Assignment(variable, pop()), node);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index ff83098..c7770c8 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -737,14 +737,20 @@
     return validator.isValid;
   }
 
-  // TODO(ngeoffray): Cache the information if this method ends up
-  // being hot.
+  Map<HBasicBlock, bool> dominatesCache;
+
   bool dominates(HBasicBlock other) {
+    if (dominatesCache == null) {
+      dominatesCache = new Map<HBasicBlock, bool>();
+    } else {
+      bool res = dominatesCache[other];
+      if (res != null) return res;
+    }
     do {
-      if (identical(this, other)) return true;
+      if (identical(this, other)) return dominatesCache[other] = true;
       other = other.dominator;
     } while (other != null && other.id >= id);
-    return false;
+    return dominatesCache[other] = false;
   }
 }
 
@@ -2416,24 +2422,26 @@
 
   void addBackEdge(HBasicBlock predecessor) {
     backEdges.add(predecessor);
-    addBlock(predecessor);
+    List<HBasicBlock> workQueue = <HBasicBlock>[predecessor];
+    do {
+      HBasicBlock current = workQueue.removeLast();
+      addBlock(current, workQueue);
+    } while (!workQueue.isEmpty);
   }
 
   // Adds a block and transitively all its predecessors in the loop as
   // loop blocks.
-  void addBlock(HBasicBlock block) {
+  void addBlock(HBasicBlock block, List<HBasicBlock> workQueue) {
     if (identical(block, header)) return;
     HBasicBlock parentHeader = block.parentLoopHeader;
     if (identical(parentHeader, header)) {
       // Nothing to do in this case.
     } else if (parentHeader != null) {
-      addBlock(parentHeader);
+      workQueue.add(parentHeader);
     } else {
       block.parentLoopHeader = header;
       blocks.add(block);
-      for (int i = 0, length = block.predecessors.length; i < length; i++) {
-        addBlock(block.predecessors[i]);
-      }
+      workQueue.addAll(block.predecessors);
     }
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 33bab0b..463e198 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -285,7 +285,7 @@
     Selector selector = node.selector;
     HInstruction input = node.inputs[1];
 
-    if (selector.isCall()) {
+    if (selector.isCall() || selector.isOperator()) {
       Element target;
       if (input.isExtendableArray(compiler)) {
         if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
@@ -302,11 +302,11 @@
           if (node.inputs[2].isString(compiler)) {
             target = backend.jsStringSplit;
           }
-        } else if (selector.applies(backend.jsStringConcat, compiler)) {
-          // `concat` is turned into a JavaScript '+' so we need to
+        } else if (selector.applies(backend.jsStringOperatorAdd, compiler)) {
+          // `operator+` is turned into a JavaScript '+' so we need to
           // make sure the receiver is not null.
           if (node.inputs[2].isString(compiler) && !input.canBeNull()) {
-            target = backend.jsStringConcat;
+            target = backend.jsStringOperatorAdd;
           }
         } else if (selector.applies(backend.jsStringToString, compiler)
                    && !input.canBeNull()) {
@@ -1153,6 +1153,12 @@
   }
 }
 
+class GvnWorkItem {
+  final HBasicBlock block;
+  final ValueSet valueSet;
+  GvnWorkItem(this.block, this.valueSet);
+}
+
 class SsaGlobalValueNumberer implements OptimizationPhase {
   final String name = "SsaGlobalValueNumberer";
   final Compiler compiler;
@@ -1166,7 +1172,12 @@
   void visitGraph(HGraph graph) {
     computeChangesFlags(graph);
     moveLoopInvariantCode(graph);
-    visitBasicBlock(graph.entry, new ValueSet());
+    List<GvnWorkItem> workQueue =
+        <GvnWorkItem>[new GvnWorkItem(graph.entry, new ValueSet())];
+    do {
+      GvnWorkItem item = workQueue.removeLast();
+      visitBasicBlock(item.block, item.valueSet, workQueue);
+    } while (!workQueue.isEmpty);
   }
 
   void moveLoopInvariantCode(HGraph graph) {
@@ -1243,7 +1254,8 @@
     return input.block.id > dominator.id;
   }
 
-  void visitBasicBlock(HBasicBlock block, ValueSet values) {
+  void visitBasicBlock(
+      HBasicBlock block, ValueSet values, List<GvnWorkItem> workQueue) {
     HInstruction instruction = block.first;
     if (block.isLoopHeader()) {
       int flags = loopChangesFlags[block.id];
@@ -1280,10 +1292,16 @@
       assert(block.id < dominated.id);
       if (!successorValues.isEmpty && block.id + 1 < dominated.id) {
         visited.clear();
-        int changesFlags = getChangesFlagsForDominatedBlock(block, dominated);
+        List<HBasicBlock> workQueue = <HBasicBlock>[dominated];
+        int changesFlags = 0;
+        do {
+          HBasicBlock current = workQueue.removeLast();
+          changesFlags |=
+              getChangesFlagsForDominatedBlock(block, current, workQueue);
+        } while (!workQueue.isEmpty);
         successorValues.kill(changesFlags);
       }
-      visitBasicBlock(dominated, successorValues);
+      workQueue.add(new GvnWorkItem(dominated, successorValues));
     }
   }
 
@@ -1329,7 +1347,8 @@
   }
 
   int getChangesFlagsForDominatedBlock(HBasicBlock dominator,
-                                       HBasicBlock dominated) {
+                                       HBasicBlock dominated,
+                                       List<HBasicBlock> workQueue) {
     int changesFlags = 0;
     List<HBasicBlock> predecessors = dominated.predecessors;
     for (int i = 0, length = predecessors.length; i < length; i++) {
@@ -1344,7 +1363,7 @@
         // Loop bodies might not be on the path from dominator to dominated,
         // but they can invalidate values.
         changesFlags |= loopChangesFlags[id];
-        changesFlags |= getChangesFlagsForDominatedBlock(dominator, block);
+        workQueue.add(block);
       }
     }
     return changesFlags;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index 257864c..2f4f70a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -47,6 +47,12 @@
   Range newNormalizedRange(Value low, Value up) {
     return new Range.normalize(low, up, this);
   }
+
+  Range newMarkerRange() {
+    return new Range(new MarkerValue(false, this),
+                     new MarkerValue(true, this),
+                     this);
+  }
 }
 
 /**
@@ -89,6 +95,33 @@
 }
 
 /**
+ * The [MarkerValue] class is used to recognize ranges of loop
+ * updates.
+ */
+class MarkerValue extends Value {
+  /// If [positive] is true (respectively false), the marker goes
+  /// to [MaxIntValue] (respectively [MinIntValue]) when being added
+  /// to a positive (respectively negative) value.
+  final bool positive;
+
+  const MarkerValue(this.positive, info) : super(info);
+
+  Value operator +(Value other) {
+    if (other.isPositive && positive) return const MaxIntValue();
+    if (other.isNegative && !positive) return const MinIntValue();
+    if (other is IntValue) return this;
+    return const UnknownValue();
+  }
+
+  Value operator -(Value other) {
+    if (other.isPositive && !positive) return const MinIntValue();
+    if (other.isNegative && positive) return const MaxIntValue();
+    if (other is IntValue) return this;
+    return const UnknownValue();
+  }
+}
+
+/**
  * An [IntValue] contains a constant integer value.
  */
 class IntValue extends Value {
@@ -454,7 +487,7 @@
         lower.min(other.lower), upper.max(other.upper));
   }
 
-  intersection(Range other) {
+  Range intersection(Range other) {
     Value low = lower.max(other.lower);
     Value up = upper.min(other.upper);
     // If we could not compute max or min, pick a value in the two
@@ -621,7 +654,7 @@
     // phase is not necessarily run before the [ValueRangeAnalyzer].
     if (phi.inputs.any((i) => !i.isInteger())) return info.newUnboundRange();
     if (phi.block.isLoopHeader()) {
-      Range range = tryInferLoopPhiRange(phi);
+      Range range = new LoopUpdateRecognizer(ranges, info).run(phi);
       if (range == null) return info.newUnboundRange();
       return range;
     }
@@ -633,11 +666,6 @@
     return range;
   }
 
-  Range tryInferLoopPhiRange(HPhi phi) {
-    HInstruction update = phi.inputs[1];
-    return update.accept(new LoopUpdateRecognizer(phi, ranges, info));
-  }
-
   Range visitConstant(HConstant constant) {
     if (!constant.isInteger()) return info.newUnboundRange();
     IntConstant constantInt = constant.constant;
@@ -908,52 +936,48 @@
 }
 
 /**
- * Recognizes a number of patterns in a loop update instruction and
- * tries to infer a range for the loop phi.
+ * Tries to find a range for the update instruction of a loop phi.
  */
 class LoopUpdateRecognizer extends HBaseVisitor {
-  final HPhi loopPhi;
   final Map<HInstruction, Range> ranges;
   final ValueRangeInfo info;
-  LoopUpdateRecognizer(this.loopPhi, this.ranges, this.info);
+  LoopUpdateRecognizer(this.ranges, this.info);
 
-  Range visitAdd(HAdd operation) {
-    Range range = getRangeForRecognizableOperation(operation);
-    if (range == null) return info.newUnboundRange();
-    Range initial = ranges[loopPhi.inputs[0]];
-    if (range.isPositive) {
-      return info.newNormalizedRange(initial.lower, const MaxIntValue());
-    } else if (range.isNegative) {
-      return info.newNormalizedRange(const MinIntValue(), initial.upper);
-    }
-    return info.newUnboundRange();
+  Range run(HPhi loopPhi) {
+    // Create a marker range for the loop phi, so that if the update
+    // uses the loop phi, it has a range to use.
+    ranges[loopPhi] = info.newMarkerRange();
+    Range updateRange = visit(loopPhi.inputs[1]);
+    ranges[loopPhi] = null;
+    if (updateRange == null) return null;
+    Range startRange = ranges[loopPhi.inputs[0]];
+    // If the lower (respectively upper) value is the marker, we know
+    // the loop does not change it, so we can just use the
+    // [startRange]'s lower (upper) value. Otherwise the lower (upper) value
+    // is the minimum of the [startRange]'s lower (upper) and the
+    // [updateRange]'s lower (upper).
+    Value low = updateRange.lower is MarkerValue
+        ? startRange.lower
+        : updateRange.lower.min(startRange.lower);
+    Value up = updateRange.upper is MarkerValue
+        ? startRange.upper
+        : updateRange.upper.max(startRange.upper);
+    return info.newNormalizedRange(low, up);
   }
 
-  Range visitSubtract(HSubtract operation) {
-    Range range = getRangeForRecognizableOperation(operation);
-    if (range == null) return info.newUnboundRange();
-    Range initial = ranges[loopPhi.inputs[0]];
-    if (range.isPositive) {
-      return info.newNormalizedRange(const MinIntValue(), initial.upper);
-    } else if (range.isNegative) {
-      return info.newNormalizedRange(initial.lower, const MaxIntValue());
-    }
-    return info.newUnboundRange();
+  Range visit(HInstruction instruction) {
+    if (!instruction.isInteger()) return null;
+    if (ranges[instruction] != null) return ranges[instruction];
+    return instruction.accept(this);
   }
 
   Range visitPhi(HPhi phi) {
+    // If the update of a loop phi involves another loop phi, we give
+    // up.
+    if (phi.block.isLoopHeader()) return null;
     Range phiRange;
     for (HInstruction input in phi.inputs) {
-      HInstruction instruction = unwrap(input);
-      // If one of the inputs is the loop phi, then we're only
-      // interested in the other inputs: a loop phi feeding itself means
-      // it is not being updated.
-      if (instruction == loopPhi) continue;
-
-      // If another loop phi is involved, it's too complex to analyze.
-      if (instruction is HPhi && instruction.block.isLoopHeader()) return null;
-
-      Range inputRange = instruction.accept(this);
+      Range inputRange = visit(input);
       if (inputRange == null) return null;
       if (phiRange == null) {
         phiRange = inputRange;
@@ -964,49 +988,23 @@
     return phiRange;
   }
 
-  /**
-   * If [operation] is recognizable, returns the inferred range.
-   * Otherwise returns [null].
-   */
-  Range getRangeForRecognizableOperation(HBinaryArithmetic operation) {
-    if (!operation.left.isInteger()) return null;
-    if (!operation.right.isInteger()) return null;
-    HInstruction left = unwrap(operation.left);
-    HInstruction right = unwrap(operation.right);
-    // We only recognize operations that operate on the loop phi.
-    bool isLeftLoopPhi = (left == loopPhi);
-    bool isRightLoopPhi = (right == loopPhi);
-    if (!isLeftLoopPhi && !isRightLoopPhi) return null;
-
-    var other = isLeftLoopPhi ? right : left;
-    // If the analysis already computed range for the update, use it.
-    if (ranges[other] != null) return ranges[other];
-
-    // We currently only handle constants in updates if the
-    // update does not have a range.
-    if (other.isConstant()) {
-      Value value = info.newIntValue(other.constant.value);
-      return info.newNormalizedRange(value, value);
-    }
-    return null;
+  Range visitCheck(HCheck instruction) {
+    return visit(instruction.checkedInput);
   }
 
-  /**
-   * [HCheck] instructions may check the loop phi. Since we only
-   * recognize updates on the loop phi, we must [unwrap] the [HCheck]
-   * instruction to check if it references the loop phi.
-   */
-  HInstruction unwrap(instruction) {
-    if (instruction is HCheck) return unwrap(instruction.checkedInput);
-    // [HPhi] might have two different [HCheck] instructions as
-    // inputs, checking the same instruction.
-    if (instruction is HPhi && !instruction.block.isLoopHeader()) {
-      HInstruction result = unwrap(instruction.inputs[0]);
-      for (int i = 1; i < instruction.inputs.length; i++) {
-        if (result != unwrap(instruction.inputs[i])) return instruction;
-      }
-      return result;
-    }
-    return instruction;
+  Range visitAdd(HAdd operation) {
+    return handleBinaryOperation(operation);
+  }
+
+  Range visitSubtract(HSubtract operation) {
+    return handleBinaryOperation(operation);
+  }
+
+  Range handleBinaryOperation(HBinaryArithmetic instruction) {
+    Range leftRange = visit(instruction.left);
+    Range rightRange = visit(instruction.right);
+    if (leftRange == null || rightRange == null) return null;
+    BinaryOperation operation = instruction.operation(info.constantSystem);
+    return operation.apply(leftRange, rightRange);
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 3c8bae6..61191fc 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -592,7 +592,7 @@
       return const DynamicAccess();
     } else if (element.impliesType()) {
       // The literal `Foo` where Foo is a class, a typedef, or a type variable.
-      if (elements.getType(node) != null) {
+      if (elements.isTypeLiteral(node)) {
         assert(invariant(node, identical(compiler.typeClass,
             elements.getType(node).element),
             message: 'Expected type literal type: '
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index aa6512e..49d14b1 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -1065,10 +1065,14 @@
     return result == const DynamicTypeMask() ? null : result;
   }
 
+  Iterable<TypeMask> get containerTypes {
+    throw new UnsupportedError("");
+  }
+
   void clear() {}
 
   Iterable<Element> getCallersOf(Element element) {
-    throw "Don't use me";
+    throw new UnsupportedError("");
   }
 
   // --- analysis ---
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
index 22271b5..0abae5d 100644
--- a/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/container_tracer.dart
@@ -264,6 +264,9 @@
     // [potentialType] can be null if we did not find any instruction
     // that adds elements to the list.
     if (potentialType == null) {
+      if (_VERBOSE) {
+        print('Found empty type for $analyzedNode $startElement');
+      }
       mask.elementType = new TypeMask.nonNullEmpty();
       return;
     }
@@ -462,6 +465,7 @@
       LocalsHandler closureLocals = new LocalsHandler<TypeMask>.from(
           locals, node, useOtherTryBlock: false);
       new ContainerTracerVisitor(function, tracer, closureLocals).run();
+      return types.functionType;
     } else {
       // Visiting [analyzedElement].
       FunctionSignature signature = function.computeSignature(compiler);
@@ -472,8 +476,8 @@
       visit(node.initializers);
       visitingInitializers = false;
       visit(node.body);
+      return null;
     }
-    return types.functionType;
   }
 
   TypeMask visitLiteralList(LiteralList node) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
index a4d3936..9569030 100644
--- a/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/inferrer_visitor.dart
@@ -384,17 +384,28 @@
     void mergeOneBranch(LocalsHandler<T> other) {
       other.locals.forEachOwnLocal((Element local, T type) {
         T myType = locals[local];
-        if (myType == null) return;
+        if (myType == null) return; // Variable is only defined in [other].
         if (type == myType) return;
         locals[local] = types.allocateDiamondPhi(myType, type);
       });
     }
 
+    void inPlaceUpdateOneBranch(LocalsHandler<T> other) {
+      other.locals.forEachOwnLocal((Element local, T type) {
+        T myType = locals[local];
+        if (myType == null) return; // Variable is only defined in [other].
+        if (type == myType) return;
+        locals[local] = type;
+      });
+    }
+
     if (thenBranch.aborts) {
       if (elseBranch == null) return;
-      mergeOneBranch(elseBranch);
-    } else if (elseBranch == null || elseBranch.aborts) {
+      inPlaceUpdateOneBranch(elseBranch);
+    } else if (elseBranch == null) {
       mergeOneBranch(thenBranch);
+    } else if (elseBranch.aborts) {
+      inPlaceUpdateOneBranch(thenBranch);
     } else {
       void mergeLocal(Element local) {
         T myType = locals[local];
@@ -678,7 +689,9 @@
   }
 
   T visitTypeReferenceSend(Send node) {
-    return types.typeType;
+    // If [node] is not a type literal is the class name of a static access,
+    // in which case we don't use the type mask.
+    return elements.isTypeLiteral(node) ? types.typeType : null;
   }
 
   bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 7d305fd..6079d4b 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -169,7 +169,7 @@
   /**
    * Callers of an element.
    */
-  Map<Element, int> get callers => null;
+  Map<Element, Set<Spannable>> get callers => null;
 
   /**
    * Number of times the element has been processed.
@@ -183,20 +183,20 @@
   TypeMask get returnType => null;
   void set returnType(value) {}
 
-  void addCaller(Element caller) {
+  void addCaller(Element caller, Spannable node) {
     if (callers.containsKey(caller)) {
-      callers[caller]++;
+      callers[caller].add(node);
     } else {
-      callers[caller] = 1;
+      callers[caller] = new Set<Spannable>()..add(node);
     }
   }
 
-  void removeCall(Element caller) {
+  void removeCall(Element caller, Spannable node) {
     if (!callers.containsKey(caller)) return;
-    if (callers[caller] == 1) {
+    Set<Spannable> calls = callers[caller];
+    calls.remove(node);
+    if (calls.isEmpty) {
       callers.remove(caller);
-    } else {
-      callers[caller]--;
     }
   }
 
@@ -208,7 +208,7 @@
 }
 
 class FunctionTypeInformation extends TypeInformation {
-  Map<Element, int> callers = new Map<Element, int>();
+  Map<Element, Set<Spannable>> callers = new Map<Element, Set<Spannable>>();
   TypeMask returnType;
   int analyzeCount = 0;
   bool canBeClosurized = false;
@@ -230,7 +230,7 @@
 
 class FieldTypeInformation extends TypeInformation {
   TypeMask type;
-  Map<Element, int> callers = new Map<Element, int>();
+  Map<Element, Set<Spannable>> callers = new Map<Element, Set<Spannable>>();
   Map<Spannable, TypeMask> assignments = new Map<Spannable, TypeMask>();
   int analyzeCount = 0;
 
@@ -333,9 +333,10 @@
  * type information about visited nodes, as well as to request type
  * information of elements.
  */
-abstract class InferrerEngine<T> implements MinimalInferrerEngine<T> {
+abstract class InferrerEngine<T, V extends TypeSystem>
+    implements MinimalInferrerEngine<T> {
   final Compiler compiler;
-  final TypeSystem<T> types;
+  final V types;
   final Map<Node, T> concreteTypes = new Map<Node, T>();
 
   InferrerEngine(this.compiler, this.types);
@@ -361,11 +362,6 @@
   T returnTypeOfElement(Element element);
 
   /**
-   * Returns the type returned by a call to this [selector].
-   */
-  T returnTypeOfSelector(Selector selector);
-
-  /**
    * Records that [node] sets final field [element] to be of type [type].
    *
    * [nodeHolder] is the element holder of [node].
@@ -590,10 +586,44 @@
       return returnTypeOfElement(element);
     }
   }
+
+  void updateSelectorInTree(Element owner, Node node, Selector selector) {
+    var elements = compiler.enqueuer.resolution.getCachedElements(owner);
+    if (node.asSendSet() != null) {
+      if (selector.isSetter() || selector.isIndexSet()) {
+        elements.setSelector(node, selector);
+      } else if (selector.isGetter() || selector.isIndex()) {
+        elements.setGetterSelectorInComplexSendSet(node, selector);
+      } else {
+        assert(selector.isOperator());
+        elements.setOperatorSelectorInComplexSendSet(node, selector);
+      }
+    } else if (node.asSend() != null) {
+      elements.setSelector(node, selector);
+    } else {
+      assert(node.asForIn() != null);
+      if (selector.asUntyped == compiler.iteratorSelector) {
+        elements.setIteratorSelector(node, selector);
+      } else if (selector.asUntyped == compiler.currentSelector) {
+        elements.setCurrentSelector(node, selector);
+      } else {
+        assert(selector.asUntyped == compiler.moveNextSelector);
+        elements.setMoveNextSelector(node, selector);
+      }
+    }
+  }
+
+  bool isNativeElement(Element element) {
+    if (element.isNative()) return true;
+    return element.isMember()
+        && element.getEnclosingClass().isNative()
+        && element.isField();
+  }
 }
 
 class InternalSimpleTypesInferrer
-    extends InferrerEngine<TypeMask> implements TypesInferrer {
+    extends InferrerEngine<TypeMask, TypeMaskSystem>
+    implements TypesInferrer {
   /**
    * Maps a class to a [ClassTypeInformation] to help collect type
    * information of final fields.
@@ -1023,13 +1053,6 @@
         && newType != types.nullType;
   }
 
-  bool isNativeElement(Element element) {
-    if (element.isNative()) return true;
-    return element.isMember()
-        && element.getEnclosingClass().isNative()
-        && element.isField();
-  }
-
   TypeMask checkTypeAnnotation(Element analyzedElement, TypeMask newType) {
     if (compiler.trustTypeAnnotations
         // Parameters are being checked by the method, and we can
@@ -1181,11 +1204,11 @@
     return outermost.declaration == element.declaration;
   }
 
-  void addCaller(Element caller, Element callee) {
+  void addCaller(Element caller, Element callee, Spannable node) {
     assert(caller.isImplementation);
     assert(callee.isImplementation);
     assert(isNotClosure(caller));
-    typeInformationOf(callee).addCaller(caller);
+    typeInformationOf(callee).addCaller(caller, node);
   }
 
   bool addArguments(Spannable node,
@@ -1293,7 +1316,7 @@
 
     assert(isNotClosure(caller));
     callee = callee.implementation;
-    addCaller(caller, callee);
+    addCaller(caller, callee, node);
 
     if (selector != null && selector.isSetter() && callee.isField()) {
       recordTypeOfNonFinalField(
@@ -1333,7 +1356,7 @@
                                Selector selector,
                                Element caller,
                                Element callee) {
-    typeInformationOf(callee).removeCall(caller);
+    typeInformationOf(callee).removeCall(caller, node);
     if (callee.isField()) {
       if (selector.isSetter()) {
         Map<Spannable, TypeMask> assignments =
@@ -1378,6 +1401,9 @@
 
   TypeMask handleIntrisifiedSelector(Selector selector,
                                      ArgumentsTypes arguments) {
+    // If [:compiler.intClass:] has not been resolved, there are no int values
+    // in the program.
+    if (!compiler.intClass.isResolved) return null;
     TypeMask intType = types.intType;
     if (selector.mask != intType) return null;
     if (!selector.isCall() && !selector.isOperator()) return null;
@@ -1597,13 +1623,13 @@
 }
 
 class SimpleTypeInferrerVisitor<T>
-    extends InferrerVisitor<T, InferrerEngine<T>> {
+    extends InferrerVisitor<T, InferrerEngine<T, TypeSystem<T>>> {
   T returnType;
   bool visitingInitializers = false;
   bool isConstructorRedirect = false;
   SideEffects sideEffects = new SideEffects.empty();
   final Element outermostElement;
-  final InferrerEngine<T> inferrer;
+  final InferrerEngine<T, TypeSystem<T>> inferrer;
   final Set<Element> capturedVariables = new Set<Element>();
 
   SimpleTypeInferrerVisitor.internal(analyzedElement,
@@ -1616,7 +1642,7 @@
 
   factory SimpleTypeInferrerVisitor(Element element,
                                     Compiler compiler,
-                                    InferrerEngine<T> inferrer,
+                                    InferrerEngine<T, TypeSystem<T>> inferrer,
                                     [LocalsHandler<T> handler]) {
     Element outermostElement =
         element.getOutermostEnclosingMemberOrTopLevel().implementation;
@@ -1774,12 +1800,18 @@
       // We only set the type once. We don't need to re-visit the children
       // when re-analyzing the node.
       return inferrer.concreteTypes.putIfAbsent(node, () {
-        T elementType = types.nonNullEmpty();
+        T elementType;
         int length = 0;
         for (Node element in node.elements.nodes) {
+          T type = visit(element);
+          elementType = elementType == null
+              ? types.allocatePhi(null, null, type)
+              : types.addPhiInput(null, elementType, type);
           length++;
-          elementType = types.computeLUB(elementType, visit(element));
         }
+        elementType = elementType == null
+            ? types.nonNullEmpty()
+            : types.simplifyPhi(null, null, elementType);
         return types.allocateContainer(
             types.constListType,
             node,
@@ -2047,7 +2079,7 @@
     isThisExposed = true;
     if (node.isPropertyAccess) {
       return handleStaticSend(node, selector, element, null);
-    } else if (element.isFunction()) {
+    } else if (element.isFunction() || element.isGenerativeConstructor()) {
       if (!selector.applies(element, compiler)) return types.dynamicType;
       ArgumentsTypes arguments = analyzeArguments(node.arguments);
       return handleStaticSend(node, selector, element, arguments);
@@ -2176,31 +2208,6 @@
         sideEffects, inLoop);
   }
 
-  void updateSelectorInTree(Node node, Selector selector) {
-    if (node.asSendSet() != null) {
-      if (selector.isSetter() || selector.isIndexSet()) {
-        elements.setSelector(node, selector);
-      } else if (selector.isGetter() || selector.isIndex()) {
-        elements.setGetterSelectorInComplexSendSet(node, selector);
-      } else {
-        assert(selector.isOperator());
-        elements.setOperatorSelectorInComplexSendSet(node, selector);
-      }
-    } else if (node.asSend() != null) {
-      elements.setSelector(node, selector);
-    } else {
-      assert(node.asForIn() != null);
-      if (selector.asUntyped == compiler.iteratorSelector) {
-        elements.setIteratorSelector(node, selector);
-      } else if (selector.asUntyped == compiler.currentSelector) {
-        elements.setCurrentSelector(node, selector);
-      } else {
-        assert(selector.asUntyped == compiler.moveNextSelector);
-        elements.setMoveNextSelector(node, selector);
-      }
-    }
-  }
-
   T handleDynamicSend(Node node,
                       Selector selector,
                       T receiverType,
@@ -2211,12 +2218,12 @@
       selector = (receiverType == types.dynamicType)
           ? selector.asUntyped
           : types.newTypedSelector(receiverType, selector);
-      updateSelectorInTree(node, selector);
+      inferrer.updateSelectorInTree(analyzedElement, node, selector);
     }
 
     // If the receiver of the call is a local, we may know more about
     // its type by refining it with the potential targets of the
-    // calls. 
+    // calls.
     if (node.asSend() != null) {
       Node receiver = node.asSend().receiver;
       if (receiver != null) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_graph_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/type_graph_inferrer.dart
new file mode 100644
index 0000000..0430004
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/type_graph_inferrer.dart
@@ -0,0 +1,1359 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library type_graph_inferrer;
+
+import 'dart:collection' show Queue, LinkedHashSet, IterableBase, HashMap;
+import '../dart_types.dart' show DartType, InterfaceType, TypeKind;
+import '../elements/elements.dart';
+import '../tree/tree.dart' show Node;
+import 'types.dart' show TypeMask, ContainerTypeMask, TypesInferrer;
+import '../universe/universe.dart' show Selector, TypedSelector, SideEffects;
+import '../dart2jslib.dart' show Compiler, SourceString, TreeElementMapping;
+import 'inferrer_visitor.dart' show TypeSystem, ArgumentsTypes, CallSite;
+import '../native_handler.dart' as native;
+import '../util/util.dart' show Spannable;
+import 'simple_types_inferrer.dart';
+import '../dart2jslib.dart' show invariant;
+
+/**
+ * Common class for all nodes in the graph. The current nodes are:
+ *
+ * - Concrete types
+ * - Elements
+ * - Call sites
+ * - Narrowing instructions
+ * - Phi instructions
+ * - Containers (for lists)
+ * - Type of the element in a container
+ *
+ * A node has a set of assignments and users. Assignments are used to
+ * compute the type of the node ([TypeInformation.refine]). Users are
+ * added to the inferrer's work queue when the type of the node
+ * changes.
+ */
+abstract class TypeInformation {
+  var /* List|Set */ users;
+  var /* List|ParameterAssignments */ assignments;
+
+  /// The type the inferrer has found for this [TypeInformation].
+  /// Initially dynamic.
+  TypeMask type;
+
+  /// We give up on inferencing for special elements, as well as for
+  /// complicated cyclic dependencies.
+  bool abandonInferencing = false;
+
+  /// Number of times this [TypeInformation] has changed type.
+  int refineCount = 0;
+
+  /// Whether this [TypeInformation] is currently in the inferrer's
+  /// work queue.
+  bool inQueue = false;
+
+  // TypeInformations are unique.
+  static int staticHashCode = 0;
+  final int hashCode = staticHashCode++;
+
+  bool get isConcrete => false;
+
+  TypeInformation(this.type, [users, assignments])
+      : users = (users == null) ? new Set<TypeInformation>() : users,
+        assignments = (assignments == null) ? <TypeInformation>[] : assignments;
+      
+
+  void addUser(TypeInformation user) {
+    assert(!user.isConcrete);
+    users.add(user);
+  }
+
+  void removeUser(TypeInformation user) {
+    assert(!user.isConcrete);
+    users.remove(user);
+  }
+
+  void addAssignment(TypeInformation assignment) {
+    if (abandonInferencing) return;
+    // Cheap one-level cycle detection.
+    if (assignment == this) return;
+    assignments.add(assignment);
+    assignment.addUser(this);
+  }
+
+  void removeAssignment(TypeInformation assignment) {
+    if (!abandonInferencing) {
+      assignments.remove(assignment);
+    }
+    // We can have multiple assignments of the same [TypeInformation].
+    if (!assignments.contains(assignment)) {
+      assignment.removeUser(this);
+    }
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return type;
+  }
+
+  TypeMask refineOptimistic(TypeGraphInferrerEngine inferrer) {
+    return refine(inferrer);
+  }
+
+  void giveUp(TypeGraphInferrerEngine inferrer) {
+    abandonInferencing = true;
+    type = inferrer.types.dynamicType.type;
+    assignments = const <TypeInformation>[];
+  }
+
+  void clear() {
+    assignments = const <TypeInformation>[];
+    users = const <TypeInformation>[];
+  }
+}
+
+/**
+ * Parameters of instance functions behave differently than other
+ * elements because the inferrer may remove assignments. This happens
+ * when the receiver of a dynamic call site can be refined
+ * to a type where we know more about which instance method is being
+ * called.
+ */
+class ParameterAssignments extends IterableBase<TypeInformation> {
+  final Map<TypeInformation, int> assignments =
+      new HashMap<TypeInformation, int>();
+
+  void remove(TypeInformation info) {
+    int existing = assignments[info];
+    if (existing == null) return;
+    if (existing == 1) {
+      assignments.remove(info);
+    } else {
+      assignments[info] = existing - 1;
+    }
+  }
+
+  void add(TypeInformation info) {
+    int existing = assignments[info];
+    if (existing == null) {
+      assignments[info] = 1;
+    } else {
+      assignments[info] = existing + 1;
+    }
+  }
+
+  Iterator<TypeInformation> get iterator => assignments.keys.iterator;
+  Iterable<TypeInformation> where(Function f) => assignments.keys.where(f);
+
+  bool contains(TypeInformation info) => assignments.containsKey(info);
+}
+
+/**
+ * A node representing a resolved element of the program. The kind of
+ * elements that need an [ElementTypeRepresentation] are:
+ *
+ * - Functions (including getters and setters)
+ * - Constructors (factory or generative)
+ * - Fields
+ * - Parameters
+ * - Local variables mutated in closures
+ *
+ * The [ElementTypeInformation] of a function and a constructor is its
+ * return type.
+ *
+ * Note that a few elements of these kinds must be treated specially,
+ * and they are dealt in [ElementTypeInformation.handleSpecialCase]:
+ *
+ * - Parameters of closures, [noSuchMethod] and [call] instance
+ *   methods: we currently do not infer types for those.
+ *
+ * - Fields and parameters being assigned by synthesized calls done by
+ *   the backend: we do not know what types the backend will use.
+ *
+ * - Native functions and fields: because native methods contain no Dart
+ *   code, and native fields do not have Dart assignments, we just
+ *   trust their type annotation.
+ *   
+ */
+class ElementTypeInformation extends TypeInformation {
+  final Element element;
+  final Map<Element, Set<Spannable>> callers =
+      new Map<Element, Set<Spannable>>();
+
+  ElementTypeInformation.internal(this.element, type, assignments)
+      : super(type, null, assignments);
+
+  factory ElementTypeInformation(Element element, TypeMask type) {
+    var assignments = null;
+    if (element.enclosingElement.isInstanceMember()
+        && (element.isParameter() || element.isFieldParameter())) {
+      assignments = new ParameterAssignments();
+    }
+    return new ElementTypeInformation.internal(element, type, assignments);
+  }
+
+  void addCall(Element caller, Spannable node) {
+    callers.putIfAbsent(caller, () => new Set<Spannable>()).add(node);
+  }
+
+  void removeCall(Element caller, Spannable node) {
+    Set<Spannable> calls = callers[caller];
+    if (calls == null) return;
+    calls.remove(node);
+    if (calls.isEmpty) {
+      callers.remove(caller);
+    }
+  }
+
+  TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
+    if (abandonInferencing) {
+      return type;
+    }
+    if (element.isParameter()) {
+      Element enclosing = element.enclosingElement;
+      if (Elements.isLocal(enclosing)) {
+        // Do not infer types for parameters of closures.
+        giveUp(inferrer);
+        return type;
+      } else if (enclosing.isInstanceMember()
+                 && (enclosing.name == Compiler.NO_SUCH_METHOD
+                     || enclosing.name == Compiler.CALL_OPERATOR_NAME)) {
+        // Do not infer types for parameters of [noSuchMethod] and
+        // [call] instance methods.
+        giveUp(inferrer);
+        return type;
+      }
+    }
+    if (element.isField()
+        || element.isParameter()
+        || element.isFieldParameter()) {
+      if (!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
+        // Do not infer types for fields and parameters being assigned
+        // by synthesized calls.
+        giveUp(inferrer);
+        return type;
+      }
+    }
+    if (inferrer.isNativeElement(element)) {
+      // Use the type annotation as the type for native elements. We
+      // also give up on inferring to make sure this element never
+      // goes in the work queue.
+      giveUp(inferrer);
+      if (element.isField()) {
+        InterfaceType rawType = element.computeType(inferrer.compiler).asRaw();
+        return rawType.treatAsDynamic
+            ? inferrer.types.dynamicType.type
+            : new TypeMask.subtype(rawType);
+      } else {
+        assert(element.isFunction()
+               || element.isGetter()
+               || element.isSetter());
+        var elementType = element.computeType(inferrer.compiler);
+        if (elementType.kind != TypeKind.FUNCTION) {
+          return type;
+        } else {
+          return inferrer.typeOfNativeBehavior(
+              native.NativeBehavior.ofMethod(element, inferrer.compiler)).type;
+        }
+      }
+    }
+    return null;
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    TypeMask special = handleSpecialCases(inferrer);
+    if (special != null) return special;
+    return inferrer.types.computeTypeMask(assignments);
+  }
+
+  TypeMask refineOptimistic(TypeGraphInferrerEngine inferrer) {
+    TypeMask special = handleSpecialCases(inferrer);
+    if (special != null) return special;
+    return inferrer.types.computeTypeMask(
+        assignments.where((e) => e.isConcrete));
+  }
+
+  String toString() => 'Element $element';
+}
+
+/**
+ * A [CallSiteTypeInformation] is a call found in the AST, or a
+ * synthesized call for implicit calls in Dart (such as forwarding
+ * factories). The [call] field is a [Node] for the former, and an
+ * [Element] for the latter.
+ *
+ * In the inferrer graph, [CallSiteTypeInformation] nodes do not have
+ * any assignment. They rely on the [caller] field for static calls,
+ * and [selector] and [receiver] fields for dynamic calls.
+ */
+abstract class CallSiteTypeInformation extends TypeInformation {
+  final Spannable call;
+  final Element caller;
+  final Selector selector;
+  final ArgumentsTypes arguments;
+
+  CallSiteTypeInformation(
+      this.call,
+      this.caller,
+      this.selector,
+      this.arguments,
+      TypeMask type) : super(type, null, const <TypeInformation>[]);
+
+  String toString() => 'Call site $call';
+
+  /// Add [this] to the graph being computed by [engine].
+  void addToGraph(TypeGraphInferrerEngine engine);
+
+  /// Return an iterable over the targets of this call.
+  Iterable<Element> get callees;
+}
+
+class StaticCallSiteTypeInformation extends CallSiteTypeInformation {
+  final Element calledElement;
+
+  StaticCallSiteTypeInformation(
+      Spannable call,
+      Element enclosing,
+      this.calledElement,
+      Selector selector,
+      ArgumentsTypes arguments,
+      TypeMask type) : super(call, enclosing, selector, arguments, type);
+
+  void addToGraph(TypeGraphInferrerEngine inferrer) {
+    ElementTypeInformation callee =
+        inferrer.types.getInferredTypeOf(calledElement);
+    callee.addCall(caller, call);
+    callee.addUser(this);
+    if (arguments != null) {
+      arguments.forEach((info) => info.addUser(this));
+    }
+    inferrer.updateParameterAssignments(
+        this, calledElement, arguments, selector, remove: false, init: true);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return inferrer.types.getInferredTypeOf(calledElement).type;
+  }
+
+  Iterable<Element> get callees => [calledElement.implementation];
+}
+
+class DynamicCallSiteTypeInformation extends CallSiteTypeInformation {
+  final TypeInformation receiver;
+  /// Cached targets of this call.
+  Iterable<Element> targets;
+
+  DynamicCallSiteTypeInformation(
+      Spannable call,
+      Element enclosing,
+      Selector selector,
+      this.receiver,
+      ArgumentsTypes arguments,
+      TypeMask type) : super(call, enclosing, selector, arguments, type);
+
+  void addToGraph(TypeGraphInferrerEngine inferrer) {
+    assert(receiver != null);
+    Selector typedSelector = computeTypedSelector(inferrer);
+    targets = inferrer.compiler.world.allFunctions.filter(typedSelector);
+    receiver.addUser(this);
+    if (arguments != null) {
+      arguments.forEach((info) => info.addUser(this));
+    }
+    for (Element element in targets) {
+      ElementTypeInformation callee = inferrer.types.getInferredTypeOf(element);
+      callee.addCall(caller, call);
+      callee.addUser(this);
+      inferrer.updateParameterAssignments(
+          this, element, arguments, typedSelector, remove: false, init: true);
+    }
+  }
+
+  Iterable<Element> get callees => targets.map((e) => e.implementation);
+
+  Selector computeTypedSelector(TypeGraphInferrerEngine inferrer) {
+    TypeMask receiverType = receiver.type;
+    if (selector.mask != receiverType) {
+      return receiverType == inferrer.compiler.typesTask.dynamicType
+          ? selector.asUntyped
+          : new TypedSelector(receiverType, selector);
+    } else {
+      return selector;
+    }
+  }
+
+  bool hasOnePositionalArgumentWithType(TypeMask type) {
+    return arguments.named.isEmpty
+        && arguments.positional.length == 1
+        && arguments.positional[0].type == type;
+  }
+
+  /**
+   * We optimize certain operations on the [int] class because we know
+   * more about their return type than the actual Dart code. For
+   * example, we know int + int returns an int. The Dart code for
+   * [int.operator+] only says it returns a [num].
+   */
+  TypeInformation handleIntrisifiedSelector(Selector selector,
+                                            TypeGraphInferrerEngine inferrer) {
+    if (!inferrer.compiler.backend.intImplementation.isResolved) return null;
+    TypeMask intType = inferrer.compiler.typesTask.intType;
+    if (selector.mask != intType) return null;
+    if (!selector.isCall() && !selector.isOperator()) return null;
+    if (!arguments.named.isEmpty) return null;
+    if (arguments.positional.length > 1) return null;
+
+    SourceString name = selector.name;
+    if (name == const SourceString('*')
+        || name == const SourceString('+')
+        || name == const SourceString('%')
+        || name == const SourceString('remainder')) {
+        return hasOnePositionalArgumentWithType(intType)
+            ? inferrer.types.intType
+            : null;
+    } else if (name == const SourceString('-')) {
+      if (arguments.hasNoArguments()) return inferrer.types.intType;
+      if (hasOnePositionalArgumentWithType(intType)) {
+        return inferrer.types.intType;
+      }
+      return null;
+    } else if (name == const SourceString('abs')) {
+      return arguments.hasNoArguments() ? inferrer.types.intType : null;
+    }
+    return null;
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    Iterable<Element> oldTargets = targets;
+    Selector typedSelector = computeTypedSelector(inferrer);
+    inferrer.updateSelectorInTree(caller, call, typedSelector);
+    targets = inferrer.compiler.world.allFunctions.filter(typedSelector);
+
+    // Walk over the found targets, and compute the joined union type mask
+    // for all these targets.
+    TypeMask newType = inferrer.types.computeTypeMask(targets.map((element) {
+      if (!oldTargets.contains(element)) {
+        ElementTypeInformation callee =
+            inferrer.types.getInferredTypeOf(element);
+        callee.addCall(caller, call);
+        callee.addUser(this);
+        inferrer.updateParameterAssignments(
+            this, element, arguments, typedSelector, remove: false);
+      }
+      
+      if (receiver.type.isContainer && selector.isIndex()) {
+        // Find the [ElementInContainerTypeInformation] node and tell
+        // that this node is a user of it. Later, when the element
+        // type changes, this node will be notified.
+        ContainerTypeMask mask = receiver.type;
+        ContainerTypeInformation container =
+            inferrer.types.allocatedContainers[mask.allocationNode];
+        ElementInContainerTypeInformation element = container.elementType;
+        if (!element.users.contains(element)) {
+          element.addUser(this);
+        }
+        return element;
+      } else {
+        TypeInformation info =
+            handleIntrisifiedSelector(typedSelector, inferrer);
+        if (info != null) return info;
+        return inferrer.typeOfElementWithSelector(element, typedSelector);
+      }
+    }));
+
+    // Walk over the old targets, and remove calls that cannot happen
+    // anymore.
+    oldTargets.forEach((element) {
+      if (!targets.contains(element)) {
+        ElementTypeInformation callee =
+            inferrer.types.getInferredTypeOf(element);
+        callee.removeCall(caller, call);
+        callee.removeUser(this);
+        inferrer.updateParameterAssignments(
+            this, element, arguments, typedSelector, remove: true);
+      }
+    });
+    return newType;
+  }
+
+  void giveUp(TypeGraphInferrerEngine inferrer) {
+    inferrer.updateSelectorInTree(caller, call, selector);
+    Iterable<Element> oldTargets = targets;
+    targets = inferrer.compiler.world.allFunctions.filter(selector);
+    for (Element element in targets) {
+      if (!oldTargets.contains(element)) {
+        ElementTypeInformation callee =
+            inferrer.types.getInferredTypeOf(element);
+        callee.addCall(caller, call);
+        inferrer.updateParameterAssignments(
+            this, element, arguments, selector, remove: false);
+      }
+    }
+    super.giveUp(inferrer);
+  }
+}
+
+/**
+ * A [ConcreteTypeInformation] represents a type that needed
+ * to be materialized during the creation of the graph. For example,
+ * literals, [:this:] or [:super:] need a [ConcreteTypeInformation].
+ *
+ * [ConcreteTypeInformation] nodes have no assignment. Also, to save
+ * on memory, we do not add users to [ConcreteTypeInformation] nodes,
+ * because we know such node will never be refined to a different
+ * type.
+ */
+class ConcreteTypeInformation extends TypeInformation {
+  ConcreteTypeInformation(TypeMask type)
+      : super(type, const <TypeInformation>[], const <TypeInformation>[]);
+
+  bool get isConcrete => true;
+
+  void addUser(TypeInformation user) {
+    // Nothing to do, a concrete type does not get updated so never
+    // needs to notify its users.
+  }
+
+  void removeUser(TypeInformation user) {
+  }
+
+  void addAssignment(TypeInformation assignment) {
+  }
+
+  void removeAssignment(TypeInformation assignment) {
+    assert(false);
+  }
+
+  String toString() => 'Type $type';
+}
+
+/**
+ * A [NarrowTypeInformation] narrows a [TypeInformation] to a type,
+ * represented in [typeAnnotation].
+ *
+ * A [NarrowTypeInformation] node has only one assignment: the
+ * [TypeInformation] it narrows.
+ *
+ * [NarrowTypeInformation] nodes are created for:
+ *
+ * - Code after `is` and `as` checks, where we have more information
+ *   on the type of the right hand side of the expression.
+ *
+ * - Code after a dynamic call, where we have more information on the
+ *   type of the receiver: it can only be of a class that holds a
+ *   potential target of this dynamic call.
+ *
+ * - In checked mode, after a type annotation, we have more
+ *   information on the type of an element (parameter, function,
+ *   local). TODO(ngeoffray): Implement this.
+ */
+class NarrowTypeInformation extends TypeInformation {
+  final TypeMask typeAnnotation;
+
+  NarrowTypeInformation(narrowedType,
+                        this.typeAnnotation,
+                        TypeMask type) : super(type) {
+    addAssignment(narrowedType);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return assignments[0].type.intersection(typeAnnotation, inferrer.compiler);
+  }
+
+  String toString() => 'Narrow ${assignments.first} to $typeAnnotation';
+}
+
+/**
+ * A [ContainerTypeInformation] is a [ConcreteTypeInformation] created
+ * for each `List` instantiations.
+ */
+class ContainerTypeInformation extends ConcreteTypeInformation {
+  final TypeInformation elementType;
+
+  ContainerTypeInformation(containerType, this.elementType)
+      : super(containerType);
+
+  String toString() => 'Container type';
+}
+
+/**
+ * An [ElementInContainerTypeInformation] holds the common type of the
+ * elements in a [ContainerTypeInformation].
+ */
+class ElementInContainerTypeInformation extends TypeInformation {
+  final ContainerTypeMask container;
+
+  ElementInContainerTypeInformation(elementType, this.container, type)
+      : super(type) {
+    // [elementType] is not null for const lists.
+    if (elementType != null) addAssignment(elementType);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    if (assignments.isEmpty) return type;
+    return container.elementType =
+        inferrer.types.computeTypeMask(assignments);
+  }
+
+  String toString() => 'Element in container';
+}
+
+/**
+ * A [PhiElementTypeInformation] is an union of
+ * [ElementTypeInformation], that is local to a method.
+ */
+class PhiElementTypeInformation extends TypeInformation {
+  final Node branchNode;
+  final bool isLoopPhi;
+  final Element element;
+
+  PhiElementTypeInformation(this.branchNode, this.isLoopPhi, this.element, type)
+      : super(type);
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return inferrer.types.computeTypeMask(assignments);
+  }
+
+  TypeMask refineOptimistic(TypeGraphInferrerEngine inferrer) {
+    return isLoopPhi
+        ? assignments[0].type
+        : inferrer.types.computeTypeMask(assignments);
+  }
+
+  String toString() => 'Phi $element';
+}
+
+class TypeInformationSystem extends TypeSystem<TypeInformation> {
+  final Compiler compiler;
+
+  /// [ElementTypeInformation]s for elements.
+  final Map<Element, TypeInformation> typeInformations =
+      new Map<Element, TypeInformation>();
+
+  /// [ContainerTypeInformation] for allocated containers.
+  final Map<Node, TypeInformation> allocatedContainers =
+      new Map<Node, TypeInformation>();
+
+  /// Cache of [ConcreteTypeInformation].
+  final Map<TypeMask, TypeInformation> concreteTypes =
+      new Map<TypeMask, TypeInformation>();
+
+  /// List of [TypeInformation]s allocated inside method bodies (calls,
+  /// narrowing, phis, and containers).
+  final List<TypeInformation> allocatedTypes = <TypeInformation>[];
+
+  TypeInformationSystem(this.compiler) {
+    nonNullEmptyType = getConcreteTypeFor(const TypeMask.nonNullEmpty());
+  }
+
+  TypeInformation nullTypeCache;
+  TypeInformation get nullType {
+    if (nullTypeCache != null) return nullTypeCache;
+    return nullTypeCache = getConcreteTypeFor(compiler.typesTask.nullType);
+  }
+
+  TypeInformation intTypeCache;
+  TypeInformation get intType {
+    if (intTypeCache != null) return intTypeCache;
+    return intTypeCache = getConcreteTypeFor(compiler.typesTask.intType);
+  }
+
+  TypeInformation doubleTypeCache;
+  TypeInformation get doubleType {
+    if (doubleTypeCache != null) return doubleTypeCache;
+    return doubleTypeCache = getConcreteTypeFor(compiler.typesTask.doubleType);
+  }
+
+  TypeInformation numTypeCache;
+  TypeInformation get numType {
+    if (numTypeCache != null) return numTypeCache;
+    return numTypeCache = getConcreteTypeFor(compiler.typesTask.numType);
+  }
+
+  TypeInformation boolTypeCache;
+  TypeInformation get boolType {
+    if (boolTypeCache != null) return boolTypeCache;
+    return boolTypeCache = getConcreteTypeFor(compiler.typesTask.boolType);
+  }
+
+  TypeInformation functionTypeCache;
+  TypeInformation get functionType {
+    if (functionTypeCache != null) return functionTypeCache;
+    return functionTypeCache =
+        getConcreteTypeFor(compiler.typesTask.functionType);
+  }
+
+  TypeInformation listTypeCache;
+  TypeInformation get listType {
+    if (listTypeCache != null) return listTypeCache;
+    return listTypeCache = getConcreteTypeFor(compiler.typesTask.listType);
+  }
+
+  TypeInformation constListTypeCache;
+  TypeInformation get constListType {
+    if (constListTypeCache != null) return constListTypeCache;
+    return constListTypeCache =
+        getConcreteTypeFor(compiler.typesTask.constListType);
+  }
+
+  TypeInformation fixedListTypeCache;
+  TypeInformation get fixedListType {
+    if (fixedListTypeCache != null) return fixedListTypeCache;
+    return fixedListTypeCache =
+        getConcreteTypeFor(compiler.typesTask.fixedListType);
+  }
+
+  TypeInformation growableListTypeCache;
+  TypeInformation get growableListType {
+    if (growableListTypeCache != null) return growableListTypeCache;
+    return growableListTypeCache =
+        getConcreteTypeFor(compiler.typesTask.growableListType);
+  }
+
+  TypeInformation mapTypeCache;
+  TypeInformation get mapType {
+    if (mapTypeCache != null) return mapTypeCache;
+    return mapTypeCache = getConcreteTypeFor(compiler.typesTask.mapType);
+  }
+
+  TypeInformation constMapTypeCache;
+  TypeInformation get constMapType {
+    if (constMapTypeCache != null) return constMapTypeCache;
+    return constMapTypeCache =
+        getConcreteTypeFor(compiler.typesTask.constMapType);
+  }
+
+  TypeInformation stringTypeCache;
+  TypeInformation get stringType {
+    if (stringTypeCache != null) return stringTypeCache;
+    return stringTypeCache = getConcreteTypeFor(compiler.typesTask.stringType);
+  }
+
+  TypeInformation typeTypeCache;
+  TypeInformation get typeType {
+    if (typeTypeCache != null) return typeTypeCache;
+    return typeTypeCache = getConcreteTypeFor(compiler.typesTask.typeType);
+  }
+
+  TypeInformation dynamicTypeCache;
+  TypeInformation get dynamicType {
+    if (dynamicTypeCache != null) return dynamicTypeCache;
+    return dynamicTypeCache =
+        getConcreteTypeFor(compiler.typesTask.dynamicType);
+  }
+
+  TypeInformation nonNullEmptyType;
+
+  TypeInformation computeLUB(TypeInformation firstType,
+                             TypeInformation secondType) {
+    if (firstType == null) return secondType;
+    if (firstType == secondType) return firstType;
+    if (firstType == nonNullEmptyType) return secondType;
+    if (secondType == nonNullEmptyType) return firstType;
+    if (firstType == dynamicType || secondType == dynamicType) {
+      return dynamicType;
+    }
+    return getConcreteTypeFor(
+        firstType.type.union(secondType.type, compiler));
+  }
+
+  TypeInformation refineReceiver(Selector selector, TypeInformation receiver) {
+    if (receiver.type.isExact) return receiver;
+    TypeMask otherType = compiler.world.allFunctions.receiverType(selector);
+    // If this is refining to nullable subtype of `Object` just return
+    // the receiver. We know the narrowing is useless.
+    if (otherType.isNullable && otherType.containsAll(compiler)) {
+      return receiver;
+    }
+    TypeInformation newType =
+        new NarrowTypeInformation(receiver, otherType, dynamicType.type);
+    allocatedTypes.add(newType);
+    return newType;
+  }
+
+  TypeInformation narrowType(TypeInformation type,
+                             DartType annotation,
+                             {bool isNullable: true}) {
+    if (annotation.treatAsDynamic) return type;
+    if (annotation.isVoid) return nullType;
+    if (annotation.element == compiler.objectClass) return type;
+    TypeMask otherType;
+    if (annotation.kind == TypeKind.TYPEDEF
+        || annotation.kind == TypeKind.FUNCTION) {
+      otherType = functionType.type;
+    } else if (annotation.kind == TypeKind.TYPE_VARIABLE) {
+      // TODO(ngeoffray): Narrow to bound.
+      return type;
+    } else {
+      assert(annotation.kind == TypeKind.INTERFACE);
+      otherType = new TypeMask.nonNullSubtype(annotation);
+    }
+    if (isNullable) otherType = otherType.nullable();
+    if (type.type.isExact) {
+      return type;
+    } else {
+      TypeInformation newType =
+          new NarrowTypeInformation(type, otherType, dynamicType.type);
+      allocatedTypes.add(newType);
+      return newType;
+    }
+  }
+
+  ElementTypeInformation getInferredTypeOf(Element element) {
+    element = element.implementation;
+    return typeInformations.putIfAbsent(element, () {
+      return new ElementTypeInformation(element, dynamicType.type);
+    });
+  }
+
+  ConcreteTypeInformation getConcreteTypeFor(TypeMask mask) {
+    return concreteTypes.putIfAbsent(mask, () {
+      return new ConcreteTypeInformation(mask);
+    });
+  }
+
+  TypeInformation nonNullSubtype(DartType type) {
+    return getConcreteTypeFor(new TypeMask.nonNullSubtype(type));
+  }
+
+  TypeInformation nonNullSubclass(DartType type) {
+    return getConcreteTypeFor(new TypeMask.nonNullSubclass(type));
+  }
+
+  TypeInformation nonNullExact(DartType type) {
+    return getConcreteTypeFor(new TypeMask.nonNullExact(type));
+  }
+
+  TypeInformation nonNullEmpty() {
+    return nonNullEmptyType;
+  }
+
+  TypeInformation allocateContainer(TypeInformation type,
+                                    Node node,
+                                    Element enclosing,
+                                    [TypeInformation elementType, int length]) {
+    ContainerTypeMask mask = new ContainerTypeMask(type.type, node, enclosing);
+    mask.elementType = elementType == null ? null : elementType.type;
+    mask.length = length;
+    TypeMask elementTypeMask = elementType == null
+        ? dynamicType.type
+        : elementType.type;
+    TypeInformation element = new ElementInContainerTypeInformation(
+        elementType, mask, elementTypeMask);
+    allocatedTypes.add(element);
+    return allocatedContainers[node] =
+        new ContainerTypeInformation(mask, element);
+  }
+
+  Selector newTypedSelector(TypeInformation info, Selector selector) {
+    return new TypedSelector(info.type, selector);
+  }
+
+  TypeInformation allocateDiamondPhi(TypeInformation firstInput,
+                                     TypeInformation secondInput) {
+    PhiElementTypeInformation result =
+        new PhiElementTypeInformation(null, false, null, dynamicType.type);
+    result.addAssignment(firstInput);
+    result.addAssignment(secondInput);
+    allocatedTypes.add(result);
+    return result;
+  }
+
+  PhiElementTypeInformation allocatePhi(Node node,
+                                        Element element,
+                                        inputType) {
+    // Check if [inputType] is a phi for a local updated in
+    // the try/catch block [node]. If it is, no need to allocate a new
+    // phi.
+    if (inputType is PhiElementTypeInformation
+        && inputType.branchNode == node) {
+      return inputType;
+    }
+    PhiElementTypeInformation result =
+        new PhiElementTypeInformation(node, true, element, dynamicType.type);
+    allocatedTypes.add(result);
+    result.addAssignment(inputType);
+    return result;
+  }
+
+  TypeInformation simplifyPhi(Node node,
+                              Element element,
+                              PhiElementTypeInformation phiType) {
+    if (phiType.assignments.length == 1) return phiType.assignments.first;
+    return phiType;
+  }
+
+  PhiElementTypeInformation addPhiInput(Element element,
+                                        PhiElementTypeInformation phiType,
+                                        TypeInformation newType) {
+    phiType.addAssignment(newType);
+    return phiType;
+  }
+
+  TypeMask computeTypeMask(Iterable<TypeInformation> assignments) {
+    TypeMask newType = const TypeMask.nonNullEmpty();
+    for (var info in assignments) {
+      newType = newType.union(info.type, compiler);
+    }
+    return newType.containsAll(compiler) ? dynamicType.type : newType;
+  }
+}
+
+/**
+ * A work queue for the inferrer. It filters out nodes on
+ * which we gave up on inferencing, as well as ensures through
+ * [TypeInformation.inQueue] that a node is in the queue only once at
+ * a time.
+ */
+class WorkQueue {
+  final Queue<TypeInformation> queue = new Queue<TypeInformation>();
+
+  void add(TypeInformation element) {
+    if (element.abandonInferencing) return;
+    if (element.inQueue) return;
+    queue.addLast(element);
+    element.inQueue = true;
+  }
+
+  void addAll(Iterable<TypeInformation> all) {
+    all.forEach(add);
+  }
+
+  TypeInformation remove() {
+    TypeInformation element = queue.removeFirst();
+    element.inQueue = false;
+    return element;
+  }
+
+  bool get isEmpty => queue.isEmpty;
+
+  int get length => queue.length;
+}
+
+/**
+ * An inferencing engine that computes a call graph of
+ * [TypeInformation] nodes by visiting the AST of the application, and
+ * then does the inferencing on the graph.
+ *
+ * The inferencing is currently done in three steps:
+ *
+ * 1) Compute the call graph.
+ * 2) Refine all nodes in a way that avoids cycles.
+ * 3) Refine all nodes.
+ *
+ */
+class TypeGraphInferrerEngine
+    extends InferrerEngine<TypeInformation, TypeInformationSystem> {
+  final Map<Element, ConcreteTypeInformation> defaultTypeOfParameter =
+      new Map<Element, ConcreteTypeInformation>();
+  final WorkQueue workQueue = new WorkQueue();
+
+  /// The maximum number of times we allow a node in the graph to
+  /// change types. If a node reaches that limit, we give up
+  /// inferencing on it and give it the dynamic type.
+  final int MAX_CHANGE_COUNT = 5;
+
+  int overallRefineCount = 0;
+
+  TypeGraphInferrerEngine(Compiler compiler)
+        : super(compiler, new TypeInformationSystem(compiler));
+
+  void runOverAllElements() {
+    if (compiler.disableTypeInference) return;
+    int addedInGraph = 0;
+    compiler.progress.reset();
+
+    sortResolvedElements().forEach((Element element) {
+      if (compiler.progress.elapsedMilliseconds > 500) {
+        compiler.log('Added $addedInGraph elements in inferencing graph.');
+        compiler.progress.reset();
+      }
+      SimpleTypeInferrerVisitor visitor =
+          new SimpleTypeInferrerVisitor(element, compiler, this);
+      TypeInformation type;
+      compiler.withCurrentElement(element, () {
+        type = visitor.run();
+      });
+      addedInGraph++;
+
+      if (element.isField()) {
+        Node node = element.parseNode(compiler);
+        if (element.modifiers.isFinal() || element.modifiers.isConst()) {
+          // If [element] is final and has an initializer, we record
+          // the inferred type.
+          if (node.asSendSet() != null) {
+            recordType(element, type);
+          } else if (!element.isInstanceMember()) {
+            recordType(element, types.nullType);
+          }
+        } else if (node.asSendSet() == null) {
+          // Only update types of static fields if there is no
+          // assignment. Instance fields are dealt with in the constructor.
+          if (Elements.isStaticOrTopLevelField(element)) {
+            recordTypeOfNonFinalField(node, element, type, null);
+          }
+        } else {
+          recordTypeOfNonFinalField(node, element, type, null);
+        }
+      } else {
+        recordReturnType(element, type);
+      }
+    });
+    compiler.log('Added $addedInGraph elements in inferencing graph.');
+
+    buildWorkQueue();
+    refineOptimistic();
+    buildWorkQueue();
+    refine();
+
+    compiler.log('Inferred $overallRefineCount types.');
+  }
+
+
+  void refineOptimistic() {
+    while (!workQueue.isEmpty) {
+      if (compiler.progress.elapsedMilliseconds > 500) {
+        compiler.log('Inferred $overallRefineCount types.');
+        compiler.progress.reset();
+      }
+      TypeInformation info = workQueue.remove();
+      TypeMask oldType = info.type;
+      TypeMask newType = info.refineOptimistic(this);
+      if ((info.type = newType) != oldType) {
+        overallRefineCount++;
+        workQueue.addAll(info.users);
+      }
+    }
+  }
+
+  void refine() {
+    while (!workQueue.isEmpty) {
+      if (compiler.progress.elapsedMilliseconds > 500) {
+        compiler.log('Inferred $overallRefineCount types.');
+        compiler.progress.reset();
+      }
+      TypeInformation info = workQueue.remove();
+      TypeMask oldType = info.type;
+      TypeMask newType = info.refine(this);
+      if ((info.type = newType) != oldType) {
+        overallRefineCount++;
+        info.refineCount++;
+        if (info.refineCount > MAX_CHANGE_COUNT) {
+          info.giveUp(this);
+        }
+        workQueue.addAll(info.users);
+      }
+    }
+  }
+
+  void buildWorkQueue() {
+    workQueue.addAll(types.typeInformations.values);
+    workQueue.addAll(types.allocatedTypes);
+  }
+
+  /**
+   * Update the assignments to parameters in the graph. [remove] tells
+   * wheter assignments must be added or removed. If [init] is true,
+   * parameters are added to the work queue.
+   */
+  void updateParameterAssignments(TypeInformation caller,
+                                  Element callee,
+                                  ArgumentsTypes arguments,
+                                  Selector selector,
+                                  {bool remove, bool init: false}) {
+    if (callee.name == Compiler.NO_SUCH_METHOD) return;
+    if (callee.isField()) {
+      if (selector.isSetter()) {
+        ElementTypeInformation info = types.getInferredTypeOf(callee);
+        if (remove) {
+          info.removeAssignment(arguments.positional[0]);
+        } else {
+          info.addAssignment(arguments.positional[0]);
+        }
+        if (!init) workQueue.add(info);
+      }
+    } else if (callee.isGetter()) {
+      return;
+    } else if (selector != null && selector.isGetter()) {
+      if (!remove) {
+        FunctionElement function = callee.implementation;
+        FunctionSignature signature = function.computeSignature(compiler);
+        signature.forEachParameter((Element parameter) {
+          ElementTypeInformation info = types.getInferredTypeOf(parameter);
+          info.giveUp(this);
+        });
+      }
+    } else {
+      FunctionElement function = callee.implementation;
+      FunctionSignature signature = function.computeSignature(compiler);
+      int parameterIndex = 0;
+      bool visitingRequiredParameter = true;
+      signature.forEachParameter((Element parameter) {
+        if (parameter == signature.firstOptionalParameter) {
+          visitingRequiredParameter = false;
+        }
+        TypeInformation type = visitingRequiredParameter
+            ? arguments.positional[parameterIndex]
+            : signature.optionalParametersAreNamed
+              ? arguments.named[parameter.name]
+              : parameterIndex < arguments.positional.length
+                  ? arguments.positional[parameterIndex]
+                  : null;
+        if (type == null) type = getDefaultTypeOfParameter(parameter);
+        TypeInformation info = types.getInferredTypeOf(parameter);
+        if (remove) {
+          info.removeAssignment(type);
+        } else {
+          info.addAssignment(type);
+        }
+        parameterIndex++;
+        if (!init) workQueue.add(info);
+      });
+    }
+  }
+
+  void updateAllParametersOf(FunctionElement function) {}
+  void onGenerativeConstructorAnalyzed(Element element) {}
+
+  void setDefaultTypeOfParameter(Element parameter, TypeInformation type) {
+    assert(parameter.enclosingElement.isImplementation);
+    getDefaultTypeOfParameter(parameter).type = type.type;
+  }
+
+  TypeInformation getDefaultTypeOfParameter(Element parameter) {
+    return defaultTypeOfParameter.putIfAbsent(parameter, () {
+      return new ConcreteTypeInformation(types.dynamicType.type);
+    });
+  }
+
+  TypeInformation typeOfElement(Element element) {
+    if (element is FunctionElement) return types.functionType;
+    return types.getInferredTypeOf(element);
+  }
+
+  TypeInformation returnTypeOfElement(Element element) {
+    if (element is !FunctionElement) return types.dynamicType;
+    return types.getInferredTypeOf(element);
+  }
+
+  void recordTypeOfFinalField(Spannable node,
+                              Element analyzed,
+                              Element element,
+                              TypeInformation type,
+                              CallSite constraint) {
+    types.getInferredTypeOf(element).addAssignment(type);
+  }
+
+  void recordTypeOfNonFinalField(Spannable node,
+                                 Element element,
+                                 TypeInformation type,
+                                 CallSite constraint) {
+    types.getInferredTypeOf(element).addAssignment(type);
+  }
+
+  bool recordType(Element element, TypeInformation type) {
+    types.getInferredTypeOf(element).addAssignment(type);
+    return false;
+  }
+
+  void recordReturnType(Element element, TypeInformation type) {
+    TypeInformation info = types.getInferredTypeOf(element);
+    if (element.name == const SourceString('==')) {
+      info.addAssignment(types.boolType);
+    }
+    // TODO(ngeoffray): Clean up. We do these checks because
+    // [SimpleTypesInferrer] deals with two different inferrers.
+    if (type == null) return;
+    if (info.assignments.isEmpty) info.addAssignment(type);
+  }
+
+  TypeInformation addReturnTypeFor(Element element,
+                                   TypeInformation unused,
+                                   TypeInformation newType) {
+    TypeInformation type = types.getInferredTypeOf(element);
+    // TODO(ngeoffray): Clean up. We do this check because
+    // [SimpleTypesInferrer] deals with two different inferrers.
+    if (element.isGenerativeConstructor()) return type;
+    type.addAssignment(newType);
+    return type;
+  }
+
+  TypeInformation registerCalledElement(Spannable node,
+                                        Selector selector,
+                                        Element caller,
+                                        Element callee,
+                                        ArgumentsTypes arguments,
+                                        CallSite constraint,
+                                        SideEffects sideEffects,
+                                        bool inLoop) {
+    CallSiteTypeInformation info = new StaticCallSiteTypeInformation(
+          node, caller, callee, selector, arguments, types.dynamicType.type);
+    if (inLoop) {
+      compiler.world.addFunctionCalledInLoop(callee);
+    }
+    info.addToGraph(this);
+    updateSideEffects(sideEffects, selector, callee);
+    return info;
+  }
+
+  TypeInformation registerCalledSelector(Node node,
+                                         Selector selector,
+                                         TypeInformation receiverType,
+                                         Element caller,
+                                         ArgumentsTypes arguments,
+                                         CallSite constraint,
+                                         SideEffects sideEffects,
+                                         bool inLoop) {
+    if (selector.isClosureCall()) return types.dynamicType;
+
+    if (inLoop && selector.mask != null) {
+      // For instance methods, we only register a selector called in a
+      // loop if it is a typed selector, to avoid marking too many
+      // methods as being called from within a loop. This cuts down
+      // on the code bloat.
+      // TODO(ngeoffray): We should move the filtering on the selector
+      // in the backend. It is not the inferrer role to do this kind
+      // of optimization.
+      compiler.world.allFunctions.filter(selector).forEach((callee) {
+        compiler.world.addFunctionCalledInLoop(callee);
+      });
+    }
+    compiler.world.allFunctions.filter(selector).forEach((callee) {
+      updateSideEffects(sideEffects, selector, callee);
+    });
+
+    DynamicCallSiteTypeInformation info = new DynamicCallSiteTypeInformation(
+        node, caller, selector, receiverType, arguments,
+        types.dynamicType.type);
+    info.addToGraph(this);
+    return info;
+  }
+
+  // Sorts the resolved elements by size. We do this for this inferrer
+  // to get the same results for [ContainerTracer] compared to the
+  // [SimpleTypesInferrer].
+  Iterable<Element> sortResolvedElements() {
+    int max = 0;
+    Map<int, Set<Element>> methodSizes = new Map<int, Set<Element>>();
+    compiler.enqueuer.resolution.resolvedElements.forEach(
+      (Element element, TreeElementMapping mapping) {
+        element = element.implementation;
+        if (element.impliesType()) return;
+        assert(invariant(element,
+            element.isField() ||
+            element.isFunction() ||
+            element.isGenerativeConstructor() ||
+            element.isGetter() ||
+            element.isSetter(),
+            message: 'Unexpected element kind: ${element.kind}'));
+        // TODO(ngeoffray): Not sure why the resolver would put a null
+        // mapping.
+        if (mapping == null) return;
+        if (element.isAbstract(compiler)) return;
+        // Put the other operators in buckets by length, later to be added in
+        // length order.
+        int length = mapping.selectors.length;
+        max = length > max ? length : max;
+        Set<Element> set = methodSizes.putIfAbsent(
+            length, () => new LinkedHashSet<Element>());
+        set.add(element);
+    });
+
+    List<Element> result = <Element>[];
+
+    for (int i = 0; i <= max; i++) {
+      Set<Element> set = methodSizes[i];
+      if (set != null) {
+        result.addAll(set);
+      }
+    }
+    return result;
+  }
+
+  void clear() {
+    defaultTypeOfParameter.clear();
+    types.typeInformations.values.forEach((info) => info.clear());
+    types.allocatedTypes.clear();
+    types.concreteTypes.clear();
+  }
+
+  Iterable<Element> getCallersOf(Element element) {
+    if (compiler.disableTypeInference) {
+      throw new UnsupportedError(
+          "Cannot query the type inferrer when type inference is disabled.");
+    }
+    return types.getInferredTypeOf(element).callers.keys;
+  }
+}
+
+class TypeGraphInferrer implements TypesInferrer {
+  TypeGraphInferrerEngine inferrer;
+  final Compiler compiler;
+  TypeGraphInferrer(Compiler this.compiler);
+
+  String get name => 'Graph inferrer';
+
+  void analyzeMain(_) {
+    inferrer = new TypeGraphInferrerEngine(compiler);
+    inferrer.runOverAllElements();
+  }
+
+  TypeMask getReturnTypeOfElement(Element element) {
+    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    return inferrer.types.getInferredTypeOf(element).type;
+  }
+
+  TypeMask getTypeOfElement(Element element) {
+    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    return inferrer.types.getInferredTypeOf(element).type;
+  }
+
+  TypeMask getTypeOfNode(Element owner, Node node) {
+    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    return inferrer.types.allocatedContainers[node].type;
+  }
+
+  TypeMask getTypeOfSelector(Selector selector) {
+    if (compiler.disableTypeInference) return compiler.typesTask.dynamicType;
+    // Bailout for closure calls. We're not tracking types of
+    // closures.
+    if (selector.isClosureCall()) return compiler.typesTask.dynamicType;
+    if (selector.isSetter() || selector.isIndexSet()) {
+      return compiler.typesTask.dynamicType;
+    }
+    if (selector.isIndex()
+        && selector.mask != null
+        && selector.mask.isContainer) {
+      ContainerTypeMask mask = selector.mask;
+      TypeMask elementType = mask.elementType;
+      return elementType == null ? compiler.typesTask.dynamicType : elementType;
+    }
+
+    TypeMask result = const TypeMask.nonNullEmpty();
+    Iterable<Element> elements = compiler.world.allFunctions.filter(selector);
+    for (Element element in elements) {
+      TypeMask type =
+          inferrer.typeOfElementWithSelector(element, selector).type;
+      result = result.union(type, compiler);
+    }
+    return result;
+  }
+
+  Iterable<TypeMask> get containerTypes {
+    if (compiler.disableTypeInference) {
+      throw new UnsupportedError(
+          "Cannot query the type inferrer when type inference is disabled.");
+    }
+    return inferrer.types.allocatedContainers.values.map((info) => info.type);
+  }
+
+  Iterable<Element> getCallersOf(Element element) {
+    if (compiler.disableTypeInference) {
+      throw new UnsupportedError(
+          "Cannot query the type inferrer when type inference is disabled.");
+    }
+    return inferrer.getCallersOf(element);
+  }
+
+  void clear() {
+    inferrer.clear();
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index 201a697..a192b65 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -11,6 +11,7 @@
 import '../util/util.dart';
 import '../universe/universe.dart';
 import 'simple_types_inferrer.dart' show SimpleTypesInferrer;
+import 'type_graph_inferrer.dart' show TypeGraphInferrer;
 import 'concrete_types_inferrer.dart' show ConcreteTypesInferrer;
 import '../dart_types.dart';
 
@@ -42,31 +43,151 @@
   static final bool DUMP_SURPRISING_RESULTS = false;
 
   final String name = 'Type inference';
-  SimpleTypesInferrer typesInferrer;
+  TypesInferrer typesInferrer;
   ConcreteTypesInferrer concreteTypesInferrer;
 
   TypesTask(Compiler compiler) : super(compiler) {
-    typesInferrer = new SimpleTypesInferrer(compiler);
+    typesInferrer = new TypeGraphInferrer(compiler);
     if (compiler.enableConcreteTypeInference) {
       concreteTypesInferrer = new ConcreteTypesInferrer(compiler);
     }
   }
 
-  TypeMask dynamicType;
-  TypeMask nullType;
-  TypeMask intType;
-  TypeMask doubleType;
-  TypeMask numType;
-  TypeMask boolType;
-  TypeMask functionType;
-  TypeMask listType;
-  TypeMask constListType;
-  TypeMask fixedListType;
-  TypeMask growableListType;
-  TypeMask mapType;
-  TypeMask constMapType;
-  TypeMask stringType;
-  TypeMask typeType;
+  TypeMask dynamicTypeCache;
+  TypeMask nullTypeCache;
+  TypeMask intTypeCache;
+  TypeMask doubleTypeCache;
+  TypeMask numTypeCache;
+  TypeMask boolTypeCache;
+  TypeMask functionTypeCache;
+  TypeMask listTypeCache;
+  TypeMask constListTypeCache;
+  TypeMask fixedListTypeCache;
+  TypeMask growableListTypeCache;
+  TypeMask mapTypeCache;
+  TypeMask constMapTypeCache;
+  TypeMask stringTypeCache;
+  TypeMask typeTypeCache;
+
+  TypeMask get dynamicType {
+    if (dynamicTypeCache == null) {
+      dynamicTypeCache = new TypeMask.subclass(compiler.objectClass.rawType);
+    }
+    return dynamicTypeCache;
+  }
+
+  TypeMask get intType {
+    if (intTypeCache == null) {
+      intTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.intImplementation.rawType);
+    }
+    return intTypeCache;
+  }
+
+  TypeMask get doubleType {
+    if (doubleTypeCache == null) {
+      doubleTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.doubleImplementation.rawType);
+    }
+    return doubleTypeCache;
+  }
+
+  TypeMask get numType {
+    if (numTypeCache == null) {
+      numTypeCache = new TypeMask.nonNullSubclass(
+          compiler.backend.numImplementation.rawType);
+    }
+    return numTypeCache;
+  }
+
+  TypeMask get boolType {
+    if (boolTypeCache == null) {
+      boolTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.boolImplementation.rawType);
+    }
+    return boolTypeCache;
+  }
+
+  TypeMask get functionType {
+    if (functionTypeCache == null) {
+      functionTypeCache = new TypeMask.nonNullSubtype(
+          compiler.backend.functionImplementation.rawType);
+    }
+    return functionTypeCache;
+  }
+
+  TypeMask get listType {
+    if (listTypeCache == null) {
+      listTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.listImplementation.rawType);
+    }
+    return listTypeCache;
+  }
+
+  TypeMask get constListType {
+    if (constListTypeCache == null) {
+      constListTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.constListImplementation.rawType);
+    }
+    return constListTypeCache;
+  }
+
+  TypeMask get fixedListType {
+    if (fixedListTypeCache == null) {
+      fixedListTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.fixedListImplementation.rawType);
+    }
+    return fixedListTypeCache;
+  }
+
+  TypeMask get growableListType {
+    if (growableListTypeCache == null) {
+      growableListTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.growableListImplementation.rawType);
+    }
+    return growableListTypeCache;
+  }
+
+  TypeMask get mapType {
+    if (mapTypeCache == null) {
+      mapTypeCache = new TypeMask.nonNullSubtype(
+          compiler.backend.mapImplementation.rawType);
+    }
+    return mapTypeCache;
+  }
+
+  TypeMask get constMapType {
+    if (constMapTypeCache == null) {
+      constMapTypeCache = new TypeMask.nonNullSubtype(
+          compiler.backend.constMapImplementation.rawType);
+    }
+    return constMapTypeCache;
+  }
+
+  TypeMask get stringType {
+    if (stringTypeCache == null) {
+      stringTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.stringImplementation.rawType);
+    }
+    return stringTypeCache;
+  }
+
+  TypeMask get typeType {
+    if (typeTypeCache == null) {
+      typeTypeCache = new TypeMask.nonNullExact(
+          compiler.backend.typeImplementation.rawType);
+    }
+    return typeTypeCache;
+  }
+
+  TypeMask get nullType {
+    if (nullTypeCache == null) {
+      // TODO(johnniwinther): Assert that the null type has been resolved.
+      nullTypeCache = new TypeMask.empty();
+    }
+    return nullTypeCache;
+  }
+
 
   /// Replaces native types by their backend implementation.
   Element normalize(Element cls) {
@@ -181,56 +302,11 @@
     }
   }
 
-  // TODO(ngeoffray): Get rid of this method. Unit tests don't always
-  // ensure these classes are resolved.
-  rawTypeOf(ClassElement cls) {
-    cls.ensureResolved(compiler);
-    assert(cls.rawType != null);
-    return cls.rawType;
-  }
-
-  void initializeTypes() {
-    nullType = new TypeMask.empty();
-
-    Backend backend = compiler.backend;
-    intType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.intImplementation));
-    doubleType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.doubleImplementation));
-    numType = new TypeMask.nonNullSubclass(
-        rawTypeOf(backend.numImplementation));
-    stringType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.stringImplementation));
-    boolType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.boolImplementation));
-
-    listType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.listImplementation));
-    constListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.constListImplementation));
-    fixedListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.fixedListImplementation));
-    growableListType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.growableListImplementation));
-
-    mapType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.mapImplementation));
-    constMapType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.constMapImplementation));
-    functionType = new TypeMask.nonNullSubtype(
-        rawTypeOf(backend.functionImplementation));
-    typeType = new TypeMask.nonNullExact(
-        rawTypeOf(backend.typeImplementation));
-
-    dynamicType = new TypeMask.subclass(rawTypeOf(compiler.objectClass));
-  }
-
   /**
    * Called when resolution is complete.
    */
   void onResolutionComplete(Element mainElement) {
     measure(() {
-      initializeTypes();
       typesInferrer.analyzeMain(mainElement);
       if (concreteTypesInferrer != null) {
         bool success = concreteTypesInferrer.analyzeMain(mainElement);
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index c108cf8..f8248d4 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -378,6 +378,17 @@
   static const MessageKind TYPE_VARIABLE_IN_CONSTANT = const MessageKind(
       'Error: Cannot refer to type variable in constant.');
 
+  static const MessageKind INVALID_TYPE_VARIABLE_BOUND = const MessageKind(
+      "Warning: '#{typeArgument}' is not a subtype of bound '#{bound}' for "
+      "type variable '#{typeVariable}' of type '#{thisType}'.",
+      howToFix: "Try to change or remove the type argument.",
+      examples: const ["""
+class C<T extends num> {}
+
+// 'String' is not a valid instantiation of T with bound num.'.
+main() => new C<String>();
+"""]);
+
   static const MessageKind INVALID_USE_OF_SUPER = const MessageKind(
       'Error: "super" not allowed here.');
 
@@ -418,6 +429,21 @@
   static const MessageKind CANNOT_INSTANTIATE_TYPEDEF = const MessageKind(
       'Error: Cannot instantiate typedef "#{typedefName}".');
 
+  static const MessageKind TYPEDEF_FORMAL_WITH_DEFAULT = const MessageKind(
+      "Error: A parameter of a typedef can't specify a default value.",
+      howToFix: "Remove the default value.",
+      examples: const ["""
+typedef void F([int arg = 0]);
+
+main() {
+  F f;
+}""", """
+typedef void F({int arg: 0});
+
+main() {
+  F f;
+}"""]);
+
   static const MessageKind CANNOT_INSTANTIATE_TYPE_VARIABLE = const MessageKind(
       'Error: Cannot instantiate type variable "#{typeVariableName}".');
 
@@ -623,6 +649,21 @@
       const MessageKind(
           'Error: Top-level variable cannot be declared static.');
 
+  static const MessageKind REFERENCE_IN_INITIALIZATION = const MessageKind(
+       "Error: Variable '#{variableName}' is referenced during its "
+       "initialization.",
+       howToFix: "If you are trying to reference a shadowed variable, rename"
+         " one of the variables.",
+       examples: const ["""
+foo(t) {
+  var t = t;
+  return t;
+}
+
+main() => foo(1);
+"""]);
+
+
   static const MessageKind WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT =
       const MessageKind(
           'Error: Wrong number of arguments to assert. Should be 1, but given '
diff --git a/sdk/lib/_internal/lib/collection_patch.dart b/sdk/lib/_internal/lib/collection_patch.dart
index c5fa69c..670b4ab 100644
--- a/sdk/lib/_internal/lib/collection_patch.dart
+++ b/sdk/lib/_internal/lib/collection_patch.dart
@@ -6,23 +6,34 @@
 import 'dart:_foreign_helper' show JS;
 
 patch class HashMap<K, V> {
-  patch factory HashMap({ bool equals(K key1, K key2), int hashCode(K key) }) {
-    if (hashCode == null) {
+  patch factory HashMap({ bool equals(K key1, K key2),
+                          int hashCode(K key),
+                          bool isValidKey(potentialKey) }) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _HashMap<K, V>();
+        }
+        if (identical(identical, equals)) {
+          return new _IdentityHashMap<K, V>();
+        }
+        hashCode = _defaultHashCode;
+      } else if (equals == null) {
+        equals = _defaultEquals;
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
       if (equals == null) {
-        return new _HashMapImpl<K, V>();
+        equals = _defaultEquals;
       }
-      if (identical(identical, equals)) {
-        return new _IdentityHashMap<K, V>();
-      }
-      hashCode = _defaultHashCode;
-    } else if (equals == null) {
-      equals = _defaultEquals;
     }
-    return new _CustomHashMap<K, V>(equals, hashCode);
+    return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);
   }
 }
 
-class _HashMapImpl<K, V> implements HashMap<K, V> {
+class _HashMap<K, V> implements HashMap<K, V> {
   int _length = 0;
 
   // The hash map contents are divided into three parts: one part for
@@ -43,7 +54,9 @@
   // guard against concurrent modifications.
   List _keys;
 
-  _HashMapImpl();
+  _HashMap();
+
+  Type get runtimeType => HashMap;
 
   int get length => _length;
   bool get isEmpty => _length == 0;
@@ -234,7 +247,7 @@
     _setTableEntry(table, key, value);
   }
 
-  V _removeHashTableEntry(var table, K key) {
+  V _removeHashTableEntry(var table, Object key) {
     if (table != null && _hasTableEntry(table, key)) {
       V value = _getTableEntry(table, key);
       _deleteTableEntry(table, key);
@@ -325,7 +338,7 @@
   }
 }
 
-class _IdentityHashMap<K, V> extends _HashMapImpl<K, V> {
+class _IdentityHashMap<K, V> extends _HashMap<K, V> {
   int _findBucketIndex(var bucket, var key) {
     if (bucket == null) return -1;
     int length = JS('int', '#.length', bucket);
@@ -336,10 +349,27 @@
   }
 }
 
-class _CustomHashMap<K, V> extends _HashMapImpl<K, V> {
+class _CustomHashMap<K, V> extends _HashMap<K, V> {
   final _Equality<K> _equals;
   final _Hasher<K> _hashCode;
-  _CustomHashMap(this._equals, this._hashCode);
+  final _Predicate _validKey;
+  _CustomHashMap(this._equals, this._hashCode, bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+  V operator[](Object key) {
+    if (!_validKey(key)) return null;
+    return super[key];
+  }
+
+  bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
+    return super.containsKey(key);
+  }
+
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    return super.remove(key);
+  }
 
   int _computeHashCode(var key) {
     // We force the hash codes to be unsigned 30-bit integers to avoid
@@ -416,6 +446,34 @@
 }
 
 patch class LinkedHashMap<K, V> {
+  patch factory LinkedHashMap({ bool equals(K key1, K key2),
+                                int hashCode(K key),
+                                bool isValidKey(potentialKey) }) {
+    if (isValidKey == null) {
+      if (hashCode == null) {
+        if (equals == null) {
+          return new _LinkedHashMap<K, V>();
+        }
+        if (identical(identical, equals)) {
+          return new _LinkedIdentityHashMap<K, V>();
+        }
+        hashCode = _defaultHashCode;
+      } else if (equals == null) {
+        equals = _defaultEquals;
+      }
+    } else {
+      if (hashCode == null) {
+        hashCode = _defaultHashCode;
+      }
+      if (equals == null) {
+        equals = _defaultEquals;
+      }
+    }
+    return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
+  }
+}
+
+class _LinkedHashMap<K, V> implements LinkedHashMap<K, V> {
   int _length = 0;
 
   // The hash map contents are divided into three parts: one part for
@@ -440,22 +498,23 @@
   // iterated over.
   int _modifications = 0;
 
-  patch LinkedHashMap();
+  _LinkedHash();
 
-  patch int get length => _length;
-  patch bool get isEmpty => _length == 0;
-  patch bool get isNotEmpty => !isEmpty;
+  Type get runtimeType => LinkedHashMap;
 
+  int get length => _length;
+  bool get isEmpty => _length == 0;
+  bool get isNotEmpty => !isEmpty;
 
-  patch Iterable<K> get keys {
+  Iterable<K> get keys {
     return new LinkedHashMapKeyIterable<K>(this);
   }
 
-  patch Iterable<V> get values {
+  Iterable<V> get values {
     return keys.map((each) => this[each]);
   }
 
-  patch bool containsKey(Object key) {
+  bool containsKey(Object key) {
     if (_isStringKey(key)) {
       var strings = _strings;
       if (strings == null) return false;
@@ -474,17 +533,17 @@
     }
   }
 
-  patch bool containsValue(Object value) {
+  bool containsValue(Object value) {
     return keys.any((each) => this[each] == value);
   }
 
-  patch void addAll(Map<K, V> other) {
+  void addAll(Map<K, V> other) {
     other.forEach((K key, V value) {
       this[key] = value;
     });
   }
 
-  patch V operator[](Object key) {
+  V operator[](Object key) {
     if (_isStringKey(key)) {
       var strings = _strings;
       if (strings == null) return null;
@@ -506,7 +565,7 @@
     }
   }
 
-  patch void operator[]=(K key, V value) {
+  void operator[]=(K key, V value) {
     if (_isStringKey(key)) {
       var strings = _strings;
       if (strings == null) _strings = strings = _newHashTable();
@@ -536,14 +595,14 @@
     }
   }
 
-  patch V putIfAbsent(K key, V ifAbsent()) {
+  V putIfAbsent(K key, V ifAbsent()) {
     if (containsKey(key)) return this[key];
     V value = ifAbsent();
     this[key] = value;
     return value;
   }
 
-  patch V remove(Object key) {
+  V remove(Object key) {
     if (_isStringKey(key)) {
       return _removeHashTableEntry(_strings, key);
     } else if (_isNumericKey(key)) {
@@ -564,7 +623,7 @@
     }
   }
 
-  patch void clear() {
+  void clear() {
     if (_length > 0) {
       _strings = _nums = _rest = _first = _last = null;
       _length = 0;
@@ -572,7 +631,7 @@
     }
   }
 
-  patch void forEach(void action(K key, V value)) {
+  void forEach(void action(K key, V value)) {
     LinkedHashMapCell cell = _first;
     int modifications = _modifications;
     while (cell != null) {
@@ -593,7 +652,7 @@
     }
   }
 
-  V _removeHashTableEntry(var table, K key) {
+  V _removeHashTableEntry(var table, Object key) {
     if (table == null) return null;
     LinkedHashMapCell cell = _getTableEntry(table, key);
     if (cell == null) return null;
@@ -655,7 +714,7 @@
     return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key);
   }
 
-  static int _computeHashCode(var key) {
+  int _computeHashCode(var key) {
     // We force the hash codes to be unsigned 30-bit integers to avoid
     // issues with problematic keys like '__proto__'. Another option
     // would be to throw an exception if the hash code isn't a number.
@@ -675,12 +734,12 @@
     JS('void', 'delete #[#]', table, key);
   }
 
-  static List _getBucket(var table, var key) {
+  List _getBucket(var table, var key) {
     var hash = _computeHashCode(key);
     return JS('var', '#[#]', table, hash);
   }
 
-  static int _findBucketIndex(var bucket, var key) {
+  int _findBucketIndex(var bucket, var key) {
     if (bucket == null) return -1;
     int length = JS('int', '#.length', bucket);
     for (int i = 0; i < length; i++) {
@@ -702,6 +761,61 @@
     _deleteTableEntry(table, temporaryKey);
     return table;
   }
+
+  String toString() => Maps.mapToString(this);
+}
+
+class _LinkedIdentityHashMap<K, V> extends _LinkedHashMap<K, V> {
+  int _findBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      if (identical(cell._key, key)) return i;
+    }
+    return -1;
+  }
+}
+
+class _LinkedCustomHashMap<K, V> extends _LinkedHashMap<K, V> {
+  final _Equality<K> _equals;
+  final _Hasher<K> _hashCode;
+  final _Predicate _validKey;
+  _LinkedCustomHashMap(this._equals, this._hashCode,
+                       bool validKey(potentialKey))
+      : _validKey = (validKey != null) ? validKey : ((v) => v is K);
+
+  V operator[](Object key) {
+    if (!_validKey(key)) return null;
+    return super[key];
+  }
+
+  bool containsKey(Object key) {
+    if (!_validKey(key)) return false;
+    return super.containsKey(key);
+  }
+
+  V remove(Object key) {
+    if (!_validKey(key)) return null;
+    return super.remove(key);
+  }
+
+  int _computeHashCode(var key) {
+    // We force the hash codes to be unsigned 30-bit integers to avoid
+    // issues with problematic keys like '__proto__'. Another option
+    // would be to throw an exception if the hash code isn't a number.
+    return JS('int', '# & 0x3ffffff', _hashCode(key));
+  }
+
+  int _findBucketIndex(var bucket, var key) {
+    if (bucket == null) return -1;
+    int length = JS('int', '#.length', bucket);
+    for (int i = 0; i < length; i++) {
+      LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
+      if (_equals(cell._key, key)) return i;
+    }
+    return -1;
+  }
 }
 
 class LinkedHashMapCell {
diff --git a/sdk/lib/_internal/lib/foreign_helper.dart b/sdk/lib/_internal/lib/foreign_helper.dart
index 165a0a4..ae91916 100644
--- a/sdk/lib/_internal/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/lib/foreign_helper.dart
@@ -231,11 +231,6 @@
 String JS_FUNCTION_TYPE_NAMED_PARAMETERS_TAG() {}
 
 /**
- * Returns the global object, usually called encoded as [: $ :].
- */
-JS_GLOBAL_OBJECT() {}
-
-/**
  * Obtain [name] from Namer.
  */
 String JS_GET_NAME(String name) {}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 04ee3a9..1837aaf 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 patch class _Directory {
-  patch static String _current() {
+  patch static _current() {
     throw new UnsupportedError("Directory._current");
   }
   patch static _setCurrent(path) {
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 9fe12b0..d8fcff4a 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -577,13 +577,8 @@
     JS("void", r"#.console.log(#)", globalThis, msg);
   }
 
-  /** Find a constructor given its name. */
-  static dynamic _getJSConstructorFromName(String factoryName) {
-    return JS("", "#[#]", JS_CURRENT_ISOLATE(), factoryName);
-  }
-
-  static dynamic _getJSFunctionFromName(String functionName) {
-    return JS("", "#[#]", JS_CURRENT_ISOLATE(), functionName);
+  static _getJSFunctionFromName(String functionName) {
+    return JS("", "init.globalFunctions[#]", functionName);
   }
 
   /**
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index fe0fcc1..0ce4ec6 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -19,7 +19,6 @@
                                    JS_FUNCTION_TYPE_TAG,
                                    JS_FUNCTION_TYPE_VOID_RETURN_TAG,
                                    JS_GET_NAME,
-                                   JS_GLOBAL_OBJECT,
                                    JS_HAS_EQUALS,
                                    JS_IS_INDEXABLE_FIELD_NAME,
                                    JS_OBJECT_CLASS_NAME,
@@ -729,7 +728,7 @@
     if (JS('bool', '# == "num"', className)) return const JSNumber();
     if (JS('bool', '# == "bool"', className)) return const JSBool();
     if (JS('bool', '# == "List"', className)) return const JSArray();
-    return JS('var', '#[#]', JS_CURRENT_ISOLATE(), className);
+    return JS('var', 'init.allClasses[#]', className);
   }
 
   static bool identicalImplementation(a, b) {
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index deb2faa..d16178b 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -91,12 +91,14 @@
       var metadataFunction = data[4];
       var fields = data[5];
       bool isRoot = data[6];
+      var globalObject = data[7];
       List metadata = (metadataFunction == null)
           ? const [] : JS('List', '#()', metadataFunction);
       var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
       libraries.add(
           new JsLibraryMirror(
-              s(name), uri, classes, functions, metadata, fields, isRoot));
+              s(name), uri, classes, functions, metadata, fields, isRoot,
+              globalObject));
     }
     return result;
   }
@@ -199,6 +201,7 @@
   final List _metadata;
   final String _compactFieldSpecification;
   final bool _isRoot;
+  final _globalObject;
   List<JsMethodMirror> _cachedFunctionMirrors;
   List<JsVariableMirror> _cachedFields;
   UnmodifiableMapView<Symbol, ClassMirror> _cachedClasses;
@@ -215,7 +218,8 @@
                   this._functions,
                   this._metadata,
                   this._compactFieldSpecification,
-                  this._isRoot)
+                  this._isRoot,
+                  this._globalObject)
       : super(simpleName);
 
   String get _prettyName => 'LibraryMirror';
@@ -282,11 +286,18 @@
   }
 
   _loadField(String name) {
+    // TODO(ahe): What about lazily initialized fields? See
+    // [JsClassMirror.getField].
+
+    // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so we
+    // shouldn't use [_globalObject] here.
     assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
     return JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
   }
 
   void _storeField(String name, Object arg) {
+    // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so we
+    // shouldn't use [_globalObject] here.
     assert(JS('bool', '# in #', name, JS_CURRENT_ISOLATE()));
     JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), name, arg);
   }
@@ -296,9 +307,7 @@
     var result = new List<JsMethodMirror>();
     for (int i = 0; i < _functions.length; i++) {
       String name = _functions[i];
-      // TODO(ahe): Create accessor for accessing $.  It is also
-      // used in js_helper.
-      var jsFunction = JS('', '#[#]', JS_CURRENT_ISOLATE(), name);
+      var jsFunction = JS('', '#[#]', _globalObject, name);
       String unmangledName = mangledGlobalNames[name];
       if (unmangledName == null) {
         // If there is no unmangledName, [jsFunction] is either a synthetic
@@ -794,9 +803,7 @@
       String mangledName = keys[i];
       if (mangledName == '') continue; // Skip static field descriptor.
       String unmangledName = mangledName;
-      // TODO(ahe): Create accessor for accessing $.  It is also
-      // used in js_helper.
-      var jsFunction = JS('', '#[#]', JS_CURRENT_ISOLATE(), mangledName);
+      var jsFunction = JS('', '#[#]', owner._globalObject, mangledName);
 
       bool isConstructor = false;
       if (i + 1 < length) {
@@ -926,6 +933,8 @@
   InstanceMirror setField(Symbol fieldName, Object arg) {
     JsVariableMirror mirror = variables[fieldName];
     if (mirror != null && mirror.isStatic && !mirror.isFinal) {
+      // '$' (JS_CURRENT_ISOLATE()) stores state which is stored directly, so
+      // we shouldn't use [JsLibraryMirror._globalObject] here.
       String jsName = mirror._jsName;
       if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
         throw new RuntimeError('Cannot find "$jsName" in current isolate.');
@@ -941,6 +950,8 @@
     JsVariableMirror mirror = variables[fieldName];
     if (mirror != null && mirror.isStatic) {
       String jsName = mirror._jsName;
+      // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
+      // we shouldn't use [JsLibraryMirror._globalObject] here.
       if (!JS('bool', '# in #', jsName, JS_CURRENT_ISOLATE())) {
         throw new RuntimeError('Cannot find "$jsName" in current isolate.');
       }
@@ -969,7 +980,7 @@
           orElse: () {
             // TODO(ahe): What receiver to use?
             throw new NoSuchMethodError(
-                owner, constructorName, positionalArguments, namedArguments);
+                this, constructorName, positionalArguments, namedArguments);
           });
       JsCache.update(_jsConstructorCache, n(constructorName), mirror);
     }
@@ -988,7 +999,7 @@
             constructorName, positionalArguments, namedArguments));
   }
 
-  DeclarationMirror get owner {
+  JsLibraryMirror get owner {
     if (_owner == null) {
       if (_jsConstructorOrInterceptor is Interceptor) {
         _owner = reflectType(Object).owner;
@@ -1363,6 +1374,10 @@
       throw new NoSuchMethodError(
           owner, simpleName, positionalArguments, namedArguments);
     }
+    // Using JS_CURRENT_ISOLATE() ('$') here is actually correct, although
+    // _jsFunction may not be a property of '$', most static functions do not
+    // care who their receiver is. But to lazy getters, it is important that
+    // 'this' is '$'.
     return JS('', r'#.apply(#, #)', _jsFunction, JS_CURRENT_ISOLATE(),
               new List.from(positionalArguments));
   }
diff --git a/sdk/lib/_internal/lib/js_number.dart b/sdk/lib/_internal/lib/js_number.dart
index 445e927..8dd89d8 100644
--- a/sdk/lib/_internal/lib/js_number.dart
+++ b/sdk/lib/_internal/lib/js_number.dart
@@ -278,6 +278,65 @@
 
   bool get isOdd => (this & 1) == 1;
 
+  int toUnsigned(int width) {
+    return this & ((1 << width) - 1);
+  }
+
+  int toSigned(int width) {
+    int signMask = 1 << (width - 1);
+    return (this & (signMask - 1)) - (this & signMask);
+  }
+
+  int get bitLength {
+    int nonneg = this < 0 ? -this-1 : this;
+    if (nonneg >= 0x100000000) {
+      nonneg = nonneg ~/ 0x100000000;
+      return _bitCount(_spread(nonneg)) + 32;
+    }
+    return _bitCount(_spread(nonneg));
+  }
+
+  // Assumes i is <= 32-bit and unsigned.
+  static int _bitCount(int i) {
+    // See "Hacker's Delight", section 5-1, "Counting 1-Bits".
+
+    // The basic strategy is to use "divide and conquer" to
+    // add pairs (then quads, etc.) of bits together to obtain
+    // sub-counts.
+    //
+    // A straightforward approach would look like:
+    //
+    // i = (i & 0x55555555) + ((i >>  1) & 0x55555555);
+    // i = (i & 0x33333333) + ((i >>  2) & 0x33333333);
+    // i = (i & 0x0F0F0F0F) + ((i >>  4) & 0x0F0F0F0F);
+    // i = (i & 0x00FF00FF) + ((i >>  8) & 0x00FF00FF);
+    // i = (i & 0x0000FFFF) + ((i >> 16) & 0x0000FFFF);
+    //
+    // The code below removes unnecessary &'s and uses a
+    // trick to remove one instruction in the first line.
+
+    i = _shru(i, 0) - (_shru(i, 1) & 0x55555555);
+    i = (i & 0x33333333) + (_shru(i, 2) & 0x33333333);
+    i = 0x0F0F0F0F & (i + _shru(i, 4));
+    i += _shru(i, 8);
+    i += _shru(i, 16);
+    return (i & 0x0000003F);
+  }
+
+  static _shru(int value, int shift) => JS('int', '# >>> #', value, shift);
+  static _shrs(int value, int shift) => JS('int', '# >> #', value, shift);
+  static _ors(int a, int b) => JS('int', '# | #', a, b);
+
+  // Assumes i is <= 32-bit
+  static int _spread(int i) {
+    i = _ors(i, _shrs(i, 1));
+    i = _ors(i, _shrs(i, 2));
+    i = _ors(i, _shrs(i, 4));
+    i = _ors(i, _shrs(i, 8));
+    i = _shru(_ors(i, _shrs(i, 16)), 0);
+    return i;
+  }
+
   Type get runtimeType => int;
 
   int operator ~() => JS('int', r'(~#) >>> 0', this);
diff --git a/sdk/lib/_internal/lib/js_rti.dart b/sdk/lib/_internal/lib/js_rti.dart
index f582c1a..432d237 100644
--- a/sdk/lib/_internal/lib/js_rti.dart
+++ b/sdk/lib/_internal/lib/js_rti.dart
@@ -350,9 +350,9 @@
   if (hasField(interceptor, '${JS_OPERATOR_IS_PREFIX()}_$signatureName')) {
     return true;
   }
-  var signatureLocation = JS_GLOBAL_OBJECT();
+  var signatureLocation = JS_CURRENT_ISOLATE();
   if (isNotNull(contextName)) {
-    signatureLocation = getField(signatureLocation, contextName);
+    signatureLocation = getField(JS('=Object', 'init.allClasses'), contextName);
   }
   var typeSignature =
       getField(signatureLocation, '${JS_SIGNATURE_NAME()}_$signatureName');
diff --git a/sdk/lib/_internal/lib/js_string.dart b/sdk/lib/_internal/lib/js_string.dart
index adc32e8..8a8ac16 100644
--- a/sdk/lib/_internal/lib/js_string.dart
+++ b/sdk/lib/_internal/lib/js_string.dart
@@ -44,8 +44,6 @@
     return JS('String', r'# + #', this, other);
   }
 
-  String concat(String other) => this + other;
-
   bool endsWith(String other) {
     checkString(other);
     int otherLength = other.length;
diff --git a/sdk/lib/_internal/lib/regexp_helper.dart b/sdk/lib/_internal/lib/regexp_helper.dart
index bec8253..09fe861 100644
--- a/sdk/lib/_internal/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/lib/regexp_helper.dart
@@ -17,9 +17,9 @@
  * when it's returned, with no user-provided code run in between.
  */
 regExpGetGlobalNative(JSSyntaxRegExp regexp) {
-  var regexp = regexp._nativeGlobalVersion;
-  JS("void", "#.lastIndex = 0", regexp);
-  return regexp;
+  var nativeRegexp = regexp._nativeGlobalVersion;
+  JS("void", "#.lastIndex = 0", nativeRegexp);
+  return nativeRegexp;
 }
 
 class JSSyntaxRegExp implements RegExp {
diff --git a/sdk/lib/_internal/pub/lib/src/barback.dart b/sdk/lib/_internal/pub/lib/src/barback.dart
index 36de8dc..3c14a16 100644
--- a/sdk/lib/_internal/pub/lib/src/barback.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback.dart
@@ -8,13 +8,45 @@
 
 import 'package:barback/barback.dart';
 
-import 'barback/load_transformers.dart';
+import 'barback/load_all_transformers.dart';
 import 'barback/pub_package_provider.dart';
 import 'barback/rewrite_import_transformer.dart';
 import 'barback/server.dart';
 import 'barback/watch_sources.dart';
 import 'utils.dart';
 
+/// An identifier for a transformer and the configuration that will be passed to
+/// it.
+///
+/// It's possible that [asset] defines multiple transformers. If so,
+/// [configuration] will be passed to all of them.
+class TransformerId {
+  /// The asset containing the transformer.
+  final AssetId asset;
+
+  /// The configuration to pass to the transformer.
+  ///
+  /// This will be null if no configuration was provided.
+  final Map configuration;
+
+  TransformerId(this.asset, this.configuration) {
+    if (configuration == null) return;
+    for (var reserved in ['include', 'exclude']) {
+      if (!configuration.containsKey(reserved)) continue;
+      throw new FormatException('Configuration for transformer '
+          '${idToLibraryIdentifier(asset)} may not include reserved key '
+          '"$reserved".');
+    }
+  }
+
+  // TODO(nweiz): support deep equality on [configuration] as well.
+  bool operator==(other) => other is TransformerId &&
+      other.asset == asset &&
+      other.configuration == configuration;
+
+  int get hashCode => asset.hashCode ^ configuration.hashCode;
+}
+
 /// Creates a [BarbackServer] serving on [host] and [port].
 ///
 /// This transforms and serves all library and asset files in all packages in
@@ -44,7 +76,7 @@
       })
     ];
 
-    _loadTransformers(server, graph).then((_) {
+    loadAllTransformers(server, graph).then((_) {
       if (!completer.isCompleted) completer.complete(server);
     }).catchError((error) {
       if (!completer.isCompleted) completer.completeError(error);
@@ -58,49 +90,55 @@
   });
 }
 
-/// Loads all transformers depended on by packages in [graph].
+/// Parses a library identifier to an asset id.
 ///
-/// This uses [server] to serve the Dart files from which transformers are
-/// loaded, then adds the transformers to `server.barback`.
-Future _loadTransformers(BarbackServer server, PackageGraph graph) {
-  // Add a rewrite transformer for each package, so that we can resolve
-  // "package:" imports while loading transformers.
-  var rewrite = new RewriteImportTransformer();
-  for (var package in graph.packages.values) {
-    server.barback.updateTransformers(package.name, [[rewrite]]);
+/// A library identifier is a string of the form "package_name" or
+/// "package_name/path/to/library". It does not have a trailing extension. If it
+/// just has a package name, it expands to lib/${package}.dart in that package.
+/// Otherwise, it expands to lib/${path}.dart in that package.
+AssetId libraryIdentifierToId(String identifier) {
+  if (identifier.isEmpty) {
+    throw new FormatError('Invalid library identifier: "".');
   }
 
-  // A map from each transformer id to the set of packages that use it.
-  var idsToPackages = new Map<AssetId, Set<String>>();
-  for (var package in graph.packages.values) {
-    for (var id in unionAll(package.pubspec.transformers)) {
-      idsToPackages.putIfAbsent(id, () => new Set<String>()).add(package.name);
-    }
+  // Convert the concise asset name in the pubspec (of the form "package"
+  // or "package/library") to an AssetId that points to an actual dart
+  // file ("package/lib/package.dart" or "package/lib/library.dart",
+  // respectively).
+  var parts = split1(identifier, "/");
+  if (parts.length == 1) parts.add(parts.single);
+  return new AssetId(parts.first, 'lib/' + parts.last + '.dart');
+}
+
+final _libraryPathRegExp = new RegExp(r"^lib/(.*)\.dart$");
+
+/// Converts [id] to a library identifier.
+///
+/// A library identifier is a string of the form "package_name" or
+/// "package_name/path/to/library". It does not have a trailing extension. If it
+/// just has a package name, it expands to lib/${package}.dart in that package.
+/// Otherwise, it expands to lib/${path}.dart in that package.
+///
+/// This will throw an [ArgumentError] if [id] doesn't represent a library in
+/// `lib/`.
+String idToLibraryIdentifier(AssetId id) {
+  var match = _libraryPathRegExp.firstMatch(id.path);
+  if (match == null) {
+    throw new ArgumentError("Asset id $id doesn't identify a library.");
   }
 
-  // TODO(nweiz): support transformers that (possibly transitively)
-  // depend on other transformers.
-  var transformersForId = new Map<AssetId, Set<Transformer>>();
-  return Future.wait(idsToPackages.keys.map((id) {
-    return loadTransformers(server, id).then((transformers) {
-      if (transformers.isEmpty) {
-        var path = id.path.replaceFirst('lib/', '');
-        // Ensure that packages are listed in a deterministic order.
-        var packages = idsToPackages[id].toList();
-        packages.sort();
-        throw new ApplicationException(
-            "No transformers were defined in package:${id.package}/$path,\n"
-            "required by ${packages.join(', ')}.");
-      }
+  if (match[1] == id.package) return id.package;
+  return '${id.package}/${match[1]}';
+}
 
-      transformersForId[id] = transformers;
-    });
-  })).then((_) {
-    for (var package in graph.packages.values) {
-      var phases = package.pubspec.transformers.map((phase) {
-        return unionAll(phase.map((id) => transformersForId[id]));
-      });
-      server.barback.updateTransformers(package.name, phases);
-    }
-  });
+/// Converts [id] to a "package:" URI.
+///
+/// This will throw an [ArgumentError] if [id] doesn't represent a library in
+/// `lib/`.
+Uri idToPackageUri(AssetId id) {
+  if (!id.path.startsWith('lib/')) {
+    throw new ArgumentError("Asset id $id doesn't identify a library.");
+  }
+
+  return new Uri(scheme: 'package', path: id.path.replaceFirst('lib/', ''));
 }
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
new file mode 100644
index 0000000..e954da8
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
@@ -0,0 +1,252 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub.load_all_transformers;
+
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+
+import 'load_transformers.dart';
+import 'rewrite_import_transformer.dart';
+import 'server.dart';
+import 'watch_sources.dart';
+import '../barback.dart';
+import '../utils.dart';
+
+/// Loads all transformers depended on by packages in [graph].
+///
+/// This uses [server] to serve the Dart files from which transformers are
+/// loaded, then adds the transformers to `server.barback`.
+Future loadAllTransformers(BarbackServer server, PackageGraph graph) {
+  // In order to determine in what order we should load transformers, we need to
+  // know which transformers depend on which others. This is different than
+  // normal package dependencies. Let's begin with some terminology:
+  //
+  // * If package A is transformed by package B, we say A has a "transformer
+  //   dependency" on B.
+  // * If A imports B we say A has a "package dependency" on B.
+  // * If A needs B's transformers to be loaded in order to load A's
+  //   transformers, we say A has an "ordering dependency" on B.
+  //
+  // In particular, an ordering dependency is defined as follows:
+  //
+  // * If A has a transformer dependency on B, A also has an ordering dependency
+  //   on B.
+  // * If A has a transitive package dependency on B and B has a transformer
+  //   dependency on C, A has an ordering dependency on C.
+  //
+  // The order that transformers are loaded is determined by each package's
+  // ordering dependencies. We treat the packages as a directed acyclic[1] graph
+  // where each package is a node and the ordering dependencies are the edges
+  // (that is, the packages form a partially ordered set). We then load[2]
+  // packages in a topological sort order of this graph.
+  //
+  // [1] TODO(nweiz): support cycles in some cases.
+  //
+  // [2] We use "loading a package" as a shorthand for loading that package's
+  //     transformers.
+
+  // Add a rewrite transformer for each package, so that we can resolve
+  // "package:" imports while loading transformers.
+  var rewrite = new RewriteImportTransformer();
+  for (var package in graph.packages.values) {
+    server.barback.updateTransformers(package.name, [[rewrite]]);
+  }
+
+  var orderingDeps = _computeOrderingDeps(graph);
+  var packageTransformers = _computePackageTransformers(graph);
+
+  var loader = new _TransformerLoader(server, graph);
+
+  // The packages on which no packages have ordering dependencies -- that is,
+  // the packages that don't need to be loaded before any other packages. These
+  // packages will be loaded last, since all of their ordering dependencies need
+  // to be loaded before they're loaded. However, they'll be traversed by
+  // [loadPackage] first.
+  var rootPackages = graph.packages.keys.toSet()
+      .difference(unionAll(orderingDeps.values));
+
+  // The Futures for packages that have been loaded or are being actively loaded
+  // by [loadPackage]. Once one of these Futures is complete, the transformers
+  // for that package will all be available from [loader].
+  var loadingPackages = new Map<String, Future>();
+
+  // A helper function that loads all the transformers that [package] uses, then
+  // all the transformers that [package] defines.
+  Future loadPackage(String package) {
+    if (loadingPackages.containsKey(package)) return loadingPackages[package];
+
+    // First, load each package upon which [package] has an ordering dependency.
+    var future = Future.wait(orderingDeps[package].map(loadPackage)).then((_) {
+      // Go through the transformers used by [package] phase-by-phase. If any
+      // phase uses a transformer defined in [package] itself, that transform
+      // should be loaded after running all previous phases.
+      var transformers = [[rewrite]];
+      return Future.forEach(graph.packages[package].pubspec.transformers,
+          (phase) {
+        return Future.wait(phase.where((id) => id.asset.package == package)
+            .map(loader.load)).then((_) {
+          transformers.add(unionAll(phase.map(
+              (id) => loader.transformersFor(id))));
+          server.barback.updateTransformers(package, transformers);
+        });
+      }).then((_) {
+        // Now that we've applied all the transformers used by [package] via
+        // [Barback.updateTransformers], we load any transformers defined in
+        // [package] but used elsewhere.
+        return Future.wait(packageTransformers[package].map(loader.load));
+      });
+    });
+    loadingPackages[package] = future;
+    return future;
+  }
+
+  return Future.wait(rootPackages.map(loadPackage)).then((_) {
+    /// Reset the transformers for each package to get rid of [rewrite], which
+    /// is no longer needed.
+    for (var package in graph.packages.values) {
+      var phases = package.pubspec.transformers.map((phase) {
+        return unionAll(phase.map((id) => loader.transformersFor(id)));
+      });
+      server.barback.updateTransformers(package.name, phases);
+    }
+  });
+}
+
+/// Computes and returns the graph of ordering dependencies for [graph].
+///
+/// This graph is in the form of a map whose keys are packages and whose values
+/// are those packages' ordering dependencies.
+Map<String, Set<String>> _computeOrderingDeps(PackageGraph graph) {
+  var orderingDeps = new Map<String, Set<String>>();
+  // Iterate through the packages in a deterministic order so that if there are
+  // multiple cycles we choose which to print consistently.
+  var packages = ordered(graph.packages.values.map((package) => package.name));
+  for (var package in packages) {
+    // This package's transformer dependencies are also ordering dependencies.
+    var deps = _transformerDeps(graph, package);
+    deps.remove(package);
+    // The transformer dependencies of this package's transitive package
+    // dependencies are also ordering dependencies for this package.
+    var transitivePackageDeps = graph.transitiveDependencies(package)
+        .map((package) => package.name);
+    for (var packageDep in ordered(transitivePackageDeps)) {
+      var transformerDeps = _transformerDeps(graph, packageDep);
+      if (transformerDeps.contains(package)) {
+        throw _cycleError(graph, package, packageDep);
+      }
+      deps.addAll(transformerDeps);
+    }
+    orderingDeps[package] = deps;
+  }
+
+  return orderingDeps;
+}
+
+/// Returns the set of transformer dependencies for [package].
+Set<String> _transformerDeps(PackageGraph graph, String package) =>
+  unionAll(graph.packages[package].pubspec.transformers)
+      .map((id) => id.asset.package).toSet();
+
+/// Returns an [ApplicationException] describing an ordering dependency cycle
+/// detected in [graph].
+///
+/// [dependee] and [depender] should be the names of two packages known to be in
+/// the cycle. In addition, [depender] should have a transformer dependency on
+/// [dependee].
+ApplicationException _cycleError(PackageGraph graph, String dependee,
+    String depender) {
+  assert(_transformerDeps(graph, depender).contains(dependee));
+
+  var simpleGraph = mapMapValues(graph.packages,
+      (_, package) => package.dependencies.map((dep) => dep.name).toList());
+  var path = shortestPath(simpleGraph, dependee, depender);
+  path.add(dependee);
+  return new ApplicationException("Transformer cycle detected:\n" +
+      pairs(path).map((pair) {
+    var transformers = unionAll(graph.packages[pair.first].pubspec.transformers)
+        .where((id) => id.asset.package == pair.last)
+        .map(idToLibraryIdentifier).toList();
+    if (transformers.isEmpty) {
+      return "  ${pair.first} depends on ${pair.last}";
+    } else {
+      return "  ${pair.first} is transformed by ${toSentence(transformers)}";
+    }
+  }).join("\n"));
+}
+
+/// Returns a map from each package name in [graph] to the transformer ids of
+/// all transformers exposed by that package and used by other packages.
+Map<String, Set<TransformerId>> _computePackageTransformers(
+    PackageGraph graph) {
+  var packageTransformers = listToMap(graph.packages.values,
+      (package) => package.name, (_) => new Set<TransformerId>());
+  for (var package in graph.packages.values) {
+    for (var phase in package.pubspec.transformers) {
+      for (var id in phase) {
+        packageTransformers[id.asset.package].add(id);
+      }
+    }
+  }
+  return packageTransformers;
+}
+
+/// A class that loads transformers defined in specific files.
+class _TransformerLoader {
+  final BarbackServer _server;
+
+  /// The loaded transformers defined in the library identified by each
+  /// transformer id.
+  final _transformers = new Map<TransformerId, Set<Transformer>>();
+
+  /// The packages that use each transformer asset id.
+  ///
+  /// Used for error reporting.
+  final _transformerUsers = new Map<AssetId, Set<String>>();
+
+  _TransformerLoader(this._server, PackageGraph graph) {
+    for (var package in graph.packages.values) {
+      for (var id in unionAll(package.pubspec.transformers)) {
+        _transformerUsers.putIfAbsent(id.asset, () => new Set<String>())
+            .add(package.name);
+      }
+    }
+  }
+
+  /// Loads the transformer(s) defined in [id].
+  ///
+  /// Once the returned future completes, these transformers can be retrieved
+  /// using [transformersFor]. If [id] doesn't define any transformers, this
+  /// will complete to an error.
+  Future load(TransformerId id) {
+    if (_transformers.containsKey(id)) return new Future.value();
+
+    // TODO(nweiz): load multiple instances of the same transformer from the
+    // same isolate rather than spinning up a separate isolate for each one.
+    return loadTransformers(_server, id).then((transformers) {
+      if (!transformers.isEmpty) {
+        _transformers[id] = transformers;
+        return;
+      }
+
+      var message = "No transformers";
+      if (id.configuration != null) {
+        message += " that accept configuration";
+      }
+      throw new ApplicationException(
+          "$message were defined in ${idToPackageUri(id.asset)},\n"
+          "required by ${ordered(_transformerUsers[id.asset]).join(', ')}.");
+    });
+  }
+
+  /// Returns the set of transformers for [id].
+  ///
+  /// It's an error to call this before [load] is called with [id] and the
+  /// future it returns has completed.
+  Set<Transformers> transformersFor(TransformerId id) {
+    assert(_transformers.containsKey(id));
+    return _transformers[id];
+  }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
index 72634bc..b2c8464 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
@@ -2,9 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library pub.serialize_transformer;
+library pub.load_transformers;
 
 import 'dart:async';
+import 'dart:convert';
 import 'dart:isolate';
 
 import 'package:barback/barback.dart';
@@ -21,15 +22,19 @@
 const _TRANSFORMER_ISOLATE = """
 import 'dart:async';
 import 'dart:isolate';
+import 'dart:convert';
 import 'dart:mirrors';
 
 import 'http://localhost:<<PORT>>/packages/barback/barback.dart';
 
 /// Sets up the initial communication with the host isolate.
 void main() {
-  port.receive((uri, replyTo) {
+  port.receive((args, replyTo) {
     _sendFuture(replyTo, new Future.sync(() {
-      return initialize(Uri.parse(uri)).map(_serializeTransformer).toList();
+      var library = Uri.parse(args['library']);
+      var configuration = JSON.decode(args['configuration']);
+      return initialize(library, configuration).
+          map(_serializeTransformer).toList();
     }));
   });
 }
@@ -37,8 +42,8 @@
 /// Loads all the transformers defined in [uri] and adds them to [transformers].
 ///
 /// We then load the library, find any Transformer subclasses in it, instantiate
-/// them, and return them.
-Iterable<Transformer> initialize(Uri uri) {
+/// them (with [configuration] if it's non-null), and return them.
+Iterable<Transformer> initialize(Uri uri, Map configuration) {
   var mirrors = currentMirrorSystem();
   // TODO(nweiz): look this up by name once issue 5897 is fixed.
   var transformerUri = Uri.parse(
@@ -46,17 +51,30 @@
   var transformerClass = mirrors.libraries[transformerUri]
       .classes[const Symbol('Transformer')];
 
-  return mirrors.libraries[uri].classes.values.where((classMirror) {
-    if (classMirror.isPrivate) return false;
-    if (isAbstract(classMirror)) return false;
-    if (!classIsA(classMirror, transformerClass)) return false;
-    var constructor = classMirror.constructors[classMirror.simpleName];
-    if (constructor == null) return false;
-    if (!constructor.parameters.isEmpty) return false;
-    return true;
-  }).map((classMirror) {
-    return classMirror.newInstance(const Symbol(''), []).reflectee;
-  });
+  // TODO(nweiz): if no valid transformers are found, throw an error message
+  // describing candidates and why they were rejected.
+  return mirrors.libraries[uri].classes.values.map((classMirror) {
+    if (classMirror.isPrivate) return null;
+    if (isAbstract(classMirror)) return null;
+    if (!classIsA(classMirror, transformerClass)) return null;
+
+    var constructor = getConstructor(classMirror, 'asPlugin');
+    if (constructor == null) return null;
+    if (constructor.parameters.isEmpty) {
+      if (configuration != null) return null;
+      return classMirror.newInstance(const Symbol('asPlugin'), []).reflectee;
+    }
+    if (constructor.parameters.length != 1) return null;
+
+    // If the constructor expects configuration and none was passed, it defaults
+    // to an empty map.
+    if (configuration == null) configuration = {};
+
+    // TODO(nweiz): if the constructor accepts named parameters, automatically
+    // destructure the configuration map.
+    return classMirror.newInstance(const Symbol('asPlugin'), [configuration])
+        .reflectee;
+  }).where((classMirror) => classMirror != null);
 }
 
 /// A wrapper for a [Transform] that's in the host isolate.
@@ -107,6 +125,13 @@
 }
 ClassMirror _objectMirror;
 
+// TODO(nweiz): clean this up when issue 13248 is fixed.
+MethodMirror getConstructor(ClassMirror classMirror, String constructor) {
+  var name = new Symbol("\${MirrorSystem.getName(classMirror.simpleName)}"
+      ".\$constructor");
+  return classMirror.constructors[name];
+}
+
 // TODO(nweiz): get rid of this when issue 12439 is fixed.
 /// Returns whether or not [mirror] is a subtype of [superclass].
 ///
@@ -256,23 +281,28 @@
 }
 """;
 
-/// Load and return all transformers from the library identified by [library].
+/// Load and return all transformers from the library identified by [id].
 ///
-/// [server] is used to serve [library] and any Dart files it imports.
+/// [server] is used to serve any Dart files needed to load the transformer.
 Future<Set<Transformer>> loadTransformers(BarbackServer server,
-    AssetId library) {
-  var path = library.path.replaceFirst('lib/', '');
+    TransformerId id) {
+  var path = id.asset.path.replaceFirst('lib/', '');
   // TODO(nweiz): load from a "package:" URI when issue 12474 is fixed.
-  var uri = 'http://localhost:${server.port}/packages/${library.package}/$path';
+  var uri = 'http://localhost:${server.port}/packages/${id.asset.package}/'
+      '$path';
   var code = 'import "$uri";' +
       _TRANSFORMER_ISOLATE.replaceAll('<<PORT>>', server.port.toString());
-  log.fine("Loading transformers from $library");
+  log.fine("Loading transformers from ${id.asset}");
   return dart.runInIsolate(code).then((sendPort) {
-    return _receiveFuture(sendPort.call(uri)).then((transformers) {
+    return _receiveFuture(sendPort.call({
+      'library': uri,
+      // TODO(nweiz): support non-JSON-encodable configuration maps.
+      'configuration': JSON.encode(id.configuration)
+    })).then((transformers) {
       transformers = transformers
           .map((transformer) => new _ForeignTransformer(transformer))
           .toSet();
-      log.fine("Transformers from $library: $transformers");
+      log.fine("Transformers from ${id.asset}: $transformers");
       return transformers;
     });
   }).catchError((error) {
@@ -287,7 +317,7 @@
     // If there was an IsolateSpawnException and the import that actually failed
     // was the one we were loading transformers from, throw an application
     // exception with a more user-friendly message.
-    fail('Transformer library "package:${library.package}/$path" not found.');
+    fail('Transformer library "package:${id.asset.package}/$path" not found.');
   });
 }
 
diff --git a/sdk/lib/_internal/pub/lib/src/directory_tree.dart b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
index ad67e26..b0d0710 100644
--- a/sdk/lib/_internal/pub/lib/src/directory_tree.dart
+++ b/sdk/lib/_internal/pub/lib/src/directory_tree.dart
@@ -7,6 +7,8 @@
 
 import 'package:path/path.dart' as path;
 
+import 'utils.dart';
+
 /// Draws a directory tree for the given list of files. Given a list of files
 /// like:
 ///
@@ -101,8 +103,7 @@
   if (name != null) _drawLine(buffer, prefix, isLast, name);
 
   // Recurse to the children.
-  var childNames = new List.from(children.keys);
-  childNames.sort();
+  var childNames = ordered(children.keys);
 
   _drawChild(bool isLastChild, String child) {
     var childPrefix = _getPrefix(name == null, isLast);
diff --git a/sdk/lib/_internal/pub/lib/src/package_graph.dart b/sdk/lib/_internal/pub/lib/src/package_graph.dart
index 687b720..634eb5c 100644
--- a/sdk/lib/_internal/pub/lib/src/package_graph.dart
+++ b/sdk/lib/_internal/pub/lib/src/package_graph.dart
@@ -18,4 +18,22 @@
   final Map<String, Package> packages;
 
   PackageGraph(this.entrypoint, this.packages);
+
+  /// Returns the set of transitive dependencies of the package named
+  /// [packageName].
+  Set<Package> transitiveDependencies(String packageName) {
+    var seen = new Set<Package>();
+    traverse(Package package) {
+      if (seen.contains(package)) return;
+      seen.add(package);
+      for (var dep in package.dependencies) {
+        traverse(packages[dep.name]);
+      }
+    }
+
+    var package = packages[packageName];
+    traverse(package);
+    seen.remove(package);
+    return seen;
+  }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/pubspec.dart b/sdk/lib/_internal/pub/lib/src/pubspec.dart
index ba0df4d..0813315 100644
--- a/sdk/lib/_internal/pub/lib/src/pubspec.dart
+++ b/sdk/lib/_internal/pub/lib/src/pubspec.dart
@@ -8,6 +8,7 @@
 import 'package:yaml/yaml.dart';
 import 'package:path/path.dart' as path;
 
+import 'barback.dart';
 import 'io.dart';
 import 'package.dart';
 import 'source.dart';
@@ -29,9 +30,8 @@
   /// The packages this package depends on when it is the root package.
   final List<PackageDep> devDependencies;
 
-  /// The ids of the libraries containing the transformers to use for this
-  /// package.
-  final List<Set<AssetId>> transformers;
+  /// The ids of the transformers to use for this package.
+  final List<Set<TransformerId>> transformers;
 
   /// The environment-related metadata.
   final PubspecEnvironment environment;
@@ -73,7 +73,7 @@
       dependencies = <PackageDep>[],
       devDependencies = <PackageDep>[],
       environment = new PubspecEnvironment(),
-      transformers = <Set<AssetId>>[],
+      transformers = <Set<TransformerId>>[],
       fields = {};
 
   /// Whether or not the pubspec has no contents.
@@ -157,8 +157,7 @@
     if (collisions.length == 1) {
       packageNames = 'Package "${collisions.first}"';
     } else {
-      var names = collisions.toList();
-      names.sort();
+      var names = ordered(collisions);
       var buffer = new StringBuffer();
       buffer.write("Packages ");
       for (var i = 0; i < names.length; i++) {
@@ -174,6 +173,7 @@
 
       packageNames = buffer.toString();
     }
+
     throw new FormatException(
         '$packageNames cannot appear in both "dependencies" and '
         '"dev_dependencies".');
@@ -189,18 +189,28 @@
     transformers = transformers.map((phase) {
       if (phase is! List) phase = [phase];
       return phase.map((transformer) {
-        if (transformer is! String) {
+        if (transformer is! String && transformer is! Map) {
           throw new FormatException(
-              'Transformer "$transformer" must be a string.');
+              'Transformer "$transformer" must be a string or map.');
         }
 
-        // Convert the concise asset name in the pubspec (of the form "package"
-        // or "package/library") to an AssetId that points to an actual dart
-        // file ("package/lib/package.dart" or "package/lib/library.dart",
-        // respectively).
-        var parts = split1(transformer, "/");
-        if (parts.length == 1) parts.add(parts.single);
-        var id = new AssetId(parts.first, 'lib/' + parts.last + '.dart');
+        var id;
+        var configuration;
+        if (transformer is String) {
+          id = libraryIdentifierToId(transformer);
+        } else {
+          if (transformer.length != 1) {
+            throw new FormatException('Transformer map "$transformer" must '
+                'have a single key: the library identifier.');
+          }
+
+          id = libraryIdentifierToId(transformer.keys.single);
+          configuration = transformer.values.single;
+          if (configuration is! Map) {
+            throw new FormatException('Configuration for transformer "$id" '
+                'must be a map, but was "$configuration".');
+          }
+        }
 
         if (id.package != name &&
             !dependencies.any((ref) => ref.name == id.package)) {
@@ -208,7 +218,7 @@
               '"$transformer".');
         }
 
-        return id;
+        return new TransformerId(id, configuration);
       }).toSet();
     }).toList();
   } else {
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
index eb2fc63..09d5fbf 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -187,8 +187,7 @@
       map[dep.depender] = dep.dep;
     }
 
-    var names = map.keys.toList();
-    names.sort();
+    var names = ordered(map.keys);
 
     buffer.writeAll(names.map(
         (name) => "- '$name' ${_describeDependency(map[name])}"), '\n');
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 44f530a..acca0bb 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -7,6 +7,7 @@
 
 import 'dart:async';
 import 'dart:io';
+import "dart:collection";
 import "dart:convert";
 import 'dart:mirrors';
 
@@ -91,6 +92,15 @@
   return result.toString();
 }
 
+/// Returns a sentence fragment listing the elements of [iter].
+///
+/// This converts each element of [iter] to a string and separates them with
+/// commas and/or "and" where appropriate.
+String toSentence(Iterable iter) {
+  if (iter.length == 1) return iter.first.toString();
+  return iter.take(iter.length - 1).join(", ") + " and ${iter.last}";
+}
+
 /// Flattens nested lists inside an iterable into a single list containing only
 /// non-list elements.
 List flatten(Iterable nested) {
@@ -126,6 +136,115 @@
   return minuendSet;
 }
 
+/// Returns a list containing the sorted elements of [iter].
+List ordered(Iterable<Comparable> iter) {
+  var list = iter.toList();
+  list.sort();
+  return list;
+}
+
+/// Returns the element of [iter] for which [f] returns the minimum value.
+minBy(Iterable iter, Comparable f(element)) {
+  var min = null;
+  var minComparable = null;
+  for (var element in iter) {
+    var comparable = f(element);
+    if (minComparable == null ||
+        comparable.compareTo(minComparable) < 0) {
+      min = element;
+      minComparable = comparable;
+    }
+  }
+  return min;
+}
+
+/// Returns every pair of consecutive elements in [iter].
+///
+/// For example, if [iter] is `[1, 2, 3, 4]`, this will return `[(1, 2), (2, 3),
+/// (3, 4)]`.
+Iterable<Pair> pairs(Iterable iter) {
+  var previous = iter.first;
+  return iter.skip(1).map((element) {
+    var oldPrevious = previous;
+    previous = element;
+    return new Pair(oldPrevious, element);
+  });
+}
+
+/// Creates a map from [iter], using the return values of [keyFn] as the keys
+/// and the return values of [valueFn] as the values.
+Map listToMap(Iterable iter, keyFn(element), valueFn(element)) {
+  var map = new Map();
+  for (var element in iter) {
+    map[keyFn(element)] = valueFn(element);
+  }
+  return map;
+}
+
+/// Creates a new map from [map] with new keys and values.
+///
+/// The return values of [keyFn] are used as the keys and the return values of
+/// [valueFn] are used as the values for the new map.
+Map mapMap(Map map, keyFn(key, value), valueFn(key, value)) =>
+  listToMap(map.keys,
+      (key) => keyFn(key, map[key]),
+      (key) => valueFn(key, map[key]));
+
+/// Creates a new map from [map] with the same keys.
+///
+/// The return values of [valueFn] are used as the values for the new map.
+Map mapMapValues(Map map, fn(key, value)) => mapMap(map, (key, _) => key, fn);
+
+/// Returns the shortest path from [start] to [end] in [graph].
+///
+/// The graph is represented by a map whose keys are vertices and whose values
+/// are vertices reachable from the keys. [start] and [end] must be vertices in
+/// this graph.
+List shortestPath(Map<dynamic, Iterable> graph, start, end) {
+  assert(graph.containsKey(start));
+  assert(graph.containsKey(end));
+
+  // Dijkstra's algorithm.
+  var infinity = graph.length;
+  var distance = mapMapValues(graph, (_1, _2) => infinity);
+
+  // A map from each node to the node that came before it on the shortest path
+  // from it back to [start].
+  var previous = {};
+
+  distance[start] = 0;
+  var remaining = graph.keys.toSet();
+  while (!remaining.isEmpty) {
+    var current = minBy(remaining, (node) => distance[node]);
+    remaining.remove(current);
+
+    // If there's no remaining node that's reachable from [start], then there's
+    // no path from [start] to [end].
+    if (distance[current] == infinity) return null;
+
+    // If we've reached [end], we've found the shortest path to it and we just
+    // need to reconstruct that path.
+    if (current == end) break;
+
+    for (var neighbor in graph[current]) {
+      if (!remaining.contains(neighbor)) continue;
+      var newDistance = distance[current] + 1;
+      if (newDistance >= distance[neighbor]) continue;
+      distance[neighbor] = newDistance;
+      previous[neighbor] = current;
+    }
+  }
+
+  var path = new Queue();
+  var current = end;
+  while (current != null) {
+    path.addFirst(current);
+    current = previous[current];
+  }
+
+  return path.toList();
+}
+
 /// Replace each instance of [matcher] in [source] with the return value of
 /// [fn].
 String replace(String source, Pattern matcher, String fn(Match)) {
diff --git a/sdk/lib/_internal/pub/test/pubspec_test.dart b/sdk/lib/_internal/pub/test/pubspec_test.dart
index 092611d..4404461 100644
--- a/sdk/lib/_internal/pub/test/pubspec_test.dart
+++ b/sdk/lib/_internal/pub/test/pubspec_test.dart
@@ -214,6 +214,15 @@
       expectFormatError('{author: abe, authors: ted}');
     });
 
+    test("throws if a transformer isn't a string or map", () {
+      expectFormatError('{transformers: 12}');
+      expectFormatError('{transformers: [12]}');
+    });
+
+    test("throws if a transformer's configuration isn't a map", () {
+      expectFormatError('{transformers: {pkg: 12}}');
+    });
+
     test("allows comment-only files", () {
       var pubspec = new Pubspec.parse(null, '''
 # No external dependencies yet
diff --git a/sdk/lib/_internal/pub/test/serve/configuration_defaults_to_empty_map_test.dart b/sdk/lib/_internal/pub/test/serve/configuration_defaults_to_empty_map_test.dart
new file mode 100644
index 0000000..bad8e52
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/configuration_defaults_to_empty_map_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'dart:convert';
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+final transformer = """
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:barback/barback.dart';
+
+class ConfigTransformer extends Transformer {
+  final Map configuration;
+
+  ConfigTransformer.asPlugin(this.configuration);
+
+  String get allowedExtensions => '.txt';
+
+  Future apply(Transform transform) {
+    return transform.primaryInput.readAsString().then((contents) {
+      var id = transform.primaryInput.id.changeExtension(".json");
+      transform.addOutput(new Asset.fromString(id, JSON.encode(configuration)));
+    });
+  }
+}
+""";
+
+main() {
+  initConfig();
+  integration("configuration defaults to an empty map", () {
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": ["myapp/src/transformer"]
+      }),
+      d.dir("lib", [d.dir("src", [
+        d.file("transformer.dart", transformer)
+      ])]),
+      d.dir("web", [
+        d.file("foo.txt", "foo")
+      ])
+    ]).create();
+
+    createLockFile('myapp', pkg: ['barback']);
+
+    var server = startPubServe();
+    requestShouldSucceed("foo.json", JSON.encode({}));
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/detects_a_transformer_cycle.dart b/sdk/lib/_internal/pub/test/serve/detects_a_transformer_cycle.dart
new file mode 100644
index 0000000..1da3080
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/detects_a_transformer_cycle.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("detects a transformer cycle", () {
+    d.dir("foo", [
+      d.pubspec({
+        "name": "foo",
+        "version": "1.0.0",
+        "transformers": ["myapp/transformer"],
+        "dependencies": {'myapp': {'path': '../myapp'}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('foo')),
+      ])
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": ["foo/transformer"],
+        "dependencies": {'foo': {'path': '../foo'}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('myapp')),
+      ])
+    ]).create();
+
+    createLockFile('myapp', sandbox: ['foo'], pkg: ['barback']);
+
+    // Use port 0 to get an ephemeral port.
+    var process = startPub(args: ["serve", "--port=0"]);
+    process.shouldExit(1);
+    expect(process.remainingStderr(), completion(equals(
+        "Transformer cycle detected:\n"
+        "  foo is transformed by myapp/transformer\n"
+        "  myapp is transformed by foo/transformer")));
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/detects_an_ordering_dependency_cycle.dart b/sdk/lib/_internal/pub/test/serve/detects_an_ordering_dependency_cycle.dart
new file mode 100644
index 0000000..3316e8d
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/detects_an_ordering_dependency_cycle.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("detects an ordering dependency cycle", () {
+    d.dir("foo", [
+      d.pubspec({
+        "name": "foo",
+        "version": "1.0.0",
+        "transformers": ["myapp/transformer"],
+        "dependencies": {'myapp': {'path': '../myapp'}}
+      })
+    ]).create();
+
+    d.dir("bar", [
+      d.pubspec({
+        "name": "bar",
+        "version": "1.0.0",
+        "dependencies": {'foo': {'path': '../foo'}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('bar')),
+      ])
+    ]).create();
+
+    d.dir("baz", [
+      d.pubspec({
+        "name": "baz",
+        "version": "1.0.0",
+        "transformers": ["bar/transformer"],
+        "dependencies": {'bar': {'path': '../bar'}}
+      })
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "dependencies": {'baz': {'path': '../baz'}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('myapp')),
+      ])
+    ]).create();
+
+    createLockFile('myapp', sandbox: ['foo', 'bar', 'baz'], pkg: ['barback']);
+
+    // Use port 0 to get an ephemeral port.
+    var process = startPub(args: ["serve", "--port=0"]);
+    process.shouldExit(1);
+    expect(process.remainingStderr(), completion(equals(
+        "Transformer cycle detected:\n"
+        "  bar depends on foo\n"
+        "  foo is transformed by myapp/transformer\n"
+        "  myapp depends on baz\n"
+        "  baz is transformed by bar/transformer")));
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_run_a_transform_on_an_input_in_another_package_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_run_a_transform_on_an_input_in_another_package_test.dart
index 3a39dd3..942a9e9 100644
--- a/sdk/lib/_internal/pub/test/serve/does_not_run_a_transform_on_an_input_in_another_package_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/does_not_run_a_transform_on_an_input_in_another_package_test.dart
@@ -32,9 +32,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {
-      'foo': '../foo'
-    }, pkg: ['barback']);
+    createLockFile('myapp', sandbox: ['foo'], pkg: ['barback']);
 
     startPubServe();
     requestShould404("assets/myapp/bar.out");
diff --git a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_file_that_defines_no_transforms_test.dart b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_file_that_defines_no_transforms_test.dart
index 3803c91..a636fcd 100644
--- a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_file_that_defines_no_transforms_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_file_that_defines_no_transforms_test.dart
@@ -23,7 +23,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     var pub = startPub(args: ['serve', '--port=0']);
     expect(pub.nextErrLine(), completion(startsWith('No transformers were '
diff --git a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_pubspec_with_reserved_transformer_config_test.dart b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_pubspec_with_reserved_transformer_config_test.dart
new file mode 100644
index 0000000..5ba03d8
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_pubspec_with_reserved_transformer_config_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+
+  integration("fails to load a pubspec with reserved transformer config", () {
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": [{"myapp/src/transformer": {'include': 'something'}}]
+      }),
+      d.dir("lib", [d.dir("src", [
+        d.file("transformer.dart", REWRITE_TRANSFORMER)
+      ])])
+    ]).create();
+
+    createLockFile('myapp', pkg: ['barback']);
+
+    var pub = startPub(args: ['serve', '--port=0']);
+    expect(pub.nextErrLine(), completion(startsWith('Could not parse ')));
+    expect(pub.nextErrLine(), completion(equals('Configuration for '
+        'transformer myapp/src/transformer may not include reserved key '
+        '"include".')));
+    pub.shouldExit(1);
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_a_syntax_error_test.dart b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_a_syntax_error_test.dart
index 38f96c1..b9b3073 100644
--- a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_a_syntax_error_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_a_syntax_error_test.dart
@@ -25,7 +25,7 @@
       ])])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     var pub = startPub(args: ['serve', '--port=0']);
     expect(pub.nextErrLine(), completion(startsWith('Error on line')));
diff --git a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_an_import_error_test.dart b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_an_import_error_test.dart
index f663af0..0251159 100644
--- a/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_an_import_error_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/fails_to_load_a_transform_with_an_import_error_test.dart
@@ -25,7 +25,7 @@
       ])])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     var pub = startPub(args: ['serve', '--port=0']);
     expect(pub.nextErrLine(), completion(matches(new RegExp(
diff --git a/sdk/lib/_internal/pub/test/serve/fails_to_load_an_unconfigurable_transformer_when_config_is_passed_test.dart b/sdk/lib/_internal/pub/test/serve/fails_to_load_an_unconfigurable_transformer_when_config_is_passed_test.dart
new file mode 100644
index 0000000..0403641
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/fails_to_load_an_unconfigurable_transformer_when_config_is_passed_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+
+  integration("fails to load an unconfigurable transformer when config is "
+      "passed", () {
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": [{"myapp/src/transformer": {'foo': 'bar'}}]
+      }),
+      d.dir("lib", [d.dir("src", [
+        d.file("transformer.dart", REWRITE_TRANSFORMER)
+      ])])
+    ]).create();
+
+    createLockFile('myapp', pkg: ['barback']);
+
+    var pub = startPub(args: ['serve', '--port=0']);
+    expect(pub.nextErrLine(), completion(startsWith('No transformers that '
+        'accept configuration were defined in ')));
+    pub.shouldExit(1);
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/loads_a_diamond_transformer_dependency_graph_test.dart b/sdk/lib/_internal/pub/test/serve/loads_a_diamond_transformer_dependency_graph_test.dart
new file mode 100644
index 0000000..1a7330c
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/loads_a_diamond_transformer_dependency_graph_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("loads a diamond transformer dependency graph", () {
+    d.dir("top", [
+      d.pubspec({
+        "name": "top",
+        "version": "1.0.0"
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('top')),
+      ])
+    ]).create();
+
+    d.dir("left", [
+      d.pubspec({
+        "name": "left",
+        "version": "1.0.0",
+        "transformers": ["top/transformer"],
+        "dependencies": {"top": {"path": "../top"}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('left')),
+      ])
+    ]).create();
+
+    d.dir("right", [
+      d.pubspec({
+        "name": "right",
+        "version": "1.0.0",
+        "transformers": ["top/transformer"],
+        "dependencies": {"top": {"path": "../top"}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('right')),
+      ])
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": [
+          "left/transformer",
+          "right/transformer",
+          "myapp/transformer"
+        ],
+        "dependencies": {
+          'left': {'path': '../left'},
+          'right': {'path': '../right'},
+        }
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('myapp'))
+      ]),
+      d.dir("web", [
+        d.file("main.dart", 'const TOKEN = "main.dart";')
+      ])
+    ]).create();
+
+    createLockFile('myapp',
+        sandbox: ['top', 'left', 'right'],
+        pkg: ['barback']);
+
+    startPubServe();
+    requestShouldSucceed("main.dart",
+        'const TOKEN = "(((main.dart, (left, top)), (right, top)), ((myapp, '
+        '(left, top)), (right, top)))";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/loads_ordering_dependencies_in_the_correct_order_test.dart b/sdk/lib/_internal/pub/test/serve/loads_ordering_dependencies_in_the_correct_order_test.dart
new file mode 100644
index 0000000..5695154
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/loads_ordering_dependencies_in_the_correct_order_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("loads ordering dependencies in the correct order", () {
+    d.dir("foo", [
+      d.libPubspec("foo", '1.0.0'),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('foo'))
+      ])
+    ]).create();
+
+    d.dir("bar", [
+      d.pubspec({
+        "name": "bar",
+        "version": "1.0.0",
+        "transformers": ["foo/transformer"],
+        "dependencies": {"foo": {"path": "../foo"}}
+      }),
+      d.dir("lib", [
+        d.file("bar.dart", 'const TOKEN = "bar";')
+      ])
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": ["myapp/transformer"],
+        "dependencies": {"bar": {"path": "../bar"}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('myapp', import: 'bar'))
+      ]),
+      d.dir("web", [
+        d.file("main.dart", 'const TOKEN = "main.dart";')
+      ])
+    ]).create();
+
+    createLockFile('myapp', sandbox: ['foo', 'bar'], pkg: ['barback']);
+
+    startPubServe();
+    requestShouldSucceed("main.dart",
+        'const TOKEN = "(main.dart, myapp imports (bar, foo))";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/passes_configuration_to_a_transformer_test.dart b/sdk/lib/_internal/pub/test/serve/passes_configuration_to_a_transformer_test.dart
new file mode 100644
index 0000000..e3f68e1
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/passes_configuration_to_a_transformer_test.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'dart:convert';
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+final transformer = """
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:barback/barback.dart';
+
+class ConfigTransformer extends Transformer {
+  final Map configuration;
+
+  ConfigTransformer.asPlugin(this.configuration);
+
+  String get allowedExtensions => '.txt';
+
+  Future apply(Transform transform) {
+    return transform.primaryInput.readAsString().then((contents) {
+      var id = transform.primaryInput.id.changeExtension(".json");
+      transform.addOutput(new Asset.fromString(id, JSON.encode(configuration)));
+    });
+  }
+}
+""";
+
+main() {
+  initConfig();
+  integration("passes configuration to a transformer", () {
+    var configuration = {"param": ["list", "of", "values"]};
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": [{"myapp/src/transformer": configuration}]
+      }),
+      d.dir("lib", [d.dir("src", [
+        d.file("transformer.dart", transformer)
+      ])]),
+      d.dir("web", [
+        d.file("foo.txt", "foo")
+      ])
+    ]).create();
+
+    createLockFile('myapp', pkg: ['barback']);
+
+    var server = startPubServe();
+    requestShouldSucceed("foo.json", JSON.encode(configuration));
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/prints_a_transform_error_in_apply_test.dart b/sdk/lib/_internal/pub/test/serve/prints_a_transform_error_in_apply_test.dart
index e0b361d..2d90ee8 100644
--- a/sdk/lib/_internal/pub/test/serve/prints_a_transform_error_in_apply_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/prints_a_transform_error_in_apply_test.dart
@@ -16,7 +16,7 @@
 import 'package:barback/barback.dart';
 
 class RewriteTransformer extends Transformer {
-  RewriteTransformer();
+  RewriteTransformer.asPlugin();
 
   String get allowedExtensions => '.txt';
 
@@ -40,7 +40,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     var server = startPubServe();
     expect(server.nextErrLine(),
diff --git a/sdk/lib/_internal/pub/test/serve/prints_a_transform_interface_error_test.dart b/sdk/lib/_internal/pub/test/serve/prints_a_transform_interface_error_test.dart
index 63aa5c1..9e35a46 100644
--- a/sdk/lib/_internal/pub/test/serve/prints_a_transform_interface_error_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/prints_a_transform_interface_error_test.dart
@@ -16,7 +16,7 @@
 import 'package:barback/barback.dart';
 
 class RewriteTransformer extends Transformer {
-  RewriteTransformer();
+  RewriteTransformer.asPlugin();
 
   String get allowedExtensions => '.txt';
 }
@@ -38,7 +38,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     var server = startPubServe();
     expect(server.nextErrLine(), completion(equals('Build error:')));
diff --git a/sdk/lib/_internal/pub/test/serve/runs_a_local_transform_on_the_application_package_test.dart b/sdk/lib/_internal/pub/test/serve/runs_a_local_transform_on_the_application_package_test.dart
index 0ae9397..e8fbd33 100644
--- a/sdk/lib/_internal/pub/test/serve/runs_a_local_transform_on_the_application_package_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/runs_a_local_transform_on_the_application_package_test.dart
@@ -24,7 +24,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {}, pkg: ['barback']);
+    createLockFile('myapp', pkg: ['barback']);
 
     startPubServe();
     requestShouldSucceed("foo.out", "foo.out");
diff --git a/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transform_on_the_application_package_test.dart b/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transform_on_the_application_package_test.dart
index 8185e56..ca88225 100644
--- a/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transform_on_the_application_package_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transform_on_the_application_package_test.dart
@@ -29,9 +29,7 @@
       ])
     ]).create();
 
-    createLockFile('myapp', {
-      'foo': '../foo'
-    }, pkg: ['barback']);
+    createLockFile('myapp', sandbox: ['foo'], pkg: ['barback']);
 
     startPubServe();
     requestShouldSucceed("foo.out", "foo.out");
diff --git a/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transformer_on_a_local_transformer_test.dart b/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transformer_on_a_local_transformer_test.dart
new file mode 100644
index 0000000..b3073a8
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/runs_a_third_party_transformer_on_a_local_transformer_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("runs a third-party transformer on a local transformer", () {
+    d.dir("foo", [
+      d.libPubspec("foo", '1.0.0'),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('foo'))
+      ])
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": ["foo/transformer", "myapp/transformer"],
+        "dependencies": {"foo": {"path": "../foo"}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('myapp'))
+      ]),
+      d.dir("web", [
+        d.file("main.dart", 'const TOKEN = "main.dart";')
+      ])
+    ]).create();
+
+    createLockFile('myapp', sandbox: ['foo'], pkg: ['barback']);
+
+    startPubServe();
+    requestShouldSucceed("main.dart",
+        'const TOKEN = "((main.dart, foo), (myapp, foo))";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/runs_a_transform_on_a_dependency_test.dart b/sdk/lib/_internal/pub/test/serve/runs_a_transform_on_a_dependency_test.dart
index 90f2990..80bff98 100644
--- a/sdk/lib/_internal/pub/test/serve/runs_a_transform_on_a_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/serve/runs_a_transform_on_a_dependency_test.dart
@@ -29,9 +29,7 @@
       d.appPubspec({"foo": {"path": "../foo"}}),
     ]).create();
 
-    createLockFile('myapp', {
-      'foo': '../foo'
-    }, pkg: ['barback']);
+    createLockFile('myapp', sandbox: ['foo'], pkg: ['barback']);
 
     startPubServe();
     requestShouldSucceed("assets/foo/foo.out", "foo.out");
diff --git a/sdk/lib/_internal/pub/test/serve/runs_one_third_party_transformer_on_another_test.dart b/sdk/lib/_internal/pub/test/serve/runs_one_third_party_transformer_on_another_test.dart
new file mode 100644
index 0000000..96732e9
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/runs_one_third_party_transformer_on_another_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("runs one third-party transformer on another", () {
+    d.dir("foo", [
+      d.pubspec({
+        "name": "foo",
+        "version": "1.0.0"
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('foo')),
+      ])
+    ]).create();
+
+    d.dir("bar", [
+      d.pubspec({
+        "name": "bar",
+        "version": "1.0.0",
+        "transformers": ["foo/transformer"],
+        "dependencies": {"foo": {"path": "../foo"}}
+      }),
+      d.dir("lib", [
+        d.file("transformer.dart", dartTransformer('bar')),
+      ])
+    ]).create();
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": ["bar/transformer"],
+        "dependencies": {'bar': {'path': '../bar'}}
+      }),
+      d.dir("web", [
+        d.file("main.dart", 'const TOKEN = "main.dart";')
+      ])
+    ]).create();
+
+    createLockFile('myapp', sandbox: ['foo', 'bar'], pkg: ['barback']);
+
+    startPubServe();
+    requestShouldSucceed("main.dart",
+        'const TOKEN = "(main.dart, (bar, foo))";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
index 5046638..46ace9d 100644
--- a/sdk/lib/_internal/pub/test/serve/utils.dart
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -26,7 +26,7 @@
 import 'package:barback/barback.dart';
 
 class RewriteTransformer extends Transformer {
-  RewriteTransformer();
+  RewriteTransformer.asPlugin();
 
   String get allowedExtensions => '.txt';
 
@@ -39,6 +39,52 @@
 }
 """;
 
+/// Returns the source code for a Dart library defining a Transformer that
+/// rewrites Dart files.
+///
+/// The transformer defines a constant named TOKEN whose value is [id]. When the
+/// transformer transforms another Dart file, it will look for a "TOKEN"
+/// constant definition there and modify it to include *this* transformer's
+/// TOKEN value as well.
+///
+/// If [import] is passed, it should be the name of a package that defines its
+/// own TOKEN constant. The primary library of that package will be imported
+/// here and its TOKEN value will be added to this library's.
+String dartTransformer(String id, {String import}) {
+  if (import != null) {
+    id = '$id imports \${$import.TOKEN}';
+    import = 'import "package:$import/$import.dart" as $import;';
+  } else {
+    import = '';
+  }
+
+  return """
+import 'dart:async';
+
+import 'package:barback/barback.dart';
+$import
+
+const TOKEN = "$id";
+
+final _tokenRegExp = new RegExp(r'^const TOKEN = "(.*?)";\$', multiLine: true);
+
+class DartTransformer extends Transformer {
+  DartTransformer.asPlugin();
+
+  String get allowedExtensions => '.dart';
+
+  Future apply(Transform transform) {
+    return transform.primaryInput.readAsString().then((contents) {
+      transform.addOutput(new Asset.fromString(transform.primaryInput.id,
+          contents.replaceAllMapped(_tokenRegExp, (match) {
+        return 'const TOKEN = "(\${match[1]}, \$TOKEN)";';
+      })));
+    });
+  }
+}
+""";
+}
+
 /// Schedules starting the "pub serve" process.
 ///
 /// If [shouldInstallFirst] is `true`, validates that pub install is run first.
diff --git a/sdk/lib/_internal/pub/test/serve/with_configuration_only_instantiates_configurable_transformers_test.dart b/sdk/lib/_internal/pub/test/serve/with_configuration_only_instantiates_configurable_transformers_test.dart
new file mode 100644
index 0000000..6c010bf
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/with_configuration_only_instantiates_configurable_transformers_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub_tests;
+
+import 'dart:convert';
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+final transformer = """
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:barback/barback.dart';
+
+class ConfigTransformer extends Transformer {
+  final Map configuration;
+
+  ConfigTransformer.asPlugin(this.configuration);
+
+  String get allowedExtensions => '.txt';
+
+  Future apply(Transform transform) {
+    return transform.primaryInput.readAsString().then((contents) {
+      var id = transform.primaryInput.id.changeExtension(".json");
+      transform.addOutput(new Asset.fromString(id, JSON.encode(configuration)));
+    });
+  }
+}
+
+class RewriteTransformer extends Transformer {
+  RewriteTransformer.asPlugin();
+
+  String get allowedExtensions => '.txt';
+
+  Future apply(Transform transform) {
+    return transform.primaryInput.readAsString().then((contents) {
+      var id = transform.primaryInput.id.changeExtension(".out");
+      transform.addOutput(new Asset.fromString(id, "\$contents.out"));
+    });
+  }
+}
+""";
+
+main() {
+  initConfig();
+  integration("with configuration, only instantiates configurable transformers",
+      () {
+    var configuration = {"param": ["list", "of", "values"]};
+
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "transformers": [{"myapp/src/transformer": configuration}]
+      }),
+      d.dir("lib", [d.dir("src", [
+        d.file("transformer.dart", transformer)
+      ])]),
+      d.dir("web", [
+        d.file("foo.txt", "foo")
+      ])
+    ]).create();
+
+    createLockFile('myapp', pkg: ['barback']);
+
+    var server = startPubServe();
+    requestShouldSucceed("foo.json", JSON.encode(configuration));
+    requestShould404("foo.out");
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 64c1682..897b69e 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -607,12 +607,20 @@
 
 /// Create a lock file for [package] without running `pub install`.
 ///
-/// This creates a lock file with only path dependencies. [dependencies] is a
-/// map of dependency names to paths. [pkg] is a list of packages in the Dart
-/// repo's "pkg" directory; each package listed here and all its dependencies
-/// will be linked to the version in the Dart repo.
-void createLockFile(String package, Map<String, String> dependencies,
-    {Iterable<String> pkg}) {
+/// This creates a lock file with only path dependencies. [sandbox] is a list of
+/// dependencies to be found in the sandbox directory. [pkg] is a list of
+/// packages in the Dart repo's "pkg" directory; each package listed here and
+/// all its dependencies will be linked to the version in the Dart repo.
+void createLockFile(String package, {Iterable<String> sandbox,
+    Iterable<String> pkg}) {
+  var dependencies = {};
+
+  if (sandbox != null) {
+    for (var package in sandbox) {
+      dependencies[package] = '../$package';
+    }
+  }
+
   if (pkg != null) {
     var pkgDir = path.absolute(path.join(
         path.dirname(Platform.executable),
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index fb72872..aa5b111 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -107,7 +107,7 @@
    * Any attempt to listen after calling [close] will throw, so there won't
    * be any further listeners.
    */
-  _FutureImpl _doneFuture;
+  _Future _doneFuture;
 
   _BroadcastStreamController(this._onListen, this._onCancel)
       : _state = _STATE_INITIAL {
@@ -140,9 +140,9 @@
 
   bool get _mayAddEvent => (_state < _STATE_CLOSED);
 
-  _FutureImpl _ensureDoneFuture() {
+  _Future _ensureDoneFuture() {
     if (_doneFuture != null) return _doneFuture;
-    return _doneFuture = new _FutureImpl();
+    return _doneFuture = new _Future();
   }
 
   // Linked list helpers
@@ -314,7 +314,7 @@
     assert(_isEmpty);
     if (isClosed && _doneFuture._mayComplete) {
       // When closed, _doneFuture is not null.
-      _doneFuture._asyncSetValue(null);
+      _doneFuture._asyncComplete(null);
     }
     _runGuarded(_onCancel);
   }
@@ -348,7 +348,7 @@
     } else {
       assert(_doneFuture != null);
       assert(_doneFuture._mayComplete);
-      _doneFuture._asyncSetValue(null);
+      _doneFuture._asyncComplete(null);
     }
   }
 }
@@ -388,7 +388,7 @@
     } else {
       assert(_doneFuture != null);
       assert(_doneFuture._mayComplete);
-      _doneFuture._asyncSetValue(null);
+      _doneFuture._asyncComplete(null);
     }
   }
 }
@@ -480,5 +480,5 @@
   }
   void cancel() {}
   bool get isPaused => _pauseCount > 0;
-  Future asFuture([Object value]) => new _FutureImpl();
+  Future asFuture([Object value]) => new _Future();
 }
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 4904415..ddeec59 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -100,18 +100,23 @@
    * If a value is returned, it becomes the result of the created future.
    */
   factory Future(computation()) {
-    _ThenFuture<dynamic, T> future =
-        new _ThenFuture<dynamic, T>((_) => computation());
-    Timer.run(() => future._sendValue(null));
-    return future;
+    _Future result = new _Future<T>();
+    Timer.run(() {
+      try {
+        result._complete(computation());
+      } catch (e, s) {
+        result._completeError(e, s);
+      }
+    });
+    return result;
   }
 
   /**
    * Creates a future containing the result of immediately calling
    * [computation].
    *
-   * if the result of executing [computation] throws, the returned future is
-   * completed with the error. If a thrown value is an [AsyncError], it is used
+   * If calling [computation] throws, the returned future is completed with the
+   * error. If a thrown value is an [AsyncError], it is used
    * directly, instead of wrapping this error again in another [AsyncError].
    *
    * If the returned value is itself a [Future], completion of
@@ -121,9 +126,9 @@
   factory Future.sync(computation()) {
     try {
       var result = computation();
-      return new _FutureImpl<T>().._setOrChainValue(result);
+      return new Future<T>.value(result);
     } catch (error, stackTrace) {
-      return new _FutureImpl<T>.immediateError(error, stackTrace);
+      return new Future<T>.error(error, stackTrace);
     }
   }
 
@@ -135,7 +140,9 @@
    *
    * See [Completer] to create a Future and complete it later.
    */
-  factory Future.value([T value]) => new _FutureImpl<T>.immediate(value);
+  factory Future.value([T value]) {
+    return new _Future<T>.immediate(value);
+  }
 
   /**
    * A future that completes with an error in the next event-loop iteration.
@@ -143,7 +150,7 @@
    * See [Completer] to create a Future and complete it later.
    */
   factory Future.error(var error, [Object stackTrace]) {
-    return new _FutureImpl<T>.immediateError(error, stackTrace);
+    return new _Future<T>.immediateError(error, stackTrace);
   }
 
   /**
@@ -163,13 +170,13 @@
    * See [Completer]s, for futures with values that are computed asynchronously.
    */
   factory Future.delayed(Duration duration, [T computation()]) {
-    // TODO(floitsch): no need to allocate a ThenFuture when the computation is
-    // null.
-    if (computation == null) computation = (() => null);
-    _ThenFuture<dynamic, T> future =
-        new _ThenFuture<dynamic, T>((_) => computation());
-    new Timer(duration, () => future._sendValue(null));
-    return future;
+    Completer completer = new Completer.sync();
+    Future result = completer.future;
+    if (computation != null) {
+      result = result.then((ignored) => computation());
+    }
+    new Timer(duration, () { completer.complete(null); });
+    return result;
   }
 
   /**
@@ -181,7 +188,36 @@
    * of the returned future will be a list of all the values that were produced.
    */
   static Future<List> wait(Iterable<Future> futures) {
-    return new _FutureImpl<List>.wait(futures);
+    Completer completer;
+    // List collecting values from the futures.
+    // Set to null if an error occurs.
+    List values;
+    void handleError(error) {
+      if (values != null) {
+        values = null;
+        completer.completeError(error);
+      }
+    }
+    // As each future completes, put its value into the corresponding
+    // position in the list of values.
+    int remaining = 0;
+    for (Future future in futures) {
+      int pos = remaining++;
+      future.catchError(handleError).then((Object value) {
+        if (values == null) return null;
+        values[pos] = value;
+        remaining--;
+        if (remaining == 0) {
+          completer.complete(values);
+        }
+      });
+    }
+    if (remaining == 0) {
+      return new Future.value(const []);
+    }
+    values = new List(remaining);
+    completer = new Completer<List>();
+    return completer.future;
   }
 
   /**
@@ -195,14 +231,14 @@
    * iteration to stop and will be piped through the returned [Future].
    */
   static Future forEach(Iterable input, Future f(element)) {
-    _FutureImpl doneSignal = new _FutureImpl();
+    _Future doneSignal = new _Future();
     Iterator iterator = input.iterator;
     void nextElement(_) {
       if (iterator.moveNext()) {
         new Future.sync(() => f(iterator.current))
-            .then(nextElement, onError: doneSignal._setError);
+            .then(nextElement, onError: doneSignal._completeError);
       } else {
-        doneSignal._setValue(null);
+        doneSignal._complete(null);
       }
     }
     nextElement(null);
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 4c846c6..ea8f902 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -4,155 +4,53 @@
 
 part of dart.async;
 
+/** The onValue and onError handlers return either a value or a future */
+typedef dynamic _FutureOnValue<T>(T value);
+typedef dynamic _FutureOnError(error);
+/** Test used by [Future.catchError] to handle skip some errors. */
+typedef bool _FutureErrorTest(var error);
+/** Used by [WhenFuture]. */
+typedef _FutureAction();
+
 abstract class _Completer<T> implements Completer<T> {
-  final Future<T> future;
-  bool _isComplete = false;
+  final _Future<T> future = new _Future<T>();
 
-  _Completer() : future = new _FutureImpl<T>() {
-    _FutureImpl futureImpl = future;
-    futureImpl._zone.expectCallback();
-  }
+  void complete([T value]);
 
-  void _setFutureValue(T value);
-  void _setFutureError(error);
+  void completeError(Object error, [Object stackTrace = null]);
 
-  void complete([T value]) {
-    if (_isComplete) throw new StateError("Future already completed");
-    _isComplete = true;
-    _FutureImpl futureImpl = future;
-    _setFutureValue(value);
-  }
-
-  void completeError(Object error, [Object stackTrace = null]) {
-    if (_isComplete) throw new StateError("Future already completed");
-    _isComplete = true;
-    if (stackTrace != null) {
-      // Force the stack trace onto the error, even if it already had one.
-      _attachStackTrace(error, stackTrace);
-    }
-    _FutureImpl futureImpl = future;
-    _setFutureError(error);
-  }
-
-  bool get isCompleted => _isComplete;
+  // The future's _isComplete doesn't take into account pending completions.
+  // We therefore use _mayComplete.
+  bool get isCompleted => !future._mayComplete;
 }
 
 class _AsyncCompleter<T> extends _Completer<T> {
-  void _setFutureValue(T value) {
-    _FutureImpl future = this.future;
-    future._asyncSetValue(value);
-    // The async-error will schedule another callback, so we can cancel
-    // the expectation without shutting down the zone.
-    future._zone.cancelCallbackExpectation();
+
+  void complete([T value]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._asyncComplete(value);
   }
 
-  void _setFutureError(error) {
-    _FutureImpl future = this.future;
-    future._asyncSetError(error);
-    // The async-error will schedule another callback, so we can cancel
-    // the expectation without shutting down the zone.
-    future._zone.cancelCallbackExpectation();
+  void completeError(Object error, [Object stackTrace = null]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._asyncCompleteError(error, stackTrace);
   }
 }
 
 class _SyncCompleter<T> extends _Completer<T> {
-  void _setFutureValue(T value) {
-    _FutureImpl future = this.future;
-    future._setValue(value);
-    future._zone.cancelCallbackExpectation();
+
+  void complete([T value]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._complete(value);
   }
 
-  void _setFutureError(error) {
-    _FutureImpl future = this.future;
-    future._setError(error);
-    future._zone.cancelCallbackExpectation();
+  void completeError(Object error, [Object stackTrace = null]) {
+    if (!future._mayComplete) throw new StateError("Future already completed");
+    future._completeError(error, stackTrace);
   }
 }
 
-/**
- * A listener on a future.
- *
- * When the future completes, the [_sendValue] or [_sendError] method
- * is invoked with the result.
- *
- * Listeners are kept in a linked list.
- */
-abstract class _FutureListener<T> {
-  _FutureListener _nextListener;
-  factory _FutureListener.wrap(_FutureImpl future) {
-    return new _FutureListenerWrapper(future);
-  }
-  void _sendValue(T value);
-  void _sendError(error);
-
-  bool _inSameErrorZone(_Zone otherZone);
-}
-
-/** Adapter for a [_FutureImpl] to be a future result listener. */
-class _FutureListenerWrapper<T> implements _FutureListener<T> {
-  _FutureImpl future;
-  _FutureListener _nextListener;
-  _FutureListenerWrapper(this.future);
-  _sendValue(T value) { future._setValueUnchecked(value); }
-  _sendError(error) { future._setErrorUnchecked(error); }
-  bool _inSameErrorZone(_Zone otherZone) => future._inSameErrorZone(otherZone);
-}
-
-/**
- * This listener is installed at error-zone boundaries. It signals an
- * uncaught error in the zone of origin when an error is sent from one error
- * zone to another.
- *
- * When a Future is listening to another Future and they have not been
- * instantiated in the same error-zone then Futures put an instance of this
- * class between them (see [_FutureImpl._addListener]).
- *
- * For example:
- *
- *     var completer = new Completer();
- *     var future = completer.future.then((x) => x);
- *     catchErrors(() {
- *       var future2 = future.catchError(print);
- *     });
- *     completer.completeError(499);
- *
- * In this example `future` and `future2` are in different error-zones. The
- * error (499) that originates outside `catchErrors` must not reach the
- * `catchError` future (`future2`) inside `catchErrors`.
- *
- * When invoking `catchError` on `future` the Future installs an
- * [_ErrorZoneBoundaryListener] between itself and the result, `future2`.
- *
- * Conceptually _ErrorZoneBoundaryListeners could be implemented as
- * `catchError`s on the origin future as well.
- */
-class _ErrorZoneBoundaryListener implements _FutureListener {
-  _FutureListener _nextListener;
-  final _FutureListener _listener;
-
-  _ErrorZoneBoundaryListener(this._listener);
-
-  bool _inSameErrorZone(_Zone otherZone) {
-    // Should never be called. We use [_inSameErrorZone] to know if we have
-    // to insert an instance of [_ErrorZoneBoundaryListener] (and in the
-    // controller). Once we have inserted one we should never need to use it
-    // anymore.
-    throw new UnsupportedError(
-        "A Zone boundary doesn't support the inSameErrorZone test.");
-  }
-
-  void _sendValue(value) {
-    _listener._sendValue(value);
-  }
-
-  void _sendError(error) {
-    // We are not allowed to send an error from one error-zone to another.
-    // This is the whole purpose of this class.
-    _Zone.current.handleUncaughtError(error);
-  }
-}
-
-class _FutureImpl<T> implements Future<T> {
+class _Future<T> implements Future<T> {
   // State of the future. The state determines the interpretation of the
   // [resultOrListeners] field.
   // TODO(lrn): rename field since it can also contain a chained future.
@@ -161,35 +59,40 @@
   /// [resultOrListeners] field holds a single-linked list of
   /// [FutureListener] listeners.
   static const int _INCOMPLETE = 0;
-  /// Pending completion. Set when completed using [_asyncSetValue] or
-  /// [_asyncSetError]. It is an error to try to complete it again.
+  /// Pending completion. Set when completed using [_asyncComplete] or
+  /// [_asyncCompleteError]. It is an error to try to complete it again.
   static const int _PENDING_COMPLETE = 1;
   /// The future has been chained to another future. The result of that
   /// other future becomes the result of this future as well.
-  /// In this state, the [resultOrListeners] field holds the future that
-  /// will give the result to this future. Both existing and new listeners are
-  /// forwarded directly to the other future.
+  /// In this state, no callback should be executed anymore.
+  // TODO(floitsch): we don't really need a special "_CHAINED" state. We could
+  // just use the PENDING_COMPLETE state instead.
   static const int _CHAINED = 2;
-  /// The future has been chained to another future, but there hasn't been
-  /// any listeners added to this future yet. If it is completed with an
-  /// error, the error will be considered unhandled.
-  static const int _CHAINED_UNLISTENED = 6;
   /// The future has been completed with a value result.
-  static const int _VALUE = 8;
+  static const int _VALUE = 4;
   /// The future has been completed with an error result.
-  static const int _ERROR = 12;
+  static const int _ERROR = 8;
 
   /** Whether the future is complete, and as what. */
   int _state = _INCOMPLETE;
 
   final _Zone _zone = _Zone.current.fork();
 
-  bool get _isChained => (_state & _CHAINED) != 0;
-  bool get _hasChainedListener => _state == _CHAINED;
-  bool get _isComplete => _state >= _VALUE;
   bool get _mayComplete => _state == _INCOMPLETE;
+  bool get _isChained => _state == _CHAINED;
+  bool get _isComplete => _state >= _VALUE;
   bool get _hasValue => _state == _VALUE;
-  bool get _hasError => _state >= _ERROR;
+  bool get _hasError => _state == _ERROR;
+
+  set _isChained(bool value) {
+    if (value) {
+      assert(!_isComplete);
+      _state = _CHAINED;
+    } else {
+      assert(_isChained);
+      _state = _INCOMPLETE;
+    }
+  }
 
   /**
    * Either the result, a list of listeners or another future.
@@ -212,175 +115,132 @@
    */
   var _resultOrListeners;
 
-  _FutureImpl();
+  /**
+   * A [_Future] implements a linked list. If a future has more than one
+   * listener the [_nextListener] field of the first listener points to the
+   * remaining listeners.
+   */
+  // TODO(floitsch): since single listeners are the common case we should
+  // use a bit to indicate that the _resultOrListeners contains a container.
+  _Future _nextListener;
 
-  _FutureImpl.immediate(T value) {
-    _state = _VALUE;
-    _resultOrListeners = value;
+  // TODO(floitsch): we only need two closure fields to store the callbacks.
+  // If we store the type of a closure in the state field (where there are
+  // still bits left), we can just store two closures instead of using 4
+  // fields of which 2 are always null.
+  final _FutureOnValue _onValueCallback;
+  final _FutureErrorTest _errorTestCallback;
+  final _FutureOnError _onErrorCallback;
+  final _FutureAction _whenCompleteActionCallback;
+
+  _FutureOnValue get _onValue => _isChained ? null : _onValueCallback;
+  _FutureErrorTest get _errorTest => _isChained ? null : _errorTestCallback;
+  _FutureOnError get _onError => _isChained ? null : _onErrorCallback;
+  _FutureAction get _whenCompleteAction
+      => _isChained ? null : _whenCompleteActionCallback;
+
+  _Future()
+      : _onValueCallback = null, _errorTestCallback = null,
+        _onErrorCallback = null, _whenCompleteActionCallback = null;
+
+  _Future.immediate(T value)
+        : _onValueCallback = null, _errorTestCallback = null,
+          _onErrorCallback = null, _whenCompleteActionCallback = null {
+    _asyncComplete(value);
   }
 
-  _FutureImpl.immediateError(var error, [Object stackTrace]) {
-    if (stackTrace != null) {
-      // Force stack trace onto error, even if it had already one.
-      _attachStackTrace(error, stackTrace);
-    }
-    _asyncSetError(error);
+  _Future.immediateError(var error, [Object stackTrace])
+      : _onValueCallback = null, _errorTestCallback = null,
+        _onErrorCallback = null, _whenCompleteActionCallback = null {
+    _asyncCompleteError(error, stackTrace);
   }
 
-  factory _FutureImpl.wait(Iterable<Future> futures) {
-    Completer completer;
-    // List collecting values from the futures.
-    // Set to null if an error occurs.
-    List values;
-    void handleError(error) {
-      if (values != null) {
-        values = null;
-        completer.completeError(error);
-      }
-    }
-    // As each future completes, put its value into the corresponding
-    // position in the list of values.
-    int remaining = 0;
-    for (Future future in futures) {
-      int pos = remaining++;
-      future.catchError(handleError).then((Object value) {
-        if (values == null) return null;
-        values[pos] = value;
-        remaining--;
-        if (remaining == 0) {
-          completer.complete(values);
-        }
-      });
-    }
-    if (remaining == 0) {
-      return new Future.value(const []);
-    }
-    values = new List(remaining);
-    completer = new Completer<List>();
-    return completer.future;
+  _Future._then(this._onValueCallback, this._onErrorCallback)
+      : _errorTestCallback = null, _whenCompleteActionCallback = null {
+    _zone.expectCallback();
+  }
+
+  _Future._catchError(this._onErrorCallback, this._errorTestCallback)
+    : _onValueCallback = null, _whenCompleteActionCallback = null {
+    _zone.expectCallback();
+  }
+
+  _Future._whenComplete(this._whenCompleteActionCallback)
+      : _onValueCallback = null, _errorTestCallback = null,
+        _onErrorCallback = null {
+    _zone.expectCallback();
   }
 
   Future then(f(T value), { onError(error) }) {
-    if (onError == null) {
-      return new _ThenFuture(f).._subscribeTo(this);
-    }
-    return new _SubscribeFuture(f, onError).._subscribeTo(this);
+    _Future result;
+    result = new _Future._then(f, onError);
+    _addListener(result);
+    return result;
   }
 
   Future catchError(f(error), { bool test(error) }) {
-    return new _CatchErrorFuture(f, test).._subscribeTo(this);
+    _Future result = new _Future._catchError(f, test);
+    _addListener(result);
+    return result;
   }
 
   Future<T> whenComplete(action()) {
-    return new _WhenFuture<T>(action).._subscribeTo(this);
+    _Future result = new _Future<T>._whenComplete(action);
+    _addListener(result);
+    return result;
   }
 
   Stream<T> asStream() => new Stream.fromFuture(this);
 
-  bool _inSameErrorZone(_Zone otherZone) {
-    return _zone.inSameErrorZone(otherZone);
+  void _markPendingCompletion() {
+    if (!_mayComplete) throw new StateError("Future already completed");
+    _state = _PENDING_COMPLETE;
+  }
+
+  T get _value {
+    assert(_isComplete && _hasValue);
+    return _resultOrListeners;
+  }
+
+  Object get _error {
+    assert(_isComplete && _hasError);
+    return _resultOrListeners;
   }
 
   void _setValue(T value) {
-    if (!_mayComplete) throw new StateError("Future already completed");
-    _setValueUnchecked(value);
-  }
-
-  void _setValueUnchecked(T value) {
-    _FutureListener listeners = _isChained ? null : _removeListeners();
+    assert(!_isComplete);  // But may have a completion pending.
     _state = _VALUE;
     _resultOrListeners = value;
-    while (listeners != null) {
-      _FutureListener listener = listeners;
-      listeners = listener._nextListener;
-      listener._nextListener = null;
-      listener._sendValue(value);
-    }
   }
 
   void _setError(Object error) {
-    if (!_mayComplete) throw new StateError("Future already completed");
-    _setErrorUnchecked(error);
-  }
-
-  void _setErrorUnchecked(Object error) {
-    _FutureListener listeners;
-    bool hasListeners;
-    if (_isChained) {
-      listeners = null;
-      hasListeners = (_state == _CHAINED);  // and not _CHAINED_UNLISTENED.
-    } else {
-      listeners = _removeListeners();
-      hasListeners = (listeners != null);
-    }
-
+    assert(!_isComplete);  // But may have a completion pending.
     _state = _ERROR;
     _resultOrListeners = error;
-
-    if (!hasListeners) {
-      // TODO(floitsch): Hook this into unhandled error handling.
-      var error = _resultOrListeners;
-      _zone.handleUncaughtError(error);
-      return;
-    }
-    while (listeners != null) {
-      _FutureListener listener = listeners;
-      listeners = listener._nextListener;
-      listener._nextListener = null;
-      listener._sendError(error);
-    }
   }
 
-  void _asyncSetValue(T value) {
-    if (!_mayComplete) throw new StateError("Future already completed");
-    _state = _PENDING_COMPLETE;
-    runAsync(() { _setValueUnchecked(value); });
-  }
-
-  void _asyncSetError(Object error) {
-    if (!_mayComplete) throw new StateError("Future already completed");
-    _state = _PENDING_COMPLETE;
-    runAsync(() { _setErrorUnchecked(error); });
-  }
-
-  void _addListener(_FutureListener listener) {
+  void _addListener(_Future listener) {
     assert(listener._nextListener == null);
-    if (!listener._inSameErrorZone(_zone)) {
-      listener = new _ErrorZoneBoundaryListener(listener);
-    }
-    if (_isChained) {
-      _state = _CHAINED;  // In case it was _CHAINED_UNLISTENED.
-      _FutureImpl resultSource = _chainSource;
-      resultSource._addListener(listener);
-      return;
-    }
     if (_isComplete) {
       // Handle late listeners asynchronously.
       runAsync(() {
-        if (_hasValue) {
-          T value = _resultOrListeners;
-          listener._sendValue(value);
-        } else {
-          assert(_hasError);
-          listener._sendError(_resultOrListeners);
-        }
+        _propagateToListeners(this, listener);
       });
     } else {
-      assert(!_isComplete);
       listener._nextListener = _resultOrListeners;
       _resultOrListeners = listener;
     }
   }
 
-  _FutureListener _removeListeners() {
+  _Future _removeListeners() {
     // Reverse listeners before returning them, so the resulting list is in
     // subscription order.
     assert(!_isComplete);
-    _FutureListener current = _resultOrListeners;
+    _Future current = _resultOrListeners;
     _resultOrListeners = null;
-    _FutureListener prev = null;
+    _Future prev = null;
     while (current != null) {
-      _FutureListener next = current._nextListener;
+      _Future next = current._nextListener;
       current._nextListener = prev;
       prev = current;
       current = next;
@@ -388,270 +248,268 @@
     return prev;
   }
 
-  /**
-   * Make another [_FutureImpl] receive the result of this one.
-   *
-   * If this future is already complete, the [future] is notified
-   * immediately. This function is only called during event resolution
-   * where it's acceptable to send an event.
-   */
-  void _chain(_FutureImpl future) {
-    if (!_isComplete) {
-      future._chainFromFuture(this);
-    } else if (_hasValue) {
-      future._setValue(_resultOrListeners);
-    } else {
-      assert(_hasError);
-      future._setError(_resultOrListeners);
-    }
-  }
+  static void _chainFutures(Future source, _Future target) {
+    assert(!target._isComplete);
 
-  /**
-   * Returns the future that this future is chained to.
-   *
-   * If that future is itself chained to something else,
-   * get the [_chainSource] of that future instead, and make this
-   * future chain directly to the earliest source.
-   */
-  _FutureImpl get _chainSource {
-    assert(_isChained);
-    _FutureImpl future = _resultOrListeners;
-    if (future._isChained) {
-      future = _resultOrListeners = future._chainSource;
-    }
-    return future;
-  }
-
-  /**
-   * Make this incomplete future end up with the same result as [resultSource].
-   *
-   * This is done by moving all listeners to [resultSource] and forwarding all
-   * future [_addListener] calls to [resultSource] directly.
-   */
-  void _chainFromFuture(_FutureImpl resultSource) {
-    assert(!_isComplete);
-    assert(!_isChained);
-    if (resultSource._isChained) {
-      resultSource = resultSource._chainSource;
-    }
-    assert(!resultSource._isChained);
-    if (identical(this, resultSource)) {
-      // The only unchained future in a future dependency tree (as defined
-      // by the chain-relations) is the "root" that every other future depends
-      // on. The future we are adding is unchained, so if it is already in the
-      // tree, it must be the root, so that's the only one we need to check
-      // against to detect a cycle.
-      _setError(new StateError("Cyclic future dependency."));
-      return;
-    }
-    _FutureListener cursor = _removeListeners();
-    bool hadListeners = cursor != null;
-    while (cursor != null) {
-      _FutureListener listener = cursor;
-      cursor = cursor._nextListener;
-      listener._nextListener = null;
-      resultSource._addListener(listener);
-    }
-    // Listen with this future as well, so that when the other future completes,
-    // this future will be completed as well.
-    resultSource._addListener(this._asListener());
-    _resultOrListeners = resultSource;
-    _state = hadListeners ? _CHAINED : _CHAINED_UNLISTENED;
-  }
-
-  /**
-   * Helper function to handle the result of transforming an incoming event.
-   *
-   * If the result is itself a [Future], this future is linked to that
-   * future's output. If not, this future is completed with the result.
-   */
-  void _setOrChainValue(var result) {
-    assert(!_isChained);
-    assert(!_isComplete);
-    if (result is Future) {
-      // Result should be a Future<T>.
-      if (result is _FutureImpl) {
-        _FutureImpl chainFuture = result;
-        chainFuture._chain(this);
-        return;
+    // Mark the target as chained (and as such half-completed).
+    target._isChained = true;
+    if (source is _Future) {
+      _Future internalFuture = source;
+      if (internalFuture._isComplete) {
+        _propagateToListeners(internalFuture, target);
       } else {
-        Future future = result;
-        future.then(_setValue,
-                    onError: _setError);
-        return;
+        internalFuture._addListener(target);
       }
     } else {
-      // Result must be of type T.
-      _setValue(result);
+      source.then((value) {
+          assert(target._isChained);
+          target._complete(value);
+        },
+        onError: (error) {
+          assert(target._isChained);
+          target._completeError(error);
+        });
     }
   }
 
-  _FutureListener _asListener() => new _FutureListener.wrap(this);
-}
+  void _complete(value) {
+    assert(!_isComplete);
+    assert(_onValue == null);
+    assert(_onError == null);
+    assert(_whenCompleteAction == null);
+    assert(_errorTest == null);
 
-/**
- * Transforming future base class.
- *
- * A transforming future is itself a future and a future listener.
- * Subclasses override [_sendValue]/[_sendError] to intercept
- * the results of a previous future.
- */
-abstract class _TransformFuture<S, T> extends _FutureImpl<T>
-                                      implements _FutureListener<S> {
-  // _FutureListener implementation.
-  _FutureListener _nextListener;
-
-  _TransformFuture() {
-    _zone.expectCallback();
-  }
-
-  void _sendValue(S value) {
-    _zone.executeCallback(() => _zonedSendValue(value));
-  }
-
-  void _sendError(error) {
-    _zone.executeCallback(() => _zonedSendError(error));
-  }
-
-  void _subscribeTo(_FutureImpl future) {
-    future._addListener(this);
-  }
-
-  void _zonedSendValue(S value);
-  void _zonedSendError(error);
-}
-
-/** The onValue and onError handlers return either a value or a future */
-typedef dynamic _FutureOnValue<T>(T value);
-typedef dynamic _FutureOnError(error);
-/** Test used by [Future.catchError] to handle skip some errors. */
-typedef bool _FutureErrorTest(var error);
-/** Used by [WhenFuture]. */
-typedef _FutureAction();
-
-/** Future returned by [Future.then] with no [:onError:] parameter. */
-class _ThenFuture<S, T> extends _TransformFuture<S, T> {
-  // TODO(ahe): Restore type when feature is implemented in dart2js
-  // checked mode.
-  final /* _FutureOnValue<S> */ _onValue;
-
-  _ThenFuture(this._onValue);
-
-  _zonedSendValue(S value) {
-    assert(_onValue != null);
-    var result;
-    try {
-      result = _onValue(value);
-    } catch (e, s) {
-      _setError(_asyncError(e, s));
+    if (value is Future) {
+      _chainFutures(value, this);
       return;
     }
-    _setOrChainValue(result);
-  }
-
-  void _zonedSendError(error) {
-    _setError(error);
-  }
-}
-
-/** Future returned by [Future.catchError]. */
-class _CatchErrorFuture<T> extends _TransformFuture<T,T> {
-  final _FutureErrorTest _test;
-  final _FutureOnError _onError;
-
-  _CatchErrorFuture(this._onError, this._test);
-
-  _zonedSendValue(T value) {
+    _Future listeners = _removeListeners();
     _setValue(value);
+    _propagateToListeners(this, listeners);
   }
 
-  _zonedSendError(error) {
-    assert(_onError != null);
-    // if _test is supplied, check if it returns true, otherwise just
-    // forward the error unmodified.
-    if (_test != null) {
-      bool matchesTest;
-      try {
-        matchesTest = _test(error);
-      } catch (e, s) {
-        _setError(_asyncError(e, s));
-        return;
-      }
-      if (!matchesTest) {
-        _setError(error);
-        return;
-      }
+  void _completeError(error, [StackTrace stackTrace]) {
+    assert(!_isComplete);
+    assert(_onValue == null);
+    assert(_onError == null);
+    assert(_whenCompleteAction == null);
+    assert(_errorTest == null);
+
+    if (stackTrace != null) {
+      // Force the stack trace onto the error, even if it already had one.
+      _attachStackTrace(error, stackTrace);
     }
-    // Act on the error, and use the result as this future's result.
-    var result;
-    try {
-      result = _onError(error);
-    } catch (e, s) {
-      _setError(_asyncError(e, s));
-      return;
-    }
-    _setOrChainValue(result);
-  }
-}
 
-/** Future returned by [Future.then] with an [:onError:] parameter. */
-class _SubscribeFuture<S, T> extends _ThenFuture<S, T> {
-  final _FutureOnError _onError;
-
-  _SubscribeFuture(onValue(S value), this._onError) : super(onValue);
-
-  // The _sendValue method is inherited from ThenFuture.
-
-  void _zonedSendError(error) {
-    assert(_onError != null);
-    var result;
-    try {
-      result = _onError(error);
-    } catch (e, s) {
-      _setError(_asyncError(e, s));
-      return;
-    }
-    _setOrChainValue(result);
-  }
-}
-
-/** Future returned by [Future.whenComplete]. */
-class _WhenFuture<T> extends _TransformFuture<T, T> {
-  final _FutureAction _action;
-
-  _WhenFuture(this._action);
-
-  void _zonedSendValue(T value) {
-    try {
-      var result = _action();
-      if (result is Future) {
-        Future resultFuture = result;
-        resultFuture.then((_) {
-          _setValue(value);
-        }, onError: _setError);
-        return;
-      }
-    } catch (e, s) {
-      _setError(_asyncError(e, s));
-      return;
-    }
-    _setValue(value);
-  }
-
-  void _zonedSendError(error) {
-    try {
-      var result = _action();
-      if (result is Future) {
-        Future resultFuture = result;
-        // TODO(lrn): Find a way to combine [error] into [e].
-        resultFuture.then((_) {
-          _setError(error);
-        }, onError: _setError);
-        return;
-      }
-    } catch (e, s) {
-      error = _asyncError(e, s);
-    }
+    _Future listeners = _isChained ? null : _removeListeners();
     _setError(error);
+    _propagateToListeners(this, listeners);
+  }
+
+  void _asyncComplete(value) {
+    assert(!_isComplete);
+    assert(_onValue == null);
+    assert(_onError == null);
+    assert(_whenCompleteAction == null);
+    assert(_errorTest == null);
+    // Two corner cases if the value is a future:
+    //   1. the future is already completed and an error.
+    //   2. the future is not yet completed but might become an error.
+    // The first case means that we must not immediately complete the Future,
+    // as our code would immediately start propagating the error without
+    // giving the time to install error-handlers.
+    // However the second case requires us to deal with the value immediately.
+    // Otherwise the value could complete with an error and report an
+    // unhandled error, even though we know we are already going to listen to
+    // it.
+    if (value is Future &&
+        (value is! _Future || !(value as _Future)._isComplete)) {
+      // Case 2 from above. We need to register.
+      // Note that we are still completing asynchronously: either we register
+      // through .then (in which case the completing is asynchronous), or we
+      // have a _Future which isn't complete yet.
+      _complete(value);
+      return;
+    }
+
+    _markPendingCompletion();
+    runAsync(() {
+      _complete(value);
+    });
+  }
+
+  void _asyncCompleteError(error, [StackTrace stackTrace]) {
+    assert(!_isComplete);
+    assert(_onValue == null);
+    assert(_onError == null);
+    assert(_whenCompleteAction == null);
+    assert(_errorTest == null);
+
+    _markPendingCompletion();
+    runAsync(() {
+      _completeError(error, stackTrace);
+    });
+  }
+
+  /**
+   * Propagates the value/error of [source] to its [listeners].
+   *
+   * Unlinks all listeners and propagates the source to each listener
+   * separately.
+   */
+  static void _propagateMultipleListeners(_Future source, _Future listeners) {
+    assert(listeners != null);
+    assert(listeners._nextListener != null);
+    do {
+      _Future listener = listeners;
+      listeners = listener._nextListener;
+      listener._nextListener = null;
+      _propagateToListeners(source, listener);
+    } while (listeners != null);
+  }
+
+  /**
+   * Propagates the value/error of [source] to its [listeners], executing the
+   * listeners' callbacks.
+   *
+   * If [runCallback] is true (which should be the default) it executes
+   * the registered action of listeners. If it is `false` then the callback is
+   * skipped. This is used to complete futures with chained futures.
+   */
+  static void _propagateToListeners(_Future source, _Future listeners) {
+    while (true) {
+      if (!source._isComplete) return;  // Chained future.
+      bool hasError = source._hasError;
+      if (hasError && listeners == null) {
+        source._zone.handleUncaughtError(source._error);
+        return;
+      }
+      if (listeners == null) return;
+      _Future listener = listeners;
+      if (listener._nextListener != null) {
+        // Usually futures only have one listener. If they have several, we
+        // handle them specially.
+        _propagateMultipleListeners(source, listeners);
+        return;
+      }
+      if (hasError && !source._zone.inSameErrorZone(listener._zone)) {
+        // Don't cross zone boundaries with errors.
+        source._zone.handleUncaughtError(source._error);
+        return;
+      }
+      if (!identical(_Zone.current, listener._zone)) {
+        // Run the propagation in the listener's zone to avoid
+        // zone transitions. The idea is that many chained futures will
+        // be in the same zone.
+        listener._zone.executePeriodicCallback(() {
+          _propagateToListeners(source, listener);
+        });
+        return;
+      }
+
+      // Do the actual propagation.
+      // TODO(floitsch): Do we need to go through the zone even if we
+      // don't have a callback to execute?
+      bool listenerHasValue;
+      var listenerValueOrError;
+      // Set to true if a whenComplete needs to wait for a future.
+      // The whenComplete action will resume the propagation by itself.
+      bool isPropagationAborted = false;
+      // Even though we are already in the right zone (due to the optimization
+      // above), we still need to go through the zone. The overhead of
+      // executeCallback is however smaller when it is already in the correct
+      // zone.
+      // TODO(floitsch): only run callbacks in the zone, not the whole
+      // handling code.
+      listener._zone.executeCallback(() {
+        // TODO(floitsch): mark the listener as pending completion. Currently
+        // we can't do this, since the markPendingCompletion verifies that
+        // the future is not already marked (or chained).
+        try {
+          if (!hasError) {
+            var value = source._value;
+            if (listener._onValue != null) {
+              listenerValueOrError = listener._onValue(value);
+              listenerHasValue = true;
+            } else {
+              // Copy over the value from the source.
+              listenerValueOrError = value;
+              listenerHasValue = true;
+            }
+          } else {
+            Object error = source._error;
+            _FutureErrorTest test = listener._errorTest;
+            bool matchesTest = true;
+            if (test != null) {
+              matchesTest = test(error);
+            }
+            if (matchesTest && listener._onError != null) {
+              listenerValueOrError = listener._onError(error);
+              listenerHasValue = true;
+            } else {
+              // Copy over the error from the source.
+              listenerValueOrError = error;
+              listenerHasValue = false;
+            }
+          }
+
+          if (listener._whenCompleteAction != null) {
+            var completeResult = listener._whenCompleteAction();
+            if (completeResult is Future) {
+              listener._isChained = true;
+              completeResult.then((ignored) {
+                // Try again, but this time don't run the whenComplete callback.
+                _propagateToListeners(source, listener);
+              }, onError: (error) {
+                // When there is an error, we have to make the error the new
+                // result of the current listener.
+                if (completeResult is! _Future) {
+                  // This should be a rare case.
+                  completeResult = new _Future();
+                  completeResult._setError(error);
+                }
+                _propagateToListeners(completeResult, listener);
+              });
+              isPropagationAborted = true;
+              // We will reenter the listener's zone.
+              listener._zone.expectCallback();
+            }
+          }
+        } catch (e, s) {
+          // Set the exception as error.
+          listenerValueOrError = _asyncError(e, s);
+          listenerHasValue = false;
+        }
+        if (listenerHasValue && listenerValueOrError is Future) {
+          // We are going to reenter the zone to finish what we started.
+          listener._zone.expectCallback();
+        }
+      });
+      if (isPropagationAborted) return;
+      // If the listener's value is a future we need to chain it.
+      if (listenerHasValue && listenerValueOrError is Future) {
+        Future chainSource = listenerValueOrError;
+        // Shortcut if the chain-source is already completed. Just continue the
+        // loop.
+        if (chainSource is _Future && (chainSource as _Future)._isComplete) {
+          // propagate the value (simulating a tail call).
+          listener._isChained = true;
+          source = chainSource;
+          listeners = listener;
+          continue;
+        }
+        _chainFutures(chainSource, listener);
+        return;
+      }
+
+      if (listenerHasValue) {
+        listeners = listener._removeListeners();
+        listener._setValue(listenerValueOrError);
+      } else {
+        listeners = listener._removeListeners();
+        listener._setError(listenerValueOrError);
+      }
+      // Prepare for next round.
+      source = listener;
+    }
   }
 }
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 4242e4f..495d047 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -272,7 +272,7 @@
    * Reduces a sequence of values by repeatedly applying [combine].
    */
   Future<T> reduce(T combine(T previous, T element)) {
-    _FutureImpl<T> result = new _FutureImpl<T>();
+    _Future<T> result = new _Future<T>();
     bool seenFirst = false;
     T value;
     StreamSubscription subscription;
@@ -287,12 +287,12 @@
           seenFirst = true;
         }
       },
-      onError: result._setError,
+      onError: result._completeError,
       onDone: () {
         if (!seenFirst) {
-          result._setError(new StateError("No elements"));
+          result._completeError(new StateError("No elements"));
         } else {
-          result._setValue(value);
+          result._complete(value);
         }
       },
       cancelOnError: true
@@ -302,7 +302,7 @@
 
   /** Reduces a sequence of values by repeatedly applying [combine]. */
   Future fold(var initialValue, combine(var previous, T element)) {
-    _FutureImpl result = new _FutureImpl();
+    _Future result = new _Future();
     var value = initialValue;
     StreamSubscription subscription;
     subscription = this.listen(
@@ -314,10 +314,10 @@
         );
       },
       onError: (e) {
-        result._setError(e);
+        result._completeError(e);
       },
       onDone: () {
-        result._setValue(value);
+        result._complete(value);
       },
       cancelOnError: true);
     return result;
@@ -334,7 +334,7 @@
    * the "done" event arrives.
    */
   Future<String> join([String separator = ""]) {
-    _FutureImpl<String> result = new _FutureImpl<String>();
+    _Future<String> result = new _Future<String>();
     StringBuffer buffer = new StringBuffer();
     StreamSubscription subscription;
     bool first = true;
@@ -348,14 +348,14 @@
           buffer.write(element);
         } catch (e, s) {
           subscription.cancel();
-          result._setError(_asyncError(e, s));
+          result._completeError(_asyncError(e, s));
         }
       },
       onError: (e) {
-        result._setError(e);
+        result._completeError(e);
       },
       onDone: () {
-        result._setValue(buffer.toString());
+        result._complete(buffer.toString());
       },
       cancelOnError: true);
     return result;
@@ -368,7 +368,7 @@
    * If this stream reports an error, the [Future] will report that error.
    */
   Future<bool> contains(Object needle) {
-    _FutureImpl<bool> future = new _FutureImpl<bool>();
+    _Future<bool> future = new _Future<bool>();
     StreamSubscription subscription;
     subscription = this.listen(
         (T element) {
@@ -377,15 +377,15 @@
             (bool isMatch) {
               if (isMatch) {
                 subscription.cancel();
-                future._setValue(true);
+                future._complete(true);
               }
             },
             _cancelAndError(subscription, future)
           );
         },
-        onError: future._setError,
+        onError: future._completeError,
         onDone: () {
-          future._setValue(false);
+          future._complete(false);
         },
         cancelOnError: true);
     return future;
@@ -399,7 +399,7 @@
    * stream has an error event, or if [action] throws.
    */
   Future forEach(void action(T element)) {
-    _FutureImpl future = new _FutureImpl();
+    _Future future = new _Future();
     StreamSubscription subscription;
     subscription = this.listen(
         (T element) {
@@ -409,9 +409,9 @@
             _cancelAndError(subscription, future)
           );
         },
-        onError: future._setError,
+        onError: future._completeError,
         onDone: () {
-          future._setValue(null);
+          future._complete(null);
         },
         cancelOnError: true);
     return future;
@@ -424,7 +424,7 @@
    * If this stream reports an error, the [Future] will report that error.
    */
   Future<bool> every(bool test(T element)) {
-    _FutureImpl<bool> future = new _FutureImpl<bool>();
+    _Future<bool> future = new _Future<bool>();
     StreamSubscription subscription;
     subscription = this.listen(
         (T element) {
@@ -433,15 +433,15 @@
             (bool isMatch) {
               if (!isMatch) {
                 subscription.cancel();
-                future._setValue(false);
+                future._complete(false);
               }
             },
             _cancelAndError(subscription, future)
           );
         },
-        onError: future._setError,
+        onError: future._completeError,
         onDone: () {
-          future._setValue(true);
+          future._complete(true);
         },
         cancelOnError: true);
     return future;
@@ -454,7 +454,7 @@
    * If this stream reports an error, the [Future] will report that error.
    */
   Future<bool> any(bool test(T element)) {
-    _FutureImpl<bool> future = new _FutureImpl<bool>();
+    _Future<bool> future = new _Future<bool>();
     StreamSubscription subscription;
     subscription = this.listen(
         (T element) {
@@ -463,15 +463,15 @@
             (bool isMatch) {
               if (isMatch) {
                 subscription.cancel();
-                future._setValue(true);
+                future._complete(true);
               }
             },
             _cancelAndError(subscription, future)
           );
         },
-        onError: future._setError,
+        onError: future._completeError,
         onDone: () {
-          future._setValue(false);
+          future._complete(false);
         },
         cancelOnError: true);
     return future;
@@ -480,13 +480,13 @@
 
   /** Counts the elements in the stream. */
   Future<int> get length {
-    _FutureImpl<int> future = new _FutureImpl<int>();
+    _Future<int> future = new _Future<int>();
     int count = 0;
     this.listen(
       (_) { count++; },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setValue(count);
+        future._complete(count);
       },
       cancelOnError: true);
     return future;
@@ -494,16 +494,16 @@
 
   /** Reports whether this stream contains any elements. */
   Future<bool> get isEmpty {
-    _FutureImpl<bool> future = new _FutureImpl<bool>();
+    _Future<bool> future = new _Future<bool>();
     StreamSubscription subscription;
     subscription = this.listen(
       (_) {
         subscription.cancel();
-        future._setValue(false);
+        future._complete(false);
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setValue(true);
+        future._complete(true);
       },
       cancelOnError: true);
     return future;
@@ -512,14 +512,14 @@
   /** Collects the data of this stream in a [List]. */
   Future<List<T>> toList() {
     List<T> result = <T>[];
-    _FutureImpl<List<T>> future = new _FutureImpl<List<T>>();
+    _Future<List<T>> future = new _Future<List<T>>();
     this.listen(
       (T data) {
         result.add(data);
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setValue(result);
+        future._complete(result);
       },
       cancelOnError: true);
     return future;
@@ -528,14 +528,14 @@
   /** Collects the data of this stream in a [Set]. */
   Future<Set<T>> toSet() {
     Set<T> result = new Set<T>();
-    _FutureImpl<Set<T>> future = new _FutureImpl<Set<T>>();
+    _Future<Set<T>> future = new _Future<Set<T>>();
     this.listen(
       (T data) {
         result.add(data);
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setValue(result);
+        future._complete(result);
       },
       cancelOnError: true);
     return future;
@@ -627,17 +627,17 @@
    * [:this.elementAt(0):].
    */
   Future<T> get first {
-    _FutureImpl<T> future = new _FutureImpl<T>();
+    _Future<T> future = new _Future<T>();
     StreamSubscription subscription;
     subscription = this.listen(
       (T value) {
         subscription.cancel();
-        future._setValue(value);
+        future._complete(value);
         return;
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setError(new StateError("No elements"));
+        future._completeError(new StateError("No elements"));
       },
       cancelOnError: true);
     return future;
@@ -653,7 +653,7 @@
    * the resulting future completes with a [StateError].
    */
   Future<T> get last {
-    _FutureImpl<T> future = new _FutureImpl<T>();
+    _Future<T> future = new _Future<T>();
     T result = null;
     bool foundResult = false;
     StreamSubscription subscription;
@@ -662,13 +662,13 @@
         foundResult = true;
         result = value;
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
         if (foundResult) {
-          future._setValue(result);
+          future._complete(result);
           return;
         }
-        future._setError(new StateError("No elements"));
+        future._completeError(new StateError("No elements"));
       },
       cancelOnError: true);
     return future;
@@ -680,7 +680,7 @@
    * If [this] is empty or has more than one element throws a [StateError].
    */
   Future<T> get single {
-    _FutureImpl<T> future = new _FutureImpl<T>();
+    _Future<T> future = new _Future<T>();
     T result = null;
     bool foundResult = false;
     StreamSubscription subscription;
@@ -690,19 +690,19 @@
           subscription.cancel();
           // This is the second element we get.
           Error error = new StateError("More than one element");
-          future._setError(error);
+          future._completeError(error);
           return;
         }
         foundResult = true;
         result = value;
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
         if (foundResult) {
-          future._setValue(result);
+          future._complete(result);
           return;
         }
-        future._setError(new StateError("No elements"));
+        future._completeError(new StateError("No elements"));
       },
       cancelOnError: true);
     return future;
@@ -723,7 +723,7 @@
    * error.
    */
   Future<dynamic> firstWhere(bool test(T element), {Object defaultValue()}) {
-    _FutureImpl<dynamic> future = new _FutureImpl();
+    _Future<dynamic> future = new _Future();
     StreamSubscription subscription;
     subscription = this.listen(
       (T value) {
@@ -732,19 +732,19 @@
           (bool isMatch) {
             if (isMatch) {
               subscription.cancel();
-              future._setValue(value);
+              future._complete(value);
             }
           },
           _cancelAndError(subscription, future)
         );
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
         if (defaultValue != null) {
-          _runUserCode(defaultValue, future._setValue, future._setError);
+          _runUserCode(defaultValue, future._complete, future._completeError);
           return;
         }
-        future._setError(new StateError("firstMatch ended without match"));
+        future._completeError(new StateError("firstMatch ended without match"));
       },
       cancelOnError: true);
     return future;
@@ -758,7 +758,7 @@
    * is done.
    */
   Future<dynamic> lastWhere(bool test(T element), {Object defaultValue()}) {
-    _FutureImpl<dynamic> future = new _FutureImpl();
+    _Future<dynamic> future = new _Future();
     T result = null;
     bool foundResult = false;
     StreamSubscription subscription;
@@ -775,17 +775,17 @@
           _cancelAndError(subscription, future)
         );
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
         if (foundResult) {
-          future._setValue(result);
+          future._complete(result);
           return;
         }
         if (defaultValue != null) {
-          _runUserCode(defaultValue, future._setValue, future._setError);
+          _runUserCode(defaultValue, future._complete, future._completeError);
           return;
         }
-        future._setError(new StateError("lastMatch ended without match"));
+        future._completeError(new StateError("lastMatch ended without match"));
       },
       cancelOnError: true);
     return future;
@@ -798,7 +798,7 @@
    * matching element occurs in the stream.
    */
   Future<T> singleWhere(bool test(T element)) {
-    _FutureImpl<T> future = new _FutureImpl<T>();
+    _Future<T> future = new _Future<T>();
     T result = null;
     bool foundResult = false;
     StreamSubscription subscription;
@@ -810,7 +810,7 @@
             if (isMatch) {
               if (foundResult) {
                 subscription.cancel();
-                future._setError(
+                future._completeError(
                     new StateError('Multiple matches for "single"'));
                 return;
               }
@@ -821,13 +821,13 @@
           _cancelAndError(subscription, future)
         );
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
         if (foundResult) {
-          future._setValue(result);
+          future._complete(result);
           return;
         }
-        future._setError(new StateError("single ended without match"));
+        future._completeError(new StateError("single ended without match"));
       },
       cancelOnError: true);
     return future;
@@ -846,20 +846,20 @@
    */
   Future<T> elementAt(int index) {
     if (index is! int || index < 0) throw new ArgumentError(index);
-    _FutureImpl<T> future = new _FutureImpl<T>();
+    _Future<T> future = new _Future<T>();
     StreamSubscription subscription;
     subscription = this.listen(
       (T value) {
         if (index == 0) {
           subscription.cancel();
-          future._setValue(value);
+          future._complete(value);
           return;
         }
         index -= 1;
       },
-      onError: future._setError,
+      onError: future._completeError,
       onDone: () {
-        future._setError(new RangeError.value(index));
+        future._completeError(new RangeError.value(index));
       },
       cancelOnError: true);
     return future;
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 5b3d760..194602e 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -250,7 +250,7 @@
   // TODO(lrn): Could this be stored in the varData field too, if it's not
   // accessed until the call to "close"? Then we need to special case if it's
   // accessed earlier, or if close is called before subscribing.
-  _FutureImpl _doneFuture;
+  _Future _doneFuture;
 
   _StreamController();
 
@@ -347,7 +347,7 @@
   // StreamSink interface.
   Future addStream(Stream<T> source) {
     if (!_mayAddEvent) throw _badEventState();
-    if (_isCanceled) return new _FutureImpl.immediate(null);
+    if (_isCanceled) return new _Future.immediate(null);
     _StreamControllerAddStreamState addState =
         new _StreamControllerAddStreamState(this, _varData, source);
     _varData = addState;
@@ -359,8 +359,8 @@
 
   Future _ensureDoneFuture() {
     if (_doneFuture == null) {
-      _doneFuture = new _FutureImpl();
-      if (_isCanceled) _doneFuture._setValue(null);
+      _doneFuture = new _Future();
+      if (_isCanceled) _doneFuture._complete(null);
     }
     return _doneFuture;
   }
@@ -479,7 +479,7 @@
         (_state & ~(_STATE_SUBSCRIBED | _STATE_ADDSTREAM)) | _STATE_CANCELED;
     _runGuarded(_onCancel);
     if (_doneFuture != null && _doneFuture._mayComplete) {
-      _doneFuture._asyncSetValue(null);
+      _doneFuture._asyncComplete(null);
     }
   }
 
@@ -649,13 +649,13 @@
  */
 class _AddStreamState<T> {
   // [_FutureImpl] returned by call to addStream.
-  _FutureImpl addStreamFuture;
+  _Future addStreamFuture;
 
   // Subscription on stream argument to addStream.
   StreamSubscription addSubscription;
 
   _AddStreamState(_EventSink<T> controller, Stream source)
-      : addStreamFuture = new _FutureImpl(),
+      : addStreamFuture = new _Future(),
         addSubscription = source.listen(controller._add,
                                         onError: controller._addError,
                                         onDone: controller._close,
@@ -675,7 +675,7 @@
   }
 
   void complete() {
-    addStreamFuture._asyncSetValue(null);
+    addStreamFuture._asyncComplete(null);
   }
 }
 
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 7f26c4f..ffab312 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -190,13 +190,13 @@
   }
 
   Future asFuture([var futureValue]) {
-    _FutureImpl<T> result = new _FutureImpl<T>();
+    _Future<T> result = new _Future<T>();
 
     // Overwrite the onDone and onError handlers.
-    _onDone = () { result._setValue(futureValue); };
+    _onDone = () { result._complete(futureValue); };
     _onError = (error) {
       cancel();
-      result._setError(error);
+      result._completeError(error);
     };
 
     return result;
@@ -716,7 +716,7 @@
   void cancel() {}
   bool get isPaused => _pauseCounter > 0;
 
-  Future asFuture([futureValue]) => new _FutureImpl();
+  Future asFuture([futureValue]) => new _Future();
 }
 
 class _AsBroadcastStream<T> extends Stream<T> {
@@ -917,14 +917,14 @@
 
   Future<bool> moveNext() {
     if (_state == _STATE_DONE) {
-      return new _FutureImpl<bool>.immediate(false);
+      return new _Future<bool>.immediate(false);
     }
     if (_state == _STATE_MOVING) {
       throw new StateError("Already waiting for next.");
     }
     if (_state == _STATE_FOUND) {
       _state = _STATE_MOVING;
-      _futureOrPrefetch = new _FutureImpl<bool>();
+      _futureOrPrefetch = new _Future<bool>();
       return _futureOrPrefetch;
     } else {
       assert(_state >= _STATE_EXTRA_DATA);
@@ -934,14 +934,14 @@
           _current = _futureOrPrefetch;
           _futureOrPrefetch = null;
           _subscription.resume();
-          return new _FutureImpl<bool>.immediate(true);
+          return new _Future<bool>.immediate(true);
         case _STATE_EXTRA_ERROR:
           Object prefetch = _futureOrPrefetch;
           _clear();
-          return new _FutureImpl<bool>.immediateError(prefetch);
+          return new _Future<bool>.immediateError(prefetch);
         case _STATE_EXTRA_DONE:
           _clear();
-          return new _FutureImpl<bool>.immediate(false);
+          return new _Future<bool>.immediate(false);
       }
     }
   }
@@ -957,9 +957,9 @@
   void cancel() {
     StreamSubscription subscription = _subscription;
     if (_state == _STATE_MOVING) {
-      _FutureImpl<bool> hasNext = _futureOrPrefetch;
+      _Future<bool> hasNext = _futureOrPrefetch;
       _clear();
-      hasNext._setValue(false);
+      hasNext._complete(false);
     } else {
       _clear();
     }
@@ -969,10 +969,10 @@
   void _onData(T data) {
     if (_state == _STATE_MOVING) {
       _current = data;
-      _FutureImpl<bool> hasNext = _futureOrPrefetch;
+      _Future<bool> hasNext = _futureOrPrefetch;
       _futureOrPrefetch = null;
       _state = _STATE_FOUND;
-      hasNext._setValue(true);
+      hasNext._complete(true);
       return;
     }
     _subscription.pause();
@@ -983,10 +983,10 @@
 
   void _onError(Object error) {
     if (_state == _STATE_MOVING) {
-      _FutureImpl<bool> hasNext = _futureOrPrefetch;
+      _Future<bool> hasNext = _futureOrPrefetch;
       // We have cancelOnError: true, so the subscription is canceled.
       _clear();
-      hasNext._setError(error);
+      hasNext._completeError(error);
       return;
     }
     _subscription.pause();
@@ -997,9 +997,9 @@
 
   void _onDone() {
      if (_state == _STATE_MOVING) {
-      _FutureImpl<bool> hasNext = _futureOrPrefetch;
+      _Future<bool> hasNext = _futureOrPrefetch;
       _clear();
-      hasNext._setValue(false);
+      hasNext._complete(false);
       return;
     }
     _subscription.pause();
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index 7436b92..b126747 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -25,10 +25,10 @@
 }
 
 /** Helper function to make an onError argument to [_runUserCode]. */
-_cancelAndError(StreamSubscription subscription, _FutureImpl future) =>
+_cancelAndError(StreamSubscription subscription, _Future future) =>
   (error) {
     subscription.cancel();
-    future._setError(error);
+    future._completeError(error);
   };
 
 
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 9be85d1..bd1da92 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -87,13 +87,13 @@
    *
    * Returns the result of the invocation.
    */
-  runFromChildZone(f());
+  dynamic runFromChildZone(f());
 
   /**
    * Same as [runFromChildZone] but catches uncaught errors and gives them to
    * [handleUncaughtError].
    */
-  runFromChildZoneGuarded(f());
+  dynamic runFromChildZoneGuarded(f());
 
   /**
    * Runs [f] asynchronously in [zone].
@@ -181,7 +181,7 @@
    * A zone is done when its dynamic extent has finished executing and
    * there are no outstanding asynchronous callbacks.
    */
-  _dispose() {
+  void _dispose() {
     if (_parentZone != null) {
       _parentZone._removeChild(this);
     }
@@ -218,10 +218,10 @@
     this._runGuarded(f);
   }
 
-  runFromChildZone(f()) => this._runUnguarded(f);
-  runFromChildZoneGuarded(f()) => this._runGuarded(f);
+  dynamic runFromChildZone(f()) => this._runUnguarded(f);
+  dynamic runFromChildZoneGuarded(f()) => this._runGuarded(f);
 
-  _runInZone(f(), bool handleUncaught) {
+  dynamic _runInZone(f(), bool handleUncaught) {
     if (identical(_Zone._current, this)
         && !handleUncaught
         && _isExecutingCallback) {
@@ -261,18 +261,18 @@
    *
    * Uncaught errors are given to [handleUncaughtError].
    */
-  _runGuarded(void f()) {
+  dynamic _runGuarded(void f()) {
     return _runInZone(f, true);
   }
 
   /**
    * Runs the function but doesn't catch uncaught errors.
    */
-  _runUnguarded(void f()) {
+  dynamic _runUnguarded(void f()) {
     return _runInZone(f, false);
   }
 
-  runAsync(void f(), _Zone zone) => _parentZone.runAsync(f, zone);
+  void runAsync(void f(), _Zone zone) => _parentZone.runAsync(f, zone);
 
   // TODO(floitsch): the zone should just forward to the parent zone. The
   // default zone should then create the _ZoneTimer.
@@ -305,7 +305,7 @@
 
   _Zone get _errorZone => this;
 
-  handleUncaughtError(error) {
+  void handleUncaughtError(error) {
     _scheduleAsyncCallback(() {
       print("Uncaught Error: ${error}");
       var trace = getAttachedStackTrace(error);
@@ -341,14 +341,15 @@
   _WaitForCompletionZone(_Zone parentZone, this._onDone) : super(parentZone);
 
   /**
-   * Runs the given function asynchronously. Executes the [_onDone] callback
-   * when the zone is done.
+   * Runs the given function.
+   *
+   * Executes the [_onDone] callback when the zone is done.
    */
-  runWaitForCompletion(void f()) {
+  dynamic runWaitForCompletion(void f()) {
     return this._runUnguarded(f);
   }
 
-  _dispose() {
+  void _dispose() {
     super._dispose();
     _onDone();
   }
@@ -370,7 +371,7 @@
 
   _Zone get _errorZone => this;
 
-  handleUncaughtError(error) {
+  void handleUncaughtError(error) {
     try {
       _handleError(error);
     } catch(e, s) {
@@ -386,7 +387,7 @@
    * Runs the given function asynchronously. Executes the [_onDone] callback
    * when the zone is done.
    */
-  runWaitForCompletion(void f()) {
+  dynamic runWaitForCompletion(void f()) {
     return this._runGuarded(f);
   }
 
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 3aadab2..bcca966 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -41,6 +41,14 @@
    * for keys in order to place them in the hash table. If it is omitted, the
    * key's own [Object.hashCode] is used.
    *
+   * If using methods like [operator[]], [remove] and [containsKey] together
+   * with a custom equality and hashcode, an extra `isValidKey` function
+   * can be supplied. This function is called before calling [equals] or
+   * [hashCode] with an argument that may not be a [K] instance, and if the
+   * call returns false, the key is assumed to not be in the set.
+   * The [isValidKey] function defaults to just testing if the object is a
+   * [K] instance.
+   *
    * The used `equals` and `hashCode` method should always be consistent,
    * so that if `equals(a, b)` then `hashCode(a) == hashCode(b)`. The hash
    * of an object, or what it compares equal to, should not change while the
@@ -50,7 +58,9 @@
    * you also want to supply the other. The only common exception is to pass
    * [identical] as the equality and use the default hash code.
    */
-  external factory HashMap({bool equals(K key1, K key2), int hashCode(K key)});
+  external factory HashMap({bool equals(K key1, K key2),
+                            int hashCode(K key),
+                            bool isValidKey(potentialKey)});
 
   /**
    * Creates a [HashMap] that contains all key value pairs of [other].
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index ff6f045f..34744d0 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -18,8 +18,10 @@
  *
  * The map allows `null` as a key.
  */
-class LinkedHashMap<K, V> implements HashMap<K, V> {
-  external LinkedHashMap();
+abstract class LinkedHashMap<K, V> implements HashMap<K, V> {
+  external factory LinkedHashMap({ bool equals(K key1, K key2),
+                                   int hashCode(K key),
+                                   bool isValidKey(potentialKey) });
 
   /**
    * Creates a [LinkedHashMap] that contains all key value pairs of [other].
@@ -64,35 +66,4 @@
     Maps._fillMapWithIterables(map, keys, values);
     return map;
   }
-
-  external bool containsKey(Object key);
-
-  external bool containsValue(Object value);
-
-  external void addAll(Map<K, V> other);
-
-  external V operator [](Object key);
-
-  external void operator []=(K key, V value);
-
-  external V putIfAbsent(K key, V ifAbsent());
-
-  external V remove(Object key);
-
-  external void clear();
-
-  external void forEach(void action (K key, V value));
-
-  /** The keys of the map, in insertion order. */
-  external Iterable<K> get keys;
-  /** The values of the map, in the order of their corresponding [keys].*/
-  external Iterable<V> get values;
-
-  external int get length;
-
-  external bool get isEmpty;
-
-  external bool get isNotEmpty;
-
-  String toString() => Maps.mapToString(this);
 }
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index a0c3624..72251d9 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -4,6 +4,8 @@
 
 part of dart.collection;
 
+typedef bool _Predicate<T>(T value);
+
 /**
  * A node in a splay tree. It holds the sorting key and the left
  * and right children in the tree.
@@ -229,6 +231,10 @@
   }
 }
 
+class _TypeTest<T> {
+  bool test(v) => v is T;
+}
+
 /*
  * A [Map] of objects that can be ordered relative to each other.
  *
@@ -238,19 +244,31 @@
  * Keys of the map are compared using the `compare` function passed in
  * the constructor. If that is omitted, the objects are assumed to be
  * [Comparable], and are compared using their [Comparable.compareTo]
- * method. This also means that `null` is *not* allowed as a key.
+ * method. Non-comparable objects (including `null`) will not work as keys
+ * in that case.
+ *
+ * To allow calling [operator[]], [remove] or [containsKey] with objects
+ * that are not supported by the `compare` function, an extra `isValidKey`
+ * predicate function can be supplied. This function is tested before
+ * using the `compare` function on an argument value that may not be a [K]
+ * value. If omitted, the `isValidKey` function defaults to testing if the
+ * value is a [K].
  */
 class SplayTreeMap<K, V> extends _SplayTree<K> implements Map<K, V> {
   Comparator<K> _comparator;
+  _Predicate _validKey;
 
-  SplayTreeMap([int compare(K key1, K key2)])
-      : _comparator = (compare == null) ? Comparable.compare : compare;
+  SplayTreeMap([int compare(K key1, K key2), bool isValidKey(potentialKey)])
+      : _comparator = (compare == null) ? Comparable.compare : compare,
+        _validKey = (isValidKey != null) ? isValidKey : ((v) => v is K);
 
   /**
    * Creates a [SplayTreeMap] that contains all key value pairs of [other].
    */
-  factory SplayTreeMap.from(Map<K, V> other, [int compare(K key1, K key2)]) =>
-      new SplayTreeMap(compare)..addAll(other);
+  factory SplayTreeMap.from(Map<K, V> other,
+                            [ int compare(K key1, K key2),
+                              bool isValidKey(potentialKey)]) =>
+      new SplayTreeMap(compare, isValidKey)..addAll(other);
 
   /**
    * Creates a [SplayTreeMap] where the keys and values are computed from the
@@ -266,8 +284,9 @@
    * identity function.
    */
   factory SplayTreeMap.fromIterable(Iterable<K> iterable,
-      {K key(element), V value(element), int compare(K key1, K key2)}) {
-    SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
+      {K key(element), V value(element), int compare(K key1, K key2),
+       bool isValidKey(potentialKey) }) {
+    SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare, isValidKey);
     Maps._fillMapWithMappedIterable(map, iterable, key, value);
     return map;
   }
@@ -284,8 +303,8 @@
    * It is an error if the two [Iterable]s don't have the same length.
    */
   factory SplayTreeMap.fromIterables(Iterable<K> keys, Iterable<V> values,
-      [int compare(K key1, K key2)]) {
-    SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare);
+      [int compare(K key1, K key2), bool isValidKey(potentialKey)]) {
+    SplayTreeMap<K, V> map = new SplayTreeMap<K, V>(compare, isValidKey);
     Maps._fillMapWithIterables(map, keys, values);
     return map;
   }
@@ -296,7 +315,7 @@
 
   V operator [](Object key) {
     if (key == null) throw new ArgumentError(key);
-    if (key is! K) return null;
+    if (!_validKey(key)) return null;
     if (_root != null) {
       int comp = _splay(key);
       if (comp == 0) {
@@ -308,7 +327,7 @@
   }
 
   V remove(Object key) {
-    if (key is! K) return null;
+    if (!_validKey(key)) return null;
     _SplayTreeMapNode mapRoot = _remove(key);
     if (mapRoot != null) return mapRoot.value;
     return null;
@@ -378,7 +397,7 @@
   }
 
   bool containsKey(Object key) {
-    return key is K && _splay(key) == 0;
+    return _validKey(key) && _splay(key) == 0;
   }
 
   bool containsValue(Object value) {
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index a902226..9ac401b5 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -155,7 +155,7 @@
 import "dart:collection";
 import "dart:_collection-dev" hide Symbol;
 import "dart:_collection-dev" as _collection_dev;
-import "dart:convert" show UTF8;
+import "dart:convert" show UTF8, Encoding;
 
 part "bool.dart";
 part "comparable.dart";
diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart
index 409e294..4aa161b 100644
--- a/sdk/lib/core/double.dart
+++ b/sdk/lib/core/double.dart
@@ -9,6 +9,8 @@
 // different platform implementations.
 
 /**
+ * A double-precision floating point number.
+ *
  * Representation of Dart doubles containing double specific constants
  * and operations and specializations of operations inherited from
  * [num]. Dart doubles are 64-bit floating-point numbers as specified in the
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 96a6d40..2b1b70c 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -99,6 +99,78 @@
   bool get isOdd;
 
   /**
+   * Returns the minimum number of bits required to store this integer.
+   *
+   * The number of bits excludes the sign bit, which gives the natural length
+   * for non-negative (unsigned) values.  Negative values are complemented to
+   * return the bit position of the first bit that differs from the sign bit.
+   *
+   * To find the the number of bits needed to store the value as a signed value,
+   * add one, i.e. use `x.bitLength + 1`.
+   *
+   *      x.bitLength == (-x-1).bitLength
+   *
+   *      3.bitLength == 2;     // 00000011
+   *      2.bitLength == 2;     // 00000010
+   *      1.bitLength == 1;     // 00000001
+   *      0.bitLength == 0;     // 00000000
+   *      (-1).bitLength == 0;  // 11111111
+   *      (-2).bitLength == 1;  // 11111110
+   *      (-3).bitLength == 2;  // 11111101
+   *      (-4).bitLength == 2;  // 11111100
+   */
+  int get bitLength;
+
+  /**
+   * Returns the least significant [width] bits of this integer as a
+   * non-negative number (i.e. unsigned representation).  The returned value has
+   * zeros in all bit positions higher than [width].
+   *
+   *     (-1).toUnsigned(5) == 32   // 11111111  ->  00011111
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit quantity:
+   *
+   *     q = (q + 1).toUnsigned(8);
+   *
+   * `q` will count from `0` up to `255` and then wrap around to `0`.
+   *
+   * If the input fits in [width] bits without truncation, the result is the
+   * same as the input.  The minimum width needed to avoid truncation of `x` is
+   * given by `x.bitLength`, i.e.
+   *
+   *     x == x.toUnsigned(x.bitLength);
+   */
+  int toUnsigned(int width);
+
+  /**
+   * Returns the least significant [width] bits of this integer, extending the
+   * highest retained bit to the sign.  This is the same as truncating the value
+   * to fit in [width] bits using an signed 2-s complement representation.  The
+   * returned value has the same bit value in all positions higher than [width].
+   *
+   *                                    V--sign bit-V
+   *     16.toSigned(5) == -16   //  00010000 -> 11110000
+   *     239.toSigned(5) == 15   //  11101111 -> 00001111
+   *                                    ^           ^
+   *
+   * This operation can be used to simulate arithmetic from low level languages.
+   * For example, to increment an 8 bit signed quantity:
+   *
+   *     q = (q + 1).toSigned(8);
+   *
+   * `q` will count from `0` up to `127`, wrap to `-128` and count back up to
+   * `127`.
+   *
+   * If the input value fits in [width] bits without truncation, the result is
+   * the same as the input.  The minimum width needed to avoid truncation of `x`
+   * is `x.bitLength + 1`, i.e.
+   *
+   *     x == x.toSigned(x.bitLength + 1);
+   */
+  int toSigned(int width);
+
+  /**
    * Return the negative value of this integer.
    *
    * The result of negating an integer always has the opposite sign, except
diff --git a/sdk/lib/core/stopwatch.dart b/sdk/lib/core/stopwatch.dart
index 9afc50b..c47c6d2 100644
--- a/sdk/lib/core/stopwatch.dart
+++ b/sdk/lib/core/stopwatch.dart
@@ -5,7 +5,7 @@
 part of dart.core;
 
 /**
- * A simple [Stopwatch] interface to measure elapsed time.
+ * A simple stopwatch interface to measure elapsed time.
  */
 class Stopwatch {
   // The _start and _stop fields capture the time when [start] and [stop]
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 30057f1..aa00f63 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -8,6 +8,7 @@
  * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986.
  */
 class Uri {
+  final String _host;
   int _port;
   String _path;
 
@@ -46,15 +47,29 @@
    *
    * Returns the empty string if there is no authority component and
    * hence no host.
+   *
+   * If the host is an IP version 6 address, the surrounding `[` and `]` is
+   * removed.
    */
-  final String host;
+  String get host {
+    if (_host != null && _host.startsWith('[')) {
+      return _host.substring(1, _host.length - 1);
+    }
+    return _host;
+  }
 
   /**
    * Returns the port part of the authority component.
    *
    * Returns 0 if there is no port in the authority component.
    */
-  int get port => _port;
+  int get port {
+    if (_port == 0) {
+      if (scheme == "http") return 80;
+      if (scheme == "https") return 443;
+    }
+    return _port;
+  }
 
   /**
    * Returns the path component.
@@ -98,7 +113,7 @@
   static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
 
   Uri._fromMatch(Match m) :
-    this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
+    this(scheme: _makeScheme(_emptyIfNull(m[_COMPONENT_SCHEME])),
          userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
          host: _eitherOf(
          m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]),
@@ -123,7 +138,7 @@
    * [userInfo].
    *
    * The host part of the authority component is set through
-   * [host]. The host can either be a hostname, a IPv4 address or an
+   * [host]. The host can either be a hostname, an IPv4 address or an
    * IPv6 address, contained in '[' and ']'. If the host contains a
    * ':' character, the '[' and ']' are added if not already provided.
    *
@@ -153,9 +168,9 @@
    *
    * The fragment component is set through [fragment].
    */
-  Uri({scheme,
+  Uri({String scheme,
        this.userInfo: "",
-       this.host: "",
+       String host: "",
        port: 0,
        String path,
        Iterable<String> pathSegments,
@@ -163,6 +178,7 @@
        Map<String, String> queryParameters,
        fragment: ""}) :
       scheme = _makeScheme(scheme),
+      _host = _makeHost(host),
       query = _makeQuery(query, queryParameters),
       fragment = _makeFragment(fragment) {
     // Perform scheme specific normalization.
@@ -237,22 +253,34 @@
         break;
       }
     }
+    var hostEnd = hostStart;
+    if (hostStart < authority.length &&
+        authority.codeUnitAt(hostStart) == _LEFT_BRACKET) {
+      // IPv6 host.
+      for (; hostEnd < authority.length; hostEnd++) {
+        if (authority.codeUnitAt(hostEnd) == _RIGHT_BRACKET) break;
+      }
+      if (hostEnd == authority.length) {
+        throw new FormatException("Invalid IPv6 host entry.");
+      }
+      parseIPv6Address(authority.substring(hostStart + 1, hostEnd));
+      hostEnd++;  // Skip the closing bracket.
+      if (hostEnd != authority.length &&
+          authority.codeUnitAt(hostEnd) != _COLON) {
+        throw new FormatException("Invalid end of authority");
+      }
+    }
     // Split host and port.
     bool hasPort = false;
-    for (int i = hostStart; i < authority.length; i++) {
-      if (authority.codeUnitAt(i) == _COLON) {
-        hasPort = true;
-        host = authority.substring(hostStart, i);
-        if (!host.isEmpty) {
-          var portString = authority.substring(i + 1);
-          if (portString.isNotEmpty) port = int.parse(portString);
-        }
+    for (; hostEnd < authority.length; hostEnd++) {
+      if (authority.codeUnitAt(hostEnd) == _COLON) {
+        var portString = authority.substring(hostEnd + 1);
+        // We allow the empty port - falling back to initial value.
+        if (portString.isNotEmpty) port = int.parse(portString);
         break;
       }
     }
-    if (!hasPort) {
-      host = hasUserInfo ? authority.substring(hostStart) : authority;
-    }
+    host = authority.substring(hostStart, hostEnd);
 
     return new Uri(scheme: scheme,
                    userInfo: userInfo,
@@ -474,6 +502,24 @@
     return _queryParameters;
   }
 
+  static String _makeHost(String host) {
+    if (host == null || host.isEmpty) return host;
+    if (host.codeUnitAt(0) == _LEFT_BRACKET) {
+      if (host.codeUnitAt(host.length - 1) != _RIGHT_BRACKET) {
+        throw new FormatException('Missing end `]` to match `[` in host');
+      }
+      parseIPv6Address(host.substring(1, host.length - 1));
+      return host;
+    }
+    for (int i = 0; i < host.length; i++) {
+      if (host.codeUnitAt(i) == _COLON) {
+        parseIPv6Address(host);
+        return '[$host]';
+      }
+    }
+    return host;
+  }
+
   static String _makeScheme(String scheme) {
     bool isSchemeLowerCharacter(int ch) {
       return ch < 128 &&
@@ -489,6 +535,10 @@
     int length = scheme.length;
     for (int i = 0; i < length; i++) {
       int codeUnit = scheme.codeUnitAt(i);
+      if (i == 0 && !_isAlphabeticCharacter(codeUnit)) {
+        // First code unit must be an alphabetic character.
+        throw new ArgumentError('Illegal scheme: $scheme');
+      }
       if (!isSchemeLowerCharacter(codeUnit)) {
         if (isSchemeCharacter(codeUnit)) {
           allLowercase = false;
@@ -670,7 +720,7 @@
   static final RegExp _splitRe = new RegExp(
       '^'
       '(?:'
-        '([^:/?#.]+)'                   // scheme - ignore special characters
+        '([^:/?#]+)'                    // scheme - ignore special characters
                                         // used by other URL parts such as :,
                                         // ?, /, #, and .
       ':)?'
@@ -828,15 +878,15 @@
    * See: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
    */
   String get origin {
-    if (scheme == "" || host == null || host == "") {
+    if (scheme == "" || _host == null || _host == "") {
       throw new StateError("Cannot use origin without a scheme: $this");
     }
     if (scheme != "http" && scheme != "https") {
       throw new StateError(
         "Origin is only applicable schemes http and https: $this");
     }
-    if (port == 0) return "$scheme://$host";
-    return "$scheme://$host:$port";
+    if (_port == 0) return "$scheme://$_host";
+    return "$scheme://$_host:$_port";
   }
 
   /**
@@ -931,7 +981,7 @@
     }
     _checkNonWindowsPathReservedCharacters(pathSegments, false);
     var result = new StringBuffer();
-    if (isAbsolute) result.write("/");
+    if (_isPathAbsolute) result.write("/");
     result.writeAll(pathSegments, "/");
     return result.toString();
   }
@@ -949,7 +999,7 @@
       _checkWindowsPathReservedCharacters(segments, false);
     }
     var result = new StringBuffer();
-    if (isAbsolute && !hasDriveLetter) result.write("\\");
+    if (_isPathAbsolute && !hasDriveLetter) result.write("\\");
     if (host != "") {
       result.write("\\");
       result.write(host);
@@ -960,13 +1010,17 @@
     return result.toString();
   }
 
+  bool get _isPathAbsolute {
+    if (path == null || path.isEmpty) return false;
+    return path.startsWith('/');
+  }
+
   void _writeAuthority(StringSink ss) {
     _addIfNonEmpty(ss, userInfo, userInfo, "@");
-    ss.write(host == null ? "null" :
-             host.contains(':') ? '[$host]' : host);
-    if (port != 0) {
+    ss.write(_host == null ? "null" : _host);
+    if (_port != 0) {
       ss.write(":");
-      ss.write(port.toString());
+      ss.write(_port.toString());
     }
   }
 
@@ -1017,7 +1071,7 @@
    * safe for literal use as a URI component.
    *
    * All characters except uppercase and lowercase letters, digits and
-   * the characters `!$&'()*+,;=:@` are percent-encoded. This is the
+   * the characters `-_.!~*'()` are percent-encoded. This is the
    * set of characters specified in RFC 2396 and the which is
    * specified for the encodeUriComponent in ECMA-262 version 5.1.
    *
@@ -1083,12 +1137,13 @@
    * pluses to spaces.
    *
    * It will create a byte-list of the decoded characters, and then use
-   * [decode] to decode the byte-list to a String. Default is a UTF-8 decoder.
+   * [encoding] to decode the byte-list to a String. The default encoding is
+   * UTF-8.
    */
   static String decodeQueryComponent(
       String encodedComponent,
-      {String decode(List<int> bytes): null}) {
-    return _uriDecode(encodedComponent, plusToSpace: true, decode: decode);
+      {Encoding encoding: UTF8}) {
+    return _uriDecode(encodedComponent, plusToSpace: true, encoding: encoding);
   }
 
   /**
@@ -1128,26 +1183,156 @@
    * Keys in the query string that have no value are mapped to the
    * empty string.
    *
-   * Each query component will be decoded using [decode]. Default is a UTF-8
-   * decoder.
+   * Each query component will be decoded using [encoding]. The default encoding
+   * is UTF-8.
    */
-  static Map<String, String> splitQueryString(
-      String query,
-      {String decode(List<int> bytes): null}) {
+  static Map<String, String> splitQueryString(String query,
+                                              {Encoding encoding: UTF8}) {
     return query.split("&").fold({}, (map, element) {
       int index = element.indexOf("=");
       if (index == -1) {
-        if (element != "") map[decodeQueryComponent(element)] = "";
+        if (element != "") {
+          map[decodeQueryComponent(element, encoding: encoding)] = "";
+        }
       } else if (index != 0) {
         var key = element.substring(0, index);
         var value = element.substring(index + 1);
-        map[Uri.decodeQueryComponent(key, decode: decode)] =
-            decodeQueryComponent(value, decode: decode);
+        map[Uri.decodeQueryComponent(key, encoding: encoding)] =
+            decodeQueryComponent(value, encoding: encoding);
       }
       return map;
     });
   }
 
+  /**
+   * Parse the [host] as an IP version 4 (IPv4) address, returning the address
+   * as a list of 4 bytes in network byte order (big endian).
+   *
+   * Throws a [FormatException] if [host] is not a valid IPv4 address
+   * representation.
+   */
+  static List<int> parseIPv4Address(String host) {
+    void error(String msg) {
+      throw new FormatException('Illegal IPv4 address, $msg');
+    }
+    var bytes = host.split('.');
+    if (bytes.length != 4) {
+      error('IPv4 address should contain exactly 4 parts');
+    }
+    // TODO(ajohnsen): Consider using Uint8List.
+    return bytes
+        .map((byteString) {
+          int byte = int.parse(byteString);
+          if (byte < 0 || byte > 255) {
+            error('each part must be in the range of `0..255`');
+          }
+          return byte;
+        })
+        .toList();
+  }
+
+  /**
+   * Parse the [host] as an IP version 6 (IPv6) address, returning the address
+   * as a list of 16 bytes in network byte order (big endian).
+   *
+   * Throws a [FormatException] if [host] is not a valid IPv6 address
+   * representation.
+   *
+   * Some examples of IPv6 addresses:
+   *  * ::1
+   *  * FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
+   *  * 3ffe:2a00:100:7031::1
+   *  * ::FFFF:129.144.52.38
+   *  * 2010:836B:4179::836B:4179
+   */
+  static List<int> parseIPv6Address(String host) {
+    // An IPv6 address consists of exactly 8 parts of 1-4 hex digits, seperated
+    // by `:`'s, with the following exceptions:
+    //
+    //  - One (and only one) wildcard (`::`) may be present, representing a fill
+    //    of 0's. The IPv6 `::` is thus 16 bytes of `0`.
+    //  - The last two parts may be replaced by an IPv4 address.
+    void error(String msg) {
+      throw new FormatException('Illegal IPv6 address, $msg');
+    }
+    int parseHex(int start, int end) {
+      if (end - start > 4) {
+        error('an IPv6 part can only contain a maximum of 4 hex digits');
+      }
+      int value = int.parse(host.substring(start, end), radix: 16);
+      if (value < 0 || value > (1 << 16) - 1) {
+        error('each part must be in the range of `0x0..0xFFFF`');
+      }
+      return value;
+    }
+    if (host.length < 2) error('address is too short');
+    List<int> parts = [];
+    bool wildcardSeen = false;
+    int partStart = 0;
+    // Parse all parts, except a potential last one.
+    for (int i = 0; i < host.length; i++) {
+      if (host.codeUnitAt(i) == _COLON) {
+        if (i == 0) {
+          // If we see a `:` in the beginning, expect wildcard.
+          i++;
+          if (host.codeUnitAt(i) != _COLON) {
+            error('invalid start colon.');
+          }
+          partStart = i;
+        }
+        if (i == partStart) {
+          // Wildcard. We only allow one.
+          if (wildcardSeen) {
+            error('only one wildcard `::` is allowed');
+          }
+          wildcardSeen = true;
+          parts.add(-1);
+        } else {
+          // Found a single colon. Parse [partStart..i] as a hex entry.
+          parts.add(parseHex(partStart, i));
+        }
+        partStart = i + 1;
+      }
+    }
+    if (parts.length == 0) error('too few parts');
+    bool atEnd = partStart == host.length;
+    bool isLastWildcard = parts.last == -1;
+    if (atEnd && !isLastWildcard) {
+      error('expected a part after last `:`');
+    }
+    if (!atEnd) {
+      try {
+        parts.add(parseHex(partStart, host.length));
+      } catch (e) {
+        // Failed to parse the last chunk as hex. Try IPv4.
+        try {
+          List<int> last = parseIPv4Address(host.substring(partStart));
+          parts.add(last[0] << 8 | last[1]);
+          parts.add(last[2] << 8 | last[3]);
+        } catch (e) {
+          error('invalid end of IPv6 address.');
+        }
+      }
+    }
+    if (wildcardSeen) {
+      if (parts.length > 7) {
+        error('an address with a wildcard must have less than 7 parts');
+      }
+    } else if (parts.length != 8) {
+      error('an address without a wildcard must contain exactly 8 parts');
+    }
+    // TODO(ajohnsen): Consider using Uint8List.
+    return parts
+        .expand((value) {
+          if (value == -1) {
+            return new List.filled((9 - parts.length) * 2, 0);
+          } else {
+            return [(value >> 8) & 0xFF, value & 0xFF];
+          }
+        })
+        .toList();
+  }
+
   // Frequently used character codes.
   static const int _DOUBLE_QUOTE = 0x22;
   static const int _PERCENT = 0x25;
@@ -1164,7 +1349,9 @@
   static const int _UPPER_CASE_A = 0x41;
   static const int _UPPER_CASE_F = 0x46;
   static const int _UPPER_CASE_Z = 0x5A;
+  static const int _LEFT_BRACKET = 0x5B;
   static const int _BACKSLASH = 0x5C;
+  static const int _RIGHT_BRACKET = 0x5D;
   static const int _LOWER_CASE_A = 0x61;
   static const int _LOWER_CASE_F = 0x66;
   static const int _LOWER_CASE_Z = 0x7A;
@@ -1244,11 +1431,11 @@
    * If [plusToSpace] is `true`, plus characters will be converted to spaces.
    *
    * The decoder will create a byte-list of the percent-encoded parts, and then
-   * decode the byte-list using [decode]. Default is a UTF-8 decoder.
+   * decode the byte-list using [encoding]. The default encodingis UTF-8.
    */
   static String _uriDecode(String text,
                            {bool plusToSpace: false,
-                            String decode(List<int> bytes): null}) {
+                            Encoding encoding: UTF8}) {
     StringBuffer result = new StringBuffer();
     List<int> codepoints = new List<int>();
     for (int i = 0; i < text.length;) {
@@ -1271,13 +1458,16 @@
           if (i == text.length) break;
           ch = text.codeUnitAt(i);
         }
-        result.write(
-            decode == null ? UTF8.decode(codepoints) : decode(codepoints));
+        result.write(encoding.decode(codepoints));
       }
     }
     return result.toString();
   }
 
+  static bool _isAlphabeticCharacter(int codeUnit)
+    => (codeUnit >= _LOWER_CASE_A && codeUnit <= _LOWER_CASE_Z) ||
+       (codeUnit >= _UPPER_CASE_A && codeUnit <= _UPPER_CASE_Z);
+
   // Tables of char-codes organized as a bit vector of 128 bits where
   // each bit indicate whether a character code on the 0-127 needs to
   // be escaped or not.
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 129d2d9..d5bf1dd 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -12,7 +12,7 @@
  *
  * * If you've never written a web app before, try our
  * tutorials&mdash;[A Game of Darts](http://dartlang.org/docs/tutorials).
- * 
+ *
  * * To see some web-based Dart apps in action and to play with the code,
  * download
  * [Dart Editor](http://www.dartlang.org/#get-started)
@@ -54,7 +54,8 @@
     JSName, Null, Returns,
     findDispatchTagForInterceptorClass, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
-    Interceptor, JSExtendableArray, findInterceptorConstructorForType;
+    Interceptor, JSExtendableArray, findInterceptorConstructorForType,
+    getNativeInterceptor;
 
 
 
@@ -184,7 +185,7 @@
   @DomName('HTMLAnchorElement.HTMLAnchorElement')
   @DocsEditable()
   factory AnchorElement({String href}) {
-    var e = document.$dom_createElement("a");
+    var e = document.createElement("a");
     if (href != null) e.href = href;
     return e;
   }
@@ -432,7 +433,7 @@
 
   @DomName('HTMLAreaElement.HTMLAreaElement')
   @DocsEditable()
-  factory AreaElement() => document.$dom_createElement("area");
+  factory AreaElement() => document.createElement("area");
 
   @DomName('HTMLAreaElement.alt')
   @DocsEditable()
@@ -540,7 +541,7 @@
 
   @DomName('HTMLBRElement.HTMLBRElement')
   @DocsEditable()
-  factory BRElement() => document.$dom_createElement("br");
+  factory BRElement() => document.createElement("br");
 }
 // 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
@@ -570,7 +571,7 @@
 
   @DomName('HTMLBaseElement.HTMLBaseElement')
   @DocsEditable()
-  factory BaseElement() => document.$dom_createElement("base");
+  factory BaseElement() => document.createElement("base");
 
   @DomName('HTMLBaseElement.href')
   @DocsEditable()
@@ -697,7 +698,7 @@
 
   @DomName('HTMLBodyElement.HTMLBodyElement')
   @DocsEditable()
-  factory BodyElement() => document.$dom_createElement("body");
+  factory BodyElement() => document.createElement("body");
 
   @DomName('HTMLBodyElement.onblur')
   @DocsEditable()
@@ -760,7 +761,7 @@
 
   @DomName('HTMLButtonElement.HTMLButtonElement')
   @DocsEditable()
-  factory ButtonElement() => document.$dom_createElement("button");
+  factory ButtonElement() => document.createElement("button");
 
   @DomName('HTMLButtonElement.autofocus')
   @DocsEditable()
@@ -882,7 +883,7 @@
   @DomName('HTMLCanvasElement.HTMLCanvasElement')
   @DocsEditable()
   factory CanvasElement({int width, int height}) {
-    var e = document.$dom_createElement("canvas");
+    var e = document.createElement("canvas");
     if (width != null) e.width = width;
     if (height != null) e.height = height;
     return e;
@@ -1975,7 +1976,7 @@
 
   @DomName('HTMLContentElement.HTMLContentElement')
   @DocsEditable()
-  factory ContentElement() => document.$dom_createElement("content");
+  factory ContentElement() => document.createElement("content");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('content');
@@ -6317,7 +6318,7 @@
 
   @DomName('HTMLDListElement.HTMLDListElement')
   @DocsEditable()
-  factory DListElement() => document.$dom_createElement("dl");
+  factory DListElement() => document.createElement("dl");
 }
 // 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
@@ -6336,7 +6337,7 @@
 
   @DomName('HTMLDataListElement.HTMLDataListElement')
   @DocsEditable()
-  factory DataListElement() => document.$dom_createElement("datalist");
+  factory DataListElement() => document.createElement("datalist");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('datalist');
@@ -6551,7 +6552,7 @@
 
   @DomName('HTMLDetailsElement.HTMLDetailsElement')
   @DocsEditable()
-  factory DetailsElement() => document.$dom_createElement("details");
+  factory DetailsElement() => document.createElement("details");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('details');
@@ -6914,10 +6915,11 @@
 
 @DocsEditable()
 /**
- * Represents an HTML <div> element.
+ * A generic container for content on an HTML page;
+ * corresponds to the &lt;div&gt; tag.
  *
- * The [DivElement] is a generic container for content and does not have any
- * special significance. It is functionally similar to [SpanElement].
+ * The [DivElement] is a generic container and does not have any semantic
+ * significance. It is functionally similar to [SpanElement].
  *
  * The [DivElement] is a block-level element, as opposed to [SpanElement],
  * which is an inline-level element.
@@ -6941,7 +6943,7 @@
 
   @DomName('HTMLDivElement.HTMLDivElement')
   @DocsEditable()
-  factory DivElement() => document.$dom_createElement("div");
+  factory DivElement() => document.createElement("div");
 }
 // 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
@@ -7169,16 +7171,14 @@
   @DocsEditable()
   DocumentFragment createDocumentFragment() native;
 
-  @JSName('createElement')
   /// Deprecated: use new Element.tag(tagName) instead.
   @DomName('Document.createElement')
   @DocsEditable()
-  Element $dom_createElement(String localName_OR_tagName, [String typeExtension]) native;
+  Element createElement(String localName_OR_tagName, [String typeExtension]) native;
 
-  @JSName('createElementNS')
   @DomName('Document.createElementNS')
   @DocsEditable()
-  Element $dom_createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) native;
+  Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) native;
 
   @JSName('createEvent')
   @DomName('Document.createEvent')
@@ -8819,8 +8819,8 @@
    *
    * * [isTagSupported]
    */
-  factory Element.tag(String tag) =>
-      _ElementFactoryProvider.createElement_tag(tag);
+  factory Element.tag(String tag, [String typeExtention]) =>
+      _ElementFactoryProvider.createElement_tag(tag, typeExtention);
 
   /// Creates a new `<a>` element.
   ///
@@ -9137,7 +9137,7 @@
    * The tag should be a valid HTML tag name.
    */
   static bool isTagSupported(String tag) {
-    var e = _ElementFactoryProvider.createElement_tag(tag);
+    var e = _ElementFactoryProvider.createElement_tag(tag, null);
     return e is Element && !(e is UnknownElement);
   }
 
@@ -9397,7 +9397,7 @@
   @SupportedBrowser(SupportedBrowser.CHROME, '25')
   @Experimental()
   ShadowRoot get shadowRoot =>
-      JS('ShadowRoot', '#.shadowRoot || #.webkitShadowRoot', this, this);
+      JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this);
 
 
   /**
@@ -9688,12 +9688,17 @@
     if (_parseDocument == null) {
       _parseDocument = document.implementation.createHtmlDocument('');
       _parseRange = _parseDocument.createRange();
+
+      // Workaround for Chrome bug 229142- URIs are not resolved in new doc.
+      var base = _parseDocument.createElement('base');
+      base.href = document._baseUri;
+      _parseDocument.head.append(base);
     }
     var contextElement;
     if (this is BodyElement) {
       contextElement = _parseDocument.body;
     } else {
-      contextElement = _parseDocument.$dom_createElement(tagName);
+      contextElement = _parseDocument.createElement(tagName);
       _parseDocument.body.append(contextElement);
     }
     var fragment;
@@ -10586,9 +10591,19 @@
   @DomName('Document.createElement')
   // Optimization to improve performance until the dart2js compiler inlines this
   // method.
-  static dynamic createElement_tag(String tag) =>
-      // Firefox may return a JS function for some types (Embed, Object).
-      JS('Element|=Object', 'document.createElement(#)', tag);
+  static dynamic createElement_tag(String tag, String typeExtension) {
+    // Firefox may return a JS function for some types (Embed, Object).
+    if (typeExtension != null) {
+      return JS('Element|=Object', 'document.createElement(#, #)',
+          tag, typeExtension);
+    }
+    // Should be able to eliminate this and just call the two-arg version above
+    // with null typeExtension, but Chrome treats the tag as case-sensitive if
+    // typeExtension is null.
+    // https://code.google.com/p/chromium/issues/detail?id=282467
+    return JS('Element|=Object', 'document.createElement(#)', tag);
+  }
+
 }
 
 
@@ -10624,7 +10639,7 @@
 
   @DomName('HTMLEmbedElement.HTMLEmbedElement')
   @DocsEditable()
-  factory EmbedElement() => document.$dom_createElement("embed");
+  factory EmbedElement() => document.createElement("embed");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('embed');
@@ -11263,7 +11278,7 @@
 
   @DomName('HTMLFieldSetElement.HTMLFieldSetElement')
   @DocsEditable()
-  factory FieldSetElement() => document.$dom_createElement("fieldset");
+  factory FieldSetElement() => document.createElement("fieldset");
 
   @DomName('HTMLFieldSetElement.disabled')
   @DocsEditable()
@@ -11957,7 +11972,7 @@
 
   @DomName('HTMLFormElement.HTMLFormElement')
   @DocsEditable()
-  factory FormElement() => document.$dom_createElement("form");
+  factory FormElement() => document.createElement("form");
 
   @DomName('HTMLFormElement.acceptCharset')
   @DocsEditable()
@@ -12217,7 +12232,7 @@
 
   @DomName('HTMLHRElement.HTMLHRElement')
   @DocsEditable()
-  factory HRElement() => document.$dom_createElement("hr");
+  factory HRElement() => document.createElement("hr");
 }
 // 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
@@ -12273,7 +12288,7 @@
 
   @DomName('HTMLHeadElement.HTMLHeadElement')
   @DocsEditable()
-  factory HeadElement() => document.$dom_createElement("head");
+  factory HeadElement() => document.createElement("head");
 }
 // 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
@@ -12288,27 +12303,27 @@
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h1() => document.$dom_createElement("h1");
+  factory HeadingElement.h1() => document.createElement("h1");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h2() => document.$dom_createElement("h2");
+  factory HeadingElement.h2() => document.createElement("h2");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h3() => document.$dom_createElement("h3");
+  factory HeadingElement.h3() => document.createElement("h3");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h4() => document.$dom_createElement("h4");
+  factory HeadingElement.h4() => document.createElement("h4");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h5() => document.$dom_createElement("h5");
+  factory HeadingElement.h5() => document.createElement("h5");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h6() => document.$dom_createElement("h6");
+  factory HeadingElement.h6() => document.createElement("h6");
 }
 // 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
@@ -12732,8 +12747,76 @@
       '#.webkitVisibilityState)', this, this, this, this);
 
   @Experimental
-  void register(String tag, Type customElementClass) {
-    _registerCustomElement(JS('', 'window'), this, tag, customElementClass);
+  /**
+   * Register a custom subclass of Element to be instantiatable by the DOM.
+   *
+   * This is necessary to allow the construction of any custom elements.
+   *
+   * The class being registered must either subclass HtmlElement or SvgElement.
+   * If they subclass these directly then they can be used as:
+   *
+   *     class FooElement extends HtmlElement{
+   *        void created() {
+   *          print('FooElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-foo', FooElement);
+   *       var myFoo = new Element.tag('x-foo');
+   *       // prints 'FooElement created!' to the console.
+   *     }
+   *
+   * The custom element can also be instantiated via HTML using the syntax
+   * `<x-foo></x-foo>`
+   *
+   * Other elements can be subclassed as well:
+   *
+   *     class BarElement extends InputElement{
+   *        void created() {
+   *          print('BarElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-bar', BarElement);
+   *       var myBar = new Element.tag('input', 'x-bar');
+   *       // prints 'BarElement created!' to the console.
+   *     }
+   *
+   * This custom element can also be instantiated via HTML using the syntax
+   * `<input is="x-bar"></input>`
+   *
+   * The [nativeTagName] parameter is needed by platforms without native support
+   * when subclassing a native type other than:
+   *
+   * * HtmlElement
+   * * SvgElement
+   * * AnchorElement
+   * * AudioElement
+   * * ButtonElement
+   * * CanvasElement
+   * * DivElement
+   * * ImageElement
+   * * InputElement
+   * * LIElement
+   * * LabelElement
+   * * MenuElement
+   * * MeterElement
+   * * OListElement
+   * * OptionElement
+   * * OutputElement
+   * * ParagraphElement
+   * * PreElement
+   * * ProgressElement
+   * * SelectElement
+   * * SpanElement
+   * * UListElement
+   * * VideoElement
+   */
+  void register(String tag, Type customElementClass, {String nativeTagName}) {
+    _registerCustomElement(JS('', 'window'), this, tag, customElementClass,
+        nativeTagName);
   }
 
   @Creates('Null')  // Set from Dart code; does not instantiate a native type.
@@ -12798,7 +12881,7 @@
 
   @DomName('HTMLHtmlElement.HTMLHtmlElement')
   @DocsEditable()
-  factory HtmlHtmlElement() => document.$dom_createElement("html");
+  factory HtmlHtmlElement() => document.createElement("html");
 }
 // 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
@@ -13394,7 +13477,7 @@
 
   @DomName('HTMLIFrameElement.HTMLIFrameElement')
   @DocsEditable()
-  factory IFrameElement() => document.$dom_createElement("iframe");
+  factory IFrameElement() => document.createElement("iframe");
 
   @DomName('HTMLIFrameElement.contentWindow')
   @DocsEditable()
@@ -13488,7 +13571,7 @@
   @DomName('HTMLImageElement.HTMLImageElement')
   @DocsEditable()
   factory ImageElement({String src, int width, int height}) {
-    var e = document.$dom_createElement("img");
+    var e = document.createElement("img");
     if (src != null) e.src = src;
     if (width != null) e.width = width;
     if (height != null) e.height = height;
@@ -13587,7 +13670,7 @@
      native "HTMLInputElement" {
 
   factory InputElement({String type}) {
-    var e = document.$dom_createElement("input");
+    var e = document.createElement("input");
     if (type != null) {
       try {
         // IE throws an exception for unknown types.
@@ -14627,7 +14710,7 @@
 
   @DomName('HTMLKeygenElement.HTMLKeygenElement')
   @DocsEditable()
-  factory KeygenElement() => document.$dom_createElement("keygen");
+  factory KeygenElement() => document.createElement("keygen");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('keygen') && (new Element.tag('keygen') is KeygenElement);
@@ -14700,7 +14783,7 @@
 
   @DomName('HTMLLIElement.HTMLLIElement')
   @DocsEditable()
-  factory LIElement() => document.$dom_createElement("li");
+  factory LIElement() => document.createElement("li");
 
   @DomName('HTMLLIElement.type')
   @DocsEditable()
@@ -14725,7 +14808,7 @@
 
   @DomName('HTMLLabelElement.HTMLLabelElement')
   @DocsEditable()
-  factory LabelElement() => document.$dom_createElement("label");
+  factory LabelElement() => document.createElement("label");
 
   @DomName('HTMLLabelElement.control')
   @DocsEditable()
@@ -14752,7 +14835,7 @@
 
   @DomName('HTMLLegendElement.HTMLLegendElement')
   @DocsEditable()
-  factory LegendElement() => document.$dom_createElement("legend");
+  factory LegendElement() => document.createElement("legend");
 
   @DomName('HTMLLegendElement.form')
   @DocsEditable()
@@ -14771,7 +14854,7 @@
 
   @DomName('HTMLLinkElement.HTMLLinkElement')
   @DocsEditable()
-  factory LinkElement() => document.$dom_createElement("link");
+  factory LinkElement() => document.createElement("link");
 
   @DomName('HTMLLinkElement.disabled')
   @DocsEditable()
@@ -14918,7 +15001,7 @@
 
   @DomName('HTMLMapElement.HTMLMapElement')
   @DocsEditable()
-  factory MapElement() => document.$dom_createElement("map");
+  factory MapElement() => document.createElement("map");
 
   @DomName('HTMLMapElement.areas')
   @DocsEditable()
@@ -16135,7 +16218,7 @@
 
   @DomName('HTMLMenuElement.HTMLMenuElement')
   @DocsEditable()
-  factory MenuElement() => document.$dom_createElement("menu");
+  factory MenuElement() => document.createElement("menu");
 }
 // 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
@@ -16282,7 +16365,7 @@
 
   @DomName('HTMLMetaElement.HTMLMetaElement')
   @DocsEditable()
-  factory MetaElement() => document.$dom_createElement("meta");
+  factory MetaElement() => document.createElement("meta");
 
   @DomName('HTMLMetaElement.content')
   @DocsEditable()
@@ -16348,7 +16431,7 @@
 
   @DomName('HTMLMeterElement.HTMLMeterElement')
   @DocsEditable()
-  factory MeterElement() => document.$dom_createElement("meter");
+  factory MeterElement() => document.createElement("meter");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('meter');
@@ -17785,6 +17868,11 @@
   @DocsEditable()
   static const int TEXT_NODE = 3;
 
+  @JSName('baseURI')
+  @DomName('Node.baseURI')
+  @DocsEditable()
+  final String _baseUri;
+
   @DomName('Node.childNodes')
   @DocsEditable()
   @deprecated
@@ -18291,7 +18379,7 @@
 
   @DomName('HTMLOListElement.HTMLOListElement')
   @DocsEditable()
-  factory OListElement() => document.$dom_createElement("ol");
+  factory OListElement() => document.createElement("ol");
 
   @DomName('HTMLOListElement.reversed')
   @DocsEditable()
@@ -18322,7 +18410,7 @@
 
   @DomName('HTMLObjectElement.HTMLObjectElement')
   @DocsEditable()
-  factory ObjectElement() => document.$dom_createElement("object");
+  factory ObjectElement() => document.createElement("object");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('object');
@@ -18402,7 +18490,7 @@
 
   @DomName('HTMLOptGroupElement.HTMLOptGroupElement')
   @DocsEditable()
-  factory OptGroupElement() => document.$dom_createElement("optgroup");
+  factory OptGroupElement() => document.createElement("optgroup");
 
   @DomName('HTMLOptGroupElement.disabled')
   @DocsEditable()
@@ -18490,7 +18578,7 @@
 
   @DomName('HTMLOutputElement.HTMLOutputElement')
   @DocsEditable()
-  factory OutputElement() => document.$dom_createElement("output");
+  factory OutputElement() => document.createElement("output");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('output');
@@ -18612,7 +18700,7 @@
 
   @DomName('HTMLParagraphElement.HTMLParagraphElement')
   @DocsEditable()
-  factory ParagraphElement() => document.$dom_createElement("p");
+  factory ParagraphElement() => document.createElement("p");
 }
 // 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
@@ -18628,7 +18716,7 @@
 
   @DomName('HTMLParamElement.HTMLParamElement')
   @DocsEditable()
-  factory ParamElement() => document.$dom_createElement("param");
+  factory ParamElement() => document.createElement("param");
 
   @DomName('HTMLParamElement.name')
   @DocsEditable()
@@ -19270,7 +19358,7 @@
 
   @DomName('HTMLPreElement.HTMLPreElement')
   @DocsEditable()
-  factory PreElement() => document.$dom_createElement("pre");
+  factory PreElement() => document.createElement("pre");
 
   @DomName('HTMLPreElement.wrap')
   @DocsEditable()
@@ -19315,7 +19403,7 @@
 
   @DomName('HTMLProgressElement.HTMLProgressElement')
   @DocsEditable()
-  factory ProgressElement() => document.$dom_createElement("progress");
+  factory ProgressElement() => document.createElement("progress");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('progress');
@@ -19440,7 +19528,7 @@
 
   @DomName('HTMLQuoteElement.HTMLQuoteElement')
   @DocsEditable()
-  factory QuoteElement() => document.$dom_createElement("q");
+  factory QuoteElement() => document.createElement("q");
 
   @DomName('HTMLQuoteElement.cite')
   @DocsEditable()
@@ -20462,7 +20550,7 @@
 
   @DomName('HTMLScriptElement.HTMLScriptElement')
   @DocsEditable()
-  factory ScriptElement() => document.$dom_createElement("script");
+  factory ScriptElement() => document.createElement("script");
 
   @DomName('HTMLScriptElement.async')
   @DocsEditable()
@@ -20649,7 +20737,7 @@
 
   @DomName('HTMLSelectElement.HTMLSelectElement')
   @DocsEditable()
-  factory SelectElement() => document.$dom_createElement("select");
+  factory SelectElement() => document.createElement("select");
 
   @DomName('HTMLSelectElement.autofocus')
   @DocsEditable()
@@ -20892,7 +20980,7 @@
 
   @DomName('HTMLShadowElement.HTMLShadowElement')
   @DocsEditable()
-  factory ShadowElement() => document.$dom_createElement("shadow");
+  factory ShadowElement() => document.createElement("shadow");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('shadow');
@@ -21135,7 +21223,7 @@
 
   @DomName('HTMLSourceElement.HTMLSourceElement')
   @DocsEditable()
-  factory SourceElement() => document.$dom_createElement("source");
+  factory SourceElement() => document.createElement("source");
 
   @DomName('HTMLSourceElement.media')
   @DocsEditable()
@@ -21192,7 +21280,7 @@
 
   @DomName('HTMLSpanElement.HTMLSpanElement')
   @DocsEditable()
-  factory SpanElement() => document.$dom_createElement("span");
+  factory SpanElement() => document.createElement("span");
 }
 // 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
@@ -22091,7 +22179,7 @@
 
   @DomName('HTMLStyleElement.HTMLStyleElement')
   @DocsEditable()
-  factory StyleElement() => document.$dom_createElement("style");
+  factory StyleElement() => document.createElement("style");
 
   @DomName('HTMLStyleElement.disabled')
   @DocsEditable()
@@ -22182,7 +22270,7 @@
 
   @DomName('HTMLTableCaptionElement.HTMLTableCaptionElement')
   @DocsEditable()
-  factory TableCaptionElement() => document.$dom_createElement("caption");
+  factory TableCaptionElement() => document.createElement("caption");
 }
 // 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
@@ -22197,7 +22285,7 @@
 
   @DomName('HTMLTableCellElement.HTMLTableCellElement')
   @DocsEditable()
-  factory TableCellElement() => document.$dom_createElement("td");
+  factory TableCellElement() => document.createElement("td");
 
   @DomName('HTMLTableCellElement.cellIndex')
   @DocsEditable()
@@ -22228,7 +22316,7 @@
 
   @DomName('HTMLTableColElement.HTMLTableColElement')
   @DocsEditable()
-  factory TableColElement() => document.$dom_createElement("col");
+  factory TableColElement() => document.createElement("col");
 
   @DomName('HTMLTableColElement.span')
   @DocsEditable()
@@ -22294,7 +22382,7 @@
 
   @DomName('HTMLTableElement.HTMLTableElement')
   @DocsEditable()
-  factory TableElement() => document.$dom_createElement("table");
+  factory TableElement() => document.createElement("table");
 
   @DomName('HTMLTableElement.border')
   @DocsEditable()
@@ -22399,7 +22487,7 @@
 
   @DomName('HTMLTableRowElement.HTMLTableRowElement')
   @DocsEditable()
-  factory TableRowElement() => document.$dom_createElement("tr");
+  factory TableRowElement() => document.createElement("tr");
 
   @JSName('cells')
   @DomName('HTMLTableRowElement.cells')
@@ -22573,7 +22661,7 @@
 
   @DomName('HTMLTemplateElement.HTMLTemplateElement')
   @DocsEditable()
-  factory TemplateElement() => document.$dom_createElement("template");
+  factory TemplateElement() => document.createElement("template");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('template');
@@ -22693,7 +22781,7 @@
   //       + <td>Bar</td>
   //
   static Element _extractTemplateFromAttributeTemplate(Element el) {
-    var template = el.document.$dom_createElement('template');
+    var template = el.document.createElement('template');
     el.parentNode.insertBefore(template, el);
 
     for (var name in el.attributes.keys.toList()) {
@@ -22846,7 +22934,7 @@
 
   @DomName('HTMLTextAreaElement.HTMLTextAreaElement')
   @DocsEditable()
-  factory TextAreaElement() => document.$dom_createElement("textarea");
+  factory TextAreaElement() => document.createElement("textarea");
 
   @DomName('HTMLTextAreaElement.autofocus')
   @DocsEditable()
@@ -23351,7 +23439,7 @@
 
   @DomName('HTMLTitleElement.HTMLTitleElement')
   @DocsEditable()
-  factory TitleElement() => document.$dom_createElement("title");
+  factory TitleElement() => document.createElement("title");
 }
 // 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
@@ -23617,7 +23705,7 @@
 
   @DomName('HTMLTrackElement.HTMLTrackElement')
   @DocsEditable()
-  factory TrackElement() => document.$dom_createElement("track");
+  factory TrackElement() => document.createElement("track");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => Element.isTagSupported('track');
@@ -23894,7 +23982,7 @@
 
   @DomName('HTMLUListElement.HTMLUListElement')
   @DocsEditable()
-  factory UListElement() => document.$dom_createElement("ul");
+  factory UListElement() => document.createElement("ul");
 }
 // 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
@@ -24000,7 +24088,7 @@
 
   @DomName('HTMLVideoElement.HTMLVideoElement')
   @DocsEditable()
-  factory VideoElement() => document.$dom_createElement("video");
+  factory VideoElement() => document.createElement("video");
 
   @DomName('HTMLVideoElement.height')
   @DocsEditable()
@@ -31959,7 +32047,32 @@
       convertDartClosureToJS(_callCreated, 1));
 }
 
-void _registerCustomElement(context, document, String tag, Type type) {
+const _typeNameToTag = const {
+  'HTMLAnchorElement': 'a',
+  'HTMLAudioElement': 'audio',
+  'HTMLButtonElement': 'button',
+  'HTMLCanvasElement': 'canvas',
+  'HTMLDivElement': 'div',
+  'HTMLImageElement': 'img',
+  'HTMLInputElement': 'input',
+  'HTMLLIElement': 'li',
+  'HTMLLabelElement': 'label',
+  'HTMLMenuElement': 'menu',
+  'HTMLMeterElement': 'meter',
+  'HTMLOListElement': 'ol',
+  'HTMLOptionElement': 'option',
+  'HTMLOutputElement': 'output',
+  'HTMLParagraphElement': 'p',
+  'HTMLPreElement': 'pre',
+  'HTMLProgressElement': 'progress',
+  'HTMLSelectElement': 'select',
+  'HTMLSpanElement': 'span',
+  'HTMLUListElement': 'ul',
+  'HTMLVideoElement': 'video',
+};
+
+void _registerCustomElement(context, document, String tag, Type type,
+    String extendsTagName) {
   // Function follows the same pattern as the following JavaScript code for
   // registering a custom element.
   //
@@ -31979,6 +32092,10 @@
     throw new ArgumentError(type);
   }
 
+  // Workaround for 13190- use an article element to ensure that HTMLElement's
+  // interceptor is resolved correctly.
+  getNativeInterceptor(new Element.tag('article'));
+
   String baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
   if (baseClassName == null) {
     throw new ArgumentError(type);
@@ -32001,8 +32118,17 @@
 
   setNativeSubclassDispatchRecord(proto, interceptor);
 
-  JS('void', '#.register(#, #)',
-      document, tag, JS('', '{prototype: #}', proto));
+  var options = JS('=Object', '{prototype: #}', proto);
+
+  if (baseClassName != 'HTMLElement') {
+    if (extendsTagName != null) {
+      JS('=Object', '#.extends = #', options, extendsTagName);
+    } else if (_typeNameToTag.containsKey(baseClassName)) {
+      JS('=Object', '#.extends = #', options, _typeNameToTag[baseClassName]);
+    }
+  }
+
+  JS('void', '#.register(#, #)', document, tag, options);
 }
 // 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
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 3bce62d..4682b6c 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -204,7 +204,7 @@
   @DomName('HTMLAnchorElement.HTMLAnchorElement')
   @DocsEditable()
   factory AnchorElement({String href}) {
-    var e = document.$dom_createElement("a");
+    var e = document.createElement("a");
     if (href != null) e.href = href;
     return e;
   }
@@ -537,7 +537,7 @@
 
   @DomName('HTMLAreaElement.HTMLAreaElement')
   @DocsEditable()
-  factory AreaElement() => document.$dom_createElement("area");
+  factory AreaElement() => document.createElement("area");
 
   @DomName('HTMLAreaElement.alt')
   @DocsEditable()
@@ -678,7 +678,7 @@
 
   @DomName('HTMLBRElement.HTMLBRElement')
   @DocsEditable()
-  factory BRElement() => document.$dom_createElement("br");
+  factory BRElement() => document.createElement("br");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -714,7 +714,7 @@
 
   @DomName('HTMLBaseElement.HTMLBaseElement')
   @DocsEditable()
-  factory BaseElement() => document.$dom_createElement("base");
+  factory BaseElement() => document.createElement("base");
 
   @DomName('HTMLBaseElement.href')
   @DocsEditable()
@@ -861,7 +861,7 @@
 
   @DomName('HTMLBodyElement.HTMLBodyElement')
   @DocsEditable()
-  factory BodyElement() => document.$dom_createElement("body");
+  factory BodyElement() => document.createElement("body");
 
   @DomName('HTMLBodyElement.onblur')
   @DocsEditable()
@@ -927,7 +927,7 @@
 
   @DomName('HTMLButtonElement.HTMLButtonElement')
   @DocsEditable()
-  factory ButtonElement() => document.$dom_createElement("button");
+  factory ButtonElement() => document.createElement("button");
 
   @DomName('HTMLButtonElement.autofocus')
   @DocsEditable()
@@ -1098,7 +1098,7 @@
   @DomName('HTMLCanvasElement.HTMLCanvasElement')
   @DocsEditable()
   factory CanvasElement({int width, int height}) {
-    var e = document.$dom_createElement("canvas");
+    var e = document.createElement("canvas");
     if (width != null) e.width = width;
     if (height != null) e.height = height;
     return e;
@@ -2369,7 +2369,7 @@
 
   @DomName('HTMLContentElement.HTMLContentElement')
   @DocsEditable()
-  factory ContentElement() => document.$dom_createElement("content");
+  factory ContentElement() => document.createElement("content");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -6884,7 +6884,7 @@
 
   @DomName('HTMLDListElement.HTMLDListElement')
   @DocsEditable()
-  factory DListElement() => document.$dom_createElement("dl");
+  factory DListElement() => document.createElement("dl");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -6906,7 +6906,7 @@
 
   @DomName('HTMLDataListElement.HTMLDataListElement')
   @DocsEditable()
-  factory DataListElement() => document.$dom_createElement("datalist");
+  factory DataListElement() => document.createElement("datalist");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -7145,7 +7145,7 @@
 
   @DomName('HTMLDetailsElement.HTMLDetailsElement')
   @DocsEditable()
-  factory DetailsElement() => document.$dom_createElement("details");
+  factory DetailsElement() => document.createElement("details");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -7456,10 +7456,11 @@
 
 @DocsEditable()
 /**
- * Represents an HTML <div> element.
+ * A generic container for content on an HTML page;
+ * corresponds to the &lt;div&gt; tag.
  *
- * The [DivElement] is a generic container for content and does not have any
- * special significance. It is functionally similar to [SpanElement].
+ * The [DivElement] is a generic container and does not have any semantic
+ * significance. It is functionally similar to [SpanElement].
  *
  * The [DivElement] is a block-level element, as opposed to [SpanElement],
  * which is an inline-level element.
@@ -7483,7 +7484,7 @@
 
   @DomName('HTMLDivElement.HTMLDivElement')
   @DocsEditable()
-  factory DivElement() => document.$dom_createElement("div");
+  factory DivElement() => document.createElement("div");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -7705,7 +7706,7 @@
   @DocsEditable()
   DocumentFragment createDocumentFragment() native "Document_createDocumentFragment_Callback";
 
-  Element $dom_createElement(String localName_OR_tagName, [String typeExtension]) {
+  Element createElement(String localName_OR_tagName, [String typeExtension]) {
     if ((localName_OR_tagName is String || localName_OR_tagName == null) && typeExtension == null) {
       return _createElement_1(localName_OR_tagName);
     }
@@ -7719,7 +7720,7 @@
 
   Element _createElement_2(localName_OR_tagName, typeExtension) native "Document__createElement_2_Callback";
 
-  Element $dom_createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
+  Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
     if ((qualifiedName is String || qualifiedName == null) && (namespaceURI is String || namespaceURI == null) && typeExtension == null) {
       return _createElementNS_1(namespaceURI, qualifiedName);
     }
@@ -8491,7 +8492,7 @@
 
   String get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -8499,7 +8500,7 @@
   String get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -8507,7 +8508,7 @@
   String get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -9398,8 +9399,8 @@
    *
    * * [isTagSupported]
    */
-  factory Element.tag(String tag) =>
-      _ElementFactoryProvider.createElement_tag(tag);
+  factory Element.tag(String tag, [String typeExtention]) =>
+      _ElementFactoryProvider.createElement_tag(tag, typeExtention);
 
   /// Creates a new `<a>` element.
   ///
@@ -9716,7 +9717,7 @@
    * The tag should be a valid HTML tag name.
    */
   static bool isTagSupported(String tag) {
-    var e = _ElementFactoryProvider.createElement_tag(tag);
+    var e = _ElementFactoryProvider.createElement_tag(tag, null);
     return e is Element && !(e is UnknownElement);
   }
 
@@ -10103,12 +10104,17 @@
     if (_parseDocument == null) {
       _parseDocument = document.implementation.createHtmlDocument('');
       _parseRange = _parseDocument.createRange();
+
+      // Workaround for Chrome bug 229142- URIs are not resolved in new doc.
+      var base = _parseDocument.createElement('base');
+      base.href = document._baseUri;
+      _parseDocument.head.append(base);
     }
     var contextElement;
     if (this is BodyElement) {
       contextElement = _parseDocument.body;
     } else {
-      contextElement = _parseDocument.$dom_createElement(tagName);
+      contextElement = _parseDocument.createElement(tagName);
       _parseDocument.body.append(contextElement);
     }
     var fragment;
@@ -11004,8 +11010,8 @@
 class _ElementFactoryProvider {
 
   @DomName('Document.createElement')
-  static Element createElement_tag(String tag) =>
-      document.$dom_createElement(tag);
+  static Element createElement_tag(String tag, String typeExtension) =>
+      document.createElement(tag, typeExtension);
 }
 
 
@@ -11043,7 +11049,7 @@
 
   @DomName('HTMLEmbedElement.HTMLEmbedElement')
   @DocsEditable()
-  factory EmbedElement() => document.$dom_createElement("embed");
+  factory EmbedElement() => document.createElement("embed");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -11712,7 +11718,7 @@
 
   @DomName('HTMLFieldSetElement.HTMLFieldSetElement')
   @DocsEditable()
-  factory FieldSetElement() => document.$dom_createElement("fieldset");
+  factory FieldSetElement() => document.createElement("fieldset");
 
   @DomName('HTMLFieldSetElement.disabled')
   @DocsEditable()
@@ -11947,7 +11953,7 @@
 
   File get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -11955,7 +11961,7 @@
   File get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -11963,7 +11969,7 @@
   File get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -12464,7 +12470,7 @@
 
   @DomName('HTMLFormElement.HTMLFormElement')
   @DocsEditable()
-  factory FormElement() => document.$dom_createElement("form");
+  factory FormElement() => document.createElement("form");
 
   @DomName('HTMLFormElement.acceptCharset')
   @DocsEditable()
@@ -12750,7 +12756,7 @@
 
   @DomName('HTMLHRElement.HTMLHRElement')
   @DocsEditable()
-  factory HRElement() => document.$dom_createElement("hr");
+  factory HRElement() => document.createElement("hr");
 
 }
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
@@ -12806,7 +12812,7 @@
 
   @DomName('HTMLHeadElement.HTMLHeadElement')
   @DocsEditable()
-  factory HeadElement() => document.$dom_createElement("head");
+  factory HeadElement() => document.createElement("head");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -12824,27 +12830,27 @@
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h1() => document.$dom_createElement("h1");
+  factory HeadingElement.h1() => document.createElement("h1");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h2() => document.$dom_createElement("h2");
+  factory HeadingElement.h2() => document.createElement("h2");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h3() => document.$dom_createElement("h3");
+  factory HeadingElement.h3() => document.createElement("h3");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h4() => document.$dom_createElement("h4");
+  factory HeadingElement.h4() => document.createElement("h4");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h5() => document.$dom_createElement("h5");
+  factory HeadingElement.h5() => document.createElement("h5");
 
   @DomName('HTMLHeadingElement.HTMLHeadingElement')
   @DocsEditable()
-  factory HeadingElement.h6() => document.$dom_createElement("h6");
+  factory HeadingElement.h6() => document.createElement("h6");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -12984,7 +12990,7 @@
 
   Node get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -12992,7 +12998,7 @@
   Node get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -13000,7 +13006,7 @@
   Node get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -13061,7 +13067,7 @@
 
   Node get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -13069,7 +13075,7 @@
   Node get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -13077,7 +13083,7 @@
   Node get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -13277,8 +13283,75 @@
   String get visibilityState => _webkitVisibilityState;
 
   @Experimental
-  void register(String tag, Type custom) {
-    _Utils.register(tag, custom);
+  /**
+   * Register a custom subclass of Element to be instantiatable by the DOM.
+   *
+   * This is necessary to allow the construction of any custom elements.
+   *
+   * The class being registered must either subclass HtmlElement or SvgElement.
+   * If they subclass these directly then they can be used as:
+   *
+   *     class FooElement extends HtmlElement{
+   *        void created() {
+   *          print('FooElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-foo', FooElement);
+   *       var myFoo = new Element.tag('x-foo');
+   *       // prints 'FooElement created!' to the console.
+   *     }
+   *
+   * The custom element can also be instantiated via HTML using the syntax
+   * `<x-foo></x-foo>`
+   *
+   * Other elements can be subclassed as well:
+   *
+   *     class BarElement extends InputElement{
+   *        void created() {
+   *          print('BarElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-bar', BarElement);
+   *       var myBar = new Element.tag('input', 'x-bar');
+   *       // prints 'BarElement created!' to the console.
+   *     }
+   *
+   * This custom element can also be instantiated via HTML using the syntax
+   * `<input is="x-bar"></input>`
+   *
+   * The [nativeTagName] parameter is needed by platforms without native support
+   * when subclassing a native type other than:
+   *
+   * * HtmlElement
+   * * SvgElement
+   * * AnchorElement
+   * * AudioElement
+   * * ButtonElement
+   * * CanvasElement
+   * * DivElement
+   * * ImageElement
+   * * InputElement
+   * * LIElement
+   * * LabelElement
+   * * MenuElement
+   * * MeterElement
+   * * OListElement
+   * * OptionElement
+   * * OutputElement
+   * * ParagraphElement
+   * * PreElement
+   * * ProgressElement
+   * * SelectElement
+   * * SpanElement
+   * * UListElement
+   * * VideoElement
+   */
+  void register(String tag, Type customElementClass, {String nativeTagName}) {
+    _Utils.register(tag, customElementClass);
   }
 
   // Note: used to polyfill <template>
@@ -13486,7 +13559,7 @@
 
   @DomName('HTMLHtmlElement.HTMLHtmlElement')
   @DocsEditable()
-  factory HtmlHtmlElement() => document.$dom_createElement("html");
+  factory HtmlHtmlElement() => document.createElement("html");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -14074,7 +14147,7 @@
 
   @DomName('HTMLIFrameElement.HTMLIFrameElement')
   @DocsEditable()
-  factory IFrameElement() => document.$dom_createElement("iframe");
+  factory IFrameElement() => document.createElement("iframe");
 
   @DomName('HTMLIFrameElement.contentWindow')
   @DocsEditable()
@@ -14202,7 +14275,7 @@
   @DomName('HTMLImageElement.HTMLImageElement')
   @DocsEditable()
   factory ImageElement({String src, int width, int height}) {
-    var e = document.$dom_createElement("img");
+    var e = document.createElement("img");
     if (src != null) e.src = src;
     if (width != null) e.width = width;
     if (height != null) e.height = height;
@@ -14339,7 +14412,7 @@
      {
 
   factory InputElement({String type}) {
-    var e = document.$dom_createElement("input");
+    var e = document.createElement("input");
     if (type != null) {
       try {
         // IE throws an exception for unknown types.
@@ -15554,7 +15627,7 @@
 
   @DomName('HTMLKeygenElement.HTMLKeygenElement')
   @DocsEditable()
-  factory KeygenElement() => document.$dom_createElement("keygen");
+  factory KeygenElement() => document.createElement("keygen");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -15648,7 +15721,7 @@
 
   @DomName('HTMLLIElement.HTMLLIElement')
   @DocsEditable()
-  factory LIElement() => document.$dom_createElement("li");
+  factory LIElement() => document.createElement("li");
 
   @DomName('HTMLLIElement.type')
   @DocsEditable()
@@ -15686,7 +15759,7 @@
 
   @DomName('HTMLLabelElement.HTMLLabelElement')
   @DocsEditable()
-  factory LabelElement() => document.$dom_createElement("label");
+  factory LabelElement() => document.createElement("label");
 
   @DomName('HTMLLabelElement.control')
   @DocsEditable()
@@ -15720,7 +15793,7 @@
 
   @DomName('HTMLLegendElement.HTMLLegendElement')
   @DocsEditable()
-  factory LegendElement() => document.$dom_createElement("legend");
+  factory LegendElement() => document.createElement("legend");
 
   @DomName('HTMLLegendElement.form')
   @DocsEditable()
@@ -15742,7 +15815,7 @@
 
   @DomName('HTMLLinkElement.HTMLLinkElement')
   @DocsEditable()
-  factory LinkElement() => document.$dom_createElement("link");
+  factory LinkElement() => document.createElement("link");
 
   @DomName('HTMLLinkElement.disabled')
   @DocsEditable()
@@ -15949,7 +16022,7 @@
 
   @DomName('HTMLMapElement.HTMLMapElement')
   @DocsEditable()
-  factory MapElement() => document.$dom_createElement("map");
+  factory MapElement() => document.createElement("map");
 
   @DomName('HTMLMapElement.areas')
   @DocsEditable()
@@ -17408,7 +17481,7 @@
 
   @DomName('HTMLMenuElement.HTMLMenuElement')
   @DocsEditable()
-  factory MenuElement() => document.$dom_createElement("menu");
+  factory MenuElement() => document.createElement("menu");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -17545,7 +17618,7 @@
 
   @DomName('HTMLMetaElement.HTMLMetaElement')
   @DocsEditable()
-  factory MetaElement() => document.$dom_createElement("meta");
+  factory MetaElement() => document.createElement("meta");
 
   @DomName('HTMLMetaElement.content')
   @DocsEditable()
@@ -17624,7 +17697,7 @@
 
   @DomName('HTMLMeterElement.HTMLMeterElement')
   @DocsEditable()
-  factory MeterElement() => document.$dom_createElement("meter");
+  factory MeterElement() => document.createElement("meter");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -17971,7 +18044,7 @@
 
   MimeType get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -17979,7 +18052,7 @@
   MimeType get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -17987,7 +18060,7 @@
   MimeType get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -19126,6 +19199,10 @@
   @DocsEditable()
   static const int TEXT_NODE = 3;
 
+  @DomName('Node.baseURI')
+  @DocsEditable()
+  String get _baseUri native "Node_baseURI_Getter";
+
   @DomName('Node.childNodes')
   @DocsEditable()
   @deprecated
@@ -19399,7 +19476,7 @@
 
   Node get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -19407,7 +19484,7 @@
   Node get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -19415,7 +19492,7 @@
   Node get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -19666,7 +19743,7 @@
 
   @DomName('HTMLOListElement.HTMLOListElement')
   @DocsEditable()
-  factory OListElement() => document.$dom_createElement("ol");
+  factory OListElement() => document.createElement("ol");
 
   @DomName('HTMLOListElement.reversed')
   @DocsEditable()
@@ -19712,7 +19789,7 @@
 
   @DomName('HTMLObjectElement.HTMLObjectElement')
   @DocsEditable()
-  factory ObjectElement() => document.$dom_createElement("object");
+  factory ObjectElement() => document.createElement("object");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -19825,7 +19902,7 @@
 
   @DomName('HTMLOptGroupElement.HTMLOptGroupElement')
   @DocsEditable()
-  factory OptGroupElement() => document.$dom_createElement("optgroup");
+  factory OptGroupElement() => document.createElement("optgroup");
 
   @DomName('HTMLOptGroupElement.disabled')
   @DocsEditable()
@@ -19933,7 +20010,7 @@
 
   @DomName('HTMLOutputElement.HTMLOutputElement')
   @DocsEditable()
-  factory OutputElement() => document.$dom_createElement("output");
+  factory OutputElement() => document.createElement("output");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -20074,7 +20151,7 @@
 
   @DomName('HTMLParagraphElement.HTMLParagraphElement')
   @DocsEditable()
-  factory ParagraphElement() => document.$dom_createElement("p");
+  factory ParagraphElement() => document.createElement("p");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -20093,7 +20170,7 @@
 
   @DomName('HTMLParamElement.HTMLParamElement')
   @DocsEditable()
-  factory ParamElement() => document.$dom_createElement("param");
+  factory ParamElement() => document.createElement("param");
 
   @DomName('HTMLParamElement.name')
   @DocsEditable()
@@ -20679,7 +20756,7 @@
 
   Plugin get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -20687,7 +20764,7 @@
   Plugin get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -20695,7 +20772,7 @@
   Plugin get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -20811,7 +20888,7 @@
 
   @DomName('HTMLPreElement.HTMLPreElement')
   @DocsEditable()
-  factory PreElement() => document.$dom_createElement("pre");
+  factory PreElement() => document.createElement("pre");
 
   @DomName('HTMLPreElement.wrap')
   @DocsEditable()
@@ -20867,7 +20944,7 @@
 
   @DomName('HTMLProgressElement.HTMLProgressElement')
   @DocsEditable()
-  factory ProgressElement() => document.$dom_createElement("progress");
+  factory ProgressElement() => document.createElement("progress");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -21010,7 +21087,7 @@
 
   @DomName('HTMLQuoteElement.HTMLQuoteElement')
   @DocsEditable()
-  factory QuoteElement() => document.$dom_createElement("q");
+  factory QuoteElement() => document.createElement("q");
 
   @DomName('HTMLQuoteElement.cite')
   @DocsEditable()
@@ -22030,7 +22107,7 @@
 
   @DomName('HTMLScriptElement.HTMLScriptElement')
   @DocsEditable()
-  factory ScriptElement() => document.$dom_createElement("script");
+  factory ScriptElement() => document.createElement("script");
 
   @DomName('HTMLScriptElement.async')
   @DocsEditable()
@@ -22264,7 +22341,7 @@
 
   @DomName('HTMLSelectElement.HTMLSelectElement')
   @DocsEditable()
-  factory SelectElement() => document.$dom_createElement("select");
+  factory SelectElement() => document.createElement("select");
 
   @DomName('HTMLSelectElement.autofocus')
   @DocsEditable()
@@ -22546,7 +22623,7 @@
 
   @DomName('HTMLShadowElement.HTMLShadowElement')
   @DocsEditable()
-  factory ShadowElement() => document.$dom_createElement("shadow");
+  factory ShadowElement() => document.createElement("shadow");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -22794,7 +22871,7 @@
 
   SourceBuffer get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -22802,7 +22879,7 @@
   SourceBuffer get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -22810,7 +22887,7 @@
   SourceBuffer get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -22851,7 +22928,7 @@
 
   @DomName('HTMLSourceElement.HTMLSourceElement')
   @DocsEditable()
-  factory SourceElement() => document.$dom_createElement("source");
+  factory SourceElement() => document.createElement("source");
 
   @DomName('HTMLSourceElement.media')
   @DocsEditable()
@@ -22926,7 +23003,7 @@
 
   @DomName('HTMLSpanElement.HTMLSpanElement')
   @DocsEditable()
-  factory SpanElement() => document.$dom_createElement("span");
+  factory SpanElement() => document.createElement("span");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -23014,7 +23091,7 @@
 
   SpeechGrammar get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -23022,7 +23099,7 @@
   SpeechGrammar get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -23030,7 +23107,7 @@
   SpeechGrammar get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -23989,7 +24066,7 @@
 
   @DomName('HTMLStyleElement.HTMLStyleElement')
   @DocsEditable()
-  factory StyleElement() => document.$dom_createElement("style");
+  factory StyleElement() => document.createElement("style");
 
   @DomName('HTMLStyleElement.disabled')
   @DocsEditable()
@@ -24109,7 +24186,7 @@
 
   @DomName('HTMLTableCaptionElement.HTMLTableCaptionElement')
   @DocsEditable()
-  factory TableCaptionElement() => document.$dom_createElement("caption");
+  factory TableCaptionElement() => document.createElement("caption");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -24127,7 +24204,7 @@
 
   @DomName('HTMLTableCellElement.HTMLTableCellElement')
   @DocsEditable()
-  factory TableCellElement() => document.$dom_createElement("td");
+  factory TableCellElement() => document.createElement("td");
 
   @DomName('HTMLTableCellElement.cellIndex')
   @DocsEditable()
@@ -24173,7 +24250,7 @@
 
   @DomName('HTMLTableColElement.HTMLTableColElement')
   @DocsEditable()
-  factory TableColElement() => document.$dom_createElement("col");
+  factory TableColElement() => document.createElement("col");
 
   @DomName('HTMLTableColElement.span')
   @DocsEditable()
@@ -24217,7 +24294,7 @@
 
   @DomName('HTMLTableElement.HTMLTableElement')
   @DocsEditable()
-  factory TableElement() => document.$dom_createElement("table");
+  factory TableElement() => document.createElement("table");
 
   @DomName('HTMLTableElement.border')
   @DocsEditable()
@@ -24324,7 +24401,7 @@
 
   @DomName('HTMLTableRowElement.HTMLTableRowElement')
   @DocsEditable()
-  factory TableRowElement() => document.$dom_createElement("tr");
+  factory TableRowElement() => document.createElement("tr");
 
   @DomName('HTMLTableRowElement.cells')
   @DocsEditable()
@@ -24481,7 +24558,7 @@
 
   @DomName('HTMLTemplateElement.HTMLTemplateElement')
   @DocsEditable()
-  factory TemplateElement() => document.$dom_createElement("template");
+  factory TemplateElement() => document.createElement("template");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -24600,7 +24677,7 @@
   //       + <td>Bar</td>
   //
   static Element _extractTemplateFromAttributeTemplate(Element el) {
-    var template = el.document.$dom_createElement('template');
+    var template = el.document.createElement('template');
     el.parentNode.insertBefore(template, el);
 
     for (var name in el.attributes.keys.toList()) {
@@ -24753,7 +24830,7 @@
 
   @DomName('HTMLTextAreaElement.HTMLTextAreaElement')
   @DocsEditable()
-  factory TextAreaElement() => document.$dom_createElement("textarea");
+  factory TextAreaElement() => document.createElement("textarea");
 
   @DomName('HTMLTextAreaElement.autofocus')
   @DocsEditable()
@@ -25288,7 +25365,7 @@
 
   TextTrackCue get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -25296,7 +25373,7 @@
   TextTrackCue get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -25304,7 +25381,7 @@
   TextTrackCue get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -25365,7 +25442,7 @@
 
   TextTrack get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -25373,7 +25450,7 @@
   TextTrack get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -25381,7 +25458,7 @@
   TextTrack get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -25460,7 +25537,7 @@
 
   @DomName('HTMLTitleElement.HTMLTitleElement')
   @DocsEditable()
-  factory TitleElement() => document.$dom_createElement("title");
+  factory TitleElement() => document.createElement("title");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -25663,7 +25740,7 @@
 
   Touch get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -25671,7 +25748,7 @@
   Touch get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -25679,7 +25756,7 @@
   Touch get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -25713,7 +25790,7 @@
 
   @DomName('HTMLTrackElement.HTMLTrackElement')
   @DocsEditable()
-  factory TrackElement() => document.$dom_createElement("track");
+  factory TrackElement() => document.createElement("track");
 
   /// Checks if this type is supported on the current platform.
   static bool get supported => true;
@@ -26008,7 +26085,7 @@
 
   @DomName('HTMLUListElement.HTMLUListElement')
   @DocsEditable()
-  factory UListElement() => document.$dom_createElement("ul");
+  factory UListElement() => document.createElement("ul");
 
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
@@ -26146,7 +26223,7 @@
 
   @DomName('HTMLVideoElement.HTMLVideoElement')
   @DocsEditable()
-  factory VideoElement() => document.$dom_createElement("video");
+  factory VideoElement() => document.createElement("video");
 
   @DomName('HTMLVideoElement.height')
   @DocsEditable()
@@ -28566,7 +28643,7 @@
 
   Rect get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -28574,7 +28651,7 @@
   Rect get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -28582,7 +28659,7 @@
   Rect get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -28645,7 +28722,7 @@
 
   CssRule get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -28653,7 +28730,7 @@
   CssRule get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -28661,7 +28738,7 @@
   CssRule get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -28714,7 +28791,7 @@
 
   _CSSValue get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -28722,7 +28799,7 @@
   _CSSValue get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -28730,7 +28807,7 @@
   _CSSValue get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -28980,7 +29057,7 @@
 
   Gamepad get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -28988,7 +29065,7 @@
   Gamepad get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -28996,7 +29073,7 @@
   Gamepad get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -29159,7 +29236,7 @@
 
   Node get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -29167,7 +29244,7 @@
   Node get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -29175,7 +29252,7 @@
   Node get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -29331,7 +29408,7 @@
 
   SpeechInputResult get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -29339,7 +29416,7 @@
   SpeechInputResult get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -29347,7 +29424,7 @@
   SpeechInputResult get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -29398,7 +29475,7 @@
 
   SpeechRecognitionResult get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -29406,7 +29483,7 @@
   SpeechRecognitionResult get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -29414,7 +29491,7 @@
   SpeechRecognitionResult get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -29463,7 +29540,7 @@
 
   StyleSheet get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -29471,7 +29548,7 @@
   StyleSheet get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -29479,7 +29556,7 @@
   StyleSheet get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -34406,6 +34483,31 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
+class _ConsoleVariables {
+  Map<String, Object> _data = new Map<String, Object>();
+  
+  /**
+   * Forward member accesses to the backing JavaScript object.
+   */
+  noSuchMethod(Invocation invocation) {
+    String member = MirrorSystem.getName(invocation.memberName);
+    if (invocation.isGetter) {
+      return _data[member];
+    } else if (invocation.isSetter) {
+      _data[member] = invocation.positionalArguments[0];
+    } else {
+      return Function.apply(_data[member], invocation.positionalArguments, invocation.namedArguments);
+    }
+  }
+  
+  void clear() => _data.clear();
+
+  /**
+   * List all variables currently defined.
+   */
+  List variables() => _data.keys.toList(growable: false);
+}
+
 class _Utils {
   static double dateTimeToDouble(DateTime dateTime) =>
       dateTime.millisecondsSinceEpoch.toDouble();
@@ -34504,6 +34606,41 @@
     return map;
   }
 
+  static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables();
+  /**
+   * Takes an [expression] and a list of [local] variable and returns an
+   * expression for a closure with a body matching the original expression
+   * where locals are passed in as arguments. Returns a list containing the
+   * String expression for the closure and the list of arguments that should
+   * be passed to it.
+   *
+   * For example:
+   * <code>wrapExpressionAsClosure("foo + bar", ["bar", 40, "foo", 2])</code>
+   * will return:
+   * <code>["(final $var, final bar, final foo) => foo + bar", [40, 2]]</code>
+   */
+  static List wrapExpressionAsClosure(String expression, List locals) {
+    var args = {};
+    var sb = new StringBuffer("(");
+    addArg(arg, value) {
+      arg = stripMemberName(arg);
+      if (args.containsKey(arg)) return;
+      if (args.isNotEmpty) {
+        sb.write(", ");
+      }
+      sb.write("final $arg");
+      args[arg] = value;
+    }
+    
+    addArg("\$var", _consoleTempVariables);
+    
+    for (int i = 0; i < locals.length; i+= 2) {
+      addArg(locals[i], locals[i+1]);
+    }
+    sb..write(')=>\n$expression'); 
+    return [sb.toString(), args.values.toList(growable: false)];
+  }
+
   /**
    * Convenience helper to get the keys of a [Map] as a [List].
    */
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index b1eea89..7ca4735 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -308,6 +308,10 @@
 
 
 @DocsEditable()
+/**
+ * An indexed database object for storing client-side data
+ * in web apps.
+ */
 @DomName('IDBDatabase')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX, '15')
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 9071f38..94c23a0 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -119,6 +119,10 @@
 
 
 @DocsEditable()
+/**
+ * An indexed database object for storing client-side data
+ * in web apps.
+ */
 @DomName('IDBDatabase')
 @SupportedBrowser(SupportedBrowser.CHROME)
 @SupportedBrowser(SupportedBrowser.FIREFOX, '15')
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index a7fe520..3cbf4d5 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -109,6 +109,15 @@
   Directory renameSync(String newPath);
 
   /**
+   * Returns a [Directory] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  Directory get absolute;
+
+  /**
    * Lists the sub-directories and files of this [Directory].
    * Optionally recurses into sub-directories.
    *
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index f54a641..61a226a 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -24,7 +24,7 @@
     }
   }
 
-  external static String _current();
+  external static _current();
   external static _setCurrent(path);
   external static _createTemp(String template);
   external static int _exists(String path);
@@ -34,7 +34,14 @@
   external static List _list(String path, bool recursive, bool followLinks);
   external static SendPort _newServicePort();
 
-  static Directory get current => new _Directory(_current());
+  static Directory get current {
+    var result = _current();
+    if (result is OSError) {
+      throw new DirectoryException(
+          "Getting current working directory failed", "", result);
+    }
+    return new _Directory(result);
+  }
 
   static void set current(path) {
     if (path is Directory) path = path.path;
@@ -67,6 +74,8 @@
     return (result == 1);
   }
 
+  Directory get absolute => new Directory(_absolutePath);
+
   Future<FileStat> stat() => FileStat.stat(path);
 
   FileStat statSync() => FileStat.statSync(path);
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index d5579ca..4f9d3f5 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -99,6 +99,15 @@
   int lengthSync();
 
   /**
+   * Returns a [File] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  File get absolute;
+
+  /**
    * Get the last-modified time of the file. Returns a
    * [:Future<DateTime>:] that completes with a [DateTime] object for the
    * modification date.
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index ba6b642..86acf77 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -267,6 +267,8 @@
     return result;
   }
 
+  File get absolute => new File(_absolutePath);
+
   Future<FileStat> stat() => FileStat.stat(path);
 
   FileStat statSync() => FileStat.statSync(path);
@@ -509,28 +511,42 @@
     return builder.takeBytes();
   }
 
+  String _tryDecode(List<int> bytes, Encoding encoding) {
+    try {
+      return encoding.decode(bytes);
+    } catch (_) {
+      throw new FileException(
+          "Failed to decode data using encoding '${encoding.name}'", path);
+    }
+  }
+
   Future<String> readAsString({Encoding encoding: UTF8}) {
     _ensureFileService();
     return readAsBytes().then((bytes) {
-      return encoding.decode(bytes);
+      return _tryDecode(bytes, encoding);
     });
   }
 
   String readAsStringSync({Encoding encoding: UTF8}) {
     List<int> bytes = readAsBytesSync();
-    return encoding.decode(bytes);
+    return _tryDecode(bytes, encoding);
   }
 
-  static List<String> _decodeLines(List<int> bytes, Encoding encoding) {
+  List<String> _decodeLines(List<int> bytes, Encoding encoding) {
     if (bytes.length == 0) return [];
     var list = [];
     var controller = new StreamController(sync: true);
+    var error = null;
     controller.stream
         .transform(encoding.decoder)
         .transform(new LineSplitter())
-        .listen((line) => list.add(line));
+        .listen((line) => list.add(line), onError: (e) => error = e);
     controller.add(bytes);
     controller.close();
+    if (error != null) {
+      throw new FileException(
+          "Failed to decode data using encoding '${encoding.name}'", path);
+    }
     return list;
   }
 
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 0887175..ab2b7d3 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -343,6 +343,45 @@
     });
   }
 
+  static final RegExp _absoluteWindowsPathPattern =
+      new RegExp(r'^(\\\\|[a-zA-Z]:[/\\])');
+
+  /**
+   * Returns a [bool] indicating whether this object's path is absolute.
+   *
+   * On Windows, a path is absolute if it starts with \\ or a drive letter
+   * between a and z (upper or lower case) followed by :\ or :/.
+   * On non-Windows, a path is absolute if it starts with /.
+   */
+  bool get isAbsolute {
+    if (Platform.isWindows) {
+      return path.startsWith(_absoluteWindowsPathPattern);
+    } else {
+      return path.startsWith('/');
+    }
+  }
+
+  /**
+   * Returns a [FileSystemEntity] whose path is the absolute path to [this].
+   * The type of the returned instance is the type of [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  FileSystemEntity get absolute;
+
+  String get _absolutePath {
+    if (isAbsolute) return path;
+    String current = Directory.current.path;
+    if (current.endsWith('/') ||
+        (Platform.isWindows && current.endsWith('\\'))) {
+      return '$current$path';
+    } else {
+      return '$current${Platform.pathSeparator}$path';
+    }
+  }
+
 
   /**
    * Synchronously checks whether two paths refer to the same object in the
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 1cf3387..31f6b97 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -55,8 +55,10 @@
 
 
 /**
- * The [HttpServer] class implements the server side of the HTTP
- * protocol. The [HttpServer] is a [Stream] of [HttpRequest]s. Each
+ * A server that delivers content, such as web pages, using
+ * the HTTP protocol.
+ *
+ * The [HttpServer] is a [Stream] of [HttpRequest]s. Each
  * [HttpRequest] has an associated [HttpResponse] object as its
  * [HttpRequest.response] member, and the server responds to a request by
  * writing to that [HttpResponse] object.
@@ -950,8 +952,10 @@
 
 
 /**
- * The [HttpClient] class implements the client side of the HTTP
- * protocol. It contains a number of methods to send a HTTP request
+ * A client that receives content, such as web pages, from
+ * a server using the HTTP protocol.
+ *
+ * HttpClient contains a number of methods to send a HTTP request
  * to a HTTP server and receive a HTTP response back.
  *
  * This is a two-step process, triggered by two futures. When the
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 3df3fc9..83cd223 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -85,6 +85,15 @@
   Link renameSync(String newPath);
 
   /**
+   * Returns a [Link] instance whose path is the absolute path to [this].
+   *
+   * The absolute path is computed by prefixing
+   * a relative path with the current working directory, and returning
+   * an absolute path unchanged.
+   */
+  Link get absolute;
+
+  /**
    * Gets the target of the link. Returns a future that completes with
    * the path to the target.
    *
@@ -127,6 +136,8 @@
 
   bool existsSync() => FileSystemEntity.isLinkSync(path);
 
+  Link get absolute => new Link(_absolutePath);
+
   Future<FileStat> stat() => FileStat.stat(path);
 
   FileStat statSync() => FileStat.statSync(path);
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 75f2c18..be59cd9 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -32,7 +32,7 @@
 class _SvgElementFactoryProvider {
   static SvgElement createSvgElement_tag(String tag) {
     final Element temp =
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
     return temp;
   }
 }
@@ -4740,7 +4740,7 @@
   static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
 
   factory SvgElement.tag(String tag) =>
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
   factory SvgElement.svg(String svg,
       {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
 
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 228c9a8..2201493 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -21,7 +21,7 @@
 class _SvgElementFactoryProvider {
   static SvgElement createSvgElement_tag(String tag) {
     final Element temp =
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
     return temp;
   }
 }
@@ -2970,7 +2970,7 @@
 
   Length get first {
     if (this.length > 0) {
-      return this[0];
+      return getItem(0);
     }
     throw new StateError("No elements");
   }
@@ -2978,7 +2978,7 @@
   Length get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return getItem(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -2986,7 +2986,7 @@
   Length get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return getItem(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -3430,7 +3430,7 @@
 
   Number get first {
     if (this.length > 0) {
-      return this[0];
+      return getItem(0);
     }
     throw new StateError("No elements");
   }
@@ -3438,7 +3438,7 @@
   Number get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return getItem(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -3446,7 +3446,7 @@
   Number get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return getItem(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -4440,7 +4440,7 @@
 
   PathSeg get first {
     if (this.length > 0) {
-      return this[0];
+      return getItem(0);
     }
     throw new StateError("No elements");
   }
@@ -4448,7 +4448,7 @@
   PathSeg get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return getItem(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -4456,7 +4456,7 @@
   PathSeg get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return getItem(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -5152,7 +5152,7 @@
 
   String get first {
     if (this.length > 0) {
-      return this[0];
+      return getItem(0);
     }
     throw new StateError("No elements");
   }
@@ -5160,7 +5160,7 @@
   String get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return getItem(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -5168,7 +5168,7 @@
   String get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return getItem(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -5318,7 +5318,7 @@
   static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
 
   factory SvgElement.tag(String tag) =>
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
   factory SvgElement.svg(String svg,
       {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
 
@@ -6104,7 +6104,7 @@
 
   Transform get first {
     if (this.length > 0) {
-      return this[0];
+      return getItem(0);
     }
     throw new StateError("No elements");
   }
@@ -6112,7 +6112,7 @@
   Transform get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return getItem(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -6120,7 +6120,7 @@
   Transform get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return getItem(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
@@ -6479,7 +6479,7 @@
 
   ElementInstance get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -6487,7 +6487,7 @@
   ElementInstance get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -6495,7 +6495,7 @@
   ElementInstance get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 5933b2e..f04e918 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -563,7 +563,8 @@
 }
 
 
-class Uint8ClampedList extends Uint8List
+class Uint8ClampedList extends TypedData with ListMixin<int>,
+    FixedLengthListMixin<int> implements JavaScriptIndexingBehavior, List<int>
     native "Uint8ClampedArray,CanvasPixelArray" {
   factory Uint8ClampedList(int length) => _create1(length);
 
@@ -578,8 +579,7 @@
 
   static const int BYTES_PER_ELEMENT = 1;
 
-  // Use implementation from Uint8List
-  // final int length;
+  int get length => JS("int", '#(#)', fetchLength, this);
 
   int operator[](int index) {
     _checkIndex(index, length);
@@ -615,7 +615,11 @@
 class Uint8List
     extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
     implements JavaScriptIndexingBehavior, List<int>
-    native "Uint8Array" {
+    // On some browsers Uint8ClampedArray is a subtype of Uint8Array.  Marking
+    // Uint8List as !nonleaf ensures that the native dispatch correctly handles
+    // the potential for Uint8ClampedArray to 'accidentally' pick up the
+    // dispatch record for Uint8List.
+    native "Uint8Array,!nonleaf" {
   factory Uint8List(int length) => _create1(length);
 
   factory Uint8List.fromList(List<num> list) =>
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 71d6a8d..61577b2 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -430,7 +430,7 @@
  * more space- and time-efficient than the default [List] implementation.
  * Indexed store clamps the value to range 0..0xFF.
  */
-abstract class Uint8ClampedList implements Uint8List {
+abstract class Uint8ClampedList implements List<int>, TypedData {
   /**
    * Creates a [Uint8ClampedList] of the specified length (in elements), all of
    * whose elements are initially zero.
diff --git a/sdk/lib/web_sql/dartium/web_sql_dartium.dart b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
index 828bcf8..4dfaac3 100644
--- a/sdk/lib/web_sql/dartium/web_sql_dartium.dart
+++ b/sdk/lib/web_sql/dartium/web_sql_dartium.dart
@@ -232,7 +232,7 @@
 
   Map get first {
     if (this.length > 0) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     throw new StateError("No elements");
   }
@@ -240,7 +240,7 @@
   Map get last {
     int len = this.length;
     if (len > 0) {
-      return this[len - 1];
+      return _nativeIndexedGetter(len - 1);
     }
     throw new StateError("No elements");
   }
@@ -248,7 +248,7 @@
   Map get single {
     int len = this.length;
     if (len == 1) {
-      return this[0];
+      return _nativeIndexedGetter(0);
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index bb87b73..8befe3d 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -29,8 +29,15 @@
 Language/15_Types/4_Interface_Types_A11_t01: Skip
 Language/15_Types/4_Interface_Types_A11_t02: Skip
 
+# TBF: Hence, a static warning will not be issued if f has no declared return type, since the return type would be dynamic and dynamic may be assigned to void.
+Language/13_Statements/11_Return_A07_t01: fail
+
+# TBF: typedef int func2(int); - "int is not a type"
+Language/15_Types/6_Type_dynamic_A03_t01: fail
+Language/15_Types/6_Type_dynamic_A04_t01: fail
 
 
+LibTest/core/Uri/decodeQueryComponent_A02_t01: fail # co19 Issue 591
 
 # co19 issue #380, Strings class has been removed
 LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail, OK
@@ -80,14 +87,11 @@
 # co19 issue #513, rules for finals were loosened, contradiction in spec was fixed
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A21_t01: fail, OK
 
-# co19 issue #514, it is still an error to have both a n initializing formal and an initializer in the constructor's initializer list
-Language/05_Variables/05_Variables_A05_t03: fail, OK
-
 # co19 issue #515, it is a compile-time error if there is more than one entity with the same name declared in the same scope
-Language/07_Classes/3_Setters_A08_t01: fail, OK
-Language/07_Classes/3_Setters_A08_t02: fail, OK
 Language/07_Classes/3_Setters_A08_t03: fail, OK
-Language/07_Classes/3_Setters_A08_t04: fail, OK
+
+# co19 issue #593: Conditional expressions are now allowed as constant expressions
+Language/12_Expressions/01_Constants_A15_t16: fail, OK
 
 # co19 issue #438, Static variables are initialized lazily, need not be constants
 Language/12_Expressions/01_Constants_A16_t01: fail, OK
@@ -106,9 +110,6 @@
 Language/12_Expressions/12_Instance_Creation_A01_t05: fail, OK
 Language/12_Expressions/12_Instance_Creation_A01_t06: fail, OK
 
-# co19 issue #388 (wrongly closed), StringBuffer methods changed
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail, OK
-
 # co19 issue #433 (wrongly closed), missing @static-warning annotation
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail, OK
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail, OK
@@ -120,98 +121,130 @@
 # co19 issue #543: invocation of a non-function
 Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A03_t02: fail, OK
 
-LibTest/core/NoSuchMethodError/NoSuchMethodError_A01_t01: Fail, OK # co19 issue 556
+# co19 issue #562: malformed superclass
+Language/14_Libraries_and_Scripts/1_Imports_A03_t27: fail, OK
 
-LibTest/async/Stream/listen_A04_t01: Fail, OK # co19 issue 557
-LibTest/typed_data/ByteData/buffer_A01_t02: Fail, OK # co19 issue 557
+# co19 issue #563: implicitly named libraries are allowed
+Language/14_Libraries_and_Scripts/2_Exports_A05_t01: fail, OK
 
-Language/13_Statements/11_Return_A07_t01: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A02_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A04_t03: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/1_Imports_A03_t27: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/1_Imports_A03_t47: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/1_Imports_A03_t67: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/2_Exports_A05_t01: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t24: fail # co19-roll r546: Please triage this failure
-Language/14_Libraries_and_Scripts/5_URIs_A01_t25: fail # co19-roll r546: Please triage this failure
-Language/15_Types/6_Type_dynamic_A03_t01: fail # co19-roll r546: Please triage this failure
-Language/15_Types/6_Type_dynamic_A04_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/asBroadcastStream_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/distinct_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/drain_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/drain_A02_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/EventTransformStream_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/expand_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/first_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/handleError_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/EventTransformStream/listen_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Future/asStream_A01_t02: pass # co19-roll r546: Please triage this failure
-LibTest/async/Future/asStream_A02_t01: pass # co19-roll r546: Please triage this failure
-LibTest/async/Future/whenComplete_A03_t01: pass # co19-roll r546: Please triage this failure
-LibTest/async/Stream/asBroadcastStream_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/asBroadcastStream_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/contains_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/hasListener_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/hasListener_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isClosed_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isClosed_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isPaused_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isPaused_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/sink_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/StreamController.broadcast_A04_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/distinct_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/distinct_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/drain_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/drain_A02_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamEventTransformer/handleData_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamEventTransformer/handleDone_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamEventTransformer/handleError_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/expand_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/handleError_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/isBroadcast_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamIterator/cancel_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/listen_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.fromFuture_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.fromFuture_A02_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Stream/Stream.fromIterable_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/Timer/cancel_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/compareTo_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/DateTime/subtract_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_div_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_eq_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_gt_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_lt_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_lte_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_minus_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_mult_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/Duration/operator_plus_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/asMap_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/every_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/forEach_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/lastWhere_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List.filled_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List.from_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List.generate_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List.generate_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/List.generate_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/map_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/replaceRange_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/replaceRange_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/skipWhile_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/takeWhile_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/toList_A01_t03: fail # co19-roll r546: Please triage this failure
-LibTest/core/StringBuffer/writeAll_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateSink/add_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateSink/addError_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateSink/addError_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateSink/operator_equality_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/any_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/asBroadcastStream_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/contains_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
+# co19 issue #564: URI can be any number adjacent string literals
+Language/14_Libraries_and_Scripts/5_URIs_A01_t24: fail, OK
+Language/14_Libraries_and_Scripts/5_URIs_A01_t25: fail, OK
+
+# co19 issue #565: not implemented members in non-abstract class
+LibTest/async/EventTransformStream/asBroadcastStream_A01_t02: fail, OK
+LibTest/async/Stream/asBroadcastStream_A01_t02: fail, OK
+LibTest/async/Stream/asBroadcastStream_A02_t01: fail, OK
+LibTest/async/Stream/isBroadcast_A01_t01: fail, OK
+LibTest/async/Stream/isBroadcast_A01_t02: fail, OK
+
+# co19 issue #566: Undefined class 'T'
+LibTest/async/EventTransformStream/distinct_A01_t02: fail, OK
+LibTest/async/EventTransformStream/EventTransformStream_A01_t02: fail, OK
+LibTest/async/EventTransformStream/expand_A01_t01: fail, OK
+LibTest/async/Stream/contains_A03_t01: fail, OK
+LibTest/async/Stream/distinct_A01_t01: fail, OK
+LibTest/async/Stream/distinct_A01_t02: fail, OK
+LibTest/async/Stream/expand_A01_t01: fail, OK
+LibTest/core/List/List.filled_A01_t01: fail, OK
+LibTest/core/List/List.generate_A01_t01: fail, OK
+LibTest/core/List/List.generate_A01_t02: fail, OK
+LibTest/core/List/List.generate_A01_t03: fail, OK
+LibTest/core/List/replaceRange_A01_t01: fail, OK
+LibTest/core/List/replaceRange_A01_t02: fail, OK
+LibTest/core/List/skipWhile_A02_t01: fail, OK
+LibTest/core/List/takeWhile_A02_t01: fail, OK
+
+# co19 issue #567: Undefined name 'value'
+LibTest/async/EventTransformStream/drain_A02_t01: fail, OK
+LibTest/async/EventTransformStream/drain_A02_t02: fail, OK
+LibTest/async/Stream/drain_A02_t01: fail, OK
+LibTest/async/Stream/drain_A02_t02: fail, OK
+
+# co19 issue #568: Undefined name 'Expec'
+LibTest/async/EventTransformStream/first_A02_t01: fail, OK
+
+# co19 issue #569: There is no such getter 'message' in 'Object'
+LibTest/async/EventTransformStream/handleError_A03_t01: fail, OK
+LibTest/async/EventTransformStream/listen_A03_t01: fail, OK
+LibTest/async/Stream/handleError_A03_t01: fail, OK
+LibTest/async/Stream/listen_A03_t01: fail, OK
+
+# co19 issue #570: undefined name 'events1'
+LibTest/async/StreamController/hasListener_A01_t01: fail, OK
+LibTest/async/StreamController/hasListener_A01_t02: fail, OK
+LibTest/async/StreamController/isPaused_A01_t01: fail, OK
+LibTest/async/StreamController/isPaused_A01_t03: fail, OK
+
+# co19 issue #571: There is no such getter 'hasListener' in 'EventSink'
+LibTest/async/StreamController/sink_A01_t01: fail, OK
+
+# co19 issue #572: Undefined class 'boolean'; did you mean 'bool'?
+LibTest/async/StreamController/StreamController.broadcast_A04_t01: fail, OK
+LibTest/async/StreamIterator/cancel_A01_t01: fail, OK
+LibTest/core/List/map_A02_t01: fail, OK
+
+# co19 issue #573: There is no such operator '<' in 'Object'
+LibTest/async/StreamEventTransformer/handleData_A01_t01: fail, OK
+LibTest/async/StreamEventTransformer/handleDone_A01_t01: fail, OK
+LibTest/async/StreamEventTransformer/handleError_A01_t01: fail, OK
+
+# co19 issue #574: Abstract classes cannot be created with a 'new' expression
+LibTest/async/Stream/Stream_A01_t01: fail, OK
+
+# co19 issue #575: Error has not constructor parameters
+LibTest/async/Stream/Stream.fromFuture_A02_t01: fail, OK
+LibTest/async/Stream/Stream.fromFuture_A02_t02: fail, OK
+LibTest/async/Stream/Stream.fromIterable_A01_t02: fail, OK
+
+# co19 issue #576: The name 'timer' cannot be referenced in the initializer of a variable with the same name
+LibTest/async/Timer/cancel_A01_t01: fail, OK
+
+# co19 issue #577: The argument type 'int' cannot be assigned to the parameter type 'Duration'
+LibTest/core/DateTime/subtract_A02_t01: fail, OK
+
+# co19 issue #578: Undefined class 'long'
+LibTest/core/Duration/operator_div_A01_t01: fail, OK
+LibTest/core/Duration/operator_eq_A01_t01: fail, OK
+LibTest/core/Duration/operator_gt_A01_t01: fail, OK
+LibTest/core/Duration/operator_lt_A01_t01: fail, OK
+LibTest/core/Duration/operator_lte_A01_t01: fail, OK
+LibTest/core/Duration/operator_minus_A01_t01: fail, OK
+LibTest/core/Duration/operator_mult_A01_t01: fail, OK
+LibTest/core/Duration/operator_plus_A01_t01: fail, OK
+
+# co19 issue #579: The argument type 'bool' cannot be assigned to the parameter type '(String) -> bool'
+LibTest/core/List/every_A03_t01: fail, OK
+LibTest/core/List/forEach_A01_t02: fail, OK
+
+# co19 issue #580: Undefined name 'faled'
+LibTest/core/List/lastWhere_A03_t01: fail, OK
+
+# co19 issue #581: Undefined name 'Expect'
+LibTest/core/List/List_A01_t03: fail, OK
+LibTest/core/List/List.from_A01_t03: fail, OK
+LibTest/core/List/toList_A01_t03: fail, OK
+
+# co19 issue #582: The method 'addAll' is not defined for the class 'StringBuffer'
+LibTest/core/StringBuffer/writeAll_A03_t01: fail, OK
+
+# co19 issue #583: The method 'close' is not defined for the class 'SendPort'
+LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: fail, OK
+LibTest/isolate/IsolateSink/add_A01_t02: fail, OK
+LibTest/isolate/IsolateSink/operator_equality_A01_t01: fail, OK
+
+# co19 issue #584: Undefined name 'received
+LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail, OK
+
+# co19 issue #585: Undefined name 'messagesList'
+LibTest/isolate/IsolateSink/addError_A01_t01: fail, OK
+
+# co19 issue #586: Undefined name 'message'
+LibTest/isolate/IsolateSink/addError_A01_t02: fail, OK
+
+# co19 issue #587: Missing dart:async import and other mistypes
+LibTest/isolate/IsolateStream/any_A02_t01: fail, OK
+LibTest/isolate/IsolateStream/asBroadcastStream_A01_t01: fail, OK
+LibTest/isolate/IsolateStream/contains_A01_t01: fail, OK
+LibTest/isolate/IsolateStream/contains_A02_t01: fail, OK
+LibTest/isolate/IsolateStream/isBroadcast_A01_t02: fail, OK
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 7b4a78b..cdcaa67 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -30,7 +30,7 @@
 Language/15_Types/4_Interface_Types_A11_t02: Skip
 
 
-
+LibTest/core/Uri/decodeQueryComponent_A02_t01: fail # co19 Issue 591
 
 # co19 issue #380, Strings class has been removed
 LibTest/core/RegExp/Pattern_semantics/firstMatch_CharacterClassEscape_A03_t01: fail, OK
@@ -77,14 +77,6 @@
 # co19 issue #513, rules for finals were loosened, contradiction in spec was fixed
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A21_t01: fail, OK
 
-# co19 issue #514, it is still an error to have both a n initializing formal and an initializer in the constructor's initializer list
-Language/05_Variables/05_Variables_A05_t03: fail, OK
-
-# co19 issue #515, it is a compile-time error if there is more than one entity with the same name declared in the same scope
-Language/07_Classes/3_Setters_A08_t01: fail, OK
-Language/07_Classes/3_Setters_A08_t02: fail, OK
-Language/07_Classes/3_Setters_A08_t04: fail, OK
-
 # co19 issue #438, Static variables are initialized lazily, need not be constants
 Language/12_Expressions/01_Constants_A16_t01: fail, OK
 Language/12_Expressions/01_Constants_A16_t02: fail, OK
@@ -97,9 +89,6 @@
 Language/12_Expressions/12_Instance_Creation_A01_t05: fail, OK
 Language/12_Expressions/12_Instance_Creation_A01_t06: fail, OK
 
-# co19 issue #388 (wrongly closed), StringBuffer methods changed
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail, OK
-
 # co19 issue #433 (wrongly closed), missing @static-warning annotation
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t01: fail, OK
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A03_t07: fail, OK
@@ -111,15 +100,7 @@
 # co19 issue #543: invocation of a non-function
 Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A03_t02: fail, OK
 
-LibTest/core/NoSuchMethodError/NoSuchMethodError_A01_t01: Fail, OK # co19 issue 556
-
-LibTest/async/Stream/listen_A04_t01: Fail, OK # co19 issue 557
-LibTest/typed_data/ByteData/buffer_A01_t02: Fail, OK # co19 issue 557
-
 Language/13_Statements/11_Return_A07_t01: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A02_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A04_t03: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/1_Imports_A03_t27: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/1_Imports_A03_t47: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/1_Imports_A03_t67: fail # co19-roll r546: Please triage this failure
@@ -145,8 +126,6 @@
 LibTest/async/Stream/contains_A03_t01: fail # co19-roll r546: Please triage this failure
 LibTest/async/StreamController/hasListener_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/async/StreamController/hasListener_A01_t02: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isClosed_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/async/StreamController/isClosed_A01_t02: fail # co19-roll r546: Please triage this failure
 LibTest/async/StreamController/isPaused_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/async/StreamController/isPaused_A01_t03: fail # co19-roll r546: Please triage this failure
 LibTest/async/StreamController/sink_A01_t01: fail # co19-roll r546: Please triage this failure
@@ -178,7 +157,6 @@
 LibTest/core/Duration/operator_minus_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/core/Duration/operator_mult_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/core/Duration/operator_plus_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/core/List/asMap_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/core/List/every_A03_t01: fail # co19-roll r546: Please triage this failure
 LibTest/core/List/forEach_A01_t02: fail # co19-roll r546: Please triage this failure
 LibTest/core/List/lastWhere_A03_t01: fail # co19-roll r546: Please triage this failure
@@ -196,6 +174,7 @@
 LibTest/core/List/toList_A01_t03: fail # co19-roll r546: Please triage this failure
 LibTest/core/StringBuffer/writeAll_A03_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: fail # co19-roll r546: Please triage this failure
+LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail # co19-roll r576: Please triage this failure
 LibTest/isolate/IsolateSink/add_A01_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t02: fail # co19-roll r546: Please triage this failure
@@ -204,4 +183,4 @@
 LibTest/isolate/IsolateStream/asBroadcastStream_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateStream/contains_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/IsolateStream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
\ No newline at end of file
+LibTest/isolate/IsolateStream/isBroadcast_A01_t02: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index e470bb0..2cdbc44 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -8,20 +8,26 @@
 
 ### GENERAL FAILURES ###
 
+
+[ $runtime == vm || $compiler == dart2dart || $compiler == dart2js ]
+LibTest/core/Uri/decodeQueryComponent_A02_t01: fail # co19 Issue 591
+LibTest/core/Uri/encodeComponent_A01_t02: fail # Issue 13251, co19 Issues 588, 589
+LibTest/core/Uri/toFilePath_A01_t01: pass, fail, ok # co19 Issue 592
+LibTest/core/Uri/Uri_A03_t01: fail # Issue 13250, co19 Issue 588
+LibTest/core/Uri/Uri.http_A02_t01: fail # Issue 13250, co19 Issue 588
+LibTest/core/Uri/Uri.https_A02_t01: fail # Issue 13250, co19 Issue 588
+# Maybe we should wait until isolate library is sealed before triaging these.
+LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail, timeout # co19-roll r546: Please triage this failure
+LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail, timeout # co19-roll r546: Please triage this failure
+
 [ $runtime == vm || $compiler == dart2dart || $compiler == dart2js ]
 LibTest/typed_data/ByteData/elementSizeInBytes_A01_t01: fail # co19-roll r569: Please triage this failure
 
 [ $runtime == vm || $compiler == dart2js ]
+Language/07_Classes/6_Constructors_A02_t01: SKIP # co19 issue 415.
 Language/12_Expressions/01_Constants_A16_t01: FAIL, OK # co19 issue 525
 Language/12_Expressions/01_Constants_A16_t02: FAIL, OK # co19 issue 525
-
-Language/13_Statements/11_Try_A02_t03: FAIL, OK # co19 issue 552
-Language/13_Statements/11_Try_A03_t03: FAIL, OK # co19 issue 552
-Language/13_Statements/11_Try_A04_t03: FAIL, OK # co19 issue 552
-Language/13_Statements/11_Try_A07_t03: FAIL, OK # co19 issue 553
-
-Language/07_Classes/6_Constructors_A02_t01: SKIP # co19 issue 415.
-Language/07_Classes/6_Constructors/1_Generative_Constructors_A04_t15: FAIL, OK # co19 issue 547
+Language/14_Libraries_and_Scripts/1_Imports_A03_t65: PASS, FAIL, OK # co19 issue 560
 
 LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
 LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
@@ -45,8 +51,6 @@
 LibTest/core/double/truncate_A01_t03: FAIL, OK # co19 issue 389
 LibTest/core/double/truncate_A01_t04: FAIL, OK # co19 issue 389
 
-LibTest/core/int/toStringAsExponential_A02_t01: FAIL, OK # co19 issue 477
-
 LibTest/async/Stream/Stream.periodic_A01_t01: TIMEOUT, PASS, FAIL, OK # co19 issue 538
 LibTest/async/Stream/Stream.periodic_A03_t01: PASS, FAIL, OK # co19 issue 538
 LibTest/async/Timer/run_A01_t01: PASS, FAIL, OK # co19 issue 538
@@ -65,9 +69,6 @@
 
 LibTest/async/EventTransformStream/listen_A04_t01: Pass, Timeout # co19 issue 542
 
-LibTest/async/EventTransformStream/elementAt_A03_t01: FAIL # co19 issue 545
-LibTest/async/Stream/elementAt_A03_t01: FAIL # co19 issue 545
-
 LibTest/typed_data/Int8List/Int8List.fromList_A01_t02: Fail # co19-roll r559: Please triage this failure
 
 LibTest/typed_data/Float32List/removeAll_A01_t01: Fail  # co19 issue 548
@@ -95,11 +96,19 @@
 LibTest/typed_data/Uint8List/removeAll_A01_t01: Fail  # co19 issue 548
 LibTest/typed_data/Uint8List/retainAll_A01_t01: Fail  # co19 issue 548
 
+Language/12_Expressions/06_Lists_A08_t01: Fail  # co19 issue 561
+LibTest/core/String/String_class_A01_t01: Fail  # co19 issue 561
+LibTest/core/String/concat_A01_t01: Fail  # co19 issue 561
+LibTest/core/String/concat_A02_t01: Fail  # co19 issue 561
+LibTest/core/String/hashCode_A01_t01: Fail  # co19 issue 561
+
 ### CHECKED MODE FAILURES ###
 
 [ ($runtime == vm || $compiler == dart2js) && $checked]
 Language/13_Statements/09_Switch_A05_t01: FAIL, OK # co19 issue 498
 Language/14_Libraries_and_Scripts/1_Imports_A03_t26: FAIL, OK  # co19 issue 498
+Language/14_Libraries_and_Scripts/1_Imports_A03_t46: PASS, FAIL, OK # co19 issue 560
+Language/14_Libraries_and_Scripts/1_Imports_A03_t66: PASS, FAIL, OK # co19 issue 560
 Language/15_Types/1_Static_Types_A03_t01: Fail # co19-roll r559: Please triage this failure
 LibTest/async/EventTransformStream/contains_A01_t01: FAIL, OK  # co19 issue 498
 LibTest/core/DateTime/compareTo_A02_t01: FAIL, OK  # co19 issue 498
@@ -111,4 +120,5 @@
 LibTest/core/TypeError/line_A01_t01: FAIL, OK # co19 issue 510
 LibTest/core/TypeError/srcType_A01_t01: FAIL, OK # co19 issue 510
 LibTest/core/TypeError/url_A01_t01: FAIL, OK # co19 issue 510
-LibTest/core/NoSuchMethodError/NoSuchMethodError_A01_t01: Fail # co19 issue 550
+LibTest/core/Uri/encodeFull_A01_t02: fail # co19 Issue 589
+
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index a926046..91b835e 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -6,7 +6,6 @@
 LibTest/async/Stream/Stream.periodic_A01_t01: Pass, Fail # Issue 12562.
 
 Language/07_Classes/9_Superclasses/1_Inheritance_and_Overriding_A01_t03: Fail # TODO(dart2dart-team): Please triage this failure.
-LibTest/core/int/toStringAsExponential_A02_t01: Fail # co19 issue 477
 
 Language/03_Overview/1_Scoping_A01_t39: Fail # http://dartbug.com/7202
 
@@ -122,7 +121,6 @@
 Language/03_Overview/1_Scoping_A02_t28: Fail # co19-roll r559: Please triage this failure
 Language/05_Variables/05_Variables_A05_t01: fail # co19-roll r546: Please triage this failure
 Language/05_Variables/05_Variables_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t03: fail # co19-roll r546: Please triage this failure
 Language/05_Variables/05_Variables_A06_t01: fail # co19-roll r546: Please triage this failure
 Language/05_Variables/05_Variables_A06_t02: fail # co19-roll r546: Please triage this failure
 Language/05_Variables/05_Variables_A06_t03: fail # co19-roll r546: Please triage this failure
@@ -137,9 +135,6 @@
 Language/07_Classes/1_Instance_Methods_A01_t04: Fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t05: Fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t06: Fail # co19-roll r559: Please triage this failure
-Language/07_Classes/3_Setters_A08_t01: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t04: fail # co19-roll r546: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t01: Fail # co19-roll r559: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t02: Fail # co19-roll r559: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t03: Fail # co19-roll r559: Please triage this failure
@@ -225,7 +220,6 @@
 Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/22_Equality_A01_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/22_Equality_A01_t15: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/22_Equality_A01_t16: fail # co19-roll r546: Please triage this failure
@@ -248,20 +242,9 @@
 Language/12_Expressions/33_Type_Cast_A03_t02: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/33_Type_Cast_A03_t03: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/02_Expression_Statements_A01_t08: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t01: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t02: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t04: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t05: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t06: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t07: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/03_Variable_Declaration_A04_t08: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/06_For_A01_t11: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/09_Switch_A01_t02: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/09_Switch_A04_t01: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A02_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A03_t03: fail # co19-roll r546: Please triage this failure
-Language/13_Statements/11_Try_A04_t03: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/11_Try_A07_t03: fail # co19-roll r546: Please triage this failure
 Language/13_Statements/12_Labels_A01_t03: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/1_Imports_A02_t28: fail # co19-roll r546: Please triage this failure
@@ -289,11 +272,7 @@
 Language/14_Libraries_and_Scripts/5_URIs_A01_t21: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/5_URIs_A01_t24: fail # co19-roll r546: Please triage this failure
 Language/14_Libraries_and_Scripts/5_URIs_A01_t25: fail # co19-roll r546: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t01: fail # co19-roll r546: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t02: fail # co19-roll r546: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t03: fail # co19-roll r546: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t04: fail # co19-roll r546: Please triage this failure
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t05: fail # co19-roll r546: Please triage this failure
+Language/14_Libraries_and_Scripts/1_Imports_A03_t65: pass, fail, ok # co19 issue 560
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t01: fail # co19-roll r546: Please triage this failure
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t02: fail # co19-roll r546: Please triage this failure
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t03: fail # co19-roll r546: Please triage this failure
@@ -306,10 +285,8 @@
 LibTest/async/Stream/Stream.periodic_A03_t01: fail, pass # co19-roll r546: Please triage this failure
 LibTest/async/Timer/Timer.periodic_A02_t01: fail, pass # co19-roll r546: Please triage this failure
 LibTest/core/DateTime/parse_A03_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnUri_A02_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnUri_A02_t03: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateStream/any_A02_t01: fail # co19-roll r546: Please triage this failure
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 0f0d2e3..e794031 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -12,6 +12,7 @@
 LibTest/core/List/sort_A01_t04: Fail, Pass, Timeout # Must be a bug in jsshell, test sometimes times out.
 
 [ $compiler == dart2js && $checked && $runtime == ie9 ]
+LibTest/core/Uri/encodeQueryComponent_A01_t02: Pass, Timeout # co19-roll r576: Please triage this failure
 LibTest/isolate/isolate_api/spawnUri_A02_t03: Pass, Fail # Issue 8920
 
 
@@ -20,10 +21,12 @@
 [ $compiler == dart2js ]
 Language/03_Overview/1_Scoping_A02_t05: Fail # TODO(ahe): Please triage this failure.
 Language/03_Overview/1_Scoping_A02_t06: Fail # TODO(ahe): Please triage this failure.
+Language/05_Variables/1_Evaluation_of_Implicit_Variable_Getters_A01_t02: fail # co19-roll r576: Please triage this failure
 Language/07_Classes/6_Constructors/2_Factories_A07_t01: Fail # TODO(ahe): Please triage this failure.
-LibTest/core/List/List_A03_t01: Fail # TODO(kasperl): Please triage this failure.
+Language/13_Statements/11_Try_A07_t03: fail # co19-roll r576: Please triage this failure
 LibTest/core/double/INFINITY_A01_t04: Fail # TODO(ahe): Please triage this failure.
 LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Fail # TODO(ahe): Please triage this failure.
+LibTest/core/List/List_A03_t01: Fail # TODO(kasperl): Please triage this failure.
 LibTest/core/List/sort_A01_t04: Pass, Slow # http://dartbug.com/11846
 LibTest/math/pow_A13_t01: FAIL, OK # co19 issue 507
 LibTest/math/pow_A18_t01: FAIL, OK # co19 issue 507
@@ -44,6 +47,19 @@
 LibTest/typed_data/ByteData/setUint16_A02_t02: fail # co19-roll r569: Please triage this failure
 LibTest/typed_data/ByteData/setUint32_A02_t02: fail # co19-roll r569: Please triage this failure
 LibTest/typed_data/ByteData/setUint64_A02_t02: fail # co19-roll r569: Please triage this failure
+LibTest/typed_data/Float32List/Float32List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Float32x4List/Float32x4List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Float64List/Float64List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Int16List/Int16List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Int32List/Int32List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Int8List/Int8List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Uint16List/Uint16List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Uint32List/Uint32List_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Uint8ClampedList/Uint8ClampedList_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/typed_data/Uint8List/Uint8List_A02_t01: fail # co19-roll r576: Please triage this failure
+
+[ $compiler == dart2js && $runtime != ie9 ]
+LibTest/typed_data/ByteData/ByteData_A02_t01: fail # co19-roll r576: Please triage this failure
 
 [ $compiler == dart2js && $runtime == jsshell ]
 LibTest/isolate/SendPort/send_A02_t05: Fail, Pass # TODO(ahe): Please triage this failure.
@@ -314,21 +330,8 @@
 Language/12_Expressions/30_Identifier_Reference_A04_t09: Fail # Checks that it is a compile-time error when a built-in identifier dynamic is used as the declared name of a type variable.
 Language/12_Expressions/30_Identifier_Reference_A05_t01: Fail # Checks that it is a compile-time error when a built-in identifier "abstract" is used as a type annotation of a local variable.
 Language/12_Expressions/30_Identifier_Reference_A05_t12: Fail # Checks that it is a compile-time error when a built-in identifier "static" is used as a type annotation of a local variable.
-Language/13_Statements/03_Variable_Declaration_A04_t01: Fail # Checks that a variable declaration statement var e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t02: Fail # Checks that a variable declaration statement T e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t03: Fail # Checks that a variable declaration statement const e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t04: Fail # Checks that a variable declaration statement const T e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t05: Fail # Checks that a variable declaration statement final e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t06: Fail # Checks that a variable declaration statement final T e = e; causes a compile-time error.
-Language/13_Statements/03_Variable_Declaration_A04_t07: Fail # Checks that a variable declaration statement var e = e; causes a compile-time error. A top-level variable with the same name is declared.
-Language/13_Statements/03_Variable_Declaration_A04_t08: Fail # Checks that it is a compile-time error if the initializing expression of a local variable v refers to the name v= even when a top-level variable  with the same name is declared.
 Language/14_Libraries_and_Scripts/5_URIs_A01_t24: Fail # Checks that it is a compile-time error when the URI in a part directive consists of two adjacent string literals instead of one.
 Language/14_Libraries_and_Scripts/5_URIs_A01_t25: Fail # Checks that it is a compile-time error when the URI in a part directive consists of two adjacent multi-line string literals  instead of one.
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t01: Fail # Checks that a compile error is produced when a null default value is specified for a required argument in a function type alias.
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t02: Fail # Checks that a compile error is produced when a default value is specified for an optional positional  argument in a function type alias.
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t03: Fail # Checks that a compile error is produced when a default value is specified for an optional named  argument in a function type alias.
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t04: Fail # Checks that a compile error is produced when a default value is specified for one of the required arguments in a function type alias.
-Language/15_Types/3_Type_Declarations/1_Typedef_A06_t05: Fail # Checks that a compile error is produced when default values are specified for several parameters in a function type alias.
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t01: Fail # Checks that self-referencing typedef is not allowed (return value type annotation has the same name as the type alias).
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t02: Fail # Checks that self-referencing typedef is not allowed (positional formal parameter type annotation has the same name as the type alias).
 Language/15_Types/3_Type_Declarations/1_Typedef_A07_t03: Fail # Checks that self-referencing typedef is not allowed (positional optional parameter type annotation has the same name as the type alias).
@@ -423,16 +426,12 @@
 Language/03_Overview/1_Scoping_A02_t28: fail # co19-roll r559: Please triage this failure
 Language/05_Variables/05_Variables_A05_t01: fail # co19-roll r546: Please triage this failure
 Language/05_Variables/05_Variables_A05_t02: fail # co19-roll r546: Please triage this failure
-Language/05_Variables/05_Variables_A05_t03: fail # co19-roll r546: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t01: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t02: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t03: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t04: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t05: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/1_Instance_Methods_A01_t06: fail # co19-roll r559: Please triage this failure
-Language/07_Classes/3_Setters_A08_t01: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t02: fail # co19-roll r546: Please triage this failure
-Language/07_Classes/3_Setters_A08_t04: fail # co19-roll r546: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t01: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t02: fail # co19-roll r559: Please triage this failure
 Language/07_Classes/4_Abstract_Instance_Members_A03_t03: fail # co19-roll r559: Please triage this failure
@@ -461,7 +460,6 @@
 Language/12_Expressions/12_Instance_Creation/2_Const_A11_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/12_Instance_Creation/2_Const_A11_t03: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/22_Equality_A01_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/22_Equality_A05_t01: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/30_Identifier_Reference_A02_t01: fail # co19-roll r546: Please triage this failure
@@ -511,13 +509,11 @@
 LibTest/core/Match/pattern_A01_t01: fail # co19-roll r559: Please triage this failure
 LibTest/core/RegExp/allMatches_A01_t01: fail # co19-roll r559: Please triage this failure
 LibTest/isolate/isolate_api/spawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnFunction_A04_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnFunction_A04_t03: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnUri_A02_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/spawnUri_A02_t03: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/streamSpawnFunction_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/isolate_api/streamSpawnFunction_A02_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/add_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/add_A01_t02: fail # co19-roll r546: Please triage this failure
@@ -666,5 +662,7 @@
 
 [ $compiler == dart2js || $compiler == dart2dart ]
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A15_t08: fail # co19-roll r569: Please triage this failure
-
+LibTest/core/NoSuchMethodError/NoSuchMethodError_A01_t01: fail # co19-roll r576: Please triage this failure
+LibTest/core/Uri/Uri_A06_t02: fail # co19-roll r576: Please triage this failure
+LibTest/core/Uri/Uri_A06_t03: fail # co19-roll r576: Please triage this failure
 
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 950b3b7..972dd6a 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -5,6 +5,40 @@
 [ $runtime == vm ]
 Language/12_Expressions/01_Constants_A16_t04: fail # Issue 392
 Language/12_Expressions/01_Constants_A16_t05: fail # Issue 392
+LibTest/typed_data/Float32List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Float32List/Float32List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Float32List/Float32List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Float32List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Float32x4List/Float32x4List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Float32x4List/Float32x4List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Float32x4List/Float32x4List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Float64List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Float64List/Float64List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Float64List/Float64List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Float64List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Int16List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Int16List/Int16List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Int16List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Int32List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Int32List/Int32List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Int32List/Int32List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Int32List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Int64List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Int64List/Int64List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Int64List/Int64List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Int64List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint16List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint16List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint16List/Uint16List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint16List/Uint16List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Uint32List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint32List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint32List/Uint32List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint32List/Uint32List.view_A01_t02: fail # Issue 549
+LibTest/typed_data/Uint64List/buffer_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint64List/offsetInBytes_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint64List/Uint64List.view_A01_t01: fail # Issue 549
+LibTest/typed_data/Uint64List/Uint64List.view_A01_t02: fail # Issue 549
 
 [ $runtime == vm && $system == windows ]
 LibTest/core/Stopwatch/elapsed_A01_t01: Pass, Fail # Issue 11382.
@@ -60,10 +94,12 @@
 LibTest/typed_data/Float32List/Float32List.view_A01_t02: Crash  # Issue 12868
 LibTest/typed_data/Float64List/Float64List.view_A01_t02: Crash  # Issue 12868
 
+[ $compiler == none && $runtime == vm && ($arch == simarm || $arch == simmips) ]
+LibTest/core/Uri/Uri_A06_t03: Pass, Timeout # co19-roll r576: Please triage this failure
+
 [ $compiler == none && $runtime == vm ]
 Language/05_Variables/05_Variables_A05_t01: fail # Dart issue 12539
 Language/05_Variables/05_Variables_A05_t02: fail # Dart issue 12539
-Language/05_Variables/05_Variables_A05_t03: fail # Dart issue 12539
 Language/05_Variables/05_Variables_A06_t01: fail # Dart issue 12543
 Language/05_Variables/05_Variables_A06_t02: fail # Dart issue 12543
 Language/05_Variables/05_Variables_A06_t03: fail # Dart issue 12543
@@ -71,11 +107,6 @@
 Language/05_Variables/05_Variables_A06_t05: fail # Dart issue 12543
 Language/05_Variables/05_Variables_A06_t06: fail # Dart issue 12543
 Language/05_Variables/05_Variables_A16_t02: fail # Dart issue 12544
-Language/07_Classes/07_Classes_A11_t02: fail # Dart issue 12545
-Language/07_Classes/07_Classes_A11_t04: fail # Dart issue 12545
-Language/07_Classes/3_Setters_A08_t01: fail # co19 issue 520
-Language/07_Classes/3_Setters_A08_t02: fail # co19 issue 520
-Language/07_Classes/3_Setters_A08_t04: fail # co19 issue 520
 Language/07_Classes/6_Constructors/1_Generative_Constructors_A09_t01: fail # Dart issue 12543
 Language/12_Expressions/05_Strings_A02_t46: fail # Dart issue 12547
 Language/12_Expressions/05_Strings_A02_t48: fail # Dart issue 12547
@@ -85,8 +116,6 @@
 Language/12_Expressions/12_Instance_Creation/2_Const_A10_t01: fail # co19 issue 525
 Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A05_t01: fail # Dart issue 12550
 Language/12_Expressions/15_Method_Invocation/3_Static_Invocation_A04_t09: fail # Dart issue 12549
-Language/12_Expressions/15_Method_Invocation/4_Super_Invocation_A02_t04: fail # Dart issue 12549
-Language/12_Expressions/30_Identifier_Reference_A05_t02: fail # Dart issue 12551
 Language/12_Expressions/30_Identifier_Reference_A08_t02: fail # Dart issue 12593
 Language/12_Expressions/32_Type_Test_A04_t02: fail # co19 issue 503
 Language/12_Expressions/32_Type_Test_A04_t03: fail # co19 issue 534
@@ -102,18 +131,7 @@
 Language/13_Statements/09_Switch_A03_t02: fail # Dart issue 7307
 Language/13_Statements/09_Switch_A04_t01: fail # Dart issue 11233
 Language/13_Statements/12_Labels_A01_t03: fail # Dart issue 2238
-Language/14_Libraries_and_Scripts/13_Libraries_and_Scripts_A05_t04: fail # Dart issue 12913
-Language/14_Libraries_and_Scripts/1_Imports_A03_t09: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t10: fail # Dart issue 12915
 Language/14_Libraries_and_Scripts/1_Imports_A03_t27: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t29: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t30: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t47: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t49: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t50: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t67: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t69: fail # Dart issue 12915
-Language/14_Libraries_and_Scripts/1_Imports_A03_t70: fail # Dart issue 12915
 Language/14_Libraries_and_Scripts/2_Exports_A04_t02: fail # Dart issue 12916
 Language/14_Libraries_and_Scripts/2_Exports_A04_t03: fail # Dart issue 12916
 Language/14_Libraries_and_Scripts/2_Exports_A05_t01: fail # Dart issue 12918
@@ -128,8 +146,6 @@
 LibTest/core/DateTime/parse_A03_t01: fail # Issue 12514
 
 # All isolate are being ignored at the moment as the library will go through some changes.
-LibTest/isolate/isolate_api/spawnFunction_A04_t01: fail # co19-roll r546: Please triage this failure
-LibTest/isolate/isolate_api/streamSpawnFunction_A02_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateSink/addError_A01_t02: fail # co19-roll r546: Please triage this failure
 LibTest/isolate/IsolateStream/any_A02_t01: fail # co19-roll r546: Please triage this failure
@@ -163,3 +179,10 @@
 LibTest/typed_data/Float32x4List/skip_A01_t01: Fail # Dart issue 12861
 LibTest/typed_data/Float32x4List/take_A01_t01: Fail # Dart issue 12861
 LibTest/typed_data/Float32x4List/take_A02_t01: Fail # Dart issue 12861
+
+[ $compiler == none && $runtime == vm && $system == windows ]
+Language/15_Types/4_Interface_Types_A11_t01: pass, timeout # co19-roll r576: Please triage this failure
+Language/15_Types/4_Interface_Types_A11_t02: pass, timeout # co19-roll r576: Please triage this failure
+LibTest/core/Uri/toFilePath_A02_t01: fail # co19-roll r576: Please triage this failure
+LibTest/core/Uri/Uri.file_A01_t01: fail # co19-roll r576: Please triage this failure
+
diff --git a/tests/compiler/dart2js/analyze_all_test.dart b/tests/compiler/dart2js/analyze_all_test.dart
index 58a313c..5f6a8ab 100644
--- a/tests/compiler/dart2js/analyze_all_test.dart
+++ b/tests/compiler/dart2js/analyze_all_test.dart
@@ -29,18 +29,16 @@
 
 main() {
   Uri uri = Uri.parse('test:code');
-  asyncStart();
   var compiler1 = compilerFor(SOURCE, uri, analyzeAll: false);
-  compiler1.runCompiler(uri).then((_) {
+  asyncTest(() => compiler1.runCompiler(uri).then((_) {
     Expect.isFalse(compiler1.compilationFailed);
     print(compiler1.warnings);
     Expect.isTrue(compiler1.warnings.isEmpty, 'unexpected warnings');
     Expect.isTrue(compiler1.errors.isEmpty, 'unexpected errors');
-  }).whenComplete(() => asyncEnd());
+  }));
 
-  asyncStart();
   var compiler2 = compilerFor(SOURCE, uri, analyzeAll: true);
-  compiler2.runCompiler(uri).then((_) {
+  asyncTest(() => compiler2.runCompiler(uri).then((_) {
     Expect.isTrue(compiler2.compilationFailed);
     Expect.isTrue(compiler2.warnings.isEmpty, 'unexpected warnings');
     Expect.equals(2, compiler2.errors.length,
@@ -53,5 +51,5 @@
     Expect.equals(MessageKind.CONSTRUCTOR_IS_NOT_CONST,
                   compiler2.errors[1].message.kind);
     Expect.equals("Foo", compiler2.errors[1].node.toString());
-  }).whenComplete(() => asyncEnd());
+  }));
 }
diff --git a/tests/compiler/dart2js/analyze_only_test.dart b/tests/compiler/dart2js/analyze_only_test.dart
index 67bbeb8..818149a 100644
--- a/tests/compiler/dart2js/analyze_only_test.dart
+++ b/tests/compiler/dart2js/analyze_only_test.dart
@@ -45,7 +45,7 @@
     onValue(code, errors, warnings);
   }, onError: (e) {
       throw 'Compilation failed';
-  }).whenComplete(() => asyncEnd());
+  }).then(asyncSuccess);
 }
 
 main() {
diff --git a/tests/compiler/dart2js/async_compiler_input_provider_test.dart b/tests/compiler/dart2js/async_compiler_input_provider_test.dart
index 9b8a826..d329e3a 100644
--- a/tests/compiler/dart2js/async_compiler_input_provider_test.dart
+++ b/tests/compiler/dart2js/async_compiler_input_provider_test.dart
@@ -46,11 +46,10 @@
   Uri libraryRoot = script.resolve('../../../sdk/');
   Uri packageRoot = script.resolve('./packages/');
 
-  asyncStart();
-  compiler.compile(entrypoint, libraryRoot, packageRoot,
+  asyncTest(() => compiler.compile(entrypoint, libraryRoot, packageRoot,
       provideInput, handleDiagnostic, []).then((code) {
     Expect.isNotNull(code);
-  }).whenComplete(() => asyncEnd());
+  }));
 }
 
 void handleDiagnostic(Uri uri, int begin, int end, String message,
diff --git a/tests/compiler/dart2js/bad_loop_test.dart b/tests/compiler/dart2js/bad_loop_test.dart
index 65629a4..8a86fd6 100644
--- a/tests/compiler/dart2js/bad_loop_test.dart
+++ b/tests/compiler/dart2js/bad_loop_test.dart
@@ -37,12 +37,11 @@
                                    libraryRoot,
                                    packageRoot,
                                    ['--analyze-only']);
-  asyncStart();
-  compiler.run(Uri.parse('memory:main.dart')).then((_) {
+  asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
     Expect.isTrue(compiler.compilationFailed);
     Expect.equals(5, errorCount);
     Expect.equals(1, warningCount);
-  }).whenComplete(() => asyncEnd());
+  }));
 }
 
 const Map MEMORY_SOURCE_FILES = const {
diff --git a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
index b568b19..541face 100644
--- a/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
+++ b/tests/compiler/dart2js/call_site_simple_type_inferer_test.dart
@@ -16,14 +16,13 @@
                     bool disableInlining,
                     check(compiler, element)) {
   Uri uri = new Uri(scheme: 'source');
-  asyncStart();
   var compiler = compilerFor(code, uri);
   compiler.disableInlining = disableInlining;
-  compiler.runCompiler(uri).then((_) {
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
     var cls = findElement(compiler, className);
     var member = cls.lookupLocalMember(buildSourceString(memberName));
     return check(compiler, member);
-  }).whenComplete(() => asyncEnd());
+  }));
 }
 
 const String TEST_1 = r"""
@@ -244,7 +243,7 @@
 void test() {
   runTest(TEST_1, (compiler) => [compiler.typesTask.stringType]);
   runTest(TEST_2, (compiler) => [compiler.typesTask.intType]);
-  runTest(TEST_3, (compiler) => [compiler.typesTask.numType]);
+  runTest(TEST_3, (compiler) => [compiler.typesTask.intType]);
   runTest(TEST_4, (compiler) => [compiler.typesTask.numType]);
   runTest(TEST_5, (compiler) => [compiler.typesTask.numType]);
   runTest(TEST_6, (compiler) => [compiler.typesTask.numType]);
@@ -257,8 +256,8 @@
                                  compiler.typesTask.dynamicType.nonNullable()]);
   runTest(TEST_9, (compiler) => [compiler.typesTask.intType,
                                  compiler.typesTask.intType]);
-  runTest(TEST_10, (compiler) => [subclassOfInterceptor(compiler),
-                                  subclassOfInterceptor(compiler)]);
+  runTest(TEST_10, (compiler) => [compiler.typesTask.intType,
+                                 compiler.typesTask.intType]);
   runTest(TEST_11, (compiler) => [subclassOfInterceptor(compiler),
                                   subclassOfInterceptor(compiler)]);
 
diff --git a/tests/compiler/dart2js/class_codegen2_test.dart b/tests/compiler/dart2js/class_codegen2_test.dart
index 458e1d3..0169e4e 100644
--- a/tests/compiler/dart2js/class_codegen2_test.dart
+++ b/tests/compiler/dart2js/class_codegen2_test.dart
@@ -90,10 +90,10 @@
   // { a: true, }. Make sure this doesn't happen again.
   RegExp danglingComma = new RegExp(r',[ \n]*}');
 
-  asyncStart();
-  Future.forEach([TEST_ONE, TEST_TWO, TEST_THREE, TEST_FOUR], (test) {
+  asyncTest(() => Future.forEach([TEST_ONE, TEST_TWO, TEST_THREE, TEST_FOUR],
+      (test) {
     return compileAll(test).then((generated) {
       Expect.isFalse(danglingComma.hasMatch(generated));
     });
-  }).whenComplete(() => asyncEnd());
+  }));
 }
diff --git a/tests/compiler/dart2js/class_codegen_test.dart b/tests/compiler/dart2js/class_codegen_test.dart
index ed7c90c..9a57c80 100644
--- a/tests/compiler/dart2js/class_codegen_test.dart
+++ b/tests/compiler/dart2js/class_codegen_test.dart
@@ -90,7 +90,7 @@
 
 constructor1() {
   asyncTest(() => compileAll(TEST_FIVE).then((generated) {
-    Expect.isTrue(generated.contains(new RegExp(r"new [$a-z]+\.A\(a\);")));
+    Expect.isTrue(generated.contains(new RegExp(r"new [$A-Z]+\.A\(a\);")));
   }));
 }
 
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 98aeb8a..8af47af 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -29,6 +29,8 @@
 
 import '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
        as types;
+export '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
+       show TypeMask;
 
 import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
 export '../../../sdk/lib/_internal/compiler/implementation/util/util.dart';
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index 9b9da69..a87ffe0 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -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]+\.toString\$0\(a\)')));
+  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
@@ -50,7 +50,7 @@
   // access.
   generated = compile(TEST_THREE, entry: 'foo');
   Expect.isFalse(generated.contains(r'a.get$length()'));
-  Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.A\$\(\)\.length')));
+  Expect.isTrue(generated.contains(new RegExp(r'[$A-Z]+\.A\$\(\)\.length')));
   Expect.isTrue(
-      generated.contains(new RegExp(r'[$a-z]+\.get\$length\$a\(a\)')));
+      generated.contains(new RegExp(r'[$A-Z]+\.get\$length\$a\(a\)')));
 }
diff --git a/tests/compiler/dart2js/mirrors_test.dart b/tests/compiler/dart2js/mirrors_test.dart
index 7051a3b..0d6119b 100644
--- a/tests/compiler/dart2js/mirrors_test.dart
+++ b/tests/compiler/dart2js/mirrors_test.dart
@@ -55,7 +55,7 @@
                        <String>['--preserve-comments']);
   result.then((MirrorSystem mirrors) {
     test(mirrors);
-  }).whenComplete(() => asyncEnd());
+  }).then(asyncSuccess);
 }
 
 void test(MirrorSystem mirrors) {
diff --git a/tests/compiler/dart2js/simple_inferrer_callers_test.dart b/tests/compiler/dart2js/simple_inferrer_callers_test.dart
new file mode 100644
index 0000000..616c819
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_callers_test.dart
@@ -0,0 +1,53 @@
+// 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 computation of callers of an element works when two
+// elements of the same name are being invoked in the same method.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import '../../../sdk/lib/_internal/compiler/implementation/types/types.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart';
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+const String TEST = """
+class A {
+  var field;
+}
+
+class B {
+  var field;
+}
+
+main() {
+  new A().field;
+  new B().field;
+}
+""";
+
+// Create our own type inferrer to avoid clearing out the internal
+// data structures.
+class MyInferrer extends SimpleTypesInferrer {
+  MyInferrer(compiler) : super(compiler);
+  clear() {}
+}
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  var inferrer = new MyInferrer(compiler);
+  compiler.typesTask.typesInferrer = inferrer;
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var mainElement = findElement(compiler, 'main');
+    var classA = findElement(compiler, 'A');
+    var fieldA = classA.lookupLocalMember(buildSourceString('field'));
+    var classB = findElement(compiler, 'B');
+    var fieldB = classB.lookupLocalMember(buildSourceString('field'));;
+
+    Expect.isTrue(inferrer.getCallersOf(fieldA).contains(mainElement));
+    Expect.isTrue(inferrer.getCallersOf(fieldB).contains(mainElement));
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
index 2ea06ba..ef06d96 100644
--- a/tests/compiler/dart2js/simple_inferrer_closure_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_closure_test.dart
@@ -108,13 +108,13 @@
     }
 
     checkReturn('returnInt1', compiler.typesTask.intType);
-    checkReturn('returnInt2', compiler.typesTask.intType.nullable());
+    checkReturn('returnInt2', compiler.typesTask.intType);
     checkReturn('returnInt3', compiler.typesTask.intType);
     checkReturn('returnInt4', compiler.typesTask.intType);
 
-    checkReturn('returnDyn1', compiler.typesTask.dynamicType);
-    checkReturn('returnDyn2', compiler.typesTask.dynamicType);
-    checkReturn('returnDyn3', compiler.typesTask.dynamicType);
+    checkReturn('returnDyn1', compiler.typesTask.dynamicType.nonNullable());
+    checkReturn('returnDyn2', compiler.typesTask.dynamicType.nonNullable());
+    checkReturn('returnDyn3', compiler.typesTask.dynamicType.nonNullable());
     checkReturn('returnNum1', compiler.typesTask.numType);
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
index 45b3878..af06626 100644
--- a/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_no_such_method_test.dart
@@ -21,7 +21,7 @@
   foo() => {};
 }
 
-var a;
+var a = [new B(), new C()][0];
 test1() => new A().foo();
 test2() => a.foo();
 test3() => new B().foo();
@@ -57,7 +57,7 @@
   noSuchMethod(im) => 42.5;
 }
 
-var a;
+var a = [new B(), new C(), new D()][0];
 test1() => a.foo();
 test2() => new B().foo();
 test3() => new C().foo();
diff --git a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
index 427e64d..7a1e29b 100644
--- a/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_postfix_prefix_test.dart
@@ -90,9 +90,9 @@
 
     checkReturnInClass('B', 'returnString1', typesTask.stringType);
     checkReturnInClass('B', 'returnString2', typesTask.stringType);
-    checkReturnInClass('B', 'returnDynamic1', typesTask.dynamicType);
-    checkReturnInClass('B', 'returnDynamic2', typesTask.dynamicType);
-    checkReturnInClass('B', 'returnDynamic3', typesTask.dynamicType);
-    checkReturnInClass('B', 'returnDynamic4', typesTask.dynamicType);
+    checkReturnInClass('B', 'returnDynamic1', const TypeMask.nonNullEmpty());
+    checkReturnInClass('B', 'returnDynamic2', const TypeMask.nonNullEmpty());
+    checkReturnInClass('B', 'returnDynamic3', const TypeMask.nonNullEmpty());
+    checkReturnInClass('B', 'returnDynamic4', const TypeMask.nonNullEmpty());
   }));
 }
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index cfc2a07..9af3822 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -246,6 +246,49 @@
   return (a is int || a is List) ? a : 42;
 }
 
+testIsCheck23(a) {
+  if (a is! int) throw 'foo';
+  return a;
+}
+
+testIsCheck24(a) {
+  if (a is! int) return 42;
+  return a;
+}
+
+testIsCheck25(a) {
+  if (a is int) throw 'foo';
+  return a;
+}
+
+testIsCheck26(a) {
+  if (a is int) {
+  } else {
+    throw 42;
+  }
+  return a;
+}
+
+testIsCheck27(a) {
+  if (a is int) {
+  } else {
+    return 42;
+  }
+  return a;
+}
+
+testIsCheck28(a) {
+  if (a is int) {
+  } else {
+  }
+  return a;
+}
+
+testIsCheck29(a) {
+  if (a is int) {}
+  return a;
+}
+
 testIf1(a) {
   var c = null;
   if (a) {
@@ -559,6 +602,13 @@
   testIsCheck20();
   testIsCheck21(topLevelGetter());
   testIsCheck22(topLevelGetter());
+  testIsCheck23(topLevelGetter());
+  testIsCheck24(topLevelGetter());
+  testIsCheck25(topLevelGetter());
+  testIsCheck26(topLevelGetter());
+  testIsCheck27(topLevelGetter());
+  testIsCheck28(topLevelGetter());
+  testIsCheck29(topLevelGetter());
   testIf1(topLevelGetter());
   testIf2(topLevelGetter());
   returnAsString();
@@ -665,6 +715,13 @@
     checkReturn('testIsCheck20', typesTask.dynamicType.nonNullable());
     checkReturn('testIsCheck21', typesTask.dynamicType);
     checkReturn('testIsCheck22', typesTask.dynamicType);
+    checkReturn('testIsCheck23', intType);
+    checkReturn('testIsCheck24', intType);
+    checkReturn('testIsCheck25', typesTask.dynamicType);
+    checkReturn('testIsCheck26', intType);
+    checkReturn('testIsCheck27', intType);
+    checkReturn('testIsCheck28', typesTask.dynamicType);
+    checkReturn('testIsCheck29', typesTask.dynamicType);
     checkReturn('testIf1', typesTask.intType.nullable());
     checkReturn('testIf2', typesTask.intType.nullable());
     checkReturn('returnAsString',
@@ -730,7 +787,7 @@
 
     checkReturn('testCascade1', typesTask.growableListType);
     checkReturn('testCascade2', new TypeMask.nonNullExact(
-        typesTask.rawTypeOf(findElement(compiler, 'CascadeHelper'))));
+        findElement(compiler, 'CascadeHelper').rawType));
     checkReturn('testSpecialization1', typesTask.numType);
     checkReturn('testSpecialization2', typesTask.dynamicType);
     checkReturn('testSpecialization3', typesTask.intType.nullable());
diff --git a/tests/compiler/dart2js/static_closure_test.dart b/tests/compiler/dart2js/static_closure_test.dart
index 622def2..d08c9f0 100644
--- a/tests/compiler/dart2js/static_closure_test.dart
+++ b/tests/compiler/dart2js/static_closure_test.dart
@@ -18,6 +18,6 @@
     // If this test fail, please take a look at the use of
     // toStringWrapper in captureStackTrace in js_helper.dart.
     Expect.isTrue(code.contains(
-        new RegExp(r'print\([$a-z]+\.main\$closure\);')));
+        new RegExp(r'print\([$A-Z]+\.main\$closure\);')));
   }));
 }
diff --git a/tests/compiler/dart2js/string_add_test.dart b/tests/compiler/dart2js/string_add_test.dart
new file mode 100644
index 0000000..55adbc6
--- /dev/null
+++ b/tests/compiler/dart2js/string_add_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+main() {
+  asyncTest(() => compileAll(
+      r'''main() { return "foo" + "bar"; }''').then((code) {
+    Expect.isTrue(!code.contains(r'$add'));
+  }));
+}
diff --git a/tests/compiler/dart2js/string_interpolation_test.dart b/tests/compiler/dart2js/string_interpolation_test.dart
index 01ea1bb..4cb5f60 100644
--- a/tests/compiler/dart2js/string_interpolation_test.dart
+++ b/tests/compiler/dart2js/string_interpolation_test.dart
@@ -14,6 +14,6 @@
 
   asyncTest(() => compileAll(
       r'''main() { return "foo ${new Object()}"; }''').then((code) {
-    Expect.isFalse(code.contains(r'concat'));
+    Expect.isFalse(code.contains(r'$add'));
   }));
 }
diff --git a/tests/compiler/dart2js/subtype_test.dart b/tests/compiler/dart2js/subtype_test.dart
index 2322ee0..a947ced 100644
--- a/tests/compiler/dart2js/subtype_test.dart
+++ b/tests/compiler/dart2js/subtype_test.dart
@@ -730,4 +730,4 @@
     expect(true, J_U, J_U);
     expect(false, J_U, A_T);
   }));
-}
\ No newline at end of file
+}
diff --git a/tests/compiler/dart2js/type_guard_unuser_test.dart b/tests/compiler/dart2js/type_guard_unuser_test.dart
index 4cad5fd..7df302b 100644
--- a/tests/compiler/dart2js/type_guard_unuser_test.dart
+++ b/tests/compiler/dart2js/type_guard_unuser_test.dart
@@ -47,7 +47,7 @@
   checkNumberOfMatches(matches, 0);
   Expect.isTrue(
       generated.contains(
-          new RegExp(r'return a === true \? [$a-z]+\.foo\(2\) : b;')));
+          new RegExp(r'return a === true \? [$A-Z]+\.foo\(2\) : b;')));
 
   generated = compile(TEST_TWO, entry: 'foo');
   regexp = new RegExp("foo\\(1\\)");
diff --git a/tests/compiler/dart2js/type_variable_bound_test.dart b/tests/compiler/dart2js/type_variable_bound_test.dart
index 5c9b720..6844abb 100644
--- a/tests/compiler/dart2js/type_variable_bound_test.dart
+++ b/tests/compiler/dart2js/type_variable_bound_test.dart
@@ -9,12 +9,36 @@
 
 Future compile(String source) {
   Uri uri = Uri.parse('test:code');
-  var compiler = compilerFor(source, uri);
+  var compiler = compilerFor(source, uri, analyzeOnly: true);
+  compiler.diagnosticHandler = createHandler(compiler, source);
   return compiler.runCompiler(uri).then((_) {
     return compiler;
   });
 }
 
+test(String source, {var errors, var warnings}) {
+  if (errors == null) errors = [];
+  if (errors is! List) errors = [errors];
+  if (warnings == null) warnings = [];
+  if (warnings is! List) warnings = [warnings];
+  asyncTest(() => compile(source).then((compiler) {
+    Expect.equals(!errors.isEmpty, compiler.compilationFailed);
+    Expect.equals(errors.length, compiler.errors.length,
+                  'unexpected error count: ${compiler.errors.length} '
+                  'expected ${errors.length}');
+    Expect.equals(warnings.length, compiler.warnings.length,
+                  'unexpected warning count: ${compiler.warnings.length} '
+                  'expected ${warnings.length}');
+
+    for (int i = 0 ; i < errors.length ; i++) {
+      Expect.equals(errors[i], compiler.errors[i].message.kind);
+    }
+    for (int i = 0 ; i < warnings.length ; i++) {
+      Expect.equals(warnings[i], compiler.warnings[i].message.kind);
+    }
+  }));
+}
+
 test1() {
   asyncTest(() => compile(r"""
 class A<T extends T> {}
@@ -111,9 +135,93 @@
   }));
 }
 
+test5() {
+  test(r"""
+class A<T extends num> {}
+
+void main() {
+  new A();
+  new A<num>();
+  new A<dynamic>();
+  new A<int>();
+  new A<double>();
+}
+""");
+}
+
+test6() {
+  test(r"""
+class A<T extends num> {}
+
+void main() {
+  new A<String>();
+}
+""", warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
+}
+
+test7() {
+  test(r"""
+class A<T extends num> {}
+class B<T> extends A<T> {} // Warning produced here.
+
+void main() {
+  new B(); // No warning produced here.
+  new B<String>(); // No warning produced here.
+}
+""", warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
+}
+
+test8() {
+  test(r"""
+class B<T extends B<T>> {}
+class C<T extends B<T>> extends B<T> {}
+class D<T extends C<T>> extends C<T> {}
+class E<T extends E<T>> extends D<T> {}
+class F extends E<F> {}
+
+void main() {
+  new B();
+  new B<dynamic>();
+  new B<F>();
+  new B<B<F>>();
+  new C();
+  new C<dynamic>();
+  new C<B<F>>();
+  new D();
+  new D<dynamic>();
+  new D<C<F>>();
+  new E();
+  new E<dynamic>();
+  new E<E<F>>();
+  new F();
+}
+""");
+}
+
+test9() {
+  test(r"""
+class B<T extends B<T>> {}
+class C<T extends B<T>> extends B<T> {}
+class D<T extends C<T>> extends C<T> {}
+class E<T extends E<T>> extends D<T> {}
+class F extends E<F> {}
+
+void main() {
+  new D<B<F>>(); // Warning: B<F> is not a subtype of C<T>.
+  new E<D<F>>(); // Warning: E<F> is not a subtype of E<T>.
+}
+""", warnings: [MessageKind.INVALID_TYPE_VARIABLE_BOUND,
+                MessageKind.INVALID_TYPE_VARIABLE_BOUND]);
+}
+
 main() {
   test1();
   test2();
   test3();
   test4();
+  test5();
+  test6();
+  test7();
+  test8();
+  test9();
 }
diff --git a/tests/compiler/dart2js/value_range_test.dart b/tests/compiler/dart2js/value_range_test.dart
index eff5ad8..f14c1de 100644
--- a/tests/compiler/dart2js/value_range_test.dart
+++ b/tests/compiler/dart2js/value_range_test.dart
@@ -11,6 +11,7 @@
 const int KEPT = 3;
 const int ONE_CHECK = 4;
 const int ONE_ZERO_CHECK = 5;
+const int BELOW_ZERO_CHECK = 6;
 
 final List TESTS = [
 """
@@ -197,6 +198,65 @@
 }
 """,
 REMOVED,
+"""
+main(value) {
+  var a = new List(4);
+  var sum = 0;
+  for (int i = 0; i < a.length; i++) {
+    sum += a[i];
+    if (sum == 0) i++;
+  }
+  return sum;
+}
+""",
+REMOVED,
+"""
+main(value) {
+  var a = new List(5);
+  var sum = 0;
+  for (int i = a.length - 1; i >= 0; i--) {
+    sum += a[i];
+    if (sum == 0) i--;
+  }
+  return sum;
+}
+""",
+REMOVED,
+"""
+main(value) {
+  var a = new List(6);
+  var sum = 0;
+  for (int i = 0; i < a.length; i++) {
+    sum += a[i];
+    if (sum == 0) i--;
+  }
+  return sum;
+}
+""",
+BELOW_ZERO_CHECK,
+"""
+main(value) {
+  var a = new List(7);
+  var sum = 0;
+  for (int i = 0; i < a.length;) {
+    sum += a[i];
+    sum == 0 ? i-- : i++;
+  }
+  return sum;
+}
+""",
+BELOW_ZERO_CHECK,
+"""
+main(value) {
+  var a = new List(7);
+  var sum = 0;
+  for (int i = -2; i < a.length; i = 0) {
+    sum += a[i];
+  }
+  return sum;
+}
+""",
+BELOW_ZERO_CHECK,
 ];
 
 // TODO(ahe): It would probably be better if this test used the real
@@ -290,6 +350,11 @@
     case ABOVE_ZERO:
       Expect.isTrue(!generated.contains('< 0'));
       Expect.isTrue(generated.contains('ioore'));
+      break;
+
+    case BELOW_ZERO_CHECK:
+      Expect.isTrue(generated.contains('< 0'));
+      Expect.isTrue(!generated.contains('||'));
       Expect.isTrue(generated.contains('ioore'));
       break;
 
diff --git a/tests/compiler/dart2js_native/abstract_class_test.dart b/tests/compiler/dart2js_native/abstract_class_test.dart
new file mode 100644
index 0000000..6a5989c
--- /dev/null
+++ b/tests/compiler/dart2js_native/abstract_class_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Native classes can have subclasses that are not declared to the program.  The
+// subclasses are indistinguishable from the base class.  This means that
+// abstract native classes can appear to have instances.
+
+abstract class A native "A" {
+}
+
+abstract class B native "B" {
+  foo() native;
+}
+
+class C {}
+
+makeA() native;
+makeB() native;
+
+void setup() native """
+// This code is all inside 'setup' and so not accesible from the global scope.
+function A(){}
+function B(){}
+B.prototype.foo = function() { return 'B.foo'; };
+makeA = function(){return new A};
+makeB = function(){return new B};
+""";
+
+var inscrutable;
+main() {
+  setup();
+  inscrutable = (x) => x;
+  inscrutable = inscrutable(inscrutable);
+
+  var a = makeA();
+  var b = makeB();
+  var c = inscrutable(new C());
+
+  Expect.isTrue(a is A);
+  Expect.isFalse(b is A);
+  Expect.isFalse(c is A);
+
+  Expect.isFalse(a is B);
+  Expect.isTrue(b is B);
+  Expect.isFalse(c is B);
+
+  Expect.isFalse(a is C);
+  Expect.isFalse(b is C);
+  Expect.isTrue(c is C);
+
+  Expect.equals('B.foo', b.foo());
+}
diff --git a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
index 3090172..5e4e0c3 100644
--- a/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
+++ b/tests/compiler/dart2js_native/native_class_avoids_hidden_name_frog_test.dart
@@ -6,14 +6,14 @@
 
 // Test that hidden native class names are not used by generated code.
 
-class A native "B" {
-  get name => 'A';
-  static A create() => makeA();
+class AA native "BB" {
+  get name => 'AA';
+  static AA create() => makeA();
 }
 
-class B native "C" {
-  get name => 'B';
-  static B create() => makeB();
+class BB native "C" {
+  get name => 'BB';
+  static BB create() => makeB();
 }
 
 class C {  // Ordinary class with name clashing with native class.
@@ -25,18 +25,18 @@
 makeB() native;
 
 void setup1() native """
-// Poison hidden native names 'B' and 'C' to prove the compiler didn't place
+// Poison hidden native names 'BB' and 'C' to prove the compiler didn't place
 // anthing on the hidden native class.
-B = null;
+BB = null;
 C = null;
 """;
 
 void setup2() native """
 // This code is all inside 'setup' and so not accesible from the global scope.
-function B(){}
+function BB(){}
 function C(){}
-makeA = function(){return new B};  // A is "*B"
-makeB = function(){return new C};  // B is "*C"
+makeA = function(){return new BB};  // AA is "*BB"
+makeB = function(){return new C};  // BB is "*C"
 """;
 
 int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
@@ -45,12 +45,12 @@
   setup1();
   setup2();
 
-  var things = [A.create(), B.create(), C.create()];
+  var things = [AA.create(), BB.create(), C.create()];
   var a = things[inscrutable(0)];
   var b = things[inscrutable(1)];
   var c = things[inscrutable(2)];
 
-  Expect.equals('A', a.name);
-  Expect.equals('B', b.name);
+  Expect.equals('AA', a.name);
+  Expect.equals('BB', b.name);
   Expect.equals('C', c.name);
 }
diff --git a/tests/compiler/dart2js_native/subclassing_type_test.dart b/tests/compiler/dart2js_native/subclassing_type_test.dart
new file mode 100644
index 0000000..34748bf
--- /dev/null
+++ b/tests/compiler/dart2js_native/subclassing_type_test.dart
@@ -0,0 +1,145 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:_js_helper' show Creates, setNativeSubclassDispatchRecord;
+import 'dart:_interceptors' show Interceptor, findInterceptorForType;
+
+// Test that type checks and casts work for subclasses of native classes and
+// mixins on native classes.
+
+class M {}
+
+class N native "N" {}
+
+class A extends N {}
+
+class B extends A with M {       // native mixin application.
+}
+
+class C extends Object with M {  // non-native mixin application.
+}
+
+B makeB() native;
+
+@Creates('=Object')
+getBPrototype() native;
+
+void setup() native r"""
+function B() {}
+makeB = function(){return new B;};
+
+getBPrototype = function(){return B.prototype;};
+""";
+
+A gA;
+B gB;
+C gC;
+M gM;
+
+isA(x) => x is A;
+asA(x) => x as A;
+setA(x) => gA = x;
+
+isB(x) => x is B;
+asB(x) => x as B;
+setB(x) => gB = x;
+
+isC(x) => x is C;
+asC(x) => x as C;
+setC(x) => gC = x;
+
+isM(x) => x is M;
+asM(x) => x as M;
+setM(x) => gM = x;
+
+checkTrue(f) => (x) { Expect.isTrue(f(x)); };
+checkFalse(f) => (x) { Expect.isFalse(f(x)); };
+checkId(f) => (x) { Expect.identical(x, f(x)); };
+checkThrows(f) => (x) { Expect.throws(() => f(x)); };
+
+bool get checkedMode {
+  try {
+    setA(1);
+    gA = null;
+    return false;
+  } catch (e) {
+    return true;
+  }
+}
+
+main() {
+  setup();
+
+  setNativeSubclassDispatchRecord(getBPrototype(), findInterceptorForType(B));
+
+  B b = makeB();
+  C c = new C();
+
+
+  checkFalse(isA)(1);
+  checkFalse(isB)(1);
+  checkFalse(isC)(1);
+  checkFalse(isM)(1);
+
+  checkTrue(isA)(b);
+  checkTrue(isB)(b);
+  checkTrue(isM)(b);
+  checkFalse(isC)(b);
+
+  checkTrue(isC)(c);
+  checkTrue(isM)(c);
+  checkFalse(isA)(c);
+  checkFalse(isB)(c);
+
+
+  checkThrows(asA)(1);
+  checkThrows(asB)(1);
+  checkThrows(asC)(1);
+  checkThrows(asM)(1);
+
+  checkId(asA)(b);
+  checkId(asB)(b);
+  checkId(asM)(b);
+  checkThrows(asC)(b);
+
+  checkId(asC)(c);
+  checkId(asM)(c);
+  checkThrows(asA)(c);
+  checkThrows(asB)(c);
+
+
+  if (checkedMode) {
+    checkThrows(setA)(1);
+    checkThrows(setB)(1);
+    checkThrows(setC)(1);
+    checkThrows(setM)(1);
+
+    checkId(setA)(b);
+    checkId(setB)(b);
+    checkId(setM)(b);
+    checkThrows(setC)(b);
+
+    checkId(setC)(c);
+    checkId(setM)(c);
+    checkThrows(setA)(c);
+    checkThrows(setB)(c);
+
+    // One of the above assignments had a value of the correct type.
+    Expect.isNotNull(gA);
+    Expect.isNotNull(gB);
+    Expect.isNotNull(gC);
+    Expect.isNotNull(gM);
+
+    checkId(setA)(null);
+    checkId(setB)(null);
+    checkId(setC)(null);
+    checkId(setM)(null);
+
+    Expect.isNull(gA);
+    Expect.isNull(gB);
+    Expect.isNull(gC);
+    Expect.isNull(gM);
+  }
+}
diff --git a/tests/corelib/bit_twiddling_bigint_test.dart b/tests/corelib/bit_twiddling_bigint_test.dart
new file mode 100644
index 0000000..042f7b8
--- /dev/null
+++ b/tests/corelib/bit_twiddling_bigint_test.dart
@@ -0,0 +1,61 @@
+// 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.
+// Testing Bigints.
+
+library bit_twiddling_test;
+import "package:expect/expect.dart";
+
+// See bit_twiddling_test.dart first.  This file contains only the tests that
+// need Bigint or would fail in dart2js compatibility mode.
+
+testBitLength() {
+  check(int i, width) {
+    Expect.equals(width, i.bitLength, '$i.bitLength ==  $width');
+    // (~i) written as (-i-1) to avoid issues with limited range of dart2js ops.
+    Expect.equals(width, (-i-1).bitLength, '(~$i).bitLength == $width');
+  }
+
+  check(0xffffffffffffff, 56);
+  check(0xffffffffffffffff, 64);
+  check(0xffffffffffffffffff, 72);
+  check(0x1000000000000000000, 73);
+  check(0x1000000000000000001, 73);
+
+
+  check(0xfffffffffffffffffffffffffffffffffffffe, 152);
+  check(0xffffffffffffffffffffffffffffffffffffff, 152);
+  check(0x100000000000000000000000000000000000000, 153);
+  check(0x100000000000000000000000000000000000001, 153);
+}
+
+testToUnsigned() {
+  checkU(src, width, expected) {
+    Expect.equals(expected, src.toUnsigned(width));
+  }
+
+  checkU(0x100000100000000000001, 2, 1);
+  checkU(0x100000200000000000001, 60, 0x200000000000001);
+  checkU(0x100000200000000000001, 59, 0x200000000000001);
+  checkU(0x100000200000000000001, 58, 0x200000000000001);
+  checkU(0x100000200000000000001, 57, 1);
+}
+
+testToSigned() {
+  checkS(src, width, expected) {
+    Expect.equals(expected, src.toSigned(width),
+        '$src.toSigned($width) == $expected');
+  }
+
+  checkS(0x100000100000000000001, 2, 1);
+  checkS(0x100000200000000000001, 60,  0x200000000000001);
+  checkS(0x100000200000000000001, 59,  0x200000000000001);
+  checkS(0x100000200000000000001, 58, -0x200000000000000 + 1);
+  checkS(0x100000200000000000001, 57,  1);
+}
+
+main() {
+  testBitLength();
+  testToUnsigned();
+  testToSigned();
+}
diff --git a/tests/corelib/bit_twiddling_test.dart b/tests/corelib/bit_twiddling_test.dart
new file mode 100644
index 0000000..92dafac
--- /dev/null
+++ b/tests/corelib/bit_twiddling_test.dart
@@ -0,0 +1,175 @@
+// 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.
+// Testing Bigints.
+
+library bit_twiddling_test;
+import "package:expect/expect.dart";
+
+
+bool haveBigints() {
+  return 100000000000000000000 + 1 != 100000000000000000000;
+}
+
+testBitLength() {
+  check(int i, width) {
+    Expect.equals(width, i.bitLength, '$i.bitLength ==  $width');
+    // (~i) written as (-i-1) to avoid issues with limited range of dart2js ops.
+    Expect.equals(width, (-i-1).bitLength, '(~$i).bitLength == $width');
+  }
+
+  check(0, 0);
+  check(1, 1);
+  check(2, 2);
+  check(3, 2);
+  check(4, 3);
+  check(5, 3);
+  check(6, 3);
+  check(7, 3);
+  check(8, 4);
+  check(127, 7);
+  check(128, 8);
+  check(129, 8);
+  check(2147483646, 31);
+  check(2147483647, 31);
+  check(2147483648, 32);
+  check(2147483649, 32);
+  check(4294967295, 32);
+  check(4294967296, 33);
+  check(0xffffffffff, 40);
+  check(0xfffffffffff, 44);
+  check(0xffffffffffff, 48);
+  check(0x1000000000000, 49);
+  check(0x1000000000001, 49);
+  check(0x1ffffffffffff, 49);
+  check(0x2000000000000, 50);
+  check(0x2000000000001, 50);
+
+  if (haveBigints()) {
+    check(0xffffffffffffff, 56);
+    check(0xffffffffffffffff, 64);
+    check(0xffffffffffffffffff, 72);
+    check(0x1000000000000000000, 73);
+    check(0x1000000000000000001, 73);
+
+
+    check(0xfffffffffffffffffffffffffffffffffffffe, 152);
+    check(0xffffffffffffffffffffffffffffffffffffff, 152);
+    check(0x100000000000000000000000000000000000000, 153);
+    check(0x100000000000000000000000000000000000001, 153);
+
+  }
+}
+
+testToUnsigned() {
+  checkU(src, width, expected) {
+    Expect.equals(expected, src.toUnsigned(width));
+  }
+
+  checkU(1, 8, 1);
+  checkU(0xff, 8, 0xff);
+  checkU(0xffff, 8, 0xff);
+  checkU(-1, 8, 0xff);
+  checkU(0xffffffff, 32, 0xffffffff);
+
+  checkU(0x7fffffff, 30, 0x3fffffff);
+  checkU(0x7fffffff, 31, 0x7fffffff);
+  checkU(0x7fffffff, 32, 0x7fffffff);
+  checkU(0x80000000, 30, 0);
+  checkU(0x80000000, 31, 0);
+  checkU(0x80000000, 32, 0x80000000);
+  checkU(0xffffffff, 30, 0x3fffffff);
+  checkU(0xffffffff, 31, 0x7fffffff);
+  checkU(0xffffffff, 32, 0xffffffff);
+  checkU(0x100000000, 30, 0);
+  checkU(0x100000000, 31, 0);
+  checkU(0x100000000, 32, 0);
+  checkU(0x1ffffffff, 30, 0x3fffffff);
+  checkU(0x1ffffffff, 31, 0x7fffffff);
+  checkU(0x1ffffffff, 32, 0xffffffff);
+
+  checkU(-1, 0, 0);
+  checkU( 0, 0, 0);
+  checkU( 1, 0, 0);
+  checkU( 2, 0, 0);
+  checkU( 3, 0, 0);
+
+  checkU(-1, 1, 1);
+  checkU( 0, 1, 0);
+  checkU( 1, 1, 1);
+  checkU( 2, 1, 0);
+  checkU( 3, 1, 1);
+  checkU( 4, 1, 0);
+
+  checkU(-1, 2, 3);
+  checkU( 0, 2, 0);
+  checkU( 1, 2, 1);
+  checkU( 2, 2, 2);
+  checkU( 3, 2, 3);
+  checkU( 4, 2, 0);
+
+  checkU(-1, 3, 7);
+  checkU( 0, 3, 0);
+  checkU( 1, 3, 1);
+  checkU( 2, 3, 2);
+  checkU( 3, 3, 3);
+  checkU( 4, 3, 4);
+}
+
+testToSigned() {
+  checkS(src, width, expected) {
+    Expect.equals(expected, src.toSigned(width),
+        '$src.toSigned($width) == $expected');
+  }
+
+  checkS(1, 8, 1);
+  checkS(0xff, 8, -1);
+  checkS(0xffff, 8, -1);
+  checkS(-1, 8, -1);
+  checkS(128, 8, -128);
+  checkS(0xffffffff, 32, -1);
+
+  checkS(0x7fffffff, 30, -1);
+  checkS(0x7fffffff, 31, -1);
+  checkS(0x7fffffff, 32, 0x7fffffff);
+  checkS(0x80000000, 30, 0);
+  checkS(0x80000000, 31, 0);
+  checkS(0x80000000, 32, -2147483648);
+  checkS(0xffffffff, 30, -1);
+  checkS(0xffffffff, 31, -1);
+  checkS(0xffffffff, 32, -1);
+
+  checkS(0x100000000, 30, 0);
+  checkS(0x100000000, 31, 0);
+  checkS(0x100000000, 32, 0);
+  checkS(0x1ffffffff, 30, -1);
+  checkS(0x1ffffffff, 31, -1);
+  checkS(0x1ffffffff, 32, -1);
+
+  checkS(-1, 1, -1);
+  checkS( 0, 1,  0);
+  checkS( 1, 1, -1);  // The only bit is the sign bit.
+  checkS( 2, 1,  0);
+  checkS( 3, 1, -1);
+  checkS( 4, 1,  0);
+
+  checkS(-1, 2, -1);
+  checkS( 0, 2,  0);
+  checkS( 1, 2,  1);
+  checkS( 2, 2, -2);
+  checkS( 3, 2, -1);
+  checkS( 4, 2,  0);
+
+  checkS(-1, 3, -1);
+  checkS( 0, 3,  0);
+  checkS( 1, 3,  1);
+  checkS( 2, 3,  2);
+  checkS( 3, 3,  3);
+  checkS( 4, 3, -4);
+}
+
+main() {
+  testBitLength();
+  testToUnsigned();
+  testToSigned();
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 186f01e..e46b59f 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -41,6 +41,7 @@
 error_stack_trace1_test: Fail # Issue 12399
 
 big_integer_vm_test: Fail, OK # VM specific test.
+bit_twiddling_bigint_test: Fail # Requires bigint support.
 compare_to2_test: Fail, OK    # Requires bigint support.
 string_base_vm_test: Fail, OK # VM specific test.
 
@@ -102,4 +103,4 @@
 collection_length_test: Pass, Timeout
 
 [ $arch == simmips && $mode == debug ]
-collection_to_string_test: Pass, Crash # Issue: 11207
\ No newline at end of file
+collection_to_string_test: Pass, Crash # Issue: 11207
diff --git a/tests/corelib/map_test.dart b/tests/corelib/map_test.dart
index c9ba29f..a700027 100644
--- a/tests/corelib/map_test.dart
+++ b/tests/corelib/map_test.dart
@@ -33,6 +33,8 @@
   testNumericKeys(new HashMap<num, String>(equals: identical));
   testNumericKeys(new LinkedHashMap());
   testNumericKeys(new LinkedHashMap<num, String>());
+  testNumericKeys(new LinkedHashMap(equals: identical));
+  testNumericKeys(new LinkedHashMap<num, String>(equals: identical));
 
   testNaNKeys(new Map());
   testNaNKeys(new Map<num, String>());
@@ -44,10 +46,40 @@
   // NaN is not equal to NaN.
 
   testIdentityMap(new HashMap(equals: identical));
+  testIdentityMap(new LinkedHashMap(equals: identical));
 
-  testCustomMap(new HashMap(equals: myEquals, hashCode: myHashCode));
+  testCustomMap(new HashMap(equals: myEquals, hashCode: myHashCode,
+                            isValidKey: (v) => v is Customer));
+  testCustomMap(new LinkedHashMap(equals: myEquals, hashCode: myHashCode,
+                                  isValidKey: (v) => v is Customer));
+  testCustomMap(new HashMap<Customer,dynamic>(equals: myEquals,
+                                              hashCode: myHashCode));
+
+  testCustomMap(new LinkedHashMap<Customer,dynamic>(equals: myEquals,
+                                                    hashCode: myHashCode));
 
   testIterationOrder(new LinkedHashMap());
+  testIterationOrder(new LinkedHashMap(equals: identical));
+
+  testOtherKeys(new SplayTreeMap<int, int>());
+  testOtherKeys(new SplayTreeMap<int, int>((int a, int b) => a - b,
+                                           (v) => v is int));
+  testOtherKeys(new SplayTreeMap((int a, int b) => a - b,
+                                 (v) => v is int));
+  testOtherKeys(new HashMap<int, int>());
+  testOtherKeys(new HashMap<int, int>(equals: identical));
+  testOtherKeys(new HashMap<int, int>(hashCode: (v) => v.hashCode,
+                                      isValidKey: (v) => v is int));
+  testOtherKeys(new HashMap(equals: (int x, int y) => x == y,
+                            hashCode: (int v) => v.hashCode,
+                            isValidKey: (v) => v is int));
+  testOtherKeys(new LinkedHashMap<int, int>());
+  testOtherKeys(new LinkedHashMap<int, int>(equals: identical));
+  testOtherKeys(new LinkedHashMap<int, int>(hashCode: (v) => v.hashCode,
+                                       isValidKey: (v) => v is int));
+  testOtherKeys(new LinkedHashMap(equals: (int x, int y) => x == y,
+                                  hashCode: (int v) => v.hashCode,
+                                  isValidKey: (v) => v is int));
 }
 
 
@@ -642,9 +674,26 @@
 int myHashCode(Customer c) => c.secondId;
 bool myEquals(Customer a, Customer b) => a.secondId == b.secondId;
 
-testIterationOrder(Map map) {
+void testIterationOrder(Map map) {
   var order = [0, 6, 4, 2, 7, 9, 7, 1, 2, 5, 3];
   for (int i = 0; i < order.length; i++) map[order[i]] = i;
   Expect.listEquals(map.keys.toList(), [0, 6, 4, 2, 7, 9, 1, 5, 3]);
   Expect.listEquals(map.values.toList(), [0, 1, 2, 8, 6, 5, 7, 9, 10]);
 }
+
+void testOtherKeys(Map<int, int> map) {
+  // Test that non-int keys are allowed in containsKey/remove/lookup.
+  // Custom hash sets and tree sets must be constructed so they don't
+  // use the equality/comparator on incompatible objects.
+
+  // This should not throw in either checked or unchecked mode.
+  map[0] = 0;
+  map[1] = 1;
+  map[2] = 2;
+  Expect.isFalse(map.containsKey("not an int"));
+  Expect.isFalse(map.containsKey(1.5));
+  Expect.isNull(map.remove("not an int"));
+  Expect.isNull(map.remove(1.5));
+  Expect.isNull(map["not an int"]);
+  Expect.isNull(map[1.5]);
+}
diff --git a/tests/corelib/uri_http_test.dart b/tests/corelib/uri_http_test.dart
index 354e052..95614f7 100644
--- a/tests/corelib/uri_http_test.dart
+++ b/tests/corelib/uri_http_test.dart
@@ -31,6 +31,8 @@
   check(new Uri.http("host", "/a/b", { "c": "d" }), "http://host/a/b?c=d");
   check(new Uri.http("host",
                      "/a/b", { "c=": "&d" }), "http://host/a/b?c%3D=%26d");
+  check(new Uri.http("[::]", "a"), "http://[::]/a");
+  check(new Uri.http("[::127.0.0.1]", "a"), "http://[::127.0.0.1]/a");
 }
 
 testHttpsUri() {
@@ -60,6 +62,8 @@
   check(new Uri.https("host", "/a/b", { "c": "d" }), "https://host/a/b?c=d");
   check(new Uri.https("host",
                       "/a/b", { "c=": "&d" }), "https://host/a/b?c%3D=%26d");
+  check(new Uri.https("[::]", "a"), "https://[::]/a");
+  check(new Uri.https("[::127.0.0.1]", "a"), "https://[::127.0.0.1]/a");
 }
 
 main() {
diff --git a/tests/corelib/uri_ipv4_test.dart b/tests/corelib/uri_ipv4_test.dart
new file mode 100644
index 0000000..e04b675
--- /dev/null
+++ b/tests/corelib/uri_ipv4_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+void testParseIPv4Address() {
+  void pass(String host, List<int> out) {
+    Expect.listEquals(Uri.parseIPv4Address(host), out);
+  }
+  void fail(String host) {
+    Expect.throws(() => Uri.parseIPv4Address(host),
+                  (e) => e is FormatException);
+  }
+
+  pass('127.0.0.1', [127, 0, 0, 1]);
+  pass('128.0.0.1', [128, 0, 0, 1]);
+  pass('255.255.255.255', [255, 255, 255, 255]);
+  pass('0.0.0.0', [0, 0, 0, 0]);
+  fail('127.0.0.-1');
+  fail('255.255.255.256');
+  fail('0.0.0.0.');
+  fail('0.0.0.0.0');
+  fail('a.0.0.0');
+  fail('0.0..0');
+}
+
+void main() {
+  testParseIPv4Address();
+}
diff --git a/tests/corelib/uri_ipv6_test.dart b/tests/corelib/uri_ipv6_test.dart
index 1ec9d57..0f3ba03 100644
--- a/tests/corelib/uri_ipv6_test.dart
+++ b/tests/corelib/uri_ipv6_test.dart
@@ -28,7 +28,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('/index.html', uri.path);
   Expect.equals('http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html',
                 uri.toString());
@@ -37,7 +37,7 @@
   uri = Uri.parse(path);
   Expect.equals('https', uri.scheme);
   Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(443, uri.port);
   Expect.equals('/index.html', uri.path);
   Expect.equals('https://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/index.html',
                 uri.toString());
@@ -46,7 +46,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('1080:0:0:0:8:800:200C:417A', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('/index.html', uri.path);
   Expect.equals(path, uri.toString());
 
@@ -54,7 +54,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('3ffe:2a00:100:7031::1', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('', uri.path);
   Expect.equals(path, uri.toString());
 
@@ -62,7 +62,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('1080::8:800:200C:417A', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('/foo', uri.path);
   Expect.equals(path, uri.toString());
 
@@ -70,7 +70,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('::192.9.5.5', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('/ipng', uri.path);
   Expect.equals(path, uri.toString());
 
@@ -86,7 +86,7 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('::FFFF:129.144.52.38', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('/index.html', uri.path);
   Expect.equals('http://[::FFFF:129.144.52.38]/index.html', uri.toString());
 
@@ -94,7 +94,7 @@
   uri = Uri.parse(path);
   Expect.equals('https', uri.scheme);
   Expect.equals('::FFFF:129.144.52.38', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(443, uri.port);
   Expect.equals('/index.html', uri.path);
   Expect.equals('https://[::FFFF:129.144.52.38]/index.html', uri.toString());
 
@@ -102,12 +102,50 @@
   uri = Uri.parse(path);
   Expect.equals('http', uri.scheme);
   Expect.equals('2010:836B:4179::836B:4179', uri.host);
-  Expect.equals(0, uri.port);
+  Expect.equals(80, uri.port);
   Expect.equals('', uri.path);
   Expect.equals(path, uri.toString());
 }
 
+
+void testParseIPv6Address() {
+  void pass(String host, List<int> expected) {
+    Expect.listEquals(expected, Uri.parseIPv6Address(host));
+  }
+  void fail(String host) {
+    Expect.throws(() => Uri.parseIPv6Address(host),
+                  (e) => e is FormatException);
+  }
+
+  pass('::127.0.0.1', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]);
+  pass('0::127.0.0.1', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]);
+  pass('::', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  pass('0::', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+  fail(':0::127.0.0.1');
+  fail('0:::');
+  fail(':::');
+  fail('::0:');
+  fail('::0::');
+  fail('::0::0');
+  fail('00000::0');
+  fail('-1::0');
+  fail('-AAA::0');
+  fail('0::127.0.0.1:0');
+  fail('0::127.0.0');
+  pass('0::1111', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17]);
+  pass('2010:836B:4179::836B:4179',
+       [32, 16, 131, 107, 65, 121, 0, 0, 0, 0, 0, 0, 131, 107, 65, 121] );
+  fail('2010:836B:4179:0000:127.0.0.1');
+  fail('2010:836B:4179:0000:0000:127.0.0.1');
+  fail('2010:836B:4179:0000:0000:0000::127.0.0.1');
+  fail('2010:836B:4179:0000:0000:0000:0000:127.0.0.1');
+  pass('2010:836B:4179:0000:0000:0000:127.0.0.1',
+       [32, 16, 131, 107, 65, 121, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1] );
+}
+
+
 void main() {
   testValidIpv6Uri();
+  testParseIPv6Address();
 }
 
diff --git a/tests/corelib/uri_path_test.dart b/tests/corelib/uri_path_test.dart
index d1804f9..6274e8b 100644
--- a/tests/corelib/uri_path_test.dart
+++ b/tests/corelib/uri_path_test.dart
@@ -47,12 +47,9 @@
 
     var uri1 = new Uri(pathSegments: segments);
     var uri2 = new Uri(path: path);
-    var uri3 = Uri.parse(path);
     check(uri1);
     check(uri2);
-    check(uri3);
-    Expect.equals(uri1, uri3);
-    Expect.equals(uri2, uri3);
+    Expect.equals(uri1, uri2);
   }
 
   test("", []);
diff --git a/tests/corelib/uri_scheme_test.dart b/tests/corelib/uri_scheme_test.dart
index 2a7fd76..2565e70 100644
--- a/tests/corelib/uri_scheme_test.dart
+++ b/tests/corelib/uri_scheme_test.dart
@@ -7,6 +7,8 @@
 void testInvalidArguments() {
   Expect.throws(() => new Uri(scheme: "_"), (e) => e is ArgumentError);
   Expect.throws(() => new Uri(scheme: "http_s"), (e) => e is ArgumentError);
+  Expect.throws(() => new Uri(scheme: "127.0.0.1:80"),
+                (e) => e is ArgumentError);
 }
 
 void testScheme() {
@@ -21,6 +23,7 @@
   test("http+ssl", "http+ssl:", "HTTP+ssl");
   test("urn", "urn:", "urn");
   test("urn", "urn:", "UrN");
+  test("a123.432", "a123.432:", "a123.432");
 }
 
 main() {
diff --git a/tests/html/custom/constructor_calls_created_synchronously_test.dart b/tests/html/custom/constructor_calls_created_synchronously_test.dart
index 77b5446..f383a7a 100644
--- a/tests/html/custom/constructor_calls_created_synchronously_test.dart
+++ b/tests/html/custom/constructor_calls_created_synchronously_test.dart
@@ -18,12 +18,26 @@
   }
 }
 
+loadPolyfills() {
+  if (!document.supportsRegister) {
+    // Cache blocker is a workaround for:
+    // https://code.google.com/p/dart/issues/detail?id=11834
+    var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+    return HttpRequest.getString('/root_dart/pkg/custom_element/lib/'
+      'custom-elements.debug.js?cacheBlock=$cacheBlocker').then((code) {
+      document.head.children.add(new ScriptElement()..text = code);
+    });
+  }
+}
+
 main() {
   useHtmlConfiguration();
 
   // Adapted from Blink's
   // fast/dom/custom/constructor-calls-created-synchronously test.
 
+  setUp(loadPolyfills);
+
   test('createdCallback', () {
     document.register(A.tag, A);
     var x = new A();
diff --git a/tests/html/custom/created_callback_test.dart b/tests/html/custom/created_callback_test.dart
index 1265b51..00848c4 100644
--- a/tests/html/custom/created_callback_test.dart
+++ b/tests/html/custom/created_callback_test.dart
@@ -54,12 +54,26 @@
   }
 }
 
+loadPolyfills() {
+  if (!document.supportsRegister) {
+    // Cache blocker is a workaround for:
+    // https://code.google.com/p/dart/issues/detail?id=11834
+    var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+    return HttpRequest.getString('/root_dart/pkg/custom_element/lib/'
+      'custom-elements.debug.js?cacheBlock=$cacheBlocker').then((code) {
+      document.head.children.add(new ScriptElement()..text = code);
+    });
+  }
+}
+
 main() {
   useHtmlConfiguration();
 
   // Adapted from Blink's
   // fast/dom/custom/created-callback test.
 
+  setUp(loadPolyfills);
+
   test('transfer created callback', () {
     document.register(A.tag, A);
     var x = new A();
@@ -79,6 +93,8 @@
 <x-b id="w"></x-b>
 """, treeSanitizer: new NullTreeSanitizer());
 
+    Platform.upgradeCustomElements(div);
+
     expect(C.createdInvocations, 2);
     expect(div.query('#w') is B, isTrue);
   });
diff --git a/tests/html/custom/document_register_basic_test.dart b/tests/html/custom/document_register_basic_test.dart
index eb91447..6934a47 100644
--- a/tests/html/custom/document_register_basic_test.dart
+++ b/tests/html/custom/document_register_basic_test.dart
@@ -37,11 +37,25 @@
   factory BadE() => new Element.tag(tag);
 }
 
+loadPolyfills() {
+  if (!document.supportsRegister) {
+    // Cache blocker is a workaround for:
+    // https://code.google.com/p/dart/issues/detail?id=11834
+    var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+    return HttpRequest.getString('/root_dart/pkg/custom_element/lib/'
+      'custom-elements.debug.js?cacheBlock=$cacheBlocker').then((code) {
+      document.head.children.add(new ScriptElement()..text = code);
+    });
+  }
+}
+
 main() {
   useHtmlConfiguration();
 
   // Adapted from Blink's fast/dom/custom/document-register-basic test.
 
+  setUp(loadPolyfills);
+
   test('Testing document.register() basic behaviors', () {
     document.register(Foo.tag, Foo);
 
@@ -86,6 +100,7 @@
     document.body.append(container);
     container.setInnerHtml("<x-foo></x-foo>",
         treeSanitizer: new NullTreeSanitizer());
+    Platform.upgradeCustomElements(container);
     var parsedFoo = container.firstChild;
 
     expect(parsedFoo is Foo, isTrue);
@@ -121,6 +136,7 @@
 
     container.setInnerHtml("<X-BAR></X-BAR><X-Bar></X-Bar>",
         treeSanitizer: new NullTreeSanitizer());
+    Platform.upgradeCustomElements(container);
     expect(container.firstChild is Bar, isTrue);
     expect(container.firstChild.tagName, "X-BAR");
     expect(container.lastChild is Bar, isTrue);
diff --git a/tests/html/custom/document_register_type_extensions_test.dart b/tests/html/custom/document_register_type_extensions_test.dart
index ec4bd17..cae07a1 100644
--- a/tests/html/custom/document_register_type_extensions_test.dart
+++ b/tests/html/custom/document_register_type_extensions_test.dart
@@ -4,37 +4,56 @@
 
 library document_register_type_extensions_test;
 import 'package:unittest/unittest.dart';
-import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
 import 'dart:html';
 import '../utils.dart';
 
 class Foo extends HtmlElement {
-  static final tag = 'x-foo';
+  static const tag = 'x-foo';
+  static final List outerHtmlStrings = [
+    '<x-foo></x-foo>',
+    '<?XML:NAMESPACE PREFIX = PUBLIC NS = "URN:COMPONENT" /><x-foo></x-foo>'];
   factory Foo() => new Element.tag(tag);
 }
 
 class Bar extends InputElement {
-  static final tag = 'x-bar';
-  factory Bar() => document.$dom_createElement('input', tag);
+  static const tag = 'x-bar';
+  static const outerHtmlString = '<input is="x-bar">';
+  factory Bar() => new Element.tag('input', tag);
 }
 
 class Baz extends Foo {
-  static final tag = 'x-baz';
+  static const tag = 'x-baz';
+  static final List outerHtmlStrings = [
+      '<x-baz></x-baz>',
+      '<?XML:NAMESPACE PREFIX = PUBLIC NS = "URN:COMPONENT" /><x-baz></x-baz>'];
   factory Baz() => new Element.tag(tag);
 }
 
 class Qux extends Bar {
-  static final tag = 'x-qux';
-  factory Qux() => document.$dom_createElement('input', tag);
+  static const tag = 'x-qux';
+  factory Qux() => new Element.tag('input', tag);
 }
 
 class FooBad extends DivElement {
-  static final tag = 'x-foo';
-  factory FooBad() => document.$dom_createElement('div', tag);
+  static const tag = 'x-foo';
+  factory FooBad() => new Element.tag('div', tag);
+}
+
+loadPolyfills() {
+  if (!document.supportsRegister) {
+    // Cache blocker is a workaround for:
+    // https://code.google.com/p/dart/issues/detail?id=11834
+    var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
+    return HttpRequest.getString('/root_dart/pkg/custom_element/lib/'
+      'custom-elements.debug.js?cacheBlock=$cacheBlocker').then((code) {
+      document.head.children.add(new ScriptElement()..text = code);
+    });
+  }
 }
 
 main() {
-  useHtmlConfiguration();
+  useHtmlIndividualConfiguration();
 
   // Adapted from Blink's fast/dom/custom/document-register-type-extension test.
 
@@ -46,154 +65,203 @@
     return element.form == testForm;
   };
 
-  test('construction', () {
+  var registeredTypes = false;
+  void registerTypes() {
+    if (registeredTypes) {
+      return;
+    }
+    registeredTypes = true;
     document.register(Foo.tag, Foo);
     document.register(Bar.tag, Bar);
     document.register(Baz.tag, Baz);
     document.register(Qux.tag, Qux);
+  }
 
-    expect(() => document.register(FooBad.tag, Foo), throws);
+  setUp(loadPolyfills);
 
-    // Constructors
+  group('construction', () {
+    setUp(registerTypes);
 
-    var fooNewed = new Foo();
-    var fooOuterHtml = "<x-foo></x-foo>";
-    expect(fooNewed.outerHtml, fooOuterHtml);
-    expect(fooNewed is Foo, isTrue);
-    expect(fooNewed is HtmlElement, isTrue);
-    expect(fooNewed is UnknownElement, isFalse);
+    test('cannot register twice', () {
+      expect(() => document.register(FooBad.tag, Foo), throws);
+    });
 
-    var barNewed = new Bar();
-    var barOuterHtml = '<input is="x-bar">';
-    expect(barNewed.outerHtml, barOuterHtml);
-    expect(barNewed is Bar, isTrue);
-    expect(barNewed is InputElement, isTrue);
-    expect(isFormControl(barNewed), isTrue);
+    group('constructors', () {
 
-    var bazNewed = new Baz();
-    var bazOuterHtml = "<x-baz></x-baz>";
-    expect(bazNewed.outerHtml, bazOuterHtml);
-    expect(bazNewed is Baz, isTrue);
-    expect(bazNewed is HtmlElement, isTrue);
-    expect(bazNewed is UnknownElement, isFalse);
+      test('custom tag', () {
+        var fooNewed = new Foo();
+        expect(fooNewed.outerHtml, anyOf(Foo.outerHtmlStrings));
+        expect(fooNewed is Foo, isTrue);
+        expect(fooNewed is HtmlElement, isTrue);
+        expect(fooNewed is UnknownElement, isFalse);
+      });
 
-    var quxNewed = new Qux();
-    var quxOuterHtml = '<input is="x-qux">';
-    expect(quxNewed.outerHtml, quxOuterHtml);
-    expect(quxNewed is Qux, isTrue);
-    expect(quxNewed is InputElement, isTrue);
-    expect(isFormControl(quxNewed), isTrue);
+      test('type extension', () {
+        var barNewed = new Bar();
+        expect(barNewed.outerHtml, Bar.outerHtmlString);
+        expect(barNewed is Bar, isTrue);
+        expect(barNewed is InputElement, isTrue);
+        expect(isFormControl(barNewed), isTrue);
+      });
 
-    // new Element.tag
+      test('custom tag deriving from custom tag', () {
+        var bazNewed = new Baz();
+        expect(bazNewed.outerHtml, anyOf(Baz.outerHtmlStrings));
+        expect(bazNewed is Baz, isTrue);
+        expect(bazNewed is HtmlElement, isTrue);
+        expect(bazNewed is UnknownElement, isFalse);
+      });
 
-    var fooCreated = new Element.tag('x-foo');
-    expect(fooCreated.outerHtml, fooOuterHtml);
-    expect(fooCreated is Foo, isTrue);
+      test('type extension deriving from custom tag', () {
+        var quxNewed = new Qux();
+        var quxOuterHtml = '<input is="x-qux">';
+        expect(quxNewed.outerHtml, quxOuterHtml);
+        expect(quxNewed is Qux, isTrue);
+        expect(quxNewed is InputElement, isTrue);
+        expect(isFormControl(quxNewed), isTrue);
+      });
+    });
 
-    var barCreated = new Element.tag('x-bar');
-    expect(barCreated.outerHtml, "<x-bar></x-bar>");
-    expect(barCreated is Bar, isFalse);
-    expect(barCreated is UnknownElement, isFalse);
-    expect(barCreated is HtmlElement, isTrue);
+    group('single-parameter createElement', () {
+      test('custom tag', () {
+        var fooCreated = new Element.tag('x-foo');
+        expect(fooCreated.outerHtml, anyOf(Foo.outerHtmlStrings));
+        expect(fooCreated is Foo, isTrue);
+      });
 
-    var bazCreated = new Element.tag('x-baz');
-    expect(bazCreated.outerHtml, bazOuterHtml);
-    expect(bazCreated is Baz, isTrue);
-    expect(bazCreated is UnknownElement, isFalse);
+      test('does not upgrade type extension', () {
+        var barCreated = new Element.tag('x-bar');
+        expect(barCreated is Bar, isFalse);
+        expect(barCreated.outerHtml, "<x-bar></x-bar>");
+        expect(barCreated is UnknownElement, isFalse);
+        expect(barCreated is HtmlElement, isTrue);
+      });
 
-    var quxCreated = new Element.tag('x-qux');
-    expect(quxCreated.outerHtml, "<x-qux></x-qux>");
-    expect(quxCreated is Qux, isFalse);
-    expect(quxCreated is UnknownElement, isFalse);
-    expect(quxCreated is HtmlElement, isTrue);
+      test('custom tag deriving from custom tag', () {
+        var bazCreated = new Element.tag('x-baz');
+        expect(bazCreated.outerHtml, anyOf(Baz.outerHtmlStrings));
+        expect(bazCreated is Baz, isTrue);
+        expect(bazCreated is UnknownElement, isFalse);
+      });
 
-    // create with type extensions
-    // TODO(vsm): How should we expose this?
+      test('type extension deriving from custom tag', () {
+        var quxCreated = new Element.tag('x-qux');
+        expect(quxCreated.outerHtml, "<x-qux></x-qux>");
+        expect(quxCreated is Qux, isFalse);
+        expect(quxCreated is UnknownElement, isFalse);
+        expect(quxCreated is HtmlElement, isTrue);
+      });
+    });
 
-    var divFooCreated = document.$dom_createElement("div", Foo.tag);
-    expect(divFooCreated.outerHtml, '<div is="x-foo"></div>');
-    expect(divFooCreated is Foo, isFalse);
-    expect(divFooCreated is DivElement, isTrue);
+    group('createElement with type extension', () {
+      test('does not upgrade extension of custom tag', () {
+        var divFooCreated = new Element.tag("div", Foo.tag);
+        expect(divFooCreated.outerHtml, '<div is="x-foo"></div>');
+        expect(divFooCreated is Foo, isFalse);
+        expect(divFooCreated is DivElement, isTrue);
+      });
 
-    var inputBarCreated =
-	document.$dom_createElement("input", Bar.tag);
-    expect(inputBarCreated.outerHtml, barOuterHtml);
-    expect(inputBarCreated is Bar, isTrue);
-    expect(inputBarCreated is UnknownElement, isFalse);
-    expect(isFormControl(inputBarCreated), isTrue);
+      test('upgrades valid extension', () {
+        var inputBarCreated = new Element.tag("input", Bar.tag);
+        expect(inputBarCreated.outerHtml, Bar.outerHtmlString);
+        expect(inputBarCreated is Bar, isTrue);
+        expect(inputBarCreated is UnknownElement, isFalse);
+        expect(isFormControl(inputBarCreated), isTrue);
+      });
 
-    var divBarCreated = document.$dom_createElement("div", Bar.tag);
-    expect(divBarCreated.outerHtml, '<div is="x-bar"></div>');
-    expect(divBarCreated is Bar, isFalse);
-    expect(divBarCreated is DivElement, isTrue);
+      test('type extension of incorrect tag', () {
+        var divBarCreated = new Element.tag("div", Bar.tag);
+        expect(divBarCreated.outerHtml, '<div is="x-bar"></div>');
+        expect(divBarCreated is Bar, isFalse);
+        expect(divBarCreated is DivElement, isTrue);
+      });
 
-    var fooBarCreated =
-	document.$dom_createElement(Foo.tag, Bar.tag);
-    expect(fooBarCreated.outerHtml, '<x-foo is="x-bar"></x-foo>');
-    expect(fooBarCreated is Foo, isTrue);
+      test('incorrect extension of custom tag', () {
+        var fooBarCreated = new Element.tag(Foo.tag, Bar.tag);
+        expect(fooBarCreated.outerHtml, anyOf(
+            '<x-foo is="x-bar"></x-foo>',
+            '<?XML:NAMESPACE PREFIX = PUBLIC NS = "URN:COMPONENT" />'
+                '<x-foo is="x-bar"></x-foo>'));
+        expect(fooBarCreated is Foo, isTrue);
+      });
 
-    var barFooCreated = document.$dom_createElement(Bar.tag,
-						      Foo.tag);
-    expect(barFooCreated.outerHtml, '<x-bar is="x-foo"></x-bar>');
-    expect(barFooCreated is UnknownElement, isFalse);
-    expect(barFooCreated is HtmlElement, isTrue);
+      test('incorrect extension of type extension', () {
+        var barFooCreated = new Element.tag(Bar.tag, Foo.tag);
+        expect(barFooCreated.outerHtml, '<x-bar is="x-foo"></x-bar>');
+        expect(barFooCreated is UnknownElement, isFalse);
+        expect(barFooCreated is HtmlElement, isTrue);
+      });
 
-    var fooCreatedNull = document.$dom_createElement(Foo.tag, null);
-    expect(fooCreatedNull.outerHtml, fooOuterHtml);
-    expect(fooCreatedNull is Foo, isTrue);
+      test('null type extension', () {
+        var fooCreatedNull = new Element.tag(Foo.tag, null);
+        expect(fooCreatedNull.outerHtml, anyOf(Foo.outerHtmlStrings));
+        expect(fooCreatedNull is Foo, isTrue);
+      });
 
-    var fooCreatedEmpty = document.$dom_createElement(Foo.tag, "");
-    expect(fooCreatedEmpty.outerHtml, fooOuterHtml);
-    expect(fooCreatedEmpty is Foo, isTrue);
+      test('empty type extension', () {
+        var fooCreatedEmpty = new Element.tag(Foo.tag, "");
+        expect(fooCreatedEmpty.outerHtml, anyOf(Foo.outerHtmlStrings));
+        expect(fooCreatedEmpty is Foo, isTrue);
+      });
+    });
+  });
 
-    expect(() => document.$dom_createElement('@invalid', 'x-bar'), throws);
+  group('namespaces', () {
+    setUp(registerTypes);
 
-    // Create NS with type extensions
+    test('createElementNS', () {
+      var fooCreatedNS =
+          document.createElementNS("http://www.w3.org/1999/xhtml",
+          Foo.tag, null);
+      expect(fooCreatedNS.outerHtml, anyOf(Foo.outerHtmlStrings));
+      expect(fooCreatedNS is Foo, isTrue);
 
-    var fooCreatedNS =
-	document.$dom_createElementNS("http://www.w3.org/1999/xhtml",
-				      Foo.tag, null);
-    expect(fooCreatedNS.outerHtml, fooOuterHtml);
-    expect(fooCreatedNS is Foo, isTrue);
+      var barCreatedNS =
+          document.createElementNS("http://www.w3.org/1999/xhtml", "input",
+          Bar.tag);
+      expect(barCreatedNS.outerHtml, Bar.outerHtmlString);
+      expect(barCreatedNS is Bar, isTrue);
+      expect(isFormControl(barCreatedNS), isTrue);
 
-    var barCreatedNS =
-	document.$dom_createElementNS("http://www.w3.org/1999/xhtml", "input",
-				      Bar.tag);
-    expect(barCreatedNS.outerHtml, barOuterHtml);
-    expect(barCreatedNS is Bar, isTrue);
-    expect(isFormControl(barCreatedNS), isTrue);
+      expect(() =>
+         document.createElementNS(
+             'http://example.com/2013/no-such-namespace',
+       'xml:lang', 'x-bar'), throws);
+    });
+  });
 
-    expect(() =>
-	     document.$dom_createElementNS(
-	         'http://example.com/2013/no-such-namespace',
-		 'xml:lang', 'x-bar'), throws);
+  group('parsing', () {
+    setUp(registerTypes);
 
-    // Parser
+    test('parsing', () {
+      createElementFromHtml(html) {
+        var container = new DivElement()..setInnerHtml(html,
+          treeSanitizer: new NullTreeSanitizer());
+        Platform.upgradeCustomElements(container);
+        return container.firstChild;
+      }
 
-    createElementFromHtml(html) {
-      var container = new DivElement()..setInnerHtml(html,
-        treeSanitizer: new NullTreeSanitizer());
-      return container.firstChild;
-    }
+      var fooParsed = createElementFromHtml('<x-foo>');
+      expect(fooParsed is Foo, isTrue);
 
-    var fooParsed = createElementFromHtml('<x-foo>');
-    expect(fooParsed is Foo, isTrue);
+      var barParsed = createElementFromHtml('<input is=x-bar>');
+      expect(barParsed is Bar, isTrue);
+      expect(isFormControl(barParsed), isTrue);
 
-    var barParsed = createElementFromHtml('<input is=x-bar>');
-    expect(barParsed is Bar, isTrue);
-    expect(isFormControl(barParsed), isTrue);
+      var divFooParsed = createElementFromHtml('<div is=x-foo>');
+      expect(divFooParsed is Foo, isFalse);
+      expect(divFooParsed is DivElement, isTrue);
 
-    var divFooParsed = createElementFromHtml('<div is=x-foo>');
-    expect(divFooParsed is Foo, isFalse);
-    expect(divFooParsed is DivElement, isTrue);
+      var namedBarParsed = createElementFromHtml('<x-bar>');
+      expect(namedBarParsed is Bar, isFalse);
+      // Polyfill does not convert parsed unregistered custom elements to
+      // HtmlElement.
+      // expect(namedBarParsed is UnknownElement, isFalse);
+      expect(namedBarParsed is HtmlElement, isTrue);
 
-    var namedBarParsed = createElementFromHtml('<x-bar>');
-    expect(namedBarParsed is Bar, isFalse);
-    expect(namedBarParsed is UnknownElement, isFalse);
-    expect(namedBarParsed is HtmlElement, isTrue);
-
-    var divBarParsed = createElementFromHtml('<div is=x-bar>');
-    expect(divBarParsed is Bar, isFalse);
-    expect(divBarParsed is DivElement, isTrue);
+      var divBarParsed = createElementFromHtml('<div is=x-bar>');
+      expect(divBarParsed is Bar, isFalse);
+      expect(divBarParsed is DivElement, isTrue);
+    });
   });
 }
diff --git a/tests/html/html.status b/tests/html/html.status
index 0c6ee7c..812076a 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -6,8 +6,9 @@
 event_test: Skip  # Issue 1996
 interactive_test: Skip # Must be run manually.
 
-[ $compiler == dart2js && $runtime != drt ]
-custom/*: Skip
+[ $compiler == dart2js && $runtime != drt && $browser ]
+custom/document_register_type_extensions_test/namespaces: Fail # Polyfill does not support createElementNS
+custom/document_register_basic_test: Fail # Polyfill is not case-sensitive
 
 [ $compiler == dart2js && $browser ]
 # Issue 9325 failures
@@ -24,7 +25,6 @@
 postmessage_structured_test/typed_arrays: Fail
 xhr_test: Pass, Fail # Issue 12648
 custom/attribute_changed_callback_test: Fail # 12643
-custom/created_callback_test: Fail # Issue 12642
 xhr_test/json: Fail # Issue 13069
 
 [ $compiler == none && $runtime == drt && $system == windows ]
@@ -35,9 +35,6 @@
 
 [ $compiler == dart2js && $runtime == ie10 ]
 async_test: Pass, Fail # timers test fails on ie10.
-indexeddb_2_test: Fail # Issue 12893
-indexeddb_3_test: Fail # Issue 12893
-indexeddb_4_test: Fail # Issue 12893
 indexeddb_5_test: Fail # Issue 12893
 
 [ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ]
@@ -50,11 +47,6 @@
 [ $compiler == dart2js && $browser && $checked ]
 postmessage_structured_test/typed_arrays: Fail # Issue 10097
 postmessage_structured_test/primitives: Fail # Issue 10097
-# Issue 9325 failures
-custom/constructor_calls_created_synchronously_test: Fail
-custom/created_callback_test: Fail
-custom/document_register_basic_test: Fail
-custom/document_register_type_extensions_test: Fail
 
 [ $runtime == chrome ]
 canvasrenderingcontext2d_test/drawImage_video_element: Pass,Fail # Issue 11836
@@ -90,7 +82,6 @@
 dromaeo_smoke_test: Skip #TODO(efortuna): investigating.
 element_test/click: Fail                # IE does not support firing this event.
 history_test/history: Pass, Fail # issue 8183
-indexeddb_1_test/functional: Fail # Issue 12893
 microtask_test: Fail, Pass # Appears to be flaky
 native_gc_test: Fail, Pass # BUG(7774): Untriaged.
 serialized_script_value_test: Fail
@@ -146,9 +137,13 @@
 xsltprocessor_test/supported: Fail
 
 
+[ $runtime == ie9 || $runtime == ie10 ]
+custom/document_register_type_extensions_test/construction: Fail # Issue 13193
+
 [ $runtime == ie9 ]
 isolates_test: Timeout # Issue 13027
 blob_constructor_test: Fail
+custom/document_register_type_extensions_test/namespaces: Fail # Issue 13193
 document_test/document: Pass, Fail # BUG(9654) need per-instance patching
 dom_constructors_test: Fail
 dromaeo_smoke_test: Skip #TODO(efortuna): investigating.
@@ -251,6 +246,9 @@
 xsltprocessor_test/supported: Fail
 
 [ $runtime == safari ]
+worker_test: Skip # Issue 13221
+worker_api_test: Skip # Issue 13221
+notifications_test/supported: Pass, Fail # Issue 13210
 element_types_test/supported_track: Pass, Fail
 input_element_test/supported_month: Fail, Crash
 input_element_test/supported_time: Fail, Crash
diff --git a/tests/html/safe_dom_test.dart b/tests/html/safe_dom_test.dart
index 7407d76..ee2ddaa 100644
--- a/tests/html/safe_dom_test.dart
+++ b/tests/html/safe_dom_test.dart
@@ -64,7 +64,7 @@
 
   var contextElement;
   if (contextTag != null) {
-    contextElement = doc.$dom_createElement(contextTag);
+    contextElement = doc.createElement(contextTag);
   } else {
     contextElement = doc.body;
   }
diff --git a/tests/language/duplicate_implements_test.dart b/tests/language/duplicate_implements_test.dart
index 5baf45f..e9ff103 100644
--- a/tests/language/duplicate_implements_test.dart
+++ b/tests/language/duplicate_implements_test.dart
@@ -15,5 +15,8 @@
 abstract class Z implements K<int>, K<int> { }       /// 04: compile-time error
 
 main() {
-  return null;
+  X x = new X();  /// 01: continued
+  X x = new X();  /// 02: continued
+  Z z = new Z();  /// 03: continued
+  Z z = new Z();  /// 04: continued
 }
diff --git a/tests/language/first_class_types_literals_test.dart b/tests/language/first_class_types_literals_test.dart
index 896ba5d..8ba570a 100644
--- a/tests/language/first_class_types_literals_test.dart
+++ b/tests/language/first_class_types_literals_test.dart
@@ -19,9 +19,11 @@
   Expect.equals(int, int);
   Expect.notEquals(int, num);
   Expect.equals(Foo, Foo);
+  Expect.equals(dynamic, dynamic);
 
   // Test that class literals return instances of Type.
   Expect.isTrue((D).runtimeType is Type);
+  Expect.isTrue((dynamic).runtimeType is Type);
 
   // Test that types from runtimeType and literals agree.
   Expect.equals(int, 1.runtimeType);
@@ -40,4 +42,11 @@
   Expect.throws(() => C + 1, (e) => e is NoSuchMethodError);
   Expect.throws(() => C[2], (e) => e is NoSuchMethodError);
   Expect.throws(() => C[2] = 'hest', (e) => e is NoSuchMethodError);
+  Expect.throws(() => dynamic = 1, (e) => e is NoSuchMethodError);
+  Expect.throws(() => dynamic++, (e) => e is NoSuchMethodError);
+  Expect.throws(() => dynamic + 1, (e) => e is NoSuchMethodError);
+  Expect.throws(() => dynamic[2], (e) => e is NoSuchMethodError);
+  Expect.throws(() => dynamic[2] = 'hest', (e) => e is NoSuchMethodError);
+
+  Expect.equals((dynamic).toString(), 'dynamic');
 }
diff --git a/tests/language/function_type_alias7_test.dart b/tests/language/function_type_alias7_test.dart
index 03c5e03..41712f2 100644
--- a/tests/language/function_type_alias7_test.dart
+++ b/tests/language/function_type_alias7_test.dart
@@ -7,6 +7,8 @@
 
 typedef void badFuncType([int arg = 0]);  /// 00: compile-time error
 
+typedef void badFuncType({int arg: 0});  /// 02: compile-time error
+
 class A
   extends funcType  /// 01: compile-time error
 {
@@ -14,4 +16,6 @@
 
 main() {
   new A();
+  badFuncType f;  /// 00: continued
+  badFuncType f;  /// 02: continued
 }
diff --git a/tests/language/inference_super_constructor_call_test.dart b/tests/language/inference_super_constructor_call_test.dart
new file mode 100644
index 0000000..0dc55a6
--- /dev/null
+++ b/tests/language/inference_super_constructor_call_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+// Regression test for dart2js's inferrer that used to not propagate
+// types given to generative constructors in super constructor calls.
+
+import "package:expect/expect.dart";
+
+class A {
+  final field;
+  A.full(this.field);
+}
+
+class B extends A {
+  // The following super call used to not be analyzed properly.
+  B.full(field) : super.full(field);
+}
+
+main() {
+  // Call [A.full] with an int to have the inferrer think [field] is
+  // always an int.
+  Expect.equals(84, new A.full(42).field + 42);
+  Expect.throws(() => new B.full(null).field + 42,
+                (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/issue10561_test.dart b/tests/language/issue10561_test.dart
index 37a6cef..7ff80be 100644
--- a/tests/language/issue10561_test.dart
+++ b/tests/language/issue10561_test.dart
@@ -9,7 +9,7 @@
 
 import 'dart:collection';
 
-class Foo extends LinkedHashMap {
+class Foo extends HashSet {
 }
 
 main() {
diff --git a/tests/language/issue9949_test.dart b/tests/language/issue9949_test.dart
index e161d5a..d5df0ca 100644
--- a/tests/language/issue9949_test.dart
+++ b/tests/language/issue9949_test.dart
@@ -8,11 +8,11 @@
 import "package:expect/expect.dart";
 import 'dart:collection';
 
-class Crash extends LinkedHashMap<String,String> {
+class Crash extends HashSet<String> {
   Crash(): super();
 }
 
 void main() {
   Crash map = new Crash();
-  Expect.isTrue(map is LinkedHashMap);
+  Expect.isTrue(map is HashSet);
 }
diff --git a/tests/language/language.status b/tests/language/language.status
index f1293db..7cd6bc0 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -33,7 +33,6 @@
 mixin_forwarding_constructor2_test: Fail # Issue 11888
 mixin_typedef_constructor_test: Fail # Issue 11888
 mixin_type_parameter2_test: Fail # Issue 11888
-built_in_identifier_illegal_test/19: Fail # Issue 13021
 
 [ $compiler == none && $unchecked ]
 # Only checked mode reports an error on type assignment
@@ -60,3 +59,6 @@
 [ $compiler == none && $runtime == drt ]
 mixin_illegal_object_test/01: pass # Issue 10952.
 mixin_illegal_object_test/02: pass # Issue 10952.
+
+[ $compiler == none && $runtime == drt && $system == macos ]
+field_type_check_test/none: Pass, Fail # Issue 13266
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index e360479..4dc9997 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -128,10 +128,6 @@
 
 instantiate_type_variable_test/01: fail # Issue 11595
 
-mixin_type_parameters_errors_test/01: fail # Issue 11598
-mixin_type_parameters_errors_test/02: fail # Issue 11598
-mixin_type_parameters_errors_test/05: fail # Issue 11598
-
 # test issue 11698, no setter, so warning, not error
 assign_instance_method_negative_test: fail
 
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index c0c31c7..6b182de 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js || $compiler == dart2dart ]
+block_scope_test: Fail # Issue 13204.
 compile_time_constant_c_test/none: Fail # Issue 11583
 null_test/03: Fail # Issue 12445.
 black_listed_test/none: Fail # Issue 12446.
@@ -108,8 +109,6 @@
 not_enough_positional_arguments_test/01: Fail # Issue 12838
 not_enough_positional_arguments_test/02: Fail # Issue 12838
 not_enough_positional_arguments_test/05: Fail # Issue 12838
-dynamic_test: Fail # Issue 12398
-dynamic_prefix_core_test: Fail # Issue 12398
 metadata_test: Fail # Issue 5841
 infinity_test: Fail # Issue 4984
 positive_bit_operations_test: Fail # Issue 12795
@@ -121,17 +120,12 @@
 function_type_alias5_test/00: Fail # Issue 12754
 function_type_alias5_test/01: Fail # Issue 12754
 function_type_alias5_test/02: Fail # Issue 12754
-function_type_alias7_test/00: Fail # Issue 12801
 method_binding_test: Fail # Issue 12807
 method_override_test: Fail # Issue 12808
 method_override5_test: Fail # Issue 12809
 parameter_initializer6_negative_test: Fail # Issue 3502
-named_parameters_aggregated_test/01: Fail # Issue 12801
 named_parameters_aggregated_test/03: Fail # Issue 12812
 super_implicit_closure_test: Fail # Issue 12884
-mixin_type_parameters_errors_test/01: Fail # Issue 12885
-mixin_type_parameters_errors_test/02: Fail # Issue 12885
-mixin_type_parameters_errors_test/05: Fail # Issue 12885
 external_test/11: Fail # Issue 12887
 external_test/12: Fail # Issue 12887
 external_test/13: Fail # Issue 12887
@@ -150,13 +144,8 @@
 const_syntax_test/03: Fail # Issue 12932
 const_syntax_test/04: Fail # Issue 12932
 constructor9_test/01: Fail # Issue 12934
-duplicate_implements_test/01: Fail # Issue 12991
-duplicate_implements_test/02: Fail # Issue 12991
-duplicate_implements_test/03: Fail # Issue 12991
-duplicate_implements_test/04: Fail # Issue 12991
 list_literal1_test/01: Fail # Issue 12993
 map_literal1_test/01: Fail # Issue 12993
-number_identifier_test/05: Fail # Issue 13070
 scope_variable_test/01: Fail # Issue 13016
 static_final_field2_test/02: Fail # Issue 13017
 throw7_test/01: Fail # Issue 13019
@@ -219,10 +208,6 @@
 
 on_catch_malformed_type_test: Fail # Issue 8601
 
-mixin_type_parameters_errors_test/01: Fail # Issue 12886
-mixin_type_parameters_errors_test/02: Fail # Issue 12886
-mixin_type_parameters_errors_test/05: Fail # Issue 12886
-
 # Mixins fail on the VM.
 mixin_mixin_test: Fail # Issue 9683
 mixin_mixin2_test: Fail # Issue 9683
@@ -283,7 +268,6 @@
 final_syntax_test/03: Fail # Issue 13020
 final_syntax_test/04: Fail # Issue 13020
 getter_no_setter_test/01: Fail # Issue 5519
-named_parameters_aggregated_test/01: Fail # Issue 12802
 named_parameters_aggregated_test/03: Fail # Issue 12813
 not_enough_positional_arguments_test/01: Fail # Issue 12839
 not_enough_positional_arguments_test/02: Fail # Issue 12839
@@ -302,10 +286,6 @@
 external_test/31: Fail # Issue 12888
 built_in_identifier_test/01: Fail # Issue 13022
 lazy_static3_test: Fail # Issue 12593
-duplicate_implements_test/01: Fail # Issue 12992
-duplicate_implements_test/02: Fail # Issue 12992
-duplicate_implements_test/03: Fail # Issue 12992
-duplicate_implements_test/04: Fail # Issue 12992
 list_literal1_test/01: Fail # Issue 12993
 map_literal1_test/01: Fail # Issue 12993
 method_override4_test: Fail # Issue 12810
@@ -322,7 +302,6 @@
 function_type_alias5_test/00: Fail # Issue 12755
 function_type_alias5_test/01: Fail # Issue 12755
 function_type_alias5_test/02: Fail # Issue 12755
-function_type_alias7_test/00: Fail # Issue 12802
 parameter_initializer6_negative_test: Fail # Issue 3502
 
 # DartVM problem.
@@ -357,9 +336,9 @@
 super_getter_setter_test: Fail # Issue 11065.
 f_bounded_quantification4_test: Fail # Issue 12605.
 f_bounded_quantification5_test: Fail # Issue 12605.
-many_overridden_no_such_method_test: Fail # Issue 13078
-overridden_no_such_method_test: Fail # Issue 13078
-no_such_method_test: Fail # Issue 13078
+many_overridden_no_such_method_test: Pass, Fail # Issue 13078
+overridden_no_such_method_test: Pass, Fail # Issue 13078
+no_such_method_test: Pass, Fail # Issue 13078
 
 # TODO(tball): Assign proper bug numbers.
 class_literal_test: Fail
diff --git a/tests/language/mixin_type_parameters_errors_test.dart b/tests/language/mixin_type_parameters_errors_test.dart
index be459bd..c5889e5 100644
--- a/tests/language/mixin_type_parameters_errors_test.dart
+++ b/tests/language/mixin_type_parameters_errors_test.dart
@@ -6,11 +6,11 @@
 class M<U> { }
 
 class A<X> extends S<int> with M<double> { }
-class B<U, V> extends S with M<U, V> { }  /// 01: compile-time error
-class C<A, B> extends S<A, int> with M { }  /// 02: compile-time error
+class B<U, V> extends S with M<U, V> { }  /// 01: static type warning
+class C<A, B> extends S<A, int> with M { }  /// 02: static type warning
 
 typedef F<X> = S<X> with M<X>;
-typedef G = S<int> with M<double, double>;  /// 05: compile-time error
+typedef G = S<int> with M<double, double>;  /// 05: static type warning
 
 main() {
   var a;
diff --git a/tests/language/number_identifier_test.dart b/tests/language/number_identifier_test.dart
index 9ef17d8..ab5ac20 100644
--- a/tests/language/number_identifier_test.dart
+++ b/tests/language/number_identifier_test.dart
@@ -31,6 +31,14 @@
   Expect.equals(1e+2, 1e+2as double);
   Expect.throws(() => 1.e+2,                       /// 05: ok
                 (e) => e is NoSuchMethodError);    /// 05: continued
+  1d;  /// 06: compile-time error
+  1D;  /// 07: compile-time error
+  Expect.throws(() => 1.d+2,                       /// 08: ok
+                (e) => e is NoSuchMethodError);    /// 08: continued
+  Expect.throws(() => 1.D+2,                       /// 09: ok
+                (e) => e is NoSuchMethodError);    /// 09: continued
+  1.1d;  /// 10: compile-time error
+  1.1D;  /// 11: compile-time error
   1e;  /// 02: compile-time error
   1x;  /// 03: compile-time error
 }
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 2c81f05..1594832 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -617,22 +617,6 @@
   completer.complete(21);
 }
 
-void testChainedFutureCycle() {
-  asyncStart();
-  var completer = new Completer();
-  var future, future2;
-  future  = completer.future.then((_) => future2);
-  future2 = completer.future.then((_) => future);
-  completer.complete(42);
-  int ctr = 2;
-  void receiveError(e) {
-    Expect.isTrue(e is StateError);
-    if (--ctr == 0) asyncEnd();
-  }
-  future.catchError(receiveError);
-  future.catchError(receiveError);
-}
-
 main() {
   testValue();
   testSync();
@@ -674,5 +658,4 @@
   testChainedFutureValue();
   testChainedFutureValueDelay();
   testChainedFutureError();
-  testChainedFutureCycle();
 }
diff --git a/tests/lib/async/future_value_chain2_test.dart b/tests/lib/async/future_value_chain2_test.dart
new file mode 100644
index 0000000..3b31c3d
--- /dev/null
+++ b/tests/lib/async/future_value_chain2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+import 'dart:async';
+
+
+main() {
+  asyncStart();
+  var errorFuture = new Future.error(499);
+  var valueChainFuture = new Future.sync(() => errorFuture);
+  // The errorFuture must not be propagated immediately as we would otherwise
+  // not have time to catch the error.
+  valueChainFuture.catchError((error) {
+    Expect.equals(499, error);
+    asyncEnd();
+  });
+}
diff --git a/tests/lib/async/future_value_chain3_test.dart b/tests/lib/async/future_value_chain3_test.dart
new file mode 100644
index 0000000..d6d9abf
--- /dev/null
+++ b/tests/lib/async/future_value_chain3_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+import 'dart:async';
+
+
+main() {
+  asyncStart();
+  var errorFuture = new Future.error(499);
+  errorFuture.catchError((x) {
+    Expect.equals(499, x);
+    var valueChainFuture = new Future.sync(() => errorFuture);
+    // The errorFuture must not be propagated immediately as we would otherwise
+    // not have time to catch the error.
+    valueChainFuture.catchError((error) {
+      Expect.equals(499, error);
+      asyncEnd();
+    });
+  });
+}
diff --git a/tests/lib/async/future_value_chain4_test.dart b/tests/lib/async/future_value_chain4_test.dart
new file mode 100644
index 0000000..2c7b652
--- /dev/null
+++ b/tests/lib/async/future_value_chain4_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+import 'dart:async';
+
+class MyFuture implements Future {
+  then(valueHandler, {onError}) {
+    runAsync(() { valueHandler(499); });
+  }
+  catchError(_) => null;
+  whenComplete(_) => null;
+}
+
+main() {
+  asyncStart();
+  Completer completer = new Completer();
+  completer.complete(new MyFuture());
+  Expect.isTrue(completer.isCompleted);
+  Expect.throws(() => completer.complete(42));
+  completer.future.then((_) => asyncEnd());
+}
diff --git a/tests/lib/async/future_value_chain_test.dart b/tests/lib/async/future_value_chain_test.dart
new file mode 100644
index 0000000..3cec185
--- /dev/null
+++ b/tests/lib/async/future_value_chain_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import "package:expect/expect.dart";
+import 'dart:async';
+
+
+main() {
+  asyncStart();
+  var errorFuture = new Future.error(499);
+  errorFuture.catchError((x) {
+    Expect.equals(499, x);
+    var valueChainFuture = new Future.value(errorFuture);
+    // The errorFuture must not be propagated immediately as we would otherwise
+    // not have time to catch the error.
+    valueChainFuture.catchError((error) {
+      Expect.equals(499, error);
+      asyncEnd();
+    });
+  });
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index aecf6a9..bc28219 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -19,6 +19,7 @@
 mirrors/invoke_test: Fail # Issue 11954
 mirrors/invoke_named_test: Fail # Issue 10471, 12863
 mirrors/invoke_private_test: Fail # Issue 12164
+mirrors/invoke_throws_test: Fail # Issue 11954
 mirrors/library_uri_io_test: Skip # Not intended for dart2js as it uses dart:io.
 mirrors/method_mirror_name_test: Fail # Issue 6335
 mirrors/method_mirror_properties_test: Fail # Issue 11861
@@ -26,6 +27,7 @@
 mirrors/method_mirror_source_test : Fail # Issue 6490
 mirrors/mirrors_test: Fail # TODO(ahe): I'm working on fixing this.
 mirrors/mixin_test/none: Fail # Issue 12464
+mirrors/new_instance_with_type_arguments_test: Fail # Issue 12333
 mirrors/null_test : Fail # Issue 12129
 mirrors/parameter_test: Fail # Issue 6490
 mirrors/parameter_metadata_test: Fail # Issue 10905
@@ -106,6 +108,8 @@
 async/deferred/deferred_api_test: Pass, Timeout # http://dartbug.com/12635
 convert/streamed_conversion_utf8_decode_test: Pass, Timeout # http://dartbug.com/12768
 
+[ $compiler == dart2js ]
+typed_data/typed_data_hierarchy_int64_test: Fail # Issue 10275
 
 [ $runtime == opera ]
 async/multiple_timer_test: Pass, Fail
diff --git a/tests/lib/mirrors/invoke_throws_test.dart b/tests/lib/mirrors/invoke_throws_test.dart
new file mode 100644
index 0000000..f3198a1
--- /dev/null
+++ b/tests/lib/mirrors/invoke_throws_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.invoke_throws_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class MyException {
+}
+
+class Class {
+  Class.noException();
+  Class.generative() { throw new MyException(); }
+  Class.redirecting() : this.generative();
+  factory Class.faktory() { throw new MyException(); }
+  factory Class.redirectingFactory() = Class.faktory;
+
+  get getter { throw new MyException(); }
+  set setter(v) { throw new MyException(); }
+  method() { throw new MyException(); }
+  
+  noSuchMethod(invocation) { throw new MyException(); }
+
+  static get staticGetter { throw new MyException(); }
+  static set staticSetter(v) { throw new MyException(); }
+  static staticFunction() { throw new MyException(); }
+}
+
+get libraryGetter { throw new MyException(); }
+set librarySetter(v) { throw new MyException(); }
+libraryFunction() { throw new MyException(); }
+
+main() {
+  InstanceMirror im = reflect(new Class.noException());
+  Expect.throws(() => im.getField(const Symbol('getter')),
+                (e) => e is MyException);
+  Expect.throws(() => im.setField(const Symbol('setter'), ['arg']),
+                (e) => e is MyException);
+  Expect.throws(() => im.invoke(const Symbol('method'), []),
+                (e) => e is MyException);
+  Expect.throws(() => im.invoke(const Symbol('triggerNoSuchMethod'), []),
+                (e) => e is MyException);
+
+  ClassMirror cm = reflectClass(Class);
+  Expect.throws(() => cm.getField(const Symbol('staticGetter')),
+                (e) => e is MyException);
+  Expect.throws(() => cm.setField(const Symbol('staticSetter'), ['arg']),
+                (e) => e is MyException);
+  Expect.throws(() => cm.invoke(const Symbol('staticFunction'), []),
+                (e) => e is MyException);
+  Expect.throws(() => cm.newInstance(const Symbol('generative'), []),
+                (e) => e is MyException);
+  Expect.throws(() => cm.newInstance(const Symbol('redirecting'), []),
+                (e) => e is MyException);
+  Expect.throws(() => cm.newInstance(const Symbol('faktory'), []),
+                (e) => e is MyException);
+  Expect.throws(() => cm.newInstance(const Symbol('redirectingFactory'), []),
+                (e) => e is MyException);
+
+  LibraryMirror lm = reflectClass(Class).owner;
+  Expect.throws(() => lm.getField(const Symbol('libraryGetter')),
+                (e) => e is MyException);
+  Expect.throws(() => lm.setField(const Symbol('librarySetter'), ['arg']),
+                (e) => e is MyException);
+  Expect.throws(() => lm.invoke(const Symbol('libraryFunction'), []),
+                (e) => e is MyException);
+}
diff --git a/tests/lib/mirrors/new_instance_with_type_arguments_test.dart b/tests/lib/mirrors/new_instance_with_type_arguments_test.dart
new file mode 100644
index 0000000..44238ad
--- /dev/null
+++ b/tests/lib/mirrors/new_instance_with_type_arguments_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.new_instance_with_type_arguments_test;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class A<T> {
+  Type get t => T;
+}
+class B extends A<int> {}
+class C<S> extends A<num> {
+  Type get s => S;
+}
+
+main() {
+  ClassMirror cmA = reflectClass(A);
+  ClassMirror cmB = reflectClass(B);
+  ClassMirror cmC = reflectClass(C);
+  
+  var a_int = new A<int>();
+  var a_dynamic = new A();
+  var b = new B();
+  var c_string = new C<String>();
+  var c_dynamic = new C();
+
+  Expect.equals(int, a_int.t);
+  Expect.equals(dynamic, a_dynamic.t);
+  Expect.equals(int, b.t);
+  Expect.equals(num, c_string.t);
+  Expect.equals(num, c_dynamic.t);
+
+  Expect.equals(String, c_string.s);
+  Expect.equals(dynamic, c_dynamic.s);
+
+
+  var reflective_a_int =
+      cmB.superclass.newInstance(const Symbol(''), []).reflectee;
+  var reflective_a_dynamic =
+      cmA.newInstance(const Symbol(''), []).reflectee;
+  var reflective_b =
+      cmB.newInstance(const Symbol(''), []).reflectee;
+  // TODO(rmacnak): Uncomment when reflectType is added to the API.
+  // var reflective_c_string =
+  //   reflectType(cmC.runtimeType).newInstance(const Symbol(''), []).reflectee;
+  var reflective_c_dynamic =
+      cmC.newInstance(const Symbol(''), []).reflectee;
+
+  Expect.equals(int, reflective_a_int.t);
+  Expect.equals(dynamic, reflective_a_dynamic.t);
+  Expect.equals(int, reflective_b.t);
+  // Expect.equals(num, c_string.t);
+  Expect.equals(num, reflective_c_dynamic.t);
+
+  // Expect.equals(String, c_string.s);
+  Expect.equals(dynamic, reflective_c_dynamic.s);
+
+  Expect.equals(a_int.runtimeType, reflective_a_int.runtimeType);
+  Expect.equals(a_dynamic.runtimeType, reflective_a_dynamic.runtimeType);
+  Expect.equals(b.runtimeType, reflective_b.runtimeType);
+  // Expect.equals(c_string.runtimeType, reflective_c_string.runtimeType);
+  Expect.equals(c_dynamic.runtimeType, reflective_c_dynamic.runtimeType);
+}
diff --git a/tests/lib/mirrors/parameter_test.dart b/tests/lib/mirrors/parameter_test.dart
index 7c538a7..6a86c53 100644
--- a/tests/lib/mirrors/parameter_test.dart
+++ b/tests/lib/mirrors/parameter_test.dart
@@ -31,6 +31,12 @@
   waldo(int z);
 }
 
+class C <S extends int, T> {
+  // TODO(6490): Currently only supported by the VM.
+  foo(int a, S b) => b;
+  bar(S a, T b, num c) {}
+}
+
 main() {
   ClassMirror cm = reflectClass(B);
   Map<Symbol, MethodMirror> constructors = cm.constructors;
@@ -141,4 +147,27 @@
          ' type = Class(s(int) in s(dart.core), top-level))]',
          waldo.parameters);
   expect('<null>', waldo.parameters[0].defaultValue);
+
+  cm = reflectClass(C);
+
+  MethodMirror fooInC = cm.members[const Symbol("foo")];
+  expect('Method(s(foo) in s(C))', fooInC);
+  expect('[Parameter(s(a) in s(foo),'
+         ' type = Class(s(int) in s(dart.core), top-level)), '
+         'Parameter(s(b) in s(foo),'
+         ' type = TypeVariable(s(S) in s(C),'
+         ' upperBound = Class(s(int) in s(dart.core), top-level)))]',
+         fooInC.parameters);
+
+  MethodMirror barInC = cm.members[const Symbol("bar")];
+  expect('Method(s(bar) in s(C))', barInC);
+  expect('[Parameter(s(a) in s(bar),'
+         ' type = TypeVariable(s(S) in s(C),'
+         ' upperBound = Class(s(int) in s(dart.core), top-level))), '
+         'Parameter(s(b) in s(bar),'
+         ' type = TypeVariable(s(T) in s(C),'
+         ' upperBound = Class(s(Object) in s(dart.core), top-level))), '
+         'Parameter(s(c) in s(bar),'
+         ' type = Class(s(num) in s(dart.core), top-level))]',
+         barInC.parameters);
 }
diff --git a/tests/lib/mirrors/stringify.dart b/tests/lib/mirrors/stringify.dart
index ddb0668..369f2c1 100644
--- a/tests/lib/mirrors/stringify.dart
+++ b/tests/lib/mirrors/stringify.dart
@@ -83,6 +83,13 @@
   return 'Parameter($buffer)';
 }
 
+stringifyTypeVariable(TypeVariableMirror typeVariable) {
+  var buffer = new StringBuffer();
+  writeDeclarationOn(typeVariable, buffer);
+  buffer.write(', upperBound = ${stringify(typeVariable.upperBound)}');
+  return 'TypeVariable($buffer)';
+}
+
 stringifyType(TypeMirror type) {
   var buffer = new StringBuffer();
   writeDeclarationOn(type, buffer);
@@ -116,6 +123,7 @@
   if (value is String) return value;
   if (value is Symbol) return stringifySymbol(value);
   if (value is ClassMirror) return stringifyClass(value);
+  if (value is TypeVariableMirror) return stringifyTypeVariable(value);
   if (value is TypeMirror) return stringifyType(value);
   if (value == null) return '<null>';
   throw 'Unexpected value: $value';
diff --git a/tests/lib/typed_data/typed_data_hierarchy_int64_test.dart b/tests/lib/typed_data/typed_data_hierarchy_int64_test.dart
new file mode 100644
index 0000000..3b38bb6
--- /dev/null
+++ b/tests/lib/typed_data/typed_data_hierarchy_int64_test.dart
@@ -0,0 +1,29 @@
+// 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library typed_data_hierarchy_int64_test;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+var inscrutable = null;
+
+void implementsTypedData() {
+  Expect.isTrue(inscrutable(new Int64List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Uint64List(1)) is TypedData);
+}
+
+void implementsList() {
+  Expect.isTrue(inscrutable(new Int64List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Uint64List(1)) is List<int>);
+}
+
+main() {
+  inscrutable = (x) => x;
+  implementsTypedData();
+  implementsList();
+}
+
diff --git a/tests/lib/typed_data/typed_data_hierarchy_test.dart b/tests/lib/typed_data/typed_data_hierarchy_test.dart
new file mode 100644
index 0000000..eba0e7b
--- /dev/null
+++ b/tests/lib/typed_data/typed_data_hierarchy_test.dart
@@ -0,0 +1,62 @@
+// 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library typed_data_hierarchy_test;
+
+import 'dart:typed_data';
+import 'package:expect/expect.dart';
+
+var inscrutable = null;
+
+void testClampedList() {
+  // Force lookup of Uint8List first.
+  Expect.isTrue(inscrutable(new Uint8List(1)) is Uint8List);
+
+  Expect.isFalse(new Uint8ClampedList(1) is Uint8List,
+      'Uint8ClampedList should not be a subtype of Uint8List '
+      'in optimizable test');
+  Expect.isFalse(inscrutable(new Uint8ClampedList(1)) is Uint8List,
+      'Uint8ClampedList should not be a subtype of Uint8List in dynamic test');
+}
+
+void implementsTypedData() {
+  Expect.isTrue(inscrutable(new ByteData(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Float32List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Float32x4List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Float64List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Int8List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Int16List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Int32List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Uint8List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Uint8ClampedList(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Uint16List(1)) is TypedData);
+  Expect.isTrue(inscrutable(new Uint32List(1)) is TypedData);
+}
+
+
+void implementsList() {
+  Expect.isTrue(inscrutable(new Float32List(1)) is List<double>);
+  Expect.isTrue(inscrutable(new Float32x4List(1)) is List<Float32x4>);
+  Expect.isTrue(inscrutable(new Float64List(1)) is List<double>);
+  Expect.isTrue(inscrutable(new Int8List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Int16List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Int32List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Uint8List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Uint8ClampedList(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Uint16List(1)) is List<int>);
+  Expect.isTrue(inscrutable(new Uint32List(1)) is List<int>);
+}
+
+main() {
+  inscrutable = (x) => x;
+
+  // Note: this test must come first to control order of lookup on Uint8List and
+  // Uint8ClampedList.
+  testClampedList();
+
+  implementsTypedData();
+  implementsList();
+}
diff --git a/tests/standalone/io/directory_chdir_test.dart b/tests/standalone/io/directory_chdir_test.dart
index e1c9a1d..682698f 100644
--- a/tests/standalone/io/directory_chdir_test.dart
+++ b/tests/standalone/io/directory_chdir_test.dart
@@ -26,8 +26,15 @@
     Directory.current = "..";
     Expect.isTrue(new File("111").existsSync());
     Expect.isTrue(new File("222/333").existsSync());
+    // Deleting the current working directory causes an error.
+    // On Windows, the deletion fails, and on non-Windows, the getter fails.
+    Expect.throws(() {
+      temp.deleteSync(recursive: true);
+      Directory.current;
+    }, (e) => e is DirectoryException);
     Directory.current = initialCurrent;
-    temp.deleteSync(recursive: true);
+    Directory.current;
+    if (temp.existsSync()) temp.deleteSync(recursive: true);
     asyncEnd();
   });
 }
diff --git a/tests/standalone/io/file_absolute_path_test.dart b/tests/standalone/io/file_absolute_path_test.dart
new file mode 100644
index 0000000..e2785bf
--- /dev/null
+++ b/tests/standalone/io/file_absolute_path_test.dart
@@ -0,0 +1,66 @@
+// 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.
+//
+// Dart test program for testing FileSystemEntity.absolute
+
+import "package:expect/expect.dart";
+import 'dart:io';
+
+main() {
+  if (Platform.isWindows) {
+    testWindows();
+    try {
+      Directory.current = 'C:\\';
+    } catch (e) {
+      return;
+    }
+    testWindows();
+  } else {
+    testPosix();
+    Directory.current = '.';
+    testPosix();
+    Directory.current = '/';
+    testPosix();
+
+  }
+}
+
+testWindows() {
+  String current = Directory.current.path;
+  for (String relative in ['abd', '..', '.', 'efg/hij', 'abc/']) {
+    if (current.endsWith('\\')) {
+      Expect.equals(new File(relative).absolute.path, '$current$relative');
+    } else {
+      Expect.equals(new File(relative).absolute.path, '$current\\$relative');
+    }
+    Expect.isTrue(new File(relative).absolute.isAbsolute);
+  }
+  for (String absolute in ['c:/abd', 'D:\\rf', '\\\\a_share\\folder',
+                           '\\\\?\\c:\\prefixed\path\\']) {
+    Expect.isTrue(new File(absolute).absolute.path == absolute);
+    Expect.isTrue(new File(absolute).absolute.isAbsolute);
+  }
+}
+
+testPosix() {
+  String current = Directory.current.path;
+  print(Directory.current.path);
+  for (String relative in ['abd', '..', '.', 'efg/hij', 'abc/']) {
+    if (current.endsWith('/')) {
+      Expect.equals(new File(relative).absolute.path, '$current$relative');
+    } else {
+      Expect.equals(new File(relative).absolute.path, '$current/$relative');
+    }
+    Expect.isTrue(new File(relative).absolute.isAbsolute);
+    Expect.equals(new Directory(relative).absolute.path,
+                  new Link(relative).absolute.path);
+    Expect.isTrue(new File(relative).absolute is File);
+    Expect.isTrue(new Directory(relative).absolute is Directory);
+    Expect.isTrue(new Link(relative).absolute is Link);
+  }
+  for (String absolute in ['/abd', '/', '/./..\\', '/efg/hij', '/abc/']) {
+    Expect.equals(new File(absolute).absolute.path, absolute);
+    Expect.isTrue(new File(absolute).absolute.isAbsolute);
+  }
+}
diff --git a/tests/standalone/io/file_read_encoded_test.dart b/tests/standalone/io/file_read_encoded_test.dart
new file mode 100644
index 0000000..23715c0
--- /dev/null
+++ b/tests/standalone/io/file_read_encoded_test.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+import 'dart:io';
+
+void testReadAsString() {
+  var tmp = new Directory('').createTempSync();
+
+  var file = new File('${tmp.path}/file');
+  file.createSync();
+
+  file.writeAsBytesSync([0xb0]);
+
+  Expect.throws(file.readAsStringSync, (e) => e is FileException);
+
+  asyncStart();
+  file.readAsString().then((_) {
+    Expect.fail("expected exception");
+  }).catchError((e) {
+    tmp.deleteSync(recursive: true);
+    asyncEnd();
+  }, test: (e) => e is FileException);
+}
+
+void testReadAsLines() {
+  var tmp = new Directory('').createTempSync();
+
+  var file = new File('${tmp.path}/file');
+  file.createSync();
+
+  file.writeAsBytesSync([0xb0]);
+
+  Expect.throws(file.readAsLinesSync, (e) => e is FileException);
+
+  asyncStart();
+  file.readAsLines().then((_) {
+    Expect.fail("expected exception");
+  }).catchError((e) {
+    tmp.deleteSync(recursive: true);
+    asyncEnd();
+  }, test: (e) => e is FileException);
+}
+
+void main() {
+  testReadAsString();
+  testReadAsLines();
+}
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index 2123b89..14e4780 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -1015,7 +1015,7 @@
     Expect.listEquals(expected, text.codeUnits);
     // First character is not ASCII. The default ASCII decoder will throw.
     Expect.throws(() => new File(name).readAsStringSync(encoding: ASCII),
-                  (e) => e is FormatException);
+                  (e) => e is FileException);
     // We can use an ASCII decoder that inserts the replacement character.
     var lenientAscii = const AsciiCodec(allowInvalid: true);
     text = new File(name).readAsStringSync(encoding: lenientAscii);
diff --git a/tests/standalone/io/process_run_test.dart b/tests/standalone/io/process_run_test.dart
new file mode 100644
index 0000000..2e07d0d
--- /dev/null
+++ b/tests/standalone/io/process_run_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+
+import "process_test_util.dart";
+
+
+void testProcessRunBinaryOutput() {
+  var result = Process.runSync(getProcessTestFileName(),
+                               const ["0", "0", "0", "0"],
+                               stdoutEncoding: null);
+  Expect.isTrue(result.stdout is List<int>);
+  Expect.isTrue(result.stderr is String);
+
+  result = Process.runSync(getProcessTestFileName(),
+                           const ["0", "0", "0", "0"],
+                           stderrEncoding: null);
+  Expect.isTrue(result.stdout is String);
+  Expect.isTrue(result.stderr is List<int>);
+
+  result = Process.runSync(getProcessTestFileName(),
+                           const ["0", "0", "0", "0"],
+                           stdoutEncoding: null,
+                           stderrEncoding: null);
+  Expect.isTrue(result.stdout is List<int>);
+  Expect.isTrue(result.stderr is List<int>);
+}
+
+
+void main() {
+  testProcessRunBinaryOutput();
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 77e8f0e..b8028ab 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -15,6 +15,9 @@
 
 package/invalid_uri_test: Fail, OK # Fails intentionally
 
+[ $runtime == vm && $system == windows ]
+io/file_system_watcher_test: Pass, Timeout # Issue 13228
+
 [ $runtime == vm ]
 package/package_isolate_test: Fail # http://dartbug.com/7520.
 
@@ -51,6 +54,9 @@
 [ $runtime == vm && $system == windows ]
 io/http_server_early_client_close_test: Crash, Pass # Issue 12982
 
+[ $compiler == none && $runtime == vm && $system == windows && $mode == debug ]
+io/secure_socket_bad_data_test: Crash, Pass # co19-roll r576: Please triage this failure
+
 [ $compiler == none && $runtime == drt ]
 typed_data_isolate_test: Skip # This test uses dart:io
 io/*: Skip # Don't run tests using dart:io in the browser
diff --git a/tests/standalone/typed_data_test.dart b/tests/standalone/typed_data_test.dart
index 3ea844b..47a1787 100644
--- a/tests/standalone/typed_data_test.dart
+++ b/tests/standalone/typed_data_test.dart
@@ -32,7 +32,7 @@
 
   typed_data = new Uint8ClampedList(0);
   Expect.isTrue(typed_data is Uint8ClampedList);
-  Expect.isTrue(typed_data is Uint8List);
+  Expect.isFalse(typed_data is Uint8List);
   Expect.equals(0, typed_data.length);
   Expect.equals(0, typed_data.lengthInBytes);
 
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index be63346..4c0a4aa9 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -67,6 +67,7 @@
 class JSString implements JSIndexable {
   var split;
   var concat;
+  operator+(other) {}
   var toString;
 }
 class JSFunction {}
@@ -115,5 +116,5 @@
     }
   }, onError: (e) {
       throw 'Compilation failed';
-  }).whenComplete(() => asyncEnd());
+  }).then(asyncSuccess);
 }
diff --git a/tests/utils/recursive_import_test.dart b/tests/utils/recursive_import_test.dart
index 0bb8769..9d288aa 100644
--- a/tests/utils/recursive_import_test.dart
+++ b/tests/utils/recursive_import_test.dart
@@ -54,6 +54,7 @@
   split(x) => null;
   concat(x) => null;
   toString() => null;
+  operator+(other) => null;
 }
 class JSNull {
 }
@@ -127,5 +128,5 @@
     Expect.equals(1, errorCount);
   }, onError: (e) {
       throw 'Compilation failed';
-  }).whenComplete(() => asyncEnd());
+  }).then(asyncSuccess);
 }
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index b1c695f..34e6ff0 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -19,9 +19,3 @@
 
 [ $system == macos || $system == windows ]
 *_layout_test: Skip
-
-[ $compiler == dartanalyzer ]
-dart2js_test: Fail # Issue 13012
-
-[ $compiler == dart2analyzer ]
-dart2js_test: Fail # Issue 13012
diff --git a/tools/VERSION b/tools/VERSION
index c1c78df..d4dbee5 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
 MAJOR 0
 MINOR 7
-BUILD 2
-PATCH 1
+BUILD 3
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 2b11178..f4264ab 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -118,8 +118,8 @@
 def UseBrowserController(runtime, system):
   supported_platforms = {
     'linux': ['ff', 'chromeOnAndroid', 'chrome'],
-    'mac': ['safari'],
-    'windows': ['ie9', 'ie10']
+    'mac': ['safari', 'chrome'],
+    'windows': ['ie9', 'ie10', 'ff', 'chrome']
   }
   # Platforms that we run on the fyi waterfall only.
   fyi_supported_platforms = {
@@ -183,6 +183,7 @@
     cmd.extend(targets)
 
     print 'Running: %s' % (' '.join(map(lambda arg: '"%s"' % arg, cmd)))
+    sys.stdout.flush()
     bot.RunProcess(cmd)
 
 
diff --git a/tools/coverage.dart b/tools/coverage.dart
index 34018c5..15333a6 100644
--- a/tools/coverage.dart
+++ b/tools/coverage.dart
@@ -354,7 +354,7 @@
   void getLibraries() {
     queuedCommands.add(new GetLibrariesCmd(isolateId));
   }
-  
+
   void enableDebugging(libraryId, enable) {
     queuedCommands.add(new SetLibraryPropertiesCmd(isolateId, libraryId, enable));
   }
@@ -441,7 +441,7 @@
     if (buffer == null || buffer.length == 0) {
       buffer = s;
     } else {
-      buffer = buffer.concat(s);
+      buffer = buffer + s;
     }
   }
 
@@ -471,7 +471,7 @@
     }
     if (i >= buffer.length) {
       return false;
-    } else { 
+    } else {
       return char != "{";
     }
   }
diff --git a/tools/dom/docs/docs.json b/tools/dom/docs/docs.json
index ba4c2b3..3b71d3c 100644
--- a/tools/dom/docs/docs.json
+++ b/tools/dom/docs/docs.json
@@ -188,10 +188,11 @@
     "HTMLDivElement": {
       "comment": [
         "/**",
-        " * Represents an HTML <div> element.",
+        " * A generic container for content on an HTML page;",
+        " * corresponds to the &lt;div&gt; tag.",
         " *",
-        " * The [DivElement] is a generic container for content and does not have any",
-        " * special significance. It is functionally similar to [SpanElement].",
+        " * The [DivElement] is a generic container and does not have any semantic",
+        " * significance. It is functionally similar to [SpanElement].",
         " *",
         " * The [DivElement] is a block-level element, as opposed to [SpanElement],",
         " * which is an inline-level element.",
@@ -479,6 +480,16 @@
       }
     }
   },
+  "dart.dom.indexed_db": {
+    "IDBDatabase": {
+      "comment": [
+        "/**",
+        " * An indexed database object for storing client-side data",
+        " * in web apps.",
+        " */"
+      ]
+    }
+  },
   "dart.dom.web_audio": {
     "ScriptProcessorNode": {
       "members": {
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index 2ba67aa..787af48 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -138,6 +138,36 @@
     cpp_library_emitter.EmitResolver(
         template_loader.Load('cpp_resolver.template'), dartium_output_dir)
 
+    path = os.path.join(cpp_output_dir, 'DartWebkitClassIds.h')
+    e = emitters.FileEmitter(path)
+    e.Emit("""
+// WARNING: Do not edit - generated code.
+// See dart/tools/dom/scripts/dartdomgenerator.py
+
+#ifndef DartWebkitClassIds_h
+#define DartWebkitClassIds_h
+
+namespace WebCore {
+
+enum {
+    _HistoryCrossFrameClassId = 0,
+    _LocationCrossFrameClassId,
+    _DOMWindowCrossFrameClassId,
+    _NPObjectClassId,
+    // New types that are not auto-generated should be added here.
+""")
+    for interface in webkit_database.GetInterfaces():
+      interface_name = interface.id
+      e.Emit('    %sClassId,\n' % interface_name)
+    e.Emit("""
+    NumWebkitClassIds
+};
+
+} // namespace WebCore
+
+#endif // DartWebkitClassIds_h
+""")
+
   _logger.info('Flush...')
   emitters.Flush()
 
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index acfccc1..7b7ca8e 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -166,8 +166,11 @@
       full_operation_str = self._GetStringRepresentation(interface, operation)
       if (full_operation_str in renamed_overloads and
           renamed_overloads[full_operation_str] not in already_renamed):
-        operation.ext_attrs['DartName'] = renamed_overloads[
-            full_operation_str]
+        dart_name = renamed_overloads[full_operation_str]
+        if not dart_name:
+          continue
+
+        operation.ext_attrs['DartName'] = dart_name
         potential_added_operations.add(operation.id)
       self._EnsureNoMultipleTypeSignatures(interface, operation,
           operations_by_name)
@@ -635,6 +638,20 @@
     has_length = False
     has_length_setter = False
 
+    def _HasExplicitIndexedGetter(self):
+      return any(op.id == 'getItem' for op in self._interface.operations)
+
+    def _HasCustomIndexedGetter(self):
+      return 'CustomIndexedGetter' in self._interface.ext_attrs
+
+    def _HasNativeIndexedGetter(self):
+      return not (_HasCustomIndexedGetter(self) or _HasExplicitIndexedGetter(self))
+
+    if _HasExplicitIndexedGetter(self):
+      getter_name = 'getItem'
+    else:
+      getter_name = '_nativeIndexedGetter'
+
     for attr in self._interface.attributes:
       if attr.id == 'length':
         has_length = True
@@ -648,8 +665,9 @@
         {
           'DEFINE_LENGTH_AS_NUM_ITEMS': not has_length and has_num_items,
           'DEFINE_LENGTH_SETTER': not has_length_setter,
+          'USE_NATIVE_INDEXED_GETTER': _HasNativeIndexedGetter(self) or _HasExplicitIndexedGetter(self),
         })
-    self._members_emitter.Emit(template, E=element_name)
+    self._members_emitter.Emit(template, E=element_name, GETTER=getter_name)
 
   def SecureOutputType(self, type_name, is_dart_type=False,
       can_narrow_type=False):
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 4a21a49..7242512 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -157,8 +157,6 @@
 # $dom in installments instead of all at once, but the intent is to move all of
 # these either into private_html_members or remove them from this list entirely.
 dom_private_html_members = monitored.Set('htmlrenamer.private_html_members', [
-  'Document.createElement',
-  'Document.createElementNS',
   'EventTarget.addEventListener',
   'EventTarget.removeEventListener',
 ])
@@ -273,6 +271,7 @@
   'MutationEvent.initMutationEvent',
   'MutationObserver.observe',
   'Node.attributes',
+  'Node.baseURI',
   'Node.localName',
   'Node.namespaceURI',
   'Node.removeChild',
@@ -367,6 +366,8 @@
       'DOMString repetitionType)': 'createPatternFromImage',
   'DataTransferItemList.add(File file)': 'addFile',
   'DataTransferItemList.add(DOMString data, DOMString type)': 'addData',
+  'Document.createElement(DOMString tagName)': None,
+  'Document.createElementNS(DOMString namespaceURI, DOMString qualifiedName)': None,
   'FormData.append(DOMString name, Blob value, DOMString filename)':
       'appendBlob',
   'IDBDatabase.transaction(DOMStringList storeNames, DOMString mode)':
@@ -706,7 +707,6 @@
     'Node.get:DOCUMENT_POSITION_FOLLOWING',
     'Node.get:DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC',
     'Node.get:DOCUMENT_POSITION_PRECEDING',
-    'Node.get:baseURI',
     'Node.get:prefix',
     'Node.hasAttributes',
     'Node.isDefaultNamespace',
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index fbe61c34..40c75d0 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -295,11 +295,11 @@
 _factory_ctr_strings = {
   'html': {
       'provider_name': 'document',
-      'constructor_name': '$dom_createElement'
+      'constructor_name': 'createElement'
   },
   'indexed_db': {
       'provider_name': 'document',
-      'constructor_name': '$dom_createElement'
+      'constructor_name': 'createElement'
   },
   'svg': {
     'provider_name': '_SvgElementFactoryProvider',
@@ -307,19 +307,19 @@
   },
   'typed_data': {
       'provider_name': 'document',
-      'constructor_name': '$dom_createElement'
+      'constructor_name': 'createElement'
   },
   'web_audio': {
     'provider_name': 'document',
-    'constructor_name': '$dom_createElement'
+    'constructor_name': 'createElement'
   },
   'web_gl': {
     'provider_name': 'document',
-    'constructor_name': '$dom_createElement'
+    'constructor_name': 'createElement'
   },
   'web_sql': {
     'provider_name': 'document',
-    'constructor_name': '$dom_createElement'
+    'constructor_name': 'createElement'
   },
 }
 
diff --git a/tools/dom/scripts/templateloader.py b/tools/dom/scripts/templateloader.py
index 647362b..88ef894 100644
--- a/tools/dom/scripts/templateloader.py
+++ b/tools/dom/scripts/templateloader.py
@@ -82,7 +82,7 @@
           variable = words[1]
           if variable in conditions:
             condition_stack.append((active, seen_else))
-            active = conditions[variable]
+            active = active and conditions[variable]
             seen_else = False
           else:
             error(lineno, "Unknown $if variable '%s'" % variable)
@@ -93,7 +93,8 @@
           if seen_else:
             raise error(lineno, 'Double $else')
           seen_else = True
-          active = not active
+          (parentactive, _) = condition_stack[len(condition_stack) - 1]
+          active = not active and parentactive
 
         elif directive == '$endif':
           if not condition_stack:
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index 95c64b6..3ad3381 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -18,7 +18,32 @@
       convertDartClosureToJS(_callCreated, 1));
 }
 
-void _registerCustomElement(context, document, String tag, Type type) {
+const _typeNameToTag = const {
+  'HTMLAnchorElement': 'a',
+  'HTMLAudioElement': 'audio',
+  'HTMLButtonElement': 'button',
+  'HTMLCanvasElement': 'canvas',
+  'HTMLDivElement': 'div',
+  'HTMLImageElement': 'img',
+  'HTMLInputElement': 'input',
+  'HTMLLIElement': 'li',
+  'HTMLLabelElement': 'label',
+  'HTMLMenuElement': 'menu',
+  'HTMLMeterElement': 'meter',
+  'HTMLOListElement': 'ol',
+  'HTMLOptionElement': 'option',
+  'HTMLOutputElement': 'output',
+  'HTMLParagraphElement': 'p',
+  'HTMLPreElement': 'pre',
+  'HTMLProgressElement': 'progress',
+  'HTMLSelectElement': 'select',
+  'HTMLSpanElement': 'span',
+  'HTMLUListElement': 'ul',
+  'HTMLVideoElement': 'video',
+};
+
+void _registerCustomElement(context, document, String tag, Type type,
+    String extendsTagName) {
   // Function follows the same pattern as the following JavaScript code for
   // registering a custom element.
   //
@@ -38,6 +63,10 @@
     throw new ArgumentError(type);
   }
 
+  // Workaround for 13190- use an article element to ensure that HTMLElement's
+  // interceptor is resolved correctly.
+  getNativeInterceptor(new Element.tag('article'));
+
   String baseClassName = findDispatchTagForInterceptorClass(interceptorClass);
   if (baseClassName == null) {
     throw new ArgumentError(type);
@@ -60,6 +89,15 @@
 
   setNativeSubclassDispatchRecord(proto, interceptor);
 
-  JS('void', '#.register(#, #)',
-      document, tag, JS('', '{prototype: #}', proto));
+  var options = JS('=Object', '{prototype: #}', proto);
+
+  if (baseClassName != 'HTMLElement') {
+    if (extendsTagName != null) {
+      JS('=Object', '#.extends = #', options, extendsTagName);
+    } else if (_typeNameToTag.containsKey(baseClassName)) {
+      JS('=Object', '#.extends = #', options, _typeNameToTag[baseClassName]);
+    }
+  }
+
+  JS('void', '#.register(#, #)', document, tag, options);
 }
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 80676b0..2a063c0 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -4,6 +4,31 @@
 
 part of html;
 
+class _ConsoleVariables {
+  Map<String, Object> _data = new Map<String, Object>();
+  
+  /**
+   * Forward member accesses to the backing JavaScript object.
+   */
+  noSuchMethod(Invocation invocation) {
+    String member = MirrorSystem.getName(invocation.memberName);
+    if (invocation.isGetter) {
+      return _data[member];
+    } else if (invocation.isSetter) {
+      _data[member] = invocation.positionalArguments[0];
+    } else {
+      return Function.apply(_data[member], invocation.positionalArguments, invocation.namedArguments);
+    }
+  }
+  
+  void clear() => _data.clear();
+
+  /**
+   * List all variables currently defined.
+   */
+  List variables() => _data.keys.toList(growable: false);
+}
+
 class _Utils {
   static double dateTimeToDouble(DateTime dateTime) =>
       dateTime.millisecondsSinceEpoch.toDouble();
@@ -102,6 +127,41 @@
     return map;
   }
 
+  static _ConsoleVariables _consoleTempVariables = new _ConsoleVariables();
+  /**
+   * Takes an [expression] and a list of [local] variable and returns an
+   * expression for a closure with a body matching the original expression
+   * where locals are passed in as arguments. Returns a list containing the
+   * String expression for the closure and the list of arguments that should
+   * be passed to it.
+   *
+   * For example:
+   * <code>wrapExpressionAsClosure("foo + bar", ["bar", 40, "foo", 2])</code>
+   * will return:
+   * <code>["(final $var, final bar, final foo) => foo + bar", [40, 2]]</code>
+   */
+  static List wrapExpressionAsClosure(String expression, List locals) {
+    var args = {};
+    var sb = new StringBuffer("(");
+    addArg(arg, value) {
+      arg = stripMemberName(arg);
+      if (args.containsKey(arg)) return;
+      if (args.isNotEmpty) {
+        sb.write(", ");
+      }
+      sb.write("final $arg");
+      args[arg] = value;
+    }
+    
+    addArg("\$var", _consoleTempVariables);
+    
+    for (int i = 0; i < locals.length; i+= 2) {
+      addArg(locals[i], locals[i+1]);
+    }
+    sb..write(')=>\n$expression'); 
+    return [sb.toString(), args.values.toList(growable: false)];
+  }
+
   /**
    * Convenience helper to get the keys of a [Map] as a [List].
    */
diff --git a/tools/dom/src/shared_SVGFactoryProviders.dart b/tools/dom/src/shared_SVGFactoryProviders.dart
index 6f4b9a7..eca6a9c 100644
--- a/tools/dom/src/shared_SVGFactoryProviders.dart
+++ b/tools/dom/src/shared_SVGFactoryProviders.dart
@@ -7,7 +7,7 @@
 class _SvgElementFactoryProvider {
   static SvgElement createSvgElement_tag(String tag) {
     final Element temp =
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
     return temp;
   }
 }
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 67490a8..eba39e5 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -20,7 +20,7 @@
  *
  * * If you've never written a web app before, try our
  * tutorials&mdash;[A Game of Darts](http://dartlang.org/docs/tutorials).
- * 
+ *
  * * To see some web-based Dart apps in action and to play with the code,
  * download
  * [Dart Editor](http://www.dartlang.org/#get-started)
@@ -51,7 +51,8 @@
     JSName, Null, Returns,
     findDispatchTagForInterceptorClass, setNativeSubclassDispatchRecord;
 import 'dart:_interceptors' show
-    Interceptor, JSExtendableArray, findInterceptorConstructorForType;
+    Interceptor, JSExtendableArray, findInterceptorConstructorForType,
+    getNativeInterceptor;
 import 'dart:_isolate_helper' show IsolateNatives;
 import 'dart:_foreign_helper' show JS;
 
diff --git a/tools/dom/templates/html/dartium/cpp_header.template b/tools/dom/templates/html/dartium/cpp_header.template
index 00b95c2..5a6a8de 100644
--- a/tools/dom/templates/html/dartium/cpp_header.template
+++ b/tools/dom/templates/html/dartium/cpp_header.template
@@ -16,6 +16,7 @@
 struct Dart$INTERFACE {
     static const char* const dartImplementationClassName;
     static const char* const dartImplementationLibraryName;
+    static const int dartClassId;
     typedef $WEBCORE_CLASS_NAME NativeType;
     static const bool isNode = $IS_NODE;
     static const bool isActive = $IS_ACTIVE;
diff --git a/tools/dom/templates/html/dartium/cpp_implementation.template b/tools/dom/templates/html/dartium/cpp_implementation.template
index 3ca2ad6..4e3d741 100644
--- a/tools/dom/templates/html/dartium/cpp_implementation.template
+++ b/tools/dom/templates/html/dartium/cpp_implementation.template
@@ -5,6 +5,7 @@
 // WARNING: Do not edit - generated code.
 
 #include "config.h"
+#include "DartWebkitClassIds.h"
 #include "Dart$(INTERFACE).h"
 
 $INCLUDES
@@ -28,5 +29,5 @@
 
 const char* const Dart$(INTERFACE)::dartImplementationClassName = "$DART_IMPLEMENTATION_CLASS";
 const char* const Dart$(INTERFACE)::dartImplementationLibraryName = "$DART_IMPLEMENTATION_LIBRARY";
-
+const int Dart$(INTERFACE)::dartClassId = $(INTERFACE)ClassId;
 }
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 1a556b2..6cf45d4 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -354,8 +354,8 @@
    *
    * * [isTagSupported]
    */
-  factory $CLASSNAME.tag(String tag) =>
-      _$(CLASSNAME)FactoryProvider.createElement_tag(tag);
+  factory $CLASSNAME.tag(String tag, [String typeExtention]) =>
+      _$(CLASSNAME)FactoryProvider.createElement_tag(tag, typeExtention);
 
   /// Creates a new `<a>` element.
   ///
@@ -672,7 +672,7 @@
    * The tag should be a valid HTML tag name.
    */
   static bool isTagSupported(String tag) {
-    var e = _ElementFactoryProvider.createElement_tag(tag);
+    var e = _ElementFactoryProvider.createElement_tag(tag, null);
     return e is Element && !(e is UnknownElement);
   }
 
@@ -944,7 +944,7 @@
   @SupportedBrowser(SupportedBrowser.CHROME, '25')
   @Experimental()
   ShadowRoot get shadowRoot =>
-      JS('ShadowRoot', '#.shadowRoot || #.webkitShadowRoot', this, this);
+      JS('ShadowRoot|Null', '#.shadowRoot || #.webkitShadowRoot', this, this);
 $endif
 
 
@@ -1236,12 +1236,17 @@
     if (_parseDocument == null) {
       _parseDocument = document.implementation.createHtmlDocument('');
       _parseRange = _parseDocument.createRange();
+
+      // Workaround for Chrome bug 229142- URIs are not resolved in new doc.
+      var base = _parseDocument.createElement('base');
+      base.href = document._baseUri;
+      _parseDocument.head.append(base);
     }
     var contextElement;
     if (this is BodyElement) {
       contextElement = _parseDocument.body;
     } else {
-      contextElement = _parseDocument.$dom_createElement(tagName);
+      contextElement = _parseDocument.createElement(tagName);
       _parseDocument.body.append(contextElement);
     }
     var fragment;
@@ -1322,12 +1327,22 @@
 $if DART2JS
   // Optimization to improve performance until the dart2js compiler inlines this
   // method.
-  static dynamic createElement_tag(String tag) =>
-      // Firefox may return a JS function for some types (Embed, Object).
-      JS('Element|=Object', 'document.createElement(#)', tag);
+  static dynamic createElement_tag(String tag, String typeExtension) {
+    // Firefox may return a JS function for some types (Embed, Object).
+    if (typeExtension != null) {
+      return JS('Element|=Object', 'document.createElement(#, #)',
+          tag, typeExtension);
+    }
+    // Should be able to eliminate this and just call the two-arg version above
+    // with null typeExtension, but Chrome treats the tag as case-sensitive if
+    // typeExtension is null.
+    // https://code.google.com/p/chromium/issues/detail?id=282467
+    return JS('Element|=Object', 'document.createElement(#)', tag);
+  }
+
 $else
-  static Element createElement_tag(String tag) =>
-      document.$dom_createElement(tag);
+  static Element createElement_tag(String tag, String typeExtension) =>
+      document.createElement(tag, typeExtension);
 $endif
 }
 
diff --git a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
index e4aaa29..a29e0c1 100644
--- a/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLDocument.darttemplate
@@ -174,13 +174,81 @@
 $endif
 
   @Experimental
+  /**
+   * Register a custom subclass of Element to be instantiatable by the DOM.
+   *
+   * This is necessary to allow the construction of any custom elements.
+   *
+   * The class being registered must either subclass HtmlElement or SvgElement.
+   * If they subclass these directly then they can be used as:
+   *
+   *     class FooElement extends HtmlElement{
+   *        void created() {
+   *          print('FooElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-foo', FooElement);
+   *       var myFoo = new Element.tag('x-foo');
+   *       // prints 'FooElement created!' to the console.
+   *     }
+   *
+   * The custom element can also be instantiated via HTML using the syntax
+   * `<x-foo></x-foo>`
+   *
+   * Other elements can be subclassed as well:
+   *
+   *     class BarElement extends InputElement{
+   *        void created() {
+   *          print('BarElement created!');
+   *        }
+   *     }
+   *
+   *     main() {
+   *       document.register('x-bar', BarElement);
+   *       var myBar = new Element.tag('input', 'x-bar');
+   *       // prints 'BarElement created!' to the console.
+   *     }
+   *
+   * This custom element can also be instantiated via HTML using the syntax
+   * `<input is="x-bar"></input>`
+   *
+   * The [nativeTagName] parameter is needed by platforms without native support
+   * when subclassing a native type other than:
+   *
+   * * HtmlElement
+   * * SvgElement
+   * * AnchorElement
+   * * AudioElement
+   * * ButtonElement
+   * * CanvasElement
+   * * DivElement
+   * * ImageElement
+   * * InputElement
+   * * LIElement
+   * * LabelElement
+   * * MenuElement
+   * * MeterElement
+   * * OListElement
+   * * OptionElement
+   * * OutputElement
+   * * ParagraphElement
+   * * PreElement
+   * * ProgressElement
+   * * SelectElement
+   * * SpanElement
+   * * UListElement
+   * * VideoElement
+   */
 $if DART2JS
-  void register(String tag, Type customElementClass) {
-    _registerCustomElement(JS('', 'window'), this, tag, customElementClass);
+  void register(String tag, Type customElementClass, {String nativeTagName}) {
+    _registerCustomElement(JS('', 'window'), this, tag, customElementClass,
+        nativeTagName);
   }
 $else
-  void register(String tag, Type custom) {
-    _Utils.register(tag, custom);
+  void register(String tag, Type customElementClass, {String nativeTagName}) {
+    _Utils.register(tag, customElementClass);
   }
 $endif
 
diff --git a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
index 2aa82b0..fe9ae78 100644
--- a/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLInputElement.darttemplate
@@ -29,7 +29,7 @@
     $NATIVESPEC {
 
   factory InputElement({String type}) {
-    var e = document.$dom_createElement("input");
+    var e = document.createElement("input");
     if (type != null) {
       try {
         // IE throws an exception for unknown types.
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index f54aef7..f1b7bdd 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -201,7 +201,7 @@
   //       + <td>Bar</td>
   //
   static Element _extractTemplateFromAttributeTemplate(Element el) {
-    var template = el.document.$dom_createElement('template');
+    var template = el.document.createElement('template');
     el.parentNode.insertBefore(template, el);
 
     for (var name in el.attributes.keys.toList()) {
diff --git a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
index 576854b..c9c70a7 100644
--- a/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_SVGElement.darttemplate
@@ -34,7 +34,7 @@
   static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
 
   factory $CLASSNAME.tag(String tag) =>
-      document.$dom_createElementNS("http://www.w3.org/2000/svg", tag);
+      document.createElementNS("http://www.w3.org/2000/svg", tag);
   factory $CLASSNAME.svg(String svg,
       {NodeValidator validator, NodeTreeSanitizer treeSanitizer}) {
 
diff --git a/tools/dom/templates/immutable_list_mixin.darttemplate b/tools/dom/templates/immutable_list_mixin.darttemplate
index fc48b49..78a846f 100644
--- a/tools/dom/templates/immutable_list_mixin.darttemplate
+++ b/tools/dom/templates/immutable_list_mixin.darttemplate
@@ -17,8 +17,12 @@
 $if DART2JS
       return JS('$E', '#[0]', this);
 $else
+$if USE_NATIVE_INDEXED_GETTER
+      return $GETTER(0);
+$else
       return this[0];
 $endif
+$endif
     }
     throw new StateError("No elements");
   }
@@ -29,8 +33,12 @@
 $if DART2JS
       return JS('$E', '#[#]', this, len - 1);
 $else
+$if USE_NATIVE_INDEXED_GETTER
+      return $GETTER(len - 1);
+$else
       return this[len - 1];
 $endif
+$endif
     }
     throw new StateError("No elements");
   }
@@ -41,8 +49,12 @@
 $if DART2JS
       return JS('$E', '#[0]', this);
 $else
+$if USE_NATIVE_INDEXED_GETTER
+      return $GETTER(0);
+$else
       return this[0];
 $endif
+$endif
     }
     if (len == 0) throw new StateError("No elements");
     throw new StateError("More than one element");
diff --git a/tools/task_kill.py b/tools/task_kill.py
index 56b0de9..ec6b574 100755
--- a/tools/task_kill.py
+++ b/tools/task_kill.py
@@ -166,8 +166,7 @@
     status += KillDart();
   if (options.kill_browsers):
     status += KillBrowsers()
-  # Investigating hanging firefox, see issue 13121
-  return 0
+  return status
 
 if __name__ == '__main__':
   sys.exit(Main())
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index c6e07e7..f370863 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -147,10 +147,9 @@
           if (_cleanup != null) {
             _cleanup();
           }
-          doneCompleter.complete(true);
         }).catchError((error) {
           _logEvent("Error closing browsers: $error");
-        });
+        }).whenComplete(() => doneCompleter.complete(true));
       });
       return true;
     }).catchError((error) {
@@ -317,34 +316,69 @@
 
 
 class Chrome extends Browser {
-  /**
-   * The binary used to run chrome - changing this can be nececcary for
-   * testing or using non standard chrome installation.
-   */
-  static const String binary = "google-chrome";
+  static String _binary = _getBinary();
+
+  String _version = "Version not found yet";
+
+  // This is extracted to a function since we may need to support several
+  // locations.
+  static String _getWindowsBinary() {
+    return "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
+  }
+
+  static String _getBinary() {
+    if (Platform.isWindows) return _getWindowsBinary();
+    if (Platform.isMacOS) {
+      return "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
+    }
+    if (Platform.isLinux) return 'google-chrome';
+  }
+
+  Future<bool> _getVersion() {
+    if (Platform.isWindows) {
+      // The version flag does not work on windows.
+      // See issue:
+      // https://code.google.com/p/chromium/issues/detail?id=158372
+      // The registry hack does not seem to work.
+      _version = "Can't get version on windows";
+      // We still validate that the binary exists so that we can give good
+      // feedback.
+      return new File(_binary).exists().then((exists) {
+        if (!exists) {
+          _logEvent("Chrome binary not available.");
+          _logEvent("Make sure $_binary is a valid program for running chrome");
+        }
+        return exists;
+      });
+    }
+    return Process.run(_binary, ["--version"]).then((var versionResult) {
+      if (versionResult.exitCode != 0) {
+        _logEvent("Failed to chrome get version");
+        _logEvent("Make sure $_binary is a valid program for running chrome");
+        return false;
+      }
+      _version = versionResult.stdout;
+      return true;
+    });
+  }
+
 
   Future<bool> start(String url) {
     _logEvent("Starting chrome browser on: $url");
     // Get the version and log that.
-    return Process.run(binary, ["--version"]).then((var versionResult) {
-      if (versionResult.exitCode != 0) {
-        _logEvent("Failed to chrome get version");
-        _logEvent("Make sure $binary is a valid program for running chrome");
-        return new Future.value(false);
-      }
-      version = versionResult.stdout;
-      _logEvent("Got version: $version");
+    return _getVersion().then((success) {
+      if (!success) return false;
+      _logEvent("Got version: $_version");
 
       return new Directory('').createTemp().then((userDir) {
         _cleanup = () { userDir.deleteSync(recursive: true); };
         var args = ["--user-data-dir=${userDir.path}", url,
                     "--disable-extensions", "--disable-popup-blocking",
                     "--bwsi", "--no-first-run"];
-        return startBrowser(binary, args);
-
+        return startBrowser(_binary, args);
       });
     }).catchError((e) {
-      _logEvent("Running $binary --version failed with $e");
+      _logEvent("Running $_binary --version failed with $e");
       return false;
     });
   }
@@ -455,12 +489,6 @@
 }
 
 class Firefox extends Browser {
-  /**
-   * The binary used to run firefox - changing this can be nececcary for
-   * testing or using non standard firefox installation.
-   */
-  static const String binary = "firefox";
-
   static const String enablePopUp =
       'user_pref("dom.disable_open_during_load", false);';
   static const String disableDefaultCheck =
@@ -468,6 +496,8 @@
   static const String disableScriptTimeLimit =
       'user_pref("dom.max_script_run_time", 0);';
 
+  static string _binary = _getBinary();
+
   Future _createPreferenceFile(var path) {
     var file = new File("${path.toString()}/user.js");
     var randomFile = file.openSync(mode: FileMode.WRITE);
@@ -477,11 +507,21 @@
     randomFile.close();
   }
 
+  // This is extracted to a function since we may need to support several
+  // locations.
+  static String _getWindowsBinary() {
+    return "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe";
+  }
+
+  static String _getBinary() {
+    if (Platform.isWindows) return _getWindowsBinary();
+    if (Platform.isLinux) return 'firefox';
+  }
 
   Future<bool> start(String url) {
     _logEvent("Starting firefox browser on: $url");
     // Get the version and log that.
-    return Process.run(binary, ["--version"]).then((var versionResult) {
+    return Process.run(_binary, ["--version"]).then((var versionResult) {
       if (versionResult.exitCode != 0) {
         _logEvent("Failed to firefox get version");
         _logEvent("Make sure $binary is a valid program for running firefox");
@@ -495,7 +535,7 @@
         _cleanup = () { userDir.deleteSync(recursive: true); };
         var args = ["-profile", "${userDir.path}",
                     "-no-remote", "-new-instance", url];
-        return startBrowser(binary, args);
+        return startBrowser(_binary, args);
 
       });
     }).catchError((e) {