Version 1.0.3.0

svn merge -r 30767:30923 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@30939 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 06e0a05..b9be96f 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -895,6 +895,8 @@
    */
   SimpleIdentifier get identifier => _identifier;
 
+  int get precedence => 15;
+
   /**
    * Set the identifier representing the argument being tested to the given identifier.
    *
@@ -1163,6 +1165,8 @@
    */
   Expression get expression => _expression;
 
+  int get precedence => 7;
+
   /**
    * Return the name of the type being cast to.
    *
@@ -1376,6 +1380,8 @@
    */
   Expression get leftHandSide => _leftHandSide;
 
+  int get precedence => 1;
+
   /**
    * Return the element associated with the operator based on the propagated type of the
    * left-hand-side, or `null` if the AST structure has not been resolved, if the operator is
@@ -1580,6 +1586,8 @@
    */
   Expression get leftOperand => _leftOperand;
 
+  int get precedence => operator.type.precedence;
+
   /**
    * Return the element associated with the operator based on the propagated type of the left
    * operand, or `null` if the AST structure has not been resolved, if the operator is not
@@ -1997,6 +2005,8 @@
 
   Token get endToken => cascadeSections.endToken;
 
+  int get precedence => 2;
+
   /**
    * Return the target of the cascade sections.
    *
@@ -3198,6 +3208,8 @@
 
   Token get endToken => _elseExpression.endToken;
 
+  int get precedence => 3;
+
   /**
    * Return the expression that is executed if the condition evaluates to `true`.
    *
@@ -4511,7 +4523,7 @@
  * @coverage dart.engine.ast
  */
 class EphemeralIdentifier extends SimpleIdentifier {
-  EphemeralIdentifier.full(ASTNode parent, int location) : super.full(new Token(TokenType.IDENTIFIER, location)) {
+  EphemeralIdentifier.full(ASTNode parent, int location) : super.full(new StringToken(TokenType.IDENTIFIER, "", location)) {
     parent.becomeParentOf(this);
   }
 
@@ -4628,6 +4640,19 @@
   }
 
   /**
+   * Return the precedence of this expression. The precedence is a positive integer value that
+   * defines how the source code is parsed into an AST. For example `a * b + c` is parsed as
+   * `(a * b) + c` because the precedence of `*` is greater than the precedence of
+   * `+`.
+   *
+   * You should not assume that returned values will stay the same, they might change as result of
+   * specification change. Only relative order should be used.
+   *
+   * @return the precedence of this expression
+   */
+  int get precedence;
+
+  /**
    * If this expression is an argument to an invocation, and the AST structure has been resolved,
    * and the function being invoked is known based on propagated type information, and this
    * expression corresponds to one of the parameters of the function being invoked, then return the
@@ -6110,6 +6135,8 @@
    */
   FormalParameterList get parameters => _parameters;
 
+  int get precedence => 16;
+
   /**
    * Set the body of the function to the given function body.
    *
@@ -6226,6 +6253,8 @@
    */
   Expression get function => _function;
 
+  int get precedence => 15;
+
   /**
    * Return the element associated with the function being invoked based on propagated type
    * information, or `null` if the AST structure has not been resolved or the function could
@@ -7153,6 +7182,8 @@
    */
   Token get leftBracket => _leftBracket;
 
+  int get precedence => 15;
+
   /**
    * Return the element associated with the operator based on the propagated type of the target, or
    * `null` if the AST structure has not been resolved or if the operator could not be
@@ -7437,6 +7468,8 @@
 
   Token get endToken => _argumentList.endToken;
 
+  int get precedence => 15;
+
   /**
    * Return `true` if this creation expression is used to invoke a constant constructor.
    *
@@ -7768,6 +7801,8 @@
    */
   Expression get expression => _expression;
 
+  int get precedence => 7;
+
   /**
    * Return the name of the type being tested for.
    *
@@ -8079,6 +8114,8 @@
     return builder.toString();
   }
 
+  int get precedence => 15;
+
   Element get propagatedElement => null;
 
   Element get staticElement => null;
@@ -8215,6 +8252,7 @@
  * @coverage dart.engine.ast
  */
 abstract class Literal extends Expression {
+  int get precedence => 16;
 }
 
 /**
@@ -8751,6 +8789,8 @@
    */
   SimpleIdentifier get methodName => _methodName;
 
+  int get precedence => 15;
+
   /**
    * Return the expression used to compute the receiver of the invocation. If this invocation is not
    * part of a cascade expression, then this is the same as [getTarget]. If this invocation
@@ -8903,6 +8943,8 @@
    */
   Label get name => _name;
 
+  int get precedence => 0;
+
   /**
    * Set the expression with which the name is associated to the given expression.
    *
@@ -9356,6 +9398,8 @@
    */
   Token get leftParenthesis => _leftParenthesis;
 
+  int get precedence => 15;
+
   /**
    * Return the right parenthesis.
    *
@@ -9625,6 +9669,8 @@
    */
   Expression get operand => _operand;
 
+  int get precedence => 15;
+
   /**
    * Return the element associated with the operator based on the propagated type of the operand, or
    * `null` if the AST structure has not been resolved, if the operator is not user definable,
@@ -9804,6 +9850,8 @@
    */
   Expression get operand => _operand;
 
+  int get precedence => 14;
+
   /**
    * Return the element associated with the operator based on the propagated type of the operand, or
    * `null` if the AST structure has not been resolved, if the operator is not user definable,
@@ -9972,6 +10020,8 @@
 
   String get name => "${_prefix.name}.${_identifier.name}";
 
+  int get precedence => 15;
+
   /**
    * Return the prefix associated with the library in which the identifier is defined.
    *
@@ -10081,6 +10131,8 @@
 
   Token get endToken => _propertyName.endToken;
 
+  int get precedence => 15;
+
   /**
    * Return the name of the property being accessed.
    *
@@ -10306,6 +10358,8 @@
 
   Token get endToken => keyword;
 
+  int get precedence => 0;
+
   void visitChildren(ASTVisitor visitor) {
   }
 }
@@ -10635,6 +10689,8 @@
 
   String get name => token.lexeme;
 
+  int get precedence => 16;
+
   Element get propagatedElement => _propagatedElement;
 
   Element get staticElement => _staticElement;
@@ -11199,6 +11255,8 @@
 
   Token get endToken => keyword;
 
+  int get precedence => 16;
+
   void visitChildren(ASTVisitor visitor) {
   }
 }
@@ -11580,6 +11638,8 @@
 
   Token get endToken => keyword;
 
+  int get precedence => 16;
+
   void visitChildren(ASTVisitor visitor) {
   }
 }
@@ -11642,6 +11702,8 @@
    */
   Expression get expression => _expression;
 
+  int get precedence => 0;
+
   /**
    * Set the expression computing the exception to be thrown to the given expression.
    *
@@ -15888,9 +15950,10 @@
   }
 
   List clone3(NodeList nodes) {
+    int count = nodes.length;
     List clonedNodes = new List();
-    for (ASTNode node in nodes) {
-      clonedNodes.add(node.accept(this) as ASTNode);
+    for (int i = 0; i < count; i++) {
+      clonedNodes.add((nodes[i]).accept(this) as ASTNode);
     }
     return clonedNodes;
   }
@@ -15908,7 +15971,7 @@
    * @param second the second node being compared
    * @return `true` if the two AST nodes are equal
    */
-  static bool equals3(CompilationUnit first, CompilationUnit second) {
+  static bool equals4(CompilationUnit first, CompilationUnit second) {
     ASTComparator comparator = new ASTComparator();
     return comparator.isEqual(first, second);
   }
@@ -16176,7 +16239,7 @@
 
   bool visitIntegerLiteral(IntegerLiteral node) {
     IntegerLiteral other = this._other as IntegerLiteral;
-    return isEqual6(node.literal, other.literal) && identical(node.value, other.value);
+    return isEqual6(node.literal, other.literal) && (node.value == other.value);
   }
 
   bool visitInterpolationExpression(InterpolationExpression node) {
@@ -16331,7 +16394,7 @@
 
   bool visitSimpleStringLiteral(SimpleStringLiteral node) {
     SimpleStringLiteral other = this._other as SimpleStringLiteral;
-    return isEqual6(node.literal, other.literal) && identical(node.value, other.value);
+    return isEqual6(node.literal, other.literal) && (node.value == other.value);
   }
 
   bool visitStringInterpolation(StringInterpolation node) {
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index b616ffe..965bcbd 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -606,7 +606,7 @@
       tails = new Set<N>();
       _edges[head] = tails;
     }
-    javaSetAdd(tails, tail);
+    tails.add(tail);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index ce01e2f..c024cc0 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -182,6 +182,13 @@
   bool get isAbstract;
 
   /**
+   * Return `true` if this element has an annotation of the form '@proxy'.
+   *
+   * @return `true` if this element defines a proxy
+   */
+  bool get isProxy;
+
+  /**
    * Return `true` if this class is defined by a typedef construct.
    *
    * @return `true` if this class is defined by a typedef construct
@@ -408,6 +415,11 @@
  */
 abstract class Element {
   /**
+   * An Unicode right arrow.
+   */
+  static final String RIGHT_ARROW = " \u2192 ";
+
+  /**
    * A comparator that can be used to sort elements by their name offset. Elements with a smaller
    * offset will be sorted to be before elements with a larger name offset.
    */
@@ -574,6 +586,31 @@
    * @return the field, variable, or constructor being used as an annotation
    */
   Element get element;
+
+  /**
+   * Return `true` if this annotation marks the associated element as being deprecated.
+   *
+   * @return `true` if this annotation marks the associated element as being deprecated
+   */
+  bool get isDeprecated;
+
+  /**
+   * Return `true` if this annotation marks the associated method as being expected to
+   * override an inherited method.
+   *
+   * @return `true` if this annotation marks the associated method as overriding another
+   *         method
+   */
+  bool get isOverride;
+
+  /**
+   * Return `true` if this annotation marks the associated class as implementing a proxy
+   * object.
+   *
+   * @return `true` if this annotation marks the associated class as implementing a proxy
+   *         object
+   */
+  bool get isProxy;
 }
 
 /**
@@ -2102,7 +2139,7 @@
     classesToVisit.add(this);
     while (!classesToVisit.isEmpty) {
       ClassElement currentElement = classesToVisit.removeAt(0);
-      if (javaSetAdd(visitedClasses, currentElement)) {
+      if (visitedClasses.add(currentElement)) {
         for (FieldElement field in currentElement.fields) {
           if (!field.isFinal && !field.isConst && !field.isStatic && !field.isSynthetic) {
             return true;
@@ -2128,6 +2165,15 @@
 
   bool get isAbstract => hasModifier(Modifier.ABSTRACT);
 
+  bool get isProxy {
+    for (ElementAnnotation annotation in metadata) {
+      if (annotation.isProxy) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   bool get isTypedef => hasModifier(Modifier.TYPEDEF);
 
   bool get isValidMixin => hasModifier(Modifier.MIXIN);
@@ -2136,7 +2182,7 @@
     Set<ClassElement> visitedClasses = new Set<ClassElement>();
     ClassElement currentElement = this;
     while (currentElement != null && !visitedClasses.contains(currentElement)) {
-      javaSetAdd(visitedClasses, currentElement);
+      visitedClasses.add(currentElement);
       PropertyAccessorElement element = currentElement.getGetter(getterName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -2163,7 +2209,7 @@
     Set<ClassElement> visitedClasses = new Set<ClassElement>();
     ClassElement currentElement = this;
     while (currentElement != null && !visitedClasses.contains(currentElement)) {
-      javaSetAdd(visitedClasses, currentElement);
+      visitedClasses.add(currentElement);
       MethodElement element = currentElement.getMethod(methodName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -2190,7 +2236,7 @@
     Set<ClassElement> visitedClasses = new Set<ClassElement>();
     ClassElement currentElement = this;
     while (currentElement != null && !visitedClasses.contains(currentElement)) {
-      javaSetAdd(visitedClasses, currentElement);
+      visitedClasses.add(currentElement);
       PropertyAccessorElement element = currentElement.getSetter(setterName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -2886,6 +2932,27 @@
   static List<ElementAnnotationImpl> EMPTY_ARRAY = new List<ElementAnnotationImpl>(0);
 
   /**
+   * The name of the class used to mark an element as being deprecated.
+   */
+  static String _DEPRECATED_CLASS_NAME = "Deprecated";
+
+  /**
+   * The name of the top-level variable used to mark an element as being deprecated.
+   */
+  static String _DEPRECATED_VARIABLE_NAME = "deprecated";
+
+  /**
+   * The name of the top-level variable used to mark a method as being expected to override an
+   * inherited method.
+   */
+  static String _OVERRIDE_VARIABLE_NAME = "override";
+
+  /**
+   * The name of the top-level variable used to mark a class as implementing a proxy object.
+   */
+  static String _PROXY_VARIABLE_NAME = "proxy";
+
+  /**
    * Initialize a newly created annotation.
    *
    * @param element the element representing the field, variable, or constructor being used as an
@@ -2897,6 +2964,47 @@
 
   Element get element => _element;
 
+  bool get isDeprecated {
+    if (_element != null) {
+      LibraryElement library = _element.library;
+      if (library != null && library.isDartCore) {
+        if (_element is ConstructorElement) {
+          ConstructorElement constructorElement = _element as ConstructorElement;
+          if (constructorElement.enclosingElement.name == _DEPRECATED_CLASS_NAME) {
+            return true;
+          }
+        } else if (_element is PropertyAccessorElement && _element.name == _DEPRECATED_VARIABLE_NAME) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  bool get isOverride {
+    if (_element != null) {
+      LibraryElement library = _element.library;
+      if (library != null && library.isDartCore) {
+        if (_element is PropertyAccessorElement && _element.name == _OVERRIDE_VARIABLE_NAME) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  bool get isProxy {
+    if (_element != null) {
+      LibraryElement library = _element.library;
+      if (library != null && library.isDartCore) {
+        if (_element is PropertyAccessorElement && _element.name == _PROXY_VARIABLE_NAME) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
   String toString() => "@${_element.toString()}";
 }
 
@@ -3037,19 +3145,8 @@
 
   bool get isDeprecated {
     for (ElementAnnotation annotation in _metadata) {
-      Element element = annotation.element;
-      if (element != null) {
-        LibraryElement lib = element.library;
-        if (lib != null && lib.isDartCore) {
-          if (element is ConstructorElement) {
-            ConstructorElement constructorElement = element as ConstructorElement;
-            if (constructorElement.enclosingElement.name == "Deprecated") {
-              return true;
-            }
-          } else if (element is PropertyAccessorElement && element.name == "deprecated") {
-            return true;
-          }
-        }
+      if (annotation.isDeprecated) {
+        return true;
       }
     }
     return false;
@@ -3578,7 +3675,7 @@
     }
     builder.append(")");
     if (_type != null) {
-      builder.append(" -> ");
+      builder.append(Element.RIGHT_ARROW);
       builder.append(_type.returnType);
     }
   }
@@ -3819,6 +3916,45 @@
 
   accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
 
+  /**
+   * Treating the set of arrays defined in [ExecutableElementImpl] as one long array, this
+   * returns the index position of the passed child in this [FunctionElement]. This gives a
+   * unique integer for each element, this is provided primarily for function elements that do not
+   * have a name (closures), which cannot use [Element#getNameOffset]. If there is no such
+   * element, `-1` is returned.
+   *
+   * @param element the element to find and return an integer for, if there is no such element,
+   *          `-1` is returned
+   */
+  int getIndexPosition(Element element) {
+    List<FunctionElement> functions = this.functions;
+    List<LabelElement> labels = this.labels;
+    List<LocalVariableElement> localVariables = this.localVariables;
+    List<ParameterElement> parameters = this.parameters;
+    int count = 0;
+    for (int i = 0; i < functions.length; i++, count++) {
+      if (identical(element, functions[i])) {
+        return count;
+      }
+    }
+    for (int i = 0; i < labels.length; i++, count++) {
+      if (identical(element, labels[i])) {
+        return count;
+      }
+    }
+    for (int i = 0; i < localVariables.length; i++, count++) {
+      if (identical(element, localVariables[i])) {
+        return count;
+      }
+    }
+    for (int i = 0; i < parameters.length; i++, count++) {
+      if (identical(element, parameters[i])) {
+        return count;
+      }
+    }
+    return -1;
+  }
+
   ElementKind get kind => ElementKind.FUNCTION;
 
   SourceRange get visibleRange {
@@ -4017,7 +4153,7 @@
     }
     builder.append(")");
     if (_type != null) {
-      builder.append(" -> ");
+      builder.append(Element.RIGHT_ARROW);
       builder.append(_type.returnType);
     }
   }
@@ -4371,7 +4507,7 @@
    */
   static bool isUpToDate(LibraryElement library, int timeStamp, Set<LibraryElement> visitedLibraries) {
     if (!visitedLibraries.contains(library)) {
-      javaSetAdd(visitedLibraries, library);
+      visitedLibraries.add(library);
       if (timeStamp < library.definingCompilationUnit.source.modificationStamp) {
         return false;
       }
@@ -4472,7 +4608,7 @@
     for (ExportElement element in _exports) {
       LibraryElement library = element.exportedLibrary;
       if (library != null) {
-        javaSetAdd(libraries, library);
+        libraries.add(library);
       }
     }
     return new List.from(libraries);
@@ -4485,7 +4621,7 @@
     for (ImportElement element in _imports) {
       LibraryElement library = element.importedLibrary;
       if (library != null) {
-        javaSetAdd(libraries, library);
+        libraries.add(library);
       }
     }
     return new List.from(libraries);
@@ -4504,7 +4640,7 @@
     for (ImportElement element in _imports) {
       PrefixElement prefix = element.prefix;
       if (prefix != null) {
-        javaSetAdd(prefixes, prefix);
+        prefixes.add(prefix);
       }
     }
     return new List.from(prefixes);
@@ -4896,10 +5032,10 @@
   static void add(Set<Element> elements, Element element) {
     if (element is MultiplyDefinedElementImpl) {
       for (Element conflictingElement in (element as MultiplyDefinedElementImpl)._conflictingElements) {
-        javaSetAdd(elements, conflictingElement);
+        elements.add(conflictingElement);
       }
     } else {
-      javaSetAdd(elements, element);
+      elements.add(element);
     }
   }
 
@@ -5806,7 +5942,7 @@
     }
     builder.append(")");
     if (type != null) {
-      builder.append(" -> ");
+      builder.append(Element.RIGHT_ARROW);
       builder.append(type.returnType);
     }
     return builder.toString();
@@ -5873,6 +6009,24 @@
 }
 
 /**
+ * Instances of the class `FieldFormalParameterMember` represent a parameter element defined
+ * in a parameterized type where the values of the type parameters are known.
+ */
+class FieldFormalParameterMember extends ParameterMember implements FieldFormalParameterElement {
+  /**
+   * Initialize a newly created element to represent a parameter of the given parameterized type.
+   *
+   * @param baseElement the element on which the parameterized element was created
+   * @param definingType the type in which the element is defined
+   */
+  FieldFormalParameterMember(FieldFormalParameterElement baseElement, ParameterizedType definingType) : super(baseElement, definingType);
+
+  accept(ElementVisitor visitor) => visitor.visitFieldFormalParameterElement(this);
+
+  FieldElement get field => (baseElement as FieldFormalParameterElement).field;
+}
+
+/**
  * Instances of the class `FieldMember` represent a field element defined in a parameterized
  * type where the values of the type parameters are known.
  */
@@ -6119,7 +6273,7 @@
     }
     builder.append(")");
     if (type != null) {
-      builder.append(" -> ");
+      builder.append(Element.RIGHT_ARROW);
       builder.append(type.returnType);
     }
     return builder.toString();
@@ -6146,7 +6300,8 @@
     if (baseParameter == null || definingType.typeArguments.length == 0) {
       return baseParameter;
     }
-    if (baseParameter is! FieldFormalParameterElement) {
+    bool isFieldFormal = baseParameter is FieldFormalParameterElement;
+    if (!isFieldFormal) {
       Type2 baseType = baseParameter.type;
       List<Type2> argumentTypes = definingType.typeArguments;
       List<Type2> parameterTypes = TypeParameterTypeImpl.getTypes(definingType.typeParameters);
@@ -6155,6 +6310,9 @@
         return baseParameter;
       }
     }
+    if (isFieldFormal) {
+      return new FieldFormalParameterMember(baseParameter as FieldFormalParameterElement, definingType);
+    }
     return new ParameterMember(baseParameter, definingType);
   }
 
@@ -6324,7 +6482,7 @@
     }
     builder.append(")");
     if (type != null) {
-      builder.append(" -> ");
+      builder.append(Element.RIGHT_ARROW);
       builder.append(type.returnType);
     }
     return builder.toString();
@@ -6386,13 +6544,13 @@
 
   bool get isBottom => true;
 
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) => true;
-
-  bool isSubtypeOf(Type2 type) => true;
-
   bool isSupertypeOf(Type2 type) => false;
 
   BottomTypeImpl substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) => this;
+
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) => true;
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
 }
 
 /**
@@ -6417,15 +6575,6 @@
 
   bool get isDynamic => true;
 
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
-    if (identical(this, type)) {
-      return true;
-    }
-    return withDynamic;
-  }
-
-  bool isSubtypeOf(Type2 type) => true;
-
   bool isSupertypeOf(Type2 type) => true;
 
   Type2 substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) {
@@ -6437,6 +6586,15 @@
     }
     return this;
   }
+
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+    if (identical(this, type)) {
+      return true;
+    }
+    return withDynamic;
+  }
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => true;
 }
 
 /**
@@ -6557,7 +6715,8 @@
         builder.append("}");
         needsComma = true;
       }
-      builder.append(") -> ");
+      builder.append(")");
+      builder.append(Element.RIGHT_ARROW);
       if (returnType == null) {
         builder.append("null");
       } else {
@@ -6656,9 +6815,7 @@
     return element.hashCode;
   }
 
-  bool isAssignableTo(Type2 type) => this.isSubtypeOf(type);
-
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
     if (type == null) {
       return false;
     } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
@@ -6682,7 +6839,7 @@
         return false;
       } else if (t.normalParameterTypes.length > 0) {
         for (int i = 0; i < tTypes.length; i++) {
-          if (!tTypes[i].isMoreSpecificThan3(sTypes[i], withDynamic)) {
+          if (!(tTypes[i] as TypeImpl).isMoreSpecificThan3(sTypes[i], withDynamic, visitedTypePairs)) {
             return false;
           }
         }
@@ -6699,7 +6856,7 @@
         if (typeT == null) {
           return false;
         }
-        if (!typeT.isMoreSpecificThan3(entryS.getValue(), withDynamic)) {
+        if (!(typeT as TypeImpl).isMoreSpecificThan3(entryS.getValue(), withDynamic, visitedTypePairs)) {
           return false;
         }
       }
@@ -6713,7 +6870,7 @@
       }
       if (tOpTypes.length == 0 && sOpTypes.length == 0) {
         for (int i = 0; i < sTypes.length; i++) {
-          if (!tTypes[i].isMoreSpecificThan3(sTypes[i], withDynamic)) {
+          if (!(tTypes[i] as TypeImpl).isMoreSpecificThan3(sTypes[i], withDynamic, visitedTypePairs)) {
             return false;
           }
         }
@@ -6733,7 +6890,7 @@
           sAllTypes[i] = sOpTypes[j];
         }
         for (int i = 0; i < sAllTypes.length; i++) {
-          if (!tAllTypes[i].isMoreSpecificThan3(sAllTypes[i], withDynamic)) {
+          if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan3(sAllTypes[i], withDynamic, visitedTypePairs)) {
             return false;
           }
         }
@@ -6741,94 +6898,10 @@
     }
     Type2 tRetType = t.returnType;
     Type2 sRetType = s.returnType;
-    return sRetType.isVoid || tRetType.isMoreSpecificThan3(sRetType, withDynamic);
+    return sRetType.isVoid || (tRetType as TypeImpl).isMoreSpecificThan3(sRetType, withDynamic, visitedTypePairs);
   }
 
-  bool isSubtypeOf(Type2 type) {
-    if (type == null) {
-      return false;
-    } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
-      return true;
-    } else if (type is! FunctionType) {
-      return false;
-    } else if (this == type) {
-      return true;
-    }
-    FunctionType t = this;
-    FunctionType s = type as FunctionType;
-    List<Type2> tTypes = t.normalParameterTypes;
-    List<Type2> tOpTypes = t.optionalParameterTypes;
-    List<Type2> sTypes = s.normalParameterTypes;
-    List<Type2> sOpTypes = s.optionalParameterTypes;
-    if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
-      return false;
-    }
-    if (t.namedParameterTypes.length > 0) {
-      if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
-        return false;
-      } else if (t.normalParameterTypes.length > 0) {
-        for (int i = 0; i < tTypes.length; i++) {
-          if (!tTypes[i].isAssignableTo(sTypes[i])) {
-            return false;
-          }
-        }
-      }
-      Map<String, Type2> namedTypesT = t.namedParameterTypes;
-      Map<String, Type2> namedTypesS = s.namedParameterTypes;
-      if (namedTypesT.length < namedTypesS.length) {
-        return false;
-      }
-      JavaIterator<MapEntry<String, Type2>> iteratorS = new JavaIterator(getMapEntrySet(namedTypesS));
-      while (iteratorS.hasNext) {
-        MapEntry<String, Type2> entryS = iteratorS.next();
-        Type2 typeT = namedTypesT[entryS.getKey()];
-        if (typeT == null) {
-          return false;
-        }
-        if (!typeT.isAssignableTo(entryS.getValue())) {
-          return false;
-        }
-      }
-    } else if (s.namedParameterTypes.length > 0) {
-      return false;
-    } else {
-      int tArgLength = tTypes.length + tOpTypes.length;
-      int sArgLength = sTypes.length + sOpTypes.length;
-      if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
-        return false;
-      }
-      if (tOpTypes.length == 0 && sOpTypes.length == 0) {
-        for (int i = 0; i < sTypes.length; i++) {
-          if (!tTypes[i].isAssignableTo(sTypes[i])) {
-            return false;
-          }
-        }
-      } else {
-        List<Type2> tAllTypes = new List<Type2>(sArgLength);
-        for (int i = 0; i < tTypes.length; i++) {
-          tAllTypes[i] = tTypes[i];
-        }
-        for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
-          tAllTypes[i] = tOpTypes[j];
-        }
-        List<Type2> sAllTypes = new List<Type2>(sArgLength);
-        for (int i = 0; i < sTypes.length; i++) {
-          sAllTypes[i] = sTypes[i];
-        }
-        for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
-          sAllTypes[i] = sOpTypes[j];
-        }
-        for (int i = 0; i < sAllTypes.length; i++) {
-          if (!tAllTypes[i].isAssignableTo(sAllTypes[i])) {
-            return false;
-          }
-        }
-      }
-    }
-    Type2 tRetType = t.returnType;
-    Type2 sRetType = s.returnType;
-    return sRetType.isVoid || tRetType.isAssignableTo(sRetType);
-  }
+  bool isAssignableTo(Type2 type) => isSubtypeOf3(type, new Set<TypeImpl_TypePair>());
 
   /**
    * Set the actual types of the type arguments to the given types.
@@ -6907,7 +6980,8 @@
       builder.append("}");
       needsComma = true;
     }
-    builder.append(") -> ");
+    builder.append(")");
+    builder.append(Element.RIGHT_ARROW);
     if (returnType == null) {
       builder.append("null");
     } else {
@@ -6927,6 +7001,92 @@
     }
   }
 
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+    if (type == null) {
+      return false;
+    } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) {
+      return true;
+    } else if (type is! FunctionType) {
+      return false;
+    } else if (this == type) {
+      return true;
+    }
+    FunctionType t = this;
+    FunctionType s = type as FunctionType;
+    List<Type2> tTypes = t.normalParameterTypes;
+    List<Type2> tOpTypes = t.optionalParameterTypes;
+    List<Type2> sTypes = s.normalParameterTypes;
+    List<Type2> sOpTypes = s.optionalParameterTypes;
+    if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
+      return false;
+    }
+    if (t.namedParameterTypes.length > 0) {
+      if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
+        return false;
+      } else if (t.normalParameterTypes.length > 0) {
+        for (int i = 0; i < tTypes.length; i++) {
+          if (!(tTypes[i] as TypeImpl).isAssignableTo2(sTypes[i], visitedTypePairs)) {
+            return false;
+          }
+        }
+      }
+      Map<String, Type2> namedTypesT = t.namedParameterTypes;
+      Map<String, Type2> namedTypesS = s.namedParameterTypes;
+      if (namedTypesT.length < namedTypesS.length) {
+        return false;
+      }
+      JavaIterator<MapEntry<String, Type2>> iteratorS = new JavaIterator(getMapEntrySet(namedTypesS));
+      while (iteratorS.hasNext) {
+        MapEntry<String, Type2> entryS = iteratorS.next();
+        Type2 typeT = namedTypesT[entryS.getKey()];
+        if (typeT == null) {
+          return false;
+        }
+        if (!(typeT as TypeImpl).isAssignableTo2(entryS.getValue(), visitedTypePairs)) {
+          return false;
+        }
+      }
+    } else if (s.namedParameterTypes.length > 0) {
+      return false;
+    } else {
+      int tArgLength = tTypes.length + tOpTypes.length;
+      int sArgLength = sTypes.length + sOpTypes.length;
+      if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
+        return false;
+      }
+      if (tOpTypes.length == 0 && sOpTypes.length == 0) {
+        for (int i = 0; i < sTypes.length; i++) {
+          if (!(tTypes[i] as TypeImpl).isAssignableTo2(sTypes[i], visitedTypePairs)) {
+            return false;
+          }
+        }
+      } else {
+        List<Type2> tAllTypes = new List<Type2>(sArgLength);
+        for (int i = 0; i < tTypes.length; i++) {
+          tAllTypes[i] = tTypes[i];
+        }
+        for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
+          tAllTypes[i] = tOpTypes[j];
+        }
+        List<Type2> sAllTypes = new List<Type2>(sArgLength);
+        for (int i = 0; i < sTypes.length; i++) {
+          sAllTypes[i] = sTypes[i];
+        }
+        for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
+          sAllTypes[i] = sOpTypes[j];
+        }
+        for (int i = 0; i < sAllTypes.length; i++) {
+          if (!(tAllTypes[i] as TypeImpl).isAssignableTo2(sAllTypes[i], visitedTypePairs)) {
+            return false;
+          }
+        }
+      }
+    }
+    Type2 tRetType = t.returnType;
+    Type2 sRetType = s.returnType;
+    return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo2(sRetType, visitedTypePairs);
+  }
+
   /**
    * Return the return type defined by this function's element.
    *
@@ -6994,7 +7154,7 @@
     }
     int longestPath = 1;
     try {
-      javaSetAdd(visitedClasses, classElement);
+      visitedClasses.add(classElement);
       List<InterfaceType> superinterfaces = classElement.interfaces;
       int pathLength;
       if (superinterfaces.length > 0) {
@@ -7032,13 +7192,13 @@
       ClassElement classElement = element as ClassElement;
       List<InterfaceType> superinterfaces = classElement.interfaces;
       for (InterfaceType superinterface in superinterfaces) {
-        if (javaSetAdd(set, superinterface)) {
+        if (set.add(superinterface)) {
           computeSuperinterfaceSet2(superinterface, set);
         }
       }
       InterfaceType supertype = classElement.supertype;
       if (supertype != null) {
-        if (javaSetAdd(set, supertype)) {
+        if (set.add(supertype)) {
           computeSuperinterfaceSet2(supertype, set);
         }
       }
@@ -7066,7 +7226,7 @@
     for (InterfaceType secondType in second) {
       InterfaceType firstType = firstMap[secondType.element];
       if (firstType != null) {
-        javaSetAdd(result, leastUpperBound(firstType, secondType));
+        result.add(leastUpperBound(firstType, secondType));
       }
     }
     return new List.from(result);
@@ -7205,8 +7365,8 @@
     InterfaceType j = type as InterfaceType;
     Set<InterfaceType> si = computeSuperinterfaceSet(i);
     Set<InterfaceType> sj = computeSuperinterfaceSet(j);
-    javaSetAdd(si, i);
-    javaSetAdd(sj, j);
+    si.add(i);
+    sj.add(j);
     List<InterfaceType> s = intersection(si, sj);
     List<int> depths = new List<int>.filled(s.length, 0);
     int maxDepth = 0;
@@ -7319,37 +7479,8 @@
     return false;
   }
 
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) {
-    if (identical(type, DynamicTypeImpl.instance)) {
-      return true;
-    } else if (type is! InterfaceType) {
-      return false;
-    }
-    return isMoreSpecificThan2(type as InterfaceType, new Set<ClassElement>(), withDynamic);
-  }
-
   bool get isObject => element.supertype == null;
 
-  bool isSubtypeOf(Type2 type) {
-    if (identical(type, DynamicTypeImpl.instance)) {
-      return true;
-    } else if (type is TypeParameterType) {
-      return true;
-    } else if (type is FunctionType) {
-      ClassElement element = this.element;
-      MethodElement callMethod = element.lookUpMethod("call", element.library);
-      if (callMethod != null) {
-        return callMethod.type.isSubtypeOf(type);
-      }
-      return false;
-    } else if (type is! InterfaceType) {
-      return false;
-    } else if (this == type) {
-      return true;
-    }
-    return isSubtypeOf2(type as InterfaceType, new Set<ClassElement>());
-  }
-
   ConstructorElement lookUpConstructor(String constructorName, LibraryElement library) {
     ConstructorElement constructorElement;
     if (constructorName == null) {
@@ -7382,7 +7513,7 @@
     InterfaceType supertype = superclass;
     ClassElement supertypeElement = supertype == null ? null : supertype.element;
     while (supertype != null && !visitedClasses.contains(supertypeElement)) {
-      javaSetAdd(visitedClasses, supertypeElement);
+      visitedClasses.add(supertypeElement);
       PropertyAccessorElement element = supertype.getGetter(getterName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -7418,7 +7549,7 @@
     InterfaceType supertype = superclass;
     ClassElement supertypeElement = supertype == null ? null : supertype.element;
     while (supertype != null && !visitedClasses.contains(supertypeElement)) {
-      javaSetAdd(visitedClasses, supertypeElement);
+      visitedClasses.add(supertypeElement);
       MethodElement element = supertype.getMethod(methodName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -7454,7 +7585,7 @@
     InterfaceType supertype = superclass;
     ClassElement supertypeElement = supertype == null ? null : supertype.element;
     while (supertype != null && !visitedClasses.contains(supertypeElement)) {
-      javaSetAdd(visitedClasses, supertypeElement);
+      visitedClasses.add(supertypeElement);
       PropertyAccessorElement element = supertype.getSetter(setterName);
       if (element != null && element.isAccessibleIn(library)) {
         return element;
@@ -7513,7 +7644,36 @@
     }
   }
 
-  bool isMoreSpecificThan2(InterfaceType s, Set<ClassElement> visitedClasses, bool withDynamic) {
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+    if (identical(type, DynamicTypeImpl.instance)) {
+      return true;
+    } else if (type is! InterfaceType) {
+      return false;
+    }
+    return isMoreSpecificThan2(type as InterfaceType, new Set<ClassElement>(), withDynamic, visitedTypePairs);
+  }
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+    if (identical(type, DynamicTypeImpl.instance)) {
+      return true;
+    } else if (type is TypeParameterType) {
+      return true;
+    } else if (type is FunctionType) {
+      ClassElement element = this.element;
+      MethodElement callMethod = element.lookUpMethod("call", element.library);
+      if (callMethod != null) {
+        return callMethod.type.isSubtypeOf(type);
+      }
+      return false;
+    } else if (type is! InterfaceType) {
+      return false;
+    } else if (this == type) {
+      return true;
+    }
+    return isSubtypeOf2(type as InterfaceType, new Set<ClassElement>(), visitedTypePairs);
+  }
+
+  bool isMoreSpecificThan2(InterfaceType s, Set<ClassElement> visitedClasses, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
     if (this == s) {
       return true;
     }
@@ -7529,7 +7689,7 @@
         return false;
       }
       for (int i = 0; i < tArguments.length; i++) {
-        if (!tArguments[i].isMoreSpecificThan3(sArguments[i], withDynamic)) {
+        if (!(tArguments[i] as TypeImpl).isMoreSpecificThan3(sArguments[i], withDynamic, visitedTypePairs)) {
           return false;
         }
       }
@@ -7539,32 +7699,32 @@
     if (element == null || visitedClasses.contains(element)) {
       return false;
     }
-    javaSetAdd(visitedClasses, element);
+    visitedClasses.add(element);
     InterfaceType supertype = superclass;
-    if (supertype != null && (supertype as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+    if (supertype != null && (supertype as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
       return true;
     }
     for (InterfaceType interfaceType in interfaces) {
-      if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+      if ((interfaceType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
         return true;
       }
     }
     for (InterfaceType mixinType in mixins) {
-      if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic)) {
+      if ((mixinType as InterfaceTypeImpl).isMoreSpecificThan2(s, visitedClasses, withDynamic, visitedTypePairs)) {
         return true;
       }
     }
     return false;
   }
 
-  bool isSubtypeOf2(InterfaceType type, Set<ClassElement> visitedClasses) {
+  bool isSubtypeOf2(InterfaceType type, Set<ClassElement> visitedClasses, Set<TypeImpl_TypePair> visitedTypePairs) {
     InterfaceType typeT = this;
     InterfaceType typeS = type;
     ClassElement elementT = element;
     if (elementT == null || visitedClasses.contains(elementT)) {
       return false;
     }
-    javaSetAdd(visitedClasses, elementT);
+    visitedClasses.add(elementT);
     if (typeT == typeS) {
       return true;
     } else if (elementT == typeS.element) {
@@ -7574,7 +7734,7 @@
         return false;
       }
       for (int i = 0; i < typeTArgs.length; i++) {
-        if (!typeTArgs[i].isSubtypeOf(typeSArgs[i])) {
+        if (!(typeTArgs[i] as TypeImpl).isSubtypeOf3(typeSArgs[i], visitedTypePairs)) {
           return false;
         }
       }
@@ -7583,18 +7743,18 @@
       return true;
     }
     InterfaceType supertype = superclass;
-    if (supertype != null && (supertype as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+    if (supertype != null && (supertype as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
       return true;
     }
     List<InterfaceType> interfaceTypes = interfaces;
     for (InterfaceType interfaceType in interfaceTypes) {
-      if ((interfaceType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+      if ((interfaceType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
         return true;
       }
     }
     List<InterfaceType> mixinTypes = mixins;
     for (InterfaceType mixinType in mixinTypes) {
-      if ((mixinType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses)) {
+      if ((mixinType as InterfaceTypeImpl).isSubtypeOf2(typeS, visitedClasses, visitedTypePairs)) {
         return true;
       }
     }
@@ -7665,7 +7825,22 @@
 
   String get name => _name;
 
-  bool isAssignableTo(Type2 type) => this.isSubtypeOf(type) || type.isSubtypeOf(this);
+  bool isAssignableTo(Type2 type) => isAssignableTo2(type, new Set<TypeImpl_TypePair>());
+
+  /**
+   * Return `true` if this type is assignable to the given type. A type <i>T</i> may be
+   * assigned to a type <i>S</i>, written <i>T</i> &hArr; <i>S</i>, iff either <i>T</i> <: <i>S</i>
+   * or <i>S</i> <: <i>T</i>.
+   *
+   * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+   * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+   * used to prevent infinite loops.
+   *
+   * @param type the type being compared with this type
+   * @param visitedPairs the set of pairs of types used to prevent infinite loops
+   * @return `true` if this type is assignable to the given type
+   */
+  bool isAssignableTo2(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => isSubtypeOf3(type, visitedTypePairs) || (type as TypeImpl).isSubtypeOf3(this, visitedTypePairs);
 
   bool get isBottom => false;
 
@@ -7673,12 +7848,55 @@
 
   bool get isDynamic => false;
 
-  bool isMoreSpecificThan(Type2 type) => isMoreSpecificThan3(type, false);
+  bool isMoreSpecificThan(Type2 type) => isMoreSpecificThan3(type, false, new Set<TypeImpl_TypePair>());
 
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) => false;
+  /**
+   * Return `true` if this type is more specific than the given type.
+   *
+   * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+   * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+   * used to prevent infinite loops.
+   *
+   * @param type the type being compared with this type
+   * @param withDynamic `true` if "dynamic" should be considered as a subtype of any type
+   * @param visitedPairs the set of pairs of types used to prevent infinite loops
+   * @return `true` if this type is more specific than the given type
+   */
+  bool isMoreSpecificThan3(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+    TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
+    if (!visitedTypePairs.add(typePair)) {
+      return false;
+    }
+    bool result = internalIsMoreSpecificThan(type, withDynamic, visitedTypePairs);
+    visitedTypePairs.remove(typePair);
+    return result;
+  }
 
   bool get isObject => false;
 
+  bool isSubtypeOf(Type2 type) => isSubtypeOf3(type, new Set<TypeImpl_TypePair>());
+
+  /**
+   * Return `true` if this type is a subtype of the given type.
+   *
+   * The given set of pairs of types (T1, T2), where each pair indicates that we invoked this method
+   * because we are in the process of answering the question of whether T1 is a subtype of T2, is
+   * used to prevent infinite loops.
+   *
+   * @param type the type being compared with this type
+   * @param visitedPairs the set of pairs of types used to prevent infinite loops
+   * @return `true` if this type is a subtype of the given type
+   */
+  bool isSubtypeOf3(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) {
+    TypeImpl_TypePair typePair = new TypeImpl_TypePair(this, type);
+    if (!visitedTypePairs.add(typePair)) {
+      return false;
+    }
+    bool result = internalIsSubtypeOf(type, visitedTypePairs);
+    visitedTypePairs.remove(typePair);
+    return result;
+  }
+
   bool isSupertypeOf(Type2 type) => type.isSubtypeOf(this);
 
   bool get isVoid => false;
@@ -7701,6 +7919,44 @@
       builder.append(_name);
     }
   }
+
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs);
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs);
+}
+
+class TypeImpl_TypePair {
+  Type2 _firstType;
+
+  Type2 _secondType;
+
+  TypeImpl_TypePair(Type2 firstType, Type2 secondType) {
+    this._firstType = firstType;
+    this._secondType = secondType;
+  }
+
+  bool operator ==(Object object) {
+    if (identical(object, this)) {
+      return true;
+    }
+    if (object is TypeImpl_TypePair) {
+      TypeImpl_TypePair typePair = object as TypeImpl_TypePair;
+      return _firstType == typePair._firstType && _secondType != null && _secondType == typePair._secondType;
+    }
+    return false;
+  }
+
+  int get hashCode {
+    int firstHashCode = 0;
+    if (_firstType != null) {
+      firstHashCode = _firstType.element == null ? 0 : _firstType.element.hashCode;
+    }
+    int secondHashCode = 0;
+    if (_secondType != null) {
+      secondHashCode = _secondType.element == null ? 0 : _secondType.element.hashCode;
+    }
+    return firstHashCode + secondHashCode;
+  }
 }
 
 /**
@@ -7749,21 +8005,6 @@
 
   int get hashCode => element.hashCode;
 
-  bool isMoreSpecificThan3(Type2 s, bool withDynamic) {
-    if (this == s) {
-      return true;
-    }
-    if (s.isBottom) {
-      return true;
-    }
-    if (s.isDynamic) {
-      return true;
-    }
-    return isMoreSpecificThan4(s, new Set<Type2>(), withDynamic);
-  }
-
-  bool isSubtypeOf(Type2 s) => isMoreSpecificThan3(s, true);
-
   Type2 substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) {
     int length = parameterTypes.length;
     for (int i = 0; i < length; i++) {
@@ -7774,7 +8015,22 @@
     return this;
   }
 
-  bool isMoreSpecificThan4(Type2 s, Set<Type2> visitedTypes, bool withDynamic) {
+  bool internalIsMoreSpecificThan(Type2 s, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
+    if (this == s) {
+      return true;
+    }
+    if (s.isBottom) {
+      return true;
+    }
+    if (s.isDynamic) {
+      return true;
+    }
+    return isMoreSpecificThan4(s, new Set<Type2>(), withDynamic, visitedTypePairs);
+  }
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => isMoreSpecificThan3(type, true, new Set<TypeImpl_TypePair>());
+
+  bool isMoreSpecificThan4(Type2 s, Set<Type2> visitedTypes, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) {
     Type2 bound = element.bound;
     if (s == bound) {
       return true;
@@ -7790,10 +8046,10 @@
       if (visitedTypes.contains(bound)) {
         return false;
       }
-      javaSetAdd(visitedTypes, bound);
-      return boundTypeParameter.isMoreSpecificThan4(s, visitedTypes, withDynamic);
+      visitedTypes.add(bound);
+      return boundTypeParameter.isMoreSpecificThan4(s, visitedTypes, withDynamic, visitedTypePairs);
     }
-    return bound.isMoreSpecificThan3(s, withDynamic);
+    return (bound as TypeImpl).isMoreSpecificThan3(s, withDynamic, visitedTypePairs);
   }
 }
 
@@ -7815,13 +8071,13 @@
 
   bool operator ==(Object object) => identical(object, this);
 
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic) => isSubtypeOf(type);
-
-  bool isSubtypeOf(Type2 type) => identical(type, this) || identical(type, DynamicTypeImpl.instance);
-
   bool get isVoid => true;
 
   VoidTypeImpl substitute2(List<Type2> argumentTypes, List<Type2> parameterTypes) => this;
+
+  bool internalIsMoreSpecificThan(Type2 type, bool withDynamic, Set<TypeImpl_TypePair> visitedTypePairs) => isSubtypeOf(type);
+
+  bool internalIsSubtypeOf(Type2 type, Set<TypeImpl_TypePair> visitedTypePairs) => identical(type, this) || identical(type, DynamicTypeImpl.instance);
 }
 
 /**
@@ -8375,15 +8631,6 @@
   bool isMoreSpecificThan(Type2 type);
 
   /**
-   * Return `true` if this type is more specific than the given type.
-   *
-   * @param type the type being compared with this type
-   * @param withDynamic `true` if "dynamic" should be considered as a subtype of any type
-   * @return `true` if this type is more specific than the given type
-   */
-  bool isMoreSpecificThan3(Type2 type, bool withDynamic);
-
-  /**
    * Return `true` if this type represents the type 'Object'.
    *
    * @return `true` if this type represents the type 'Object'
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 5ca1fee..2e6b37e 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -16,7 +16,7 @@
 import 'sdk.dart' show DartSdk;
 import 'element.dart';
 import 'resolver.dart';
-import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlUnit;
+import 'html.dart' show XmlTagNode, XmlAttributeNode, RecursiveXmlVisitor, HtmlScanner, HtmlScanResult, HtmlParser, HtmlParseResult, HtmlScriptTagNode, HtmlUnit;
 
 /**
  * The unique instance of the class `AnalysisEngine` serves as the entry point for the
@@ -711,14 +711,6 @@
    * @return `true` if analysis is to generate hint results
    */
   bool get hint;
-
-  /**
-   * Return `true` if analysis is to use strict mode. In strict mode, error reporting is based
-   * exclusively on the static type information.
-   *
-   * @return `true` if analysis is to use strict mode
-   */
-  bool get strictMode;
 }
 
 /**
@@ -2365,7 +2357,12 @@
   /**
    * The data descriptor representing the hints resulting from auditing the source.
    */
-  static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("DartEntry.HINTS");
+  static final DataDescriptor<List<AnalysisError>> HINTS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.HINTS");
+
+  /**
+   * The data descriptor representing the errors resulting from parsing the source.
+   */
+  static final DataDescriptor<List<AnalysisError>> PARSE_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.PARSE_ERRORS");
 
   /**
    * The data descriptor representing the parsed AST structure.
@@ -2409,13 +2406,24 @@
   HtmlUnit _parsedUnit;
 
   /**
+   * The state of the cached parse errors.
+   */
+  CacheState _parseErrorsState = CacheState.INVALID;
+
+  /**
+   * The errors produced while scanning and parsing the HTML, or `null` if the errors are not
+   * currently cached.
+   */
+  List<AnalysisError> _parseErrors = AnalysisError.NO_ERRORS;
+
+  /**
    * The state of the cached resolution errors.
    */
   CacheState _resolutionErrorsState = CacheState.INVALID;
 
   /**
-   * The errors produced while resolving the compilation unit, or `null` if the errors are not
-   * currently cached.
+   * The errors produced while resolving the HTML, or `null` if the errors are not currently
+   * cached.
    */
   List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
 
@@ -2453,6 +2461,9 @@
 
   List<AnalysisError> get allErrors {
     List<AnalysisError> errors = new List<AnalysisError>();
+    for (AnalysisError error in _parseErrors) {
+      errors.add(error);
+    }
     for (AnalysisError error in _resolutionErrors) {
       errors.add(error);
     }
@@ -2470,6 +2481,8 @@
   CacheState getState(DataDescriptor descriptor) {
     if (identical(descriptor, HtmlEntry.ELEMENT)) {
       return _elementState;
+    } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+      return _parseErrorsState;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       return _parsedUnitState;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
@@ -2485,6 +2498,8 @@
   Object getValue(DataDescriptor descriptor) {
     if (identical(descriptor, HtmlEntry.ELEMENT)) {
       return _element as Object;
+    } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+      return _parseErrors as Object;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       return _parsedUnit as Object;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
@@ -2508,6 +2523,8 @@
    */
   void invalidateAllInformation() {
     setState(SourceEntry.LINE_INFO, CacheState.INVALID);
+    _parseErrors = AnalysisError.NO_ERRORS;
+    _parseErrorsState = CacheState.INVALID;
     _parsedUnit = null;
     _parsedUnitState = CacheState.INVALID;
     _referencedLibraries = Source.EMPTY_ARRAY;
@@ -2533,6 +2550,7 @@
    */
   void recordParseError() {
     setState(SourceEntry.LINE_INFO, CacheState.ERROR);
+    setState(HtmlEntry.PARSE_ERRORS, CacheState.ERROR);
     setState(HtmlEntry.PARSED_UNIT, CacheState.ERROR);
     setState(HtmlEntry.REFERENCED_LIBRARIES, CacheState.ERROR);
     recordResolutionError();
@@ -2552,6 +2570,9 @@
     if (identical(descriptor, HtmlEntry.ELEMENT)) {
       _element = updatedValue(state, _element, null);
       _elementState = state;
+    } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+      _parseErrors = updatedValue(state, _parseErrors, null);
+      _parseErrorsState = state;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       _parsedUnit = updatedValue(state, _parsedUnit, null);
       _parsedUnitState = state;
@@ -2573,6 +2594,9 @@
     if (identical(descriptor, HtmlEntry.ELEMENT)) {
       _element = value as HtmlElement;
       _elementState = CacheState.VALID;
+    } else if (identical(descriptor, HtmlEntry.PARSE_ERRORS)) {
+      _parseErrors = value as List<AnalysisError>;
+      _parseErrorsState = CacheState.VALID;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       _parsedUnit = value as HtmlUnit;
       _parsedUnitState = CacheState.VALID;
@@ -2593,6 +2617,8 @@
   void copyFrom(SourceEntryImpl entry) {
     super.copyFrom(entry);
     HtmlEntryImpl other = entry as HtmlEntryImpl;
+    _parseErrorsState = other._parseErrorsState;
+    _parseErrors = other._parseErrors;
     _parsedUnitState = other._parsedUnitState;
     _parsedUnit = other._parsedUnit;
     _referencedLibrariesState = other._referencedLibrariesState;
@@ -2608,6 +2634,8 @@
   void writeOn(JavaStringBuilder builder) {
     builder.append("Html: ");
     super.writeOn(builder);
+    builder.append("; parseErrors = ");
+    builder.append(_parseErrorsState);
     builder.append("; parsedUnit = ");
     builder.append(_parsedUnitState);
     builder.append("; resolutionErrors = ");
@@ -2900,7 +2928,7 @@
     if (identical(state, CacheState.ERROR)) {
       AnalysisException exception = dartEntry.exception;
       if (exception != null) {
-        javaSetAdd(_exceptions, exception);
+        _exceptions.add(exception);
       }
     }
   }
@@ -3649,7 +3677,6 @@
       }
       this._options.dart2jsHint = options.dart2jsHint;
       this._options.hint = options.hint;
-      this._options.strictMode = options.strictMode;
       if (needsRecompute) {
         invalidateAllResolutionInformation();
       }
@@ -3678,16 +3705,14 @@
   void setChangedContents(Source source, String contents, int offset, int oldLength, int newLength) {
     {
       String originalContents = _sourceFactory.setContents(source, contents);
-      if (originalContents == null) {
-        if (contents != null) {
+      if (contents != null) {
+        if (contents != originalContents) {
           _incrementalAnalysisCache = IncrementalAnalysisCache.update(_incrementalAnalysisCache, source, originalContents, contents, offset, oldLength, newLength, getReadableSourceEntry(source));
           sourceChanged(source);
         }
-      } else if (originalContents != contents) {
-        _incrementalAnalysisCache = IncrementalAnalysisCache.update(_incrementalAnalysisCache, source, originalContents, contents, offset, oldLength, newLength, getReadableSourceEntry(source));
-        sourceChanged(source);
-      } else if (contents == null) {
+      } else if (originalContents != null) {
         _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
+        sourceChanged(source);
       }
     }
   }
@@ -3695,14 +3720,15 @@
   void setContents(Source source, String contents) {
     {
       String originalContents = _sourceFactory.setContents(source, contents);
-      if (originalContents == null) {
-        if (contents != null) {
+      if (contents != null) {
+        if (contents != originalContents) {
+          _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
           sourceChanged(source);
         }
-      } else if (originalContents != contents) {
+      } else if (originalContents != null) {
+        _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
         sourceChanged(source);
       }
-      _incrementalAnalysisCache = IncrementalAnalysisCache.clear(_incrementalAnalysisCache, source);
     }
   }
 
@@ -4427,13 +4453,13 @@
       DartEntry dartEntry = sourceEntry as DartEntry;
       CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
       if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
-        javaSetAdd(sources, source);
+        sources.add(source);
         return;
       }
       if (isPriority) {
         CompilationUnit parseUnit = dartEntry.anyParsedCompilationUnit;
         if (parseUnit == null) {
-          javaSetAdd(sources, source);
+          sources.add(source);
           return;
         }
       }
@@ -4442,14 +4468,14 @@
         if (libraryEntry is DartEntry) {
           CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
           if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
-            javaSetAdd(sources, source);
+            sources.add(source);
             return;
           }
           CacheState resolvedUnitState = dartEntry.getState2(DartEntry.RESOLVED_UNIT, librarySource);
           if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
             LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
             if (libraryElement != null) {
-              javaSetAdd(sources, source);
+              sources.add(source);
               return;
             }
           }
@@ -4457,7 +4483,7 @@
           if (identical(verificationErrorsState, CacheState.INVALID) || (isPriority && identical(verificationErrorsState, CacheState.FLUSHED))) {
             LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
             if (libraryElement != null) {
-              javaSetAdd(sources, source);
+              sources.add(source);
               return;
             }
           }
@@ -4466,7 +4492,7 @@
             if (identical(hintsState, CacheState.INVALID) || (isPriority && identical(hintsState, CacheState.FLUSHED))) {
               LibraryElement libraryElement = libraryEntry.getValue(DartEntry.ELEMENT);
               if (libraryElement != null) {
-                javaSetAdd(sources, source);
+                sources.add(source);
                 return;
               }
             }
@@ -4477,12 +4503,12 @@
       HtmlEntry htmlEntry = sourceEntry as HtmlEntry;
       CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT);
       if (identical(parsedUnitState, CacheState.INVALID) || (isPriority && identical(parsedUnitState, CacheState.FLUSHED))) {
-        javaSetAdd(sources, source);
+        sources.add(source);
         return;
       }
       CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
       if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
-        javaSetAdd(sources, source);
+        sources.add(source);
         return;
       }
     }
@@ -4550,7 +4576,7 @@
     if (library.source == htmlSource) {
       return true;
     }
-    javaSetAdd(visitedLibraries, library);
+    visitedLibraries.add(library);
     for (LibraryElement imported in library.importedLibraries) {
       if (isClient(imported, htmlSource, visitedLibraries)) {
         return true;
@@ -4852,6 +4878,7 @@
           HtmlUnit unit = task.htmlUnit;
           htmlCopy.setValue(SourceEntry.LINE_INFO, lineInfo);
           htmlCopy.setValue(HtmlEntry.PARSED_UNIT, unit);
+          htmlCopy.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
           htmlCopy.setValue(HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries);
           ChangeNoticeImpl notice = getNotice(source);
           notice.setErrors(htmlEntry.allErrors, lineInfo);
@@ -5154,9 +5181,9 @@
       List<Source> containingLibraries = getLibrariesContaining(source);
       Set<Source> librariesToInvalidate = new Set<Source>();
       for (Source containingLibrary in containingLibraries) {
-        javaSetAdd(librariesToInvalidate, containingLibrary);
+        librariesToInvalidate.add(containingLibrary);
         for (Source dependentLibrary in getLibrariesDependingOn(containingLibrary)) {
-          javaSetAdd(librariesToInvalidate, dependentLibrary);
+          librariesToInvalidate.add(dependentLibrary);
         }
       }
       for (Source library in librariesToInvalidate) {
@@ -5179,9 +5206,9 @@
     if (sourceEntry is DartEntry) {
       Set<Source> libraries = new Set<Source>();
       for (Source librarySource in getLibrariesContaining(source)) {
-        javaSetAdd(libraries, librarySource);
+        libraries.add(librarySource);
         for (Source dependentLibrary in getLibrariesDependingOn(librarySource)) {
-          javaSetAdd(libraries, dependentLibrary);
+          libraries.add(dependentLibrary);
         }
       }
       for (Source librarySource in libraries) {
@@ -5310,12 +5337,6 @@
   bool _hint = true;
 
   /**
-   * A flag indicating whether analysis is to use strict mode. In strict mode, error reporting is
-   * based exclusively on the static type information.
-   */
-  bool _strictMode = true;
-
-  /**
    * Initialize a newly created set of analysis options to have their default values.
    */
   AnalysisOptionsImpl();
@@ -5330,7 +5351,6 @@
     _cacheSize = options.cacheSize;
     _dart2jsHint = options.dart2jsHint;
     _hint = options.hint;
-    _strictMode = options.strictMode;
   }
 
   int get cacheSize => _cacheSize;
@@ -5340,14 +5360,6 @@
   bool get hint => _hint;
 
   /**
-   * Return `true` if analysis is to use strict mode. In strict mode, error reporting is based
-   * exclusively on the static type information.
-   *
-   * @return `true` if analysis is to use strict mode
-   */
-  bool get strictMode => _strictMode;
-
-  /**
    * Set the maximum number of sources for which AST structures should be kept in the cache to the
    * given size.
    *
@@ -5376,16 +5388,6 @@
   void set hint(bool hint) {
     this._hint = hint;
   }
-
-  /**
-   * Set whether analysis is to use strict mode to the given value. In strict mode, error reporting
-   * is based exclusively on the static type information.
-   *
-   * @param isStrict `true` if analysis is to use strict mode
-   */
-  void set strictMode(bool isStrict) {
-    _strictMode = isStrict;
-  }
 }
 
 /**
@@ -5818,7 +5820,7 @@
    *
    * @param cache the prior cache or `null` if none
    * @param source the source being updated (not `null`)
-   * @param oldContents the original source contents prior to this update (not `null`)
+   * @param oldContents the original source contents prior to this update (may be `null`)
    * @param newContents the new contents after this incremental change (not `null`)
    * @param offset the offset at which the change occurred
    * @param oldLength the length of the text being replaced
@@ -5878,7 +5880,7 @@
    */
   static IncrementalAnalysisCache verifyStructure(IncrementalAnalysisCache cache, Source source, CompilationUnit unit) {
     if (cache != null && unit != null && cache.source == source) {
-      if (!ASTComparator.equals3(cache.resolvedUnit, unit)) {
+      if (!ASTComparator.equals4(cache.resolvedUnit, unit)) {
         return null;
       }
     }
@@ -6685,7 +6687,7 @@
       errorsForSource = new Set<AnalysisError>();
       _errors[source] = errorsForSource;
     }
-    javaSetAdd(errorsForSource, error);
+    errorsForSource.add(error);
   }
 }
 
@@ -7322,7 +7324,7 @@
     List<Token> token = [null];
     TimeCounter_TimeCounterHandle timeCounterScan = PerformanceStatistics.scan.start();
     try {
-      Source_ContentReceiver receiver = new Source_ContentReceiver_12(this, errorListener, token);
+      Source_ContentReceiver receiver = new Source_ContentReceiver_11(this, errorListener, token);
       try {
         source.getContents(receiver);
       } on JavaException catch (exception) {
@@ -7341,19 +7343,19 @@
         if (directive is ExportDirective) {
           Source exportSource = resolveSource(source, directive as ExportDirective);
           if (exportSource != null) {
-            javaSetAdd(_exportedSources, exportSource);
+            _exportedSources.add(exportSource);
           }
         } else if (directive is ImportDirective) {
           Source importSource = resolveSource(source, directive as ImportDirective);
           if (importSource != null) {
-            javaSetAdd(_importedSources, importSource);
+            _importedSources.add(importSource);
           }
         } else if (directive is LibraryDirective) {
           _hasLibraryDirective2 = true;
         } else if (directive is PartDirective) {
           Source partSource = resolveSource(source, directive as PartDirective);
           if (partSource != null) {
-            javaSetAdd(_includedSources, partSource);
+            _includedSources.add(partSource);
           }
         } else if (directive is PartOfDirective) {
           _hasPartOfDirective2 = true;
@@ -7406,14 +7408,14 @@
   }
 }
 
-class Source_ContentReceiver_12 implements Source_ContentReceiver {
+class Source_ContentReceiver_11 implements Source_ContentReceiver {
   final ParseDartTask ParseDartTask_this;
 
   RecordingErrorListener errorListener;
 
   List<Token> token;
 
-  Source_ContentReceiver_12(this.ParseDartTask_this, this.errorListener, this.token);
+  Source_ContentReceiver_11(this.ParseDartTask_this, this.errorListener, this.token);
 
   void accept(CharBuffer contents, int modificationTime) {
     ParseDartTask_this.modificationTime = modificationTime;
@@ -7455,6 +7457,11 @@
   HtmlUnit htmlUnit;
 
   /**
+   * The errors that were produced by scanning and parsing the source.
+   */
+  List<AnalysisError> errors = AnalysisError.NO_ERRORS;
+
+  /**
    * An array containing the sources of the libraries that are referenced within the HTML.
    */
   List<Source> referencedLibraries = Source.EMPTY_ARRAY;
@@ -7509,8 +7516,10 @@
     HtmlScanResult scannerResult = scanner.result;
     modificationTime = scannerResult.modificationTime;
     lineInfo = new LineInfo(scannerResult.lineStarts);
-    HtmlParseResult result = new HtmlParser(source).parse(scannerResult);
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    HtmlParseResult result = new HtmlParser(source, errorListener).parse(scannerResult);
     htmlUnit = result.htmlUnit;
+    errors = errorListener.getErrors2(source);
     referencedLibraries = librarySources;
   }
 
@@ -7521,7 +7530,7 @@
    */
   List<Source> get librarySources {
     List<Source> libraries = new List<Source>();
-    htmlUnit.accept(new RecursiveXmlVisitor_13(this, libraries));
+    htmlUnit.accept(new RecursiveXmlVisitor_12(this, libraries));
     if (libraries.isEmpty) {
       return Source.EMPTY_ARRAY;
     }
@@ -7529,39 +7538,32 @@
   }
 }
 
-class RecursiveXmlVisitor_13 extends RecursiveXmlVisitor<Object> {
+class RecursiveXmlVisitor_12 extends RecursiveXmlVisitor<Object> {
   final ParseHtmlTask ParseHtmlTask_this;
 
   List<Source> libraries;
 
-  RecursiveXmlVisitor_13(this.ParseHtmlTask_this, this.libraries) : super();
+  RecursiveXmlVisitor_12(this.ParseHtmlTask_this, this.libraries) : super();
 
-  Object visitXmlTagNode(XmlTagNode node) {
-    if (javaStringEqualsIgnoreCase(node.tag.lexeme, ParseHtmlTask._TAG_SCRIPT)) {
-      bool isDartScript = false;
-      XmlAttributeNode scriptAttribute = null;
-      for (XmlAttributeNode attribute in node.attributes) {
-        if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_SRC)) {
-          scriptAttribute = attribute;
-        } else if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_TYPE)) {
-          if (javaStringEqualsIgnoreCase(attribute.text, ParseHtmlTask._TYPE_DART)) {
-            isDartScript = true;
-          }
-        }
-      }
-      if (isDartScript && scriptAttribute != null) {
-        try {
-          Uri uri = new Uri(path: scriptAttribute.text);
-          String fileName = uri.path;
-          Source librarySource = ParseHtmlTask_this.context.sourceFactory.resolveUri(ParseHtmlTask_this.source, fileName);
-          if (librarySource != null && librarySource.exists()) {
-            libraries.add(librarySource);
-          }
-        } on URISyntaxException catch (e) {
-        }
+  Object visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+    XmlAttributeNode scriptAttribute = null;
+    for (XmlAttributeNode attribute in node.attributes) {
+      if (javaStringEqualsIgnoreCase(attribute.name.lexeme, ParseHtmlTask._ATTRIBUTE_SRC)) {
+        scriptAttribute = attribute;
       }
     }
-    return super.visitXmlTagNode(node);
+    if (scriptAttribute != null) {
+      try {
+        Uri uri = new Uri(path: scriptAttribute.text);
+        String fileName = uri.path;
+        Source librarySource = ParseHtmlTask_this.context.sourceFactory.resolveUri(ParseHtmlTask_this.source, fileName);
+        if (librarySource != null && librarySource.exists()) {
+          libraries.add(librarySource);
+        }
+      } on URISyntaxException catch (e) {
+      }
+    }
+    return super.visitHtmlScriptTagNode(node);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 70123b4..804608e 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -115,6 +115,21 @@
 }
 
 /**
+ * Instances of the class `BooleanErrorListener` implement a listener that keeps track of
+ * whether an error has been reported to it.
+ */
+class BooleanErrorListener implements AnalysisErrorListener {
+  /**
+   * A flag indicating whether an error has been reported to this listener.
+   */
+  bool errorReported = false;
+
+  void onError(AnalysisError error) {
+    errorReported = true;
+  }
+}
+
+/**
  * Instances of the class `ErrorReporter` wrap an error listener with utility methods used to
  * create the errors being reported.
  *
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index e55e7da..3924cec 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -7,7 +7,11 @@
 import 'java_core.dart';
 import 'java_engine.dart';
 import 'source.dart';
-import 'element.dart' show HtmlElementImpl;
+import 'error.dart' show AnalysisErrorListener;
+import 'scanner.dart' as sc show Scanner, SubSequenceReader, Token;
+import 'parser.dart' show Parser;
+import 'ast.dart' show ASTVisitor, CompilationUnit, Expression;
+import 'element.dart' show HtmlElementImpl, HtmlScriptElement;
 import 'engine.dart' show AnalysisEngine;
 
 /**
@@ -105,6 +109,45 @@
 }
 
 /**
+ * Instances of the class `EmbeddedExpression` represent an expression enclosed between
+ * <code>{{</code> and <code>}}</code> delimiters.
+ */
+class EmbeddedExpression {
+  /**
+   * The offset of the first character of the opening delimiter.
+   */
+  int openingOffset = 0;
+
+  /**
+   * The expression that is enclosed between the delimiters.
+   */
+  Expression expression;
+
+  /**
+   * The offset of the first character of the closing delimiter.
+   */
+  int closingOffset = 0;
+
+  /**
+   * An empty array of embedded expressions.
+   */
+  static List<EmbeddedExpression> EMPTY_ARRAY = new List<EmbeddedExpression>(0);
+
+  /**
+   * Initialize a newly created embedded expression to represent the given expression.
+   *
+   * @param openingOffset the offset of the first character of the opening delimiter
+   * @param expression the expression that is enclosed between the delimiters
+   * @param closingOffset the offset of the first character of the closing delimiter
+   */
+  EmbeddedExpression(int openingOffset, Expression expression, int closingOffset) {
+    this.openingOffset = openingOffset;
+    this.expression = expression;
+    this.closingOffset = closingOffset;
+  }
+}
+
+/**
  * Instances of `HtmlParseResult` hold the result of parsing an HTML file.
  *
  * @coverage dart.engine.html
@@ -121,6 +164,36 @@
 }
 
 /**
+ * Instances of the class `TagWithEmbeddedExpressions` represent a tag whose text content
+ * contains one or more embedded expressions.
+ */
+class TagWithEmbeddedExpressions extends XmlTagNode {
+  /**
+   * The expressions that are embedded in the tag's content.
+   */
+  List<EmbeddedExpression> _expressions;
+
+  /**
+   * Initialize a newly created tag whose text content contains one or more embedded expressions.
+   *
+   * @param nodeStart the token marking the beginning of the tag
+   * @param tag the name of the tag
+   * @param attributes the attributes in the tag
+   * @param attributeEnd the token terminating the region where attributes can be
+   * @param tagNodes the children of the tag
+   * @param contentEnd the token that starts the closing tag
+   * @param closingTag the name of the tag that occurs in the closing tag
+   * @param nodeEnd the last token in the tag
+   * @param expressions the expressions that are embedded in the value
+   */
+  TagWithEmbeddedExpressions(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd, List<EmbeddedExpression> expressions) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd) {
+    this._expressions = expressions;
+  }
+
+  List<EmbeddedExpression> get expressions => _expressions;
+}
+
+/**
  * Instances of the class `RecursiveXmlVisitor` implement an XML visitor that will recursively
  * visit all of the nodes in an XML structure. For example, using an instance of this class to visit
  * a [XmlTagNode] will also cause all of the contained [XmlAttributeNode]s and
@@ -133,6 +206,11 @@
  * @coverage dart.engine.html
  */
 class RecursiveXmlVisitor<R> implements XmlVisitor<R> {
+  R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+    node.visitChildren(this);
+    return null;
+  }
+
   R visitHtmlUnit(HtmlUnit node) {
     node.visitChildren(this);
     return null;
@@ -150,6 +228,56 @@
 }
 
 /**
+ * Instances of the class `HtmlScriptTagNode` represent a script tag within an HTML file that
+ * references a Dart script.
+ */
+class HtmlScriptTagNode extends XmlTagNode {
+  /**
+   * The AST structure representing the Dart code within this tag.
+   */
+  CompilationUnit _script;
+
+  /**
+   * The element representing this script.
+   */
+  HtmlScriptElement scriptElement;
+
+  /**
+   * Initialize a newly created node to represent a script tag within an HTML file that references a
+   * Dart script.
+   *
+   * @param nodeStart the token marking the beginning of the tag
+   * @param tag the name of the tag
+   * @param attributes the attributes in the tag
+   * @param attributeEnd the token terminating the region where attributes can be
+   * @param tagNodes the children of the tag
+   * @param contentEnd the token that starts the closing tag
+   * @param closingTag the name of the tag that occurs in the closing tag
+   * @param nodeEnd the last token in the tag
+   */
+  HtmlScriptTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) : super(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+
+  accept(XmlVisitor visitor) => visitor.visitHtmlScriptTagNode(this);
+
+  /**
+   * Return the AST structure representing the Dart code within this tag, or `null` if this
+   * tag references an external script.
+   *
+   * @return the AST structure representing the Dart code within this tag
+   */
+  CompilationUnit get script => _script;
+
+  /**
+   * Set the AST structure representing the Dart code within this tag to the given compilation unit.
+   *
+   * @param unit the AST structure representing the Dart code within this tag
+   */
+  void set script(CompilationUnit unit) {
+    _script = unit;
+  }
+}
+
+/**
  * The abstract class `XmlNode` defines behavior common to all XML/HTML nodes.
  *
  * @coverage dart.engine.html
@@ -330,12 +458,39 @@
 }
 
 /**
+ * Instances of the class `AttributeWithEmbeddedExpressions` represent an attribute whose
+ * value contains one or more embedded expressions.
+ */
+class AttributeWithEmbeddedExpressions extends XmlAttributeNode {
+  /**
+   * The expressions that are embedded in the attribute's value.
+   */
+  List<EmbeddedExpression> _expressions;
+
+  /**
+   * Initialize a newly created attribute whose value contains one or more embedded expressions.
+   *
+   * @param name the name of the attribute
+   * @param equals the equals sign separating the name from the value
+   * @param value the value of the attribute
+   * @param expressions the expressions that are embedded in the value
+   */
+  AttributeWithEmbeddedExpressions(Token name, Token equals, Token value, List<EmbeddedExpression> expressions) : super(name, equals, value) {
+    this._expressions = expressions;
+  }
+
+  List<EmbeddedExpression> get expressions => _expressions;
+}
+
+/**
  * Instances of the class `SimpleXmlVisitor` implement an AST visitor that will do nothing
  * when visiting an AST node. It is intended to be a superclass for classes that use the visitor
  * pattern primarily as a dispatch mechanism (and hence don't need to recursively visit a whole
  * structure) and that only need to visit a small number of node types.
  */
 class SimpleXmlVisitor<R> implements XmlVisitor<R> {
+  R visitHtmlScriptTagNode(HtmlScriptTagNode node) => null;
+
   R visitHtmlUnit(HtmlUnit htmlUnit) => null;
 
   R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode) => null;
@@ -814,6 +969,8 @@
     this._writer = writer;
   }
 
+  Object visitHtmlScriptTagNode(HtmlScriptTagNode node) => visitXmlTagNode(node);
+
   Object visitHtmlUnit(HtmlUnit node) {
     for (XmlTagNode child in node.tagNodes) {
       visit(child);
@@ -968,6 +1125,13 @@
   Token get endToken => value;
 
   /**
+   * Return the expressions that are embedded in the attribute's value.
+   *
+   * @return the expressions that are embedded in the attribute's value
+   */
+  List<EmbeddedExpression> get expressions => EmbeddedExpression.EMPTY_ARRAY;
+
+  /**
    * Answer the lexeme for the value token without the leading and trailing quotes.
    *
    * @return the text or `null` if the value is not specified
@@ -1001,12 +1165,65 @@
 }
 
 /**
+ * Instances of the class `EmbeddedDartVisitor` implement a recursive visitor for HTML files
+ * that will invoke another visitor on all embedded dart scripts and expressions.
+ */
+class EmbeddedDartVisitor<R> implements XmlVisitor<R> {
+  /**
+   * The visitor used to visit embedded Dart code.
+   */
+  ASTVisitor<R> _dartVisitor;
+
+  /**
+   * Initialize a newly created visitor to visit all of the nodes in an HTML structure and to use
+   * the given visitor to visit all of the nodes representing any embedded scripts or expressions.
+   *
+   * @param dartVisitor the visitor used to visit embedded Dart code
+   */
+  EmbeddedDartVisitor(ASTVisitor<R> dartVisitor) {
+    this._dartVisitor = dartVisitor;
+  }
+
+  R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
+    node.visitChildren(this);
+    CompilationUnit script = node.script;
+    if (script != null) {
+      script.accept(_dartVisitor);
+    }
+    return null;
+  }
+
+  R visitHtmlUnit(HtmlUnit node) {
+    node.visitChildren(this);
+    return null;
+  }
+
+  R visitXmlAttributeNode(XmlAttributeNode node) {
+    node.visitChildren(this);
+    for (EmbeddedExpression expression in node.expressions) {
+      expression.expression.accept(_dartVisitor);
+    }
+    return null;
+  }
+
+  R visitXmlTagNode(XmlTagNode node) {
+    node.visitChildren(this);
+    for (EmbeddedExpression expression in node.expressions) {
+      expression.expression.accept(_dartVisitor);
+    }
+    return null;
+  }
+}
+
+/**
  * The interface `XmlVisitor` defines the behavior of objects that can be used to visit an
  * [XmlNode] structure.
  *
  * @coverage dart.engine.html
  */
 abstract class XmlVisitor<R> {
+  R visitHtmlScriptTagNode(HtmlScriptTagNode node);
+
   R visitHtmlUnit(HtmlUnit htmlUnit);
 
   R visitXmlAttributeNode(XmlAttributeNode xmlAttributeNode);
@@ -1107,6 +1324,31 @@
   }
 
   /**
+   * Create a node representing an attribute.
+   *
+   * @param name the name of the attribute
+   * @param equals the equals sign, or `null` if there is no value
+   * @param value the value of the attribute
+   * @return the node that was created
+   */
+  XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) => new XmlAttributeNode(name, equals, value);
+
+  /**
+   * Create a node representing a tag.
+   *
+   * @param nodeStart the token marking the beginning of the tag
+   * @param tag the name of the tag
+   * @param attributes the attributes in the tag
+   * @param attributeEnd the token terminating the region where attributes can be
+   * @param tagNodes the children of the tag
+   * @param contentEnd the token that starts the closing tag
+   * @param closingTag the name of the tag that occurs in the closing tag
+   * @param nodeEnd the last token in the tag
+   * @return the node that was created
+   */
+  XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) => new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+
+  /**
    * Answer `true` if the specified tag is self closing and thus should never have content or
    * child tag nodes.
    *
@@ -1179,7 +1421,7 @@
       reportUnexpectedToken();
       value = insertSyntheticToken(TokenType.STRING);
     }
-    return new XmlAttributeNode(name, equals, value);
+    return createAttributeNode(name, equals, value);
   }
 
   /**
@@ -1265,7 +1507,7 @@
       attributeEnd = insertSyntheticToken(TokenType.SLASH_GT);
     }
     if (identical(attributeEnd.type, TokenType.SLASH_GT) || isSelfClosing(tag)) {
-      return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, currentToken, null, attributeEnd);
+      return createTagNode(nodeStart, tag, attributes, attributeEnd, XmlTagNode.NO_TAG_NODES, currentToken, null, attributeEnd);
     }
     List<XmlTagNode> tagNodes = parseChildTagNodes();
     Token contentEnd;
@@ -1292,7 +1534,7 @@
       reportUnexpectedToken();
       nodeEnd = insertSyntheticToken(TokenType.GT);
     }
-    return new XmlTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+    return createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
   }
 
   /**
@@ -1486,6 +1728,13 @@
     return tag;
   }
 
+  /**
+   * Return the expressions that are embedded in the tag's content.
+   *
+   * @return the expressions that are embedded in the tag's content
+   */
+  List<EmbeddedExpression> get expressions => EmbeddedExpression.EMPTY_ARRAY;
+
   void visitChildren(XmlVisitor visitor) {
     for (XmlAttributeNode node in attributes) {
       node.accept(visitor);
@@ -1513,14 +1762,64 @@
  * @coverage dart.engine.html
  */
 class HtmlParser extends XmlParser {
+  /**
+   * The line information associated with the source being parsed.
+   */
+  LineInfo _lineInfo;
+
+  /**
+   * The error listener to which errors will be reported.
+   */
+  AnalysisErrorListener _errorListener;
+
+  static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\"";
+
+  static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'";
+
+  static String _OPENING_DELIMITER = "{{";
+
+  static String _CLOSING_DELIMITER = "}}";
+
+  static String _SCRIPT = "script";
+
+  static String _TYPE = "type";
+
+  /**
+   * A set containing the names of tags that do not have a closing tag.
+   */
   static Set<String> SELF_CLOSING = new Set<String>();
 
   /**
    * Construct a parser for the specified source.
    *
    * @param source the source being parsed
+   * @param errorListener the error listener to which errors will be reported
    */
-  HtmlParser(Source source) : super(source);
+  HtmlParser(Source source, AnalysisErrorListener errorListener) : super(source) {
+    this._errorListener = errorListener;
+  }
+
+  Token getEndToken(Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
+    if (nodeEnd != null) {
+      return nodeEnd;
+    }
+    if (closingTag != null) {
+      return closingTag;
+    }
+    if (contentEnd != null) {
+      return contentEnd;
+    }
+    if (!tagNodes.isEmpty) {
+      return tagNodes[tagNodes.length - 1].endToken;
+    }
+    if (attributeEnd != null) {
+      return attributeEnd;
+    }
+    if (!attributes.isEmpty) {
+      return attributes[attributes.length - 1].endToken;
+    }
+    return tag;
+  }
 
   /**
    * Parse the tokens specified by the given scan result.
@@ -1529,6 +1828,8 @@
    * @return the parse result (not `null`)
    */
   HtmlParseResult parse(HtmlScanResult scanResult) {
+    List<int> lineStarts = scanResult.lineStarts;
+    _lineInfo = new LineInfo(lineStarts);
     Token firstToken = scanResult.token;
     List<XmlTagNode> tagNodes = parseTopTagNodes(firstToken);
     HtmlUnit unit = new HtmlUnit(firstToken, tagNodes, currentToken);
@@ -1547,7 +1848,109 @@
     return parse(scanner.result);
   }
 
+  XmlAttributeNode createAttributeNode(Token name, Token equals, Token value) {
+    List<EmbeddedExpression> expressions = new List<EmbeddedExpression>();
+    addEmbeddedExpressions(expressions, value);
+    if (expressions.isEmpty) {
+      return new XmlAttributeNode(name, equals, value);
+    }
+    return new AttributeWithEmbeddedExpressions(name, equals, value, new List.from(expressions));
+  }
+
+  XmlTagNode createTagNode(Token nodeStart, Token tag, List<XmlAttributeNode> attributes, Token attributeEnd, List<XmlTagNode> tagNodes, Token contentEnd, Token closingTag, Token nodeEnd) {
+    if (isScriptNode(tag, attributes, tagNodes)) {
+      HtmlScriptTagNode tagNode = new HtmlScriptTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+      String contents = tagNode.content;
+      int contentOffset = attributeEnd.end;
+      LineInfo_Location location = _lineInfo.getLocation(contentOffset);
+      sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+      scanner.setSourceStart(location.lineNumber, location.columnNumber);
+      sc.Token firstToken = scanner.tokenize();
+      Parser parser = new Parser(source, _errorListener);
+      CompilationUnit unit = parser.parseCompilationUnit(firstToken);
+      unit.lineInfo = _lineInfo;
+      tagNode.script = unit;
+      return tagNode;
+    }
+    Token token = nodeStart;
+    Token endToken = getEndToken(tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+    List<EmbeddedExpression> expressions = new List<EmbeddedExpression>();
+    while (token != endToken) {
+      if (identical(token.type, TokenType.TEXT)) {
+        addEmbeddedExpressions(expressions, token);
+      }
+      token = token.next;
+    }
+    if (expressions.isEmpty) {
+      return super.createTagNode(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd);
+    }
+    return new TagWithEmbeddedExpressions(nodeStart, tag, attributes, attributeEnd, tagNodes, contentEnd, closingTag, nodeEnd, new List.from(expressions));
+  }
+
   bool isSelfClosing(Token tag) => SELF_CLOSING.contains(tag.lexeme);
+
+  /**
+   * Parse the value of the given token for embedded expressions, and add any embedded expressions
+   * that are found to the given list of expressions.
+   *
+   * @param expressions the list to which embedded expressions are to be added
+   * @param token the token whose value is to be parsed
+   */
+  void addEmbeddedExpressions(List<EmbeddedExpression> expressions, Token token) {
+    String lexeme = token.lexeme;
+    int startIndex = lexeme.indexOf(_OPENING_DELIMITER);
+    while (startIndex >= 0) {
+      int endIndex = JavaString.indexOf(lexeme, _CLOSING_DELIMITER, startIndex + 2);
+      if (endIndex < 0) {
+        return;
+      } else if (startIndex + 2 < endIndex) {
+        int offset = token.offset;
+        expressions.add(new EmbeddedExpression(startIndex, parseEmbeddedExpression(lexeme.substring(startIndex + 2, endIndex), offset + startIndex), endIndex));
+      }
+      startIndex = JavaString.indexOf(lexeme, _OPENING_DELIMITER, endIndex + 2);
+    }
+  }
+
+  /**
+   * Determine if the specified node is a Dart script.
+   *
+   * @param node the node to be tested (not `null`)
+   * @return `true` if the node is a Dart script
+   */
+  bool isScriptNode(Token tag, List<XmlAttributeNode> attributes, List<XmlTagNode> tagNodes) {
+    if (tagNodes.length != 0 || tag.lexeme != _SCRIPT) {
+      return false;
+    }
+    for (XmlAttributeNode attribute in attributes) {
+      if (attribute.name.lexeme == _TYPE) {
+        Token valueToken = attribute.value;
+        if (valueToken != null) {
+          String value = valueToken.lexeme;
+          if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Given the contents of an embedded expression that occurs at the given offset, parse it as a
+   * Dart expression. The contents should not include the expression's delimiters.
+   *
+   * @param contents the contents of the expression
+   * @param contentOffset the offset of the expression in the larger file
+   * @return the Dart expression that was parsed
+   */
+  Expression parseEmbeddedExpression(String contents, int contentOffset) {
+    LineInfo_Location location = _lineInfo.getLocation(contentOffset);
+    sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+    scanner.setSourceStart(location.lineNumber, location.columnNumber);
+    sc.Token firstToken = scanner.tokenize();
+    Parser parser = new Parser(source, _errorListener);
+    return parser.parseExpression(firstToken);
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/instrumentation.dart b/pkg/analyzer/lib/src/generated/instrumentation.dart
index 50ddb07..a9c7b7b 100644
--- a/pkg/analyzer/lib/src/generated/instrumentation.dart
+++ b/pkg/analyzer/lib/src/generated/instrumentation.dart
@@ -40,13 +40,13 @@
   /**
    * A builder that will silently ignore all data and logging requests.
    */
-  static final InstrumentationBuilder nullBuilder = new InstrumentationBuilder_17();
+  static final InstrumentationBuilder nullBuilder = new InstrumentationBuilder_18();
 
   /**
    * An instrumentation logger that can be used when no other instrumentation logger has been
    * configured. This logger will silently ignore all data and logging requests.
    */
-  static InstrumentationLogger _NULL_LOGGER = new InstrumentationLogger_18();
+  static InstrumentationLogger _NULL_LOGGER = new InstrumentationLogger_19();
 
   /**
    * The current instrumentation logger.
@@ -92,7 +92,7 @@
   }
 }
 
-class InstrumentationBuilder_17 implements InstrumentationBuilder {
+class InstrumentationBuilder_18 implements InstrumentationBuilder {
   InstrumentationBuilder data(String name, bool value) => this;
 
   InstrumentationBuilder data2(String name, int value) => this;
@@ -120,7 +120,7 @@
   InstrumentationBuilder record(Exception exception) => this;
 }
 
-class InstrumentationLogger_18 implements InstrumentationLogger {
+class InstrumentationLogger_19 implements InstrumentationLogger {
   InstrumentationBuilder createBuilder(String name) => Instrumentation.nullBuilder;
 }
 
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index 46fdaae..ea75f59 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -82,6 +82,9 @@
 
 class JavaArrays {
   static bool equals(List a, List b) {
+    if (identical(a, b)) {
+      return true;
+    }
     if (a.length != b.length) {
       return false;
     }
@@ -401,14 +404,6 @@
   return oldValue;
 }
 
-bool javaSetAdd(Set s, o) {
-  if (!s.contains(o)) {
-    s.add(o);
-    return true;
-  }
-  return false;
-}
-
 bool javaCollectionContainsAll(Iterable list, Iterable c) {
   return c.fold(true, (bool prev, e) => prev && list.contains(e));
 }
@@ -419,12 +414,6 @@
   return oldValue;
 }
 
-void javaMapPutAll(Map target, Map source) {
-  source.forEach((k, v) {
-    target[k] = v;
-  });
-}
-
 bool javaStringEqualsIgnoreCase(String a, String b) {
   return a.toLowerCase() == b.toLowerCase();
 }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 465cf56..fc20dc5 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -1163,60 +1163,69 @@
   }
 
   /**
-   * Given a range of tokens that were re-scanned, re-parse the minimimum number of tokens to
-   * produce a consistent AST structure. The range is represented by the first and last tokens in
-   * the range. The tokens are assumed to be contained in the same token stream.
+   * Given a range of tokens that were re-scanned, re-parse the minimum number of tokens to produce
+   * a consistent AST structure. The range is represented by the first and last tokens in the range.
+   * The tokens are assumed to be contained in the same token stream.
    *
-   * @param firstToken the first token in the range of tokens that were re-scanned or `null`
-   *          if no new tokens were inserted
-   * @param lastToken the last token in the range of tokens that were re-scanned or `null` if
-   *          no new tokens were inserted
+   * @param leftToken the token in the new token stream immediately to the left of the range of
+   *          tokens that were inserted
+   * @param rightToken the token in the new token stream immediately to the right of the range of
+   *          tokens that were inserted
    * @param originalStart the offset in the original source of the first character that was modified
    * @param originalEnd the offset in the original source of the last character that was modified
    */
-  ASTNode reparse(ASTNode originalStructure, Token firstToken, Token lastToken, int originalStart, int originalEnd) {
+  ASTNode reparse(ASTNode originalStructure, Token leftToken, Token rightToken, int originalStart, int originalEnd) {
     ASTNode oldNode = null;
     ASTNode newNode = null;
-    if (firstToken != null) {
-      if (originalEnd < originalStart) {
-        oldNode = new NodeLocator.con1(originalStart).searchWithin(originalStructure);
-      } else {
-        oldNode = new NodeLocator.con2(originalStart, originalEnd).searchWithin(originalStructure);
-      }
-      int originalOffset = oldNode.offset;
-      Token parseToken = findTokenAt(firstToken, originalOffset);
-      if (parseToken == null) {
-        return null;
-      }
-      Parser parser = new Parser(_source, _errorListener);
-      parser.currentToken = parseToken;
-      while (newNode == null) {
-        ASTNode parent = oldNode.parent;
-        if (parent == null) {
-          parseToken = findFirstToken(parseToken);
-          parser.currentToken = parseToken;
-          return parser.parseCompilationUnit2() as ASTNode;
-        }
-        try {
-          IncrementalParseDispatcher dispatcher = new IncrementalParseDispatcher(parser, oldNode);
-          newNode = parent.accept(dispatcher);
-        } on InsufficientContextException catch (exception) {
-          oldNode = parent;
-          originalOffset = oldNode.offset;
-          parseToken = findTokenAt(parseToken, originalOffset);
-          parser.currentToken = parseToken;
-        } on JavaException catch (exception) {
-          return null;
-        }
-      }
-      if (newNode.offset != originalOffset) {
-        return null;
-      }
-      if (identical(oldNode, originalStructure)) {
-        return newNode as ASTNode;
-      }
-      ResolutionCopier.copyResolutionData(oldNode, newNode);
+    Token firstToken = leftToken.next;
+    if (identical(firstToken, rightToken)) {
+      firstToken = leftToken;
     }
+    if (originalEnd < originalStart) {
+      oldNode = new NodeLocator.con1(originalStart).searchWithin(originalStructure);
+    } else {
+      oldNode = new NodeLocator.con2(originalStart, originalEnd).searchWithin(originalStructure);
+    }
+    int originalOffset = oldNode.offset;
+    Token parseToken = findTokenAt(firstToken, originalOffset);
+    if (parseToken == null) {
+      return null;
+    }
+    Parser parser = new Parser(_source, _errorListener);
+    parser.currentToken = parseToken;
+    while (newNode == null) {
+      ASTNode parent = oldNode.parent;
+      if (parent == null) {
+        parseToken = findFirstToken(parseToken);
+        parser.currentToken = parseToken;
+        return parser.parseCompilationUnit2() as ASTNode;
+      }
+      bool advanceToParent = false;
+      try {
+        IncrementalParseDispatcher dispatcher = new IncrementalParseDispatcher(parser, oldNode);
+        newNode = parent.accept(dispatcher);
+        Token mappedToken = _tokenMap.get(oldNode.endToken.next);
+        if (mappedToken == null || mappedToken.offset != newNode.endToken.next.offset || newNode.offset != oldNode.offset) {
+          advanceToParent = true;
+        }
+      } on InsufficientContextException catch (exception) {
+        advanceToParent = true;
+      } on JavaException catch (exception) {
+        return null;
+      }
+      if (advanceToParent) {
+        newNode = null;
+        oldNode = parent;
+        originalOffset = oldNode.offset;
+        parseToken = findTokenAt(parseToken, originalOffset);
+        parser.currentToken = parseToken;
+      }
+    }
+    if (identical(oldNode, originalStructure)) {
+      ResolutionCopier.copyResolutionData(oldNode, newNode);
+      return newNode as ASTNode;
+    }
+    ResolutionCopier.copyResolutionData(oldNode, newNode);
     IncrementalASTCloner cloner = new IncrementalASTCloner(oldNode, newNode, _tokenMap);
     return originalStructure.accept(cloner) as ASTNode;
   }
@@ -1342,9 +1351,7 @@
     InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseCompilationUnit");
     try {
       _currentToken = token;
-      CompilationUnit compilationUnit = parseCompilationUnit2();
-      gatherTodoComments(token);
-      return compilationUnit;
+      return parseCompilationUnit2();
     } finally {
       instrumentation.log2(2);
     }
@@ -1722,8 +1729,9 @@
           if (partOfDirectiveFound) {
             reportError9(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
           } else {
-            for (Directive precedingDirective in directives) {
-              reportError10(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, precedingDirective.keyword, []);
+            int directiveCount = directives.length;
+            for (int i = 0; i < directiveCount; i++) {
+              reportError10(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
             }
             partOfDirectiveFound = true;
           }
@@ -2529,7 +2537,15 @@
    *
    * @return the synthetic identifier that was created
    */
-  SimpleIdentifier createSyntheticIdentifier() => new SimpleIdentifier.full(createSyntheticToken2(TokenType.IDENTIFIER));
+  SimpleIdentifier createSyntheticIdentifier() {
+    Token syntheticToken;
+    if (identical(_currentToken.type, TokenType.KEYWORD)) {
+      syntheticToken = injectToken(new SyntheticStringToken(TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
+    } else {
+      syntheticToken = createSyntheticToken2(TokenType.IDENTIFIER);
+    }
+    return new SimpleIdentifier.full(syntheticToken);
+  }
 
   /**
    * Create a synthetic string literal.
@@ -2543,14 +2559,14 @@
    *
    * @return the synthetic token that was created
    */
-  Token createSyntheticToken(Keyword keyword) => new Parser_SyntheticKeywordToken(keyword, _currentToken.offset);
+  Token createSyntheticToken(Keyword keyword) => injectToken(new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
 
   /**
    * Create a synthetic token with the given type.
    *
    * @return the synthetic token that was created
    */
-  Token createSyntheticToken2(TokenType type) => new StringToken(type, "", _currentToken.offset);
+  Token createSyntheticToken2(TokenType type) => injectToken(new StringToken(type, "", _currentToken.offset));
 
   /**
    * Check that the given expression is assignable and report an error if it isn't.
@@ -2617,7 +2633,9 @@
    * @return the range that was found
    */
   List<int> findRange(List<List<int>> ranges, int index) {
-    for (List<int> range in ranges) {
+    int rangeCount = ranges.length;
+    for (int i = 0; i < rangeCount; i++) {
+      List<int> range = ranges[i];
       if (range[0] <= index && index <= range[1]) {
         return range;
       } else if (index < range[0]) {
@@ -2627,19 +2645,6 @@
     return null;
   }
 
-  void gatherTodoComments(Token token) {
-    while (token != null && token.type != TokenType.EOF) {
-      Token commentToken = token.precedingComments;
-      while (commentToken != null) {
-        if (identical(commentToken.type, TokenType.SINGLE_LINE_COMMENT) || identical(commentToken.type, TokenType.MULTI_LINE_COMMENT)) {
-          scrapeTodoComment(commentToken);
-        }
-        commentToken = commentToken.next;
-      }
-      token = token.next;
-    }
-  }
-
   /**
    * Advance to the next token in the token stream, making it the new current token.
    *
@@ -2726,6 +2731,19 @@
   }
 
   /**
+   * Inject the given token into the token stream immediately before the current token.
+   *
+   * @param token the token to be added to the token stream
+   * @return the token that was just added to the token stream
+   */
+  Token injectToken(Token token) {
+    Token previous = _currentToken.previous;
+    token.setNext(_currentToken);
+    previous.setNext(token);
+    return token;
+  }
+
+  /**
    * Return `true` if the current token appears to be the beginning of a function declaration.
    *
    * @return `true` if the current token appears to be the beginning of a function declaration
@@ -3623,12 +3641,11 @@
       return null;
     }
     try {
-      List<bool> errorFound = [false];
-      AnalysisErrorListener listener = new AnalysisErrorListener_16(errorFound);
+      BooleanErrorListener listener = new BooleanErrorListener();
       Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence(referenceSource), sourceOffset), listener);
       scanner.setSourceStart(1, 1);
       Token firstToken = scanner.tokenize();
-      if (errorFound[0]) {
+      if (listener.errorReported) {
         return null;
       }
       Token newKeyword = null;
@@ -3869,7 +3886,7 @@
       }
     } else {
       body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
-      if (constKeyword != null && factoryKeyword != null) {
+      if (constKeyword != null && factoryKeyword != null && externalKeyword == null) {
         reportError10(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
       } else if (body is EmptyFunctionBody) {
         if (factoryKeyword != null && externalKeyword == null) {
@@ -5577,7 +5594,7 @@
           if (definedLabels.contains(label)) {
             reportError10(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
           } else {
-            javaSetAdd(definedLabels, label);
+            definedLabels.add(label);
           }
           Token colon = expect2(TokenType.COLON);
           labels.add(new Label.full(identifier, colon));
@@ -6032,20 +6049,6 @@
   }
 
   /**
-   * Look for user defined tasks in comments and convert them into info level analysis issues.
-   *
-   * @param commentToken the comment token to analyze
-   */
-  void scrapeTodoComment(Token commentToken) {
-    JavaPatternMatcher matcher = new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
-    if (matcher.find()) {
-      int offset = commentToken.offset + matcher.start() + matcher.group(1).length;
-      int length = matcher.group(2).length;
-      // _errorListener.onError(new AnalysisError.con2(_source, offset, length, TodoCode.TODO, [matcher.group(2)]));
-    }
-  }
-
-  /**
    * Parse the 'final', 'const', 'var' or type preceding a variable declaration, starting at the
    * given token, without actually creating a type or changing the current token. Return the token
    * following the type that was parsed, or `null` if the given token is not the first token
@@ -6843,16 +6846,6 @@
   int get length => 0;
 }
 
-class AnalysisErrorListener_16 implements AnalysisErrorListener {
-  List<bool> errorFound;
-
-  AnalysisErrorListener_16(this.errorFound);
-
-  void onError(AnalysisError error) {
-    errorFound[0] = true;
-  }
-}
-
 /**
  * The enumeration `ParserErrorCode` defines the error codes used for errors detected by the
  * parser. The convention for this class is for the name of the error code to indicate the problem
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a329dae..c9f6551 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -152,8 +152,9 @@
     element.methods = holder.methods;
     element.typeParameters = typeParameters;
     element.validMixin = _isValidMixin;
-    for (FunctionTypeImpl functionType in _functionTypesToFix) {
-      functionType.typeArguments = typeArguments;
+    int functionTypeCount = _functionTypesToFix.length;
+    for (int i = 0; i < functionTypeCount; i++) {
+      _functionTypesToFix[i].typeArguments = typeArguments;
     }
     _functionTypesToFix = null;
     _currentHolder.addType(element);
@@ -1108,16 +1109,8 @@
  * Instances of the class `HtmlUnitBuilder` build an element model for a single HTML unit.
  */
 class HtmlUnitBuilder implements ht.XmlVisitor<Object> {
-  static String _APPLICATION_DART_IN_DOUBLE_QUOTES = "\"application/dart\"";
-
-  static String _APPLICATION_DART_IN_SINGLE_QUOTES = "'application/dart'";
-
-  static String _SCRIPT = "script";
-
   static String _SRC = "src";
 
-  static String _TYPE = "type";
-
   /**
    * The analysis context in which the element model will be built.
    */
@@ -1199,6 +1192,52 @@
     return result;
   }
 
+  Object visitHtmlScriptTagNode(ht.HtmlScriptTagNode node) {
+    if (_parentNodes.contains(node)) {
+      return reportCircularity(node);
+    }
+    _parentNodes.add(node);
+    try {
+      Source htmlSource = _htmlElement.source;
+      ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
+      String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
+      if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
+        EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
+        try {
+          LibraryResolver resolver = new LibraryResolver(_context);
+          LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSource, _modificationStamp, node.script, true) as LibraryElementImpl;
+          script.scriptLibrary = library;
+          resolvedLibraries.addAll(resolver.resolvedLibraries);
+          errorListener.addAll(resolver.errorListener);
+        } on AnalysisException catch (exception) {
+          AnalysisEngine.instance.logger.logError3(exception);
+        }
+        node.scriptElement = script;
+        _scripts.add(script);
+      } else {
+        ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
+        if (scriptSourcePath != null) {
+          try {
+            scriptSourcePath = Uri.encodeFull(scriptSourcePath);
+            parseUriWithException(scriptSourcePath);
+            Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
+            script.scriptSource = scriptSource;
+            if (scriptSource == null || !scriptSource.exists()) {
+              reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute, [scriptSourcePath]);
+            }
+          } on URISyntaxException catch (exception) {
+            reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, [scriptSourcePath]);
+          }
+        }
+        node.scriptElement = script;
+        _scripts.add(script);
+      }
+    } finally {
+      _parentNodes.remove(node);
+    }
+    return null;
+  }
+
   Object visitHtmlUnit(ht.HtmlUnit node) {
     _parentNodes = new List<ht.XmlTagNode>();
     _scripts = new List<HtmlScriptElement>();
@@ -1212,78 +1251,23 @@
     return null;
   }
 
-  Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
+  Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
+    for (ht.EmbeddedExpression expression in node.expressions) {
+      resolveExpression(expression.expression);
+    }
+    return null;
+  }
 
   Object visitXmlTagNode(ht.XmlTagNode node) {
     if (_parentNodes.contains(node)) {
-      JavaStringBuilder builder = new JavaStringBuilder();
-      builder.append("Found circularity in XML nodes: ");
-      bool first = true;
-      for (ht.XmlTagNode pathNode in _parentNodes) {
-        if (first) {
-          first = false;
-        } else {
-          builder.append(", ");
-        }
-        String tagName = pathNode.tag.lexeme;
-        if (identical(pathNode, node)) {
-          builder.append("*");
-          builder.append(tagName);
-          builder.append("*");
-        } else {
-          builder.append(tagName);
-        }
-      }
-      AnalysisEngine.instance.logger.logError(builder.toString());
-      return null;
+      return reportCircularity(node);
     }
     _parentNodes.add(node);
     try {
-      if (isScriptNode(node)) {
-        Source htmlSource = _htmlElement.source;
-        ht.XmlAttributeNode scriptAttribute = getScriptSourcePath(node);
-        String scriptSourcePath = scriptAttribute == null ? null : scriptAttribute.text;
-        if (identical(node.attributeEnd.type, ht.TokenType.GT) && scriptSourcePath == null) {
-          EmbeddedHtmlScriptElementImpl script = new EmbeddedHtmlScriptElementImpl(node);
-          String contents = node.content;
-          int attributeEnd = node.attributeEnd.end;
-          LineInfo_Location location = _lineInfo.getLocation(attributeEnd);
-          sc.Scanner scanner = new sc.Scanner(htmlSource, new sc.SubSequenceReader(new CharSequence(contents), attributeEnd), errorListener);
-          scanner.setSourceStart(location.lineNumber, location.columnNumber);
-          sc.Token firstToken = scanner.tokenize();
-          List<int> lineStarts = scanner.lineStarts;
-          Parser parser = new Parser(htmlSource, errorListener);
-          CompilationUnit unit = parser.parseCompilationUnit(firstToken);
-          try {
-            LibraryResolver resolver = new LibraryResolver(_context);
-            LibraryElementImpl library = resolver.resolveEmbeddedLibrary(htmlSource, _modificationStamp, unit, true) as LibraryElementImpl;
-            script.scriptLibrary = library;
-            resolvedLibraries.addAll(resolver.resolvedLibraries);
-            errorListener.addAll(resolver.errorListener);
-          } on AnalysisException catch (exception) {
-            AnalysisEngine.instance.logger.logError3(exception);
-          }
-          _scripts.add(script);
-        } else {
-          ExternalHtmlScriptElementImpl script = new ExternalHtmlScriptElementImpl(node);
-          if (scriptSourcePath != null) {
-            try {
-              scriptSourcePath = Uri.encodeFull(scriptSourcePath);
-              parseUriWithException(scriptSourcePath);
-              Source scriptSource = _context.sourceFactory.resolveUri(htmlSource, scriptSourcePath);
-              script.scriptSource = scriptSource;
-              if (scriptSource == null || !scriptSource.exists()) {
-                reportValueError(HtmlWarningCode.URI_DOES_NOT_EXIST, scriptAttribute, [scriptSourcePath]);
-              }
-            } on URISyntaxException catch (exception) {
-              reportValueError(HtmlWarningCode.INVALID_URI, scriptAttribute, [scriptSourcePath]);
-            }
-          }
-          _scripts.add(script);
-        }
-      } else {
-        node.visitChildren(this);
+      for (ht.EmbeddedExpression expression in node.expressions) {
+        resolveExpression(expression.expression);
       }
+      node.visitChildren(this);
     } finally {
       _parentNodes.remove(node);
     }
@@ -1305,28 +1289,27 @@
     return null;
   }
 
-  /**
-   * Determine if the specified node is a Dart script.
-   *
-   * @param node the node to be tested (not `null`)
-   * @return `true` if the node is a Dart script
-   */
-  bool isScriptNode(ht.XmlTagNode node) {
-    if (node.tagNodes.length != 0 || node.tag.lexeme != _SCRIPT) {
-      return false;
-    }
-    for (ht.XmlAttributeNode attribute in node.attributes) {
-      if (attribute.name.lexeme == _TYPE) {
-        ht.Token valueToken = attribute.value;
-        if (valueToken != null) {
-          String value = valueToken.lexeme;
-          if (value == _APPLICATION_DART_IN_DOUBLE_QUOTES || value == _APPLICATION_DART_IN_SINGLE_QUOTES) {
-            return true;
-          }
-        }
+  Object reportCircularity(ht.XmlTagNode node) {
+    JavaStringBuilder builder = new JavaStringBuilder();
+    builder.append("Found circularity in XML nodes: ");
+    bool first = true;
+    for (ht.XmlTagNode pathNode in _parentNodes) {
+      if (first) {
+        first = false;
+      } else {
+        builder.append(", ");
+      }
+      String tagName = pathNode.tag.lexeme;
+      if (identical(pathNode, node)) {
+        builder.append("*");
+        builder.append(tagName);
+        builder.append("*");
+      } else {
+        builder.append(tagName);
       }
     }
-    return false;
+    AnalysisEngine.instance.logger.logError(builder.toString());
+    return null;
   }
 
   /**
@@ -1356,6 +1339,9 @@
     int length = attribute.value.length - 2;
     reportError(errorCode, offset, length, arguments);
   }
+
+  void resolveExpression(Expression expression) {
+  }
 }
 
 /**
@@ -1589,7 +1575,11 @@
    * @see HintCode#DEPRECATED_MEMBER_USE
    */
   bool checkForDeprecatedMemberUse2(SimpleIdentifier identifier) {
-    if (identifier.inDeclarationContext() || (identifier.parent is ConstructorName && identical(identifier, (identifier.parent as ConstructorName).name)) || (identifier.parent is SuperConstructorInvocation && identical(identifier, (identifier.parent as SuperConstructorInvocation).constructorName))) {
+    if (identifier.inDeclarationContext()) {
+      return false;
+    }
+    ASTNode parent = identifier.parent;
+    if ((parent is ConstructorName && identical(identifier, (parent as ConstructorName).name)) || (parent is SuperConstructorInvocation && identical(identifier, (parent as SuperConstructorInvocation).constructorName)) || parent is HideCombinator) {
       return false;
     }
     return checkForDeprecatedMemberUse(identifier.bestElement, identifier);
@@ -2087,6 +2077,7 @@
       new Dart2JSVerifier(errorReporter).visitCompilationUnit(unit);
     }
     new BestPracticesVerifier(errorReporter).visitCompilationUnit(unit);
+    new ToDoFinder(errorReporter).findIn(unit);
   }
 }
 
@@ -2547,6 +2538,68 @@
 }
 
 /**
+ * Instances of the class `ToDoFinder` find to-do comments in Dart code.
+ */
+class ToDoFinder {
+  /**
+   * The error reporter by which to-do comments will be reported.
+   */
+  ErrorReporter _errorReporter;
+
+  /**
+   * Initialize a newly created to-do finder to report to-do comments to the given reporter.
+   *
+   * @param errorReporter the error reporter by which to-do comments will be reported
+   */
+  ToDoFinder(ErrorReporter errorReporter) {
+    this._errorReporter = errorReporter;
+  }
+
+  /**
+   * Search the comments in the given compilation unit for to-do comments and report an error for
+   * each.
+   *
+   * @param unit the compilation unit containing the to-do comments
+   */
+  void findIn(CompilationUnit unit) {
+    gatherTodoComments(unit.beginToken);
+  }
+
+  /**
+   * Search the comment tokens reachable from the given token and create errors for each to-do
+   * comment.
+   *
+   * @param token the head of the list of tokens being searched
+   */
+  void gatherTodoComments(sc.Token token) {
+    while (token != null && token.type != sc.TokenType.EOF) {
+      sc.Token commentToken = token.precedingComments;
+      while (commentToken != null) {
+        if (identical(commentToken.type, sc.TokenType.SINGLE_LINE_COMMENT) || identical(commentToken.type, sc.TokenType.MULTI_LINE_COMMENT)) {
+          scrapeTodoComment(commentToken);
+        }
+        commentToken = commentToken.next;
+      }
+      token = token.next;
+    }
+  }
+
+  /**
+   * Look for user defined tasks in comments and convert them into info level analysis issues.
+   *
+   * @param commentToken the comment token to analyze
+   */
+  void scrapeTodoComment(sc.Token commentToken) {
+    JavaPatternMatcher matcher = new JavaPatternMatcher(TodoCode.TODO_REGEX, commentToken.lexeme);
+    if (matcher.find()) {
+      int offset = commentToken.offset + matcher.start() + matcher.group(1).length;
+      int length = matcher.group(2).length;
+      _errorReporter.reportError4(TodoCode.TODO, offset, length, [matcher.group(2)]);
+    }
+  }
+}
+
+/**
  * Instances of the class `DeclarationMatcher` determine whether the element model defined by
  * a given AST structure matches an existing element model.
  */
@@ -3154,8 +3207,8 @@
   GeneralizingElementVisitor_7(this.DeclarationMatcher_this) : super();
 
   Object visitElement(Element element) {
-    javaSetAdd(DeclarationMatcher_this._allElements, element);
-    javaSetAdd(DeclarationMatcher_this._unmatchedElements, element);
+    DeclarationMatcher_this._allElements.add(element);
+    DeclarationMatcher_this._unmatchedElements.add(element);
     return super.visitElement(element);
   }
 }
@@ -3806,12 +3859,6 @@
   LibraryElement _definingLibrary;
 
   /**
-   * A flag indicating whether we are running in strict mode. In strict mode, error reporting is
-   * based exclusively on the static type information.
-   */
-  bool _strictMode = false;
-
-  /**
    * A flag indicating whether we should generate hints.
    */
   bool _enableHints = false;
@@ -3857,7 +3904,6 @@
     this._resolver = resolver;
     this._definingLibrary = resolver.definingLibrary;
     AnalysisOptions options = _definingLibrary.context.analysisOptions;
-    _strictMode = options.strictMode;
     _enableHints = options.hint;
     _dynamicType = resolver.typeProvider.dynamicType;
     _typeType = resolver.typeProvider.typeType;
@@ -3879,7 +3925,7 @@
         Type2 propagatedType = getPropagatedType(leftHandSide);
         MethodElement propagatedMethod = lookUpMethod(leftHandSide, propagatedType, methodName);
         node.propagatedElement = propagatedMethod;
-        bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+        bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
         bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
         if (shouldReportMissingMember_propagated) {
           if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -3909,7 +3955,7 @@
         Type2 propagatedType = getPropagatedType(leftOperand);
         MethodElement propagatedMethod = lookUpMethod(leftOperand, propagatedType, methodName);
         node.propagatedElement = propagatedMethod;
-        bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+        bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
         bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
         if (shouldReportMissingMember_propagated) {
           if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4246,6 +4292,9 @@
 
   Object visitMethodInvocation(MethodInvocation node) {
     SimpleIdentifier methodName = node.methodName;
+    if (methodName.isSynthetic) {
+      return null;
+    }
     Expression target = node.realTarget;
     if (target is SuperExpression && !isSuperInValidContext(target as SuperExpression)) {
       return null;
@@ -4368,7 +4417,7 @@
     Type2 propagatedType = getPropagatedType(operand);
     MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
     node.propagatedElement = propagatedMethod;
-    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
     bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
     if (shouldReportMissingMember_propagated) {
       if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4442,7 +4491,7 @@
       Type2 propagatedType = getPropagatedType(operand);
       MethodElement propagatedMethod = lookUpMethod(operand, propagatedType, methodName);
       node.propagatedElement = propagatedMethod;
-      bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+      bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
       bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
       if (shouldReportMissingMember_propagated) {
         if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4497,6 +4546,9 @@
   }
 
   Object visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.isSynthetic) {
+      return null;
+    }
     if (node.staticElement != null) {
       return null;
     }
@@ -4603,8 +4655,9 @@
    * @param annotations the AST nodes used to generate new elements
    */
   void addAnnotations(List<ElementAnnotationImpl> annotationList, NodeList<Annotation> annotations) {
-    for (Annotation annotationNode in annotations) {
-      Element resolvedElement = annotationNode.element;
+    int annotationCount = annotations.length;
+    for (int i = 0; i < annotationCount; i++) {
+      Element resolvedElement = annotations[i].element;
       if (resolvedElement != null) {
         annotationList.add(new ElementAnnotationImpl(resolvedElement));
       }
@@ -4690,7 +4743,7 @@
    * @return `true` if and only if an error code is generated on the passed node
    */
   bool checkForUndefinedIndexOperator(IndexExpression node, Expression target, String methodName, MethodElement staticMethod, MethodElement propagatedMethod, Type2 staticType, Type2 propagatedType) {
-    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedMethod));
+    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticMethod);
     bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedMethod) : false;
     if (shouldReportMissingMember_propagated) {
       if (memberFoundInSubclass(propagatedType.element, methodName, true, false)) {
@@ -4973,7 +5026,7 @@
     if (visitedInterfaces.contains(targetClass)) {
       return null;
     }
-    javaSetAdd(visitedInterfaces, targetClass);
+    visitedInterfaces.add(targetClass);
     if (includeTargetType) {
       PropertyAccessorElement getter = targetType.getGetter(getterName);
       if (getter != null && getter.isAccessibleIn(_definingLibrary)) {
@@ -5042,7 +5095,7 @@
     if (visitedInterfaces.contains(targetClass)) {
       return null;
     }
-    javaSetAdd(visitedInterfaces, targetClass);
+    visitedInterfaces.add(targetClass);
     if (includeTargetType) {
       ExecutableElement member = targetType.getMethod(memberName);
       if (member != null) {
@@ -5156,7 +5209,7 @@
     if (visitedInterfaces.contains(targetClass)) {
       return null;
     }
-    javaSetAdd(visitedInterfaces, targetClass);
+    visitedInterfaces.add(targetClass);
     if (includeTargetType) {
       MethodElement method = targetType.getMethod(methodName);
       if (method != null && method.isAccessibleIn(_definingLibrary)) {
@@ -5226,7 +5279,7 @@
     if (visitedInterfaces.contains(targetClass)) {
       return null;
     }
-    javaSetAdd(visitedInterfaces, targetClass);
+    visitedInterfaces.add(targetClass);
     if (includeTargetType) {
       PropertyAccessorElement setter = targetType.getSetter(setterName);
       if (setter != null && setter.isAccessibleIn(_definingLibrary)) {
@@ -5485,7 +5538,7 @@
           resolvedParameters[i] = element;
           nameNode.staticElement = element;
         }
-        if (!javaSetAdd(usedNames, name)) {
+        if (!usedNames.add(name)) {
           _resolver.reportError6(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
         }
       } else {
@@ -5655,7 +5708,7 @@
     }
     propertyName.staticElement = staticElement;
     propertyName.propagatedElement = propagatedElement;
-    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticElement) && (_strictMode || shouldReportMissingMember(propagatedType, propagatedElement));
+    bool shouldReportMissingMember_static = shouldReportMissingMember(staticType, staticElement);
     bool shouldReportMissingMember_propagated = !shouldReportMissingMember_static && _enableHints ? shouldReportMissingMember(propagatedType, propagatedElement) : false;
     if (shouldReportMissingMember_propagated) {
       if (memberFoundInSubclass(propagatedType.element, propertyName.name, false, true)) {
@@ -5758,15 +5811,6 @@
   }
 
   /**
-   * Return the propagated element if it is not `null`, or the static element if it is.
-   *
-   * @param staticElement the element computed using static type information
-   * @param propagatedElement the element computed using propagated type information
-   * @return the more specific of the two elements
-   */
-  ExecutableElement select(ExecutableElement staticElement, ExecutableElement propagatedElement) => propagatedElement != null ? propagatedElement : staticElement;
-
-  /**
    * Given a node that can have annotations associated with it and the element to which that node
    * has been resolved, create the annotations in the element model representing the annotations on
    * the node.
@@ -5843,6 +5887,8 @@
 
   String get name => _name;
 
+  int get precedence => 16;
+
   Element get propagatedElement => null;
 
   Element get staticElement => null;
@@ -6191,7 +6237,7 @@
     }
     if (superclassElt != null) {
       if (!visitedClasses.contains(superclassElt)) {
-        javaSetAdd(visitedClasses, classElt);
+        visitedClasses.add(classElt);
         resultMap = new MemberMap.con2(computeClassChainLookupMap(superclassElt, visitedClasses));
       } else {
         _classLookup[superclassElt] = resultMap;
@@ -6281,7 +6327,7 @@
     if (superclassElement != null) {
       if (!visitedInterfaces.contains(superclassElement)) {
         try {
-          javaSetAdd(visitedInterfaces, superclassElement);
+          visitedInterfaces.add(superclassElement);
           MemberMap map = computeInterfaceLookupMap(superclassElement, visitedInterfaces);
           map = new MemberMap.con2(map);
           substituteTypeParametersDownHierarchy(supertype, map);
@@ -6310,7 +6356,7 @@
       if (interfaceElement != null) {
         if (!visitedInterfaces.contains(interfaceElement)) {
           try {
-            javaSetAdd(visitedInterfaces, interfaceElement);
+            visitedInterfaces.add(interfaceElement);
             MemberMap map = computeInterfaceLookupMap(interfaceElement, visitedInterfaces);
             map = new MemberMap.con2(map);
             substituteTypeParametersDownHierarchy(interfaceType, map);
@@ -6346,7 +6392,7 @@
           set = new Set<ExecutableElement>();
           unionMap[key] = set;
         }
-        javaSetAdd(set, lookupMap.getValue(i));
+        set.add(lookupMap.getValue(i));
       }
     }
     for (MapEntry<String, Set<ExecutableElement>> entry in getMapEntrySet(unionMap)) {
@@ -6479,7 +6525,7 @@
       errorSet = new Set<AnalysisError>();
       _errorsInClassElement[classElt] = errorSet;
     }
-    javaSetAdd(errorSet, new AnalysisError.con2(classElt.source, offset, length, errorCode, arguments));
+    errorSet.add(new AnalysisError.con2(classElt.source, offset, length, errorCode, arguments));
   }
 
   /**
@@ -6646,10 +6692,10 @@
   List<Library> get importsAndExports {
     Set<Library> libraries = new Set<Library>();
     for (Library library in imports) {
-      javaSetAdd(libraries, library);
+      libraries.add(library);
     }
     for (Library library in exports) {
-      javaSetAdd(libraries, library);
+      libraries.add(library);
     }
     return new List.from(libraries);
   }
@@ -7101,7 +7147,10 @@
       Library targetLibrary = createLibrary(librarySource);
       _coreLibrary = _libraryMap[_coreLibrarySource];
       if (_coreLibrary == null) {
-        _coreLibrary = createLibrary(_coreLibrarySource);
+        _coreLibrary = createLibraryOrNull(_coreLibrarySource);
+        if (_coreLibrary == null) {
+          throw new AnalysisException.con1("Core library does not exist");
+        }
       }
       instrumentation.metric3("createLibrary", "complete");
       computeLibraryDependencies(targetLibrary);
@@ -7158,7 +7207,7 @@
    *          libraries are referenced
    */
   void addLibrariesInCycle(Library library, Set<Library> librariesInCycle, Map<Library, List<Library>> dependencyMap) {
-    if (javaSetAdd(librariesInCycle, library)) {
+    if (librariesInCycle.add(library)) {
       List<Library> dependentLibraries = dependencyMap[library];
       if (dependentLibraries != null) {
         for (Library dependentLibrary in dependentLibraries) {
@@ -7178,7 +7227,7 @@
    *          recursion
    */
   void addToDependencyMap(Library library, Map<Library, List<Library>> dependencyMap, Set<Library> visitedLibraries) {
-    if (javaSetAdd(visitedLibraries, library)) {
+    if (visitedLibraries.add(library)) {
       for (Library referencedLibrary in library.importsAndExports) {
         addDependencyToMap(dependencyMap, library, referencedLibrary);
         addToDependencyMap(referencedLibrary, dependencyMap, visitedLibraries);
@@ -7258,7 +7307,7 @@
               }
               directive.element = importElement;
               imports.add(importElement);
-              if (doesCompilationUnitHavePartOfDirective(importedLibrary.getAST(importedSource))) {
+              if (analysisContext.computeKindOf(importedSource) != SourceKind.LIBRARY) {
                 errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
               }
             }
@@ -7278,7 +7327,7 @@
               }
               directive.element = exportElement;
               exports.add(exportElement);
-              if (doesCompilationUnitHavePartOfDirective(exportedLibrary.getAST(exportedSource))) {
+              if (analysisContext.computeKindOf(exportedSource) != SourceKind.LIBRARY) {
                 StringLiteral uriLiteral = exportDirective.uri;
                 errorListener.onError(new AnalysisError.con2(library.librarySource, uriLiteral.offset, uriLiteral.length, CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY, [uriLiteral.toSource()]));
               }
@@ -7391,12 +7440,12 @@
       if (directive is ExportDirective) {
         Source exportSource = resolveSource(librarySource, directive as ExportDirective);
         if (exportSource != null) {
-          javaSetAdd(exportedSources, exportSource);
+          exportedSources.add(exportSource);
         }
       } else if (directive is ImportDirective) {
         Source importSource = resolveSource(librarySource, directive as ImportDirective);
         if (importSource != null) {
-          javaSetAdd(importedSources, importSource);
+          importedSources.add(importSource);
         }
       }
     }
@@ -7508,22 +7557,6 @@
   }
 
   /**
-   * Return `true` if and only if the passed [CompilationUnit] has a part-of directive.
-   *
-   * @param node the [CompilationUnit] to test
-   * @return `true` if and only if the passed [CompilationUnit] has a part-of directive
-   */
-  bool doesCompilationUnitHavePartOfDirective(CompilationUnit node) {
-    NodeList<Directive> directives = node.directives;
-    for (Directive directive in directives) {
-      if (directive is PartOfDirective) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
    * Return an array containing the lexical identifiers associated with the nodes in the given list.
    *
    * @param names the AST nodes representing the identifiers
@@ -7787,32 +7820,12 @@
  */
 class ProxyConditionalAnalysisError {
   /**
-   * The name of the proxy annotation, from dart:core.
-   */
-  static String _PROXY_ANNOTATION_NAME = "proxy";
-
-  /**
    * Return `true` if the given element represents a class that has the proxy annotation.
    *
    * @param element the class being tested
    * @return `true` if the given element represents a class that has the proxy annotation
    */
-  static bool classHasProxyAnnotation(Element element) {
-    if (element is ClassElement) {
-      ClassElement classElement = element as ClassElement;
-      List<ElementAnnotation> annotations = classElement.metadata;
-      for (ElementAnnotation annotation in annotations) {
-        Element elementAnnotation = annotation.element;
-        if (elementAnnotation != null) {
-          LibraryElement lib = elementAnnotation.library;
-          if (lib != null && lib.isDartCore && elementAnnotation.name == _PROXY_ANNOTATION_NAME) {
-            return true;
-          }
-        }
-      }
-    }
-    return false;
-  }
+  static bool classHasProxyAnnotation(Element element) => (element is ClassElement) && (element as ClassElement).isProxy;
 
   /**
    * The enclosing [ClassElement], this is what will determine if the error code should, or
@@ -8030,19 +8043,24 @@
   Object visitCompilationUnit(CompilationUnit node) {
     try {
       overrideManager.enterScope();
-      for (Directive directive in node.directives) {
-        directive.accept(this);
+      NodeList<Directive> directives = node.directives;
+      int directiveCount = directives.length;
+      for (int i = 0; i < directiveCount; i++) {
+        directives[i].accept(this);
       }
-      List<CompilationUnitMember> classes = new List<CompilationUnitMember>();
-      for (CompilationUnitMember declaration in node.declarations) {
-        if (declaration is ClassDeclaration) {
-          classes.add(declaration);
-        } else {
+      NodeList<CompilationUnitMember> declarations = node.declarations;
+      int declarationCount = declarations.length;
+      for (int i = 0; i < declarationCount; i++) {
+        CompilationUnitMember declaration = declarations[i];
+        if (declaration is! ClassDeclaration) {
           declaration.accept(this);
         }
       }
-      for (CompilationUnitMember declaration in classes) {
-        declaration.accept(this);
+      for (int i = 0; i < declarationCount; i++) {
+        CompilationUnitMember declaration = declarations[i];
+        if (declaration is ClassDeclaration) {
+          declaration.accept(this);
+        }
       }
     } finally {
       overrideManager.exitScope();
@@ -9449,18 +9467,20 @@
    * its declaration statement.
    */
   void hideNamesDefinedInBlock(EnclosedScope scope, Block block) {
-    for (Statement statement in block.statements) {
+    NodeList<Statement> statements = block.statements;
+    int statementCount = statements.length;
+    for (int i = 0; i < statementCount; i++) {
+      Statement statement = statements[i];
       if (statement is VariableDeclarationStatement) {
         VariableDeclarationStatement vds = statement as VariableDeclarationStatement;
-        for (VariableDeclaration variableDeclaration in vds.variables.variables) {
-          Element element = variableDeclaration.element;
-          scope.hide(element);
+        NodeList<VariableDeclaration> variables = vds.variables.variables;
+        int variableCount = variables.length;
+        for (int j = 0; j < variableCount; j++) {
+          scope.hide(variables[j].element);
         }
-      }
-      if (statement is FunctionDeclarationStatement) {
+      } else if (statement is FunctionDeclarationStatement) {
         FunctionDeclarationStatement fds = statement as FunctionDeclarationStatement;
-        Element element = fds.functionDeclaration.element;
-        scope.hide(element);
+        scope.hide(fds.functionDeclaration.element);
       }
     }
   }
@@ -10157,6 +10177,15 @@
   Object visitMethodInvocation(MethodInvocation node) {
     SimpleIdentifier methodNameNode = node.methodName;
     Element staticMethodElement = methodNameNode.staticElement;
+    if (staticMethodElement is LocalVariableElement) {
+      LocalVariableElement variable = staticMethodElement as LocalVariableElement;
+      Type2 staticType = variable.type;
+      recordStaticType(methodNameNode, staticType);
+      Type2 propagatedType = _overrideManager.getType(variable);
+      if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+        recordPropagatedType2(methodNameNode, propagatedType);
+      }
+    }
     Type2 staticStaticType = computeStaticReturnType(staticMethodElement);
     recordStaticType(node, staticStaticType);
     Type2 staticPropagatedType = computePropagatedReturnType(staticMethodElement);
@@ -11119,7 +11148,7 @@
    * @param allSubtypes the computed set of subtypes of the passed class element
    */
   void computeAllSubtypes2(ClassElement classElement, Set<ClassElement> visitedClasses, Set<ClassElement> allSubtypes) {
-    if (!javaSetAdd(visitedClasses, classElement)) {
+    if (!visitedClasses.add(classElement)) {
       return;
     }
     Set<ClassElement> subtypes = _subtypeMap[classElement];
@@ -11188,7 +11217,7 @@
     if (libraryElement == null || _visitedLibraries.contains(libraryElement)) {
       return;
     }
-    javaSetAdd(_visitedLibraries, libraryElement);
+    _visitedLibraries.add(libraryElement);
     computeSubtypesInCompilationUnit(libraryElement.definingCompilationUnit);
     List<CompilationUnitElement> parts = libraryElement.parts;
     for (CompilationUnitElement part in parts) {
@@ -11216,7 +11245,7 @@
       subtypes = new Set<ClassElement>();
       _subtypeMap[supertypeElement] = subtypes;
     }
-    javaSetAdd(subtypes, subtypeElement);
+    subtypes.add(subtypeElement);
   }
 }
 
@@ -13165,7 +13194,7 @@
    * A list of the namespaces representing the names that are available in this scope from imported
    * libraries.
    */
-  List<Namespace> _importedNamespaces = new List<Namespace>();
+  List<Namespace> _importedNamespaces;
 
   /**
    * Initialize a newly created scope representing the names imported into the given library.
@@ -13229,8 +13258,11 @@
    */
   void createImportedNamespaces(LibraryElement definingLibrary) {
     NamespaceBuilder builder = new NamespaceBuilder();
-    for (ImportElement element in definingLibrary.imports) {
-      _importedNamespaces.add(builder.createImportNamespace(element));
+    List<ImportElement> imports = definingLibrary.imports;
+    int count = imports.length;
+    _importedNamespaces = new List<Namespace>(count);
+    for (int i = 0; i < count; i++) {
+      _importedNamespaces[i] = builder.createImportNamespace(imports[i]);
     }
   }
 
@@ -13579,7 +13611,7 @@
    * @return the mapping table that was created
    */
   Map<String, Element> createExportMapping(LibraryElement library, Set<LibraryElement> visitedElements) {
-    javaSetAdd(visitedElements, library);
+    visitedElements.add(library);
     try {
       Map<String, Element> definedNames = new Map<String, Element>();
       for (ExportElement element in library.exports) {
@@ -14017,7 +14049,7 @@
           if (keys.contains(value)) {
             invalidKeys.add(key);
           } else {
-            javaSetAdd(keys, value);
+            keys.add(value);
           }
         }
       } else {
@@ -14027,7 +14059,7 @@
           if (keys.contains(value)) {
             invalidKeys.add(key);
           } else {
-            javaSetAdd(keys, value);
+            keys.add(value);
           }
         } else {
           reportEqualKeys = false;
@@ -14166,7 +14198,7 @@
    * @param expression the expression to validate
    */
   void validateInitializerExpression(List<ParameterElement> parameterElements, Expression expression) {
-    EvaluationResultImpl result = expression.accept(new ConstantVisitor_14(this, parameterElements));
+    EvaluationResultImpl result = expression.accept(new ConstantVisitor_13(this, parameterElements));
     reportErrors(result, CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
   }
 
@@ -14212,12 +14244,12 @@
   }
 }
 
-class ConstantVisitor_14 extends ConstantVisitor {
+class ConstantVisitor_13 extends ConstantVisitor {
   final ConstantVerifier ConstantVerifier_this;
 
   List<ParameterElement> parameterElements;
 
-  ConstantVisitor_14(this.ConstantVerifier_this, this.parameterElements) : super();
+  ConstantVisitor_13(this.ConstantVerifier_this, this.parameterElements) : super();
 
   EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) {
     Element element = node.staticElement;
@@ -14286,12 +14318,6 @@
   InheritanceManager _inheritanceManager;
 
   /**
-   * A flag indicating whether we are running in strict mode. In strict mode, error reporting is
-   * based exclusively on the static type information.
-   */
-  bool _strictMode = false;
-
-  /**
    * This is set to `true` iff the visitor is currently visiting children nodes of a
    * [ConstructorDeclaration] and the constructor is 'const'.
    *
@@ -14439,7 +14465,6 @@
     this._isInSystemLibrary = currentLibrary.source.isInSystemLibrary;
     this._typeProvider = typeProvider;
     this._inheritanceManager = inheritanceManager;
-    _strictMode = currentLibrary.context.analysisOptions.strictMode;
     _isEnclosingConstructorConst = false;
     _isInCatchClause = false;
     _isInStaticVariableDeclaration = false;
@@ -14993,7 +15018,7 @@
     checkForInvalidAssignment2(nameNode, initializerNode);
     nameNode.accept(this);
     String name = nameNode.name;
-    javaSetAdd(_namesForReferenceToDeclaredVariableInInitializer, name);
+    _namesForReferenceToDeclaredVariableInInitializer.add(name);
     _isInInstanceVariableInitializer = _isInInstanceVariableDeclaration;
     try {
       if (initializerNode != null) {
@@ -15160,7 +15185,7 @@
         InterfaceType superclassType = _enclosingClass.supertype;
         ClassElement superclassElement = superclassType == null ? null : superclassType.element;
         while (superclassElement != null && !visitedClasses.contains(superclassElement)) {
-          javaSetAdd(visitedClasses, superclassElement);
+          visitedClasses.add(superclassElement);
           LibraryElement superclassLibrary = superclassElement.library;
           List<FieldElement> fieldElts = superclassElement.fields;
           for (FieldElement fieldElt in fieldElts) {
@@ -15650,30 +15675,12 @@
     if (actualStaticType == null || expectedStaticType == null) {
       return false;
     }
-    if (_strictMode) {
-      if (actualStaticType.isAssignableTo(expectedStaticType)) {
-        return false;
-      }
-      _errorReporter.reportError2(errorCode, expression, [
-          actualStaticType.displayName,
-          expectedStaticType.displayName]);
-      return true;
-    }
-    if (actualPropagatedType == null || expectedPropagatedType == null) {
-      if (actualStaticType.isAssignableTo(expectedStaticType)) {
-        return false;
-      }
-      _errorReporter.reportError2(errorCode, expression, [
-          actualStaticType.displayName,
-          expectedStaticType.displayName]);
-      return true;
-    }
-    if (actualStaticType.isAssignableTo(expectedStaticType) || actualStaticType.isAssignableTo(expectedPropagatedType) || actualPropagatedType.isAssignableTo(expectedStaticType) || actualPropagatedType.isAssignableTo(expectedPropagatedType)) {
+    if (actualStaticType.isAssignableTo(expectedStaticType)) {
       return false;
     }
     _errorReporter.reportError2(errorCode, expression, [
-        (actualPropagatedType == null ? actualStaticType : actualPropagatedType).displayName,
-        (expectedPropagatedType == null ? expectedStaticType : expectedPropagatedType).displayName]);
+        actualStaticType.displayName,
+        expectedStaticType.displayName]);
     return true;
   }
 
@@ -16628,26 +16635,11 @@
     }
     if (staticType.isAssignableTo(fieldType)) {
       return false;
-    } else if (_strictMode) {
-      if (_isEnclosingConstructorConst) {
-        _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
-      } else {
-        _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
-      }
-      return true;
-    }
-    Type2 propagatedType = expression.propagatedType;
-    if (propagatedType != null && propagatedType.isAssignableTo(fieldType)) {
-      return false;
     }
     if (_isEnclosingConstructorConst) {
-      _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [
-          (propagatedType == null ? staticType : propagatedType).displayName,
-          fieldType.displayName]);
+      _errorReporter.reportError2(CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
     } else {
-      _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [
-          (propagatedType == null ? staticType : propagatedType).displayName,
-          fieldType.displayName]);
+      _errorReporter.reportError2(StaticWarningCode.FIELD_INITIALIZER_NOT_ASSIGNABLE, expression, [staticType.displayName, fieldType.displayName]);
     }
     return true;
   }
@@ -17023,18 +17015,9 @@
     Type2 leftType = (leftElement == null) ? getStaticType(lhs) : leftElement.type;
     Type2 staticRightType = getStaticType(rhs);
     bool isStaticAssignable = staticRightType.isAssignableTo(leftType);
-    Type2 propagatedRightType = rhs.propagatedType;
-    if (_strictMode || propagatedRightType == null) {
-      if (!isStaticAssignable) {
-        _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
-        return true;
-      }
-    } else {
-      bool isPropagatedAssignable = propagatedRightType.isAssignableTo(leftType);
-      if (!isStaticAssignable && !isPropagatedAssignable) {
-        _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
-        return true;
-      }
+    if (!isStaticAssignable) {
+      _errorReporter.reportError2(StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [staticRightType.displayName, leftType.displayName]);
+      return true;
     }
     return false;
   }
@@ -17434,11 +17417,11 @@
       if (methodName == ElementResolver.NO_SUCH_METHOD_METHOD_NAME) {
         return false;
       }
-      javaSetAdd(methodsInEnclosingClass, methodName);
+      methodsInEnclosingClass.add(methodName);
     }
     Set<String> accessorsInEnclosingClass = new Set<String>();
     for (PropertyAccessorElement accessor in accessors) {
-      javaSetAdd(accessorsInEnclosingClass, accessor.name);
+      accessorsInEnclosingClass.add(accessor.name);
     }
     Set<ExecutableElement> missingOverrides = new Set<ExecutableElement>();
     MemberMap membersInheritedFromInterfaces = _inheritanceManager.getMapOfMembersInheritedFromInterfaces(_enclosingClass);
@@ -17459,11 +17442,11 @@
       }
       if (executableElt is MethodElement) {
         if (!methodsInEnclosingClass.contains(memberName) && !memberHasConcreteMethodImplementationInSuperclassChain(_enclosingClass, memberName, new List<ClassElement>())) {
-          javaSetAdd(missingOverrides, executableElt);
+          missingOverrides.add(executableElt);
         }
       } else if (executableElt is PropertyAccessorElement) {
         if (!accessorsInEnclosingClass.contains(memberName) && !memberHasConcreteAccessorImplementationInSuperclassChain(_enclosingClass, memberName, new List<ClassElement>())) {
-          javaSetAdd(missingOverrides, executableElt);
+          missingOverrides.add(executableElt);
         }
       }
     }
@@ -17931,27 +17914,14 @@
       return true;
     }
     bool isStaticAssignable = staticReturnType.isAssignableTo(expectedReturnType);
-    Type2 propagatedReturnType = returnExpression.propagatedType;
-    if (_strictMode || propagatedReturnType == null) {
-      if (isStaticAssignable) {
-        return false;
-      }
-      _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
-          staticReturnType.displayName,
-          expectedReturnType.displayName,
-          _enclosingFunction.displayName]);
-      return true;
-    } else {
-      bool isPropagatedAssignable = propagatedReturnType.isAssignableTo(expectedReturnType);
-      if (isStaticAssignable || isPropagatedAssignable) {
-        return false;
-      }
-      _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
-          staticReturnType.displayName,
-          expectedReturnType.displayName,
-          _enclosingFunction.displayName]);
-      return true;
+    if (isStaticAssignable) {
+      return false;
     }
+    _errorReporter.reportError2(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, returnExpression, [
+        staticReturnType.displayName,
+        expectedReturnType.displayName,
+        _enclosingFunction.displayName]);
+    return true;
   }
 
   /**
@@ -18394,7 +18364,7 @@
       if (constructors.contains(current)) {
         return identical(current, element);
       }
-      javaSetAdd(constructors, current);
+      constructors.add(current);
       current = current.redirectedConstructor;
       if (current is ConstructorMember) {
         current = (current as ConstructorMember).baseElement;
@@ -18431,8 +18401,8 @@
           break;
         }
       }
-      current.accept(new GeneralizingElementVisitor_15(target, toCheck));
-      javaSetAdd(checked, current);
+      current.accept(new GeneralizingElementVisitor_14(target, toCheck));
+      checked.add(current);
     }
   }
 
@@ -18641,12 +18611,12 @@
   INIT_STATE(String name, int ordinal) : super(name, ordinal);
 }
 
-class GeneralizingElementVisitor_15 extends GeneralizingElementVisitor<Object> {
+class GeneralizingElementVisitor_14 extends GeneralizingElementVisitor<Object> {
   Element target;
 
   List<Element> toCheck;
 
-  GeneralizingElementVisitor_15(this.target, this.toCheck) : super();
+  GeneralizingElementVisitor_14(this.target, this.toCheck) : super();
 
   bool _inClass = false;
 
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index ff0a29a..413cf3b 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -526,6 +526,24 @@
 }
 
 /**
+ * Synthetic `StringToken` represent a token whose value is independent of it's type.
+ *
+ * @coverage dart.engine.parser
+ */
+class SyntheticStringToken extends StringToken {
+  /**
+   * Initialize a newly created token to represent a token of the given type with the given value.
+   *
+   * @param type the type of the token
+   * @param value the lexeme represented by this token
+   * @param offset the offset from the beginning of the file to the first character in the token
+   */
+  SyntheticStringToken(TokenType type, String value, int offset) : super(type, value, offset);
+
+  bool get isSynthetic => true;
+}
+
+/**
  * Instances of the class `IncrementalScanner` implement a scanner that scans a subset of a
  * string and inserts the resulting tokens into the middle of an existing token stream.
  *
@@ -543,16 +561,23 @@
   final TokenMap tokenMap = new TokenMap();
 
   /**
-   * The first token in the range of tokens that are different from the tokens in the original token
-   * stream.
+   * The token in the new token stream immediately to the left of the range of tokens that were
+   * inserted, or the token immediately to the left of the modified region if there were no new
+   * tokens.
    */
-  Token _firstToken;
+  Token leftToken;
 
   /**
-   * The last token in the range of tokens that are different from the tokens in the original token
-   * stream.
+   * The token in the new token stream immediately to the right of the range of tokens that were
+   * inserted, or the token immediately to the right of the modified region if there were no new
+   * tokens.
    */
-  Token lastToken;
+  Token rightToken;
+
+  /**
+   * A flag indicating whether there were any tokens changed as a result of the modification.
+   */
+  bool _hasNonWhitespaceChange2 = false;
 
   /**
    * Initialize a newly created scanner.
@@ -566,13 +591,12 @@
   }
 
   /**
-   * Return the first token in the range of tokens that are different from the tokens in the
-   * original token stream or `null` if the new tokens are the same as the original tokens
-   * except for offset.
+   * Return `true` if there were any tokens either added or removed (or both) as a result of
+   * the modification.
    *
-   * @return the first token in the range of new tokens
+   * @return `true` if there were any tokens changed as a result of the modification
    */
-  Token get firstToken => _firstToken;
+  bool hasNonWhitespaceChange() => _hasNonWhitespaceChange2;
 
   /**
    * Given the stream of tokens scanned from the original source, the modified source (the result of
@@ -590,39 +614,64 @@
     while (originalStream.type != TokenType.EOF && originalStream.end < index) {
       originalStream = copyAndAdvance(originalStream, 0);
     }
-    Token lastCopied = tail;
-    int modifiedEnd = index + insertedLength - 1;
-    if (originalStream.offset < index) {
-      modifiedEnd += originalStream.end - index - removedLength;
-    }
-    _reader.offset = Math.min(originalStream.offset, index) - 1;
-    int next = _reader.advance();
-    while (next != -1 && _reader.offset <= modifiedEnd) {
-      next = bigSwitch(next);
-    }
-    _firstToken = lastCopied.next;
-    lastToken = tail;
-    if (_firstToken == null || identical(_firstToken.type, TokenType.EOF)) {
-      _firstToken = null;
-      lastToken = null;
-    } else if (originalStream.end == index && _firstToken.end == index) {
-      tokenMap.put(originalStream, _firstToken);
-      if (identical(lastToken, _firstToken)) {
-        lastToken = lastToken.next;
-      }
-      _firstToken = _firstToken.next;
-    }
-    int removedEnd = index + removedLength - 1 + Math.max(0, tail.end - index - insertedLength);
-    while (originalStream.offset <= removedEnd) {
+    Token oldFirst = originalStream;
+    Token oldLeftToken = originalStream.previous;
+    leftToken = tail;
+    int removedEnd = index + (removedLength == 0 ? 0 : removedLength - 1);
+    while (originalStream.type != TokenType.EOF && originalStream.offset <= removedEnd) {
       originalStream = originalStream.next;
     }
-    int delta = insertedLength - removedLength;
-    while (originalStream.type != TokenType.EOF) {
-      originalStream = copyAndAdvance(originalStream, delta);
+    Token oldLast;
+    Token oldRightToken;
+    if (originalStream.type != TokenType.EOF && removedEnd + 1 == originalStream.offset) {
+      oldLast = originalStream;
+      originalStream = originalStream.next;
+      oldRightToken = originalStream;
+    } else {
+      oldLast = originalStream.previous;
+      oldRightToken = originalStream;
     }
-    Token eof = copyAndAdvance(originalStream, delta);
-    eof.setNextWithoutSettingPrevious(eof);
-    return super.firstToken;
+    int delta = insertedLength - removedLength;
+    int scanStart = Math.min(oldFirst.offset, index);
+    int oldEnd = oldLast.end + delta - 1;
+    int newEnd = index + insertedLength - 1;
+    int scanEnd = Math.max(newEnd, oldEnd);
+    _reader.offset = scanStart - 1;
+    int next = _reader.advance();
+    while (next != -1 && _reader.offset <= scanEnd) {
+      next = bigSwitch(next);
+    }
+    if (identical(originalStream.type, TokenType.EOF)) {
+      copyAndAdvance(originalStream, delta);
+      rightToken = tail;
+      rightToken.setNextWithoutSettingPrevious(rightToken);
+    } else {
+      originalStream = copyAndAdvance(originalStream, delta);
+      rightToken = tail;
+      while (originalStream.type != TokenType.EOF) {
+        originalStream = copyAndAdvance(originalStream, delta);
+      }
+      Token eof = copyAndAdvance(originalStream, delta);
+      eof.setNextWithoutSettingPrevious(eof);
+    }
+    Token newFirst = leftToken.next;
+    while (newFirst != rightToken && oldFirst != oldRightToken && newFirst.type != TokenType.EOF && equals3(oldFirst, newFirst)) {
+      tokenMap.put(oldFirst, newFirst);
+      oldLeftToken = oldFirst;
+      oldFirst = oldFirst.next;
+      leftToken = newFirst;
+      newFirst = newFirst.next;
+    }
+    Token newLast = rightToken.previous;
+    while (newLast != leftToken && oldLast != oldLeftToken && newLast.type != TokenType.EOF && equals3(oldLast, newLast)) {
+      tokenMap.put(oldLast, newLast);
+      oldRightToken = oldLast;
+      oldLast = oldLast.previous;
+      rightToken = newLast;
+      newLast = newLast.previous;
+    }
+    _hasNonWhitespaceChange2 = leftToken.next != rightToken || oldLeftToken.next != oldRightToken;
+    return firstToken;
   }
 
   Token copyAndAdvance(Token originalToken, int delta) {
@@ -639,6 +688,16 @@
     }
     return originalToken.next;
   }
+
+  /**
+   * Return `true` if the two tokens are equal to each other. For the purposes of the
+   * incremental scanner, two tokens are equal if they have the same type and lexeme.
+   *
+   * @param oldToken the token from the old stream that is being compared
+   * @param newToken the token from the new stream that is being compared
+   * @return `true` if the two tokens are equal to each other
+   */
+  bool equals3(Token oldToken, Token newToken) => identical(oldToken.type, newToken.type) && oldToken.length == newToken.length && oldToken.lexeme == newToken.lexeme;
 }
 
 /**
@@ -1823,8 +1882,7 @@
 
   /**
    * Return `true` if this token is a synthetic token. A synthetic token is a token that was
-   * introduced by the parser in order to recover from an error in the code. Synthetic tokens always
-   * have a length of zero (`0`).
+   * introduced by the parser in order to recover from an error in the code.
    *
    * @return `true` if this token is a synthetic token
    */
@@ -2065,17 +2123,17 @@
   /**
    * A value used to indicate that the token type is a bitwise-and operator.
    */
-  static final TokenClass BITWISE_AND_OPERATOR = new TokenClass.con2('BITWISE_AND_OPERATOR', 3, 8);
+  static final TokenClass BITWISE_AND_OPERATOR = new TokenClass.con2('BITWISE_AND_OPERATOR', 3, 10);
 
   /**
    * A value used to indicate that the token type is a bitwise-or operator.
    */
-  static final TokenClass BITWISE_OR_OPERATOR = new TokenClass.con2('BITWISE_OR_OPERATOR', 4, 6);
+  static final TokenClass BITWISE_OR_OPERATOR = new TokenClass.con2('BITWISE_OR_OPERATOR', 4, 8);
 
   /**
    * A value used to indicate that the token type is a bitwise-xor operator.
    */
-  static final TokenClass BITWISE_XOR_OPERATOR = new TokenClass.con2('BITWISE_XOR_OPERATOR', 5, 7);
+  static final TokenClass BITWISE_XOR_OPERATOR = new TokenClass.con2('BITWISE_XOR_OPERATOR', 5, 9);
 
   /**
    * A value used to indicate that the token type is a cascade operator.
@@ -2090,7 +2148,7 @@
   /**
    * A value used to indicate that the token type is an equality operator.
    */
-  static final TokenClass EQUALITY_OPERATOR = new TokenClass.con2('EQUALITY_OPERATOR', 8, 9);
+  static final TokenClass EQUALITY_OPERATOR = new TokenClass.con2('EQUALITY_OPERATOR', 8, 6);
 
   /**
    * A value used to indicate that the token type is a logical-and operator.
@@ -2110,7 +2168,7 @@
   /**
    * A value used to indicate that the token type is a relational operator.
    */
-  static final TokenClass RELATIONAL_OPERATOR = new TokenClass.con2('RELATIONAL_OPERATOR', 12, 10);
+  static final TokenClass RELATIONAL_OPERATOR = new TokenClass.con2('RELATIONAL_OPERATOR', 12, 7);
 
   /**
    * A value used to indicate that the token type is a shift operator.
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index c4985f0..e06e06b 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -62,11 +62,6 @@
   static String _CHROMIUM_DIRECTORY_NAME = "chromium";
 
   /**
-   * The name of the environment variable whose value is the path to the default Dart SDK directory.
-   */
-  static String _DART_SDK_ENVIRONMENT_VARIABLE_NAME = "DART_SDK";
-
-  /**
    * The name of the file containing the Dartium executable on Linux.
    */
   static String _DARTIUM_EXECUTABLE_NAME_LINUX = "chrome";
@@ -154,36 +149,16 @@
   }
 
   /**
-   * Return the default Dart SDK, or `null` if the directory containing the default SDK cannot
-   * be determined (or does not exist).
-   *
-   * Added in order to test AnalysisContextImpl2.
-   *
-   * @return the default Dart SDK
-   */
-  static DirectoryBasedDartSdk get defaultSdk2 {
-    JavaFile sdkDirectory = defaultSdkDirectory;
-    if (sdkDirectory == null) {
-      return null;
-    }
-    return new DirectoryBasedDartSdk.con1(sdkDirectory, true);
-  }
-
-  /**
    * Return the default directory for the Dart SDK, or `null` if the directory cannot be
    * determined (or does not exist). The default directory is provided by a [System] property
-   * named `com.google.dart.sdk`, or, if the property is not defined, an environment variable
-   * named `DART_SDK`.
+   * named `com.google.dart.sdk`.
    *
    * @return the default directory for the Dart SDK
    */
   static JavaFile get defaultSdkDirectory {
     String sdkProperty = JavaSystemIO.getProperty(_DEFAULT_DIRECTORY_PROPERTY_NAME);
     if (sdkProperty == null) {
-      sdkProperty = JavaSystemIO.getenv(_DART_SDK_ENVIRONMENT_VARIABLE_NAME);
-      if (sdkProperty == null) {
-        return null;
-      }
+      return null;
     }
     JavaFile sdkDirectory = new JavaFile(sdkProperty);
     if (!sdkDirectory.exists()) {
@@ -471,14 +446,13 @@
    * @return the library map read from the given source
    */
   LibraryMap readFrom(JavaFile librariesFile, String libraryFileContents) {
-    List<bool> foundError = [false];
-    AnalysisErrorListener errorListener = new AnalysisErrorListener_11(foundError);
+    BooleanErrorListener errorListener = new BooleanErrorListener();
     Source source = new FileBasedSource.con2(null, librariesFile, UriKind.FILE_URI);
     Scanner scanner = new Scanner(source, new CharSequenceReader(new CharSequence(libraryFileContents)), errorListener);
     Parser parser = new Parser(source, errorListener);
     CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
     SdkLibrariesReader_LibraryBuilder libraryBuilder = new SdkLibrariesReader_LibraryBuilder();
-    if (!foundError[0]) {
+    if (!errorListener.errorReported) {
       unit.accept(libraryBuilder);
     }
     return libraryBuilder.librariesMap;
@@ -564,16 +538,4 @@
     }
     return null;
   }
-}
-
-class AnalysisErrorListener_11 implements AnalysisErrorListener {
-  List<bool> foundError;
-
-  AnalysisErrorListener_11(this.foundError);
-
-  void onError(AnalysisError error) {
-    if (error != null && error.errorCode.type != ErrorType.TODO) {
-      foundError[0] = true;
-    }
-  }
 }
\ No newline at end of file
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 7c3206e..f817d7b 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -8,6 +8,50 @@
 import 'engine.dart' show AnalysisContext;
 
 /**
+ * Instances of interface `LocalSourcePredicate` are used to determine if the given
+ * [Source] is "local" in some sense, so can be updated.
+ *
+ * @coverage dart.engine.source
+ */
+abstract class LocalSourcePredicate {
+  /**
+   * Instance of [LocalSourcePredicate] that always returns `false`.
+   */
+  static final LocalSourcePredicate _FALSE = new LocalSourcePredicate_15();
+
+  /**
+   * Instance of [LocalSourcePredicate] that always returns `true`.
+   */
+  static final LocalSourcePredicate _TRUE = new LocalSourcePredicate_16();
+
+  /**
+   * Instance of [LocalSourcePredicate] that returns `true` for all [Source]s
+   * except of SDK.
+   */
+  static final LocalSourcePredicate _NOT_SDK = new LocalSourcePredicate_17();
+
+  /**
+   * Determines if the given [Source] is local.
+   *
+   * @param source the [Source] to analyze
+   * @return `true` if the given [Source] is local
+   */
+  bool isLocal(Source source);
+}
+
+class LocalSourcePredicate_15 implements LocalSourcePredicate {
+  bool isLocal(Source source) => false;
+}
+
+class LocalSourcePredicate_16 implements LocalSourcePredicate {
+  bool isLocal(Source source) => true;
+}
+
+class LocalSourcePredicate_17 implements LocalSourcePredicate {
+  bool isLocal(Source source) => source.uriKind != UriKind.DART_URI;
+}
+
+/**
  * Instances of the class `SourceFactory` resolve possibly relative URI's against an existing
  * [Source].
  *
@@ -20,14 +64,19 @@
   AnalysisContext context;
 
   /**
+   * A cache of content used to override the default content of a source.
+   */
+  ContentCache contentCache;
+
+  /**
    * The resolvers used to resolve absolute URI's.
    */
   List<UriResolver> _resolvers;
 
   /**
-   * A cache of content used to override the default content of a source.
+   * The predicate to determine is [Source] is local.
    */
-  ContentCache contentCache;
+  LocalSourcePredicate _localSourcePredicate;
 
   /**
    * Initialize a newly created source factory.
@@ -38,6 +87,7 @@
   SourceFactory.con1(ContentCache contentCache, List<UriResolver> resolvers) {
     this.contentCache = contentCache;
     this._resolvers = resolvers;
+    this._localSourcePredicate = LocalSourcePredicate._NOT_SDK;
   }
 
   /**
@@ -113,6 +163,14 @@
   }
 
   /**
+   * Determines if the given [Source] is local.
+   *
+   * @param source the [Source] to analyze
+   * @return `true` if the given [Source] is local
+   */
+  bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
+
+  /**
    * Return a source object representing the URI that results from resolving the given (possibly
    * relative) contained URI against the URI associated with an existing source object, or
    * `null` if either the contained URI is invalid or if it cannot be resolved against the
@@ -161,6 +219,15 @@
   String setContents(Source source, String contents) => contentCache.setContents(source, contents);
 
   /**
+   * Sets the [LocalSourcePredicate].
+   *
+   * @param localSourcePredicate the predicate to determine is [Source] is local
+   */
+  void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
+    this._localSourcePredicate = localSourcePredicate;
+  }
+
+  /**
    * Return the contents of the given source, or `null` if this factory does not override the
    * contents of the source.
    *
@@ -501,6 +568,11 @@
  */
 class SourceRange {
   /**
+   * An empty [SourceRange] with offset `0` and length `0`.
+   */
+  static SourceRange EMPTY = new SourceRange(0, 0);
+
+  /**
    * The 0-based index of the first character of the source code for this element, relative to the
    * source buffer in which this element is contained.
    */
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index e2ea6be..60bc557 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -10,6 +10,50 @@
 export 'source.dart';
 
 /**
+ * Instances of interface `LocalSourcePredicate` are used to determine if the given
+ * [Source] is "local" in some sense, so can be updated.
+ *
+ * @coverage dart.engine.source
+ */
+abstract class LocalSourcePredicate {
+  /**
+   * Instance of [LocalSourcePredicate] that always returns `false`.
+   */
+  static final LocalSourcePredicate _FALSE = new LocalSourcePredicate_15();
+
+  /**
+   * Instance of [LocalSourcePredicate] that always returns `true`.
+   */
+  static final LocalSourcePredicate _TRUE = new LocalSourcePredicate_16();
+
+  /**
+   * Instance of [LocalSourcePredicate] that returns `true` for all [Source]s
+   * except of SDK.
+   */
+  static final LocalSourcePredicate _NOT_SDK = new LocalSourcePredicate_17();
+
+  /**
+   * Determines if the given [Source] is local.
+   *
+   * @param source the [Source] to analyze
+   * @return `true` if the given [Source] is local
+   */
+  bool isLocal(Source source);
+}
+
+class LocalSourcePredicate_15 implements LocalSourcePredicate {
+  bool isLocal(Source source) => false;
+}
+
+class LocalSourcePredicate_16 implements LocalSourcePredicate {
+  bool isLocal(Source source) => true;
+}
+
+class LocalSourcePredicate_17 implements LocalSourcePredicate {
+  bool isLocal(Source source) => source.uriKind != UriKind.DART_URI;
+}
+
+/**
  * Instances of the class `FileBasedSource` implement a source that represents a file.
  *
  * @coverage dart.engine.source
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index ccb5b6d..f54675a 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -355,6 +355,10 @@
   /// A counter for spaces that should be emitted preceding the next token.
   int leadingSpaces = 0;
 
+  /// A flag to specify whether line-leading spaces should be preserved (and
+  /// addded to the indent level).
+  bool allowLineLeadingSpaces;
+
   /// Used for matching EOL comments
   final twoSlashes = new RegExp(r'//[^/]');
 
@@ -393,7 +397,7 @@
 
   visitArgumentList(ArgumentList node) {
     token(node.leftParenthesis);
-    visitNodes(node.arguments, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.arguments);
     token(node.rightParenthesis);
   }
 
@@ -462,7 +466,7 @@
 
   visitCatchClause(CatchClause node) {
 
-    token(node.onKeyword, precededBy: space, followedBy: space);
+    token(node.onKeyword, followedBy: space);
     visit(node.exceptionType);
 
     if (node.catchKeyword != null) {
@@ -595,9 +599,10 @@
     space();
     for (var i = 0; i < node.initializers.length; i++) {
       if (i > 0) {
-        comma();
+        // preceding comma
+        token(node.initializers[i].beginToken.previous);
         newlines();
-        space(2);
+        space(n: 2, allowLineLeading: true);
       }
       node.initializers[i].accept(this);
     }
@@ -606,7 +611,7 @@
 
   visitConstructorRedirects(ConstructorDeclaration node) {
     token(node.separator /* = */, precededBy: space, followedBy: space);
-    visitNodes(node.initializers, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.initializers);
     visit(node.redirectedConstructor);
   }
 
@@ -764,15 +769,24 @@
     if (node.initialization != null) {
       visit(node.initialization);
     } else {
-      visit(node.variables);
+      if (node.variables == null) {
+        space();
+      } else {
+        visit(node.variables);
+      }
     }
     token(node.leftSeparator);
     space();
     visit(node.condition);
     token(node.rightSeparator);
-    visitNodes(node.updaters, precededBy: space, separatedBy: space);
+    if (node.updaters != null) {
+      space();
+      visitCommaSeparatedNodes(node.updaters);
+    }
     token(node.rightParenthesis);
-    space();
+    if (node.body is! EmptyStatement) {
+      space();
+    }
     visit(node.body);
   }
 
@@ -817,7 +831,7 @@
   visitHideCombinator(HideCombinator node) {
     token(node.keyword);
     space();
-    visitNodes(node.hiddenNames, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.hiddenNames);
   }
 
   visitIfStatement(IfStatement node) {
@@ -842,7 +856,7 @@
   visitImplementsClause(ImplementsClause node) {
     token(node.keyword);
     space();
-    visitNodes(node.interfaces, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.interfaces);
   }
 
   visitImportDirective(ImportDirective node) {
@@ -926,8 +940,10 @@
     modifier(node.constKeyword);
     visit(node.typeArguments);
     token(node.leftBracket);
-    visitNodes(node.elements, separatedBy: commaSeperator);
+    indent();
+    visitCommaSeparatedNodes(node.elements);
     optionalTrailingComma(node.rightBracket);
+    unindent();
     token(node.rightBracket);
   }
 
@@ -935,8 +951,10 @@
     modifier(node.constKeyword);
     visitNode(node.typeArguments, followedBy: space);
     token(node.leftBracket);
-    visitNodes(node.entries, separatedBy: commaSeperator);
+    indent();
+    visitCommaSeparatedNodes(node.entries);
     optionalTrailingComma(node.rightBracket);
+    unindent();
     token(node.rightBracket);
   }
 
@@ -1068,7 +1086,7 @@
   visitShowCombinator(ShowCombinator node) {
     token(node.keyword);
     space();
-    visitNodes(node.shownNames, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.shownNames);
   }
 
   visitSimpleFormalParameter(SimpleFormalParameter node) {
@@ -1165,7 +1183,7 @@
 
   visitTypeArgumentList(TypeArgumentList node) {
     token(node.leftBracket);
-    visitNodes(node.arguments, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.arguments);
     token(node.rightBracket);
   }
 
@@ -1182,7 +1200,7 @@
 
   visitTypeParameterList(TypeParameterList node) {
     token(node.leftBracket);
-    visitNodes(node.typeParameters, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.typeParameters);
     token(node.rightBracket);
   }
 
@@ -1199,7 +1217,7 @@
   visitVariableDeclarationList(VariableDeclarationList node) {
     modifier(node.keyword);
     visitNode(node.type, followedBy: space);
-    visitNodes(node.variables, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.variables);
   }
 
   visitVariableDeclarationStatement(VariableDeclarationStatement node) {
@@ -1213,14 +1231,16 @@
     token(node.leftParenthesis);
     visit(node.condition);
     token(node.rightParenthesis);
-    space();
+    if (node.body is! EmptyStatement) {
+      space();
+    }
     visit(node.body);
   }
 
   visitWithClause(WithClause node) {
     token(node.withKeyword);
     space();
-    visitNodes(node.mixinTypes, separatedBy: commaSeperator);
+    visitCommaSeparatedNodes(node.mixinTypes);
   }
 
   /// Safely visit the given [node].
@@ -1262,6 +1282,26 @@
     }
   }
 
+  /// Visit a comma-separated list of [nodes] if not null.
+  visitCommaSeparatedNodes(NodeList<ASTNode> nodes) {
+    if (nodes != null) {
+      var size = nodes.length;
+      if (size > 0) {
+        var node;
+        for (var i = 0; i < size; i++) {
+          node = nodes[i];
+          if (i > 0) {
+            var comma = node.beginToken.previous;
+            token(comma);
+            space();
+          }
+          node.accept(this);
+        }
+      }
+    }
+  }
+
+
   /// Visit a [node], and if not null, optionally preceded or followed by the
   /// specified functions.
   visitNode(ASTNode node, {precededBy(): null, followedBy(): null}) {
@@ -1292,7 +1332,7 @@
   /// Optionally emit a trailing comma.
   optionalTrailingComma(Token rightBracket) {
     if (rightBracket.previous.lexeme == ',') {
-      comma();
+      token(rightBracket.previous);
     }
   }
 
@@ -1319,7 +1359,10 @@
 
   emitSpaces() {
     while (leadingSpaces > 0) {
-      writer.print(' ');
+      if (!writer.currentLine.isWhitespace() || allowLineLeadingSpaces) {
+        writer.print(' ');
+      }
+      allowLineLeadingSpaces = false;
       leadingSpaces--;
     }
   }
@@ -1338,20 +1381,13 @@
     }
   }
 
-  commaSeperator() {
-    comma();
-    space();
-  }
-
-  comma() {
-    writer.print(',');
-  }
-
-
-  /// Emit a non-breakable space.
-  space([n = 1]) {
+  /// Emit a non-breakable space. If [allowLineLeading] is specified, spaces
+  /// will be preserved at the start of a line (in addition to the
+  /// indent-level), otherwise line-leading spaces will be ignored.
+  space({n: 1, allowLineLeading: false}) {
     //TODO(pquitslund): replace with a proper space token
     leadingSpaces+=n;
+    allowLineLeadingSpaces = allowLineLeading;
   }
 
   /// Emit a breakable space
@@ -1413,7 +1449,8 @@
     var lines = max(min, countNewlinesBetween(previousToken, currentToken));
     writer.newlines(lines);
 
-    previousToken = currentToken.previous;
+    previousToken =
+        currentToken.previous != null ? currentToken.previous : token.previous;
 
     while (comment != null) {
 
@@ -1424,8 +1461,11 @@
       if (newlines > 0) {
         writer.newlines(newlines);
         lines += newlines;
-      } else if (!isEOF(token)) {
-        append(' ');
+      } else {
+        var spaces = countSpacesBetween(comment, nextToken);
+        if (spaces > 0) {
+          space();
+        }
       }
 
       previousToken = comment;
@@ -1436,7 +1476,6 @@
     return lines;
   }
 
-
   ensureTrailingNewline() {
     if (writer.lastToken is! NewlineToken) {
       writer.newline();
@@ -1451,11 +1490,11 @@
 
   /// Emit this [comment], inserting leading whitespace if appropriate.
   emitComment(Token comment, Token previousToken) {
-    if (!writer.currentLine.isWhitespace() && !isBlock(comment)) {
+    if (!writer.currentLine.isWhitespace() && previousToken != null) {
       var ws = countSpacesBetween(previousToken, comment);
       // Preserve one space but no more
-      if (ws > 0) {
-        append(' ');
+      if (ws > 0 && leadingSpaces == 0) {
+        space();
       }
     }
 
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 51639e1..fc47861 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.10.2
+version: 0.10.3
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/generated/ast_test.dart
index 5dc1b2d..ab7d96c 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/generated/ast_test.dart
@@ -1011,7 +1011,7 @@
         "}"]);
     CompilationUnit unit = ParserTestCase.parseCompilationUnit(source, []);
     List<ASTNode> nodes = new List<ASTNode>();
-    BreadthFirstVisitor<Object> visitor = new BreadthFirstVisitor_19(nodes);
+    BreadthFirstVisitor<Object> visitor = new BreadthFirstVisitor_20(nodes);
     visitor.visitAllNodes(unit);
     EngineTestCase.assertSize(59, nodes);
     EngineTestCase.assertInstanceOf(CompilationUnit, nodes[0]);
@@ -1031,10 +1031,10 @@
   }
 }
 
-class BreadthFirstVisitor_19 extends BreadthFirstVisitor<Object> {
+class BreadthFirstVisitor_20 extends BreadthFirstVisitor<Object> {
   List<ASTNode> nodes;
 
-  BreadthFirstVisitor_19(this.nodes) : super();
+  BreadthFirstVisitor_20(this.nodes) : super();
 
   Object visitNode(ASTNode node) {
     nodes.add(node);
diff --git a/pkg/analyzer/test/generated/element_test.dart b/pkg/analyzer/test/generated/element_test.dart
index 496ce5e..cfa5913 100644
--- a/pkg/analyzer/test/generated/element_test.dart
+++ b/pkg/analyzer/test/generated/element_test.dart
@@ -1021,6 +1021,20 @@
     JUnitTestCase.assertFalse(0 == typeA.hashCode);
   }
 
+  void test_isAssignableTo_typeVariables() {
+    ClassElement classA = ElementFactory.classElement2("A", ["E"]);
+    ClassElement classB = ElementFactory.classElement2("B", ["F", "G"]);
+    InterfaceTypeImpl typeAF = new InterfaceTypeImpl.con1(classA);
+    typeAF.typeArguments = <Type2> [classB.typeParameters[0].type];
+    InterfaceTypeImpl typeAG = new InterfaceTypeImpl.con1(classA);
+    typeAG.typeArguments = <Type2> [classB.typeParameters[1].type];
+    JUnitTestCase.assertFalse(typeAG.isAssignableTo(typeAF));
+  }
+
+  void test_isAssignableTo_void() {
+    JUnitTestCase.assertFalse(VoidTypeImpl.instance.isAssignableTo(_typeProvider.intType));
+  }
+
   void test_isDirectSupertypeOf_extends() {
     ClassElement classA = ElementFactory.classElement2("A", []);
     ClassElement classB = ElementFactory.classElement("B", classA.type, []);
@@ -1737,6 +1751,14 @@
         final __test = new InterfaceTypeImplTest();
         runJUnitTest(__test, __test.test_hashCode);
       });
+      _ut.test('test_isAssignableTo_typeVariables', () {
+        final __test = new InterfaceTypeImplTest();
+        runJUnitTest(__test, __test.test_isAssignableTo_typeVariables);
+      });
+      _ut.test('test_isAssignableTo_void', () {
+        final __test = new InterfaceTypeImplTest();
+        runJUnitTest(__test, __test.test_isAssignableTo_void);
+      });
       _ut.test('test_isDirectSupertypeOf_extends', () {
         final __test = new InterfaceTypeImplTest();
         runJUnitTest(__test, __test.test_isDirectSupertypeOf_extends);
@@ -2791,7 +2813,7 @@
 
   void test_isSubtypeOf_baseCase_classFunction() {
     ClassElementImpl functionElement = ElementFactory.classElement2("Function", []);
-    InterfaceTypeImpl functionType = new InterfaceTypeImpl_24(functionElement);
+    InterfaceTypeImpl functionType = new InterfaceTypeImpl_25(functionElement);
     FunctionType f = ElementFactory.functionElement("f").type;
     JUnitTestCase.assertTrue(f.isSubtypeOf(functionType));
   }
@@ -3290,8 +3312,8 @@
   }
 }
 
-class InterfaceTypeImpl_24 extends InterfaceTypeImpl {
-  InterfaceTypeImpl_24(ClassElement arg0) : super.con1(arg0);
+class InterfaceTypeImpl_25 extends InterfaceTypeImpl {
+  InterfaceTypeImpl_25(ClassElement arg0) : super.con1(arg0);
 
   bool get isDartCoreFunction => true;
 }
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 8ea3dae..38a08d5 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4379,7 +4379,7 @@
    * @throws Exception if the method could not be invoked or throws an exception
    */
   String computeStringValue(String lexeme, bool first, bool last) {
-    AnalysisErrorListener listener = new AnalysisErrorListener_25();
+    AnalysisErrorListener listener = new AnalysisErrorListener_26();
     Parser parser = new Parser(null, listener);
     return invokeParserMethodImpl(parser, "computeStringValue", <Object> [lexeme, first, last], null) as String;
   }
@@ -6633,12 +6633,27 @@
   }
 }
 
-class AnalysisErrorListener_25 implements AnalysisErrorListener {
+class AnalysisErrorListener_26 implements AnalysisErrorListener {
   void onError(AnalysisError event) {
     JUnitTestCase.fail("Unexpected compilation error: ${event.message} (${event.offset}, ${event.length})");
   }
 }
 
+class NonErrorParserTest extends ParserTestCase {
+  void test_constFactory_external() {
+    ParserTestCase.parse("parseClassMember", <Object> ["C"], "external const factory C();");
+  }
+
+  static dartSuite() {
+    _ut.group('NonErrorParserTest', () {
+      _ut.test('test_constFactory_external', () {
+        final __test = new NonErrorParserTest();
+        runJUnitTest(__test, __test.test_constFactory_external);
+      });
+    });
+  }
+}
+
 /**
  * The class `ComplexParserTest` defines parser tests that test the parsing of more complex
  * code fragments or the interactions between multiple parsing methods. For example, tests to ensure
@@ -9076,26 +9091,14 @@
 }
 
 class IncrementalParserTest extends EngineTestCase {
-  void fail_delete_identifier_beginning() {
+  void fail_delete_everything() {
+    assertParse("", "f() => a + b;", "", "");
+  }
+
+  void test_delete_identifier_beginning() {
     assertParse("f() => ", "ab", "", "s + b;");
   }
 
-  void fail_delete_mergeTokens() {
-    assertParse("f() => a", " + b + ", "", "c;");
-  }
-
-  void fail_insert_convertOneFunctionToTwo() {
-    assertParse("f()", "", " => 0; g()", " {}");
-  }
-
-  void fail_insert_period_betweenIdentifiers1() {
-    assertParse("f() => a", "", ".", " b;");
-  }
-
-  void fail_replace_multiple_partialFirstAndLast() {
-    assertParse("f() => a", "a + b", "b * a", "b;");
-  }
-
   void test_delete_identifier_end() {
     assertParse("f() => a", "bs", "", " + b;");
   }
@@ -9104,6 +9107,10 @@
     assertParse("f() => a", "b", "", "s + b;");
   }
 
+  void test_delete_mergeTokens() {
+    assertParse("f() => a", " + b + ", "", "c;");
+  }
+
   void test_insert_afterIdentifier1() {
     assertParse("f() => a", "", "bs", " + b;");
   }
@@ -9120,6 +9127,18 @@
     assertParse("f() => a + ", "", "x", "b;");
   }
 
+  void test_insert_convertOneFunctionToTwo() {
+    assertParse("f()", "", " => 0; g()", " {}");
+  }
+
+  void test_insert_end() {
+    assertParse("class A {}", "", " class B {}", "");
+  }
+
+  void test_insert_insideIdentifier() {
+    assertParse("f() => co", "", "w.", "b;");
+  }
+
   void test_insert_newIdentifier1() {
     assertParse("f() => a;", "", " b", " c;");
   }
@@ -9132,6 +9151,10 @@
     assertParse("f() => a + b", "", ".", ";");
   }
 
+  void test_insert_period_betweenIdentifiers1() {
+    assertParse("f() => a", "", ".", " b;");
+  }
+
   void test_insert_period_betweenIdentifiers2() {
     assertParse("f() => a ", "", ".", "b;");
   }
@@ -9172,6 +9195,10 @@
     assertParse("f() => f", "ir", "ro", "st + b;");
   }
 
+  void test_replace_multiple_partialFirstAndLast() {
+    assertParse("f() => a", "a + b", "b * a", "b;");
+  }
+
   void test_replace_operator_oneForMany() {
     assertParse("f() => a ", "+", "* c -", " b;");
   }
@@ -9213,13 +9240,17 @@
     Token incrementalTokens = incrementalScanner.rescan(originalTokens, replaceStart, removed.length, added.length);
     JUnitTestCase.assertNotNull(incrementalTokens);
     IncrementalParser incrementalParser = new IncrementalParser(source, incrementalScanner.tokenMap, incrementalListener);
-    CompilationUnit incrementalUnit = incrementalParser.reparse(originalUnit, incrementalScanner.firstToken, incrementalScanner.lastToken, replaceStart, prefix.length + removed.length);
+    CompilationUnit incrementalUnit = incrementalParser.reparse(originalUnit, incrementalScanner.leftToken, incrementalScanner.rightToken, replaceStart, prefix.length + removed.length);
     JUnitTestCase.assertNotNull(incrementalUnit);
-    JUnitTestCase.assertTrue(ASTComparator.equals3(modifiedUnit, incrementalUnit));
+    JUnitTestCase.assertTrue(ASTComparator.equals4(modifiedUnit, incrementalUnit));
   }
 
   static dartSuite() {
     _ut.group('IncrementalParserTest', () {
+      _ut.test('test_delete_identifier_beginning', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_delete_identifier_beginning);
+      });
       _ut.test('test_delete_identifier_end', () {
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_delete_identifier_end);
@@ -9228,6 +9259,10 @@
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_delete_identifier_middle);
       });
+      _ut.test('test_delete_mergeTokens', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_delete_mergeTokens);
+      });
       _ut.test('test_insert_afterIdentifier1', () {
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_insert_afterIdentifier1);
@@ -9244,6 +9279,18 @@
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_insert_beforeIdentifier2);
       });
+      _ut.test('test_insert_convertOneFunctionToTwo', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_insert_convertOneFunctionToTwo);
+      });
+      _ut.test('test_insert_end', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_insert_end);
+      });
+      _ut.test('test_insert_insideIdentifier', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_insert_insideIdentifier);
+      });
       _ut.test('test_insert_newIdentifier1', () {
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_insert_newIdentifier1);
@@ -9260,6 +9307,10 @@
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_insert_periodAndIdentifier);
       });
+      _ut.test('test_insert_period_betweenIdentifiers1', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_insert_period_betweenIdentifiers1);
+      });
       _ut.test('test_insert_period_betweenIdentifiers2', () {
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_insert_period_betweenIdentifiers2);
@@ -9296,6 +9347,10 @@
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_replace_identifier_middle);
       });
+      _ut.test('test_replace_multiple_partialFirstAndLast', () {
+        final __test = new IncrementalParserTest();
+        runJUnitTest(__test, __test.test_replace_multiple_partialFirstAndLast);
+      });
       _ut.test('test_replace_operator_oneForMany', () {
         final __test = new IncrementalParserTest();
         runJUnitTest(__test, __test.test_replace_operator_oneForMany);
@@ -11314,6 +11369,7 @@
   ComplexParserTest.dartSuite();
   ErrorParserTest.dartSuite();
   IncrementalParserTest.dartSuite();
+  NonErrorParserTest.dartSuite();
   RecoveryParserTest.dartSuite();
   ResolutionCopierTest.dartSuite();
   SimpleParserTest.dartSuite();
@@ -11364,10 +11420,10 @@
   'ensureAssignable_1': new MethodTrampoline(1, (Parser target, arg0) => target.ensureAssignable(arg0)),
   'expect_1': new MethodTrampoline(1, (Parser target, arg0) => target.expect(arg0)),
   'findRange_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.findRange(arg0, arg1)),
-  'gatherTodoComments_1': new MethodTrampoline(1, (Parser target, arg0) => target.gatherTodoComments(arg0)),
   'getCodeBlockRanges_1': new MethodTrampoline(1, (Parser target, arg0) => target.getCodeBlockRanges(arg0)),
   'getEndToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.getEndToken(arg0)),
   'hasReturnTypeInTypeAlias_0': new MethodTrampoline(0, (Parser target) => target.hasReturnTypeInTypeAlias()),
+  'injectToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.injectToken(arg0)),
   'isFunctionDeclaration_0': new MethodTrampoline(0, (Parser target) => target.isFunctionDeclaration()),
   'isFunctionExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target.isFunctionExpression(arg0)),
   'isHexDigit_1': new MethodTrampoline(1, (Parser target, arg0) => target.isHexDigit(arg0)),
@@ -11469,7 +11525,6 @@
   'peek_1': new MethodTrampoline(1, (Parser target, arg0) => target.peek2(arg0)),
   'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError(arg0, arg1, arg2)),
   'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError9(arg0, arg1)),
-  'scrapeTodoComment_1': new MethodTrampoline(1, (Parser target, arg0) => target.scrapeTodoComment(arg0)),
   'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFinalConstVarOrType(arg0)),
   'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFormalParameterList(arg0)),
   'skipPastMatchingToken_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipPastMatchingToken(arg0)),
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index e85b6c5..3bc159c 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -1490,6 +1490,21 @@
     verify([source]);
   }
 
+  void test_deprecatedMemberUse_hide() {
+    Source source = addSource(EngineTestCase.createSource([
+        "library lib;",
+        "import 'lib1.dart' hide B;",
+        "A a = new A();"]));
+    addSource2("/lib1.dart", EngineTestCase.createSource([
+        "library lib1;",
+        "class A {}",
+        "@deprecated",
+        "class B {}"]));
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_duplicateDefinition_emptyName() {
     Source source = addSource(EngineTestCase.createSource([
         "Map _globalMap = {",
@@ -4131,6 +4146,18 @@
     verify([source]);
   }
 
+  void test_undefinedIdentifier_synthetic_whenExpression() {
+    Source source = addSource(EngineTestCase.createSource(["print(x) {}", "main() {", "  print(is String);", "}"]));
+    resolve(source);
+    assertErrors(source, [ParserErrorCode.MISSING_IDENTIFIER]);
+  }
+
+  void test_undefinedIdentifier_synthetic_whenMethodName() {
+    Source source = addSource(EngineTestCase.createSource(["print(x) {}", "main(int p) {", "  p.();", "}"]));
+    resolve(source);
+    assertErrors(source, [ParserErrorCode.MISSING_IDENTIFIER]);
+  }
+
   void test_undefinedMethod_functionExpression_callMethod() {
     Source source = addSource(EngineTestCase.createSource(["main() {", "  (() => null).call();", "}"]));
     resolve(source);
@@ -4460,6 +4487,10 @@
         final __test = new NonErrorResolverTest();
         runJUnitTest(__test, __test.test_defaultValueInFunctionTypedParameter_optional);
       });
+      _ut.test('test_deprecatedMemberUse_hide', () {
+        final __test = new NonErrorResolverTest();
+        runJUnitTest(__test, __test.test_deprecatedMemberUse_hide);
+      });
       _ut.test('test_duplicateDefinition_emptyName', () {
         final __test = new NonErrorResolverTest();
         runJUnitTest(__test, __test.test_duplicateDefinition_emptyName);
@@ -5388,6 +5419,14 @@
         final __test = new NonErrorResolverTest();
         runJUnitTest(__test, __test.test_undefinedIdentifier_show);
       });
+      _ut.test('test_undefinedIdentifier_synthetic_whenExpression', () {
+        final __test = new NonErrorResolverTest();
+        runJUnitTest(__test, __test.test_undefinedIdentifier_synthetic_whenExpression);
+      });
+      _ut.test('test_undefinedIdentifier_synthetic_whenMethodName', () {
+        final __test = new NonErrorResolverTest();
+        runJUnitTest(__test, __test.test_undefinedIdentifier_synthetic_whenMethodName);
+      });
       _ut.test('test_undefinedMethod_functionExpression_callMethod', () {
         final __test = new NonErrorResolverTest();
         runJUnitTest(__test, __test.test_undefinedMethod_functionExpression_callMethod);
@@ -12454,6 +12493,21 @@
     verify([source]);
   }
 
+  void test_typeAliasCannotReferenceItself_11987() {
+    Source source = addSource(EngineTestCase.createSource([
+        "typedef void F(List<G> l);",
+        "typedef void G(List<F> l);",
+        "main() {",
+        "  F foo(G g) => g;",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [
+        CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
+        CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
+        StaticTypeWarningCode.RETURN_OF_INVALID_TYPE]);
+    verify([source]);
+  }
+
   void test_typeAliasCannotReferenceItself_parameterType_named() {
     Source source = addSource(EngineTestCase.createSource(["typedef A({A a});"]));
     resolve(source);
@@ -13962,6 +14016,10 @@
         final __test = new CompileTimeErrorCodeTest();
         runJUnitTest(__test, __test.test_superInRedirectingConstructor_superRedirection);
       });
+      _ut.test('test_typeAliasCannotReferenceItself_11987', () {
+        final __test = new CompileTimeErrorCodeTest();
+        runJUnitTest(__test, __test.test_typeAliasCannotReferenceItself_11987);
+      });
       _ut.test('test_typeAliasCannotReferenceItself_parameterType_named', () {
         final __test = new CompileTimeErrorCodeTest();
         runJUnitTest(__test, __test.test_typeAliasCannotReferenceItself_parameterType_named);
@@ -14312,7 +14370,6 @@
   void setUp() {
     super.setUp();
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.strictMode = true;
     options.hint = false;
     analysisContext.analysisOptions = options;
   }
@@ -21272,7 +21329,7 @@
 class EnclosedScopeTest extends ResolverTestCase {
   void test_define_duplicate() {
     GatheringErrorListener errorListener2 = new GatheringErrorListener();
-    Scope rootScope = new Scope_22(errorListener2);
+    Scope rootScope = new Scope_23(errorListener2);
     EnclosedScope scope = new EnclosedScope(rootScope);
     VariableElement element1 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
     VariableElement element2 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
@@ -21283,7 +21340,7 @@
 
   void test_define_normal() {
     GatheringErrorListener errorListener3 = new GatheringErrorListener();
-    Scope rootScope = new Scope_23(errorListener3);
+    Scope rootScope = new Scope_24(errorListener3);
     EnclosedScope outerScope = new EnclosedScope(rootScope);
     EnclosedScope innerScope = new EnclosedScope(outerScope);
     VariableElement element1 = ElementFactory.localVariableElement(ASTFactory.identifier3("v1"));
@@ -21307,20 +21364,20 @@
   }
 }
 
-class Scope_22 extends Scope {
+class Scope_23 extends Scope {
   GatheringErrorListener errorListener2;
 
-  Scope_22(this.errorListener2) : super();
+  Scope_23(this.errorListener2) : super();
 
   AnalysisErrorListener get errorListener => errorListener2;
 
   Element lookup3(Identifier identifier, String name, LibraryElement referencingLibrary) => null;
 }
 
-class Scope_23 extends Scope {
+class Scope_24 extends Scope {
   GatheringErrorListener errorListener3;
 
-  Scope_23(this.errorListener3) : super();
+  Scope_24(this.errorListener3) : super();
 
   AnalysisErrorListener get errorListener => errorListener3;
 
@@ -22043,6 +22100,22 @@
     verify([source]);
   }
 
+  void test_localVariable_types_invoked() {
+    Source source = addSource(EngineTestCase.createSource([
+        "const A = null;",
+        "main() {",
+        "  var myVar = (int p) => 'foo';",
+        "  myVar(42);",
+        "}"]));
+    LibraryElement library = resolve(source);
+    JUnitTestCase.assertNotNull(library);
+    CompilationUnit unit = analysisContext.getResolvedCompilationUnit(source, library);
+    JUnitTestCase.assertNotNull(unit);
+    List<bool> found = [false];
+    unit.accept(new RecursiveASTVisitor_27(this, found));
+    JUnitTestCase.assertTrue(found[0]);
+  }
+
   void test_metadata_class() {
     Source source = addSource(EngineTestCase.createSource(["const A = null;", "@A class C {}"]));
     LibraryElement library = resolve(source);
@@ -22380,6 +22453,10 @@
         final __test = new SimpleResolverTest();
         runJUnitTest(__test, __test.test_labels_switch);
       });
+      _ut.test('test_localVariable_types_invoked', () {
+        final __test = new SimpleResolverTest();
+        runJUnitTest(__test, __test.test_localVariable_types_invoked);
+      });
       _ut.test('test_metadata_class', () {
         final __test = new SimpleResolverTest();
         runJUnitTest(__test, __test.test_metadata_class);
@@ -22428,6 +22505,25 @@
   }
 }
 
+class RecursiveASTVisitor_27 extends RecursiveASTVisitor<Object> {
+  final SimpleResolverTest SimpleResolverTest_this;
+
+  List<bool> found;
+
+  RecursiveASTVisitor_27(this.SimpleResolverTest_this, this.found) : super();
+
+  Object visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.name == "myVar" && node.parent is MethodInvocation) {
+      found[0] = true;
+      Type2 staticType = node.staticType;
+      JUnitTestCase.assertSame(SimpleResolverTest_this.typeProvider.dynamicType, staticType);
+      FunctionType propagatedType = node.propagatedType as FunctionType;
+      JUnitTestCase.assertEquals(SimpleResolverTest_this.typeProvider.stringType, propagatedType.returnType);
+    }
+    return null;
+  }
+}
+
 class SubtypeManagerTest extends EngineTestCase {
   /**
    * The inheritance manager being tested.
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index d70eec5..04350a5 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -1879,146 +1879,183 @@
    */
   Token _incrementalTokens;
 
-  void fail_delete_identifier_beginning() {
+  void test_delete_identifier_beginning() {
     scan("", "ab", "", "s + b;");
-    assertTokens(0, 0, ["s", "+", "b", ";"]);
-  }
-
-  void fail_delete_mergeTokens() {
-    scan("a", " + b + ", "", "c;");
-    assertTokens(0, 0, ["ac", ";"]);
-  }
-
-  void fail_replace_multiple_partialFirstAndLast() {
-    scan("a", "a + b", "b * a", "b;");
-    assertTokens(0, 2, ["ab", "*", "ab", ";"]);
+    assertTokens(-1, 1, ["s", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_delete_identifier_end() {
     scan("a", "bs", "", " + b;");
-    assertTokens(0, 0, ["a", "+", "b", ";"]);
+    assertTokens(-1, 1, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_delete_identifier_middle() {
     scan("a", "b", "", "s + b;");
-    assertTokens(0, 0, ["as", "+", "b", ";"]);
+    assertTokens(-1, 1, ["as", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+  }
+
+  void test_delete_mergeTokens() {
+    scan("a", " + b + ", "", "c;");
+    assertTokens(-1, 1, ["ac", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_afterIdentifier1() {
     scan("a", "", "bs", " + b;");
-    assertTokens(0, 0, ["abs", "+", "b", ";"]);
+    assertTokens(-1, 1, ["abs", "+", "b", ";"]);
     assertReplaced(1, "+");
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_afterIdentifier2() {
     scan("a + b", "", "y", ";");
-    assertTokens(2, 2, ["a", "+", "by", ";"]);
+    assertTokens(1, 3, ["a", "+", "by", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_beforeIdentifier() {
     scan("a + ", "", "x", "b;");
-    assertTokens(2, 2, ["a", "+", "xb", ";"]);
+    assertTokens(1, 3, ["a", "+", "xb", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_beforeIdentifier_firstToken() {
     scan("", "", "x", "a + b;");
-    assertTokens(0, 0, ["xa", "+", "b", ";"]);
+    assertTokens(-1, 1, ["xa", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_convertOneFunctionToTwo() {
     scan("f()", "", " => 0; g()", " {}");
-    assertTokens(3, 8, ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]);
+    assertTokens(2, 9, ["f", "(", ")", "=>", "0", ";", "g", "(", ")", "{", "}"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+  }
+
+  void test_insert_end() {
+    scan("class A {}", "", " class B {}", "");
+    assertTokens(3, 8, ["class", "A", "{", "}", "class", "B", "{", "}"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+  }
+
+  void test_insert_insideIdentifier() {
+    scan("co", "", "w.", "b;");
+    assertTokens(-1, 3, ["cow", ".", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_newIdentifier1() {
     scan("a; ", "", "b", " c;");
-    assertTokens(2, 2, ["a", ";", "b", "c", ";"]);
+    assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_newIdentifier2() {
     scan("a;", "", "b", "  c;");
-    assertTokens(2, 2, ["a", ";", "b", "c", ";"]);
+    assertTokens(1, 3, ["a", ";", "b", "c", ";"]);
     assertReplaced(1, ";");
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_period() {
     scan("a + b", "", ".", ";");
-    assertTokens(3, 3, ["a", "+", "b", ".", ";"]);
+    assertTokens(2, 4, ["a", "+", "b", ".", ";"]);
   }
 
   void test_insert_period_betweenIdentifiers1() {
     scan("a", "", ".", " b;");
-    assertTokens(1, 1, ["a", ".", "b", ";"]);
+    assertTokens(0, 2, ["a", ".", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_period_betweenIdentifiers2() {
     scan("a ", "", ".", "b;");
-    assertTokens(1, 1, ["a", ".", "b", ";"]);
+    assertTokens(0, 2, ["a", ".", "b", ";"]);
   }
 
   void test_insert_period_betweenIdentifiers3() {
     scan("a ", "", ".", " b;");
-    assertTokens(1, 1, ["a", ".", "b", ";"]);
+    assertTokens(0, 2, ["a", ".", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_period_insideExistingIdentifier() {
     scan("a", "", ".", "b;");
-    assertTokens(0, 2, ["a", ".", "b", ";"]);
+    assertTokens(-1, 3, ["a", ".", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_periodAndIdentifier() {
     scan("a + b", "", ".x", ";");
-    assertTokens(3, 4, ["a", "+", "b", ".", "x", ";"]);
+    assertTokens(2, 5, ["a", "+", "b", ".", "x", ";"]);
   }
 
   void test_insert_whitespace_beginning_beforeToken() {
     scan("", "", " ", "a + b;");
-    assertTokens(-1, -1, ["a", "+", "b", ";"]);
+    assertTokens(0, 1, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_whitespace_betweenTokens() {
     scan("a ", "", " ", "+ b;");
-    assertTokens(-1, -1, ["a", "+", "b", ";"]);
+    assertTokens(1, 2, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_whitespace_end_afterToken() {
     scan("a + b;", "", " ", "");
-    assertTokens(-1, -1, ["a", "+", "b", ";"]);
+    assertTokens(3, 4, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_whitespace_end_afterWhitespace() {
     scan("a + b; ", "", " ", "");
-    assertTokens(-1, -1, ["a", "+", "b", ";"]);
+    assertTokens(3, 4, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_insert_whitespace_withMultipleComments() {
     scan(EngineTestCase.createSource(["//comment", "//comment2", "a"]), "", " ", " + b;");
-    assertTokens(-1, -1, ["a", "+", "b", ";"]);
+    assertTokens(1, 2, ["a", "+", "b", ";"]);
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_replace_identifier_beginning() {
     scan("", "b", "f", "ell + b;");
-    assertTokens(0, 0, ["fell", "+", "b", ";"]);
+    assertTokens(-1, 1, ["fell", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_replace_identifier_end() {
     scan("bel", "l", "t", " + b;");
-    assertTokens(0, 0, ["belt", "+", "b", ";"]);
+    assertTokens(-1, 1, ["belt", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_replace_identifier_middle() {
     scan("f", "ir", "ro", "st + b;");
-    assertTokens(0, 0, ["frost", "+", "b", ";"]);
+    assertTokens(-1, 1, ["frost", "+", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
+  }
+
+  void test_replace_multiple_partialFirstAndLast() {
+    scan("a", "a + b", "b * a", "b;");
+    assertTokens(-1, 3, ["ab", "*", "ab", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_replace_operator_oneForMany() {
     scan("a ", "+", "* c -", " b;");
-    assertTokens(1, 3, ["a", "*", "c", "-", "b", ";"]);
+    assertTokens(0, 4, ["a", "*", "c", "-", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_replace_operator_oneForOne() {
     scan("a ", "+", "*", " b;");
-    assertTokens(1, 1, ["a", "*", "b", ";"]);
+    assertTokens(0, 2, ["a", "*", "b", ";"]);
+    JUnitTestCase.assertTrue(_incrementalScanner.hasNonWhitespaceChange());
   }
 
   void test_tokenMap() {
@@ -2032,8 +2069,16 @@
       JUnitTestCase.assertEquals(oldToken.lexeme, newToken.lexeme);
       oldToken = oldToken.next;
     }
+    JUnitTestCase.assertFalse(_incrementalScanner.hasNonWhitespaceChange());
   }
 
+  /**
+   * Assert that the token at the given offset was replaced with a new token having the given
+   * lexeme.
+   *
+   * @param tokenOffset the offset of the token being tested
+   * @param lexeme the expected lexeme of the new token
+   */
   void assertReplaced(int tokenOffset, String lexeme) {
     Token oldToken = _originalTokens;
     for (int i = 0; i < tokenOffset; i++) {
@@ -2046,35 +2091,52 @@
     JUnitTestCase.assertNotSame(oldToken, newToken);
   }
 
-  void assertTokens(int firstIndex, int lastIndex, List<String> lexemes) {
-    Token firstToken = null;
-    Token lastToken = null;
+  /**
+   * Assert that the result of the incremental scan matches the given list of lexemes and that the
+   * left and right tokens correspond to the tokens at the given indices.
+   *
+   * @param leftIndex the expected index of the left token
+   * @param rightIndex the expected index of the right token
+   * @param lexemes the expected lexemes of the resulting tokens
+   */
+  void assertTokens(int leftIndex, int rightIndex, List<String> lexemes) {
     int count = lexemes.length;
+    JUnitTestCase.assertTrueMsg("Invalid left index", leftIndex >= -1 && leftIndex < count);
+    JUnitTestCase.assertTrueMsg("Invalid right index", rightIndex >= 0 && rightIndex <= count);
+    Token leftToken = null;
+    Token rightToken = null;
     Token token = _incrementalTokens;
+    if (leftIndex < 0) {
+      leftToken = token.previous;
+    }
     for (int i = 0; i < count; i++) {
       JUnitTestCase.assertEquals(lexemes[i], token.lexeme);
-      if (i == firstIndex) {
-        firstToken = token;
+      if (i == leftIndex) {
+        leftToken = token;
       }
-      if (i == lastIndex) {
-        lastToken = token;
+      if (i == rightIndex) {
+        rightToken = token;
       }
       token = token.next;
     }
+    if (rightIndex >= count) {
+      rightToken = token;
+    }
     JUnitTestCase.assertSameMsg("Too many tokens", TokenType.EOF, token.type);
-    if (firstIndex >= 0) {
-      JUnitTestCase.assertNotNull(firstToken);
+    if (leftIndex >= 0) {
+      JUnitTestCase.assertNotNull(leftToken);
     }
-    JUnitTestCase.assertSame(firstToken, _incrementalScanner.firstToken);
-    if (lastIndex >= 0) {
-      JUnitTestCase.assertNotNull(lastToken);
+    JUnitTestCase.assertSameMsg("Invalid left token", leftToken, _incrementalScanner.leftToken);
+    if (rightIndex >= 0) {
+      JUnitTestCase.assertNotNull(rightToken);
     }
-    JUnitTestCase.assertSame(lastToken, _incrementalScanner.lastToken);
+    JUnitTestCase.assertSameMsg("Invalid right token", rightToken, _incrementalScanner.rightToken);
   }
 
   /**
    * Given a description of the original and modified contents, perform an incremental scan of the
-   * two pieces of text.
+   * two pieces of text. Verify that the incremental scan produced the same tokens as those that
+   * would be produced by a full scan of the new contents.
    *
    * @param prefix the unchanged text before the edit region
    * @param removed the text that was removed from the original contents
@@ -2113,6 +2175,10 @@
 
   static dartSuite() {
     _ut.group('IncrementalScannerTest', () {
+      _ut.test('test_delete_identifier_beginning', () {
+        final __test = new IncrementalScannerTest();
+        runJUnitTest(__test, __test.test_delete_identifier_beginning);
+      });
       _ut.test('test_delete_identifier_end', () {
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_delete_identifier_end);
@@ -2121,6 +2187,10 @@
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_delete_identifier_middle);
       });
+      _ut.test('test_delete_mergeTokens', () {
+        final __test = new IncrementalScannerTest();
+        runJUnitTest(__test, __test.test_delete_mergeTokens);
+      });
       _ut.test('test_insert_afterIdentifier1', () {
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_insert_afterIdentifier1);
@@ -2141,6 +2211,14 @@
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_insert_convertOneFunctionToTwo);
       });
+      _ut.test('test_insert_end', () {
+        final __test = new IncrementalScannerTest();
+        runJUnitTest(__test, __test.test_insert_end);
+      });
+      _ut.test('test_insert_insideIdentifier', () {
+        final __test = new IncrementalScannerTest();
+        runJUnitTest(__test, __test.test_insert_insideIdentifier);
+      });
       _ut.test('test_insert_newIdentifier1', () {
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_insert_newIdentifier1);
@@ -2205,6 +2283,10 @@
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_replace_identifier_middle);
       });
+      _ut.test('test_replace_multiple_partialFirstAndLast', () {
+        final __test = new IncrementalScannerTest();
+        runJUnitTest(__test, __test.test_replace_multiple_partialFirstAndLast);
+      });
       _ut.test('test_replace_operator_oneForMany', () {
         final __test = new IncrementalScannerTest();
         runJUnitTest(__test, __test.test_replace_operator_oneForMany);
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 06954e6..91f0ba6 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -286,7 +286,7 @@
    * @param secondError the second error being compared
    * @return `true` if the two errors are equivalent
    */
-  bool equals4(AnalysisError firstError, AnalysisError secondError) => identical(firstError.errorCode, secondError.errorCode) && firstError.offset == secondError.offset && firstError.length == secondError.length && equals5(firstError.source, secondError.source);
+  bool equals5(AnalysisError firstError, AnalysisError secondError) => identical(firstError.errorCode, secondError.errorCode) && firstError.offset == secondError.offset && firstError.length == secondError.length && equals6(firstError.source, secondError.source);
 
   /**
    * Return `true` if the two sources are equivalent.
@@ -295,7 +295,7 @@
    * @param secondSource the second source being compared
    * @return `true` if the two sources are equivalent
    */
-  bool equals5(Source firstSource, Source secondSource) {
+  bool equals6(Source firstSource, Source secondSource) {
     if (firstSource == null) {
       return secondSource == null;
     } else if (secondSource == null) {
@@ -379,7 +379,7 @@
    */
   bool foundAndRemoved(List<AnalysisError> errors, AnalysisError targetError) {
     for (AnalysisError error in errors) {
-      if (equals4(error, targetError)) {
+      if (equals5(error, targetError)) {
         errors.remove(error);
         return true;
       }
diff --git a/pkg/analyzer/test/services/formatter_test.dart b/pkg/analyzer/test/services/formatter_test.dart
index 72f010b..61e4356 100644
--- a/pkg/analyzer/test/services/formatter_test.dart
+++ b/pkg/analyzer/test/services/formatter_test.dart
@@ -536,6 +536,40 @@
         );
     });
 
+    test('CU - comments (8)', () {
+      expectCUFormatsTo(
+          'var x /* X */, y;\n',
+          'var x /* X */, y;\n'
+      );
+    });
+
+    test('CU - comments (9)', () {
+      expectCUFormatsTo(
+          'main() {\n'
+          '  foo(1 /* bang */, 2);\n'
+          '}\n'
+          'foo(x, y) => null;\n',
+          'main() {\n'
+          '  foo(1 /* bang */, 2);\n'
+          '}\n'
+          'foo(x, y) => null;\n'
+      );
+    });
+
+    test('CU - comments (10)', () {
+      expectCUFormatsTo(
+          'var l = [1 /* bang */, 2];\n',
+          'var l = [1 /* bang */, 2];\n'
+      );
+    });
+
+    test('CU - comments (11)', () {
+      expectCUFormatsTo(
+          'var m = {1: 2 /* bang */, 3: 4};\n',
+          'var m = {1: 2 /* bang */, 3: 4};\n'
+      );
+    });
+
     test('CU - EOF nl', () {
       expectCUFormatsTo(
           'var x = 1;',
@@ -711,6 +745,20 @@
       );
     });
 
+    test('stmt (empty while body)', () {
+      expectStmtFormatsTo(
+        'while (true);',
+        'while (true);'
+      );
+    });
+
+    test('stmt (empty for body)', () {
+      expectStmtFormatsTo(
+        'for ( ; ; );',
+        'for ( ; ; );'
+      );
+    });
+
     test('stmt (cascades)', () {
       expectStmtFormatsTo(
         '"foo"\n'
@@ -734,6 +782,16 @@
         'var l = [1,2,3,4];',
         'var l = [1, 2, 3, 4];'
       );
+      expectStmtFormatsTo(
+        'var l = [\n'
+        '1,\n'
+        '2,\n'
+        '];',
+        'var l = [\n'
+        '  1,\n'
+        '  2,\n'
+        '];'
+      );
       //Dangling ','
       expectStmtFormatsTo(
         'var l = [1,];',
@@ -747,6 +805,17 @@
         'var map = const {"foo": "bar", "fuz": null};'
       );
 
+      expectStmtFormatsTo(
+          'var map = {\n'
+          '"foo": "bar",\n'
+          '"bar": "baz"'
+          '};',
+          'var map = {\n'
+          '  "foo": "bar",\n'
+          '  "bar": "baz"'
+          '};'
+      );
+
       //Dangling ','
       expectStmtFormatsTo(
         'var map = {"foo": "bar",};',
@@ -767,6 +836,18 @@
         '  print(e);\n'
         '}'
       );
+      expectStmtFormatsTo(
+          'try{\n'
+          'doSomething();\n'
+          '}on Exception catch (e){\n'
+          'print(e);\n'
+          '}',
+          'try {\n'
+          '  doSomething();\n'
+          '} on Exception catch (e) {\n'
+          '  print(e);\n'
+          '}'
+      );
     });
 
     test('stmt (binary/ternary ops)', () {
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index df98f1d..3454899 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -122,7 +122,7 @@
     // Keep track of logged errors so we can know that the build failed.
     onLog.listen((entry) {
       if (entry.level == LogLevel.ERROR) {
-        // TODO(nweiz): keep track of stack trace.
+        // TODO(nweiz): keep track of stack chain.
         _accumulatedErrors.add(
             new TransformerException(entry.transform, entry.message, null));
       }
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index 2372ba9..a1af547 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -10,6 +10,7 @@
 import 'asset_id.dart';
 import 'errors.dart';
 import 'transform_node.dart';
+import 'utils.dart';
 
 /// Describes the current state of an asset as part of a transformation graph.
 ///
@@ -125,7 +126,7 @@
   /// The return value of [callback] is piped to the returned Future.
   Future _waitForState(bool test(AssetState state),
       callback(AssetState state)) {
-    if (test(state)) return new Future.sync(() => callback(state));
+    if (test(state)) return syncFuture(() => callback(state));
     return onStateChange.firstWhere(test).then((_) => callback(state));
   }
 
diff --git a/pkg/barback/lib/src/build_result.dart b/pkg/barback/lib/src/build_result.dart
index 52b341e..faeb256 100644
--- a/pkg/barback/lib/src/build_result.dart
+++ b/pkg/barback/lib/src/build_result.dart
@@ -4,10 +4,6 @@
 
 library barback.build_result;
 
-import 'dart:async';
-
-import 'package:stack_trace/stack_trace.dart';
-
 import 'errors.dart';
 import 'utils.dart';
 
@@ -49,14 +45,14 @@
     return "errors:\n" + errors.map((error) {
       var stackTrace = null;
       if (error is TransformerException || error is AssetLoadException) {
-        stackTrace = new Trace.from(error.stackTrace);
+        stackTrace = error.stackTrace.terse;
       }
 
       var msg = new StringBuffer();
       msg.write(prefixLines(error.toString()));
       if (stackTrace != null) {
         msg.write("\n\n");
-        msg.write("Stack trace:\n");
+        msg.write("Stack chain:\n");
         msg.write(prefixLines(stackTrace.toString()));
       }
       return msg.toString();
diff --git a/pkg/barback/lib/src/cancelable_future.dart b/pkg/barback/lib/src/cancelable_future.dart
index 4454f5c..84c19f1 100644
--- a/pkg/barback/lib/src/cancelable_future.dart
+++ b/pkg/barback/lib/src/cancelable_future.dart
@@ -32,8 +32,8 @@
   Future then(onValue(T value), {Function onError}) =>
     _completer.future.then(onValue, onError: onError);
   Future<T> whenComplete(action()) => _completer.future.whenComplete(action);
-  Future timeout(Duration timeLimit, [void onTimeout()]) =>
-    _completer.future.timeout(timeLimit, onTimeout);
+  Future timeout(Duration timeLimit, {void onTimeout()}) =>
+    _completer.future.timeout(timeLimit, onTimeout: onTimeout);
   /// Cancels this future.
   void cancel() {
     _canceled = true;
diff --git a/pkg/barback/lib/src/errors.dart b/pkg/barback/lib/src/errors.dart
index bb9af79..d62efeb 100644
--- a/pkg/barback/lib/src/errors.dart
+++ b/pkg/barback/lib/src/errors.dart
@@ -4,8 +4,6 @@
 
 library barback.errors;
 
-import 'dart:async';
-
 import 'package:stack_trace/stack_trace.dart';
 
 import 'asset_id.dart';
@@ -115,9 +113,11 @@
 abstract class _WrappedException implements BarbackException {
   /// The wrapped exception.
   final error;
-  final StackTrace stackTrace;
+  final Chain stackTrace;
 
-  _WrappedException(this.error, this.stackTrace);
+  _WrappedException(this.error, StackTrace stackTrace)
+      : this.stackTrace = stackTrace == null ? null :
+            new Chain.forTrace(stackTrace);
 
   String get _message;
 
@@ -127,7 +127,7 @@
     var stack = stackTrace;
     if (stack == null && error is Error) stack = error.stackTrace;
     if (stack != null) {
-      result = "$result\n${new Trace.from(stack).terse}";
+      result = "$result\n${stackTrace.terse}";
     }
 
     return result;
diff --git a/pkg/barback/lib/src/file_pool.dart b/pkg/barback/lib/src/file_pool.dart
index 31d32ed..dab9409 100644
--- a/pkg/barback/lib/src/file_pool.dart
+++ b/pkg/barback/lib/src/file_pool.dart
@@ -8,6 +8,8 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'pool.dart';
 import 'utils.dart';
 
@@ -33,7 +35,7 @@
   /// try again.
   Stream<List<int>> openRead(String path) {
     return futureStream(_pool.request().then((resource) {
-      return new File(path).openRead().transform(
+      return Chain.track(new File(path).openRead()).transform(
           new StreamTransformer.fromHandlers(handleDone: (sink) {
         sink.close();
         resource.release();
diff --git a/pkg/barback/lib/src/internal_asset.dart b/pkg/barback/lib/src/internal_asset.dart
index 6b3c9fb..75b4969 100644
--- a/pkg/barback/lib/src/internal_asset.dart
+++ b/pkg/barback/lib/src/internal_asset.dart
@@ -6,7 +6,6 @@
 
 import 'dart:async';
 import 'dart:convert';
-import 'dart:io';
 import 'dart:typed_data';
 
 import 'asset.dart';
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
index 95ecbb1..2ecf6b4 100644
--- a/pkg/barback/lib/src/package_graph.dart
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -66,6 +66,9 @@
   /// [Future] returned by [getAllAssets].
   var _lastUnexpectedError;
 
+  /// The stack trace for [_lastUnexpectedError].
+  StackTrace _lastUnexpectedErrorTrace;
+
   // TODO(nweiz): Allow transformers to declare themselves as "lightweight" or
   // "heavyweight" and adjust their restrictions appropriately. Simple
   // transformers may be very efficient to run in parallel, whereas dart2js uses
@@ -114,8 +117,9 @@
         // errors, the result will automatically be considered a success.
         _resultsController.add(
             new BuildResult.aggregate(_cascadeResults.values));
-      }, onError: (error, [stackTrace]) {
+      }, onError: (error, stackTrace) {
         _lastUnexpectedError = error;
+        _lastUnexpectedErrorTrace = stackTrace;
         _resultsController.addError(error, stackTrace);
       });
     }
@@ -152,7 +156,7 @@
     if (_lastUnexpectedError != null) {
       var error = _lastUnexpectedError;
       _lastUnexpectedError = null;
-      return new Future.error(error);
+      return new Future.error(error, _lastUnexpectedErrorTrace);
     }
 
     // If the build completed with an error, complete the future with it.
diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart
index ff8ad5c..13bc700 100644
--- a/pkg/barback/lib/src/phase_input.dart
+++ b/pkg/barback/lib/src/phase_input.dart
@@ -291,7 +291,7 @@
   /// synchronously to ensure that [_adjustTransformers] isn't called before the
   /// callback.
   Future _waitForTransformers(callback()) {
-    if (_adjustTransformersFuture == null) return new Future.sync(callback);
+    if (_adjustTransformersFuture == null) return syncFuture(callback);
     return _adjustTransformersFuture.then(
         (_) => _waitForTransformers(callback));
   }
diff --git a/pkg/barback/lib/src/pool.dart b/pkg/barback/lib/src/pool.dart
index 7f89c12..24100ca 100644
--- a/pkg/barback/lib/src/pool.dart
+++ b/pkg/barback/lib/src/pool.dart
@@ -9,6 +9,9 @@
 
 import 'package:stack_trace/stack_trace.dart';
 
+import 'utils.dart';
+
+// TODO(nweiz): put this somewhere that it can be shared between packages.
 /// Manages an abstract pool of resources with a limit on how many may be in use
 /// at once.
 ///
@@ -73,7 +76,7 @@
   /// The return value of [callback] is piped to the returned Future.
   Future withResource(callback()) {
     return request().then((resource) =>
-        new Future.sync(callback).whenComplete(resource.release));
+        syncFuture(callback).whenComplete(resource.release));
   }
 
   /// If there are any pending requests, this will fire the oldest one.
@@ -107,7 +110,7 @@
   void _onTimeout() {
     for (var completer in _requestedResources) {
       completer.completeError("Pool deadlock: all resources have been "
-          "allocated for too long.", new Trace.current().vmTrace);
+          "allocated for too long.", new Chain.current());
     }
     _requestedResources.clear();
     _timer = null;
diff --git a/pkg/barback/lib/src/serialize.dart b/pkg/barback/lib/src/serialize.dart
index fa5adea..f0b356e 100644
--- a/pkg/barback/lib/src/serialize.dart
+++ b/pkg/barback/lib/src/serialize.dart
@@ -88,24 +88,17 @@
   /// property.
   final String message;
 
-  /// The exception's stack trace, or `null` if no stack trace was available.
-  final Trace stackTrace;
+  /// The exception's stack chain, or `null` if no stack chain was available.
+  final Chain stackTrace;
 
   /// Loads a [CrossIsolateException] from a serialized representation.
   ///
   /// [error] should be the result of [CrossIsolateException.serialize].
-  factory CrossIsolateException.deserialize(Map error) {
-    var type = error['type'];
-    var message = error['message'];
-    var stackTrace = error['stack'] == null ? null :
-            new Trace.parse(error['stack']);
-    return new CrossIsolateException._(type, message, stackTrace);
-  }
-
-  /// Loads a [CrossIsolateException] from a serialized representation.
-  ///
-  /// [error] should be the result of [CrossIsolateException.serialize].
-  CrossIsolateException._(this.type, this.message, this.stackTrace);
+  CrossIsolateException.deserialize(Map error)
+      : type = error['type'],
+        message = error['message'],
+        stackTrace = error['stack'] == null ? null :
+            new Chain.parse(error['stack']);
 
   /// Serializes [error] to an object that can safely be passed across isolate
   /// boundaries.
@@ -114,7 +107,7 @@
     return {
       'type': error.runtimeType.toString(),
       'message': _getErrorMessage(error),
-      'stack': stack == null ? null : stack.toString()
+      'stack': stack == null ? null : new Chain.forTrace(stack).toString()
     };
   }
 
diff --git a/pkg/barback/lib/src/utils.dart b/pkg/barback/lib/src/utils.dart
index 71576ff..a4a5950 100644
--- a/pkg/barback/lib/src/utils.dart
+++ b/pkg/barback/lib/src/utils.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:typed_data';
 
+import 'package:stack_trace/stack_trace.dart';
+
 /// A pair of values.
 class Pair<E, F> {
   E first;
@@ -151,12 +153,12 @@
 
   for (var stream in streams) {
     stream.listen(
-      controller.add,
-      onError: controller.addError,
-      onDone: () {
-    doneCount++;
-    if (doneCount == streams.length) controller.close();
-  });
+        controller.add,
+        onError: controller.addError,
+        onDone: () {
+      doneCount++;
+      if (doneCount == streams.length) controller.close();
+    });
   }
 
   return controller.stream;
@@ -193,6 +195,9 @@
 // TODO(jmesserly): doc comment changed to due 14601.
 Future newFuture(callback()) => new Future.value().then((_) => callback());
 
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
 /// Returns a buffered stream that will emit the same values as the stream
 /// returned by [future] once [future] completes.
 ///
diff --git a/pkg/barback/pubspec.yaml b/pkg/barback/pubspec.yaml
index 54e3a1a..3032f3d 100644
--- a/pkg/barback/pubspec.yaml
+++ b/pkg/barback/pubspec.yaml
@@ -1,5 +1,15 @@
 name: barback
-version: 0.9.0 # Replaced by publish_barback.py. Do not edit.
+
+# Note! This version is referenced directly in the pub source code in
+# lib/src/barback.dart. Pub implicitly places a version constraint on barback
+# to ensure users only select a version of barback that works with their current
+# version of pub.
+#
+# When the minor version of this is upgraded, you *must* update that version
+# number in pub to stay in sync with this. New patch versions are considered
+# backwards compatible, and pub will allow later patch versions automatically.
+version: 0.10.2+1
+
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://www.dartlang.org
 description: >
@@ -19,14 +29,5 @@
 dev_dependencies:
   scheduled_test: ">=0.9.0 <0.10.0"
   unittest: ">=0.9.0 <0.10.0"
-
 environment:
-  # Barback is tightly coupled to the SDK because pub contains code that is run
-  # against the user's version of barback. We need to ensure that that version
-  # of barback is compatible with the user's version of pub.
-  #
-  # Since the SDK itself can't place constraints on barback, we do a reverse
-  # constraint and have barback itself only allow specific SDK versions.
-  # This ensures that for each SDK version, there is a single known good version
-  # of barback that will be used with it.
-  sdk: "$SDK_CONSTRAINT$"
+  sdk: ">=1.0.1 <2.0.0"
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index d21d235..fb0094f 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -324,8 +324,10 @@
     }
   });
   // After everything is created, do a pass through all classes to make sure no
-  // intermediate classes created by mixins are included.
-  entityMap.values.where((e) => e is Class).forEach((c) => c.makeValid());
+  // intermediate classes created by mixins are included, all the links to
+  // exported members point to the new library.
+  entityMap.values.where((e) => e is Class).forEach(
+      (c) => c.updateLinksAndRemoveIntermediaryClasses());
   // Everything is a subclass of Object, therefore empty the list to avoid a
   // giant list of subclasses to be printed out.
   if (includeSdk) (entityMap['dart-core.Object'] as Class).subclasses.clear();
@@ -342,7 +344,8 @@
       throw new StateError('No library_list.json');
     }
     libraryMap =
-        JSON.decode(new File('$_outputDirectory/library_list.json').readAsStringSync());
+        JSON.decode(new File(
+            '$_outputDirectory/library_list.json').readAsStringSync());
     libraryMap['libraries'].addAll(filteredEntities
         .where((e) => e is Library)
         .map((e) => e.previewMap));
@@ -618,7 +621,8 @@
   if (elementName != null) {
     return new markdown.Element.text('a', elementName);
   }
-  return _fixComplexReference(name, currentLibrary, currentClass, currentMember);
+  return _fixComplexReference(name, currentLibrary, currentClass,
+      currentMember);
 }
 
 markdown.Node fixReferenceWithScope(String name, DeclarationMirror scope) {
@@ -643,11 +647,17 @@
   if (!dir.existsSync()) {
     dir.createSync();
   }
-  // We assume there's a single extra level of directory structure for packages.
   if (path.split(filename).length > 1) {
-    var subdir = new Directory(path.join(_outputDirectory, path.dirname(filename)));
-    if (!subdir.existsSync()) {
-      subdir.createSync();
+    var splitList = path.split(filename);
+    for (int i = 0; i < splitList.length; i++) {
+      var level = splitList[i];
+    }
+    for (var level in path.split(filename)) {
+      var subdir = new Directory(path.join(_outputDirectory,
+                                           path.dirname(filename)));
+      if (!subdir.existsSync()) {
+        subdir.createSync();
+      }
     }
   }
   File file = new File(path.join(_outputDirectory, filename));
@@ -753,14 +763,23 @@
   }
 
   /// Returns a map of [Variable] objects constructed from [mirrorMap].
+  /// The optional parameter [containingLibrary] is contains data for variables
+  /// defined at the top level of a library (potentially for exporting
+  /// purposes).
   Map<String, Variable> _createVariables(Map<String,
-      VariableMirror> mirrorMap) {
+      VariableMirror> mirrorMap, [Library containingLibrary]) {
     var data = {};
     // TODO(janicejl): When map to map feature is created, replace the below
     // with a filter. Issue(#9590).
     mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
       if (_includePrivate || !_isHidden(mirror)) {
-        entityMap[docName(mirror)] = new Variable(mirrorName, mirror);
+        if (containingLibrary != null && mirror.owner.qualifiedName !=
+            containingLibrary.mirror.qualifiedName) {
+          entityMap[docName(mirror)] = new ExportedVariable(mirrorName, mirror,
+              containingLibrary);
+        } else {
+          entityMap[docName(mirror)] = new Variable(mirrorName, mirror);
+        }
         data[mirrorName] = entityMap[docName(mirror)];
       }
     });
@@ -768,11 +787,15 @@
   }
 
   /// Returns a map of [Method] objects constructed from [mirrorMap].
-  MethodGroup _createMethods(Map<String, MethodMirror> mirrorMap) {
+  /// The optional parameter [containingLibrary] is contains data for variables
+  /// defined at the top level of a library (potentially for exporting
+  /// purposes).
+  MethodGroup _createMethods(Map<String, MethodMirror> mirrorMap,
+      [Library containingLibrary]) {
     var group = new MethodGroup();
     mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
       if (_includePrivate || !mirror.isPrivate) {
-        group.addMethod(mirror);
+        group.addMethod(mirror, containingLibrary);
       }
     });
     return group;
@@ -857,14 +880,25 @@
   bool hasBeenCheckedForPackage = false;
   String packageIntro;
 
+  Map<String, Exported> _exportedMembers;
+
   Library(LibraryMirror libraryMirror) : super(libraryMirror) {
     var exported = _calcExportedItems(libraryMirror);
-    this.classes = _createClasses(
-        exported['classes']..addAll(libraryMirror.classes));
+    _createClasses(exported['classes']..addAll(libraryMirror.classes));
     this.functions = _createMethods(
-        exported['methods']..addAll(libraryMirror.functions));
+        exported['methods']..addAll(libraryMirror.functions), this);
     this.variables = _createVariables(
-        exported['variables']..addAll(libraryMirror.variables));
+        exported['variables']..addAll(libraryMirror.variables), this);
+
+    var exportedVariables = {};
+    variables.forEach((key, value) {
+      if (value is ExportedVariable) {
+        exportedVariables[key] = value;
+      }
+    });
+    _exportedMembers = new Map.from(this.classes.exported)
+        ..addAll(this.functions.exported)
+        ..addAll(exportedVariables);
   }
 
   String get packagePrefix => packageName == null || packageName.isEmpty ?
@@ -883,13 +917,12 @@
 
   String get name => docName(mirror);
 
-  /// Returns a [ClassGroup] containing error, typedef and regular classes.
-  ClassGroup _createClasses(Map<String, ClassMirror> mirrorMap) {
-    var group = new ClassGroup();
+  /// Set our classes field with error, typedef and regular classes.
+  void _createClasses(Map<String, ClassMirror> mirrorMap) {
+    this.classes = new ClassGroup();
     mirrorMap.forEach((String mirrorName, ClassMirror mirror) {
-        group.addClass(mirror);
+      this.classes.addClass(mirror, this);
     });
-    return group;
   }
 
   /// For the given library determine what items (if any) are exported.
@@ -1087,16 +1120,26 @@
   ///
   /// If it does not exist in the owner library, it is a mixin applciation and
   /// should be removed.
-  void makeValid() {
+  void updateLinksAndRemoveIntermediaryClasses() {
     var library = entityMap[owner];
-    if (library != null && !library.classes.containsKey(name)) {
-      this.isPrivate = true;
-      // Since we are now making the mixin a private class, make all elements
-      // with the mixin as an owner private too.
-      entityMap.values.where((e) => e.owner == qualifiedName)
-        .forEach((element) => element.isPrivate = true);
-      // Move the subclass up to the next public superclass
-      subclasses.forEach((subclass) => addSubclass(subclass));
+    if (library != null) {
+      if (!library.classes.containsKey(name) && mirror.isNameSynthetic) {
+        // In the mixin case, remove the intermediary classes.
+        this.isPrivate = true;
+        // Since we are now making the mixin a private class, make all elements
+        // with the mixin as an owner private too.
+        entityMap.values.where((e) => e.owner == qualifiedName).forEach(
+            (element) => element.isPrivate = true);
+        // Move the subclass up to the next public superclass
+        subclasses.forEach((subclass) => addSubclass(subclass));
+      } else {
+        // It is an exported item. Loop through each of the exported types,
+        // and tell them to update their links, given these other exported
+        // names within the library.
+        for (Exported member in library._exportedMembers.values) {
+          member.updateExports(library._exportedMembers.keys);
+        }
+      }
     }
   }
 
@@ -1110,8 +1153,8 @@
     });
   }
 
-  /// If a class extends a private superclass, find the closest public superclass
-  /// of the private superclass.
+  /// If a class extends a private superclass, find the closest public
+  /// superclass of the private superclass.
   String validSuperclass() {
     if (superclass == null) return 'dart.core.Object';
     if (_isVisible(superclass)) return superclass.qualifiedName;
@@ -1140,6 +1183,52 @@
   int compareTo(aClass) => name.compareTo(aClass.name);
 }
 
+abstract class Exported {
+  void updateExports(Map<String, Indexable> libraryExports);
+}
+
+Map _filterMap(exported, map, test) {
+  map.forEach((key, value) {
+    if (test(value)) exported[key] = value;
+  });
+  return exported;
+}
+
+class ExportedClass extends Class implements Exported {
+  Class _originalClass;
+  Library _exportingLibrary;
+
+  ExportedClass(ClassMirror originalClass, Library this._exportingLibrary) :
+      super._(originalClass) {
+    _originalClass = new Class(originalClass);
+  }
+
+  // The qualified name (for URL purposes) and the file name are the same,
+  // of the form packageName/ClassName or packageName/ClassName.methodName.
+  // This defines both the URL and the directory structure.
+  String get fileName => path.join(_exportingLibrary.packageName,
+      _exportingLibrary.mirror.qualifiedName + '.' + _originalClass.name);
+
+  void updateExports(Map<String, Indexable> libraryExports) {
+    // TODO(efortuna): If this class points to another exported class or type
+    // of some sort, then that reference needs to be updated here.
+    /* these need to be updated:
+    'comment': comment,
+    'superclass': validSuperclass(),
+    'implements': interfaces.where(_isVisible)
+        .map((e) => e.qualifiedName).toList(),
+    'subclass': (subclasses.toList()..sort())
+        .map((x) => x.qualifiedName).toList(),
+    'variables': recurseMap(variables),
+    'inheritedVariables': recurseMap(inheritedVariables),
+    'methods': methods.toMap(),
+    'inheritedMethods': inheritedMethods.toMap(),
+    'annotations': annotations.map((a) => a.toMap()).toList(),
+    'generics': recurseMap(generics)
+    */
+  }
+}
+
 /// A container to categorize classes into the following groups: abstract
 /// classes, regular classes, typedefs, and errors.
 class ClassGroup {
@@ -1147,7 +1236,17 @@
   Map<String, Typedef> typedefs = {};
   Map<String, Class> errors = {};
 
-  void addClass(ClassMirror classMirror) {
+  Map<String, Exported> get exported {
+    var exported = _filterMap({}, classes, (value) => value is ExportedClass);
+    // TODO(efortuna): The line below needs updating.
+    exported = _filterMap(exported, typedefs,
+        (value) => value is ExportedClass);
+    exported = _filterMap(exported, errors,
+        (value) => value is ExportedClass);
+    return exported;
+  }
+
+  void addClass(ClassMirror classMirror, Library containingLibrary) {
     if (classMirror.isTypedef) {
       // This is actually a Dart2jsTypedefMirror, and it does define value,
       // but we don't have visibility to that type.
@@ -1159,6 +1258,13 @@
     } else {
       var clazz = new Class(classMirror);
 
+      if (classMirror.library.qualifiedName !=
+          containingLibrary.mirror.qualifiedName) {
+        var exportedClass = new ExportedClass(classMirror, containingLibrary);
+        entityMap[clazz.fileName] = exportedClass;
+        clazz = exportedClass;
+      }
+
       if (clazz.isError()) {
         errors[classMirror.simpleName] = clazz;
       } else if (classMirror.isClass) {
@@ -1261,6 +1367,26 @@
   }
 }
 
+class ExportedVariable extends Variable implements Exported {
+  Library _exportingLibrary;
+
+  ExportedVariable(String variableName, VariableMirror originalVariable,
+      Library this._exportingLibrary) : super(variableName, originalVariable);
+
+  String get fileName => path.join(_exportingLibrary.packageName,
+          _exportingLibrary.mirror.qualifiedName + '.' + super.name);
+
+  void updateExports(Map<String, Indexable> libraryExports) {
+    // TODO(efortuna): if this class points to another exported class or type
+    // of some sort, then that reference needs to be updated here.
+    /* these need to be updated:
+    'comment': comment,
+    'type': new List.filled(1, type.toMap()),
+    'annotations': annotations.map((a) => a.toMap()).toList()
+    */
+  }
+}
+
 /// A class containing properties of a Dart method.
 class Method extends Indexable {
 
@@ -1331,6 +1457,33 @@
   }
 }
 
+class ExportedMethod extends Method implements Exported {
+  Library _exportingLibrary;
+
+  ExportedMethod(MethodMirror originalMethod, Library this._exportingLibrary) :
+      super(originalMethod);
+
+  // TODO(efortuna): Refactor this code so the exported items can share this
+  // behavior.
+  String get fileName => path.join(_exportingLibrary.packageName,
+      _exportingLibrary.mirror.qualifiedName + '.' + super.name);
+
+  void updateExports(Map<String, Indexable> libraryExports) {
+    // TODO(efortuna): if this class points to another exported class or type
+    // of some sort, then that reference needs to be updated here.
+    /* these need to be updated:
+    'qualifiedName': qualifiedName,
+    'comment': comment,
+    'commentFrom': commentInheritedFrom,
+    'return': new List.filled(1, returnType.toMap()),
+    'parameters': recurseMap(parameters),
+    'annotations': annotations.map((a) => a.toMap()).toList()
+    */
+  }
+}
+
+
+
 /// A container to categorize methods into the following groups: setters,
 /// getters, constructors, operators, regular methods.
 class MethodGroup {
@@ -1340,8 +1493,27 @@
   Map<String, Method> operators = {};
   Map<String, Method> regularMethods = {};
 
-  void addMethod(MethodMirror mirror) {
-    var method = new Method(mirror);
+  Map<String, Exported> get exported {
+    var exported = {};
+    for (Map<String, Method> group in [setters, getters, constructors,
+      operators, regularMethods]) {
+      exported = _filterMap(exported, group,
+          (value) => value is ExportedMethod);
+    }
+    return exported;
+  }
+
+  /// The optional parameter [containingLibrary] is contains data for variables
+  /// defined at the top level of a library (potentially for exporting
+  /// purposes).
+  void addMethod(MethodMirror mirror, [Library containingLibrary]) {
+    var method;
+    if (containingLibrary != null && mirror.owner.qualifiedName !=
+        containingLibrary.mirror.qualifiedName) {
+      method = new ExportedMethod(mirror, containingLibrary);
+    } else {
+      method = new Method(mirror);
+    }
     entityMap[docName(mirror)] = method;
     if (mirror.isSetter) {
       setters[mirror.simpleName] = method;
@@ -1498,9 +1670,13 @@
   }
   var owner = m.owner;
   if (owner == null) return m.qualifiedName;
-  // For the unnamed constructor we just return the class name.
-  if (m.simpleName == '') return docName(owner);
-  return docName(owner) + '.' + m.simpleName;
+  var simpleName = m.simpleName;
+  if (m is MethodMirror && m.isConstructor) {
+    // We name constructors specially -- including the class name again and a
+    // "-" to separate the constructor from its name (if any).
+    simpleName = '${owner.simpleName}-$simpleName';
+  }
+  return docName(owner) + '.' + simpleName;
 }
 
 /// Remove statics from the map of inherited items before adding them.
diff --git a/pkg/http/README.md b/pkg/http/README.md
new file mode 100644
index 0000000..93d4266
--- /dev/null
+++ b/pkg/http/README.md
@@ -0,0 +1,21 @@
+# http
+
+A composable, Future-based library for making HTTP requests.
+
+This package contains a set of high-level functions and classes that make it
+easy to consume HTTP resources.
+
+**NOTE:** This package currently only works for
+server-side or command-line Dart applications. In other words, if the app
+imports `dart:io`, it can use this package.
+
+## Using
+
+Please see the [API docs][docs] for explanations and examples.
+
+## Filing issues
+
+Please file issues for the http package at [http://dartbug.com/new][bugs].
+
+[bugs]: http://dartbug.com/new
+[docs]: https://api.dartlang.org/docs/channels/dev/latest/http.html
\ No newline at end of file
diff --git a/pkg/http/lib/src/base_client.dart b/pkg/http/lib/src/base_client.dart
index 86925c3..87a4224 100644
--- a/pkg/http/lib/src/base_client.dart
+++ b/pkg/http/lib/src/base_client.dart
@@ -128,7 +128,7 @@
   /// Sends a non-streaming [Request] and returns a non-streaming [Response].
   Future<Response> _sendUnstreamed(String method, url,
       Map<String, String> headers, [body, Encoding encoding]) {
-    return new Future.sync(() {
+    return syncFuture(() {
       if (url is String) url = Uri.parse(url);
       var request = new Request(method, url);
 
diff --git a/pkg/http/lib/src/io_client.dart b/pkg/http/lib/src/io_client.dart
index 6695fb8..b4fa893 100644
--- a/pkg/http/lib/src/io_client.dart
+++ b/pkg/http/lib/src/io_client.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'base_client.dart';
 import 'base_request.dart';
 import 'streamed_response.dart';
@@ -23,7 +25,8 @@
   Future<StreamedResponse> send(BaseRequest request) {
     var stream = request.finalize();
 
-    return _inner.openUrl(request.method, request.url).then((ioRequest) {
+    return Chain.track(_inner.openUrl(request.method, request.url))
+        .then((ioRequest) {
       ioRequest.followRedirects = request.followRedirects;
       ioRequest.maxRedirects = request.maxRedirects;
       ioRequest.contentLength = request.contentLength;
@@ -31,7 +34,7 @@
       request.headers.forEach((name, value) {
         ioRequest.headers.set(name, value);
       });
-      return stream.pipe(ioRequest);
+      return Chain.track(stream.pipe(ioRequest));
     }).then((response) {
       var headers = {};
       response.headers.forEach((key, values) {
diff --git a/pkg/http/lib/src/multipart_file.dart b/pkg/http/lib/src/multipart_file.dart
index 19c03bf..d316e2a 100644
--- a/pkg/http/lib/src/multipart_file.dart
+++ b/pkg/http/lib/src/multipart_file.dart
@@ -9,6 +9,7 @@
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
 
 import 'byte_stream.dart';
 import 'utils.dart';
@@ -93,8 +94,8 @@
       {String filename, ContentType contentType}) {
     if (filename == null) filename = path.basename(filePath);
     var file = new File(filePath);
-    return file.length().then((length) {
-      var stream = new ByteStream(file.openRead());
+    return Chain.track(file.length()).then((length) {
+      var stream = new ByteStream(Chain.track(file.openRead()));
       return new MultipartFile(field, stream, length,
           filename: filename,
           contentType: contentType);
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index 8383959..d3a4307 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -9,6 +9,8 @@
 import 'dart:io';
 import 'dart:typed_data';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'byte_stream.dart';
 
 /// Converts a URL query string (or `application/x-www-form-urlencoded` body)
@@ -36,32 +38,11 @@
 String mapToQuery(Map<String, String> map, {Encoding encoding}) {
   var pairs = <List<String>>[];
   map.forEach((key, value) =>
-      pairs.add([urlEncode(key, encoding: encoding),
-                 urlEncode(value, encoding: encoding)]));
+      pairs.add([Uri.encodeQueryComponent(key, encoding: encoding),
+                 Uri.encodeQueryComponent(value, encoding: encoding)]));
   return pairs.map((pair) => "${pair[0]}=${pair[1]}").join("&");
 }
 
-// TODO(nweiz): get rid of this when issue 12780 is fixed.
-/// URL-encodes [source] using [encoding].
-String urlEncode(String source, {Encoding encoding}) {
-  if (encoding == null) encoding = UTF8;
-  return encoding.encode(source).map((byte) {
-    // Convert spaces to +, like encodeQueryComponent.
-    if (byte == 0x20) return '+';
-    // Pass through digits.
-    if ((byte >= 0x30 && byte < 0x3A) ||
-        // Pass through uppercase letters.
-        (byte >= 0x41 && byte < 0x5B) ||
-        // Pass through lowercase letters.
-        (byte >= 0x61 && byte < 0x7B) ||
-        // Pass through `-._~`.
-        (byte == 0x2D || byte == 0x2E || byte == 0x5F || byte == 0x7E)) {
-      return new String.fromCharCode(byte);
-    }
-    return '%' + byte.toRadixString(16).toUpperCase();
-  }).join();
-}
-
 /// Like [String.split], but only splits on the first occurrence of the pattern.
 /// This will always return an array of two elements or fewer.
 ///
@@ -234,3 +215,6 @@
   }
   return nextElement(null);
 }
+
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
diff --git a/pkg/http/pubspec.yaml b/pkg/http/pubspec.yaml
index 2e2aafa..80018b1 100644
--- a/pkg/http/pubspec.yaml
+++ b/pkg/http/pubspec.yaml
@@ -1,10 +1,11 @@
 name: http
 version: 0.9.0
 author: "Dart Team <misc@dartlang.org>"
-homepage: http://www.dartlang.org
+homepage: https://pub.dartlang.org/packages/http
 description: A composable, Future-based API for making HTTP requests.
 dependencies:
   path: ">=0.9.0 <0.10.0"
+  stack_trace: ">=0.9.0 <0.10.0"
 dev_dependencies:
   unittest: ">=0.9.0 <0.10.0"
 environment:
diff --git a/pkg/observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
index 10378fa..dcb8853 100644
--- a/pkg/observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -315,7 +315,9 @@
   var _foo = 42;
   List log = [];
 
-  noSuchMethod(Invocation invocation) {
+  // TODO(ahe): Remove @reflectable from here (once either of
+  // http://dartbug.com/15408 or http://dartbug.com/15409 are fixed).
+  @reflectable noSuchMethod(Invocation invocation) {
     final name = invocation.memberName;
     log.add(name);
     if (name == #foo && invocation.isGetter) return _foo;
diff --git a/pkg/pkg.status b/pkg/pkg.status
index d9c7d08..e6b3e7b 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -167,6 +167,7 @@
 # printed. Minified versions of these tests exist that test the behavior when
 # minified.
 unittest/test/*_unminified_test: Skip # DO NOT COPY THIS UNLESS YOU WORK ON DART2JS
+unittest/test/mirror_matchers_test: Fail # Issue 15405
 
 [ $compiler == dart2js && $browser ]
 stack_trace/test/vm_test: Fail, OK # VM-specific traces
@@ -347,9 +348,3 @@
 
 [ $runtime == vm && ($system == windows || $system == linux) ]
 watcher/test/*/mac_os_test: Skip
-
-[ $runtime == vm && $system == linux ]
-watcher/test/*/linux_test: Pass, Slow # Issue 14606
-
-[ $runtime == vm && $system == macos ]
-watcher/test/directory_watcher/mac_os_test: Pass, Fail  # Issue 15024
diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart
index f3ad9ea..b9b81bf 100644
--- a/pkg/polymer/lib/src/instance.dart
+++ b/pkg/polymer/lib/src/instance.dart
@@ -24,6 +24,9 @@
 /**
  * The mixin class for Polymer elements. It provides convenience features on top
  * of the custom elements web standard.
+ *
+ * If this class is used as a mixin,
+ * you must call `polymerCreated()` from the body of your constructor.
  */
 abstract class Polymer implements Element, Observable, NodeBindExtension {
   // Fully ported from revision:
@@ -124,6 +127,12 @@
   // TODO(jmesserly): Polymer does not have this feature. Reconcile.
   ShadowRoot getShadowRoot(String customTagName) => _shadowRoots[customTagName];
 
+  /**
+   * If this class is used as a mixin, this method must be called from inside
+   * of the `created()` constructor.
+   *
+   * If this class is a superclass, calling `super.created()` is sufficient.
+   */
   void polymerCreated() {
     if (this.ownerDocument.window != null || alwaysPrepare ||
         _preparingElements > 0) {
diff --git a/pkg/polymer/lib/src/reflected_type.dart b/pkg/polymer/lib/src/reflected_type.dart
index ad11ffb..6486abc 100644
--- a/pkg/polymer/lib/src/reflected_type.dart
+++ b/pkg/polymer/lib/src/reflected_type.dart
@@ -25,7 +25,7 @@
 
 final Symbol _mangledNameField = () {
   var jsClassMirrorMirror = reflect(reflectClass(ClassMirror)).type;
-  for (var name in jsClassMirrorMirror.variables.keys) {
+  for (var name in jsClassMirrorMirror.declarations.keys) {
     if (MirrorSystem.getName(name) == '_mangledName') return name;
   }
 }();
diff --git a/pkg/scheduled_test/lib/scheduled_process.dart b/pkg/scheduled_test/lib/scheduled_process.dart
index 8f91459a..1d46d46 100644
--- a/pkg/scheduled_test/lib/scheduled_process.dart
+++ b/pkg/scheduled_test/lib/scheduled_process.dart
@@ -8,6 +8,8 @@
 import 'dart:convert';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'scheduled_test.dart';
 import 'src/utils.dart';
 import 'src/value_future.dart';
@@ -97,12 +99,12 @@
     _scheduleExceptionCleanup();
 
     var stdoutWithCanceller = _lineStreamWithCanceller(
-        _process.then((p) => p.stdout));
+        _process.then((p) => Chain.track(p.stdout)));
     _stdoutCanceller = stdoutWithCanceller.last;
     _stdoutLog = stdoutWithCanceller.first;
 
     var stderrWithCanceller = _lineStreamWithCanceller(
-        _process.then((p) => p.stderr));
+        _process.then((p) => Chain.track(p.stderr)));
     _stderrCanceller = stderrWithCanceller.last;
     _stderrLog = stderrWithCanceller.first;
 
@@ -150,10 +152,11 @@
         workingDirectory = results[2];
         environment = results[3];
         _updateDescription(executable, arguments);
-        return Process.start(executable,
-                             arguments,
-                             workingDirectory: workingDirectory,
-                             environment: environment).then((process) {
+        return Chain.track(
+            Process.start(executable,
+                          arguments,
+                          workingDirectory: workingDirectory,
+                          environment: environment)).then((process) {
           process.stdin.encoding = UTF8;
           return process;
         });
@@ -169,7 +172,7 @@
     // process is running, we want the schedule to move to the onException
     // queue where the process will be killed, rather than blocking the tasks
     // queue waiting for the process to exit.
-    _process.then((p) => p.exitCode).then((exitCode) {
+    _process.then((p) => Chain.track(p.exitCode)).then((exitCode) {
       if (_endExpected) {
         exitCodeCompleter.complete(exitCode);
         return;
diff --git a/pkg/scheduled_test/lib/scheduled_server.dart b/pkg/scheduled_test/lib/scheduled_server.dart
index 3f2addd..202fdb8 100644
--- a/pkg/scheduled_test/lib/scheduled_server.dart
+++ b/pkg/scheduled_test/lib/scheduled_server.dart
@@ -8,9 +8,12 @@
 import 'dart:collection';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import 'scheduled_test.dart';
 import 'src/scheduled_server/handler.dart';
 import 'src/scheduled_server/safe_http_server.dart';
+import 'src/utils.dart';
 
 typedef Future ScheduledHandler(HttpRequest request);
 
@@ -46,8 +49,8 @@
 
     var scheduledServer;
     scheduledServer = new ScheduledServer._(schedule(() {
-      return SafeHttpServer.bind("127.0.0.1", 0).then((server) {
-        server.listen(scheduledServer._handleRequest,
+      return Chain.track(SafeHttpServer.bind("127.0.0.1", 0)).then((server) {
+        Chain.track(server).listen(scheduledServer._handleRequest,
             onError: currentSchedule.signalError);
         currentSchedule.onComplete.schedule(server.close);
         return server;
@@ -89,7 +92,7 @@
   /// responsibility to check that the method/path are correct and that it's
   /// being run at the correct time.
   void _handleRequest(HttpRequest request) {
-    wrapFuture(new Future.sync(() {
+    wrapFuture(syncFuture(() {
       if (_handlers.isEmpty) {
         fail("'$description' received ${request.method} ${request.uri.path} "
              "when no more requests were expected.");
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index 1be401c..807424f2 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -191,6 +191,7 @@
 
 import 'dart:async';
 
+import 'package:stack_trace/stack_trace.dart';
 import 'package:unittest/unittest.dart' as unittest;
 
 import 'src/schedule.dart';
@@ -230,22 +231,26 @@
   _ensureInitialized();
   _ensureSetUpForTopLevel();
   testFn(description, () {
-    var asyncDone = unittest.expectAsync0(() {});
-    return currentSchedule.run(() {
-      if (_setUpFn != null) _setUpFn();
-      body();
-    }).then((_) {
-      // If we got here, the test completed successfully so tell unittest so.
-      asyncDone();
-    }).catchError((e) {
+    var completer = new Completer();
+
+    Chain.capture(() {
+      _currentSchedule = new Schedule();
+      return currentSchedule.run(() {
+        if (_setUpFn != null) _setUpFn();
+        body();
+      }).then(completer.complete);
+    }, onError: (e, chain) {
       if (e is ScheduleError) {
         assert(e.schedule.errors.contains(e));
         assert(e.schedule == currentSchedule);
         unittest.registerException(e.schedule.errorString());
       } else {
-        unittest.registerException(e);
+        unittest.registerException(e, chain);
       }
+      completer.complete();
     });
+
+    return completer.future;
   });
 }
 
@@ -317,7 +322,6 @@
         throw new StateError('There seems to be another scheduled test '
             'still running.');
       }
-      _currentSchedule = new Schedule();
       if (_setUpFn != null) {
         var parentFn = _setUpFn;
         _setUpFn = () { parentFn(); setUpFn(); };
@@ -332,9 +336,7 @@
     });
   } else {
     unittest.setUp(() {
-      if (currentSchedule == null) {
-        throw new StateError('No schedule allocated.');
-      } else if (_setUpFn != null) {
+      if (_setUpFn != null) {
         var parentFn = _setUpFn;
         _setUpFn = () { parentFn(); setUpFn(); };
       } else {
diff --git a/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
index 1b377ae..6d8705b 100644
--- a/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/directory_descriptor.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
 
 import '../../descriptor.dart';
 import '../../scheduled_test.dart';
@@ -26,7 +27,8 @@
   Future create([String parent]) => schedule(() {
     if (parent == null) parent = defaultRoot;
     var fullPath = path.join(parent, name);
-    return new Directory(fullPath).create(recursive: true).then((_) {
+    return Chain.track(new Directory(fullPath).create(recursive: true))
+        .then((_) {
       return Future.wait(
           contents.map((entry) => entry.create(fullPath)).toList());
     });
@@ -43,7 +45,7 @@
     }
 
     return Future.wait(contents.map((entry) {
-      return new Future.sync(() => entry.validateNow(fullPath))
+      return syncFuture(() => entry.validateNow(fullPath))
           .then((_) => null)
           .catchError((e) => e);
     })).then((results) {
@@ -54,7 +56,7 @@
   }
 
   Stream<List<int>> load(String pathToLoad) {
-    return futureStream(new Future.value().then((_) {
+    return futureStream(syncFuture(() {
       if (path.posix.isAbsolute(pathToLoad)) {
         throw new ArgumentError("Can't load absolute path '$pathToLoad'.");
       }
diff --git a/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
index 9111b3d..515f6e4 100644
--- a/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/file_descriptor.dart
@@ -10,6 +10,7 @@
 import 'dart:math' as math;
 
 import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
 
 import '../../descriptor.dart';
 import '../../scheduled_test.dart';
@@ -49,7 +50,8 @@
 
   Future create([String parent]) => schedule(() {
     if (parent == null) parent = defaultRoot;
-    return new File(path.join(parent, name)).writeAsBytes(contents);
+    return Chain.track(new File(path.join(parent, name))
+        .writeAsBytes(contents));
   }, "creating file '$name'");
 
   Future validate([String parent]) =>
@@ -62,7 +64,7 @@
       fail("File not found: '$fullPath'.");
     }
 
-    return new File(fullPath).readAsBytes().then(_validateNow);
+    return Chain.track(new File(fullPath).readAsBytes()).then(_validateNow);
   }
 
   // TODO(nweiz): rather than setting up an inheritance chain, just store a
diff --git a/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
index 590a1ce..8303117 100644
--- a/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/nothing_descriptor.dart
@@ -11,6 +11,7 @@
 
 import '../../descriptor.dart';
 import '../../scheduled_test.dart';
+import '../utils.dart';
 
 /// A descriptor that validates that no file exists with the given name.
 /// Creating this descriptor is a no-op and loading from it is invalid.
@@ -23,7 +24,7 @@
   Future validate([String parent]) => schedule(() => validateNow(parent),
       "validating '$name' doesn't exist");
 
-  Future validateNow([String parent]) => new Future.sync(() {
+  Future validateNow([String parent]) => syncFuture(() {
     if (parent == null) parent = defaultRoot;
     var fullPath = path.join(parent, name);
     if (new File(fullPath).existsSync()) {
diff --git a/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
index 130cfdd..4ce8602 100644
--- a/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
+++ b/pkg/scheduled_test/lib/src/descriptor/pattern_descriptor.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
 
 import '../../descriptor.dart';
 import '../../scheduled_test.dart';
@@ -112,5 +113,6 @@
   }
 
   Future create([String parent]) => new Future.error(
-      new UnsupportedError("Pattern descriptors don't support create()."));
+      new UnsupportedError("Pattern descriptors don't support create()."),
+      new Chain.current());
 }
diff --git a/pkg/scheduled_test/lib/src/schedule.dart b/pkg/scheduled_test/lib/src/schedule.dart
index 7cc30fb..5bf5947 100644
--- a/pkg/scheduled_test/lib/src/schedule.dart
+++ b/pkg/scheduled_test/lib/src/schedule.dart
@@ -426,7 +426,7 @@
     }
 
     var task = new Task(() {
-      return new Future.sync(fn).catchError((e, stackTrace) {
+      return syncFuture(fn).catchError((e, stackTrace) {
         throw new ScheduleError.from(_schedule, e, stackTrace: stackTrace);
       });
     }, description, this);
@@ -495,15 +495,15 @@
       _schedule.currentQueue != this || pendingCallbacks.isEmpty;
 
     _totalCallbacks++;
-    var trace = new Trace.current();
+    var chain = new Chain.current();
     var pendingCallback = new PendingCallback._(() {
       var fullDescription = description;
       if (fullDescription == null) {
         fullDescription = "Out-of-band operation #${_totalCallbacks}";
       }
 
-      var stackString = prefixLines(terseTraceString(trace));
-      fullDescription += "\n\nStack trace:\n$stackString";
+      var stackString = prefixLines(terseTraceString(chain));
+      fullDescription += "\n\nStack chain:\n$stackString";
       return fullDescription;
     });
     _pendingCallbacks.add(pendingCallback);
diff --git a/pkg/scheduled_test/lib/src/schedule_error.dart b/pkg/scheduled_test/lib/src/schedule_error.dart
index 264a0aa..5b273fd 100644
--- a/pkg/scheduled_test/lib/src/schedule_error.dart
+++ b/pkg/scheduled_test/lib/src/schedule_error.dart
@@ -4,8 +4,6 @@
 
 library schedule_error;
 
-import 'dart:async';
-
 import 'package:stack_trace/stack_trace.dart';
 
 import 'schedule.dart';
@@ -18,7 +16,7 @@
   final error;
 
   /// The stack trace that was attached to the error. Can be `null`.
-  final stackTrace;
+  final StackTrace stackTrace;
 
   /// The schedule during which this error occurred.
   final Schedule schedule;
@@ -53,16 +51,12 @@
       stackTrace = error.stackTrace;
     }
 
-    if (stackTrace == null) stackTrace = new Trace.current();
+    if (stackTrace == null) stackTrace = new Chain.current();
     return new ScheduleError(schedule, error, stackTrace);
   }
 
-  // TODO(floitsch): restore StackTrace type when it has been integrated into
-  // the core libraries.
-  ScheduleError(Schedule schedule, error, var stackTrace)
-      : error = error,
-        stackTrace = stackTrace,
-        schedule = schedule,
+  ScheduleError(Schedule schedule, this.error, this.stackTrace)
+      : schedule = schedule,
         task = schedule.currentTask,
         queue = schedule.currentQueue,
         pendingCallbacks = schedule.currentQueue == null ? <PendingCallback>[]
@@ -86,7 +80,7 @@
     }
 
     if (stackTrace != null) {
-      result.write('Stack trace:\n');
+      result.write('Stack chain:\n');
       result.write(prefixLines(terseTraceString(stackTrace)));
       result.write("\n\n");
     }
diff --git a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
index 7241171..fdfcd44 100644
--- a/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_future_matchers.dart
@@ -6,8 +6,6 @@
 
 import 'dart:async';
 
-import 'package:stack_trace/stack_trace.dart';
-
 import '../scheduled_test.dart';
 
 /// Matches a [Future] that completes successfully with a value. Note that this
@@ -62,11 +60,9 @@
       }
     }
 
-    var outerTrace = new Trace.current();
     currentSchedule.wrapFuture(item.then((value) {
       if (_matcher == null) return;
 
-      // TODO(floitsch): we cannot switch traces anymore.
       // If expect throws we might want to be able to switch to the outer trace
       // instead.
       expect(value, _matcher);
diff --git a/pkg/scheduled_test/lib/src/scheduled_server/handler.dart b/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
index 316d536..ecac381 100644
--- a/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_server/handler.dart
@@ -53,7 +53,7 @@
         // between a test failing while waiting for a handler and a test failing
         // while executing a handler.
         chainToCompleter(schedule(() {
-          return new Future.sync(() {
+          return syncFuture(() {
             if (request.method != method || request.uri.path != path) {
               fail("'${server.description}' expected $method $path, "
                    "but got ${request.method} ${request.uri.path}.");
@@ -71,7 +71,7 @@
   /// completing. Otherwise, completes immediately.
   Future _waitForTask() {
     return pumpEventQueue().then((_) {
-      if (currentSchedule.currentTask != _taskBefore) return;
+      if (currentSchedule.currentTask != _taskBefore) return null;
       // If we're one task before the handler was scheduled, wait for that
       // task to complete and pump the event queue so that [ready] will be
       // set.
diff --git a/pkg/scheduled_test/lib/src/substitute_future.dart b/pkg/scheduled_test/lib/src/substitute_future.dart
index d30c936..5c91689 100644
--- a/pkg/scheduled_test/lib/src/substitute_future.dart
+++ b/pkg/scheduled_test/lib/src/substitute_future.dart
@@ -29,8 +29,8 @@
   Future then(onValue(T value), {Function onError}) =>
     _completer.future.then(onValue, onError: onError);
   Future<T> whenComplete(action()) => _completer.future.whenComplete(action);
-  Future timeout(Duration timeLimit, [void onTimeout()]) =>
-    _completer.future.timeout(timeLimit, onTimeout);
+  Future timeout(Duration timeLimit, {void onTimeout()}) =>
+    _completer.future.timeout(timeLimit, onTimeout: onTimeout);
 
   /// Substitutes [newFuture] for the currently wrapped [Future], which is
   /// returned.
diff --git a/pkg/scheduled_test/lib/src/task.dart b/pkg/scheduled_test/lib/src/task.dart
index 997e806..5bd52430 100644
--- a/pkg/scheduled_test/lib/src/task.dart
+++ b/pkg/scheduled_test/lib/src/task.dart
@@ -61,7 +61,7 @@
   Future get result => _resultCompleter.future;
   final _resultCompleter = new Completer();
 
-  final Trace stackTrace;
+  final Chain stackChain;
 
   Task(fn(), String description, TaskQueue queue)
     : this._(fn, description, queue, null, queue.contents.length);
@@ -71,7 +71,7 @@
 
   Task._(fn(), this.description, TaskQueue queue, this.parent, this._id)
       : queue = queue,
-        stackTrace = new Trace.current() {
+        stackChain = new Chain.current() {
     this.fn = () {
       if (state != TaskState.WAITING) {
         throw new StateError("Can't run $state task '$this'.");
@@ -123,12 +123,8 @@
   String toString() => description == null ? "#$_id" : description;
 
   String toStringWithStackTrace() {
-    var result = toString();
-    if (stackTrace != null) {
-      var stackString = prefixLines(terseTraceString(stackTrace));
-      result += "\n\nStack trace:\n$stackString";
-    }
-    return result;
+    var stackString = prefixLines(terseTraceString(stackChain));
+    return "$this\n\nStack chain:\n$stackString";
   }
 
   /// Returns a detailed representation of [queue] with this task highlighted.
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index 7daac77..9cba044 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -31,6 +31,9 @@
   future.then(completer.complete, onError: completer.completeError);
 }
 
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
 /// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
 /// first line is prefixed with that instead.
 String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
@@ -72,10 +75,6 @@
   }
 }
 
-// TODO(nweiz): remove this when issue 8731 is fixed.
-/// Returns a [Stream] that will immediately emit [error] and then close.
-Stream errorStream(error) => new Future.error(error).asStream();
-
 /// Returns a buffered stream that will emit the same values as the stream
 /// returned by [future] once [future] completes.
 ///
@@ -127,12 +126,11 @@
 ///
 /// If the [StreamIterator] has no elements, the result is a state error.
 Future<String> streamIteratorFirst(StreamIterator<String> streamIterator) {
-  StackTrace stackTrace = new Trace.current();
   return streamIterator.moveNext().then((hasNext) {
     if (hasNext) {
       return streamIterator.current;
     } else {
-      return new Future.error(new StateError("No elements"), stackTrace);
+      throw new StateError("No elements");
     }
   });
 }
@@ -233,8 +231,12 @@
 /// Returns a string representation of [trace] that has the core and test frames
 /// folded together.
 String terseTraceString(StackTrace trace) {
-  return new Trace.from(trace).terse.foldFrames((frame) {
-    return frame.package == 'scheduled_test' || frame.package == 'unittest' ||
-        frame.isCore;
-  }).toString().trim();
+  return new Chain(new Chain.forTrace(trace).traces.map((trace) {
+    return trace.foldFrames((frame) {
+      return frame.package == 'scheduled_test' ||
+             frame.package == 'unittest' ||
+             frame.package == 'stack_trace' ||
+             frame.isCore;
+    });
+  })).terse.toString().trim();
 }
diff --git a/pkg/scheduled_test/lib/src/value_future.dart b/pkg/scheduled_test/lib/src/value_future.dart
index 3821feb..b0d458b 100644
--- a/pkg/scheduled_test/lib/src/value_future.dart
+++ b/pkg/scheduled_test/lib/src/value_future.dart
@@ -35,6 +35,6 @@
   Future then(onValue(T value), {Function onError}) =>
     _future.then(onValue, onError: onError);
   Future<T> whenComplete(action()) => _future.whenComplete(action);
-  Future timeout(Duration timeLimit, [void onTimeout()]) =>
-    _future.timeout(timeLimit, onTimeout);
+  Future timeout(Duration timeLimit, {void onTimeout()}) =>
+    _future.timeout(timeLimit, onTimeout: onTimeout);
 }
diff --git a/pkg/scheduled_test/test/metatest.dart b/pkg/scheduled_test/test/metatest.dart
index 18309bd..c8bc601 100644
--- a/pkg/scheduled_test/test/metatest.dart
+++ b/pkg/scheduled_test/test/metatest.dart
@@ -204,7 +204,7 @@
         "description": testCase.description,
         "message": testCase.message,
         "result": testCase.result,
-        "stackTrace": testCase.stackTrace
+        "stackTrace": testCase.stackTrace.toString()
       }).toList()
     });
   }
diff --git a/pkg/scheduled_test/test/scheduled_process_test.dart b/pkg/scheduled_test/test/scheduled_process_test.dart
index 151e917..8ff1533 100644
--- a/pkg/scheduled_test/test/scheduled_process_test.dart
+++ b/pkg/scheduled_test/test/scheduled_process_test.dart
@@ -5,7 +5,6 @@
 library scheduled_process_test;
 
 import 'dart:async';
-import 'dart:convert';
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
diff --git a/pkg/scheduled_test/test/utils.dart b/pkg/scheduled_test/test/utils.dart
index 9bfc913..6fc24f3 100644
--- a/pkg/scheduled_test/test/utils.dart
+++ b/pkg/scheduled_test/test/utils.dart
@@ -25,7 +25,7 @@
 Future timeout(Future input, int milliseconds, onTimeout()) {
   var completer = new Completer();
   var timer = new Timer(new Duration(milliseconds: milliseconds), () {
-    chainToCompleter(new Future.sync(onTimeout), completer);
+    chainToCompleter(syncFuture(onTimeout), completer);
   });
   input.then((value) {
     if (completer.isCompleted) return;
diff --git a/pkg/serialization/lib/serialization.dart b/pkg/serialization/lib/serialization.dart
index aa32bd7..2920d87 100644
--- a/pkg/serialization/lib/serialization.dart
+++ b/pkg/serialization/lib/serialization.dart
@@ -20,12 +20,11 @@
  *      address.street = 'N 34th';
  *      address.city = 'Seattle';
  *      var serialization = new Serialization()
- *          ..addRuleFor(address);
+ *          ..addRuleFor(Address);
  *      Map output = serialization.write(address);
  *
- * This creates a new serialization and adds a rule for address objects. Right
- * now it has to be passed an address instance because of limitations using
- * Address as a literal. Then we ask the [Serialization] to write the address
+ * This creates a new serialization and adds a rule for address objects.
+ * Then we ask the [Serialization] to write the address
  * and we get back a Map which is a [json]able representation of the state of
  * the address and related objects. Note that while the output in this case
  * is a [Map], the type will vary depending on which output format we've told
@@ -35,7 +34,7 @@
  * fields of the address object. We can also specify those fields explicitly.
  *
  *      var serialization = new Serialization()
- *        ..addRuleFor(address,
+ *        ..addRuleFor(Address,
  *            constructor: "create",
  *            constructorFields: ["number", "street"],
  *            fields: ["city"]);
@@ -47,7 +46,7 @@
  * serialized.
  *
  *      var serialization = new Serialization()
- *        ..addRuleFor(address,
+ *        ..addRuleFor(Address,
  *            constructor: "",
  *            excludeFields: ["other", "stuff"]);
  *
@@ -189,7 +188,7 @@
  * [Reader] or [Writer] respectively.
  *
  *     new Serialization()
- *       ..addRuleFor(new Person(), constructorFields: ["name"])
+ *       ..addRuleFor(Person, constructorFields: ["name"])
  *       ..namedObjects['Person'] = reflect(new Person()).type;
  */
 library serialization;
diff --git a/pkg/unittest/lib/mirror_matchers.dart b/pkg/unittest/lib/mirror_matchers.dart
index 7d1597f..25f2b6d 100644
--- a/pkg/unittest/lib/mirror_matchers.dart
+++ b/pkg/unittest/lib/mirror_matchers.dart
@@ -49,10 +49,19 @@
     var mirror = reflect(item);
     var classMirror = mirror.type;
     var symbol = new Symbol(_name);
-    if (!classMirror.getters.containsKey(symbol)) {
+    var candidate = classMirror.declarations[symbol];
+    if (candidate == null) {
       addStateInfo(matchState, {'reason': 'has no property named "$_name"'});
       return false;
     }
+    bool isInstanceField = candidate is VariableMirror && !candidate.isStatic;
+    bool isInstanceGetter =
+        candidate is MethodMirror && candidate.isGetter && !candidate.isStatic;
+    if (!(isInstanceField || isInstanceGetter)) {
+      addStateInfo(matchState, {'reason':
+          'has a member named "$_name", but it is not an instance property'});
+      return false;
+    }
     if (_matcher == null) return true;
     var result = mirror.getField(symbol);
     var resultMatches = _matcher.matches(result.reflectee, matchState);
diff --git a/pkg/unittest/test/mirror_matchers_test.dart b/pkg/unittest/test/mirror_matchers_test.dart
index 4a445ed..2fe0319 100644
--- a/pkg/unittest/test/mirror_matchers_test.dart
+++ b/pkg/unittest/test/mirror_matchers_test.dart
@@ -7,6 +7,13 @@
 
 import 'test_utils.dart';
 
+class C {
+  var instanceField = 1;
+  get instanceGetter => 2;
+  static var staticField = 3;
+  static get staticGetter => 4;
+}
+
 void main() {
 
   initUtils();
@@ -21,5 +28,18 @@
         'Expected: has property "length" which matches <2> '
         'Actual: [3] '
         'Which: has property "length" with value <1>');
+    var c = new C();
+    shouldPass(c, hasProperty('instanceField', 1));
+    shouldPass(c, hasProperty('instanceGetter', 2));
+    shouldFail(c, hasProperty('staticField'), 
+        'Expected: has property "staticField" '
+        'Actual: <Instance of \'C\'> '
+        'Which: has a member named "staticField",'
+        ' but it is not an instance property');
+    shouldFail(c, hasProperty('staticGetter'),
+        'Expected: has property "staticGetter" '
+        'Actual: <Instance of \'C\'> '
+        'Which: has a member named "staticGetter",'
+        ' but it is not an instance property');
   });
 }
\ No newline at end of file
diff --git a/pkg/watcher/lib/src/directory_watcher/linux.dart b/pkg/watcher/lib/src/directory_watcher/linux.dart
index d62c6ef..76558dd 100644
--- a/pkg/watcher/lib/src/directory_watcher/linux.dart
+++ b/pkg/watcher/lib/src/directory_watcher/linux.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 import '../utils.dart';
 import '../watch_event.dart';
 import 'resubscribable.dart';
@@ -56,13 +58,13 @@
   _LinuxDirectoryWatcher(String directory)
       : directory = directory {
     // Batch the inotify changes together so that we can dedup events.
-    var innerStream = new Directory(directory).watch().transform(
-        new BatchedStreamTransformer<FileSystemEvent>());
+    var innerStream = Chain.track(new Directory(directory).watch())
+        .transform(new BatchedStreamTransformer<FileSystemEvent>());
     _listen(innerStream, _onBatch,
         onError: _eventsController.addError,
         onDone: _onDone);
 
-    _listen(new Directory(directory).list(), (entity) {
+    _listen(Chain.track(new Directory(directory).list()), (entity) {
       _entries[entity.path] = new _EntryState(entity is Directory);
       if (entity is! Directory) return;
       _watchSubdir(entity.path);
@@ -157,7 +159,7 @@
     // event for every new file.
     watcher.ready.then((_) {
       if (!isReady || _eventsController.isClosed) return;
-      _listen(new Directory(path).list(recursive: true), (entry) {
+      _listen(Chain.track(new Directory(path).list(recursive: true)), (entry) {
         if (entry is Directory) return;
         _eventsController.add(new WatchEvent(ChangeType.ADD, entry.path));
       }, onError: (error, stackTrace) {
@@ -213,7 +215,7 @@
 
       if (oldState == _EntryState.DIRECTORY) {
         var watcher = _subWatchers.remove(path);
-        if (watcher == null) return;
+        if (watcher == null) continue;
         for (var path in watcher._allFiles) {
           _eventsController.add(new WatchEvent(ChangeType.REMOVE, path));
         }
@@ -247,6 +249,17 @@
   /// Handles the underlying event stream closing, indicating that the directory
   /// being watched was removed.
   void _onDone() {
+    // Most of the time when a directory is removed, its contents will get
+    // individual REMOVE events before the watch stream is closed -- in that
+    // case, [_entries] will be empty here. However, if the directory's removal
+    // is caused by a MOVE, we need to manually emit events.
+    if (isReady) {
+      _entries.forEach((path, state) {
+        if (state == _EntryState.DIRECTORY) return;
+        _eventsController.add(new WatchEvent(ChangeType.REMOVE, path));
+      });
+    }
+
     // The parent directory often gets a close event before the subdirectories
     // are done emitting events. We wait for them to finish before we close
     // [events] so that we can be sure to emit a remove event for every file
diff --git a/pkg/watcher/lib/src/directory_watcher/mac_os.dart b/pkg/watcher/lib/src/directory_watcher/mac_os.dart
index 5b1feb3..90036cc 100644
--- a/pkg/watcher/lib/src/directory_watcher/mac_os.dart
+++ b/pkg/watcher/lib/src/directory_watcher/mac_os.dart
@@ -7,6 +7,9 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:path/path.dart' as p;
+import 'package:stack_trace/stack_trace.dart';
+
 import '../constructable_file_system_event.dart';
 import '../path_set.dart';
 import '../utils.dart';
@@ -21,14 +24,22 @@
 /// succession, it won't report them in the order they occurred. See issue
 /// 14373.
 ///
-/// This also works around issues 14793, 14806, and 14849 in the implementation
-/// of [Directory.watch].
+/// This also works around issues 15458 and 14849 in the implementation of
+/// [Directory.watch].
 class MacOSDirectoryWatcher extends ResubscribableDirectoryWatcher {
+  // TODO(nweiz): remove these when issue 15042 is fixed.
+  static var logDebugInfo = false;
+  static var _count = 0;
+
   MacOSDirectoryWatcher(String directory)
-      : super(directory, () => new _MacOSDirectoryWatcher(directory));
+      : super(directory, () => new _MacOSDirectoryWatcher(directory, _count++));
 }
 
 class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher {
+  // TODO(nweiz): remove these when issue 15042 is fixed.
+  static var _count = 0;
+  final String _id;
+
   final String directory;
 
   Stream<WatchEvent> get events => _eventsController.stream;
@@ -68,21 +79,33 @@
   /// watcher is closed. This does not include [_watchSubscription].
   final _subscriptions = new Set<StreamSubscription>();
 
-  _MacOSDirectoryWatcher(String directory)
+  _MacOSDirectoryWatcher(String directory, int parentId)
       : directory = directory,
-        _files = new PathSet(directory) {
+        _files = new PathSet(directory),
+        _id = "$parentId/${_count++}" {
     _startWatch();
 
-    _listen(new Directory(directory).list(recursive: true),
+    _listen(Chain.track(new Directory(directory).list(recursive: true)),
         (entity) {
       if (entity is! Directory) _files.add(entity.path);
     },
         onError: _emitError,
-        onDone: _readyCompleter.complete,
+        onDone: () {
+      if (MacOSDirectoryWatcher.logDebugInfo) {
+        print("[$_id] watcher is ready, known files:");
+        for (var file in _files.toSet()) {
+          print("[$_id]   ${p.relative(file, from: directory)}");
+        }
+      }
+      _readyCompleter.complete();
+    },
         cancelOnError: true);
   }
 
   void close() {
+    if (MacOSDirectoryWatcher.logDebugInfo) {
+      print("[$_id] watcher is closed");
+    }
     for (var subscription in _subscriptions) {
       subscription.cancel();
     }
@@ -94,26 +117,65 @@
 
   /// The callback that's run when [Directory.watch] emits a batch of events.
   void _onBatch(List<FileSystemEvent> batch) {
+    if (MacOSDirectoryWatcher.logDebugInfo) {
+      print("[$_id] ======== batch:");
+      for (var event in batch) {
+        print("[$_id]   ${_formatEvent(event)}");
+      }
+
+      print("[$_id] known files:");
+      for (var file in _files.toSet()) {
+        print("[$_id]   ${p.relative(file, from: directory)}");
+      }
+    }
+
     batches++;
 
     _sortEvents(batch).forEach((path, events) {
+      var relativePath = p.relative(path, from: directory);
+      if (MacOSDirectoryWatcher.logDebugInfo) {
+        print("[$_id] events for $relativePath:\n");
+        for (var event in events) {
+          print("[$_id]   ${_formatEvent(event)}");
+        }
+      }
+
       var canonicalEvent = _canonicalEvent(events);
       events = canonicalEvent == null ?
           _eventsBasedOnFileSystem(path) : [canonicalEvent];
+      if (MacOSDirectoryWatcher.logDebugInfo) {
+        print("[$_id] canonical event for $relativePath: "
+            "${_formatEvent(canonicalEvent)}");
+        print("[$_id] actionable events for $relativePath: "
+            "${events.map(_formatEvent)}");
+      }
 
       for (var event in events) {
         if (event is FileSystemCreateEvent) {
           if (!event.isDirectory) {
+            // Don't emit ADD events for files or directories that we already
+            // know about. Such an event comes from FSEvents reporting an add
+            // that happened prior to the watch beginning.
+            if (_files.contains(path)) continue;
+
             _emitEvent(ChangeType.ADD, path);
             _files.add(path);
             continue;
           }
 
-          _listen(new Directory(path).list(recursive: true), (entity) {
+          if (_files.containsDir(path)) continue;
+
+          _listen(Chain.track(new Directory(path).list(recursive: true)),
+              (entity) {
             if (entity is Directory) return;
             _emitEvent(ChangeType.ADD, entity.path);
             _files.add(entity.path);
-          }, onError: _emitError, cancelOnError: true);
+          }, onError: (e, stackTrace) {
+            if (MacOSDirectoryWatcher.logDebugInfo) {
+              print("[$_id] got error listing $relativePath: $e");
+            }
+            _emitError(e, stackTrace);
+          }, cancelOnError: true);
         } else if (event is FileSystemModifyEvent) {
           assert(!event.isDirectory);
           _emitEvent(ChangeType.MODIFY, path);
@@ -125,6 +187,10 @@
         }
       }
     });
+
+    if (MacOSDirectoryWatcher.logDebugInfo) {
+      print("[$_id] ======== batch complete");
+    }
   }
 
   /// Sort all the events in a batch into sets based on their path.
@@ -161,34 +227,12 @@
       set.add(event);
     }
 
-    for (var event in batch.where((event) => event is! FileSystemMoveEvent)) {
+    for (var event in batch) {
+      // The Mac OS watcher doesn't emit move events. See issue 14806.
+      assert(event is! FileSystemMoveEvent);
       addEvent(event.path, event);
     }
 
-    // Issue 14806 means that move events can be misleading if they're in the
-    // same batch as another modification of a related file. If they are, we
-    // make the event set empty to ensure we check the state of the filesystem.
-    // Otherwise, treat them as a DELETE followed by an ADD.
-    for (var event in batch.where((event) => event is FileSystemMoveEvent)) {
-      if (eventsForPaths.containsKey(event.path) ||
-          eventsForPaths.containsKey(event.destination)) {
-
-        if (!isInModifiedDirectory(event.path)) {
-          eventsForPaths[event.path] = new Set();
-        }
-        if (!isInModifiedDirectory(event.destination)) {
-          eventsForPaths[event.destination] = new Set();
-        }
-
-        continue;
-      }
-
-      addEvent(event.path, new ConstructableFileSystemDeleteEvent(
-          event.path, event.isDirectory));
-      addEvent(event.destination, new ConstructableFileSystemCreateEvent(
-          event.path, event.isDirectory));
-    }
-
     return eventsForPaths;
   }
 
@@ -209,6 +253,7 @@
 
     var type = batch.first.type;
     var isDir = batch.first.isDirectory;
+    var hadModifyEvent = false;
 
     for (var event in batch.skip(1)) {
       // If one event reports that the file is a directory and another event
@@ -219,7 +264,10 @@
       // safely assume the file was modified after a CREATE or before the
       // REMOVE; otherwise there will also be a REMOVE or CREATE event
       // (respectively) that will be contradictory.
-      if (event is FileSystemModifyEvent) continue;
+      if (event is FileSystemModifyEvent) {
+        hadModifyEvent = true;
+        continue;
+      }
       assert(event is FileSystemCreateEvent || event is FileSystemDeleteEvent);
 
       // If we previously thought this was a MODIFY, we now consider it to be a
@@ -234,13 +282,23 @@
       if (type != event.type) return null;
     }
 
+    // If we got a CREATE event for a file we already knew about, that comes
+    // from FSEvents reporting an add that happened prior to the watch
+    // beginning. If we also received a MODIFY event, we want to report that,
+    // but not the CREATE.
+    if (type == FileSystemEvent.CREATE && hadModifyEvent &&
+        _files.contains(batch.first.path)) {
+      type = FileSystemEvent.MODIFY;
+    }
+
     switch (type) {
       case FileSystemEvent.CREATE:
-        // Issue 14793 means that CREATE events can actually mean DELETE, so we
-        // should always check the filesystem for them.
-        return null;
+        return new ConstructableFileSystemCreateEvent(batch.first.path, isDir);
       case FileSystemEvent.DELETE:
-        return new ConstructableFileSystemDeleteEvent(batch.first.path, isDir);
+        // Issue 15458 means that DELETE events for directories can actually
+        // mean CREATE, so we always check the filesystem for them.
+        if (isDir) return null;
+        return new ConstructableFileSystemCreateEvent(batch.first.path, false);
       case FileSystemEvent.MODIFY:
         return new ConstructableFileSystemModifyEvent(
             batch.first.path, isDir, false);
@@ -261,6 +319,13 @@
     var fileExists = new File(path).existsSync();
     var dirExists = new Directory(path).existsSync();
 
+    if (MacOSDirectoryWatcher.logDebugInfo) {
+      print("[$_id] file existed: $fileExisted");
+      print("[$_id] dir existed: $dirExisted");
+      print("[$_id] file exists: $fileExists");
+      print("[$_id] dir exists: $dirExists");
+    }
+
     var events = [];
     if (fileExisted) {
       if (fileExists) {
@@ -314,8 +379,9 @@
   /// Start or restart the underlying [Directory.watch] stream.
   void _startWatch() {
     // Batch the FSEvent changes together so that we can dedup events.
-    var innerStream = new Directory(directory).watch(recursive: true).transform(
-        new BatchedStreamTransformer<FileSystemEvent>());
+    var innerStream =
+        Chain.track(new Directory(directory).watch(recursive: true))
+        .transform(new BatchedStreamTransformer<FileSystemEvent>());
     _watchSubscription = innerStream.listen(_onBatch,
         onError: _eventsController.addError,
         onDone: _onDone);
@@ -325,10 +391,9 @@
   void _emitEvent(ChangeType type, String path) {
     if (!isReady) return;
 
-    // Don't emit ADD events for files that we already know about. Such an event
-    // probably comes from FSEvents reporting an add that happened prior to the
-    // watch beginning.
-    if (type == ChangeType.ADD && _files.contains(path)) return;
+    if (MacOSDirectoryWatcher.logDebugInfo) {
+      print("[$_id] emitting $type ${p.relative(path, from: directory)}");
+    }
 
     _eventsController.add(new WatchEvent(type, path));
   }
@@ -350,4 +415,23 @@
     }, cancelOnError: cancelOnError);
     _subscriptions.add(subscription);
   }
+
+  // TODO(nweiz): remove this when issue 15042 is fixed.
+  /// Return a human-friendly string representation of [event].
+  String _formatEvent(FileSystemEvent event) {
+    if (event == null) return 'null';
+
+    var path = p.relative(event.path, from: directory);
+    var type = event.isDirectory ? 'directory' : 'file';
+    if (event is FileSystemCreateEvent) {
+      return "create $type $path";
+    } else if (event is FileSystemDeleteEvent) {
+      return "delete $type $path";
+    } else if (event is FileSystemModifyEvent) {
+      return "modify $type $path";
+    } else if (event is FileSystemMoveEvent) {
+      return "move $type $path to "
+          "${p.relative(event.destination, from: directory)}";
+    }
+  }
 }
diff --git a/pkg/watcher/lib/src/directory_watcher/polling.dart b/pkg/watcher/lib/src/directory_watcher/polling.dart
index e50a0c0..684f7aa 100644
--- a/pkg/watcher/lib/src/directory_watcher/polling.dart
+++ b/pkg/watcher/lib/src/directory_watcher/polling.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 
 import 'package:crypto/crypto.dart';
+import 'package:stack_trace/stack_trace.dart';
 
 import '../async_queue.dart';
 import '../stat.dart';
@@ -105,7 +106,7 @@
       _filesToProcess.add(null);
     }
 
-    var stream = new Directory(directory).list(recursive: true);
+    var stream = Chain.track(new Directory(directory).list(recursive: true));
     _listSubscription = stream.listen((entity) {
       assert(!_events.isClosed);
 
@@ -185,7 +186,7 @@
 
   /// Calculates the SHA-1 hash of the file at [path].
   Future<List<int>> _hashFile(String path) {
-    return new File(path).readAsBytes().then((bytes) {
+    return Chain.track(new File(path).readAsBytes()).then((bytes) {
       var sha1 = new SHA1();
       sha1.add(bytes);
       return sha1.close();
diff --git a/pkg/watcher/lib/src/stat.dart b/pkg/watcher/lib/src/stat.dart
index d36eff3..166d789 100644
--- a/pkg/watcher/lib/src/stat.dart
+++ b/pkg/watcher/lib/src/stat.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:stack_trace/stack_trace.dart';
+
 /// A function that takes a file path and returns the last modified time for
 /// the file at that path.
 typedef DateTime MockTimeCallback(String path);
@@ -29,5 +31,5 @@
     return new Future.value(_mockTimeCallback(path));
   }
 
-  return FileStat.stat(path).then((stat) => stat.modified);
+  return Chain.track(FileStat.stat(path)).then((stat) => stat.modified);
 }
diff --git a/pkg/watcher/pubspec.yaml b/pkg/watcher/pubspec.yaml
index b95c7ef..93d8eb4 100644
--- a/pkg/watcher/pubspec.yaml
+++ b/pkg/watcher/pubspec.yaml
@@ -9,6 +9,7 @@
 dependencies:
   crypto: ">=0.9.0 <0.10.0"
   path: ">=0.9.0 <0.10.0"
+  stack_trace: ">=0.9.0 <0.10.0"
 dev_dependencies:
   scheduled_test: ">=0.9.0 <0.10.0"
   unittest: ">=0.9.0 <0.10.0"
diff --git a/pkg/watcher/test/directory_watcher/linux_test.dart b/pkg/watcher/test/directory_watcher/linux_test.dart
index ba69569..f53b272 100644
--- a/pkg/watcher/test/directory_watcher/linux_test.dart
+++ b/pkg/watcher/test/directory_watcher/linux_test.dart
@@ -14,14 +14,7 @@
 
   watcherFactory = (dir) => new LinuxDirectoryWatcher(dir);
 
-  setUp(() {
-    // Increase the timeout because closing a [Directory.watch] stream blocks
-    // the main isolate for a very long time on Goobuntu, as of kernel
-    // 3.2.5-gg1336 (see issue 14606).
-    currentSchedule.timeout *= 3;
-
-    createSandbox();
-  });
+  setUp(createSandbox);
 
   sharedTests();
 
diff --git a/pkg/watcher/test/directory_watcher/mac_os_test.dart b/pkg/watcher/test/directory_watcher/mac_os_test.dart
index 7d31221..8fc2d3e 100644
--- a/pkg/watcher/test/directory_watcher/mac_os_test.dart
+++ b/pkg/watcher/test/directory_watcher/mac_os_test.dart
@@ -2,8 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:async';
-
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:watcher/src/directory_watcher/mac_os.dart';
 import 'package:watcher/watcher.dart';
@@ -13,6 +11,7 @@
 
 main() {
   initConfig();
+  MacOSDirectoryWatcher.logDebugInfo = true;
 
   watcherFactory = (dir) => new MacOSDirectoryWatcher(dir);
 
@@ -52,28 +51,6 @@
     withPermutations((i, j, k) =>
         writeFile("dir/sub/sub-$i/sub-$j/file-$k.txt"));
 
-    // We sleep here because a narrow edge case caused by two interacting bugs
-    // can produce events that aren't expected if we start the watcher too
-    // soon after creating the files above. Here's what happens:
-    //
-    // * We create "dir/sub" and its contents above.
-    //
-    // * We initialize the watcher watching "dir".
-    //
-    // * Due to issue 14373, the watcher can receive native events describing
-    //   the creation of "dir/sub" and its contents despite the fact that they
-    //   occurred before the watcher was started.
-    //
-    // * Usually the above events will occur while the watcher is doing its
-    //   initial scan of "dir/sub" and be ignored, but occasionally they will
-    //   occur afterwards.
-    //
-    // * When processing the bogus CREATE events, the watcher has to assume that
-    //   they could mean something other than CREATE (issue 14793). Thus it
-    //   assumes that the files or directories in question could have changed
-    //   and emits CHANGE events or additional REMOVE/CREATE pairs for them.
-    schedule(() => new Future.delayed(new Duration(seconds: 2)));
-
     startWatcher(dir: "dir");
 
     renameDir("dir/sub", "sub");
diff --git a/pkg/watcher/test/no_subscription/mac_os_test.dart b/pkg/watcher/test/no_subscription/mac_os_test.dart
index 3862134..e0275c4 100644
--- a/pkg/watcher/test/no_subscription/mac_os_test.dart
+++ b/pkg/watcher/test/no_subscription/mac_os_test.dart
@@ -9,32 +9,6 @@
 import 'shared.dart';
 import '../utils.dart';
 
-// This is currently failing due to issue 14793. The reason is fairly complex:
-//
-// 1. As part of the test, an "unwatched.txt" file is created while there are no
-//    active watchers on the containing directory.
-//
-// 2. A watcher is then added.
-//
-// 3. The watcher lists the contents of the directory and notices that
-//    "unwatched.txt" already exists.
-//
-// 4. Since FSEvents reports past changes (issue 14373), the IO event stream
-//    emits a CREATED event for "unwatched.txt".
-//
-// 5. Due to issue 14793, the watcher cannot trust that this is really a CREATED
-//    event and checks the status of "unwatched.txt" on the filesystem against
-//    its internal state.
-//
-// 6. "unwatched.txt" exists on the filesystem and the watcher knows about it
-//    internally as well. It assumes this means that the file was modified.
-//
-// 7. The watcher emits an unexpected MODIFIED event for "unwatched.txt",
-//    causing the test to fail.
-//
-// Once issue 14793 is fixed, this will no longer be the case and the test will
-// work again.
-
 main() {
   initConfig();
 
diff --git a/pkg/watcher/test/no_subscription/shared.dart b/pkg/watcher/test/no_subscription/shared.dart
index de625d5..99172a2 100644
--- a/pkg/watcher/test/no_subscription/shared.dart
+++ b/pkg/watcher/test/no_subscription/shared.dart
@@ -41,16 +41,6 @@
     schedule(() {
       completer = new Completer();
       subscription = watcher.events.listen(wrapAsync((event) {
-        // TODO(nweiz): Remove this when either issue 14373 or 14793 is fixed.
-        // Issue 14373 means that the new [Directory.watch] will emit an event
-        // for "unwatched.txt" being created, and issue 14793 means we have to
-        // check the filesystem, which leads us to assume that the file has been
-        // modified.
-        if (Platform.isMacOS && event.path.endsWith("unwatched.txt")) {
-          expect(event, isWatchEvent(ChangeType.MODIFY, "unwatched.txt"));
-          return;
-        }
-
         // We should get an event for the third file, not the one added while
         // we weren't subscribed.
         expect(event, isWatchEvent(ChangeType.ADD, "added.txt"));
diff --git a/pkg/watcher/test/utils.dart b/pkg/watcher/test/utils.dart
index 567bdb2..a7bd9b6 100644
--- a/pkg/watcher/test/utils.dart
+++ b/pkg/watcher/test/utils.dart
@@ -15,6 +15,9 @@
 import 'package:watcher/src/stat.dart';
 import 'package:watcher/src/utils.dart';
 
+// TODO(nweiz): remove this when issue 15042 is fixed.
+import 'package:watcher/src/directory_watcher/mac_os.dart';
+
 /// The path to the temporary sandbox created for each test. All file
 /// operations are implicitly relative to this directory.
 String _sandboxDir;
@@ -115,6 +118,11 @@
 ///
 /// If [dir] is provided, watches a subdirectory in the sandbox with that name.
 void startWatcher({String dir}) {
+  var testCase = currentTestCase.description;
+  if (MacOSDirectoryWatcher.logDebugInfo) {
+    print("starting watcher for $testCase");
+  }
+
   // We want to wait until we're ready *after* we subscribe to the watcher's
   // events.
   _watcher = createWatcher(dir: dir, waitForReady: false);
@@ -128,6 +136,10 @@
         onError: currentSchedule.signalError);
 
     currentSchedule.onComplete.schedule(() {
+      if (MacOSDirectoryWatcher.logDebugInfo) {
+        print("stopping watcher for $testCase");
+      }
+
       var numEvents = _nextEvent;
       subscription.cancel();
       _nextEvent = 0;
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 9f241b1..2a0e678 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -4,6 +4,7 @@
 
 library builtin;
 import 'dart:io';
+import 'dart:async';
 // import 'root_library'; happens here from C Code
 
 // The root library (aka the script) is imported into this library. The
@@ -91,6 +92,10 @@
   } catch (error) {
     _requestFailed(error);
   }
+  // TODO(floitsch): remove this line. It's just here to push an event on the
+  // event loop so that we invoke the scheduled microtasks. Also remove the
+  // import of dart:async when this line is not needed anymore.
+  Timer.run(() {});
 }
 
 
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index eee4430..ca3d8a3 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -60,9 +60,12 @@
   V(File_GetStdioHandleType, 1)                                                \
   V(File_GetType, 2)                                                           \
   V(File_AreIdentical, 2)                                                      \
+  V(FileSystemWatcher_CloseWatcher, 1)                                         \
+  V(FileSystemWatcher_GetSocketId, 2)                                          \
+  V(FileSystemWatcher_InitWatcher, 0)                                          \
   V(FileSystemWatcher_IsSupported, 0)                                          \
-  V(FileSystemWatcher_ReadEvents, 1)                                           \
-  V(FileSystemWatcher_UnwatchPath, 1)                                          \
+  V(FileSystemWatcher_ReadEvents, 2)                                           \
+  V(FileSystemWatcher_UnwatchPath, 2)                                          \
   V(FileSystemWatcher_WatchPath, 4)                                            \
   V(Logger_PrintString, 1)
 
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index ed010db..d284b2e 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -26,7 +26,9 @@
 const char* DartUtils::kDartExtensionScheme = "dart-ext:";
 const char* DartUtils::kAsyncLibURL = "dart:async";
 const char* DartUtils::kBuiltinLibURL = "dart:builtin";
+const char* DartUtils::kCollectionDevLibURL = "dart:_collection-dev";
 const char* DartUtils::kCoreLibURL = "dart:core";
+const char* DartUtils::kIsolateLibURL = "dart:isolate";
 const char* DartUtils::kIOLibURL = "dart:io";
 const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
 const char* DartUtils::kUriLibURL = "dart:uri";
@@ -678,18 +680,19 @@
 Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
                                                Dart_Handle builtin_lib) {
   // Setup the internal library's 'internalPrint' function.
-  Dart_Handle internal_lib =
-      Dart_LookupLibrary(NewString("dart:_collection-dev"));
-  DART_CHECK_VALID(internal_lib);
   Dart_Handle print = Dart_Invoke(
       builtin_lib, NewString("_getPrintClosure"), 0, NULL);
-  Dart_Handle result = Dart_SetField(internal_lib,
+  Dart_Handle url = NewString(kCollectionDevLibURL);
+  DART_CHECK_VALID(url);
+  Dart_Handle collection_dev_lib = Dart_LookupLibrary(url);
+  DART_CHECK_VALID(collection_dev_lib);
+  Dart_Handle result = Dart_SetField(collection_dev_lib,
                                      NewString("_printClosure"),
                                      print);
   DART_CHECK_VALID(result);
 
   // Setup the 'timer' factory.
-  Dart_Handle url = NewString(kAsyncLibURL);
+  url = NewString(kAsyncLibURL);
   DART_CHECK_VALID(url);
   Dart_Handle async_lib = Dart_LookupLibrary(url);
   DART_CHECK_VALID(async_lib);
@@ -701,8 +704,22 @@
   DART_CHECK_VALID(Dart_Invoke(
       async_lib, NewString("_setTimerFactoryClosure"), 1, args));
 
+  // Setup the 'scheduleImmediate' closure.
+  url = NewString(kIsolateLibURL);
+  DART_CHECK_VALID(url);
+  Dart_Handle isolate_lib = Dart_LookupLibrary(url);
+  DART_CHECK_VALID(isolate_lib);
+  Dart_Handle schedule_immediate_closure =
+      Dart_Invoke(isolate_lib, NewString("_getIsolateScheduleImmediateClosure"),
+                  0, NULL);
+  args[0] = schedule_immediate_closure;
+  DART_CHECK_VALID(Dart_Invoke(
+      async_lib, NewString("_setScheduleImmediateClosure"), 1, args));
+
   // Setup the corelib 'Uri.base' getter.
-  Dart_Handle corelib = Dart_LookupLibrary(NewString("dart:core"));
+  url = NewString(kCoreLibURL);
+  DART_CHECK_VALID(url);
+  Dart_Handle corelib = Dart_LookupLibrary(url);
   DART_CHECK_VALID(corelib);
   Dart_Handle uri_base = Dart_Invoke(
       builtin_lib, NewString("_getUriBaseClosure"), 0, NULL);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index f6ae3ab..3e1dbe9 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -209,7 +209,9 @@
   static const char* kDartExtensionScheme;
   static const char* kAsyncLibURL;
   static const char* kBuiltinLibURL;
+  static const char* kCollectionDevLibURL;
   static const char* kCoreLibURL;
+  static const char* kIsolateLibURL;
   static const char* kIOLibURL;
   static const char* kIOLibPatchURL;
   static const char* kUriLibURL;
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index c7e1969..335238c 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -13,6 +13,7 @@
 #include <string.h>  // NOLINT
 #include <sys/epoll.h>  // NOLINT
 #include <sys/stat.h>  // NOLINT
+#include <sys/timerfd.h>  // NOLINT
 #include <unistd.h>  // NOLINT
 #include <fcntl.h>  // NOLINT
 
@@ -29,7 +30,6 @@
 namespace bin {
 
 static const int kInterruptMessageSize = sizeof(InterruptMessage);
-static const int kInfinityTimeout = -1;
 static const int kTimerId = -1;
 static const int kShutdownId = -2;
 
@@ -134,11 +134,27 @@
   if (status == -1) {
     FATAL("Failed adding interrupt fd to epoll instance");
   }
+  timer_fd_ = TEMP_FAILURE_RETRY(timerfd_create(CLOCK_REALTIME,
+                                                TFD_NONBLOCK | TFD_CLOEXEC));
+  if (epoll_fd_ == -1) {
+    FATAL("Failed creating timerfd file descriptor");
+  }
+  // Register the timer_fd_ with the epoll instance.
+  event.events = EPOLLIN;
+  event.data.fd = timer_fd_;
+  status = TEMP_FAILURE_RETRY(epoll_ctl(epoll_fd_,
+                                        EPOLL_CTL_ADD,
+                                        timer_fd_,
+                                        &event));
+  if (status == -1) {
+    FATAL("Failed adding timerfd fd to epoll instance");
+  }
 }
 
 
 EventHandlerImplementation::~EventHandlerImplementation() {
   TEMP_FAILURE_RETRY(close(epoll_fd_));
+  TEMP_FAILURE_RETRY(close(timer_fd_));
   TEMP_FAILURE_RETRY(close(interrupt_fds_[0]));
   TEMP_FAILURE_RETRY(close(interrupt_fds_[1]));
 }
@@ -191,6 +207,14 @@
   for (ssize_t i = 0; i < bytes / kInterruptMessageSize; i++) {
     if (msg[i].id == kTimerId) {
       timeout_queue_.UpdateTimeout(msg[i].dart_port, msg[i].data);
+      struct itimerspec it;
+      memset(&it, 0, sizeof(it));
+      if (timeout_queue_.HasTimeout()) {
+        int64_t millis = timeout_queue_.CurrentTimeout();
+        it.it_value.tv_sec = millis / 1000;
+        it.it_value.tv_nsec = (millis % 1000) * 1000000;
+      }
+      timerfd_settime(timer_fd_, TFD_TIMER_ABSTIME, &it, NULL);
     } else if (msg[i].id == kShutdownId) {
       shutdown_ = true;
     } else {
@@ -338,6 +362,13 @@
   for (int i = 0; i < size; i++) {
     if (events[i].data.ptr == NULL) {
       interrupt_seen = true;
+    } else if (events[i].data.fd == timer_fd_) {
+      int64_t val;
+      VOID_TEMP_FAILURE_RETRY(read(timer_fd_, &val, sizeof(val)));
+      if (timeout_queue_.HasTimeout()) {
+        DartUtils::PostNull(timeout_queue_.CurrentPort());
+        timeout_queue_.RemoveCurrent();
+      }
     } else {
       SocketData* sd = reinterpret_cast<SocketData*>(events[i].data.ptr);
       intptr_t event_mask = GetPollEvents(events[i].events, sd);
@@ -359,29 +390,6 @@
 }
 
 
-int64_t EventHandlerImplementation::GetTimeout() {
-  if (!timeout_queue_.HasTimeout()) {
-    return kInfinityTimeout;
-  }
-  int64_t millis = timeout_queue_.CurrentTimeout() -
-      TimerUtils::GetCurrentTimeMilliseconds();
-  return (millis < 0) ? 0 : millis;
-}
-
-
-void EventHandlerImplementation::HandleTimeout() {
-  if (timeout_queue_.HasTimeout()) {
-    int64_t millis = timeout_queue_.CurrentTimeout() -
-        TimerUtils::GetCurrentTimeMilliseconds();
-    if (millis <= 0) {
-      DartUtils::PostNull(timeout_queue_.CurrentPort());
-      // Remove current from queue.
-      timeout_queue_.RemoveCurrent();
-    }
-  }
-}
-
-
 void EventHandlerImplementation::Poll(uword args) {
   static const intptr_t kMaxEvents = 16;
   struct epoll_event events[kMaxEvents];
@@ -389,20 +397,15 @@
   EventHandlerImplementation* handler_impl = &handler->delegate_;
   ASSERT(handler_impl != NULL);
   while (!handler_impl->shutdown_) {
-    int64_t millis = handler_impl->GetTimeout();
-    ASSERT(millis == kInfinityTimeout || millis >= 0);
-    if (millis > kMaxInt32) millis = kMaxInt32;
     intptr_t result = TEMP_FAILURE_RETRY(epoll_wait(handler_impl->epoll_fd_,
                                                     events,
                                                     kMaxEvents,
-                                                    millis));
+                                                    -1));
     ASSERT(EAGAIN == EWOULDBLOCK);
-    if (result == -1) {
+    if (result <= 0) {
       if (errno != EWOULDBLOCK) {
         perror("Poll failed");
       }
-    } else if (result == 0) {
-      handler_impl->HandleTimeout();
     } else {
       handler_impl->HandleEvents(events, result);
     }
diff --git a/runtime/bin/eventhandler_linux.h b/runtime/bin/eventhandler_linux.h
index 6a96aa2..2e811e8 100644
--- a/runtime/bin/eventhandler_linux.h
+++ b/runtime/bin/eventhandler_linux.h
@@ -102,9 +102,7 @@
   void Shutdown();
 
  private:
-  int64_t GetTimeout();
   void HandleEvents(struct epoll_event* events, int size);
-  void HandleTimeout();
   static void Poll(uword args);
   void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
   void HandleInterruptFd();
@@ -118,6 +116,7 @@
   bool shutdown_;
   int interrupt_fds_[2];
   int epoll_fd_;
+  int timer_fd_;
 };
 
 }  // namespace bin
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 9f1f6d0..68612a5 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -20,6 +20,7 @@
   /* patch */ static int _openStdio(int fd) native "File_OpenStdio";
 }
 
+
 patch class _RandomAccessFile {
   /* patch */ static int _close(int id) native "File_Close";
   /* patch */ static _readByte(int id) native "File_ReadByte";
@@ -37,52 +38,125 @@
   /* patch */ static _flush(int id) native "File_Flush";
 }
 
-patch class _FileSystemWatcher {
-  /* patch */ factory _FileSystemWatcher(
-      String path, int events, bool recursive)
-    => new _FileSystemWatcherImpl(path, events, recursive);
 
-  /* patch */ static bool get isSupported => _FileSystemWatcherImpl.isSupported;
+class _WatcherPath {
+  final int pathId;
+  final String path;
+  final int events;
+  int count = 0;
+  _WatcherPath(this.pathId, this.path, this.events);
 }
 
-class _FileSystemWatcherImpl
-    extends NativeFieldWrapperClass1
-    implements _FileSystemWatcher {
+
+patch class _FileSystemWatcher {
+  static int _id;
+  static final Map<int, _WatcherPath> _idMap = {};
+
   final String _path;
   final int _events;
   final bool _recursive;
 
-  StreamController _controller;
-  StreamSubscription _subscription;
+  _WatcherPath _watcherPath;
 
-  _FileSystemWatcherImpl(this._path, this._events, this._recursive) {
-    if (!isSupported) {
-      throw new FileSystemException(
-          "File system watching is not supported on this system",
-          _path);
+  StreamController _broadcastController;
+
+  /* patch */ static Stream<FileSystemEvent> watch(
+      String path, int events, bool recursive) {
+    if (Platform.isLinux) {
+      return new _InotifyFileSystemWatcher(path, events, recursive).stream;
     }
-    _controller = new StreamController.broadcast(onListen: _listen,
-                                                 onCancel: _cancel);
+    if (Platform.isWindows) {
+      return new _Win32FileSystemWatcher(path, events, recursive).stream;
+    }
+    if (Platform.isMacOS) {
+      return new _FSEventStreamFileSystemWatcher(
+          path, events, recursive).stream;
+    }
+    throw new FileSystemException(
+        "File system watching is not supported on this platform");
   }
 
+  _FileSystemWatcher._(this._path, this._events, this._recursive) {
+    if (!isSupported) {
+      throw new FileSystemException(
+          "File system watching is not supported on this platform",
+          _path);
+    }
+    _broadcastController = new StreamController.broadcast(onListen: _listen,
+                                                          onCancel: _cancel);
+  }
+
+  Stream get stream => _broadcastController.stream;
+
   void _listen() {
-    int socketId;
+    if (_id == null) {
+      try {
+        _id = _initWatcher();
+        _newWatcher();
+      } catch (e) {
+        _broadcastController.addError(new FileSystemException(
+            "Failed to initialize file system entity watcher"));
+        _broadcastController.close();
+        return;
+      }
+    }
+    var pathId;
     try {
-      socketId = _watchPath(_path, _events, identical(true, _recursive));
+      pathId = _watchPath(_id, _path, _events, _recursive);
     } catch (e) {
-      _controller.addError(new FileSystemException(
+      _broadcastController.addError(new FileSystemException(
           "Failed to watch path", _path, e));
-      _controller.close();
+      _broadcastController.close();
       return;
     }
+    if (!_idMap.containsKey(pathId)) {
+      _idMap[pathId] = new _WatcherPath(pathId, _path, _events);
+    }
+    _watcherPath = _idMap[pathId];
+    _watcherPath.count++;
+    _pathWatched().pipe(_broadcastController);
+  }
+
+  void _cancel() {
+    if (_watcherPath != null) {
+      assert(_watcherPath.count > 0);
+      _watcherPath.count--;
+      if (_watcherPath.count == 0) {
+        _pathWatchedEnd();
+        _unwatchPath(_id, _watcherPath.pathId);
+        _idMap.remove(_watcherPath.pathId);
+      }
+      _watcherPath = null;
+    }
+    if (_idMap.isEmpty && _id != null) {
+      _closeWatcher(_id);
+      _doneWatcher();
+      _id = null;
+    }
+  }
+
+  // Called when (and after) a new watcher instance is created and available.
+  void _newWatcher() {}
+  // Called when a watcher is no longer needed.
+  void _doneWatcher() {}
+  // Called when a new path is being watched.
+  Stream _pathWatched() {}
+  // Called when a path is no longer being watched.
+  void _donePathWatched() {}
+
+  static _WatcherPath _pathFromPathId(int pathId) {
+    return _idMap[pathId];
+  }
+
+  static Stream _listenOnSocket(int socketId, int id, int pathId) {
     var socket = new _RawSocket(new _NativeSocket.watch(socketId));
-    _subscription = socket.expand((event) {
-      bool stop = false;
+    return socket.expand((event) {
+      var stops = [];
       var events = [];
       var pair = {};
       if (event == RawSocketEvent.READ) {
         String getPath(event) {
-          var path = _path;
+          var path = _pathFromPathId(event[4]).path;
           if (event[2] != null && event[2].isNotEmpty) {
             path += Platform.pathSeparator;
             path += event[2];
@@ -96,87 +170,190 @@
           }
           return (event[0] & FileSystemEvent._IS_DIR) != 0;
         }
-        void add(event) {
-          if ((event.type & _events) == 0) return;
-          events.add(event);
+        void add(id, event) {
+          if ((event.type & _pathFromPathId(id).events) == 0) return;
+          events.add([id, event]);
         }
         void rewriteMove(event, isDir) {
           if (event[3]) {
-            add(new FileSystemCreateEvent._(getPath(event), isDir));
+            add(event[4], new FileSystemCreateEvent._(getPath(event), isDir));
           } else {
-            add(new FileSystemDeleteEvent._(getPath(event), isDir));
+            add(event[4], new FileSystemDeleteEvent._(getPath(event), isDir));
           }
         }
         while (socket.available() > 0) {
-          for (var event in _readEvents()) {
+          for (var event in _readEvents(id, pathId)) {
             if (event == null) continue;
+            int pathId = event[4];
             bool isDir = getIsDir(event);
             var path = getPath(event);
             if ((event[0] & FileSystemEvent.CREATE) != 0) {
-              add(new FileSystemCreateEvent._(path, isDir));
+              add(event[4], new FileSystemCreateEvent._(path, isDir));
             }
             if ((event[0] & FileSystemEvent.MODIFY) != 0) {
-              add(new FileSystemModifyEvent._(path, isDir, true));
+              add(event[4], new FileSystemModifyEvent._(path, isDir, true));
             }
             if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
-              add(new FileSystemModifyEvent._(path, isDir, false));
+              add(event[4], new FileSystemModifyEvent._(path, isDir, false));
             }
             if ((event[0] & FileSystemEvent.MOVE) != 0) {
               int link = event[1];
               if (link > 0) {
-                if (pair.containsKey(link)) {
-                  events.add(new FileSystemMoveEvent._(
-                      getPath(pair[link]), isDir, path));
-                  pair.remove(link);
+                pair.putIfAbsent(pathId, () => {});
+                if (pair[pathId].containsKey(link)) {
+                  add(event[4],
+                      new FileSystemMoveEvent._(
+                          getPath(pair[pathId][link]), isDir, path));
+                  pair[pathId].remove(link);
                 } else {
-                  pair[link] = event;
+                  pair[pathId][link] = event;
                 }
               } else {
                 rewriteMove(event, isDir);
               }
             }
             if ((event[0] & FileSystemEvent.DELETE) != 0) {
-              add(new FileSystemDeleteEvent._(path, isDir));
+              add(event[4], new FileSystemDeleteEvent._(path, isDir));
             }
             if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
-              add(new FileSystemDeleteEvent._(path, isDir));
-              stop = true;
+              add(event[4], new FileSystemDeleteEvent._(path, isDir));
+              // Signal done event.
+              stops.add([event[4], null]);
             }
           }
         }
-        for (var event in pair.values) {
-          rewriteMove(event, getIsDir(event));
+        for (var map in pair.values) {
+          for (var event in map.values) {
+            rewriteMove(event, getIsDir(event));
+          }
         }
       } else if (event == RawSocketEvent.CLOSED) {
       } else if (event == RawSocketEvent.READ_CLOSED) {
       } else {
         assert(false);
       }
-      if (stop) socket.close();
+      events.addAll(stops);
       return events;
-    })
-    .listen(_controller.add, onDone: _cancel);
+    });
   }
 
-  void _cancel() {
-    if (_subscription != null) {
-      _unwatchPath();
-      _subscription.cancel();
-      _subscription = null;
+  /* patch */ static bool get isSupported
+      native "FileSystemWatcher_IsSupported";
+
+  static int _initWatcher() native "FileSystemWatcher_InitWatcher";
+  static void _closeWatcher(int id) native "FileSystemWatcher_CloseWatcher";
+
+  static int _watchPath(int id, String path, int events, bool recursive)
+      native "FileSystemWatcher_WatchPath";
+  static void _unwatchPath(int id, int path_id)
+      native "FileSystemWatcher_UnwatchPath";
+  static List _readEvents(int id, int path_id)
+      native "FileSystemWatcher_ReadEvents";
+  static int _getSocketId(int id, int path_id)
+      native "FileSystemWatcher_GetSocketId";
+}
+
+
+class _InotifyFileSystemWatcher extends _FileSystemWatcher {
+  static final Map<int, StreamController> _idMap = {};
+  static StreamSubscription _subscription;
+
+  _InotifyFileSystemWatcher(path, events, recursive)
+      : super._(path, events, recursive);
+
+  void _newWatcher() {
+    int id = _FileSystemWatcher._id;
+    _subscription = _FileSystemWatcher._listenOnSocket(id, id, 0)
+      .listen((event) {
+        if (_idMap.containsKey(event[0])) {
+          if (event[1] != null) {
+            _idMap[event[0]].add(event[1]);
+          } else {
+            _idMap[event[0]].close();
+          }
+        }
+      });
+  }
+
+  void _doneWatcher() {
+    _subscription.cancel();
+  }
+
+  Stream _pathWatched() {
+    var pathId = _watcherPath.pathId;
+    if (!_idMap.containsKey(pathId)) {
+      _idMap[pathId] = new StreamController.broadcast();
     }
+    return _idMap[pathId].stream;
+  }
+
+  void _pathWatchedEnd() {
+    var pathId = _watcherPath.pathId;
+    if (!_idMap.containsKey(pathId)) return;
+    _idMap[pathId].close();
+    _idMap.remove(pathId);
+  }
+}
+
+
+class _Win32FileSystemWatcher extends _FileSystemWatcher {
+  StreamSubscription _subscription;
+  StreamController _controller;
+
+  _Win32FileSystemWatcher(path, events, recursive)
+      : super._(path, events, recursive);
+
+  Stream _pathWatched() {
+    var pathId = _watcherPath.pathId;
+    _controller = new StreamController();
+    _subscription = _FileSystemWatcher._listenOnSocket(pathId, 0, pathId)
+        .listen((event) {
+          assert(event[0] == pathId);
+          if (event[1] != null) {
+            _controller.add(event[1]);
+          } else {
+            _controller.close();
+          }
+        });
+    return _controller.stream;
+  }
+
+  void _pathWatchedEnd() {
+    _subscription.cancel();
     _controller.close();
   }
-
-  Stream<FileSystemEvent> get stream => _controller.stream;
-
-  static bool get isSupported native "FileSystemWatcher_IsSupported";
-
-  int _watchPath(String path, int events, bool recursive)
-      native "FileSystemWatcher_WatchPath";
-  void _unwatchPath() native "FileSystemWatcher_UnwatchPath";
-  List _readEvents() native "FileSystemWatcher_ReadEvents";
 }
 
+
+class _FSEventStreamFileSystemWatcher extends _FileSystemWatcher {
+  StreamSubscription _subscription;
+  StreamController _controller;
+
+  _FSEventStreamFileSystemWatcher(path, events, recursive)
+      : super._(path, events, recursive);
+
+  Stream _pathWatched() {
+    var pathId = _watcherPath.pathId;
+    var socketId = _FileSystemWatcher._getSocketId(0, pathId);
+    _controller = new StreamController();
+    _subscription = _FileSystemWatcher._listenOnSocket(socketId, 0, pathId)
+        .listen((event) {
+          if (event[1] != null) {
+            _controller.add(event[1]);
+          } else {
+            _controller.close();
+          }
+        });
+    return _controller.stream;
+  }
+
+  void _pathWatchedEnd() {
+    _subscription.cancel();
+    _controller.close();
+  }
+}
+
+
 Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) {
   return new Uint8List.view(source.buffer, offsetInBytes, length);
 }
diff --git a/runtime/bin/file_system_watcher.cc b/runtime/bin/file_system_watcher.cc
index 7893ffb..0260be7 100644
--- a/runtime/bin/file_system_watcher.cc
+++ b/runtime/bin/file_system_watcher.cc
@@ -12,54 +12,57 @@
 namespace dart {
 namespace bin {
 
-static const int kWatcherNativeField = 0;
-
-
-void SetWatcherIdNativeField(Dart_Handle watcher, intptr_t id) {
-  ThrowIfError(Dart_SetNativeInstanceField(watcher, kWatcherNativeField, id));
-}
-
-
-void GetWatcherIdNativeField(Dart_Handle watcher, intptr_t* id) {
-  ThrowIfError(Dart_GetNativeInstanceField(watcher, kWatcherNativeField, id));
-}
-
 void FUNCTION_NAME(FileSystemWatcher_IsSupported)(Dart_NativeArguments args) {
   Dart_SetReturnValue(args, Dart_NewBoolean(FileSystemWatcher::IsSupported()));
 }
 
+
+void FUNCTION_NAME(FileSystemWatcher_InitWatcher)(Dart_NativeArguments args) {
+  Dart_SetReturnValue(args, Dart_NewInteger(FileSystemWatcher::Init()));
+}
+
+
+void FUNCTION_NAME(FileSystemWatcher_CloseWatcher)(Dart_NativeArguments args) {
+  intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+  FileSystemWatcher::Close(id);
+}
+
+
 void FUNCTION_NAME(FileSystemWatcher_WatchPath)(Dart_NativeArguments args) {
-  Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
+  intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
   const char* path = DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
   int events = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
   bool recursive = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
-  intptr_t id = FileSystemWatcher::WatchPath(path, events, recursive);
-  if (id == -1) {
+  intptr_t path_id = FileSystemWatcher::WatchPath(id, path, events, recursive);
+  if (path_id == -1) {
     Dart_ThrowException(DartUtils::NewDartOSError());
-  } else {
-    SetWatcherIdNativeField(watcher, id);
   }
-  intptr_t socket_id = FileSystemWatcher::GetSocketId(id);
-  Dart_SetReturnValue(args, Dart_NewInteger(socket_id));
+  Dart_SetReturnValue(args, Dart_NewInteger(path_id));
 }
 
 
 void FUNCTION_NAME(FileSystemWatcher_UnwatchPath)(Dart_NativeArguments args) {
-  Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
-  intptr_t id;
-  GetWatcherIdNativeField(watcher, &id);
-  FileSystemWatcher::UnwatchPath(id);
+  intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+  intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+  FileSystemWatcher::UnwatchPath(id, path_id);
 }
 
 
 void FUNCTION_NAME(FileSystemWatcher_ReadEvents)(Dart_NativeArguments args) {
-  Dart_Handle watcher = Dart_GetNativeArgument(args, 0);
-  intptr_t id;
-  GetWatcherIdNativeField(watcher, &id);
-  Dart_Handle handle = FileSystemWatcher::ReadEvents(id);
+  intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+  intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+  Dart_Handle handle = FileSystemWatcher::ReadEvents(id, path_id);
   ThrowIfError(handle);
   Dart_SetReturnValue(args, handle);
 }
 
+
+void FUNCTION_NAME(FileSystemWatcher_GetSocketId)(Dart_NativeArguments args) {
+  intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+  intptr_t path_id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
+  int socket_id = FileSystemWatcher::GetSocketId(id, path_id);
+  Dart_SetReturnValue(args, Dart_NewInteger(socket_id));
+}
+
 }  // namespace bin
 }  // namespace dart
diff --git a/runtime/bin/file_system_watcher.h b/runtime/bin/file_system_watcher.h
index 21c334f..6a6164a 100644
--- a/runtime/bin/file_system_watcher.h
+++ b/runtime/bin/file_system_watcher.h
@@ -37,10 +37,15 @@
   };
 
   static bool IsSupported();
-  static intptr_t WatchPath(const char* path, int events, bool recursive);
-  static void UnwatchPath(intptr_t id);
-  static intptr_t GetSocketId(intptr_t id);
-  static Dart_Handle ReadEvents(intptr_t id);
+  static intptr_t Init();
+  static void Close(intptr_t id);
+  static intptr_t WatchPath(intptr_t id,
+                            const char* path,
+                            int events,
+                            bool recursive);
+  static void UnwatchPath(intptr_t id, intptr_t path_id);
+  static intptr_t GetSocketId(intptr_t id, intptr_t path_id);
+  static Dart_Handle ReadEvents(intptr_t id, intptr_t path_id);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FileSystemWatcher);
diff --git a/runtime/bin/file_system_watcher_android.cc b/runtime/bin/file_system_watcher_android.cc
index 5971ed0..96fd325 100644
--- a/runtime/bin/file_system_watcher_android.cc
+++ b/runtime/bin/file_system_watcher_android.cc
@@ -21,42 +21,54 @@
 }
 
 
-intptr_t FileSystemWatcher::WatchPath(const char* path,
-                                      int events,
-                                      bool recursive) {
-  int fd = TEMP_FAILURE_RETRY(inotify_init());
-  if (fd < 0 || !FDUtils::SetCloseOnExec(fd)) {
+intptr_t FileSystemWatcher::Init() {
+  int id = TEMP_FAILURE_RETRY(inotify_init());
+  if (id < 0 || !FDUtils::SetCloseOnExec(id)) {
     return -1;
   }
   // Some systems dosn't support setting this as non-blocking. Since watching
   // internals are kept away from the user, we know it's possible to continue,
   // even if setting non-blocking fails.
-  FDUtils::SetNonBlocking(fd);
-  int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
-  if (events & kCreate) list_events |= IN_CREATE;
-  if (events & kModifyContent) list_events |= IN_MODIFY | IN_ATTRIB;
-  if (events & kDelete) list_events |= IN_DELETE;
-  if (events & kMove) list_events |= IN_MOVE;
-  int path_fd = TEMP_FAILURE_RETRY(inotify_add_watch(fd, path, list_events));
-  if (path_fd < 0) {
-    close(fd);
-    return -1;
-  }
-  return fd;
-}
-
-
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
-  // Nothing to do.
-}
-
-
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
+  FDUtils::SetNonBlocking(id);
   return id;
 }
 
 
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+void FileSystemWatcher::Close(intptr_t id) {
+  USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+                                      const char* path,
+                                      int events,
+                                      bool recursive) {
+  int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
+  if (events & kCreate) list_events |= IN_CREATE;
+  if (events & kModifyContent) list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
+  if (events & kDelete) list_events |= IN_DELETE;
+  if (events & kMove) list_events |= IN_MOVE;
+  int path_id = TEMP_FAILURE_RETRY(inotify_add_watch(id, path, list_events));
+  if (path_id < 0) {
+    return -1;
+  }
+  return path_id;
+}
+
+
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+  VOID_TEMP_FAILURE_RETRY(inotify_rm_watch(id, path_id));
+}
+
+
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+  USE(path_id);
+  return id;
+}
+
+
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+  USE(path_id);
   const intptr_t kEventSize = sizeof(struct inotify_event);
   const intptr_t kBufferSize = kEventSize + NAME_MAX + 1;
   uint8_t buffer[kBufferSize];
@@ -64,33 +76,36 @@
   if (bytes < 0) {
     return DartUtils::NewDartOSError();
   }
-  const intptr_t kMaxCount = kBufferSize / kEventSize + 1;
+  const intptr_t kMaxCount = bytes / kEventSize;
   Dart_Handle events = Dart_NewList(kMaxCount);
   intptr_t offset = 0;
   intptr_t i = 0;
   while (offset < bytes) {
     struct inotify_event* e =
         reinterpret_cast<struct inotify_event*>(buffer + offset);
-    Dart_Handle event = Dart_NewList(4);
-    int mask = 0;
-    if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
-    if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
-    if (e->mask & IN_CREATE) mask |= kCreate;
-    if (e->mask & IN_MOVE) mask |= kMove;
-    if (e->mask & IN_DELETE) mask |= kDelete;
-    if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
-    if (e->mask & IN_ISDIR) mask |= kIsDir;
-    Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
-    Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
-    if (e->len > 0) {
-      Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
-          reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
-    } else {
-      Dart_ListSetAt(event, 2, Dart_Null());
+    if ((e->mask & IN_IGNORED) == 0) {;
+      Dart_Handle event = Dart_NewList(5);
+      int mask = 0;
+      if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
+      if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
+      if (e->mask & IN_CREATE) mask |= kCreate;
+      if (e->mask & IN_MOVE) mask |= kMove;
+      if (e->mask & IN_DELETE) mask |= kDelete;
+      if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
+      if (e->mask & IN_ISDIR) mask |= kIsDir;
+      Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
+      Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
+      if (e->len > 0) {
+        Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
+            reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
+      } else {
+        Dart_ListSetAt(event, 2, Dart_Null());
+      }
+      Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+      Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
+      Dart_ListSetAt(events, i, event);
+      i++;
     }
-    Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
-    Dart_ListSetAt(events, i, event);
-    i++;
     offset += kEventSize + e->len;
   }
   ASSERT(offset == bytes);
diff --git a/runtime/bin/file_system_watcher_linux.cc b/runtime/bin/file_system_watcher_linux.cc
index 4e57446..8706702 100644
--- a/runtime/bin/file_system_watcher_linux.cc
+++ b/runtime/bin/file_system_watcher_linux.cc
@@ -21,40 +21,52 @@
 }
 
 
-intptr_t FileSystemWatcher::WatchPath(const char* path,
-                                      int events,
-                                      bool recursive) {
-  int fd = TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
-  if (fd < 0) return -1;
+intptr_t FileSystemWatcher::Init() {
+  int id = TEMP_FAILURE_RETRY(inotify_init1(IN_CLOEXEC));
+  if (id < 0) return -1;
   // Some systems dosn't support setting this as non-blocking. Since watching
   // internals are kept away from the user, we know it's possible to continue,
   // even if setting non-blocking fails.
-  FDUtils::SetNonBlocking(fd);
+  FDUtils::SetNonBlocking(id);
+  return id;
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+  USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+                                      const char* path,
+                                      int events,
+                                      bool recursive) {
   int list_events = IN_DELETE_SELF | IN_MOVE_SELF;
   if (events & kCreate) list_events |= IN_CREATE;
   if (events & kModifyContent) list_events |= IN_CLOSE_WRITE | IN_ATTRIB;
   if (events & kDelete) list_events |= IN_DELETE;
   if (events & kMove) list_events |= IN_MOVE;
-  int path_fd = TEMP_FAILURE_RETRY(inotify_add_watch(fd, path, list_events));
-  if (path_fd < 0) {
-    close(fd);
+  int path_id = TEMP_FAILURE_RETRY(inotify_add_watch(id, path, list_events));
+  if (path_id < 0) {
     return -1;
   }
-  return fd;
+  return path_id;
 }
 
 
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
-  // Nothing to do.
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+  VOID_TEMP_FAILURE_RETRY(inotify_rm_watch(id, path_id));
 }
 
 
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+  USE(path_id);
   return id;
 }
 
 
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+  USE(path_id);
   const intptr_t kEventSize = sizeof(struct inotify_event);
   const intptr_t kBufferSize = kEventSize + NAME_MAX + 1;
   uint8_t buffer[kBufferSize];
@@ -69,26 +81,29 @@
   while (offset < bytes) {
     struct inotify_event* e =
         reinterpret_cast<struct inotify_event*>(buffer + offset);
-    Dart_Handle event = Dart_NewList(4);
-    int mask = 0;
-    if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
-    if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
-    if (e->mask & IN_CREATE) mask |= kCreate;
-    if (e->mask & IN_MOVE) mask |= kMove;
-    if (e->mask & IN_DELETE) mask |= kDelete;
-    if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
-    if (e->mask & IN_ISDIR) mask |= kIsDir;
-    Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
-    Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
-    if (e->len > 0) {
-      Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
-          reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
-    } else {
-      Dart_ListSetAt(event, 2, Dart_Null());
+    if ((e->mask & IN_IGNORED) == 0) {;
+      Dart_Handle event = Dart_NewList(5);
+      int mask = 0;
+      if (e->mask & IN_CLOSE_WRITE) mask |= kModifyContent;
+      if (e->mask & IN_ATTRIB) mask |= kModefyAttribute;
+      if (e->mask & IN_CREATE) mask |= kCreate;
+      if (e->mask & IN_MOVE) mask |= kMove;
+      if (e->mask & IN_DELETE) mask |= kDelete;
+      if (e->mask & (IN_DELETE_SELF | IN_MOVE_SELF)) mask |= kDeleteSelf;
+      if (e->mask & IN_ISDIR) mask |= kIsDir;
+      Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
+      Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
+      if (e->len > 0) {
+        Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
+            reinterpret_cast<uint8_t*>(e->name), strlen(e->name)));
+      } else {
+        Dart_ListSetAt(event, 2, Dart_Null());
+      }
+      Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
+      Dart_ListSetAt(event, 4, Dart_NewInteger(e->wd));
+      Dart_ListSetAt(events, i, event);
+      i++;
     }
-    Dart_ListSetAt(event, 3, Dart_NewBoolean(e->mask & IN_MOVED_TO));
-    Dart_ListSetAt(events, i, event);
-    i++;
     offset += kEventSize + e->len;
   }
   ASSERT(offset == bytes);
diff --git a/runtime/bin/file_system_watcher_macos.cc b/runtime/bin/file_system_watcher_macos.cc
index 2200b78..c524e36 100644
--- a/runtime/bin/file_system_watcher_macos.cc
+++ b/runtime/bin/file_system_watcher_macos.cc
@@ -42,12 +42,6 @@
 namespace dart {
 namespace bin {
 
-static Mutex* watcher_mutex = new Mutex();
-static Monitor* watcher_monitor = new Monitor();
-
-class FSEventsWatcher;
-static FSEventsWatcher* watcher = NULL;
-
 union FSEvent {
   struct {
     uint32_t exists;
@@ -99,7 +93,7 @@
     FSEventStreamRef ref_;
   };
 
-  FSEventsWatcher() : run_loop_(0), users_(0) {
+  FSEventsWatcher() : run_loop_(0) {
     Thread::Start(Run, reinterpret_cast<uword>(this));
   }
 
@@ -107,6 +101,10 @@
     CFRunLoopStop(run_loop_);
   }
 
+  Monitor& monitor() { return monitor_; }
+
+  bool has_run_loop() const { return run_loop_ != NULL; }
+
   static void TimerCallback(CFRunLoopTimerRef timer, void* context) {
     // Dummy callback to keep RunLoop alive.
   }
@@ -116,9 +114,9 @@
     watcher->run_loop_ = CFRunLoopGetCurrent();
 
     // Notify, as the run-loop is set.
-    watcher_monitor->Enter();
-    watcher_monitor->Notify();
-    watcher_monitor->Exit();
+    watcher->monitor().Enter();
+    watcher->monitor().Notify();
+    watcher->monitor().Exit();
 
     CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
         NULL,
@@ -134,27 +132,6 @@
     CFRunLoopRun();
   }
 
-  static void Increment() {
-    if (watcher == NULL) {
-      watcher_monitor->Enter();
-      watcher = new FSEventsWatcher();
-      while (watcher->run_loop_ == NULL) {
-        watcher_monitor->Wait(Monitor::kNoTimeout);
-      }
-      watcher_monitor->Exit();
-    }
-    watcher->users_++;
-  }
-
-  static void Decrement() {
-    ASSERT(watcher->users_ > 0);
-    watcher->users_--;
-    if (watcher->users_ == 0) {
-      delete watcher;
-      watcher = NULL;
-    }
-  }
-
   Node* AddPath(const char* path, int events, bool recursive) {
     int fds[2];
     VOID_TEMP_FAILURE_RETRY(pipe(fds));
@@ -215,8 +192,8 @@
     }
   }
 
+  Monitor monitor_;
   CFRunLoopRef run_loop_;
-  int users_;
 };
 
 
@@ -226,36 +203,50 @@
 }
 
 
-intptr_t FileSystemWatcher::WatchPath(const char* path,
+intptr_t FileSystemWatcher::Init() {
+  FSEventsWatcher* watcher = new FSEventsWatcher();
+  watcher->monitor().Enter();
+  while (!watcher->has_run_loop()) {
+    watcher->monitor().Wait(1);
+  }
+  watcher->monitor().Exit();
+  return reinterpret_cast<intptr_t>(watcher);
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+  FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id);
+  delete watcher;
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+                                      const char* path,
                                       int events,
                                       bool recursive) {
-  MutexLocker lock(watcher_mutex);
-  FSEventsWatcher::Increment();
-
+  FSEventsWatcher* watcher = reinterpret_cast<FSEventsWatcher*>(id);
   FSEventsWatcher::Node* node = watcher->AddPath(path, events, recursive);
   node->Start();
   return reinterpret_cast<intptr_t>(node);
 }
 
 
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
-  MutexLocker lock(watcher_mutex);
-
-  FSEventsWatcher::Node* node = reinterpret_cast<FSEventsWatcher::Node*>(id);
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+  USE(id);
+  FSEventsWatcher::Node* node =
+      reinterpret_cast<FSEventsWatcher::Node*>(path_id);
   node->Stop();
   delete node;
-
-  FSEventsWatcher::Decrement();
 }
 
 
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
-  return reinterpret_cast<FSEventsWatcher::Node*>(id)->read_fd();
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+  return reinterpret_cast<FSEventsWatcher::Node*>(path_id)->read_fd();
 }
 
 
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
-  intptr_t fd = GetSocketId(id);
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+  intptr_t fd = GetSocketId(id, path_id);
   intptr_t avail = FDUtils::AvailableBytes(fd);
   int count = avail / sizeof(FSEvent);
   if (count <= 0) return Dart_NewList(0);
@@ -267,7 +258,7 @@
       return DartUtils::NewDartOSError();
     }
     size_t path_len = strlen(e.data.path);
-    Dart_Handle event = Dart_NewList(4);
+    Dart_Handle event = Dart_NewList(5);
     int flags = e.data.flags;
     int mask = 0;
     if (flags & kFSEventStreamEventFlagItemRenamed) {
@@ -295,6 +286,7 @@
     Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8(
         reinterpret_cast<uint8_t*>(e.data.path), path_len));
     Dart_ListSetAt(event, 3, Dart_NewBoolean(true));
+    Dart_ListSetAt(event, 4, Dart_NewInteger(path_id));
     Dart_ListSetAt(events, i, event);
   }
   return events;
diff --git a/runtime/bin/file_system_watcher_win.cc b/runtime/bin/file_system_watcher_win.cc
index 9731009..adb2426 100644
--- a/runtime/bin/file_system_watcher_win.cc
+++ b/runtime/bin/file_system_watcher_win.cc
@@ -23,9 +23,21 @@
 }
 
 
-intptr_t FileSystemWatcher::WatchPath(const char* path,
+intptr_t FileSystemWatcher::Init() {
+  return 0;
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+  USE(id);
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+                                      const char* path,
                                       int events,
                                       bool recursive) {
+  USE(id);
   const wchar_t* name = StringUtils::Utf8ToWide(path);
   HANDLE dir = CreateFileW(name,
                            FILE_LIST_DIRECTORY,
@@ -59,19 +71,22 @@
 }
 
 
-void FileSystemWatcher::UnwatchPath(intptr_t id) {
-  // Nothing to do.
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+  USE(id);
+  USE(path_id);
 }
 
 
-intptr_t FileSystemWatcher::GetSocketId(intptr_t id) {
-  return id;
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+  USE(id);
+  return path_id;
 }
 
 
-Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+  USE(id);
   const intptr_t kEventSize = sizeof(FILE_NOTIFY_INFORMATION);
-  DirectoryWatchHandle* dir = reinterpret_cast<DirectoryWatchHandle*>(id);
+  DirectoryWatchHandle* dir = reinterpret_cast<DirectoryWatchHandle*>(path_id);
   intptr_t available = dir->Available();
   intptr_t max_count = available / kEventSize + 1;
   Dart_Handle events = Dart_NewList(max_count);
@@ -83,7 +98,7 @@
     FILE_NOTIFY_INFORMATION* e =
         reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer + offset);
 
-    Dart_Handle event = Dart_NewList(4);
+    Dart_Handle event = Dart_NewList(5);
     int mask = 0;
     if (e->Action == FILE_ACTION_ADDED) mask |= kCreate;
     if (e->Action == FILE_ACTION_REMOVED) mask |= kDelete;
@@ -96,6 +111,7 @@
     Dart_ListSetAt(event, 2, Dart_NewStringFromUTF16(
         reinterpret_cast<uint16_t*>(e->FileName), e->FileNameLength / 2));
     Dart_ListSetAt(event, 3, Dart_NewBoolean(true));
+    Dart_ListSetAt(event, 4, Dart_NewInteger(path_id));
     Dart_ListSetAt(events, i, event);
     i++;
     if (e->NextEntryOffset == 0) break;
diff --git a/runtime/bin/resources.h b/runtime/bin/resources.h
index 6ee066a..02cc967 100644
--- a/runtime/bin/resources.h
+++ b/runtime/bin/resources.h
@@ -8,6 +8,11 @@
 #include <stddef.h>
 #include <string.h>
 
+// Map from Blink to Dart VM.
+#if defined(_DEBUG)
+#define DEBUG
+#endif
+
 #include "platform/assert.h"
 
 
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 0a2547c..6fa0a99 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -585,13 +585,38 @@
       ThrowPRException("TlsException",
                        "Failed NSS_SetDomesticPolicy call.");
     }
-    // Enable TLS, as well as SSL3 and SSL2.
-    status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE);
-    if (status != SECSuccess) {
-      mutex_->Unlock();  // MutexLocker destructor not called when throwing.
-      ThrowPRException("TlsException",
-                       "Failed SSL_OptionSetDefault enable TLS call.");
+
+    // Enable the same additional ciphers that Chromium does.
+    // See NSSSSLInitSingleton() in Chromium's net/socket/nss_ssl_util.cc.
+    // Explicitly enable exactly those ciphers with keys of at least 80 bits.
+    const PRUint16* const ssl_ciphers = SSL_GetImplementedCiphers();
+    const PRUint16 num_ciphers = SSL_GetNumImplementedCiphers();
+    for (int i = 0; i < num_ciphers; i++) {
+      SSLCipherSuiteInfo info;
+      if (SSL_GetCipherSuiteInfo(ssl_ciphers[i], &info, sizeof(info)) ==
+          SECSuccess) {
+        bool enabled = (info.effectiveKeyBits >= 80);
+        // Trim the list of cipher suites in order to keep the size of the
+        // ClientHello down. DSS, ECDH, CAMELLIA, SEED, ECC+3DES, and
+        // HMAC-SHA256 cipher suites are disabled.
+        if (info.symCipher == ssl_calg_camellia ||
+            info.symCipher == ssl_calg_seed ||
+            (info.symCipher == ssl_calg_3des && info.keaType != ssl_kea_rsa) ||
+            info.authAlgorithm == ssl_auth_dsa ||
+            info.macAlgorithm == ssl_hmac_sha256 ||
+            info.nonStandard ||
+            strcmp(info.keaTypeName, "ECDH") == 0) {
+          enabled = false;
+        }
+
+        if (ssl_ciphers[i] == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) {
+          // Enabled to allow servers with only a DSA certificate to function.
+          enabled = true;
+        }
+        SSL_CipherPrefSetDefault(ssl_ciphers[i], enabled);
+      }
     }
+
     status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL);
     if (status != SECSuccess) {
       mutex_->Unlock();  // MutexLocker destructor not called when throwing.
@@ -658,7 +683,7 @@
 
   SSLVersionRange vrange;
   vrange.min = SSL_LIBRARY_VERSION_3_0;
-  vrange.max = SSL_LIBRARY_VERSION_TLS_1_1;
+  vrange.max = SSL_LIBRARY_VERSION_TLS_1_2;
   SSL_VersionRangeSet(filter_, &vrange);
 
   SECStatus status;
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 175d07e..046bd18 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -427,7 +427,7 @@
       for (intptr_t i = 0; i < addresses->count(); i++) {
         InterfaceSocketAddress* interface = addresses->GetAt(i);
         SocketAddress* addr = interface->socket_address();
-        CObjectArray* entry = new CObjectArray(CObject::NewArray(4));
+        CObjectArray* entry = new CObjectArray(CObject::NewArray(5));
 
         CObjectInt32* type = new CObjectInt32(
             CObject::NewInt32(addr->GetType()));
@@ -449,6 +449,10 @@
             interface->interface_name()));
         entry->SetAt(3, interface_name);
 
+        CObjectInt64* interface_index = new CObjectInt64(CObject::NewInt64(
+            interface->interface_index()));
+        entry->SetAt(4, interface_index);
+
         array->SetAt(i + 1, entry);
       }
       result = array;
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 1bec3e6..d4ae826 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -110,9 +110,11 @@
 class InterfaceSocketAddress {
  public:
   explicit InterfaceSocketAddress(struct sockaddr* sa,
-                                  const char* interface_name)
+                                  const char* interface_name,
+                                  intptr_t interface_index)
       : socket_address_(new SocketAddress(sa)),
-        interface_name_(interface_name) {}
+        interface_name_(interface_name),
+        interface_index_(interface_index) {}
 
   ~InterfaceSocketAddress() {
     delete socket_address_;
@@ -121,10 +123,12 @@
 
   SocketAddress* socket_address() const { return socket_address_; }
   const char* interface_name() const { return interface_name_; }
+  int interface_index() const { return interface_index_; }
 
  private:
   SocketAddress* socket_address_;
   const char* interface_name_;
+  intptr_t interface_index_;
 
   DISALLOW_COPY_AND_ASSIGN(InterfaceSocketAddress);
 };
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index c36a66e..e50884b 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -11,6 +11,7 @@
 #include <string.h>  // NOLINT
 #include <sys/stat.h>  // NOLINT
 #include <unistd.h>  // NOLINT
+#include <net/if.h>  // NOLINT
 #include <netinet/tcp.h>  // NOLINT
 #include <ifaddrs.h>  // NOLINT
 
@@ -298,7 +299,7 @@
   for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
     if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
       addresses->SetAt(i, new InterfaceSocketAddress(
-          ifa->ifa_addr, strdup(ifa->ifa_name)));
+          ifa->ifa_addr, strdup(ifa->ifa_name), if_nametoindex(ifa->ifa_name)));
       i++;
     }
   }
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 6568379..b8eef1d 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -11,6 +11,7 @@
 #include <string.h>  // NOLINT
 #include <sys/stat.h>  // NOLINT
 #include <unistd.h>  // NOLINT
+#include <net/if.h>  // NOLINT
 #include <netinet/tcp.h>  // NOLINT
 #include <ifaddrs.h>  // NOLINT
 
@@ -298,7 +299,7 @@
   for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
     if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
       addresses->SetAt(i, new InterfaceSocketAddress(
-          ifa->ifa_addr, strdup(ifa->ifa_name)));
+          ifa->ifa_addr, strdup(ifa->ifa_name), if_nametoindex(ifa->ifa_name)));
       i++;
     }
   }
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 1480f1f..d313a0d 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -197,9 +197,10 @@
 
 class _NetworkInterface implements NetworkInterface {
   final String name;
-  final List<InternetAddress> addresses;
+  final int index;
+  final List<InternetAddress> addresses = [];
 
-  _NetworkInterface(String this.name, List<InternetAddress> this.addresses);
+  _NetworkInterface(this.name, this.index);
 
   String toString() {
     return "NetworkInterface('$name', $addresses)";
@@ -305,23 +306,21 @@
           if (isErrorResponse(response)) {
             throw createError(response, "Failed listing interfaces");
           } else {
-            var list = new List<NetworkInterface>();
             var map = response.skip(1)
-                .fold(new Map<String, List<InternetAddress>>(), (map, result) {
+                .fold(new Map<String, NetworkInterface>(), (map, result) {
                   var type = new InternetAddressType._from(result[0]);
                   var name = result[3];
+                  var index = result[4];
                   var address = new _InternetAddress(
                       type, result[1], "", result[2]);
                   if (!includeLinkLocal && address.isLinkLocal) return map;
                   if (!includeLoopback && address.isLoopback) return map;
-                  map.putIfAbsent(name, () => new List<InternetAddress>());
-                  map[name].add(address);
+                  map.putIfAbsent(
+                      name, () => new _NetworkInterface(name, index));
+                  map[name].addresses.add(address);
                   return map;
-                })
-                .forEach((name, addresses) {
-                  list.add(new _NetworkInterface(name, addresses));
                 });
-            return list;
+            return map.values.toList();
           }
         });
   }
@@ -465,7 +464,7 @@
     var result =
         nativeWrite(bufferAndStart.buffer, bufferAndStart.start, bytes);
     if (result is OSError) {
-      reportError(result, "Write failed");
+      scheduleMicrotask(() => reportError(result, "Write failed"));
       result = 0;
     }
     return result;
@@ -501,6 +500,7 @@
     canActivateEvents = false;
     for (int i = FIRST_EVENT; i <= LAST_EVENT; i++) {
       if (((events & (1 << i)) != 0)) {
+        if ((i == CLOSED_EVENT || i == READ_EVENT) && isClosedRead) continue;
         if (i == CLOSED_EVENT &&
             typeFlags != TYPE_LISTENING_SOCKET &&
             !isClosing &&
@@ -737,6 +737,7 @@
   }
 
   _RawServerSocket(this._socket) {
+    var zone = Zone.current;
     _controller = new StreamController(sync: true,
         onListen: _onSubscriptionStateChange,
         onCancel: _onSubscriptionStateChange,
@@ -744,14 +745,14 @@
         onResume: _onPauseStateChange);
     _socket.closeFuture.then((_) => _controller.close());
     _socket.setHandlers(
-      read: () {
+      read: zone.bindCallback(() {
         var socket = _socket.accept();
         if (socket != null) _controller.add(new _RawSocket(socket));
-      },
-      error: (e) {
+      }),
+      error: zone.bindUnaryCallback((e) {
         _controller.addError(e);
         _controller.close();
-      }
+      })
     );
   }
 
@@ -814,6 +815,7 @@
   }
 
   _RawSocket(this._socket) {
+    var zone = Zone.current;
     _controller = new StreamController(sync: true,
         onListen: _onSubscriptionStateChange,
         onCancel: _onSubscriptionStateChange,
@@ -830,10 +832,10 @@
       },
       closed: () => _controller.add(RawSocketEvent.READ_CLOSED),
       destroyed: () => _controller.add(RawSocketEvent.CLOSED),
-      error: (e) {
+      error: zone.bindUnaryCallback((e) {
         _controller.addError(e);
         close();
-      }
+      })
     );
   }
 
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index d8cd9f9..7610a73 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -329,7 +329,8 @@
          u != NULL; u = u->Next) {
       addresses->SetAt(i, new InterfaceSocketAddress(
           u->Address.lpSockaddr,
-          StringUtils::WideToUtf8(a->FriendlyName)));
+          StringUtils::WideToUtf8(a->FriendlyName),
+          a->Ipv6IfIndex));
       i++;
     }
   }
diff --git a/runtime/bin/vmservice/vmservice_dartium.dart b/runtime/bin/vmservice/vmservice_dartium.dart
new file mode 100644
index 0000000..c1520ec
--- /dev/null
+++ b/runtime/bin/vmservice/vmservice_dartium.dart
@@ -0,0 +1,60 @@
+// 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 vmservice_dartium;
+
+import 'dart:isolate';
+import 'vmservice.dart';
+
+// The receive port that isolate startup / shutdown messages are delivered on.
+RawReceivePort _receivePort;
+// The receive port that service request messages are delivered on.
+RawReceivePort _requestPort;
+
+// The native method that is called to post the response back to DevTools.
+void postResponse(String response, int cookie) native "PostResponse";
+
+void handleRequest(service, String uri, cookie) {
+  var serviceRequest = new ServiceRequest();
+  var r = serviceRequest.parse(Uri.parse(uri));
+  if (!r) {
+    // Did not understand the request uri.
+    serviceRequest.setErrorResponse('Invalid request uri: ${uri}');
+  } else {
+    var f = service.runningIsolates.route(serviceRequest);
+    if (f != null) {
+      f.then((_) {
+        postResponse(serviceRequest.response, cookie);
+      }).catchError((e) { });
+      return;
+    } else {
+      // Nothing responds to this type of request.
+      serviceRequest.setErrorResponse('No route for: $uri');
+    }
+  }
+  postResponse(serviceRequest.response, cookie);
+}
+
+main() {
+  // Create VmService.
+  var service = new VMService();
+  _receivePort = service.receivePort;
+  _requestPort = new RawReceivePort((message) {
+    if (message == null) {
+      return;
+    }
+    if (message is! List) {
+      return;
+    }
+    if (message.length != 2) {
+      return;
+    }
+    var uri = message[0];
+    if (uri is! String) {
+      return;
+    }
+    var cookie = message[1];
+    handleRequest(service, uri, cookie);
+  });
+}
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 46e4f40..3792a5b 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -57,6 +57,24 @@
   StreamController _controller;
 }
 
+typedef void ImmediateCallback();
+
+/// The callback that has been registered through `scheduleImmediate`.
+ImmediateCallback _pendingImmediateCallback;
+
+/// The closure that should be used as scheduleImmediateClosure, when the VM
+/// is responsible for the event loop.
+void _isolateScheduleImmediate(void callback()) {
+  assert(_pendingImmediateCallback == null);
+  _pendingImmediateCallback = callback;
+}
+
+/// The embedder can execute this function to get hold of
+/// [_isolateScheduleImmediate] above.
+Function _getIsolateScheduleImmediateClosure() {
+  return _isolateScheduleImmediate;
+}
+
 class _RawReceivePortImpl implements RawReceivePort {
   factory _RawReceivePortImpl() native "RawReceivePortImpl_factory";
 
@@ -92,7 +110,15 @@
   static void _handleMessage(
       _RawReceivePortImpl port, int replyId, var message) {
     assert(port != null);
+    // TODO(floitsch): this relies on the fact that any exception aborts the
+    // VM. Once we have non-fatal global exceptions we need to catch errors
+    // so that we can run the immediate callbacks.
     port._handler(message);
+    if (_pendingImmediateCallback != null) {
+      var callback = _pendingImmediateCallback;
+      _pendingImmediateCallback = null;
+      callback();
+    }
   }
 
   // Call into the VM to close the VM maintained mappings.
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 8476c15..ec24d3e 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -248,7 +248,7 @@
   Function operator [](Symbol selector) {
     bool found = false;
     for (ClassMirror c = type; c != null; c = c.superclass) {
-      var target = c.methods[selector];
+      var target = c._methods[selector];
       if (target != null && !target.isStatic && target.isRegularMethod) {
         found = true;
         break;
@@ -337,14 +337,6 @@
     return reflect(_apply(arguments, names));
   }
 
-  Future<InstanceMirror> applyAsync(List positionalArguments,
-                                    [Map<Symbol, dynamic> namedArguments]) {
-    return new Future(() {
-      return this.apply(_unwrapAsyncPositionals(positionalArguments),
-                        _unwrapAsyncNamed(namedArguments));
-    });
-  }
-
   InstanceMirror findInContext(Symbol name, {ifAbsent: null}) {
     List<String> parts = _n(name).split(".").toList(growable: false);
     if (parts.length > 3) {
@@ -504,71 +496,41 @@
   Map<Symbol, DeclarationMirror> get declarations {
     if (_declarations != null) return _declarations;
     var decls = new Map<Symbol, DeclarationMirror>();
-    decls.addAll(members);
-    decls.addAll(constructors);
+    decls.addAll(_members);
+    decls.addAll(_constructors);
     typeVariables.forEach((tv) => decls[tv.simpleName] = tv);
     return _declarations =
         new _UnmodifiableMapView<Symbol, DeclarationMirror>(decls);
   }
 
-  Map<Symbol, Mirror> _members;
-  Map<Symbol, Mirror> get members {
-    if (_members == null) {
+  Map<Symbol, Mirror> _cachedMembers;
+  Map<Symbol, Mirror> get _members {
+    if (_cachedMembers == null) {
       var whoseMembers = _isMixinAlias ? _trueSuperclass : this;
-      _members = _makeMemberMap(mixin._computeMembers(whoseMembers._reflectee));
+      _cachedMembers = _makeMemberMap(mixin._computeMembers(whoseMembers._reflectee));
     }
-    return _members;
+    return _cachedMembers;
   }
 
-  Map<Symbol, MethodMirror> _methods;
-  Map<Symbol, MethodMirror> get methods {
-    if (_methods == null) {
-      _methods = _filterMap(
-          members,
+  Map<Symbol, MethodMirror> _cachedMethods;
+  Map<Symbol, MethodMirror> get _methods {
+    if (_cachedMethods == null) {
+      _cachedMethods = _filterMap(
+          _members,
           (key, value) => (value is MethodMirror && value.isRegularMethod));
     }
-    return _methods;
+    return _cachedMethods;
   }
 
-  Map<Symbol, MethodMirror> _getters;
-  Map<Symbol, MethodMirror> get getters {
-    if (_getters == null) {
-      _getters = _filterMap(
-          members,
-          (key, value) => (value is MethodMirror && value.isGetter));
-    }
-    return _getters;
-  }
-
-  Map<Symbol, MethodMirror> _setters;
-  Map<Symbol, MethodMirror> get setters {
-    if (_setters == null) {
-      _setters = _filterMap(
-          members,
-          (key, value) => (value is MethodMirror && value.isSetter));
-    }
-    return _setters;
-  }
-
-  Map<Symbol, VariableMirror> _variables;
-  Map<Symbol, VariableMirror> get variables {
-    if (_variables == null) {
-      _variables = _filterMap(
-          members,
-          (key, value) => (value is VariableMirror));
-    }
-    return _variables;
-  }
-
-  Map<Symbol, MethodMirror> _constructors;
-  Map<Symbol, MethodMirror> get constructors {
-    if (_constructors == null) {
+  Map<Symbol, MethodMirror> _cachedConstructors;
+  Map<Symbol, MethodMirror> get _constructors {
+    if (_cachedConstructors == null) {
       var constructorsList = _computeConstructors(_reflectee);
       var stringName = _n(simpleName);
       constructorsList.forEach((c) => c._patchConstructorName(stringName));
-      _constructors = _makeMemberMap(constructorsList);
+      _cachedConstructors = _makeMemberMap(constructorsList);
     }
-    return _constructors;
+    return _cachedConstructors;
   }
 
   bool get _isAnonymousMixinApplication {
@@ -622,7 +584,7 @@
   String toString() => "ClassMirror on '${MirrorSystem.getName(simpleName)}'";
 
   Function operator [](Symbol selector) {
-    var target = methods[selector];
+    var target = _methods[selector];
     if (target == null || !target.isStatic || !target.isRegularMethod) {
       throw new ArgumentError(
           "${MirrorSystem.getName(simpleName)} has no static method "
@@ -658,16 +620,6 @@
                                       names));
   }
 
-  Future<InstanceMirror> newInstanceAsync(Symbol constructorName,
-                                          List positionalArguments,
-                                          [Map<Symbol, dynamic> namedArguments]) {
-    return new Future(() {
-      return this.newInstance(constructorName,
-                              _unwrapAsyncPositionals(positionalArguments),
-                              _unwrapAsyncNamed(namedArguments));
-    });
-  }
-
   List<InstanceMirror> get metadata {
     // Get the metadata objects, convert them into InstanceMirrors using
     // reflect() and then make them into a Dart list.
@@ -996,64 +948,23 @@
   Map<Symbol, DeclarationMirror> get declarations {
     if (_declarations != null) return _declarations;
     return _declarations =
-        new _UnmodifiableMapView<Symbol, DeclarationMirror>(members);
+        new _UnmodifiableMapView<Symbol, DeclarationMirror>(_members);
   }
 
-  Map<Symbol, Mirror> _members;
-  Map<Symbol, Mirror> get members {
-    if (_members == null) {
-      _members = _makeMemberMap(_computeMembers(_reflectee));
+  Map<Symbol, Mirror> _cachedMembers;
+  Map<Symbol, Mirror> get _members {
+    if (_cachedMembers == null) {
+      _cachedMembers = _makeMemberMap(_computeMembers(_reflectee));
     }
-    return _members;
+    return _cachedMembers;
   }
 
-  Map<Symbol, ClassMirror> _types;
-  Map<Symbol, TypeMirror> get types {
-    if (_types == null) {
-      _types = _filterMap(members, (key, value) => (value is TypeMirror));
+  Map<Symbol, MethodMirror> _cachedFunctions;
+  Map<Symbol, MethodMirror> get _functions {
+    if (_cachedFunctions == null) {
+      _cachedFunctions = _filterMap(_members, (key, value) => (value is MethodMirror));
     }
-    return _types;
-  }
-
-  Map<Symbol, ClassMirror> _classes;
-  Map<Symbol, ClassMirror> get classes {
-    if (_classes == null) {
-      _classes = _filterMap(members, (key, value) => (value is ClassMirror));
-    }
-    return _classes;
-  }
-
-  Map<Symbol, MethodMirror> _functions;
-  Map<Symbol, MethodMirror> get functions {
-    if (_functions == null) {
-      _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));
-    }
-    return _getters;
-  }
-
-  Map<Symbol, MethodMirror> _setters;
-  Map<Symbol, MethodMirror> get setters {
-    if (_setters == null) {
-      _setters = _filterMap(functions, (key, value) => (value.isSetter));
-    }
-    return _setters;
-  }
-
-  Map<Symbol, VariableMirror> _variables;
-  Map<Symbol, VariableMirror> get variables {
-    if (_variables == null) {
-      _variables = _filterMap(members,
-                              (key, value) => (value is VariableMirror));
-    }
-    return _variables;
+    return _cachedFunctions;
   }
 
   List<InstanceMirror> get metadata {
@@ -1072,7 +983,7 @@
   String toString() => "LibraryMirror on '${_n(simpleName)}'";
 
   Function operator [](Symbol selector) {
-    var target = functions[selector];
+    var target = _functions[selector];
     if (target == null || !target.isRegularMethod) {
       throw new ArgumentError(
           "${MirrorSystem.getName(simpleName)} has no top-level method "
diff --git a/runtime/lib/schedule_microtask_patch.dart b/runtime/lib/schedule_microtask_patch.dart
index 75e87c8..f08de2b 100644
--- a/runtime/lib/schedule_microtask_patch.dart
+++ b/runtime/lib/schedule_microtask_patch.dart
@@ -5,10 +5,7 @@
 patch class _AsyncRun {
   /* patch */ static void _scheduleImmediate(void callback()) {
     if (_ScheduleImmediate._closure == null) {
-      // TODO(9001): don't default to using the Timer to enqueue the immediate
-      //             callback.
-      _createTimer(Duration.ZERO, callback);
-      return;
+      throw new UnsupportedError("Microtasks are not supported");
     }
     _ScheduleImmediate._closure(callback);
   }
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 6b6e659..7c11e43 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -1259,6 +1259,13 @@
 }
 
 
+void Assembler::fsincos() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xD9);
+  EmitUint8(0xFB);
+}
+
+
 void Assembler::fptan() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0xD9);
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 0afbb0f..37d4b9c 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -512,6 +512,7 @@
 
   void fsin();
   void fcos();
+  void fsincos();
   void fptan();
 
   void xchgl(Register dst, Register src);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 5628494..662bf2f 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -2016,6 +2016,31 @@
 }
 
 
+ASSEMBLER_TEST_GENERATE(SinCos, assembler) {
+  __ fldl(Address(ESP, kWordSize));
+  __ fsincos();
+  __ subl(ESP, Immediate(2 * kWordSize));
+  __ fstpl(Address(ESP, 0));  // cos result.
+  __ movsd(XMM0, Address(ESP, 0));
+  __ fstpl(Address(ESP, 0));  // sin result.
+  __ movsd(XMM1, Address(ESP, 0));
+  __ subsd(XMM1, XMM0);  // sin - cos.
+  __ movsd(Address(ESP, 0), XMM1);
+  __ fldl(Address(ESP, 0));
+  __ addl(ESP, Immediate(2 * kWordSize));
+  __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(SinCos, test) {
+  typedef double (*SinCosCode)(double d);
+  const double arg = 1.2345;
+  const double expected = sin(arg) - cos(arg);
+  double res = reinterpret_cast<SinCosCode>(test->entry())(arg);
+  EXPECT_FLOAT_EQ(expected, res, 0.000001);
+}
+
+
 ASSEMBLER_TEST_GENERATE(Tangent, assembler) {
   __ fldl(Address(ESP, kWordSize));
   __ fptan();
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 64a2c87..01e40a8 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1188,6 +1188,7 @@
                             /* is_const = */ field.is_const(),
                             /* is_abstract = */ false,
                             /* is_external = */ false,
+                            /* is_native = */ false,
                             cls,
                             field.token_pos()));
           getter.set_result_type(type);
@@ -1798,6 +1799,7 @@
                         false,  // Not const.
                         false,  // Not abstract.
                         false,  // Not external.
+                        false,  // Not native.
                         mixin_app,
                         mixin_app.token_pos()));
 
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 0d007b2..11536a9 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -28,7 +28,7 @@
   cls = Class::New(function_name, script, Scanner::kDummyTokenIndex);
   const Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, cls, 0));
+                    true, false, false, false, false, cls, 0));
   function.set_result_type(Type::Handle(Type::DynamicType()));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function);
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 882f593..44ddb3e 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1703,6 +1703,14 @@
 }
 
 
+void SinCos(double arg, double* cos_res, double* sin_res) {
+  // The compiler may merge the calls to sincos, if supported. This
+  // typically occurs only when compiling for 64-bit targets.
+  *cos_res = cos(arg);
+  *sin_res = sin(arg);
+}
+
+
 // Update global type feedback recorded for a field recording the assignment
 // of the given value.
 //   Arg0: Field object;
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index dc09e24..47e9444 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -102,6 +102,7 @@
 void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes);
 
 double DartModulo(double a, double b);
+void SinCos(double arg, double* sin_res, double* cos_res);
 
 }  // namespace dart
 
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index a9bfc71..b012f5f 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -28,7 +28,7 @@
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index bb893d4..f2e989a 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -28,7 +28,7 @@
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index c5b51b5..c42e384 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -28,7 +28,7 @@
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index 67561db..876b754 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -28,7 +28,7 @@
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index d8771dc..64fdad3 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -354,10 +354,8 @@
         optimizer.ApplyICData();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
-        // Optimize (a << b) & c patterns, merge operations. Must occur before
-        // 'SelectRepresentations' which inserts conversion nodes.
-        // TODO(srdjan): Moved before inlining until environment use list can
-        // be used to detect when shift-left is outside the scope of bit-and.
+        // Optimize (a << b) & c patterns, merge operations.
+        // Run early in order to have more opportunity to optimize left shifts.
         optimizer.TryOptimizePatterns();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -440,6 +438,13 @@
             DEBUG_ASSERT(flow_graph->VerifyUseLists());
           }
         }
+
+        // Optimize (a << b) & c patterns, merge operations.
+        // Run after CSE in order to have more opportunity to merge
+        // instructions that have same inputs.
+        optimizer.TryOptimizePatterns();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
         if (FLAG_loop_invariant_code_motion &&
             (function.deoptimization_counter() <
              FLAG_deoptimization_counter_licm_threshold)) {
@@ -917,10 +922,11 @@
     const Function& func = Function::ZoneHandle(Function::New(
         String::Handle(Symbols::New(kEvalConst)),
         RawFunction::kRegularFunction,
-        true,  // static function.
-        false,  // not const function.
+        true,  // static function
+        false,  // not const function
         false,  // not abstract
-        false,  // not external.
+        false,  // not external
+        false,  // not native
         Class::Handle(Type::Handle(Type::Function()).type_class()),
         fragment->token_pos()));
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 60b8df6..f84dc2e 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -2026,6 +2026,17 @@
 
 
 static RawFunction* GetOriginalFunction(const Function& func) {
+  if (func.IsClosureFunction()) {
+    // Local functions (closures) in mixin functions do not have
+    // an original function they were cloned from.
+    // Note: this is a problem when a breakpoint is set in a mixed-in
+    // closure. The breakpoint is linked to the closure attached to the
+    // mixin application class, not the mixin class. When the same
+    // closure is compiled for another mixin application class, we
+    // don't find the breakpoint since we'll be looking in the
+    // mixin class.
+    return func.raw();
+  }
   const Class& origin_class = Class::Handle(func.origin());
   if (origin_class.is_patch()) {
     // Patched functions from patch classes are removed from the
@@ -2073,8 +2084,11 @@
   while (bpt != NULL) {
     if (lookup_function.raw() == bpt->function()) {
       // Check if the breakpoint is inside a closure or local function
-      // within the newly compiled function.
-      Class& owner = Class::Handle(lookup_function.Owner());
+      // within the newly compiled function. Note that we must look
+      // in the owner class of the function that just got compiled
+      // (i.e. func), not the owner class of the function we use to
+      // record the breakpoint (lookup_function).
+      Class& owner = Class::Handle(func.Owner());
       Function& closure =
           Function::Handle(owner.LookupClosureFunction(bpt->token_pos()));
       if (!closure.IsNull() && (closure.raw() != lookup_function.raw())) {
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index d1908aa..9f99579 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -508,7 +508,6 @@
       ASSERT(index >= 0);
       it.SetCurrentLocation(Location::StackSlot(index));
     } else if (loc.IsFpuRegister()) {
-      assembler()->Comment("You betcha!");
       intptr_t index = fpu_reg_slots[loc.fpu_reg()];
       ASSERT(index >= 0);
       Value* value = it.CurrentValue();
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index bf9df1a..e86da7e 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -245,6 +245,7 @@
   ~FlowGraphCompiler();
 
   static bool SupportsUnboxedMints();
+  static bool SupportsSinCos();
 
   // Accessors.
   Assembler* assembler() const { return assembler_; }
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 19a75bb..f4bc5f9 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -42,6 +42,11 @@
 }
 
 
+bool FlowGraphCompiler::SupportsSinCos() {
+  return false;
+}
+
+
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder,
                                                  const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 81ae0aa..a1661e0 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -46,6 +46,11 @@
 }
 
 
+bool FlowGraphCompiler::SupportsSinCos() {
+  return true;
+}
+
+
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder,
                                                  const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 9c09757..c615a12 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -42,6 +42,11 @@
 }
 
 
+bool FlowGraphCompiler::SupportsSinCos() {
+  return false;
+}
+
+
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder,
                                                  const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index c2b1561..9a28abd 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -43,6 +43,11 @@
 }
 
 
+bool FlowGraphCompiler::SupportsSinCos() {
+  return true;
+}
+
+
 RawDeoptInfo* CompilerDeoptInfo::CreateDeoptInfo(FlowGraphCompiler* compiler,
                                                  DeoptInfoBuilder* builder,
                                                  const Array& deopt_table) {
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 3efaad4..8c4febc 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -255,19 +255,19 @@
 // Used by TryMergeDivMod.
 // Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction,
 // and the using instruction. This is an intermediate step before merging.
-static void DivModAppendLoadIndexed(BinarySmiOpInstr* instr,
-                                    FlowGraph* flow_graph) {
-  const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
-  const intptr_t ix = (instr->op_kind() == Token::kTRUNCDIV) ? 0 : 1;
+void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr,
+                                                    intptr_t ix,
+                                                    intptr_t cid) {
+  const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(cid);
   ConstantInstr* index_instr = new ConstantInstr(Smi::Handle(Smi::New(ix)));
-  flow_graph->InsertAfter(instr, index_instr, NULL, Definition::kValue);
+  flow_graph()->InsertAfter(instr, index_instr, NULL, Definition::kValue);
   LoadIndexedInstr* load = new LoadIndexedInstr(new Value(instr),
                                                 new Value(index_instr),
                                                 index_scale,
-                                                kArrayCid,
+                                                cid,
                                                 Isolate::kNoDeoptId);
   instr->ReplaceUsesWith(load);
-  flow_graph->InsertAfter(index_instr, load, NULL, Definition::kValue);
+  flow_graph()->InsertAfter(index_instr, load, NULL, Definition::kValue);
 }
 
 
@@ -297,7 +297,7 @@
   for (intptr_t i = 0; i < merge_candidates->length(); i++) {
     BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
     if (curr_instr == NULL) {
-      // Instructions was merged already.
+      // Instruction was merged already.
       continue;
     }
     ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
@@ -316,8 +316,14 @@
           (other_binop->right()->definition() == right_def)) {
         (*merge_candidates)[k] = NULL;  // Clear it.
         // Append a LoadIndexed behind TRUNC_DIV and MOD.
-        DivModAppendLoadIndexed(curr_instr, flow_graph_);
-        DivModAppendLoadIndexed(other_binop, flow_graph_);
+        AppendLoadIndexedForMerged(
+            curr_instr,
+            MergedMathInstr::ResultIndexOf(curr_instr->op_kind()),
+            kArrayCid);
+        AppendLoadIndexedForMerged(
+            other_binop,
+            MergedMathInstr::ResultIndexOf(other_binop->op_kind()),
+            kArrayCid);
 
         ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(2);
         args->Add(new Value(curr_instr->left()->definition()));
@@ -337,16 +343,72 @@
 }
 
 
+void FlowGraphOptimizer::TryMergeMathUnary(
+    GrowableArray<MathUnaryInstr*>* merge_candidates) {
+  if (!FlowGraphCompiler::SupportsSinCos()) {
+    return;
+  }
+  if (merge_candidates->length() < 2) {
+    // Need at least a SIN and a COS.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    ASSERT((curr_instr->kind() == MethodRecognizer::kMathSin) ||
+           (curr_instr->kind() == MethodRecognizer::kMathCos));
+    // Check if there is sin/cos binop with same inputs.
+    const intptr_t other_kind =
+        (curr_instr->kind() == MethodRecognizer::kMathSin) ?
+            MethodRecognizer::kMathCos : MethodRecognizer::kMathSin;
+    Definition* def = curr_instr->value()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      MathUnaryInstr* other_op = (*merge_candidates)[k];
+      // 'other_op' can be NULL if it was already merged.
+      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
+          (other_op->value()->definition() == def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        // Append a LoadIndexed behind SIN and COS.
+        AppendLoadIndexedForMerged(
+            curr_instr,
+            MergedMathInstr::ResultIndexOf(curr_instr->kind()),
+            kTypedDataFloat64ArrayCid);
+        AppendLoadIndexedForMerged(
+            other_op,
+            MergedMathInstr::ResultIndexOf(other_op->kind()),
+            kTypedDataFloat64ArrayCid);
+        ZoneGrowableArray<Value*>* args = new ZoneGrowableArray<Value*>(1);
+        args->Add(new Value(curr_instr->value()->definition()));
+
+        // Replace with TruncDivMod.
+        MergedMathInstr* div_mod = new MergedMathInstr(
+            args,
+            curr_instr->DeoptimizationTarget(),
+            MergedMathInstr::kSinCos);
+        curr_instr->ReplaceWith(div_mod, current_iterator());
+        other_op->ReplaceUsesWith(div_mod);
+        other_op->RemoveFromGraph();
+      }
+    }
+  }
+}
+
+
 // Optimize (a << b) & c pattern: if c is a positive Smi or zero, then the
 // shift can be a truncating Smi shift-left and result is always Smi.
 // Merging occurs only per basic-block.
 void FlowGraphOptimizer::TryOptimizePatterns() {
   if (!FLAG_truncating_left_shift) return;
   ASSERT(current_iterator_ == NULL);
-  GrowableArray<BinarySmiOpInstr*> for_merge;
+  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
+  GrowableArray<MathUnaryInstr*> sin_cos_merge;
   for (intptr_t i = 0; i < block_order_.length(); ++i) {
     // Merging only per basic-block.
-    for_merge.Clear();
+    div_mod_merge.Clear();
+    sin_cos_merge.Clear();
     BlockEntryInstr* entry = block_order_[i];
     ForwardInstructionIterator it(entry);
     current_iterator_ = &it;
@@ -359,7 +421,7 @@
                                        binop->right()->definition());
         } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
                    (binop->op_kind() == Token::kMOD)) {
-          for_merge.Add(binop);
+          div_mod_merge.Add(binop);
         }
       } else if (it.Current()->IsBinaryMintOp()) {
         BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
@@ -368,9 +430,16 @@
                                        mintop->left()->definition(),
                                        mintop->right()->definition());
         }
+      } else if (it.Current()->IsMathUnary()) {
+        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
+        if ((math_unary->kind() == MethodRecognizer::kMathSin) ||
+            (math_unary->kind() == MethodRecognizer::kMathCos)) {
+          sin_cos_merge.Add(math_unary);
+        }
       }
     }
-    TryMergeTruncDivMod(&for_merge);
+    TryMergeTruncDivMod(&div_mod_merge);
+    TryMergeMathUnary(&sin_cos_merge);
     current_iterator_ = NULL;
   }
 }
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index b1fd751..c473514 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -205,6 +205,9 @@
                                     Definition* left_instr,
                                     Definition* right_instr);
   void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
+  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
+
+  void AppendLoadIndexedForMerged(Definition* instr, intptr_t ix, intptr_t cid);
 
   FlowGraph* flow_graph_;
 
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 47015a9..6db56c5 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -1222,6 +1222,8 @@
 CompileType MergedMathInstr::ComputeType() const {
   if (kind() == MergedMathInstr::kTruncDivMod) {
     return CompileType::FromCid(kArrayCid);
+  } else if (kind() == MergedMathInstr::kSinCos) {
+    return CompileType::FromCid(kTypedDataFloat64ArrayCid);
   } else {
     UNIMPLEMENTED();
     return CompileType::Dynamic();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 07604df..edc727e 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2989,6 +2989,25 @@
   deopt_id_ = original_deopt_id;
 }
 
+
+intptr_t MergedMathInstr::ResultIndexOf(MethodRecognizer::Kind kind) {
+  switch (kind) {
+    case MethodRecognizer::kMathSin: return 0;
+    case MethodRecognizer::kMathCos: return 1;
+    default: UNIMPLEMENTED(); return -1;
+  }
+}
+
+
+intptr_t MergedMathInstr::ResultIndexOf(Token::Kind token) {
+  switch (token) {
+    case Token::kTRUNCDIV: return 0;
+    case Token::kMOD: return 1;
+    default: UNIMPLEMENTED(); return -1;
+  }
+}
+
+
 #undef __
 
 }  // namespace dart
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index f5f4ac7..43b9873 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -6667,6 +6667,8 @@
   static intptr_t InputCountFor(MergedMathInstr::Kind kind) {
     if (kind == kTruncDivMod) {
       return 2;
+    } else if (kind == kSinCos) {
+      return 1;
     } else {
       UNIMPLEMENTED();
       return -1;
@@ -6687,6 +6689,8 @@
   virtual bool CanDeoptimize() const {
     if (kind_ == kTruncDivMod) {
       return true;
+    } else if (kind_ == kSinCos) {
+      return false;
     } else {
       UNIMPLEMENTED();
       return false;
@@ -6696,6 +6700,8 @@
   virtual Representation representation() const {
     if (kind_ == kTruncDivMod) {
       return kTagged;
+    } else if (kind_ == kSinCos) {
+      return kTagged;
     } else {
       UNIMPLEMENTED();
       return kTagged;
@@ -6703,9 +6709,11 @@
   }
 
   virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+    ASSERT((0 <= idx) && (idx < InputCount()));
     if (kind_ == kTruncDivMod) {
-      ASSERT((0 <= idx) && (idx < InputCount()));
       return kTagged;
+    } else if (kind_ == kSinCos) {
+      return kUnboxedDouble;
     } else {
       UNIMPLEMENTED();
       return kTagged;
@@ -6714,6 +6722,10 @@
 
   virtual intptr_t DeoptimizationTarget() const { return deopt_id_; }
 
+  // Returns the result index for one of the merged instructjons
+  static intptr_t ResultIndexOf(MethodRecognizer::Kind kind);
+  static intptr_t ResultIndexOf(Token::Kind token);
+
   DECLARE_INSTRUCTION(MergedMath)
 
   // Returns a structure describing the location constraints required
@@ -6737,6 +6749,7 @@
 
   static const char* KindToCString(MergedMathInstr::Kind kind) {
     if (kind == kTruncDivMod) return "TruncDivMod";
+    if (kind == kSinCos) return "SinCos";
     UNIMPLEMENTED();
     return "";
   }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index c7854cd..1266a3b 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1488,7 +1488,25 @@
     if (!ok_is_fall_through) {
       __ b(&ok);
     }
+
+    if (deopt == NULL) {
+      ASSERT(!compiler->is_optimizing());
+      __ Bind(fail);
+
+      __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
+      __ CompareImmediate(IP, kDynamicCid);
+      __ b(&ok, EQ);
+
+      __ Push(field_reg);
+      __ Push(value_reg);
+      __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+      __ Drop(2);  // Drop the field and the value.
+    }
   } else {
+    ASSERT(compiler->is_optimizing());
+    ASSERT(deopt != NULL);
+    ASSERT(ok_is_fall_through);
+    // Field guard class has been initialized and is known.
     if (field_reg != kNoRegister) {
       __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
     }
@@ -1527,18 +1545,11 @@
         __ CompareImmediate(value_reg,
                             reinterpret_cast<intptr_t>(Object::null()));
       }
-
-      if (ok_is_fall_through) {
-        __ b(fail, NE);
-      } else {
-        __ b(&ok, EQ);
-      }
+      __ b(fail, NE);
     } else {
       // Both value's and field's class id is known.
       if ((value_cid != field_cid) && (value_cid != nullability)) {
-        if (ok_is_fall_through) {
-          __ b(fail);
-        }
+        __ b(fail);
       } else if (field_has_length && (value_cid == field_cid)) {
         ASSERT(value_cid_reg != kNoRegister);
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1551,31 +1562,12 @@
                  FieldAddress(value_reg, TypedData::length_offset()));
         }
         __ CompareImmediate(value_cid_reg, field_length);
-        if (ok_is_fall_through) {
-          __ b(fail, NE);
-        }
+        __ b(fail, NE);
       } else {
-        // Nothing to emit.
-        ASSERT(!compiler->is_optimizing());
-        return;
+        UNREACHABLE();
       }
     }
   }
-
-  if (deopt == NULL) {
-    ASSERT(!compiler->is_optimizing());
-    __ Bind(fail);
-
-    __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset()));
-    __ CompareImmediate(IP, kDynamicCid);
-    __ b(&ok, EQ);
-
-    __ Push(field_reg);
-    __ Push(value_reg);
-    __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
-    __ Drop(2);  // Drop the field and the value.
-  }
-
   __ Bind(&ok);
 }
 
@@ -4145,6 +4137,9 @@
     __ StoreIntoObjectNoBarrier(result, store_address, result_mod);
     return;
   }
+  if (kind() == MergedMathInstr::kSinCos) {
+    UNIMPLEMENTED();
+  }
   UNIMPLEMENTED();
 }
 
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index dc8a237..8c9c9eb 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1494,7 +1494,24 @@
     if (!ok_is_fall_through) {
       __ jmp(&ok);
     }
+
+    if (deopt == NULL) {
+      ASSERT(!compiler->is_optimizing());
+      __ Bind(fail);
+
+      __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
+              Immediate(kDynamicCid));
+      __ j(EQUAL, &ok);
+
+      __ pushl(field_reg);
+      __ pushl(value_reg);
+      __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+      __ Drop(2);  // Drop the field and the value.
+    }
   } else {
+    ASSERT(compiler->is_optimizing());
+    ASSERT(deopt != NULL);
+    ASSERT(ok_is_fall_through);
     // Field guard class has been initialized and is known.
     if (field_reg != kNoRegister) {
       __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
@@ -1537,18 +1554,11 @@
             Immediate(reinterpret_cast<intptr_t>(Object::null()));
         __ cmpl(value_reg, raw_null);
       }
-
-      if (ok_is_fall_through) {
-        __ j(NOT_EQUAL, fail);
-      } else {
-        __ j(EQUAL, &ok);
-      }
+      __ j(NOT_EQUAL, fail);
     } else {
       // Both value's and field's class id is known.
       if ((value_cid != field_cid) && (value_cid != nullability)) {
-        if (ok_is_fall_through) {
-          __ jmp(fail);
-        }
+        __ jmp(fail);
       } else if (field_has_length && (value_cid == field_cid)) {
         ASSERT(value_cid_reg != kNoRegister);
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1561,31 +1571,12 @@
                   FieldAddress(value_reg, TypedData::length_offset()));
         }
         __ cmpl(value_cid_reg, Immediate(Smi::RawValue(field_length)));
-        if (ok_is_fall_through) {
-          __ j(NOT_EQUAL, fail);
-        }
+        __ j(NOT_EQUAL, fail);
       } else {
-        // Nothing to emit.
-        ASSERT(!compiler->is_optimizing());
-        return;
+        UNREACHABLE();
       }
     }
   }
-
-  if (deopt == NULL) {
-    ASSERT(!compiler->is_optimizing());
-    __ Bind(fail);
-
-    __ cmpl(FieldAddress(field_reg, Field::guarded_cid_offset()),
-            Immediate(kDynamicCid));
-    __ j(EQUAL, &ok);
-
-    __ pushl(field_reg);
-    __ pushl(value_reg);
-    __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
-    __ Drop(2);  // Drop the field and the value.
-  }
-
   __ Bind(&ok);
 }
 
@@ -4012,11 +4003,27 @@
     summary->set_temp(0, Location::RegisterLocation(EDX));
     return summary;
   }
+  if (kind() == MergedMathInstr::kSinCos) {
+    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::RegisterLocation(EAX));
+    return summary;
+  }
   UNIMPLEMENTED();
   return NULL;
 }
 
 
+typedef void (*SinCosCFunction) (double x, double* res_sin, double* res_cos);
+
+extern const RuntimeEntry kSinCosRuntimeEntry(
+    "libc_sincos", reinterpret_cast<RuntimeFunction>(
+        static_cast<SinCosCFunction>(&SinCos)), 1, true, true);
+
+
 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -4081,15 +4088,13 @@
     __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)));
     const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
     Address trunc_div_address(
-        FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
-                                                     index_scale,
-                                                     result,
-                                                     0));
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(Token::kTRUNCDIV)));
     Address mod_address(
-        FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
-                                                     index_scale,
-                                                     result,
-                                                     1));
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(Token::kMOD)));
     __ SmiTag(EAX);
     __ SmiTag(EDX);
     __ StoreIntoObjectNoBarrier(result, trunc_div_address, EAX);
@@ -4097,6 +4102,39 @@
     return;
   }
 
+  if (kind() == MergedMathInstr::kSinCos) {
+    // Do x87 sincos, since the ia32 compilers may not fuse sin/cos into
+    // sincos.
+    __ pushl(EAX);
+    __ pushl(EAX);
+    __ movsd(Address(ESP, 0), locs()->in(0).fpu_reg());
+    __ fldl(Address(ESP, 0));
+    __ fsincos();
+    __ fstpl(Address(ESP, 0));
+    __ movsd(XMM1, Address(ESP, 0));
+    __ fstpl(Address(ESP, 0));
+    __ movsd(XMM0, Address(ESP, 0));
+    __ addl(ESP, Immediate(2 * kWordSize));
+
+    Register result = locs()->out().reg();
+    const TypedData& res_array = TypedData::ZoneHandle(
+      TypedData::New(kTypedDataFloat64ArrayCid, 2, Heap::kOld));
+    __ LoadObject(result, res_array);
+    const intptr_t index_scale =
+        FlowGraphCompiler::ElementSizeFor(kTypedDataFloat64ArrayCid);
+    Address sin_address(
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kTypedDataFloat64ArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathSin)));
+    Address cos_address(
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kTypedDataFloat64ArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathCos)));
+    __ movsd(sin_address, XMM0);
+    __ movsd(cos_address, XMM1);
+    return;
+  }
+
   UNIMPLEMENTED();
 }
 
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 83d0b0c..07ac406 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1552,7 +1552,25 @@
     if (!ok_is_fall_through) {
       __ b(&ok);
     }
+
+    if (deopt == NULL) {
+      ASSERT(!compiler->is_optimizing());
+      __ Bind(fail);
+
+      __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
+      __ BranchEqual(CMPRES1, kDynamicCid, &ok);
+
+      __ addiu(SP, SP, Immediate(-2 * kWordSize));
+      __ sw(field_reg, Address(SP, 1 * kWordSize));
+      __ sw(value_reg, Address(SP, 0 * kWordSize));
+      __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+      __ Drop(2);  // Drop the field and the value.
+    }
   } else {
+    ASSERT(compiler->is_optimizing());
+    ASSERT(deopt != NULL);
+    ASSERT(ok_is_fall_through);
+    // Field guard class has been initialized and is known.
     if (field_reg != kNoRegister) {
       __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
     }
@@ -1594,17 +1612,11 @@
         __ subu(CMPRES1, value_reg, TMP);
       }
 
-      if (ok_is_fall_through) {
-        __ bne(CMPRES1, ZR, fail);
-      } else {
-        __ beq(CMPRES1, ZR, &ok);
-      }
+      __ bne(CMPRES1, ZR, fail);
     } else {
       // Both value's and field's class id is known.
       if ((value_cid != field_cid) && (value_cid != nullability)) {
-        if (ok_is_fall_through) {
-          __ b(fail);
-        }
+        __ b(fail);
       } else if (field_has_length && (value_cid == field_cid)) {
         ASSERT(value_cid_reg != kNoRegister);
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1618,31 +1630,12 @@
         }
         __ LoadImmediate(TMP, Smi::RawValue(field_length));
         __ subu(CMPRES1, value_cid_reg, TMP);
-        if (ok_is_fall_through) {
-          __ bne(CMPRES1, ZR, fail);
-        }
+        __ bne(CMPRES1, ZR, fail);
       } else {
-        // Nothing to emit.
-        ASSERT(!compiler->is_optimizing());
-        return;
+        UNREACHABLE();
       }
     }
   }
-
-  if (deopt == NULL) {
-    ASSERT(!compiler->is_optimizing());
-    __ Bind(fail);
-
-    __ lw(CMPRES1, FieldAddress(field_reg, Field::guarded_cid_offset()));
-    __ BranchEqual(CMPRES1, kDynamicCid, &ok);
-
-    __ addiu(SP, SP, Immediate(-2 * kWordSize));
-    __ sw(field_reg, Address(SP, 1 * kWordSize));
-    __ sw(value_reg, Address(SP, 0 * kWordSize));
-    __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
-    __ Drop(2);  // Drop the field and the value.
-  }
-
   __ Bind(&ok);
 }
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 9f61a2f..72160c2 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1390,7 +1390,25 @@
     if (!ok_is_fall_through) {
       __ jmp(&ok);
     }
+
+    if (deopt == NULL) {
+      ASSERT(!compiler->is_optimizing());
+      __ Bind(fail);
+
+      __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
+                          Immediate(kDynamicCid), PP);
+      __ j(EQUAL, &ok);
+
+      __ pushq(field_reg);
+      __ pushq(value_reg);
+      __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
+      __ Drop(2);  // Drop the field and the value.
+    }
   } else {
+    ASSERT(compiler->is_optimizing());
+    ASSERT(deopt != NULL);
+    ASSERT(ok_is_fall_through);
+    // Field guard class has been initialized and is known.
     if (field_reg != kNoRegister) {
       __ LoadObject(field_reg, Field::ZoneHandle(field().raw()), PP);
     }
@@ -1430,18 +1448,11 @@
         __ j(EQUAL, &ok);
         __ CompareObject(value_reg, Object::null_object(), PP);
       }
-
-      if (ok_is_fall_through) {
-        __ j(NOT_EQUAL, fail);
-      } else {
-        __ j(EQUAL, &ok);
-      }
+      __ j(NOT_EQUAL, fail);
     } else {
       // Both value's and field's class id is known.
       if ((value_cid != field_cid) && (value_cid != nullability)) {
-        if (ok_is_fall_through) {
-          __ jmp(fail);
-        }
+        __ jmp(fail);
       } else if (field_has_length && (value_cid == field_cid)) {
         ASSERT(value_cid_reg != kNoRegister);
         if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
@@ -1455,31 +1466,12 @@
         }
         __ CompareImmediate(
             value_cid_reg, Immediate(Smi::RawValue(field_length)), PP);
-        if (ok_is_fall_through) {
-          __ j(NOT_EQUAL, fail);
-        }
+        __ j(NOT_EQUAL, fail);
       } else {
-        // Nothing to emit.
-        ASSERT(!compiler->is_optimizing());
-        return;
+        UNREACHABLE();
       }
     }
   }
-
-  if (deopt == NULL) {
-    ASSERT(!compiler->is_optimizing());
-    __ Bind(fail);
-
-    __ CompareImmediate(FieldAddress(field_reg, Field::guarded_cid_offset()),
-                        Immediate(kDynamicCid), PP);
-    __ j(EQUAL, &ok);
-
-    __ pushq(field_reg);
-    __ pushq(value_reg);
-    __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2);
-    __ Drop(2);  // Drop the field and the value.
-  }
-
   __ Bind(&ok);
 }
 
@@ -4052,11 +4044,28 @@
     summary->set_temp(0, Location::RegisterLocation(RDX));
     return summary;
   }
+  if (kind() == MergedMathInstr::kSinCos) {
+    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::RegisterLocation(RAX));
+    return summary;
+  }
   UNIMPLEMENTED();
   return NULL;
 }
 
 
+
+typedef void (*SinCosCFunction) (double x, double* res_sin, double* res_cos);
+
+extern const RuntimeEntry kSinCosRuntimeEntry(
+    "libc_sincos", reinterpret_cast<RuntimeFunction>(
+        static_cast<SinCosCFunction>(&SinCos)), 1, true, true);
+
+
 void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   Label* deopt = NULL;
   if (CanDeoptimize()) {
@@ -4146,15 +4155,13 @@
     __ LoadObject(result, Array::ZoneHandle(Array::New(2, Heap::kOld)), PP);
     const intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(kArrayCid);
     Address trunc_div_address(
-        FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
-                                                     index_scale,
-                                                     result,
-                                                     0));
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(Token::kTRUNCDIV)));
     Address mod_address(
-        FlowGraphCompiler::ElementAddressForIntIndex(kArrayCid,
-                                                     index_scale,
-                                                     result,
-                                                     1));
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(Token::kMOD)));
     __ SmiTag(RAX);
     __ SmiTag(RDX);
     __ StoreIntoObjectNoBarrier(result, trunc_div_address, RAX);
@@ -4164,6 +4171,50 @@
     // in-range arguments, cannot create out-of-range result.
     return;
   }
+  if (kind() == MergedMathInstr::kSinCos) {
+    __ EnterFrame(0);
+    // +-------------------------------+
+    // | double-argument               |  <- TOS
+    // +-------------------------------+
+    // | address-cos-result            |  +8
+    // +-------------------------------+
+    // | address-sin-result            |  +16
+    // +-------------------------------+
+    // | double-storage-for-cos-result |  +24
+    // +-------------------------------+
+    // | double-storage-for-sin-result |  +32
+    // +-------------------------------+
+    // ....
+    __ ReserveAlignedFrameSpace(kDoubleSize * 3 + kWordSize * 2);
+    __ movsd(Address(RSP, 0), locs()->in(0).fpu_reg());
+
+    __ leaq(RDI, Address(RSP, 2 * kWordSize + kDoubleSize));
+    __ leaq(RSI, Address(RSP, 2 * kWordSize + 2 * kDoubleSize));
+    __ movaps(XMM0, locs()->in(0).fpu_reg());
+
+    __ CallRuntime(kSinCosRuntimeEntry, InputCount());
+    __ movsd(XMM0, Address(RSP, 2 * kWordSize + kDoubleSize * 2));  // sin.
+    __ movsd(XMM1, Address(RSP, 2 * kWordSize + kDoubleSize));  // cos.
+    __ leave();
+
+    Register result = locs()->out().reg();
+    const TypedData& res_array = TypedData::ZoneHandle(
+      TypedData::New(kTypedDataFloat64ArrayCid, 2, Heap::kOld));
+    __ LoadObject(result, res_array, PP);
+    const intptr_t index_scale =
+        FlowGraphCompiler::ElementSizeFor(kTypedDataFloat64ArrayCid);
+    Address sin_address(
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kTypedDataFloat64ArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathSin)));
+    Address cos_address(
+        FlowGraphCompiler::ElementAddressForIntIndex(
+            kTypedDataFloat64ArrayCid, index_scale, result,
+            MergedMathInstr::ResultIndexOf(MethodRecognizer::kMathCos)));
+    __ movsd(sin_address, XMM0);
+    __ movsd(cos_address, XMM1);
+    return;
+  }
   UNIMPLEMENTED();
 }
 
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index a392731..473c63b 100644
--- a/runtime/vm/megamorphic_cache_table.cc
+++ b/runtime/vm/megamorphic_cache_table.cc
@@ -64,6 +64,7 @@
                                      false,  // Not const.
                                      false,  // Not abstract.
                                      false,  // Not external.
+                                     false,  // Not native.
                                      cls,
                                      0));  // No token position.
   miss_handler_code_ = code.raw();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index a954661..b138c2a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1822,7 +1822,7 @@
     closure ^= closures.At(i);
     ASSERT(!closure.IsNull());
     if ((closure.token_pos() <= token_pos) &&
-        (token_pos < closure.end_token_pos()) &&
+        (token_pos <= closure.end_token_pos()) &&
         (best_fit_token_pos < closure.token_pos())) {
       best_fit_index = i;
       best_fit_token_pos = closure.token_pos();
@@ -2129,6 +2129,7 @@
                     false,  // Not const.
                     false,  // Not abstract.
                     false,  // Not external.
+                    false,  // Not native.
                     *this,
                     0));  // No token position.
   ArgumentsDescriptor desc(args_desc);
@@ -2337,6 +2338,7 @@
                                      false,  // Not const.
                                      false,  // Not abstract.
                                      false,  // Not external.
+                                     false,  // Not native.
                                      temp_class,
                                      0));
   eval_func.set_result_type(Type::Handle(Type::DynamicType()));
@@ -5042,6 +5044,7 @@
                            bool is_const,
                            bool is_abstract,
                            bool is_external,
+                           bool is_native,
                            const Object& owner,
                            intptr_t token_pos) {
   ASSERT(!owner.IsNull());
@@ -5054,6 +5057,7 @@
   result.set_is_const(is_const);
   result.set_is_abstract(is_abstract);
   result.set_is_external(is_external);
+  result.set_is_native(is_native);
   result.set_is_visible(true);  // Will be computed later.
   result.set_is_intrinsic(false);
   result.set_is_recognized(false);
@@ -5069,7 +5073,6 @@
   result.set_optimized_call_site_count(0);
   result.set_is_optimizable(true);
   result.set_has_finally(false);
-  result.set_is_native(false);
   result.set_is_inlinable(true);
   if (kind == RawFunction::kClosureFunction) {
     const ClosureData& data = ClosureData::Handle(ClosureData::New());
@@ -5111,6 +5114,7 @@
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     /* is_external = */ false,
+                    parent.is_native(),
                     parent_owner,
                     token_pos));
   result.set_parent_function(parent);
@@ -5497,6 +5501,7 @@
                     false,  // !const
                     false,  // !abstract
                     false,  // !external
+                    false,  // !native
                     Class::Handle(field.owner()),
                     field.token_pos()));
   init_function.set_result_type(AbstractType::Handle(field.type()));
@@ -11040,6 +11045,7 @@
                                      false,  // Not const.
                                      false,  // Not abstract.
                                      false,  // Not external.
+                                     false,  // Not native.
                                      temp_class,
                                      0));
   eval_func.set_result_type(Type::Handle(Type::DynamicType()));
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 99a9fb5..d41ba4c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1888,6 +1888,7 @@
                           bool is_const,
                           bool is_abstract,
                           bool is_external,
+                          bool is_native,
                           const Object& owner,
                           intptr_t token_pos);
 
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a4a22a6..7a017b5 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -64,12 +64,12 @@
   function_name = Symbols::New("foo");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, 0);
   functions.SetAt(0, function);
   function_name = Symbols::New("bar");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, 0);
 
   const int kNumFixedParameters = 2;
   const int kNumOptionalParameters = 3;
@@ -82,24 +82,24 @@
   function_name = Symbols::New("baz");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, 0);
   functions.SetAt(2, function);
 
   function_name = Symbols::New("Foo");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, cls, 0);
+      true, false, false, false, false, cls, 0);
 
   functions.SetAt(3, function);
   function_name = Symbols::New("Bar");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, cls, 0);
+      true, false, false, false, false, cls, 0);
   functions.SetAt(4, function);
   function_name = Symbols::New("BaZ");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, cls, 0);
+      true, false, false, false, false, cls, 0);
   functions.SetAt(5, function);
 
   // Setup the functions in the class.
@@ -2336,7 +2336,7 @@
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New("foo_papa"));
   parent = Function::New(parent_name, RawFunction::kRegularFunction,
-                         false, false, false, false, cls, 0);
+                         false, false, false, false, false, cls, 0);
   functions.SetAt(0, parent);
   cls.SetFunctions(functions);
 
@@ -2411,7 +2411,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   return &function;
 }
 
@@ -2630,12 +2630,14 @@
   const bool is_const = false;
   const bool is_abstract = false;
   const bool is_external = false;
+  const bool is_native = false;
   return Function::New(function_name,
                        RawFunction::kRegularFunction,
                        is_static,
                        is_const,
                        is_abstract,
                        is_external,
+                       is_native,
                        cls,
                        0);
 }
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 18b58c4..66d3e48 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -525,6 +525,7 @@
     has_var = false;
     has_factory = false;
     has_operator = false;
+    has_native = false;
     metadata_pos = -1;
     operator_token = Token::kILLEGAL;
     type = NULL;
@@ -576,6 +577,7 @@
   bool has_var;
   bool has_factory;
   bool has_operator;
+  bool has_native;
   intptr_t metadata_pos;
   Token::Kind operator_token;
   const AbstractType* type;
@@ -930,7 +932,7 @@
                    ident->ToCString(),
                    cls.ToCString());
         }
-        expr = GenerateStaticFieldLookup(field, TokenPos());
+        expr = GenerateStaticFieldLookup(field, ident_pos);
       }
     }
     if (expr->EvalConstExpr() == NULL) {
@@ -1065,6 +1067,7 @@
   AddFormalParamsToScope(&params, current_block_->scope);
 
   // Move forward to the start of the initializer expression.
+  intptr_t ident_pos = TokenPos();
   ExpectIdentifier("identifier expected");
   ExpectToken(Token::kASSIGN);
   intptr_t token_pos = TokenPos();
@@ -1110,7 +1113,7 @@
   AstNode* compare_transition_sentinel = new ComparisonNode(
       token_pos,
       Token::kEQ_STRICT,
-      new LoadStaticFieldNode(token_pos, field),
+      new LoadStaticFieldNode(ident_pos, field),
       new LiteralNode(field.token_pos(), Object::transition_sentinel()));
 
   SequenceNode* store_null = new SequenceNode(token_pos, NULL);
@@ -1574,6 +1577,7 @@
                         /* is_const = */ false,
                         /* is_abstract = */ false,
                         /* is_external = */ false,
+                        /* is_native = */ false,
                         current_class(),
                         parameter.name_pos));
       signature_function.set_result_type(result_type);
@@ -1997,9 +2001,9 @@
 }
 
 
-AstNode* Parser::ParseSuperFieldAccess(const String& field_name) {
+AstNode* Parser::ParseSuperFieldAccess(const String& field_name,
+                                       intptr_t field_pos) {
   TRACE_PARSER("ParseSuperFieldAccess");
-  const intptr_t field_pos = TokenPos();
   const Class& super_class = Class::ZoneHandle(current_class().SuperClass());
   if (super_class.IsNull()) {
     ErrorMsg("class '%s' does not have a superclass",
@@ -3274,6 +3278,7 @@
     ParseNativeDeclaration();
     method_end_pos = TokenPos();
     ExpectSemicolon();
+    method->has_native = true;
   } else {
     // We haven't found a method body. Issue error if one is required.
     const bool must_have_body =
@@ -3329,6 +3334,7 @@
                     method->has_const,
                     method->has_abstract,
                     method->has_external,
+                    method->has_native,
                     current_class(),
                     method->decl_begin_pos));
   func.set_result_type(*method->type);
@@ -3446,6 +3452,7 @@
                                field->has_const,
                                /* is_abstract = */ false,
                                /* is_external = */ false,
+                               /* is_native = */ false,
                                current_class(),
                                field->name_pos);
         getter.set_result_type(*field->type);
@@ -3468,6 +3475,7 @@
                              field->has_final,
                              /* is_abstract = */ false,
                              /* is_external = */ false,
+                             /* is_native = */ false,
                              current_class(),
                              field->name_pos);
       ParamList params;
@@ -3484,6 +3492,7 @@
                                field->has_final,
                                /* is_abstract = */ false,
                                /* is_external = */ false,
+                               /* is_native = */ false,
                                current_class(),
                                field->name_pos);
         ParamList params;
@@ -4010,6 +4019,7 @@
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     /* is_external = */ false,
+                    /* is_native = */ false,
                     cls,
                     cls.token_pos()));
   ctor.set_end_token_pos(ctor.token_pos());
@@ -4238,6 +4248,7 @@
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     /* is_external = */ false,
+                    /* is_native = */ false,
                     function_type_alias,
                     alias_name_pos));
   signature_function.set_result_type(result_type);
@@ -4571,6 +4582,7 @@
                                is_const,
                                /* is_abstract = */ false,
                                /* is_external = */ false,
+                               /* is_native = */ false,
                                current_class(),
                                name_pos);
         getter.set_result_type(type);
@@ -4651,6 +4663,7 @@
   ParseFormalParameterList(allow_explicit_default_values, false, &params);
 
   intptr_t function_end_pos = function_pos;
+  bool is_native = false;
   if (is_external) {
     function_end_pos = TokenPos();
     ExpectSemicolon();
@@ -4667,6 +4680,7 @@
     ParseNativeDeclaration();
     function_end_pos = TokenPos();
     ExpectSemicolon();
+    is_native = true;
   } else {
     ErrorMsg("function block expected");
   }
@@ -4677,6 +4691,7 @@
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     is_external,
+                    is_native,
                     current_class(),
                     decl_begin_pos));
   func.set_result_type(result_type);
@@ -4781,6 +4796,7 @@
   }
 
   intptr_t accessor_end_pos = accessor_pos;
+  bool is_native = false;
   if (is_external) {
     accessor_end_pos = TokenPos();
     ExpectSemicolon();
@@ -4797,17 +4813,19 @@
     ParseNativeDeclaration();
     accessor_end_pos = TokenPos();
     ExpectSemicolon();
+    is_native = true;
   } else {
     ErrorMsg("function block expected");
   }
   Function& func = Function::Handle(
       Function::New(accessor_name,
-                    is_getter? RawFunction::kGetterFunction :
-                               RawFunction::kSetterFunction,
+                    is_getter ? RawFunction::kGetterFunction :
+                                RawFunction::kSetterFunction,
                     is_static,
                     /* is_const = */ false,
                     /* is_abstract = */ false,
                     is_external,
+                    is_native,
                     current_class(),
                     decl_begin_pos));
   func.set_result_type(result_type);
@@ -5287,7 +5305,7 @@
 // Builds ReturnNode/NativeBodyNode for a native function.
 void Parser::ParseNativeFunctionBlock(const ParamList* params,
                                       const Function& func) {
-  func.set_is_native(true);
+  ASSERT(func.is_native());
   TRACE_PARSER("ParseNativeFunctionBlock");
   const Class& cls = Class::Handle(func.Owner());
   const Library& library = Library::Handle(cls.library());
@@ -7775,6 +7793,28 @@
 }
 
 
+// Check whether the syntax of expression expr is a grammatically legal
+// assignable expression. This check is used to detect situations where
+// the expression itself is assignable, but the source is grammatically
+// wrong. The AST representation of an expression cannot distinguish
+// between x = 0 and (x) = 0. The latter is illegal.
+// A syntactically legal assignable expression always ends with an
+// identifier token or a ] token. We rewind the token iterator and
+// check whether the token before end_pos is an identifier or ].
+bool Parser::IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos) {
+  ASSERT(expr->token_pos() >= 0);
+  ASSERT(expr->token_pos() < end_pos);
+  SetPosition(expr->token_pos());
+  Token::Kind token = Token::kILLEGAL;
+  while (TokenPos() < end_pos) {
+    token = CurrentToken();
+    ConsumeToken();
+  }
+  ASSERT(TokenPos() == end_pos);
+  return Token::IsIdentifier(token) || (token == Token::kRBRACK);
+}
+
+
 AstNode* Parser::CreateAssignmentNode(AstNode* original,
                                       AstNode* rhs,
                                       const String* left_ident,
@@ -7915,6 +7955,9 @@
     return expr;
   }
   // Assignment expressions.
+  if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+    ErrorMsg(expr_pos, "expression is not assignable");
+  }
   const Token::Kind assignment_op = CurrentToken();
   const intptr_t assignment_pos = TokenPos();
   ConsumeToken();
@@ -7993,6 +8036,9 @@
         Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
     const intptr_t expr_pos = TokenPos();
     expr = ParseUnaryExpr();
+    if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+      ErrorMsg(expr_pos, "expression is not assignable");
+    }
     // Is prefix.
     LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
     Token::Kind binary_op =
@@ -8155,7 +8201,7 @@
                                            intptr_t ident_pos) {
   // If the static field has an initializer, initialize the field at compile
   // time, which is only possible if the field is const.
-  AstNode* initializing_getter = RunStaticFieldInitializer(field);
+  AstNode* initializing_getter = RunStaticFieldInitializer(field, ident_pos);
   if (initializing_getter != NULL) {
     // The field is not yet initialized and could not be initialized at compile
     // time. The getter will initialize the field.
@@ -8188,7 +8234,6 @@
                                         bool consume_cascades) {
   TRACE_PARSER("ParseStaticFieldAccess");
   AstNode* access = NULL;
-  const intptr_t call_pos = TokenPos();
   const Field& field = Field::ZoneHandle(cls.LookupStaticField(field_name));
   Function& func = Function::ZoneHandle();
   if (field.IsNull()) {
@@ -8205,14 +8250,14 @@
       // there is a function of the same name.
       func = cls.LookupStaticFunction(field_name);
       if (!func.IsNull()) {
-        access = CreateImplicitClosureNode(func, call_pos, NULL);
+        access = CreateImplicitClosureNode(func, ident_pos, NULL);
       } else {
         // No function to closurize found found.
         // This field access may turn out to be a call to the setter.
         // Create a getter call, which may later be turned into
         // a setter call, or else the backend will generate
         // a throw NoSuchMethodError().
-        access = new StaticGetterNode(call_pos,
+        access = new StaticGetterNode(ident_pos,
                                       NULL,
                                       false,
                                       Class::ZoneHandle(cls.raw()),
@@ -8220,14 +8265,14 @@
       }
     } else {
       ASSERT(func.kind() != RawFunction::kImplicitStaticFinalGetter);
-      access = new StaticGetterNode(call_pos,
+      access = new StaticGetterNode(ident_pos,
                                     NULL,
                                     false,
                                     Class::ZoneHandle(cls.raw()),
                                     field_name);
     }
   } else {
-    access = GenerateStaticFieldLookup(field, TokenPos());
+    access = GenerateStaticFieldLookup(field, ident_pos);
   }
   return access;
 }
@@ -8530,6 +8575,9 @@
   expr = ParseSelectors(expr, false);
   if (IsIncrementOperator(CurrentToken())) {
     TRACE_PARSER("IncrementOperator");
+    if (!IsLegalAssignableSyntax(expr, TokenPos())) {
+      ErrorMsg(expr_pos, "expression is not assignable");
+    }
     Token::Kind incr_op = CurrentToken();
     ConsumeToken();
     // Not prefix.
@@ -8736,7 +8784,8 @@
 // If the field is already initialized, return no ast (NULL).
 // Otherwise, if the field is constant, initialize the field and return no ast.
 // If the field is not initialized and not const, return the ast for the getter.
-AstNode* Parser::RunStaticFieldInitializer(const Field& field) {
+AstNode* Parser::RunStaticFieldInitializer(const Field& field,
+                                           intptr_t field_ref_pos) {
   ASSERT(field.is_static());
   const Class& field_owner = Class::ZoneHandle(field.owner());
   const String& field_name = String::ZoneHandle(field.name());
@@ -8750,7 +8799,7 @@
                field_name.ToCString());
     } else {
       // The implicit static getter will throw the exception if necessary.
-      return new StaticGetterNode(TokenPos(),
+      return new StaticGetterNode(field_ref_pos,
                                   NULL,
                                   false,
                                   field_owner,
@@ -8782,7 +8831,7 @@
           field.set_value(Object::null_instance());
           // It is a compile-time error if evaluation of a compile-time constant
           // would raise an exception.
-          AppendErrorMsg(error, TokenPos(),
+          AppendErrorMsg(error, field_ref_pos,
                          "error initializing const field '%s'",
                          String::Handle(field.name()).ToCString());
         } else {
@@ -8792,11 +8841,11 @@
       ASSERT(const_value.IsNull() || const_value.IsInstance());
       Instance& instance = Instance::Handle();
       instance ^= const_value.raw();
-      instance = TryCanonicalize(instance, TokenPos());
+      instance = TryCanonicalize(instance, field_ref_pos);
       field.set_value(instance);
       return NULL;   // Constant
     } else {
-      return new StaticGetterNode(TokenPos(),
+      return new StaticGetterNode(field_ref_pos,
                                   NULL,
                                   false,
                                   field_owner,
@@ -8808,7 +8857,11 @@
     return NULL;
   }
   ASSERT(getter.kind() == RawFunction::kImplicitGetter);
-  return new StaticGetterNode(TokenPos(), NULL, false, field_owner, field_name);
+  return new StaticGetterNode(field_ref_pos,
+                              NULL,
+                              false,
+                              field_owner,
+                              field_name);
 }
 
 
@@ -10321,21 +10374,23 @@
                      current_function().origin()).Name()).ToCString());
       }
     }
+    const intptr_t super_pos = TokenPos();
     ConsumeToken();
     if (CurrentToken() == Token::kPERIOD) {
       ConsumeToken();
+      const intptr_t ident_pos = TokenPos();
       const String& ident = *ExpectIdentifier("identifier expected");
       if (CurrentToken() == Token::kLPAREN) {
         primary = ParseSuperCall(ident);
       } else {
-        primary = ParseSuperFieldAccess(ident);
+        primary = ParseSuperFieldAccess(ident, ident_pos);
       }
     } else if ((CurrentToken() == Token::kLBRACK) ||
         Token::CanBeOverloaded(CurrentToken()) ||
         (CurrentToken() == Token::kNE)) {
       primary = ParseSuperOperator();
     } else {
-      primary = new PrimaryNode(TokenPos(), Symbols::Super());
+      primary = new PrimaryNode(super_pos, Symbols::Super());
     }
   } else {
     UnexpectedToken();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index fc9ddbe..a500605 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -318,7 +318,8 @@
   void CheckRecursiveInvocation();
 
   const Instance& EvaluateConstExpr(intptr_t expr_pos, AstNode* expr);
-  AstNode* RunStaticFieldInitializer(const Field& field);
+  AstNode* RunStaticFieldInitializer(const Field& field,
+                                     intptr_t field_ref_pos);
   RawObject* EvaluateConstConstructorCall(
       const Class& type_class,
       const AbstractTypeArguments& type_arguments,
@@ -421,7 +422,7 @@
                                 bool resolve_getter,
                                 bool* is_no_such_method);
   AstNode* ParseSuperCall(const String& function_name);
-  AstNode* ParseSuperFieldAccess(const String& field_name);
+  AstNode* ParseSuperFieldAccess(const String& field_name, intptr_t field_pos);
   AstNode* ParseSuperOperator();
   AstNode* BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super);
 
@@ -639,6 +640,7 @@
 
   void EnsureExpressionTemp();
   void EnsureSavedCurrentContext();
+  bool IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos);
   AstNode* CreateAssignmentNode(AstNode* original,
                                 AstNode* rhs,
                                 const String* left_ident,
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 211c15e..fcbed02 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -77,6 +77,7 @@
                   false,  // Not const.
                   false,  // Not abstract.
                   false,  // Not external.
+                  false,  // Not native.
                   owner,
                   0));  // No token position.
 
diff --git a/runtime/vm/runtime_entry_test.cc b/runtime/vm/runtime_entry_test.cc
index 138bea7..687782a 100644
--- a/runtime/vm/runtime_entry_test.cc
+++ b/runtime/vm/runtime_entry_test.cc
@@ -20,7 +20,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   const Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function);
   owner_class.SetFunctions(functions);
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 70db148..bd9d7d1 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -33,7 +33,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 20f6a23..c4bc94d 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -33,7 +33,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index 71bcecf..25b3a7c 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -33,7 +33,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index 09fb677..27e3c3f 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -33,7 +33,7 @@
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class, 0));
   return &function;
 }
 
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 5401651..ac7b0d9 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -134,9 +134,9 @@
   V(Int, "int")                                                                \
   V(Double, "double")                                                          \
   V(_Float32x4, "_Float32x4")                                                  \
-  V(_Int32x4, "_Int32x4")                                                    \
+  V(_Int32x4, "_Int32x4")                                                      \
   V(Float32x4, "Float32x4")                                                    \
-  V(Int32x4, "Int32x4")                                                      \
+  V(Int32x4, "Int32x4")                                                        \
   V(Int8List, "Int8List")                                                      \
   V(Int8ListFactory, "Int8List.")                                              \
   V(Uint8List, "Uint8List")                                                    \
@@ -157,8 +157,8 @@
   V(Uint64ListFactory, "Uint64List.")                                          \
   V(Float32x4List, "Float32x4List")                                            \
   V(Float32x4ListFactory, "Float32x4List.")                                    \
-  V(Int32x4List, "Int32x4List")                                              \
-  V(Int32x4ListFactory, "Int32x4List.")                                      \
+  V(Int32x4List, "Int32x4List")                                                \
+  V(Int32x4ListFactory, "Int32x4List.")                                        \
   V(Float32List, "Float32List")                                                \
   V(Float32ListFactory, "Float32List.")                                        \
   V(Float64List, "Float64List")                                                \
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index cca7e1a..7ffa38f 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -151,7 +151,7 @@
   cls.set_library(lib);
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, cls, 0));
+                    true, false, false, false, false, cls, 0));
   code_ = Code::FinalizeCode(function, assembler_);
   if (FLAG_disassemble) {
     OS::Print("Code for test '%s' {\n", name_);
@@ -179,7 +179,7 @@
        Class::New(function_name, Script::Handle(), Scanner::kDummyTokenIndex));
   function_ = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, cls, 0);
+      true, false, false, false, false, cls, 0);
   function_.set_result_type(Type::Handle(Type::DynamicType()));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function_);
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index 38c18ee..2b08494 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -11,6 +11,7 @@
 import "tree/tree.dart";
 import "util/util.dart";
 import "elements/modelx.dart" show ElementX, FunctionElementX, ClassElementX;
+import "elements/visitor.dart" show ElementVisitor;
 
 class ClosureNamer {
   String getClosureVariableName(String name, int id) {
@@ -98,6 +99,8 @@
   }
 
   String toString() => "ClosureFieldElement($name)";
+
+  accept(ElementVisitor visitor) => visitor.visitClosureFieldElement(this);
 }
 
 // TODO(ahe): These classes continuously cause problems.  We need to
@@ -142,6 +145,8 @@
    * The most outer method this closure is declared into.
    */
   final Element methodElement;
+
+  accept(ElementVisitor visitor) => visitor.visitClosureClassElement(this);
 }
 
 // TODO(ahe): These classes continuously cause problems.  We need to
@@ -152,6 +157,8 @@
       : super(name, ElementKind.VARIABLE_LIST, enclosingElement);
 
   DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
+  accept(ElementVisitor visitor) => visitor.visitBoxElement(this);
 }
 
 // TODO(ngeoffray, ahe): These classes continuously cause problems.  We need to
@@ -168,6 +175,8 @@
   }
 
   final Element variableElement;
+
+  accept(ElementVisitor visitor) => visitor.visitBoxFieldElement(this);
 }
 
 // TODO(ahe): These classes continuously cause problems.  We need to
@@ -184,21 +193,8 @@
   // Since there is no declaration corresponding to 'this', use the position of
   // the enclosing method.
   Token position() => enclosingElement.position();
-}
 
-// TODO(ahe): These classes continuously cause problems.  We need to
-// move these classes to elements/modelx.dart or see if we can find a
-// more general solution.
-class CheckVariableElement extends ElementX {
-  Element parameter;
-  CheckVariableElement(String name, this.parameter, Element enclosing)
-      : super(name, ElementKind.VARIABLE, enclosing);
-
-  DartType computeType(Compiler compiler) => compiler.types.dynamicType;
-
-  // Since there is no declaration for the synthetic 'check' variable, use
-  // parameter.
-  Token position() => parameter.position();
+  accept(ElementVisitor visitor) => visitor.visitThisElement(this);
 }
 
 // The box-element for a scope, and the captured variables that need to be
@@ -258,11 +254,6 @@
 
   bool isClosure() => closureElement != null;
 
-  bool isVariableCaptured(Element element) {
-    return freeVariableMapping.containsKey(element)
-        || capturingScopesBox(element);
-  }
-
   bool capturingScopesBox(Element element) {
     return capturingScopes.values.any((scope) {
       return scope.boxedLoopVariables.contains(element);
@@ -294,14 +285,6 @@
       scope.capturedVariableMapping.forEach(f);
     });
   }
-
-  void forEachNonBoxedCapturedVariable(void f(Element local, Element field)) {
-    freeVariableMapping.forEach((variable, copy) {
-      if (variable is BoxElement) return;
-      if (isVariableBoxed(variable)) return;
-      f(variable, copy);
-    });
-  }
 }
 
 class ClosureTranslator extends Visitor {
diff --git a/sdk/lib/_internal/compiler/implementation/code_buffer.dart b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
index f63a99a..00baef1 100644
--- a/sdk/lib/_internal/compiler/implementation/code_buffer.dart
+++ b/sdk/lib/_internal/compiler/implementation/code_buffer.dart
@@ -74,8 +74,6 @@
 
   CodeBuffer addAll(Iterable<Object> iterable) => writeAll(iterable);
 
-  CodeBuffer addCharCode(int charCode) => writeCharCode(charCode);
-
   CodeBuffer writeCharCode(int charCode) {
     buffer.writeCharCode(charCode);
     return this;
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index fd1163e..628ee9c 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -189,19 +189,6 @@
     });
   }
 
-  /**
-   * Returns an [Iterable] of static const fields that need to be initialized.
-   * The fields must be evaluated in order since they might depend on each
-   * other.
-   */
-  Iterable<VariableElement> getStaticFinalFieldsForEmission() {
-    return initialVariableValues.keys.where((element) {
-      return element.kind == ElementKind.FIELD
-          && !element.isInstanceMember()
-          && element.modifiers.isFinal();
-    });
-  }
-
   List<VariableElement> getLazilyInitializedFieldsForEmission() {
     return new List<VariableElement>.from(lazyStatics);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 1ded67e..c49df9d 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -87,12 +87,6 @@
 
   void initializeHelperClasses() {}
 
-  void enqueueAllTopLevelFunctions(LibraryElement lib, Enqueuer world) {
-    lib.forEachExport((Element e) {
-      if (e.isFunction()) world.addToWorkList(e);
-    });
-  }
-
   void enqueueHelpers(ResolutionEnqueuer world, TreeElements elements);
   void codegen(CodegenWorkItem work);
 
@@ -1088,7 +1082,14 @@
     enqueuer.resolution.logSummary(log);
 
     if (compilationFailed) return;
-    if (analyzeOnly) return;
+    if (analyzeOnly) {
+      if (!analyzeAll) {
+        // No point in reporting unused code when [analyzeAll] is true: all
+        // code is artificially used.
+        reportUnusedCode();
+      }
+      return;
+    }
     assert(main != null);
     phase = PHASE_DONE_RESOLVING;
 
@@ -1518,6 +1519,28 @@
     }
     return firstToken;
   }
+
+  void reportUnusedCode() {
+    void checkLive(member) {
+      if (member.isFunction()) {
+        if (!enqueuer.resolution.isLive(member)) {
+          reportHint(member, MessageKind.UNUSED_METHOD,
+                     {'method_name': member.name});
+        }
+      } else if (member.isClass() && !member.isMixinApplication) {
+        member.forEachLocalMember(checkLive);
+      }
+    }
+    libraries.forEach((_, library) {
+      // TODO(ahe): Implement better heuristics to discover entry points of
+      // packages and use that to discover unused implementation details in
+      // packages.
+      if (library.isPlatformLibrary || library.isPackageLibrary) return;
+      library.compilationUnits.forEach((unit) {
+        unit.forEachLocalMember(checkLive);
+      });
+    });
+  }
 }
 
 class CompilerTask {
diff --git a/sdk/lib/_internal/compiler/implementation/constant_system.dart b/sdk/lib/_internal/compiler/implementation/constant_system.dart
index b2e2b54..4a10d40 100644
--- a/sdk/lib/_internal/compiler/implementation/constant_system.dart
+++ b/sdk/lib/_internal/compiler/implementation/constant_system.dart
@@ -6,13 +6,11 @@
 
 abstract class Operation {
   String get name;
-  bool isUserDefinable();
 }
 
 abstract class UnaryOperation extends Operation {
   /** Returns [:null:] if it was unable to fold the operation. */
   Constant fold(Constant constant);
-  apply(value);
 }
 
 abstract class BinaryOperation extends Operation {
diff --git a/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart b/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
index a1067c3..64b6003 100644
--- a/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
+++ b/sdk/lib/_internal/compiler/implementation/constant_system_dart.dart
@@ -8,7 +8,6 @@
 
 class BitNotOperation implements UnaryOperation {
   final String name = '~';
-  bool isUserDefinable() => true;
   const BitNotOperation();
   Constant fold(Constant constant) {
     if (constant.isInt()) {
@@ -17,12 +16,10 @@
     }
     return null;
   }
-  apply(value) => ~value;
 }
 
 class NegateOperation implements UnaryOperation {
   final String name = 'negate';
-  bool isUserDefinable() => true;
   const NegateOperation();
   Constant fold(Constant constant) {
     if (constant.isInt()) {
@@ -35,12 +32,10 @@
     }
     return null;
   }
-  apply(value) => -value;
 }
 
 class NotOperation implements UnaryOperation {
   final String name = '!';
-  bool isUserDefinable() => true;
   const NotOperation();
   Constant fold(Constant constant) {
     if (constant.isBool()) {
@@ -49,14 +44,12 @@
     }
     return null;
   }
-  apply(value) => !value;
 }
 
 /**
  * Operations that only work if both arguments are integers.
  */
 abstract class BinaryBitOperation implements BinaryOperation {
-  bool isUserDefinable() => true;
   const BinaryBitOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isInt() && right.isInt()) {
@@ -116,7 +109,6 @@
 }
 
 abstract class BinaryBoolOperation implements BinaryOperation {
-  bool isUserDefinable() => false;
   const BinaryBoolOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isBool() && right.isBool()) {
@@ -146,7 +138,6 @@
 }
 
 abstract class ArithmeticNumOperation implements BinaryOperation {
-  bool isUserDefinable() => true;
   const ArithmeticNumOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isNum() && right.isNum()) {
@@ -228,7 +219,6 @@
 
 class AddOperation implements BinaryOperation {
   final String name = '+';
-  bool isUserDefinable() => true;
   const AddOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isInt() && right.isInt()) {
@@ -249,7 +239,6 @@
 }
 
 abstract class RelationalNumOperation implements BinaryOperation {
-  bool isUserDefinable() => true;
   const RelationalNumOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isNum() && right.isNum()) {
@@ -294,7 +283,6 @@
 
 class EqualsOperation implements BinaryOperation {
   final String name = '==';
-  bool isUserDefinable() => true;
   const EqualsOperation();
   Constant fold(Constant left, Constant right) {
     if (left.isNum() && right.isNum()) {
@@ -317,7 +305,6 @@
 
 class IdentityOperation implements BinaryOperation {
   final String name = '===';
-  bool isUserDefinable() => false;
   const IdentityOperation();
   BoolConstant fold(Constant left, Constant right) {
     // In order to preserve runtime semantics which says that NaN !== NaN don't
diff --git a/sdk/lib/_internal/compiler/implementation/constants.dart b/sdk/lib/_internal/compiler/implementation/constants.dart
index 3e15ab8..d030524 100644
--- a/sdk/lib/_internal/compiler/implementation/constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/constants.dart
@@ -123,10 +123,6 @@
     return compiler.typesTask.nullType;
   }
 
-  void _writeJsCode(CodeBuffer buffer, ConstantHandler handler) {
-    buffer.write(JsNull);
-  }
-
   // The magic constant has no meaning. It is just a random value.
   int get hashCode => 785965825;
   DartString toDartString() => const LiteralDartString("null");
@@ -337,6 +333,7 @@
   final DartType type;
 
   ObjectConstant(this.type);
+
   bool isObject() => true;
 
   DartType computeType(Compiler compiler) => type;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 3138995..1ab6de7 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -220,6 +220,9 @@
         case 'c':
           passThrough('--enable-checked-mode');
           break;
+        case 'm':
+          passThrough('--minify');
+          break;
         default:
           throw 'Internal error: "$shortOption" did not match';
       }
@@ -239,7 +242,7 @@
 
   List<String> arguments = <String>[];
   List<OptionHandler> handlers = <OptionHandler>[
-    new OptionHandler('-[chv?]+', handleShortOptions),
+    new OptionHandler('-[chvm?]+', handleShortOptions),
     new OptionHandler('--throw-on-error',
                       (_) => diagnosticHandler.throwOnError = true),
     new OptionHandler('--suppress-warnings',
@@ -252,7 +255,7 @@
     new OptionHandler('--library-root=.+', setLibraryRoot),
     new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
     new OptionHandler('--allow-mock-compilation', passThrough),
-    new OptionHandler('--minify', passThrough),
+    new OptionHandler('--minify|-m', passThrough),
     new OptionHandler('--force-strip=.*', setStrip),
     new OptionHandler('--disable-diagnostic-colors',
                       (_) => diagnosticHandler.enableColors = false),
@@ -473,6 +476,7 @@
 Common options:
   -o <file> Generate the output into <file>.
   -c        Insert runtime type checks and enable assertions (checked mode).
+  -m        Generate minified output.
   -h        Display this message (add -v for information about all options).''');
 }
 
@@ -489,6 +493,9 @@
   -c, --enable-checked-mode, --checked
     Insert runtime type checks and enable assertions (checked mode).
 
+  -m, --minify
+    Generate minified output.
+
   -h, /h, /?, --help
     Display this message (add -v for information about all options).
 
@@ -517,9 +524,6 @@
     Skip analysis of method bodies and field initializers. This option implies
     --analyze-only.
 
-  --minify
-    Generate minified output.
-
   --suppress-warnings
     Do not display any warnings.
 
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 836d999..2ea2382 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -224,8 +224,6 @@
   }
 
   void codegen(CodegenWorkItem work) { }
-  void processNativeClasses(Enqueuer world,
-                            Iterable<LibraryElement> libraries) { }
 
   bool isUserLibrary(LibraryElement lib) {
     final INTERNAL_HELPERS = [
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 be1ffda..fec7db6 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -370,8 +370,6 @@
     compiler.cancel(reason, node: node);
   }
 
-  void unreachable() { internalError('Unreachable case'); }
-
   visit(Node node) => (node == null) ? null : node.accept(this);
 
   visitNode(Node node) { node.visitChildren(this); }  // We must go deeper.
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index cd9dff9..a4603f0 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -1249,11 +1249,25 @@
                  this.moreSpecificVisitor, this.subtypeVisitor,
                  this.potentialSubtypeVisitor);
 
-  /** Returns true if t is more specific than s */
+  /** Returns true if [t] is more specific than [s]. */
   bool isMoreSpecific(DartType t, DartType s) {
     return moreSpecificVisitor.isMoreSpecific(t, s);
   }
 
+  /**
+   * Returns the most specific type of [t] and [s] or `null` if neither is more
+   * specific than the other.
+   */
+  DartType getMostSpecific(DartType t, DartType s) {
+    if (isMoreSpecific(t, s)) {
+      return t;
+    } else if (isMoreSpecific(s, t)) {
+      return s;
+    } else {
+      return null;
+    }
+  }
+
   /** Returns true if t is a subtype of s */
   bool isSubtype(DartType t, DartType s) {
     return subtypeVisitor.isSubtype(t, s);
@@ -1652,3 +1666,97 @@
     return super.isSubtype(t, s);
   }
 }
+
+/// Visitor used to compute an instantiation of a generic type that is more
+/// specific than a given type.
+///
+/// The visitor tries to compute constraints for all type variables in the
+/// visited type by structurally matching it with the argument type. If the
+/// constraints are too complex or the two types are too different, `false`
+/// is returned. Otherwise, the [constraintMap] holds the valid constraints.
+class MoreSpecificSubtypeVisitor extends DartTypeVisitor<bool, DartType> {
+  final Compiler compiler;
+  Map<TypeVariableType, DartType> constraintMap;
+
+  MoreSpecificSubtypeVisitor(Compiler this.compiler);
+
+  /// Compute an instance of [element] which is more specific than [supertype].
+  /// If no instance is found, `null` is returned.
+  ///
+  /// Note that this computation is a heuristic. It does not find a suggestion
+  /// in all possible cases.
+  InterfaceType computeMoreSpecific(ClassElement element,
+                                    InterfaceType supertype) {
+    InterfaceType supertypeInstance =
+        element.thisType.asInstanceOf(supertype.element);
+    if (supertypeInstance == null) return null;
+
+    constraintMap = new Map<TypeVariableType, DartType>();
+    element.typeVariables.forEach((TypeVariableType typeVariable) {
+      constraintMap[typeVariable] = compiler.types.dynamicType;
+    });
+    if (supertypeInstance.accept(this, supertype)) {
+      LinkBuilder<DartType> typeArguments = new LinkBuilder<DartType>();
+      element.typeVariables.forEach((TypeVariableType typeVariable) {
+        typeArguments.addLast(constraintMap[typeVariable]);
+      });
+      return element.thisType._createType(typeArguments.toLink());
+    }
+    return null;
+  }
+
+  bool visitType(DartType type, DartType argument) {
+    return compiler.types.isMoreSpecific(type, argument);
+  }
+
+  bool visitTypes(Link<DartType> a, Link<DartType> b) {
+    while (!a.isEmpty && !b.isEmpty) {
+      if (!a.head.accept(this, b.head)) return false;
+      a = a.tail;
+      b = b.tail;
+    }
+    return a.isEmpty && b.isEmpty;
+  }
+
+  bool visitTypeVariableType(TypeVariableType type, DartType argument) {
+    DartType constraint =
+        compiler.types.getMostSpecific(constraintMap[type], argument);
+    constraintMap[type] = constraint;
+    return constraint != null;
+  }
+
+  bool visitFunctionType(FunctionType type, DartType argument) {
+    if (argument is FunctionType) {
+      if (type.parameterTypes.slowLength() !=
+          argument.parameterTypes.slowLength()) {
+        return false;
+      }
+      if (type.optionalParameterTypes.slowLength() !=
+          argument.optionalParameterTypes.slowLength()) {
+        return false;
+      }
+      if (type.namedParameters != argument.namedParameters) {
+        return false;
+      }
+
+      if (!type.returnType.accept(this, argument.returnType)) return false;
+      if (visitTypes(type.parameterTypes, argument.parameterTypes)) {
+        return false;
+      }
+      if (visitTypes(type.optionalParameterTypes,
+                     argument.optionalParameterTypes)) {
+        return false;
+      }
+      return visitTypes(type.namedParameterTypes, argument.namedParameterTypes);
+    }
+    return false;
+  }
+
+  bool visitGenericType(GenericType type, DartType argument) {
+    if (argument is GenericType) {
+      if (type.element != argument.element) return false;
+      return visitTypes(type.typeArguments, argument.typeArguments);
+    }
+    return false;
+  }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 52c6b30..f06f740 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -30,6 +30,8 @@
 
 import '../ordered_typeset.dart' show OrderedTypeSet;
 
+import 'visitor.dart' show ElementVisitor;
+
 const int STATE_NOT_STARTED = 0;
 const int STATE_STARTED = 1;
 const int STATE_DONE = 2;
@@ -257,6 +259,8 @@
   FunctionElement get targetConstructor;
 
   void diagnose(Element context, DiagnosticListener listener);
+
+  accept(ElementVisitor visitor);
 }
 
 class Elements {
@@ -580,13 +584,6 @@
     return false;
   }
 
-  static bool switchStatementHasDefault(SwitchStatement node) {
-    for (SwitchCase switchCase in node.cases) {
-      if (switchCase.isDefaultCase) return true;
-    }
-    return false;
-  }
-
   static bool isUnusedLabel(LabeledStatement node, TreeElements elements) {
     Node body = node.statement;
     TargetElement element = elements[body];
@@ -657,12 +654,18 @@
   Link<Element> get exports;
 
   /**
-   * [:true:] if this library is part of the platform, that is its canonical
+   * [:true:] if this library is part of the platform, that is, its canonical
    * uri has the scheme 'dart'.
    */
   bool get isPlatformLibrary;
 
   /**
+   * [:true:] if this library is from a package, that is, its canonical uri has
+   * the scheme 'package'.
+   */
+  bool get isPackageLibrary;
+
+  /**
    * [:true:] if this library is a platform library whose path starts with
    * an underscore.
    */
@@ -905,16 +908,11 @@
   Element lookupSuperMemberInLibrary(String memberName,
                                      LibraryElement library);
 
-  Element lookupSuperInterfaceMember(String memberName,
-                                     LibraryElement fromLibrary);
-
   Element validateConstructorLookupResults(Selector selector,
                                            Element result,
                                            Element noMatch(Element));
 
   Element lookupConstructor(Selector selector, [Element noMatch(Element)]);
-  Element lookupFactoryConstructor(Selector selector,
-                                   [Element noMatch(Element)]);
 
   void forEachMember(void f(ClassElement enclosingClass, Element member),
                      {bool includeBackendMembers: false,
@@ -990,3 +988,5 @@
 
   MetadataAnnotation ensureResolved(Compiler compiler);
 }
+
+abstract class VoidElement extends Element {}
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index b53316f..215b989 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -31,7 +31,9 @@
 
 import '../ordered_typeset.dart' show OrderedTypeSet;
 
-class ElementX implements Element {
+import 'visitor.dart' show ElementVisitor;
+
+abstract class ElementX implements Element {
   static int elementHashCode = 0;
 
   final String name;
@@ -285,8 +287,6 @@
 
   FunctionElement asFunctionElement() => null;
 
-  static bool isInvalid(Element e) => e == null || e.isErroneous();
-
   bool get isAbstract => modifiers.isAbstract();
   bool isForeign(Compiler compiler) => getLibrary() == compiler.foreignLibrary;
 
@@ -356,6 +356,8 @@
   String get message => '${messageKind.message(messageArguments)}';
 
   String toString() => '<$name: $message>';
+
+  accept(ElementVisitor visitor) => visitor.visitErroneousElement(this);
 }
 
 /// A message attached to a [WarnOnUseElementX].
@@ -416,6 +418,8 @@
     }
     return unwrapped;
   }
+
+  accept(ElementVisitor visitor) => visitor.visitWarnOnUseElement(this);
 }
 
 /**
@@ -483,6 +487,8 @@
       });
     }
   }
+
+  accept(ElementVisitor visitor) => visitor.visitAmbiguousElement(this);
 }
 
 class ScopeX {
@@ -637,6 +643,8 @@
     if (this == other) return 0;
     return '${script.uri}'.compareTo('${other.script.uri}');
   }
+
+  accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this);
 }
 
 class Importers {
@@ -975,7 +983,9 @@
 
   Scope buildScope() => new LibraryScope(this);
 
-  bool get isPlatformLibrary => canonicalUri.scheme == "dart";
+  bool get isPlatformLibrary => canonicalUri.scheme == 'dart';
+
+  bool get isPackageLibrary => canonicalUri.scheme == 'package';
 
   bool get isInternalLibrary =>
       isPlatformLibrary && canonicalUri.path.startsWith('_');
@@ -994,6 +1004,8 @@
     if (this == other) return 0;
     return getLibraryOrScriptName().compareTo(other.getLibraryOrScriptName());
   }
+
+  accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
 }
 
 class PrefixElementX extends ElementX implements PrefixElement {
@@ -1013,6 +1025,8 @@
   void addImport(Element element, Import import, DiagnosticListener listener) {
     importScope.addImport(this, element, import, listener);
   }
+
+  accept(ElementVisitor visitor) => visitor.visitPrefixElement(this);
 }
 
 class TypedefElementX extends ElementX implements TypedefElement {
@@ -1096,6 +1110,8 @@
     computeType(compiler).accept(visitor, null);
     hasBeenCheckedForCycles = true;
   }
+
+  accept(ElementVisitor visitor) => visitor.visitTypedefElement(this);
 }
 
 class VariableElementX extends ElementX implements VariableElement {
@@ -1111,6 +1127,12 @@
     : this.variables = variables,
       super(name, kind, variables.enclosingElement);
 
+  VariableElementX.synthetic(String name,
+      ElementKind kind,
+      Element enclosing) :
+        variables = null,
+        super(name, kind, enclosing);
+
   Node parseNode(DiagnosticListener listener) {
     if (cachedNode != null) return cachedNode;
     VariableDefinitions definitions = variables.parseNode(listener);
@@ -1133,13 +1155,13 @@
     return variables.computeType(compiler);
   }
 
-  DartType get type => variables.type;
-
   bool isInstanceMember() => variables.isInstanceMember();
 
   // Note: cachedNode.getBeginToken() will not be correct in all
   // cases, for example, for function typed parameters.
   Token position() => findMyName(variables.position());
+
+  accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
 }
 
 /**
@@ -1163,6 +1185,8 @@
     }
     return super.computeType(compiler);
   }
+
+  accept(ElementVisitor visitor) => visitor.visitFieldParameterElement(this);
 }
 
 // This element represents a list of variable or field declaration.
@@ -1231,6 +1255,8 @@
   bool isInstanceMember() {
     return isMember() && !modifiers.isStatic();
   }
+
+  accept(ElementVisitor visitor) => visitor.visitVariableListElement(this);
 }
 
 class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
@@ -1282,6 +1308,13 @@
   bool isInstanceMember() {
     return isMember() && !modifiers.isStatic();
   }
+
+  accept(ElementVisitor visitor) => visitor.visitAbstractFieldElement(this);
+
+  bool get isAbstract {
+    return getter != null && getter.isAbstract
+        || setter != null && setter.isAbstract;
+  }
 }
 
 // TODO(johnniwinther): [FunctionSignature] should be merged with
@@ -1549,6 +1582,8 @@
            (isFunction() || isAccessor()) &&
            _hasNoBody;
   }
+
+  accept(ElementVisitor visitor) => visitor.visitFunctionElement(this);
 }
 
 class ConstructorBodyElementX extends FunctionElementX
@@ -1578,6 +1613,8 @@
   }
 
   Token position() => constructor.position();
+
+  accept(ElementVisitor visitor) => visitor.visitConstructorBodyElement(this);
 }
 
 /**
@@ -1626,15 +1663,21 @@
   get declaration => this;
   get implementation => this;
   get defaultImplementation => this;
+
+  accept(ElementVisitor visitor) {
+    return visitor.visitFunctionElement(this);
+  }
 }
 
-class VoidElementX extends ElementX {
+class VoidElementX extends ElementX implements VoidElement {
   VoidElementX(Element enclosing) : super('void', ElementKind.VOID, enclosing);
   DartType computeType(compiler) => compiler.types.voidType;
   Node parseNode(_) {
     throw 'internal error: parseNode on void';
   }
   bool impliesType() => true;
+
+  accept(ElementVisitor visitor) => visitor.visitVoidElement(this);
 }
 
 class TypeDeclarationElementX {
@@ -1730,11 +1773,10 @@
 
   bool get isUnnamedMixinApplication => false;
 
-  // TODO(johnniwinther): Add [thisType] getter similar to [rawType].
-  InterfaceType computeType(Compiler compiler) {
+  void computeThisAndRawType(Compiler compiler, Link<DartType> typeVariables) {
     if (thisType == null) {
       if (origin == null) {
-        Link<DartType> parameters = computeTypeParameters(compiler);
+        Link<DartType> parameters = typeVariables;
         thisType = new InterfaceType(this, parameters);
         if (parameters.isEmpty) {
           rawTypeCache = thisType;
@@ -1751,6 +1793,13 @@
         rawTypeCache = origin.rawType;
       }
     }
+  }
+
+  // TODO(johnniwinther): Add [thisType] getter similar to [rawType].
+  InterfaceType computeType(Compiler compiler) {
+    if (thisType == null) {
+      computeThisAndRawType(compiler, computeTypeParameters(compiler));
+    }
     return thisType;
   }
 
@@ -1832,22 +1881,6 @@
     return null;
   }
 
-  Element lookupSuperInterfaceMember(String memberName,
-                                     LibraryElement fromLibrary) {
-    bool isPrivate = isPrivateName(memberName);
-    for (InterfaceType t in interfaces) {
-      ClassElement cls = t.element;
-      Element e = cls.lookupLocalMember(memberName);
-      if (e == null) continue;
-      // Private members from a different library are not visible.
-      if (isPrivate && !identical(fromLibrary, e.getLibrary())) continue;
-      // Static members are not inherited.
-      if (e.modifiers.isStatic()) continue;
-      return e;
-    }
-    return null;
-  }
-
   /**
    * Find the first member in the class chain with the given [selector].
    *
@@ -1968,13 +2001,6 @@
     return validateConstructorLookupResults(selector, result, noMatch);
   }
 
-  Element lookupFactoryConstructor(Selector selector,
-                                   [Element noMatch(Element)]) {
-    String constructorName = selector.name;
-    Element result = localLookup(constructorName);
-    return validateConstructorLookupResults(selector, result, noMatch);
-  }
-
   Link<Element> get constructors {
     // TODO(ajohnsen): See if we can avoid this method at some point.
     Link<Element> result = const Link<Element>();
@@ -2256,10 +2282,16 @@
 
   Link<DartType> computeTypeParameters(Compiler compiler) {
     NamedMixinApplication named = node.asNamedMixinApplication();
-    if (named == null) return const Link<DartType>();
+    if (named == null) {
+      throw new SpannableAssertionFailure(node,
+          "Type variables on unnamed mixin applications must be set on "
+          "creation.");
+    }
     return TypeDeclarationElementX.createTypeVariables(
         this, named.typeParameters);
   }
+
+  accept(ElementVisitor visitor) => visitor.visitMixinApplicationElement(this);
 }
 
 class LabelElementX extends ElementX implements LabelElement {
@@ -2296,6 +2328,8 @@
 
   Token position() => label.getBeginToken();
   String toString() => "${labelName}:";
+
+  accept(ElementVisitor visitor) => visitor.visitLabelElement(this);
 }
 
 // Represents a reference to a statement or switch-case, either by label or the
@@ -2324,6 +2358,8 @@
 
   Token position() => statement.getBeginToken();
   String toString() => statement.toString();
+
+  accept(ElementVisitor visitor) => visitor.visitTargetElement(this);
 }
 
 class TypeVariableElementX extends ElementX implements TypeVariableElement {
@@ -2331,7 +2367,7 @@
   TypeVariableType type;
   DartType bound;
 
-  TypeVariableElementX(name, Element enclosing, this.cachedNode,
+  TypeVariableElementX(String name, Element enclosing, this.cachedNode,
                        [this.type, this.bound])
     : super(name, ElementKind.TYPE_VARIABLE, enclosing);
 
@@ -2342,6 +2378,8 @@
   String toString() => "${enclosingElement.toString()}.${name}";
 
   Token position() => cachedNode.getBeginToken();
+
+  accept(ElementVisitor visitor) => visitor.visitTypeVariableElement(this);
 }
 
 /**
diff --git a/sdk/lib/_internal/compiler/implementation/elements/visitor.dart b/sdk/lib/_internal/compiler/implementation/elements/visitor.dart
new file mode 100644
index 0000000..f8f1377
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/elements/visitor.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.
+
+library visitor;
+
+import 'elements.dart';
+import '../ssa/ssa.dart'
+    show InterceptedElement;
+import '../closure.dart'
+    show ThisElement,
+         BoxElement,
+         BoxFieldElement,
+         ClosureClassElement,
+         ClosureFieldElement;
+
+abstract class ElementVisitor<R> {
+  R visit(Element e) => e.accept(this);
+
+  R visitElement(Element e);
+  R visitErroneousElement(ErroneousElement e) => visitFunctionElement(e);
+  R visitWarnOnUseElement(WarnOnUseElement e) => visitElement(e);
+  R visitAmbiguousElement(AmbiguousElement e) => visitElement(e);
+  R visitScopeContainerElement(ScopeContainerElement e) => visitElement(e);
+  R visitCompilationUnitElement(CompilationUnitElement e) => visitElement(e);
+  R visitLibraryElement(LibraryElement e) => visitScopeContainerElement(e);
+  R visitPrefixElement(PrefixElement e) => visitElement(e);
+  R visitTypedefElement(TypedefElement e) => visitElement(e);
+  R visitVariableElement(VariableElement e) => visitElement(e);
+  R visitFieldParameterElement(FieldParameterElement e) => visitElement(e);
+  R visitVariableListElement(VariableListElement e) => visitElement(e);
+  R visitAbstractFieldElement(AbstractFieldElement e) => visitElement(e);
+  R visitFunctionElement(FunctionElement e) => visitElement(e);
+  R visitConstructorBodyElement(ConstructorBodyElement e) => visitElement(e);
+  R visitClassElement(ClassElement e) => visitScopeContainerElement(e);
+  R visitTypeDeclarationElement(TypeDeclarationElement e) => visitElement(e);
+  R visitMixinApplicationElement(MixinApplicationElement e) {
+    visitClassElement(e);
+  }
+  R visitVoidElement(VoidElement e) => visitElement(e);
+  R visitLabelElement(LabelElement e) => visitElement(e);
+  R visitTargetElement(TargetElement e) => visitElement(e);
+  R visitTypeVariableElement(TypeVariableElement e) => visitElement(e);
+  R visitInterceptedElement(InterceptedElement e) => visitElement(e);
+  R visitThisElement(ThisElement e) => visitElement(e);
+  R visitBoxElement(BoxElement e) => visitElement(e);
+  R visitBoxFieldElement(BoxFieldElement e) => visitElement(e);
+  R visitClosureClassElement(ClosureClassElement e) => visitClassElement(e);
+  R visitClosureFieldElement(ClosureFieldElement e) => visitVariableElement(e);
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
index 3b75903..cb204ae 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
@@ -134,7 +134,14 @@
 
   // The set of [TypeInformation] where the traced container could
   // flow in, and operations done on them.
-  final Setlet<TypeInformation> allUsers = new Setlet<TypeInformation>();
+  final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
+
+  // Work list that gets populated with [TypeInformation] that could
+  // contain the container.
+  final List<TypeInformation> workList = <TypeInformation>[];
+
+  // The current [TypeInformation] in the analysis.
+  TypeInformation currentUser;
 
   // The list of found assignments to the container.
   final List<TypeInformation> assignments = <TypeInformation>[];
@@ -148,22 +155,23 @@
   ContainerTracerVisitor(this.container, inferrer)
       : this.inferrer = inferrer, this.compiler = inferrer.compiler;
 
+  void addNewEscapeInformation(TypeInformation info) {
+    if (flowsInto.contains(info)) return;
+    flowsInto.add(info);
+    workList.add(info);
+  }
+
   List<TypeInformation> run() {
     // Collect the [TypeInformation] where the container can flow in,
     // as well as the operations done on all these [TypeInformation]s.
-    List<TypeInformation> workList = <TypeInformation>[];
-    allUsers.add(container);
-    workList.add(container);
+    addNewEscapeInformation(container);
     while (!workList.isEmpty) {
-      TypeInformation user = workList.removeLast();
-      user.users.forEach((TypeInformation info) {
-        if (allUsers.contains(info)) return;
-        allUsers.add(info);
+      currentUser = workList.removeLast();
+      currentUser.users.forEach((TypeInformation info) {
         analyzedElements.add(info.owner);
-        if (info.reachedBy(user, inferrer)) {
-          workList.add(info);
-        }
+        info.accept(this);
       });
+      if (!continueAnalyzing) break;
       if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
         bailout('Too many users');
         break;
@@ -171,13 +179,6 @@
     }
 
     if (continueAnalyzing) {
-      for (TypeInformation info in allUsers) {
-        info.accept(this);
-        if (!continueAnalyzing) break;
-      }
-    }
-
-    if (continueAnalyzing) {
       if (!callsGrowableMethod && container.inferredLength == null) {
         container.inferredLength = container.originalLength;
       }
@@ -196,10 +197,18 @@
     callsGrowableMethod = true;
   }
 
-  visitNarrowTypeInformation(NarrowTypeInformation info) {}
-  visitPhiElementTypeInformation(PhiElementTypeInformation info) {}
+  visitNarrowTypeInformation(NarrowTypeInformation info) {
+    addNewEscapeInformation(info);
+  }
+
+  visitPhiElementTypeInformation(PhiElementTypeInformation info) {
+    addNewEscapeInformation(info);
+  }
+
   visitElementInContainerTypeInformation(
-      ElementInContainerTypeInformation info) {}
+      ElementInContainerTypeInformation info) {
+    addNewEscapeInformation(info);
+  }
 
   visitContainerTypeInformation(ContainerTypeInformation info) {
     if (container != info) {
@@ -214,17 +223,19 @@
   }
 
   visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
-    analyzedElements.add(info.caller);
     Element called = info.calledElement;
     if (called.isForeign(compiler) && called.name == 'JS') {
       bailout('Used in JS ${info.call}');
     }
+    if (inferrer.types.getInferredTypeOf(called) == currentUser) {
+      addNewEscapeInformation(info);
+    }
   }
 
   visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
     Selector selector = info.selector;
     String selectorName = selector.name;
-    if (allUsers.contains(info.receiver)) {
+    if (currentUser == info.receiver) {
       if (!okSelectorsSet.contains(selectorName)) {
         if (selector.isCall()) {
           int positionalLength = info.arguments.positional.length;
@@ -259,6 +270,13 @@
       bailout('Passed to a closure');
       return;
     }
+
+    if (info.targets
+            .map((element) => inferrer.types.getInferredTypeOf(element))
+            .any((other) => other == currentUser)) {
+      addNewEscapeInformation(info);
+    }
+
   }
 
   bool isClosure(Element element) {
@@ -274,5 +292,6 @@
     if (compiler.backend.isNeededForReflection(info.element)) {
       bailout('Escape in reflection');
     }
+    addNewEscapeInformation(info);
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 2dbdc3b..85f9ed5 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -238,11 +238,6 @@
                           bool inLoop);
 
   /**
-   * Returns the callers of [elements].
-   */
-  Iterable<Element> getCallersOf(Element element);
-
-  /**
    * Notifies to the inferrer that [analyzedElement] can have return
    * type [newType]. [currentType] is the type the [InferrerVisitor]
    * currently found.
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 2598dd3..06d0b06 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -108,10 +108,6 @@
     users = const <TypeInformation>[];
   }
 
-  bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
-    return true;
-  }
-
   /// Reset the analysis of this node by making its type empty.
   void reset(TypeGraphInferrerEngine inferrer) {
     if (abandonInferencing) return;
@@ -439,10 +435,6 @@
 
   Iterable<Element> get callees => [calledElement.implementation];
 
-  bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
-    return info == inferrer.types.getInferredTypeOf(calledElement);
-  }
-
   accept(TypeInformationVisitor visitor) {
     return visitor.visitStaticCallSiteTypeInformation(this);
   }
@@ -680,12 +672,6 @@
     super.removeAndClearReferences(inferrer);
   }
 
-  bool reachedBy(TypeInformation info, TypeGraphInferrerEngine inferrer) {
-    return targets
-            .map((element) => inferrer.types.getInferredTypeOf(element))
-            .any((other) => other == info);
-  }
-
   String toString() => 'Call site $call on ${receiver.type} $type';
 
   accept(TypeInformationVisitor visitor) {
diff --git a/sdk/lib/_internal/compiler/implementation/js/builder.dart b/sdk/lib/_internal/compiler/implementation/js/builder.dart
index e02bd00..8958b50 100644
--- a/sdk/lib/_internal/compiler/implementation/js/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/builder.dart
@@ -90,12 +90,6 @@
     return new Fun(parameters.map(toParameter).toList(), block(body));
   }
 
-  Assignment assign(Expression leftHandSide, Expression value) {
-    return new Assignment(leftHandSide, value);
-  }
-
-  Expression undefined() => new Prefix('void', new LiteralNumber('0'));
-
   VariableDeclarationList defineVar(String name, [initializer]) {
     if (initializer != null) {
       initializer = toExpression(initializer);
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index afc27de..e6268a3 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -481,12 +481,6 @@
     return callWith(arguments);
   }
 
-  Expression equals(expression) => binary('==', expression);
-
-  Expression strictEquals(expression) => binary('===', expression);
-
-  Expression notEquals(expression) => binary('!=', expression);
-
   Expression operator +(expression) => binary('+', expression);
 
   Expression operator -(expression) => binary('-', expression);
@@ -503,10 +497,6 @@
     return new Binary(operator, this, js.toExpression(expression));
   }
 
-  Expression assign(expression) {
-    return new Assignment(this, js.toExpression(expression));
-  }
-
   Expression update(String operator, expression) {
     return new Assignment.compound(this, operator, js.toExpression(expression));
   }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 17c53c0..384ca4e 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -974,10 +974,6 @@
     enqueueInResolution(getTraceFromException(), elements);
   }
 
-  void registerSetRuntimeType(TreeElements elements) {
-    enqueueInResolution(getSetRuntimeTypeInfo(), elements);
-  }
-
   void registerGetRuntimeTypeArgument(TreeElements elements) {
     enqueueInResolution(getGetRuntimeTypeArgument(), elements);
     enqueueInResolution(getGetTypeArgumentByIndex(), elements);
@@ -1326,8 +1322,12 @@
           if (importTag == null) continue;
           LibraryElement importedLibrary = library.getLibraryFromTag(tag);
           if (importedLibrary != compiler.mirrorsLibrary) continue;
+          MessageKind kind =
+              compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(library)
+              ? MessageKind.MIRROR_IMPORT
+              : MessageKind.MIRROR_IMPORT_NO_USAGE;
           compiler.withCurrentElement(library, () {
-            compiler.reportInfo(importTag, MessageKind.MIRROR_IMPORT);
+            compiler.reportInfo(importTag, kind);
           });
         }
       }
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
index e966bc2..206b3df 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_system_javascript.dart
@@ -30,7 +30,6 @@
 
   const JavaScriptBinaryBitOperation(this.dartBitOperation);
 
-  bool isUserDefinable() => dartBitOperation.isUserDefinable();
   String get name => dartBitOperation.name;
 
   Constant fold(Constant left, Constant right) {
@@ -79,7 +78,6 @@
 
   const JavaScriptNegateOperation();
 
-  bool isUserDefinable() => dartNegateOperation.isUserDefinable();
   String get name => dartNegateOperation.name;
 
   Constant fold(Constant constant) {
@@ -91,7 +89,6 @@
     }
     return dartNegateOperation.fold(constant);
   }
-  apply(value) => -value;
 }
 
 class JavaScriptBinaryArithmeticOperation implements BinaryOperation {
@@ -99,7 +96,6 @@
 
   const JavaScriptBinaryArithmeticOperation(this.dartArithmeticOperation);
 
-  bool isUserDefinable() => dartArithmeticOperation.isUserDefinable();
   String get name => dartArithmeticOperation.name;
 
   Constant fold(Constant left, Constant right) {
@@ -116,7 +112,6 @@
 
   const JavaScriptIdentityOperation();
 
-  bool isUserDefinable() => dartIdentityOperation.isUserDefinable();
   String get name => dartIdentityOperation.name;
 
   BoolConstant fold(Constant left, Constant right) {
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index d137184..25f86da 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -298,8 +298,6 @@
     }
   }
 
-  bool isReserved(String name) => name == isolateName;
-
   String constantName(Constant constant) {
     // In the current implementation it doesn't make sense to give names to
     // function constants since the function-implementation itself serves as
@@ -520,13 +518,6 @@
     return '$setterPrefix$name';
   }
 
-  String publicGetterName(String name) {
-    // We dynamically create getters from the field-name. The getter name must
-    // therefore be derived from the instance field-name.
-    String fieldName = getMappedInstanceName(name);
-    return '$getterPrefix$fieldName';
-  }
-
   String getterNameFromAccessorName(String name) {
     // We dynamically create getters from the field-name. The getter name must
     // therefore be derived from the instance field-name.
@@ -828,9 +819,6 @@
 
   String getNameOfGlobalField(VariableElement field) => getNameX(field);
 
-  // TODO(ahe): Remove this method. Use get getNameOfMember instead.
-  String getNameOfGlobalFunction(FunctionElement element) => getNameX(element);
-
   /// Returns true if [element] is stored on current isolate ('$').  We intend
   /// to store only mutable static state in [currentIsolate], constants are
   /// stored in 'C', and functions, accessors, classes, etc. are stored in one
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 4a4d495..9488f91 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -498,7 +498,6 @@
     // Unnamed mixin application classes do not need substitutions, because they
     // are never instantiated and their checks are overwritten by the class that
     // they are mixed into.
-    if (cls.isUnnamedMixinApplication) return null;
     InterfaceType type = cls.computeType(compiler);
     InterfaceType target = type.asInstanceOf(check);
     Link<DartType> typeVariables = cls.typeVariables;
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 60db17c..ac52424 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -748,20 +748,6 @@
         classElement, properties, additionalProperties[classElement]);
   }
 
-  int _selectorRank(Selector selector) {
-    int arity = selector.argumentCount * 3;
-    if (selector.isGetter()) return arity + 2;
-    if (selector.isSetter()) return arity + 1;
-    return arity;
-  }
-
-  int _compareSelectorNames(Selector selector1, Selector selector2) {
-    String name1 = selector1.name.toString();
-    String name2 = selector2.name.toString();
-    if (name1 != name2) return Comparable.compare(name1, name2);
-    return _selectorRank(selector1) - _selectorRank(selector2);
-  }
-
   /**
    * Return a function that returns true if its argument is a class
    * that needs to be emitted.
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index 955acd0..0d521bb 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -120,9 +120,6 @@
 
     bool haveSameTypeVariables(ClassElement a, ClassElement b) {
       if (a.isClosure()) return true;
-      if (b.isUnnamedMixinApplication) {
-        return false;
-      }
       return a.typeVariables == b.typeVariables;
     }
 
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index 7dfd10c..453882a 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -456,7 +456,8 @@
   Map<Uri, LibraryMirror> get libraries {
     _ensureLibraries();
     return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
-        (library) => !library._element.isInternalLibrary);
+        (library) => new bool.fromEnvironment("list_all_libraries") ||
+                     !library._element.isInternalLibrary);
   }
 
   Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors_used.dart b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
index 05ddb81..fad167e 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors_used.dart
@@ -105,11 +105,11 @@
   void analyzeUsage(LibraryElement mainApp) {
     if (compiler.mirrorsLibrary == null) return;
     measure(analyzer.run);
-    List /*<String|Element>*/ symbols = analyzer.mergedMirrorUsage.symbols;
+    List<String> symbols = analyzer.mergedMirrorUsage.symbols;
     List<Element> targets = analyzer.mergedMirrorUsage.targets;
     List<Element> metaTargets = analyzer.mergedMirrorUsage.metaTargets;
     compiler.backend.registerMirrorUsage(
-        symbols == null ? null : new Set/*<String|Element>*/.from(symbols),
+        symbols == null ? null : new Set<String>.from(symbols),
         targets == null ? null : new Set<Element>.from(targets),
         metaTargets == null ? null : new Set<Element>.from(metaTargets));
     librariesWithUsage = analyzer.librariesWithUsage;
@@ -146,17 +146,17 @@
               value, mapper.constantToNodeMap);
 
       if (named.name.source == 'symbols') {
-        analyzer.cachedValues[value] =
+        analyzer.cachedStrings[value] =
             builder.convertToListOfStrings(
                 builder.convertConstantToUsageList(value, onlyStrings: true));
       } else if (named.name.source == 'targets') {
-        analyzer.cachedValues[value] =
+        analyzer.cachedElements[value] =
             builder.resolveUsageList(builder.convertConstantToUsageList(value));
       } else if (named.name.source == 'metaTargets') {
-        analyzer.cachedValues[value] =
+        analyzer.cachedElements[value] =
             builder.resolveUsageList(builder.convertConstantToUsageList(value));
       } else if (named.name.source == 'override') {
-        analyzer.cachedValues[value] =
+        analyzer.cachedElements[value] =
             builder.resolveUsageList(builder.convertConstantToUsageList(value));
       }
     }
@@ -168,13 +168,15 @@
   final MirrorUsageAnalyzerTask task;
   List<LibraryElement> wildcard;
   final Set<LibraryElement> librariesWithUsage;
-  final Map<Constant, List> cachedValues;
+  final Map<Constant, List<String>> cachedStrings;
+  final Map<Constant, List<Element>> cachedElements;
   MirrorUsage mergedMirrorUsage;
 
   MirrorUsageAnalyzer(Compiler compiler, this.task)
       : compiler = compiler,
         librariesWithUsage = new Set<LibraryElement>(),
-        cachedValues = new Map<Constant, List>();
+        cachedStrings = new Map<Constant, List<String>>(),
+        cachedElements = new Map<Constant, List<Element>>();
 
   /// Collect and merge all @MirrorsUsed annotations. As a side-effect, also
   /// compute which libraries have the annotation (which is used by
@@ -304,7 +306,7 @@
       return a;
     }
     // TODO(ahe): Test the following cases.
-    List /*<String|Element>*/ symbols = a.symbols;
+    List<String> symbols = a.symbols;
     if (symbols == null) {
       symbols = b.symbols;
     } else if (b.symbols != null) {
@@ -340,16 +342,16 @@
         'override');
 
     return new MirrorUsage(
-        cachedValues[fields[symbolsField]],
-        cachedValues[fields[targetsField]],
-        cachedValues[fields[metaTargetsField]],
-        cachedValues[fields[overrideField]]);
+        cachedStrings[fields[symbolsField]],
+        cachedElements[fields[targetsField]],
+        cachedElements[fields[metaTargetsField]],
+        cachedElements[fields[overrideField]]);
   }
 }
 
 /// Used to represent a resolved MirrorsUsed constant.
 class MirrorUsage {
-  final List /* <String|Element> */ symbols;
+  final List<String> symbols;
   final List<Element> targets;
   final List<Element> metaTargets;
   final List<Element> override;
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index bb42db9..b4e8016 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -1045,17 +1045,6 @@
   return nativeTagInfo;
 }
 
-bool isOverriddenMethod(FunctionElement element,
-                        ClassElement cls,
-                        NativeEmitter nativeEmitter) {
-  List<ClassElement> subtypes = nativeEmitter.subtypes[cls];
-  if (subtypes == null) return false;
-  for (ClassElement subtype in subtypes) {
-    if (subtype.lookupLocalMember(element.name) != null) return true;
-  }
-  return false;
-}
-
 final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
 
 void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
diff --git a/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart b/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
index 6a68357..26a9e9f 100644
--- a/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
+++ b/sdk/lib/_internal/compiler/implementation/ordered_typeset.dart
@@ -1,203 +1,203 @@
-// 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 resolution.ordered_typeset_builder;

-

-import 'dart2jslib.dart' show Compiler, MessageKind;

-import 'dart_types.dart';

-import 'elements/elements.dart' show ClassElement;

-import 'util/util.dart' show Link, LinkBuilder;

-import 'util/util_implementation.dart' show LinkEntry;

-

-/**

- * An ordered set of the supertypes of a class. The supertypes of a class are

- * ordered by decreasing hierarchy depth and by the order they are extended,

- * mixed in, or implemented.

- *

- * For these classes

- *

- *     class A {} // Depth = 1.

- *     class B {} // Depth = 1.

- *     class C extends B implements A {} // Depth 2.

- *

- * the ordered supertypes are

- *

- *     A: [A, Object]

- *     B: [B, Object]

- *     C: [C, B, A, Object]

- */

-class OrderedTypeSet {

-  final List<Link<DartType>> _levels;

-  final Link<DartType> types;

-  final Link<DartType> _supertypes;

-

-  OrderedTypeSet._internal(List<Link<DartType>> this._levels,

-                           Link<DartType> this.types,

-                           Link<DartType> this._supertypes);

-

-  factory OrderedTypeSet.singleton(DartType type) {

-    Link<DartType> types =

-        new LinkEntry<DartType>(type, const Link<DartType>());

-    List<Link<DartType>> list = new List<Link<DartType>>(1);

-    list[0] = types;

-    return new OrderedTypeSet._internal(list, types, const Link<DartType>());

-  }

-

-  /// Creates a new [OrderedTypeSet] for [type] when it directly extends the

-  /// class which this set represents. This is for instance used to create the

-  /// type set for [ClosureClassElement] which extends [Closure].

-  OrderedTypeSet extendClass(InterfaceType type) {

-    assert(type.treatAsRaw);

-    Link<DartType> extendedTypes =

-        new LinkEntry<DartType>(type, types);

-    List<Link<DartType>> list = new List<Link<DartType>>(levels + 1);

-    for (int i = 0; i < levels; i++) {

-      list[i] = _levels[i];

-    }

-    list[levels] = extendedTypes;

-    return new OrderedTypeSet._internal(

-        list, extendedTypes, _supertypes.prepend(types.head));

-  }

-

-  Link<DartType> get supertypes => _supertypes;

-

-  int get levels => _levels.length;

-

-  int get maxDepth => levels - 1;

-

-  Link<DartType> operator [](int index) {

-    if (index < levels) {

-      return _levels[index];

-    }

-    return const Link<DartType>();

-  }

-

-  void forEach(int level, void f(DartType type)) {

-    if (level < levels) {

-      Link<DartType> pointer = _levels[level];

-      Link<DartType> end =

-          level > 0 ? _levels[level - 1] : const Link<DartType>();

-      while (!identical(pointer, end)) {

-        f(pointer.head);

-        pointer = pointer.tail;

-      }

-    }

-  }

-

-  String toString() => types.toString();

-}

-

-/**

- * Builder for creation an ordered set of the supertypes of a class. The

- * supertypes are ordered by decreasing hierarchy depth and by the order they

- * are extended, mixed in, or implemented.

- *

- * For these classes

- *

- *     class A {} // Depth = 1.

- *     class B {} // Depth = 1.

- *     class C extends B implements A {} // Depth 2.

- *

- * the ordered supertypes are

- *

- *     A: [A, Object]

- *     B: [B, Object]

- *     C: [C, B, A, Object]

- */

-class OrderedTypeSetBuilder {

-  Map<int, LinkEntry<DartType>> map = new Map<int, LinkEntry<DartType>>();

-  // TODO(15296): Avoid computing this order on the side when member

-  // lookup handles multiply inherited members correctly.

-  LinkBuilder<DartType> allSupertypes = new LinkBuilder<DartType>();

-  int maxDepth = -1;

-

-  final ClassElement cls;

-

-  OrderedTypeSetBuilder(this.cls);

-

-  void add(Compiler compiler, InterfaceType type) {

-    if (type.element == cls) {

-      if (type.element != compiler.objectClass) {

-        allSupertypes.addLast(compiler.objectClass.computeType(compiler));

-      }

-      _addAtDepth(compiler, type, maxDepth + 1);

-    } else {

-      if (type.element != compiler.objectClass) {

-        allSupertypes.addLast(type);

-      }

-      _addAtDepth(compiler, type, type.element.hierarchyDepth);

-    }

-  }

-

-  void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {

-    LinkEntry<DartType> prev = null;

-    LinkEntry<DartType> link = map[depth];

-    while (link != null) {

-      DartType existingType = link.head;

-      if (existingType == type) return;

-      if (existingType.element == type.element) {

-        compiler.reportError(cls,

-            MessageKind.MULTI_INHERITANCE,

-            {'thisType': cls.computeType(compiler),

-             'firstType': existingType,

-             'secondType': type});

-        return;

-      }

-      prev = link;

-      link = link.tail;

-    }

-    LinkEntry<DartType> next = new LinkEntry<DartType>(type);

-    next.tail = null;

-    if (prev == null) {

-      map[depth] = next;

-    } else {

-      prev.tail = next;

-    }

-    if (depth > maxDepth) {

-      maxDepth = depth;

-    }

-  }

-

-  OrderedTypeSet toTypeSet() {

-    List<Link<DartType>> levels = new List<Link<DartType>>(maxDepth + 1);

-    if (maxDepth < 0) {

-      return new OrderedTypeSet._internal(

-          levels, const Link<DartType>(), const Link<DartType>());

-    }

-    Link<DartType> next = const Link<DartType>();

-    for (int depth = 0; depth <= maxDepth; depth++) {

-      LinkEntry<DartType> first = map[depth];

-      if (first == null) {

-        levels[depth] = next;

-      } else {

-        levels[depth] = first;

-        LinkEntry<DartType> last = first;

-        while (last.tail != null) {

-          last = last.tail;

-        }

-        last.tail = next;

-        next = first;

-      }

-    }

-    return new OrderedTypeSet._internal(

-        levels, levels.last, allSupertypes.toLink());

-  }

-

-  String toString() {

-    StringBuffer sb = new StringBuffer();

-    for (int depth = 0; depth <= maxDepth; depth++) {

-      sb.write('$depth: ');

-      LinkEntry<DartType> first = map[depth];

-      if (first != null) {

-        sb.write('${first.head}');

-        while (first.tail != null) {

-          sb.write(', ${first.tail.head}');

-          first = first.tail;

-        }

-      }

-      sb.write('\n');

-    }

-    return sb.toString();

-  }

-}

+// 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 resolution.ordered_typeset_builder;
+
+import 'dart2jslib.dart' show Compiler, MessageKind;
+import 'dart_types.dart';
+import 'elements/elements.dart' show ClassElement;
+import 'util/util.dart' show Link, LinkBuilder;
+import 'util/util_implementation.dart' show LinkEntry;
+
+/**
+ * An ordered set of the supertypes of a class. The supertypes of a class are
+ * ordered by decreasing hierarchy depth and by the order they are extended,
+ * mixed in, or implemented.
+ *
+ * For these classes
+ *
+ *     class A {} // Depth = 1.
+ *     class B {} // Depth = 1.
+ *     class C extends B implements A {} // Depth 2.
+ *
+ * the ordered supertypes are
+ *
+ *     A: [A, Object]
+ *     B: [B, Object]
+ *     C: [C, B, A, Object]
+ */
+class OrderedTypeSet {
+  final List<Link<DartType>> _levels;
+  final Link<DartType> types;
+  final Link<DartType> _supertypes;
+
+  OrderedTypeSet._internal(List<Link<DartType>> this._levels,
+                           Link<DartType> this.types,
+                           Link<DartType> this._supertypes);
+
+  factory OrderedTypeSet.singleton(DartType type) {
+    Link<DartType> types =
+        new LinkEntry<DartType>(type, const Link<DartType>());
+    List<Link<DartType>> list = new List<Link<DartType>>(1);
+    list[0] = types;
+    return new OrderedTypeSet._internal(list, types, const Link<DartType>());
+  }
+
+  /// Creates a new [OrderedTypeSet] for [type] when it directly extends the
+  /// class which this set represents. This is for instance used to create the
+  /// type set for [ClosureClassElement] which extends [Closure].
+  OrderedTypeSet extendClass(InterfaceType type) {
+    assert(type.treatAsRaw);
+    Link<DartType> extendedTypes =
+        new LinkEntry<DartType>(type, types);
+    List<Link<DartType>> list = new List<Link<DartType>>(levels + 1);
+    for (int i = 0; i < levels; i++) {
+      list[i] = _levels[i];
+    }
+    list[levels] = extendedTypes;
+    return new OrderedTypeSet._internal(
+        list, extendedTypes, _supertypes.prepend(types.head));
+  }
+
+  Link<DartType> get supertypes => _supertypes;
+
+  int get levels => _levels.length;
+
+  int get maxDepth => levels - 1;
+
+  Link<DartType> operator [](int index) {
+    if (index < levels) {
+      return _levels[index];
+    }
+    return const Link<DartType>();
+  }
+
+  void forEach(int level, void f(DartType type)) {
+    if (level < levels) {
+      Link<DartType> pointer = _levels[level];
+      Link<DartType> end =
+          level > 0 ? _levels[level - 1] : const Link<DartType>();
+      while (!identical(pointer, end)) {
+        f(pointer.head);
+        pointer = pointer.tail;
+      }
+    }
+  }
+
+  String toString() => types.toString();
+}
+
+/**
+ * Builder for creation an ordered set of the supertypes of a class. The
+ * supertypes are ordered by decreasing hierarchy depth and by the order they
+ * are extended, mixed in, or implemented.
+ *
+ * For these classes
+ *
+ *     class A {} // Depth = 1.
+ *     class B {} // Depth = 1.
+ *     class C extends B implements A {} // Depth 2.
+ *
+ * the ordered supertypes are
+ *
+ *     A: [A, Object]
+ *     B: [B, Object]
+ *     C: [C, B, A, Object]
+ */
+class OrderedTypeSetBuilder {
+  Map<int, LinkEntry<DartType>> map = new Map<int, LinkEntry<DartType>>();
+  // TODO(15296): Avoid computing this order on the side when member
+  // lookup handles multiply inherited members correctly.
+  LinkBuilder<DartType> allSupertypes = new LinkBuilder<DartType>();
+  int maxDepth = -1;
+
+  final ClassElement cls;
+
+  OrderedTypeSetBuilder(this.cls);
+
+  void add(Compiler compiler, InterfaceType type) {
+    if (type.element == cls) {
+      if (type.element != compiler.objectClass) {
+        allSupertypes.addLast(compiler.objectClass.computeType(compiler));
+      }
+      _addAtDepth(compiler, type, maxDepth + 1);
+    } else {
+      if (type.element != compiler.objectClass) {
+        allSupertypes.addLast(type);
+      }
+      _addAtDepth(compiler, type, type.element.hierarchyDepth);
+    }
+  }
+
+  void _addAtDepth(Compiler compiler, InterfaceType type, int depth) {
+    LinkEntry<DartType> prev = null;
+    LinkEntry<DartType> link = map[depth];
+    while (link != null) {
+      DartType existingType = link.head;
+      if (existingType == type) return;
+      if (existingType.element == type.element) {
+        compiler.reportError(cls,
+            MessageKind.MULTI_INHERITANCE,
+            {'thisType': cls.computeType(compiler),
+             'firstType': existingType,
+             'secondType': type});
+        return;
+      }
+      prev = link;
+      link = link.tail;
+    }
+    LinkEntry<DartType> next = new LinkEntry<DartType>(type);
+    next.tail = null;
+    if (prev == null) {
+      map[depth] = next;
+    } else {
+      prev.tail = next;
+    }
+    if (depth > maxDepth) {
+      maxDepth = depth;
+    }
+  }
+
+  OrderedTypeSet toTypeSet() {
+    List<Link<DartType>> levels = new List<Link<DartType>>(maxDepth + 1);
+    if (maxDepth < 0) {
+      return new OrderedTypeSet._internal(
+          levels, const Link<DartType>(), const Link<DartType>());
+    }
+    Link<DartType> next = const Link<DartType>();
+    for (int depth = 0; depth <= maxDepth; depth++) {
+      LinkEntry<DartType> first = map[depth];
+      if (first == null) {
+        levels[depth] = next;
+      } else {
+        levels[depth] = first;
+        LinkEntry<DartType> last = first;
+        while (last.tail != null) {
+          last = last.tail;
+        }
+        last.tail = next;
+        next = first;
+      }
+    }
+    return new OrderedTypeSet._internal(
+        levels, levels.last, allSupertypes.toLink());
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    for (int depth = 0; depth <= maxDepth; depth++) {
+      sb.write('$depth: ');
+      LinkEntry<DartType> first = map[depth];
+      if (first != null) {
+        sb.write('${first.head}');
+        while (first.tail != null) {
+          sb.write(', ${first.tail.head}');
+          first = first.tail;
+        }
+      }
+      sb.write('\n');
+    }
+    return sb.toString();
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 3e04dc9..c29501b 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -528,12 +528,6 @@
     return new ResolverVisitor(compiler, element, mapping);
   }
 
-  void visitBody(ResolverVisitor visitor, Statement body) {
-    if (!compiler.analyzeSignaturesOnly) {
-      visitor.visit(body);
-    }
-  }
-
   TreeElements resolveField(VariableElement element) {
     Node tree = element.parseNode(compiler);
     if(element.modifiers.isStatic() && element.variables.isTopLevel()) {
@@ -916,6 +910,25 @@
             MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD);
       }
     }
+
+    if (!cls.isAbstract) {
+      for (DartType supertype in cls.allSupertypes) {
+        // This must have been reported elsewhere.
+        if (!supertype.element.isClass()) continue;
+        ClassElement superclass = supertype.element;
+        superclass.forEachMember((ClassElement holder, Element member) {
+          if (member.isAbstract) {
+            Element mine = cls.lookupMember(member.name);
+            if (mine == null || mine.isAbstract) {
+              compiler.reportWarningCode(
+                  cls, MessageKind.UNIMPLEMENTED_METHOD,
+                  {'class_name': cls.name, 'member_name': member.name});
+              compiler.reportHint(member, MessageKind.THIS_IS_THE_METHOD, {});
+            }
+          }
+        });
+      }
+    }
   }
 
   void checkAbstractField(Element member) {
@@ -1424,16 +1437,6 @@
     }
   }
 
-  FunctionElement resolveRedirection(FunctionElement constructor,
-                                     FunctionExpression functionNode) {
-    if (functionNode.initializers == null) return null;
-    Link<Node> link = functionNode.initializers.nodes;
-    if (!link.isEmpty && Initializers.isConstructorRedirect(link.head)) {
-      return resolveSuperOrThisForSend(constructor, functionNode, link.head);
-    }
-    return null;
-  }
-
   /**
    * Resolve all initializers of this constructor. In the case of a redirecting
    * constructor, the resolved constructor's function element is returned.
@@ -1528,20 +1531,12 @@
     compiler.reportFatalError(node, kind, arguments);
   }
 
-  void dualError(Node node, DualKind kind, [Map arguments = const {}]) {
-    error(node, kind.error, arguments);
-  }
-
   void warning(Node node, MessageKind kind, [Map arguments = const {}]) {
     ResolutionWarning message =
         new ResolutionWarning(kind, arguments, compiler.terseDiagnostics);
     compiler.reportWarning(node, message);
   }
 
-  void dualWarning(Node node, DualKind kind, [Map arguments = const {}]) {
-    warning(node, kind.warning, arguments);
-  }
-
   void cancel(Node node, String message) {
     compiler.cancel(message, node: node);
   }
@@ -2334,11 +2329,6 @@
     visitIn(node.elsePart, new BlockScope(scope));
   }
 
-  static bool isLogicalOperator(Identifier op) {
-    String str = op.source;
-    return (identical(str, '&&') || str == '||' || str == '!');
-  }
-
   Element resolveSend(Send node) {
     Selector selector = resolveSelector(node, null);
     if (node.isSuperCall) mapping.superUses.add(node);
@@ -3832,8 +3822,8 @@
         DartType supertype = resolveSupertype(element, superMixin.superclass);
         Link<Node> link = superMixin.mixins.nodes;
         while (!link.isEmpty) {
-          supertype = applyMixin(
-              supertype, checkMixinType(link.head), link.head);
+          supertype = applyMixin(supertype,
+                                 checkMixinType(link.head), link.head);
           link = link.tail;
         }
         element.supertype = supertype;
@@ -3929,16 +3919,45 @@
   DartType applyMixin(DartType supertype, DartType mixinType, Node node) {
     String superName = supertype.name;
     String mixinName = mixinType.name;
-    ClassElement mixinApplication = new MixinApplicationElementX(
+    MixinApplicationElementX mixinApplication = new MixinApplicationElementX(
         "${superName}+${mixinName}",
         element.getCompilationUnit(),
         compiler.getNextFreeClassId(),
         node,
         Modifiers.EMPTY);  // TODO(kasperl): Should this be abstract?
+    // Create synthetic type variables for the mixin application.
+    LinkBuilder<DartType> typeVariablesBuilder = new LinkBuilder<DartType>();
+    element.typeVariables.forEach((TypeVariableType type) {
+      TypeVariableElementX typeVariableElement = new TypeVariableElementX(
+          type.name, mixinApplication, type.element.parseNode(compiler));
+      TypeVariableType typeVariable = new TypeVariableType(typeVariableElement);
+      typeVariablesBuilder.addLast(typeVariable);
+    });
+    Link<DartType> typeVariables = typeVariablesBuilder.toLink();
+    // Setup bounds on the synthetic type variables.
+    Link<DartType> link = typeVariables;
+    element.typeVariables.forEach((TypeVariableType type) {
+      TypeVariableType typeVariable = link.head;
+      TypeVariableElement typeVariableElement = typeVariable.element;
+      typeVariableElement.type = typeVariable;
+      typeVariableElement.bound =
+          type.element.bound.subst(typeVariables, element.typeVariables);
+      link = link.tail;
+    });
+    // Setup this and raw type for the mixin application.
+    mixinApplication.computeThisAndRawType(compiler, typeVariables);
+    // Substitute in synthetic type variables in super and mixin types.
+    supertype = supertype.subst(typeVariables, element.typeVariables);
+    mixinType = mixinType.subst(typeVariables, element.typeVariables);
+
     doApplyMixinTo(mixinApplication, supertype, mixinType);
     mixinApplication.resolutionState = STATE_DONE;
     mixinApplication.supertypeLoadState = STATE_DONE;
-    return mixinApplication.computeType(compiler);
+    // Replace the synthetic type variables by the original type variables in
+    // the returned type (which should be the type actually extended).
+    InterfaceType mixinThisType = mixinApplication.computeType(compiler);
+    return mixinThisType.subst(element.typeVariables,
+                               mixinThisType.typeArguments);
   }
 
   bool isDefaultConstructor(FunctionElement constructor) {
@@ -4135,7 +4154,7 @@
       cls.allSupertypesAndSelf =
           new OrderedTypeSet.singleton(cls.computeType(compiler));
     }
- }
+  }
 
   /**
    * Adds [type] and all supertypes of [type] to [allSupertypes] while
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 136a930..463413a 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -22,6 +22,7 @@
          LabelElementX,
          TargetElementX,
          MixinApplicationElementX,
+         TypeVariableElementX,
          TypedefElementX,
          SynthesizedConstructorElementX;
 import '../util/util.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
index e31e9ff..ebc83d63 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/scope.dart
@@ -34,11 +34,6 @@
   }
 
   Element localLookup(String name);
-
-  static Scope buildEnclosingScope(Element element) {
-    return element.enclosingElement != null
-        ? element.enclosingElement.buildScope() : element.buildScope();
-  }
 }
 
 class VariableDefinitionScope extends NestedScope {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index eaf9feb..69a62ef 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -61,6 +61,8 @@
   // TODO(johnniwinther): Ensure that modifiers are always available.
   Modifiers get modifiers =>
       cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY;
+
+  accept(ElementVisitor visitor) => visitor.visitClassElement(this);
 }
 
 class MemberListener extends NodeListener {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
index d447029..013e11c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/keyword.dart
@@ -103,7 +103,6 @@
 abstract class KeywordState {
   KeywordState(this.keyword);
 
-  bool isLeaf();
   KeywordState next(int c);
   final Keyword keyword;
 
@@ -172,8 +171,6 @@
   ArrayKeywordState(List<KeywordState> this.table, String syntax)
     : super((syntax == null) ? null : Keyword.keywords[syntax]);
 
-  bool isLeaf() => false;
-
   KeywordState next(int c) => table[c - $a];
 
   String toString() {
@@ -201,8 +198,6 @@
 class LeafKeywordState extends KeywordState {
   LeafKeywordState(String syntax) : super(Keyword.keywords[syntax]);
 
-  bool isLeaf() => true;
-
   KeywordState next(int c) => null;
 
   String toString() => keyword.syntax;
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index a35be99..71992fa 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -552,7 +552,13 @@
   }
 
   Token expectedExpression(Token token) {
-    error("expected an expression, but got '${token.value}'", token);
+    String message;
+    if (token.info == BAD_INPUT_INFO) {
+      message = token.value;
+    } else {
+      message = "expected an expression, but got '${token.value}'";
+    }
+    error(message, token);
     return skipToEof(token);
   }
 
@@ -972,16 +978,22 @@
   }
 
   Token expectedExpression(Token token) {
-    listener.cancel("expected an expression, but got '${token.value}'",
-                    token: token);
-    pushNode(null);
-    return skipToEof(token);
+    if (token.info == BAD_INPUT_INFO) {
+      reportError(token, MessageKind.GENERIC, {'text': token.value});
+      pushNode(new ErrorExpression(token));
+      return token.next;
+    } else {
+      listener.cancel("expected an expression, but got '${token.value}'",
+                      token: token);
+      pushNode(null);
+      return skipToEof(token);
+    }
   }
 
   Token unexpected(Token token) {
     String message = "unexpected token '${token.value}'";
     if (token.info == BAD_INPUT_INFO) {
-      message = token.stringValue;
+      message = token.value;
     }
     listener.cancel(message, token: token);
     return skipToEof(token);
@@ -1071,13 +1083,6 @@
     return node;
   }
 
-  Node peekNode() {
-    assert(!nodes.isEmpty);
-    Node node = nodes.head;
-    if (VERBOSE) log("peek $node");
-    return node;
-  }
-
   void log(message) {
     print(message);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index af56bf9..53f04db 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -431,16 +431,6 @@
     return token;
   }
 
-  bool isDefaultKeyword(Token token) {
-    String value = token.stringValue;
-    if (identical(value, 'default')) return true;
-    if (identical(value, 'factory')) {
-      listener.recoverableError("expected 'default'", token: token);
-      return true;
-    }
-    return false;
-  }
-
   Token skipBlock(Token token) {
     if (!optional('{', token)) {
       return listener.expectedBlockToSkip(token);
@@ -1778,8 +1768,11 @@
   }
 
   Token parseParenthesizedExpression(Token token) {
-    var begin = (token as BeginGroupToken);
+    // We expect [begin] to be of type [BeginGroupToken], but we don't know for
+    // sure until after calling expect.
+    var begin = token;
     token = expect('(', token);
+    // [begin] is now known to have type [BeginGroupToken].
     token = parseExpression(token);
     if (!identical(begin.endGroup, token)) {
       listener.unexpected(token);
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
index 8659ead..c7e1ae7 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scanner.dart
@@ -17,6 +17,8 @@
 }
 
 abstract class AbstractScanner implements Scanner {
+  // TODO(ahe): Move this class to implementation.
+
   final bool includeComments;
 
   /**
@@ -186,14 +188,21 @@
   /** Documentation in subclass [ArrayBasedScanner]. */
   void discardOpenLt();
 
-  // TODO(ahe): Move this class to implementation.
+  /// Return true when at EOF.
+  bool atEndOfFile();
 
   Token tokenize() {
-    int next = advance();
-    while (!identical(next, $EOF)) {
-      next = bigSwitch(next);
+    while (!atEndOfFile()) {
+      int next = advance();
+      while (!identical(next, $EOF)) {
+        next = bigSwitch(next);
+      }
+      if (atEndOfFile()) {
+        appendEofToken();
+      } else {
+        error('Unexpected ${$EOF} byte in input.');
+      }
     }
-    appendEofToken();
 
     if (file != null) {
       file.length = stringOffset;
@@ -921,7 +930,14 @@
   int tokenizeInterpolatedIdentifier(int next) {
     appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO);
     beginToken(); // The identifier starts here.
-    next = tokenizeKeywordOrIdentifier(next, false);
+
+    if ($a <= next && next <= $z) {
+      next = tokenizeKeywordOrIdentifier(next, false);
+    } else if (($A <= next && next <= $Z) || identical(next, $_)) {
+      next = tokenizeIdentifier(next, scanOffset, false);
+    } else {
+      error("expected identifier or '{'", shouldAdvance: false);
+    }
     beginToken(); // The string interpolation suffix starts here.
     return next;
   }
@@ -1035,9 +1051,14 @@
     return error("unterminated string literal");
   }
 
-  int error(String message) {
+  int error(String message, {bool shouldAdvance: true}) {
     appendStringToken(BAD_INPUT_INFO, message);
-    return advance(); // Ensure progress.
+    if (atEndOfFile()) return $EOF;
+    if (shouldAdvance) {
+      return advance(); // Ensure progress.
+    } else {
+      return -1;
+    }
   }
 
   void unmatchedBeginGroup(BeginGroupToken begin) {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
index 68aea9f..f5592f4 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/scannerlib.dart
@@ -16,6 +16,8 @@
          ClassElementX,
          MetadataAnnotationX,
          MixinApplicationElementX;
+import '../elements/visitor.dart'
+    show ElementVisitor;
 import '../dart2jslib.dart';
 import '../native_handler.dart' as native;
 import '../string_validator.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
index f0f11e0..5a30e43 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/string_scanner.dart
@@ -51,4 +51,6 @@
         scanOffset + extraOffset, tokenStart, canonicalize: true);
     tail = tail.next;
   }
+
+  bool atEndOfFile() => scanOffset >= string.length - 1;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
index 523495c..62722ea 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/utf8_bytes_scanner.dart
@@ -190,4 +190,6 @@
         info, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
     tail = tail.next;
   }
+
+  bool atEndOfFile() => byteOffset >= bytes.length - 1;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index f556147..b70c2de 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -15,6 +15,8 @@
       : super(name, ElementKind.PARAMETER, enclosing);
 
   DartType computeType(Compiler compiler) => type;
+
+  accept(ElementVisitor visitor) => visitor.visitInterceptedElement(this);
 }
 
 class SsaBuilderTask extends CompilerTask {
@@ -313,12 +315,6 @@
     }
   }
 
-  bool hasValueForDirectLocal(Element element) {
-    assert(element != null);
-    assert(isAccessedDirectly(element));
-    return directLocals[element] != null;
-  }
-
   /**
    * Returns true if the local can be accessed directly. Boxed variables or
    * captured variables that are stored in the closure-field return [false].
@@ -1315,9 +1311,8 @@
     assert(argumentIndex == compiledArguments.length);
 
     // TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
-    returnElement = new ElementX("result",
-                                 ElementKind.VARIABLE,
-                                 function);
+    returnElement = new VariableElementX.synthetic("result",
+        ElementKind.VARIABLE, function);
     newLocalsHandler.updateLocal(returnElement,
                                  graph.addConstantNull(compiler));
     elements = compiler.enqueuer.resolution.getCachedElements(function);
@@ -1925,7 +1920,8 @@
       if (source != null && allIndexed && typeVariables.isEmpty) {
         copyRuntimeTypeInfo(source, newObject);
       } else {
-        callSetRuntimeTypeInfo(classElement, typeArguments, newObject);
+        newObject =
+            callSetRuntimeTypeInfo(classElement, typeArguments, newObject);
       }
     }
 
@@ -2147,8 +2143,6 @@
     push(attachPosition(instruction, node));
   }
 
-  HInstruction peek() => stack.last;
-
   HInstruction pop() {
     return stack.removeLast();
   }
@@ -2984,11 +2978,6 @@
     return new HForeign(code, type, inputs);
   }
 
-  HInstruction getRuntimeTypeInfo(HInstruction target) {
-    pushInvokeStatic(null, backend.getGetRuntimeTypeInfo(), [target]);
-    return pop();
-  }
-
   HLiteralList buildLiteralList(List<HInstruction> inputs) {
     return new HLiteralList(inputs, backend.extendableArrayType);
   }
@@ -3779,17 +3768,17 @@
     return result;
   }
 
-  void handleListConstructor(InterfaceType type,
-                             Node currentNode,
-                             HInstruction newObject) {
-    if (!backend.classNeedsRti(type.element)) return;
-    if (!type.treatAsRaw) {
-      List<HInstruction> inputs = <HInstruction>[];
-      type.typeArguments.forEach((DartType argument) {
-        inputs.add(analyzeTypeArgument(argument));
-      });
-      callSetRuntimeTypeInfo(type.element, inputs, newObject);
+  HInstruction handleListConstructor(InterfaceType type,
+                                     Node currentNode,
+                                     HInstruction newObject) {
+    if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
+      return newObject;
     }
+    List<HInstruction> inputs = <HInstruction>[];
+    type.typeArguments.forEach((DartType argument) {
+      inputs.add(analyzeTypeArgument(argument));
+    });
+    return callSetRuntimeTypeInfo(type.element, inputs, newObject);
   }
 
   void copyRuntimeTypeInfo(HInstruction source, HInstruction target) {
@@ -3798,11 +3787,11 @@
     pop();
   }
 
-  void callSetRuntimeTypeInfo(ClassElement element,
-                              List<HInstruction> rtiInputs,
-                              HInstruction newObject) {
+  HInstruction callSetRuntimeTypeInfo(ClassElement element,
+                                      List<HInstruction> rtiInputs,
+                                      HInstruction newObject) {
     if (!backend.classNeedsRti(element) || element.typeVariables.isEmpty) {
-      return;
+      return newObject;
     }
 
     HInstruction typeInfo = buildLiteralList(rtiInputs);
@@ -3815,7 +3804,8 @@
         typeInfoSetterElement,
         <HInstruction>[newObject, typeInfo],
         backend.dynamicType);
-    pop();
+    stack.last.instructionType = newObject.instructionType;
+    return pop();
   }
 
   handleNewSend(NewExpression node) {
@@ -3823,6 +3813,8 @@
     bool isFixedList = false;
     bool isFixedListConstructorCall =
         Elements.isFixedListConstructorCall(elements[send], send, compiler);
+    bool isGrowableListConstructorCall =
+        Elements.isGrowableListConstructorCall(elements[send], send, compiler);
 
     TypeMask computeType(element) {
       Element originalElement = elements[send];
@@ -3835,8 +3827,7 @@
         return inferred.containsAll(compiler)
             ? backend.fixedArrayType
             : inferred;
-      } else if (Elements.isGrowableListConstructorCall(
-                    originalElement, send, compiler)) {
+      } else if (isGrowableListConstructorCall) {
         TypeMask inferred =
             TypeMaskFactory.inferredForNode(currentElement, send, compiler);
         return inferred.containsAll(compiler)
@@ -3937,6 +3928,11 @@
         add(new HForeign(
               code, backend.nullType, [stack.last], canThrow: true));
       }
+    } else if (isGrowableListConstructorCall) {
+      js.Expression code = js.js.parseForeignJS('Array()');
+      var behavior = new native.NativeBehavior();
+      behavior.typesReturned.add(expectedType);
+      push(new HForeign(code, elementType, inputs, nativeBehavior: behavior));
     } else {
       ClassElement cls = constructor.getEnclosingClass();
       if (cls.isAbstract && constructor.isGenerativeConstructor()) {
@@ -3969,9 +3965,11 @@
     // not know about the type argument. Therefore we special case
     // this constructor to have the setRuntimeTypeInfo called where
     // the 'new' is done.
-    if ((isFixedListConstructorCall || isJSArrayTypedConstructor) &&
-        backend.classNeedsRti(compiler.listClass)) {
-      handleListConstructor(type, send, newInstance);
+    if (backend.classNeedsRti(compiler.listClass) &&
+        (isFixedListConstructorCall || isGrowableListConstructorCall ||
+         isJSArrayTypedConstructor)) {
+      newInstance = handleListConstructor(type, send, pop());
+      stack.add(newInstance);
     }
 
     // Finally, if we called a redirecting factory constructor, check the type.
@@ -4717,15 +4715,17 @@
     }
   }
 
-  void setRtiIfNeeded(HInstruction object, Node node) {
+  HInstruction setRtiIfNeeded(HInstruction object, Node node) {
     InterfaceType type = elements.getType(node);
-    if (!backend.classNeedsRti(type.element) || type.treatAsRaw) return;
+    if (!backend.classNeedsRti(type.element) || type.treatAsRaw) {
+      return object;
+    }
     List<HInstruction> arguments = <HInstruction>[];
     for (DartType argument in type.typeArguments) {
       arguments.add(analyzeTypeArgument(argument));
     }
-    callSetRuntimeTypeInfo(type.element, arguments, object);
     compiler.enqueuer.codegen.registerInstantiatedType(type, elements);
+    return callSetRuntimeTypeInfo(type.element, arguments, object);
   }
 
   visitLiteralList(LiteralList node) {
@@ -4743,7 +4743,7 @@
       }
       instruction = buildLiteralList(inputs);
       add(instruction);
-      setRtiIfNeeded(instruction, node);
+      instruction = setRtiIfNeeded(instruction, node);
     }
 
     TypeMask type =
@@ -4946,7 +4946,7 @@
     add(keyValuePairs);
     TypeMask mapType = new TypeMask.nonNullSubtype(backend.mapLiteralClass);
     pushInvokeStatic(node, backend.getMapMaker(), [keyValuePairs], mapType);
-    setRtiIfNeeded(peek(), node);
+    stack.add(setRtiIfNeeded(pop(), node));
   }
 
   visitLiteralMapEntry(LiteralMapEntry node) {
@@ -5313,12 +5313,6 @@
     jumpHandler.close();
   }
 
-  Element lookupOperator(ClassElement classElement, String operatorName) {
-    String dartMethodName =
-        Elements.constructOperatorName(operatorName, false);
-    return classElement.lookupMember(dartMethodName);
-  }
-
   visitSwitchCase(SwitchCase node) {
     compiler.internalError('SsaBuilder.visitSwitchCase');
   }
@@ -5365,9 +5359,8 @@
       open(startCatchBlock);
       // TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
       // Note that the name of this element is irrelevant.
-      Element element = new ElementX('exception',
-                                     ElementKind.PARAMETER,
-                                     currentElement);
+      Element element = new VariableElementX.synthetic('exception',
+          ElementKind.PARAMETER, currentElement);
       exception = new HLocalValue(element, backend.nonNullType);
       add(exception);
       HInstruction oldRethrowableException = rethrowableException;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 1af7f49..50aabfc 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -65,11 +65,6 @@
     return attachPosition(new js.Fun(parameters, body), element);
   }
 
-  CodeBuffer prettyPrint(js.Node node) {
-    var code = js.prettyPrint(node, compiler, allowVariableMinification: true);
-    return code;
-  }
-
   js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
     if (work.element.isField()) {
       return generateLazyInitializer(work, graph);
@@ -408,10 +403,6 @@
     return !identical(expressionType(info), TYPE_STATEMENT);
   }
 
-  bool isJSDeclaration(HExpressionInformation info) {
-    return identical(expressionType(info), TYPE_DECLARATION);
-  }
-
   bool isJSCondition(HExpressionInformation info) {
     HSubExpressionBlockInformation graph = info;
     SubExpression limits = graph.subExpression;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 9af57d7..e13b16d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -795,11 +795,6 @@
   void setUseGvn() { _useGvn = true; }
   void clearUseGvn() { _useGvn = false; }
 
-  void updateInput(int i, HInstruction insn) {
-    assert(insn != null);
-    inputs[i] = insn;
-  }
-
   /**
    * A pure instruction is an instruction that does not have any side
    * effect, nor any dependency. They can be moved anywhere in the
@@ -981,23 +976,6 @@
 
   bool isInBasicBlock() => block != null;
 
-  String inputsToString() {
-    void addAsCommaSeparated(StringBuffer buffer, List<HInstruction> list) {
-      for (int i = 0; i < list.length; i++) {
-        if (i != 0) buffer.write(', ');
-        buffer.write("@${list[i].id}");
-      }
-    }
-
-    StringBuffer buffer = new StringBuffer();
-    buffer.write('(');
-    addAsCommaSeparated(buffer, inputs);
-    buffer.write(') - used at [');
-    addAsCommaSeparated(buffer, usedBy);
-    buffer.write(']');
-    return buffer.toString();
-  }
-
   bool gvnEquals(HInstruction other) {
     assert(useGvn() && other.useGvn());
     // Check that the type and the sideEffects match.
@@ -1386,13 +1364,6 @@
 
   String toString() => 'invoke dynamic method: $selector';
   accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
-
-  bool isIndexOperatorOnIndexablePrimitive(Compiler compiler) {
-    return isInterceptedCall
-        && selector.kind == SelectorKind.INDEX
-        && selector.name == '[]'
-        && inputs[1].isIndexablePrimitive(compiler);
-  }
 }
 
 abstract class HInvokeDynamicField extends HInvokeDynamic {
@@ -1904,27 +1875,6 @@
       : super(<HInstruction>[condition]);
   toString() => 'loop-branch';
   accept(HVisitor visitor) => visitor.visitLoopBranch(this);
-
-  bool isDoWhile() {
-    return identical(kind, DO_WHILE_LOOP);
-  }
-
-  HBasicBlock computeLoopHeader() {
-    HBasicBlock result;
-    if (isDoWhile()) {
-      // In case of a do/while, the successor is a block that avoids
-      // a critical edge and branchs to the loop header.
-      result = block.successors[0].successors[0];
-    } else {
-      // For other loops, the loop header might be up the dominator
-      // tree if the loop condition has control flow.
-      result = block;
-      while (!result.isLoopHeader()) result = result.dominator;
-    }
-
-    assert(result.isLoopHeader());
-    return result;
-  }
 }
 
 class HConstant extends HInstruction {
@@ -2024,15 +1974,6 @@
     input.usedBy.add(this);
   }
 
-  bool isLogicalOperator() => logicalOperatorType != IS_NOT_LOGICAL_OPERATOR;
-
-  String logicalOperator() {
-    assert(isLogicalOperator());
-    if (logicalOperatorType == IS_AND) return "&&";
-    assert(logicalOperatorType == IS_OR);
-    return "||";
-  }
-
   toString() => 'phi';
   accept(HVisitor visitor) => visitor.visitPhi(this);
 }
@@ -2550,19 +2491,6 @@
       workQueue.addAll(block.predecessors);
     }
   }
-
-  HBasicBlock getLastBackEdge() {
-    int maxId = -1;
-    HBasicBlock result = null;
-    for (int i = 0, length = backEdges.length; i < length; i++) {
-      HBasicBlock current = backEdges[i];
-      if (current.id > maxId) {
-        maxId = current.id;
-        result = current;
-      }
-    }
-    return result;
-  }
 }
 
 
@@ -2645,7 +2573,6 @@
     visitor.visitSubGraphInfo(this);
 }
 
-
 /**
  * Generic class wrapping a [SubExpression] as a block-information until
  * expressions structures are handled properly.
@@ -2663,7 +2590,6 @@
     visitor.visitSubExpressionInfo(this);
 }
 
-
 /** A sequence of separate statements. */
 class HStatementSequenceInformation implements HStatementInformation {
   final List<HStatementInformation> statements;
@@ -2676,7 +2602,6 @@
     visitor.visitSequenceInfo(this);
 }
 
-
 class HLabeledBlockInformation implements HStatementInformation {
   final HStatementInformation body;
   final List<LabelElement> labels;
@@ -2766,8 +2691,6 @@
     return node.accept(const LoopTypeVisitor());
   }
 
-  bool isDoWhile() => kind == DO_WHILE_LOOP;
-
   bool accept(HStatementInformationVisitor visitor) =>
     visitor.visitLoopInfo(this);
 }
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
index 64c9200..76a6ade 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
@@ -24,8 +24,12 @@
 import '../scanner/scannerlib.dart'
     show PartialFunctionElement, Token, PLUS_TOKEN;
 
+import '../elements/visitor.dart'
+    show ElementVisitor;
+
 import '../elements/modelx.dart'
     show ElementX,
+         VariableElementX,
          ConstructorBodyElementX;
 
 import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
diff --git a/sdk/lib/_internal/compiler/implementation/string_validator.dart b/sdk/lib/_internal/compiler/implementation/string_validator.dart
index 98ad8fa..ea96105 100644
--- a/sdk/lib/_internal/compiler/implementation/string_validator.dart
+++ b/sdk/lib/_internal/compiler/implementation/string_validator.dart
@@ -18,18 +18,6 @@
 
   StringValidator(this.listener);
 
-  DartString validateQuotedString(Token token) {
-    String source = token.value;
-    StringQuoting quoting = quotingFromString(source);
-    int leftQuote = quoting.leftQuoteLength;
-    int rightQuote = quoting.rightQuoteLength;
-    String content = copyWithoutQuotes(source, leftQuote, rightQuote);
-    return validateString(token,
-                          token.charOffset + leftQuote,
-                          content,
-                          quoting);
-  }
-
   DartString validateInterpolationPart(Token token, StringQuoting quoting,
                                        {bool isFirst: false,
                                         bool isLast: false}) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index de5cac5..e64cbf6 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -149,6 +149,7 @@
   ContinueStatement asContinueStatement() => null;
   DoWhile asDoWhile() => null;
   EmptyStatement asEmptyStatement() => null;
+  ErrorExpression asErrorExpression() => null;
   Export asExport() => null;
   Expression asExpression() => null;
   ExpressionStatement asExpressionStatement() => null;
@@ -171,6 +172,7 @@
   LiteralMapEntry asLiteralMapEntry() => null;
   LiteralNull asLiteralNull() => null;
   LiteralString asLiteralString() => null;
+  LiteralSymbol asLiteralSymbol() => null;
   MixinApplication asMixinApplication() => null;
   Modifiers asModifiers() => null;
   NamedArgument asNamedArgument() => null;
@@ -315,6 +317,16 @@
   bool isValidBreakTarget() => true;
 }
 
+/// Errorneous expression that behaves as a literal integer (0).
+class ErrorExpression extends LiteralInt {
+  ErrorExpression(token)
+      : super(token, null);
+
+  ErrorExpression asErrorExpression() => this;
+
+  int get value => 0;
+}
+
 /**
  * A message send aka method invocation. In Dart, most operations can
  * (and should) be considered as message sends. Getters and setters
@@ -587,10 +599,6 @@
 
   bool get hasElsePart => elsePart != null;
 
-  void validate() {
-    // TODO(ahe): Check that condition has size one.
-  }
-
   accept(Visitor visitor) => visitor.visitIf(this);
 
   visitChildren(Visitor visitor) {
@@ -908,7 +916,6 @@
   void visitChildren(Visitor visitor) {}
 
   bool get isInterpolation => false;
-  bool isValidated() => dartString != null;
 
   Token getBeginToken() => token;
   Token getEndToken() => token;
@@ -1715,8 +1722,6 @@
   Token getEndToken() => statement.getEndToken();
 
   bool isValidContinueTarget() => statement.isValidContinueTarget();
-
-  Node getBody() => statement;
 }
 
 abstract class LibraryTag extends Node {
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index f5eccfd..a14859b 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -328,7 +328,6 @@
   }
 
   // TODO(karlklose): remove these functions.
-  DartType unhandledStatement() => StatementType.NOT_RETURNING;
   DartType unhandledExpression() => types.dynamicType;
 
   DartType analyzeNonVoid(Node node) {
@@ -897,6 +896,41 @@
     return type;
   }
 
+  /// Compute a version of [shownType] that is more specific that [knownType].
+  /// This is used to provided better hints when trying to promote a supertype
+  /// to a raw subtype. For instance trying to promote `Iterable<int>` to `List`
+  /// we suggest the use of `List<int>`, which would make promotion valid.
+  DartType computeMoreSpecificType(DartType shownType,
+                                   DartType knownType) {
+    if (knownType.kind == TypeKind.INTERFACE &&
+        shownType.kind == TypeKind.INTERFACE &&
+        types.isSubtype(shownType.asRaw(), knownType)) {
+      // For the comments in the block, assume the hierarchy:
+      //     class A<T, V> {}
+      //     class B<S, U> extends A<S, int> {}
+      // and a promotion from a [knownType] of `A<double, int>` to a
+      // [shownType] of `B`.
+      InterfaceType knownInterfaceType = knownType;
+      ClassElement shownClass = shownType.element;
+
+      // Compute `B<double, dynamic>` as the subtype of `A<double, int>` using
+      // the relation between `A<S, int>` and `A<double, int>`.
+      MoreSpecificSubtypeVisitor visitor =
+          new MoreSpecificSubtypeVisitor(compiler);
+      InterfaceType shownTypeGeneric = visitor.computeMoreSpecific(
+          shownClass, knownInterfaceType);
+
+      if (shownTypeGeneric != null &&
+          types.isMoreSpecific(shownTypeGeneric, knownType)) {
+        // This should be the case but we double-check.
+        // TODO(johnniwinther): Ensure that we don't suggest malbounded types.
+        return shownTypeGeneric;
+      }
+    }
+    return null;
+
+  }
+
   DartType visitSend(Send node) {
     Element element = elements[node];
 
@@ -953,13 +987,30 @@
                 new TypePromotion(node, variable, shownType);
             if (!types.isMoreSpecific(shownType, knownType)) {
               String variableName = variable.name;
-              // TODO(johnniwinther): Provide a how-to-fix in the case one tries
-              // to promote a generic type to a raw type.
-              typePromotion.addHint(node,
-                  MessageKind.NOT_MORE_SPECIFIC,
-                  {'variableName': variableName,
-                   'shownType': shownType,
-                   'knownType': knownType});
+              if (!types.isSubtype(shownType, knownType)) {
+                typePromotion.addHint(node,
+                    MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
+                    {'variableName': variableName,
+                     'shownType': shownType,
+                     'knownType': knownType});
+              } else {
+                DartType shownTypeSuggestion =
+                    computeMoreSpecificType(shownType, knownType);
+                if (shownTypeSuggestion != null) {
+                  typePromotion.addHint(node,
+                      MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+                      {'variableName': variableName,
+                       'shownType': shownType,
+                       'shownTypeSuggestion': shownTypeSuggestion,
+                       'knownType': knownType});
+                } else {
+                  typePromotion.addHint(node,
+                      MessageKind.NOT_MORE_SPECIFIC,
+                      {'variableName': variableName,
+                       'shownType': shownType,
+                       'knownType': knownType});
+                }
+              }
             }
             showTypePromotion(node, typePromotion);
           }
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 5a2b13f..5e55fb5 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -6,7 +6,6 @@
 
 import 'dart:collection' show Queue, IterableBase;
 import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../native_handler.dart' as native;
 import '../tree/tree.dart';
@@ -407,36 +406,6 @@
     return result;
   }
 
-  /**
-   * Returns true if and only if the environment is compatible with [signature].
-   */
-  bool matches(FunctionSignature signature) {
-    Types types = inferrer.compiler.types;
-    bool paramMatches(ConcreteType concrete, VariableElement parameter) {
-      DartType parameterType = parameter.variables.type;
-      if (parameterType.treatAsDynamic || parameterType.treatAsRaw) {
-        return true;
-      }
-      for (BaseType baseType in concrete.baseTypes) {
-        if (baseType.isUnknown()) return false;
-        if (baseType.isNull()) continue;
-        ClassBaseType classType = baseType;
-        if (!types.isSubtype(classType.element.rawType,
-                             parameterType)) return false;
-      }
-      return true;
-    }
-    for (VariableElement param in signature.requiredParameters) {
-      ConcreteType concrete = environment[param];
-      if (concrete == null || !paramMatches(concrete, param)) return false;
-    }
-    for (VariableElement param in signature.optionalParameters) {
-      ConcreteType concrete = environment[param];
-      if (concrete != null && !paramMatches(concrete, param)) return false;
-    }
-    return true;
-  }
-
   String toString() => "{ this: $typeOfThis, env: $environment }";
 }
 
@@ -513,10 +482,6 @@
     throw new UnsupportedError("");
   }
 
-  bool containsOnlyNull(Compiler compiler) {
-    throw new UnsupportedError("");
-  }
-
   bool containsOnlyBool(Compiler compiler) {
     throw new UnsupportedError("");
   }
@@ -545,10 +510,6 @@
     throw new UnsupportedError("");
   }
 
-  Iterable<ClassElement> containedClasses(Compiler compiler) {
-    throw new UnsupportedError("");
-  }
-
   TypeMask union(TypeMask other, Compiler compiler) {
     throw new UnsupportedError("");
   }
@@ -557,10 +518,6 @@
     throw new UnsupportedError("");
   }
 
-  bool understands(Selector selector, Compiler compiler) {
-    throw new UnsupportedError("");
-  }
-
   bool canHit(Element element, Selector selector, Compiler compiler) {
     throw new UnsupportedError("");
   }
@@ -1075,10 +1032,6 @@
 
   void clear() {}
 
-  Iterable<Element> getCallersOf(Element element) {
-    throw new UnsupportedError("");
-  }
-
   bool isCalledOnce(Element element) {
     throw new UnsupportedError("");
   }
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 2e99ab4..1938dfc 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -154,11 +154,6 @@
         || base == compiler.backend.numImplementation;
   }
 
-  bool containsOnlyNull(Compiler compiler) {
-    return base == compiler.nullClass
-        || base == compiler.backend.nullImplementation;
-  }
-
   bool containsOnlyBool(Compiler compiler) {
     return base == compiler.boolClass
         || base == compiler.backend.boolImplementation;
@@ -403,16 +398,6 @@
     return new TypeMask(null, EMPTY, isNullable && other.isNullable);
   }
 
-  Iterable<ClassElement> containedClasses(Compiler compiler) {
-    Iterable<ClassElement> self = [ base ];
-    if (isExact) {
-      return self;
-    } else {
-      Set<ClassElement> subset = containedSubset(this, compiler);
-      return (subset == null) ? self : [ self, subset ].expand((x) => x);
-    }
-  }
-
   /**
    * Returns whether [element] will be the one used at runtime when being
    * invoked on an instance of [cls]. [selector] is used to ensure library
@@ -504,23 +489,6 @@
     return selector.appliesUntyped(element, compiler);
   }
 
-  /**
-   * Returns whether this [TypeMask] understands [selector].
-   */
-  bool understands(Selector selector, Compiler compiler) {
-    ClassElement cls;
-    if (isEmpty) {
-      if (!isNullable) return false;
-      cls = compiler.backend.nullImplementation;
-    } else {
-      cls = base;
-    }
-
-    // Use [lookupMember] because finding abstract members is okay.
-    Element element = cls.implementation.lookupMember(selector.name);
-    return element != null && selector.appliesUntyped(element, compiler);
-  }
-
   bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
     // A call on an empty type mask is either dead code, or a call on
     // `null`.
diff --git a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
index bb7b7a9..ec6acab 100644
--- a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
@@ -42,10 +42,6 @@
     return forwardTo.containsOnlyNum(compiler);
   }
 
-  bool containsOnlyNull(Compiler compiler) {
-    return forwardTo.containsOnlyNull(compiler);
-  }
-
   bool containsOnlyBool(Compiler compiler) {
     return forwardTo.containsOnlyBool(compiler);
   }
@@ -74,10 +70,6 @@
     return forwardTo.singleClass(compiler);
   }
 
-  Iterable<ClassElement> containedClasses(Compiler compiler) {
-    return forwardTo.containedClasses(compiler);
-  }
-
   TypeMask union(other, Compiler compiler) {
     if (this == other) {
       return this;
@@ -93,10 +85,6 @@
     return forwardTo.intersection(other, compiler);
   }
 
-  bool understands(Selector selector, Compiler compiler) {
-    return forwardTo.understands(selector, compiler);
-  }
-
   bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
     return forwardTo.needsNoSuchMethodHandling(selector, compiler);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index e99a8f4..24b60b4 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -57,7 +57,6 @@
   bool containsOnlyInt(Compiler compiler);
   bool containsOnlyDouble(Compiler compiler);
   bool containsOnlyNum(Compiler compiler);
-  bool containsOnlyNull(Compiler compiler);
   bool containsOnlyBool(Compiler compiler);
   bool containsOnlyString(Compiler compiler);
   bool containsOnly(ClassElement element);
@@ -94,11 +93,6 @@
   ClassElement singleClass(Compiler compiler);
 
   /**
-   * Returns the classes this type mask can be.
-   */
-  Iterable<ClassElement> containedClasses(Compiler compiler);
-
-  /**
    * Returns a type mask representing the union of [this] and [other].
    */
   TypeMask union(TypeMask other, Compiler compiler);
@@ -109,11 +103,6 @@
   TypeMask intersection(TypeMask other, Compiler compiler);
 
   /**
-   * Returns whether this [TypeMask] understands [selector].
-   */
-  bool understands(Selector selector, Compiler compiler);
-
-  /**
    * Returns whether this [TypeMask] applied to [selector] can hit a
    * [noSuchMethod].
    */
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index d1ab26c..175f92f 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -30,7 +30,6 @@
   TypeMask getTypeOfSelector(Selector selector);
   Iterable<TypeMask> get containerTypes;
   void clear();
-  Iterable<Element> getCallersOf(Element element);
   bool isCalledOnce(Element element);
   bool isFixedArrayCheckedForGrowable(Node node);
 }
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
index de7fc8f..b632e9b 100644
--- a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -219,10 +219,6 @@
     });
   }
 
-  bool containsOnlyNull(Compiler compiler) {
-    return disjointMasks.every((mask) => mask.containsOnlyNull(compiler));
-  }
-
   bool containsOnlyBool(Compiler compiler) {
     return disjointMasks.every((mask) => mask.containsOnlyBool(compiler));
   }
@@ -249,15 +245,6 @@
 
   ClassElement singleClass(Compiler compiler) => null;
 
-  Iterable<ClassElement> containedClasses(Compiler compiler) {
-    return disjointMasks.expand(
-        (TypeMask mask) => mask.containedClasses(compiler));
-  }
-
-  bool understands(Selector selector, Compiler compiler) {
-    return disjointMasks.any((e) => e.understands(selector, compiler));
-  }
-
   bool needsNoSuchMethodHandling(Selector selector, Compiler compiler) {
     return disjointMasks.any(
         (e) => e.needsNoSuchMethodHandling(selector, compiler));
diff --git a/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
index d6b06ad..e4a1fa4 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
@@ -36,7 +36,6 @@
 
   bool getFlag(int position) => (flags & (1 << position)) != 0;
   void setFlag(int position) { flags |= (1 << position); }
-  void clearFlag(int position) { flags &= ~(1 << position); }
 
   int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
   int getDependsOnFlags() {
@@ -47,9 +46,7 @@
   bool dependsOnSomething() => getDependsOnFlags() != 0;
 
   void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
-  bool hasAllSideEffects() {
-    return getChangesFlags() == (1 << FLAG_CHANGES_COUNT) - 1;
-  }
+
   void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
 
   void setDependsOnSomething() {
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 73bbb9f..8e9d506 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -92,14 +92,6 @@
     return hasMatchingSelector(invokedSetters[member.name], member, compiler);
   }
 
-  bool hasFieldGetter(Element member, Compiler compiler) {
-    return fieldGetters.contains(member);
-  }
-
-  bool hasFieldSetter(Element member, Compiler compiler) {
-    return fieldSetters.contains(member);
-  }
-
   DartType registerIsCheck(DartType type, Compiler compiler) {
     type = type.unalias(compiler);
     // Even in checked mode, type annotations for return type and argument
@@ -278,7 +270,6 @@
 
   bool isOperator() => identical(kind, SelectorKind.OPERATOR);
   bool isUnaryOperator() => isOperator() && argumentCount == 0;
-  bool isBinaryOperator() => isOperator() && argumentCount == 1;
 
   /** Check whether this is a call to 'assert'. */
   bool isAssert() => isCall() && identical(name, "assert");
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
new file mode 100644
index 0000000..f8a1f9e
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -0,0 +1,188 @@
+// 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 file use methods that aren't used by dart2js.dart, but that we wish to
+/// keep anyway. This might be general API that isn't currently in use,
+/// debugging aids, or API only used for testing (see TODO below).
+
+library dart2js.use_unused_api;
+
+import 'dart2js.dart' as dart2js;
+
+import 'dart2jslib.dart' as dart2jslib;
+
+import 'tree/tree.dart' as tree;
+
+import 'util/util.dart' as util;
+
+import 'elements/visitor.dart' as elements_visitor;
+
+import 'js/js.dart' as js;
+
+import 'types/concrete_types_inferrer.dart' as concrete_types_inferrer;
+
+import 'colors.dart' as colors;
+
+import 'filenames.dart' as filenames;
+
+import 'dart_types.dart' as dart_types;
+
+import 'universe/universe.dart' as universe;
+
+import 'inferrer/type_graph_inferrer.dart' as type_graph_inferrer;
+
+import 'source_file_provider.dart' as source_file_provider;
+
+import 'ssa/ssa.dart' as ssa;
+
+class ElementVisitor extends elements_visitor.ElementVisitor {
+  visitElement(e) {}
+}
+
+void main(List<String> arguments) {
+  dart2js.main(arguments);
+  useConstant(null, null);
+  useNode(null);
+  useUtil(null);
+  useElementVisitor(new ElementVisitor());
+  useJs(new js.Program(null));
+  useJs(new js.Blob(null));
+  useJs(new js.NamedFunction(null, null));
+  useConcreteTypesInferrer(null);
+  useColor();
+  useFilenames();
+  useSsa(null);
+  useCodeBuffer(null);
+  usedByTests();
+}
+
+void useConstant(dart2jslib.Constant constant, dart2jslib.ConstantSystem cs) {
+  constant.isObject();
+  cs.isBool(constant);
+}
+
+void useNode(tree.Node node) {
+  node
+    ..asBreakStatement()
+    ..asCascade()
+    ..asCatchBlock()
+    ..asClassNode()
+    ..asCombinator()
+    ..asConditional()
+    ..asContinueStatement()
+    ..asErrorExpression()
+    ..asExport()
+    ..asFor()
+    ..asFunctionDeclaration()
+    ..asIf()
+    ..asLabeledStatement()
+    ..asLibraryDependency()
+    ..asLibraryName()
+    ..asLiteralDouble()
+    ..asLiteralList()
+    ..asLiteralMap()
+    ..asLiteralMapEntry()
+    ..asLiteralNull()
+    ..asLiteralSymbol()
+    ..asModifiers()
+    ..asPart()
+    ..asPartOf()
+    ..asRethrow()
+    ..asStatement()
+    ..asStringInterpolation()
+    ..asStringInterpolationPart()
+    ..asStringJuxtaposition()
+    ..asStringNode()
+    ..asSwitchCase()
+    ..asSwitchStatement()
+    ..asTryStatement()
+    ..asTypeAnnotation()
+    ..asTypeVariable()
+    ..asTypedef()
+    ..asWhile();
+}
+
+void useUtil(util.Link link) {
+  link.reversePrependAll(link);
+  util.trace("");
+}
+
+void useElementVisitor(ElementVisitor visitor) {
+  visitor
+    ..visit(null)
+    ..visitAbstractFieldElement(null)
+    ..visitAmbiguousElement(null)
+    ..visitBoxElement(null)
+    ..visitBoxFieldElement(null)
+    ..visitClassElement(null)
+    ..visitClosureClassElement(null)
+    ..visitClosureFieldElement(null)
+    ..visitCompilationUnitElement(null)
+    ..visitConstructorBodyElement(null)
+    ..visitElement(null)
+    ..visitErroneousElement(null)
+    ..visitFieldParameterElement(null)
+    ..visitFunctionElement(null)
+    ..visitInterceptedElement(null)
+    ..visitLabelElement(null)
+    ..visitLibraryElement(null)
+    ..visitMixinApplicationElement(null)
+    ..visitPrefixElement(null)
+    ..visitScopeContainerElement(null)
+    ..visitTargetElement(null)
+    ..visitThisElement(null)
+    ..visitTypeDeclarationElement(null)
+    ..visitTypeVariableElement(null)
+    ..visitTypedefElement(null)
+    ..visitVariableElement(null)
+    ..visitVariableListElement(null)
+    ..visitVoidElement(null)
+    ..visitWarnOnUseElement(null);
+}
+
+useJs(js.Node node) {
+  node.asVariableUse();
+}
+
+useConcreteTypesInferrer(concrete_types_inferrer.ConcreteTypesInferrer c) {
+  c.debug();
+}
+
+useColor() {
+  colors.white(null);
+  colors.blue(null);
+  colors.yellow(null);
+  colors.black(null);
+}
+
+useFilenames() {
+  filenames.appendSlash(null);
+}
+
+useSsa(ssa.HInstruction instruction) {
+  instruction.isConstantNumber();
+  new ssa.HAndOrBlockInformation(null, null, null);
+  new ssa.HStatementSequenceInformation(null);
+}
+
+useCodeBuffer(dart2jslib.CodeBuffer buffer) {
+  buffer.writeln();
+}
+
+usedByTests() {
+  // TODO(ahe): We should try to avoid including API used only for tests. In
+  // most cases, such API can be moved to a test library.
+  dart2jslib.World world = null;
+  dart2jslib.Compiler compiler = null;
+  type_graph_inferrer.TypeGraphInferrer typeGraphInferrer = null;
+  source_file_provider.SourceFileProvider sourceFileProvider = null;
+  world.hasAnyUserDefinedGetter(null);
+  compiler.importHelperLibrary(null);
+  typeGraphInferrer.getCallersOf(null);
+  dart_types.Types.sorted(null);
+  new universe.TypedSelector.subclass(null, null);
+  new universe.TypedSelector.subtype(null, null);
+  new universe.TypedSelector.exact(null, null);
+  sourceFileProvider.readStringFromUri(null);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 62dcce4..e1a8516 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -1079,11 +1079,18 @@
       "a class.");
 
   static const MessageKind STATIC_FUNCTION_BLOAT = const MessageKind(
-      "Hint: Using '#{class}.#{name}' may result in larger output.");
+      "Hint: Using '#{class}.#{name}' may lead to unnecessarily large "
+      "generated code.",
+      howToFix:
+          "Try adding '@MirrorsUsed(...)' as described at "
+          "https://goo.gl/Akrrog.");
 
-  static const MessageKind NON_CONST_BLOAT = const MessageKind('''
-Hint: Using "new #{name}' may result in larger output.
-Use 'const #{name}' if possible.''');
+  static const MessageKind NON_CONST_BLOAT = const MessageKind(
+      "Hint: Using 'new #{name}' may lead to unnecessarily large generated "
+      "code.",
+      howToFix:
+          "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
+          "described at https://goo.gl/Akrrog.");
 
   static const MessageKind STRING_EXPECTED = const MessageKind(
       "Error: Expected a 'String', but got an instance of '#{type}'.");
@@ -1331,6 +1338,13 @@
   static const MessageKind MIRROR_IMPORT = const MessageKind(
       "Info: Import of 'dart:mirrors'.");
 
+  static const MessageKind MIRROR_IMPORT_NO_USAGE = const MessageKind(
+      "Info: This import is not annotated with @MirrorsUsed, which may lead to "
+      "unnecessarily large generated code.",
+      howToFix:
+          "Try adding '@MirrorsUsed(...)' as described at "
+          "https://goo.gl/Akrrog.");
+
   static const MessageKind WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT =
       const MessageKind(
       "Error: Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant.");
@@ -1341,6 +1355,46 @@
           howToFix: "Try using a different name.",
           examples: const ["do() {} main() {}"]);
 
+  static const MessageKind UNUSED_METHOD = const MessageKind(
+      "Hint: The method '#{method_name}' is never called.",
+      howToFix: "Consider deleting it.",
+      examples: const ["deadCode() {} main() {}"]);
+
+  static const MessageKind UNIMPLEMENTED_METHOD = const MessageKind(
+      "Warning: '#{class_name}' doesn't implement '#{member_name}'.",
+      howToFix: "Try adding an implementation of '#{member_name}'.",
+      examples: const ["""
+abstract class I {
+  m();
+}
+
+class C implements I {}
+
+class D implements I {
+  m() {}
+}
+
+main() {
+ new D().m();
+ new C();
+}
+""", """
+abstract class I {
+  m();
+}
+
+class C extends I {}
+
+class D extends I {
+  m() {}
+}
+
+main() {
+ new D().m();
+ new C();
+}
+"""]);
+
   static const MessageKind COMPILER_CRASHED = const MessageKind(
       "Error: The compiler crashed when compiling this element.");
 
@@ -1394,6 +1448,17 @@
       "'#{shownType}' because '#{shownType}' is not more specific than the "
       "known type '#{knownType}' of '#{variableName}'.");
 
+  static const MessageKind NOT_MORE_SPECIFIC_SUBTYPE = const MessageKind(
+      "Hint: Variable '#{variableName}' is not shown to have type "
+      "'#{shownType}' because '#{shownType}' is not a subtype of the "
+      "known type '#{knownType}' of '#{variableName}'.");
+
+  static const MessageKind NOT_MORE_SPECIFIC_SUGGESTION = const MessageKind(
+      "Hint: Variable '#{variableName}' is not shown to have type "
+      "'#{shownType}' because '#{shownType}' is not more specific than the "
+      "known type '#{knownType}' of '#{variableName}'.",
+      howToFix: "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'.");
+
   //////////////////////////////////////////////////////////////////////////////
   // Patch errors start.
   //////////////////////////////////////////////////////////////////////////////
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index aa48510..8a044ec 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -20,8 +20,6 @@
   // distinct sets to make class hierarchy analysis faster.
   final Map<ClassElement, Set<ClassElement>> _subclasses =
       new Map<ClassElement, Set<ClassElement>>();
-  final Map<ClassElement, Set<ClassElement>> _superclasses =
-      new Map<ClassElement, Set<ClassElement>>();
   final Map<ClassElement, Set<ClassElement>> _subtypes =
       new Map<ClassElement, Set<ClassElement>>();
   final Map<ClassElement, Set<ClassElement>> _supertypes =
@@ -39,10 +37,6 @@
     return _subtypes[cls.declaration];
   }
 
-  Set<ClassElement> superclassesOf(ClassElement cls) {
-    return _superclasses[cls.declaration];
-  }
-
   Set<ClassElement> supertypesOf(ClassElement cls) {
     return _supertypes[cls.declaration];
   }
@@ -81,11 +75,8 @@
       // implemented by that type on the superclasses.
       DartType type = cls.supertype;
       while (type != null) {
-        Set<Element> superclassesOfClass =
-            _superclasses.putIfAbsent(cls, () => new Set<ClassElement>());
         Set<Element> subclassesOfSuperclass =
             _subclasses.putIfAbsent(type.element, () => new Set<ClassElement>());
-        superclassesOfClass.add(type.element);
         subclassesOfSuperclass.add(cls);
 
         Set<Element> typesImplementedBySubclassesOfCls =
@@ -151,10 +142,6 @@
     return allFunctions.filter(selector).any((each) => each.isGetter());
   }
 
-  bool hasAnyUserDefinedSetter(Selector selector) {
-     return allFunctions.filter(selector).any((each) => each.isSetter());
-  }
-
   // Returns whether a subclass of [superclass] implements [type].
   bool hasAnySubclassThatImplements(ClassElement superclass,
                                     ClassElement type) {
@@ -208,24 +195,6 @@
     return mask.locateSingleElement(selector, compiler);
   }
 
-  bool hasSingleMatch(Selector selector) {
-    Iterable<Element> targets = allFunctions.filter(selector);
-    return targets.length == 1;
-  }
-
-  Iterable<ClassElement> locateNoSuchMethodHolders(Selector selector) {
-    Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
-    ti.TypeMask mask = selector.mask;
-    if (mask != null) {
-      noSuchMethodSelector = new TypedSelector(mask, noSuchMethodSelector);
-    }
-    ClassElement objectClass = compiler.objectClass;
-    return allFunctions
-        .filter(noSuchMethodSelector)
-        .map((Element member) => member.getEnclosingClass())
-        .where((ClassElement holder) => !identical(holder, objectClass));
-  }
-
   void addFunctionCalledInLoop(Element element) {
     functionsCalledInLoop.add(element.declaration);
   }
diff --git a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
index df3f21a..f4920ae 100644
--- a/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
+++ b/sdk/lib/_internal/compiler/samples/compile_loop/compile_loop.dart
@@ -43,7 +43,7 @@
     }
   }
   return compiler.compile(
-      new Uri('memory:/main.dart'),
+      Uri.parse('memory:/main.dart'),
       Uri.parse('sdk:/sdk/'),
       null,
       inputProvider,
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
index b25aab3..36596aa 100644
--- a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -56,14 +56,14 @@
 }
 
 jsonify(MirrorSystem mirrors) {
-  var map = {};
+  var map = <String, String>{};
 
   mirrors.libraries.forEach((_, LibraryMirror library) {
     BackDoor.compilationUnitsOf(library).forEach((compilationUnit) {
       Uri uri = compilationUnit.uri;
       String filename = relativize(sdkRoot, uri, false);
       SourceFile file = handler.provider.sourceFiles['$uri'];
-      map['sdk:/$filename'] = file.text;
+      map['sdk:/$filename'] = file.slowText();
     });
   });
 
@@ -73,7 +73,7 @@
       Uri uri = sdkRoot.resolve('sdk/lib/$patch');
       String filename = relativize(sdkRoot, uri, false);
       SourceFile file = handler.provider.sourceFiles['$uri'];
-      map['sdk:/$filename'] = file.text;
+      map['sdk:/$filename'] = file.slowText();
     }
   });
 
diff --git a/sdk/lib/_internal/compiler/samples/leap/index.html b/sdk/lib/_internal/compiler/samples/leap/index.html
deleted file mode 100644
index e288ba0..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE 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
-     BSD-style license that can be found in the LICENSE file.
--->
-<html>
-  <head>
-    <title>Leap Leg</title>
-    <link rel="stylesheet" type="text/css" href="leap.css" />
-  </head>
-  <body>
-    <h2 id="status">Dart is not running</h2>
-
-    <section id="outline">
-      <h3>Outline</h3>
-      <div id="out" style="white-space: pre-wrap"></div>
-    </section>
-
-    <section id="editor">
-      <h3>Code</h3>
-      <div id="code">void main() {
-  print('Hello, World');
-}
-</div>
-    </section>
-
-    <iframe id="isolate" style="display:none" src="isolate.html"></iframe>
-
-    <div id="popup"></div>
-
-    <script type="application/dart" src="leap.dart"></script>
-    <script src="http://dart.googlecode.com/svn/branches/bleeding_edge/dart/client/dart.js"></script>
-  </body>
-</html>
diff --git a/sdk/lib/_internal/compiler/samples/leap/isolate.html b/sdk/lib/_internal/compiler/samples/leap/isolate.html
deleted file mode 100644
index 7b965b1..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/isolate.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE 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
-     BSD-style license that can be found in the LICENSE file.
--->
-<html>
-  <head>
-    <title>isolate</title>
-  </head>
-  <body>
-    <h1>fisk</h1>
-  </body>
-</html>
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap.css b/sdk/lib/_internal/compiler/samples/leap/leap.css
deleted file mode 100644
index 28e0dbe..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap.css
+++ /dev/null
@@ -1,34 +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.
- */
-
-#popup {
-  position: fixed;
-  width: 400px;
-  background: yellow;
-  border: thin solid red;
-  z-index: 100;
-  top: 0px;
-  left: 0px;
-  visibility: hidden;
-  white-space: pre-wrap
-}
-
-#outline {
-  position: fixed;
-  width: 250px;
-  border: solid;
-  padding: 5px;
-}
-
-#editor {
-  position: absolute;
-  left: 280px;
-  border: solid;
-  padding: 5px;
-}
-
-#code {
-  white-space: pre;
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap.dart b/sdk/lib/_internal/compiler/samples/leap/leap.dart
deleted file mode 100644
index f352287..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap.dart
+++ /dev/null
@@ -1,18 +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 leap;
-
-import 'dart:isolate';
-
-import 'dart:html' as html;
-import 'request_cache.dart';
-import '../../lib/compiler/implementation/elements/elements.dart';
-import '../../lib/compiler/implementation/dart2jslib.dart';
-import '../../lib/compiler/implementation/tree/tree.dart';
-import '../../lib/compiler/implementation/source_file.dart';
-import '../../lib/compiler/implementation/library_map.dart';
-
-part 'leap_leg.dart';
-part 'leap_script.dart';
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart b/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart
deleted file mode 100644
index 87ba938..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap_leg.dart
+++ /dev/null
@@ -1,295 +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.
-
-compilerIsolate(port) {
-  Runner runner = new Runner();
-  runner.init();
-
-  port.receive((msg, replyTo) {
-    replyTo.send(runner.update(msg));
-  });
-}
-
-main() {
-  html.document.query('#status').innerHTML = 'Initializing...';
-  setOutline(msg) {
-    html.document.query('#out').innerHTML = msg;
-  }
-  final codeDiv = html.document.query('#code');
-  final popup = html.document.query('#popup');
-
-  // The port for communicating with the compiler isolate.
-  var port = null;
-
-  // Should be called when [codeDiv] has changed. For now, call it always
-  // on mouse up and key up events.
-  update() {
-    if (port == null) return;
-    port.call(codeDiv.text).then(setOutline);
-  }
-
-  hide(Element e) {
-    e.style.visibility = 'hidden';
-  }
-
-  show(Element e) {
-    e.style.visibility = 'visible';
-  }
-
-  insertTextAtPoint(Event e, String newText) {
-    e.preventDefault();
-    var selection = html.window.getSelection();
-    var range = selection.getRangeAt(0);
-    var offset = range.startOffset;
-    Text text = codeDiv.nodes[0];
-    text.insertData(offset, newText);
-    selection.setPosition(text, offset + newText.length);
-  }
-
-  // This prevents creating a new div element when hitting enter.
-  codeDiv.on.keyPress.add((Event e) {
-    if (e.keyIdentifier == 'Enter') {
-      // TODO(ahe): Is 'Enter' portable?
-      insertTextAtPoint(e, '\n');
-    }
-  });
-
-  // Override tab key.
-  codeDiv.on.keyDown.add((Event e) {
-    if (e.keyIdentifier == 'U+0009') {
-      // TODO(ahe): Find better way to detect tab key.
-      insertTextAtPoint(e, '  ');
-    }
-  });
-
-  // Called on keyUp and mouseUp to display a marker at the current
-  // insertion point (the selection's first range). This probably
-  // needs more work before it works really well, but seems to be good
-  // enough for now.
-  handleUp(Event e) {
-    var selection = html.window.getSelection();
-    var range = selection.getRangeAt(0);
-    var rects = range.getClientRects();
-    if (rects.length < 1) {
-      hide(popup);
-      return;
-    }
-    html.ClientRect rect = rects.item(rects.length - 1);
-    if (rect.width.toInt() != 0) {
-      // This is a selection of multiple characters, not a single
-      // point of insertion.
-      hide(popup);
-      return;
-    }
-    popup.style.top = "${rect.bottom.toInt()}px";
-    popup.style.left = "${rect.right.toInt()}px";
-    // Instead of displaying this immediately, we could set up a timer
-    // event and display it later. This is a matter of getting the UX
-    // just right, for now it simply demonstrates that we know where
-    // the insertion point is (in pixels) and what the character
-    // offset is.
-    show(popup);
-    popup.text = '''Code completion here...
-Current character offset: ${range.startOffset}''';
-    // TODO(ahe): Better detection of when [codeDiv] has changed.
-    update();
-  }
-
-  codeDiv.on.keyUp.add(handleUp);
-  codeDiv.on.mouseUp.add(handleUp);
-
-  codeDiv.on.blur.add((Event e) => hide(popup));
-
-  // The event handlers are now set up. Allow editing.
-  codeDiv.contentEditable = "true";
-
-  // Creates a compiler isolate in its own iframe. This should prevent
-  // the compiler from blocking the UI.
-  spawnDomIsolate(html.document.query('#isolate').contentWindow,
-                       'compilerIsolate').then((sendPort) {
-    // The compiler isolate is now ready to talk. Store the port so
-    // that the update function starts requesting outlines whenever
-    // [codeDiv] changes.
-    port = sendPort;
-    // Make sure that we get an initial outline.
-    update();
-    html.document.query('#status').innerHTML = 'Ready';
-  });
-}
-
-class Runner {
-  final LeapCompiler compiler;
-
-  Runner() : compiler = new LeapCompiler();
-
-  String init() {
-    Stopwatch sw = new Stopwatch()..start();
-    // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
-    // Delete this sample.
-    compiler.scanBuiltinLibraries();
-    sw.stop();
-    return 'Scanned core libraries in ${sw.elapsedMilliseconds}ms';
-  }
-
-  String update(String codeText) {
-    StringBuffer sb = new StringBuffer();
-
-    Stopwatch sw = new Stopwatch()..start();
-
-    LibraryElement e = compile(new LeapScript(codeText));
-
-    void printFunction(FunctionElement fe, [String indentation = ""]) {
-      var paramAcc = [];
-
-      FunctionType ft = fe.computeType(compiler);
-
-      sb.write("<div>${indentation}");
-      ft.returnType.name.printOn(sb);
-      sb.write(" ");
-      fe.name.printOn(sb);
-      sb.write("(");
-      ft.parameterTypes.printOn(sb, ", ");
-      sb.write(");</div>");
-
-    }
-
-    void printField(FieldElement fe, [String indentation = ""]) {
-      sb.write("<div>${indentation}var ");
-      fe.name.printOn(sb);
-      sb.write(";</div>");
-    }
-
-    void printClass(ClassElement ce) {
-      ce.parseNode(compiler);
-
-      sb.write("<div>class ");
-      ce.name.printOn(sb);
-      sb.write(" {");
-
-      for (Element e in ce.members.reverse()) {
-        switch(e.kind) {
-        case ElementKind.FUNCTION:
-
-          printFunction(e, "&nbsp; ");
-          break;
-
-        case ElementKind.FIELD:
-
-          printField(e, "&nbsp; ");
-          break;
-        }
-      }
-      sb.write("}</div>");
-    }
-
-    for (Element c in e.topLevelElements.reverse()) {
-      switch (c.kind) {
-      case ElementKind.FUNCTION:
-        printFunction (c);
-        break;
-
-      case ElementKind.CLASS:
-        printClass(c);
-        break;
-
-      case ElementKind.FIELD:
-        printField (c);
-        break;
-      }
-    }
-
-    compiler.log("Outline ${sw.elapsedMilliseconds}");
-    return sb.toString();
-  }
-
-  Element compile(String script) {
-    return compiler.runSelective(script);
-  }
-}
-
-class LeapCompiler extends Compiler {
-  HttpRequestCache cache;
-
-  final bool throwOnError = false;
-
-  final libDir = "../..";
-
-  LeapCompiler() : cache = new HttpRequestCache(), super() {
-    tasks = [scanner, dietParser, parser, resolver, checker];
-  }
-
-  void log(message) { print(message); }
-
-  String get legDirectory => libDir;
-
-  // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
-  // Delete this sample.
-  LibraryElement scanBuiltinLibrary(String path) {
-    Uri base = Uri.parse(html.window.location.toString());
-    Uri libraryRoot = base.resolve(libDir);
-    Uri resolved = libraryRoot.resolve(DART2JS_LIBRARY_MAP[path]);
-    // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
-    // Delete this sample.
-    LibraryElement library = scanner.loadLibrary(resolved, null);
-    return library;
-  }
-
-  currentScript() {
-    if (currentElement == null) return null;
-    CompilationUnitElement compilationUnit =
-      currentElement.getCompilationUnit();
-    if (compilationUnit == null) return null;
-    return compilationUnit.script;
-  }
-
-  // TODO(rnystrom): This is broken now that scanBuiltInLibraries is async.
-  // Delete this sample.
-  Script readScript(Uri uri, [ScriptTag node]) {
-    String text = "";
-    try {
-      text = cache.readAll(uri.path.toString());
-    } catch (exception) {
-      cancel("${uri.path}: $exception", node: node);
-    }
-    SourceFile sourceFile = new SourceFile(uri.toString(), text);
-    return new Script(uri, sourceFile);
-  }
-
-  reportWarning(Node node, var message) {
-    print(message);
-  }
-
-  reportError(Node node, var message) {
-    cancel(message.toString(), node);
-  }
-
-  void cancel(String reason, {Node node, token, instruction, element}) {
-    print(reason);
-  }
-
-  Element runSelective(Script script) {
-    Stopwatch sw = new Stopwatch()..start();
-    Element e;
-    try {
-      e = runCompilerSelective(script);
-    } on CompilerCancelledException catch (exception) {
-      log(exception.toString());
-      log('compilation failed');
-      return null;
-    }
-    log('compilation succeeded: ${sw.elapsedMilliseconds}ms');
-    return e;
-  }
-
-  LibraryElement runCompilerSelective(Script script) {
-    mainApp = new LibraryElement(script);
-
-    universe.libraries.remove(script.uri.toString());
-    Element element;
-    withCurrentElement(mainApp, () {
-        scanner.scan(mainApp);
-      });
-    return mainApp;
-  }
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_script.dart b/sdk/lib/_internal/compiler/samples/leap/leap_script.dart
deleted file mode 100644
index 3fa045f..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/leap_script.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class LeapScript {
-  final text;
-  LeapScript(this.text);
-
-  String get name => "SomeName";
-  String get uri => name;
-  String get file => "somefile";
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/request_cache.dart b/sdk/lib/_internal/compiler/samples/leap/request_cache.dart
deleted file mode 100644
index 637fa7a..0000000
--- a/sdk/lib/_internal/compiler/samples/leap/request_cache.dart
+++ /dev/null
@@ -1,27 +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 request_cache;
-
-import 'dart:html';
-
-/** File system implementation using HTML5's Web Storage. */
-class HttpRequestCache {
-  final Storage storage;
-
-  HttpRequestCache() : storage = window.sessionStorage;
-
-  String readAll(String filename) {
-    String response = storage[filename];
-
-    if (response == null) {
-      HttpRequest xr = new HttpRequest();
-      xr.open("GET", filename, false);
-      xr.send();
-      response = xr.responseText;
-      storage[filename] = response;
-    }
-    return response;
-  }
-}
diff --git a/sdk/lib/_internal/compiler/samples/leap/leap_server.dart b/sdk/lib/_internal/compiler/samples/leap_server/leap_server.dart
similarity index 100%
rename from sdk/lib/_internal/compiler/samples/leap/leap_server.dart
rename to sdk/lib/_internal/compiler/samples/leap_server/leap_server.dart
diff --git a/sdk/lib/_internal/lib/collection_patch.dart b/sdk/lib/_internal/lib/collection_patch.dart
index feb40e6..192dfd3 100644
--- a/sdk/lib/_internal/lib/collection_patch.dart
+++ b/sdk/lib/_internal/lib/collection_patch.dart
@@ -515,7 +515,7 @@
   // iterated over.
   int _modifications = 0;
 
-  _LinkedHash();
+  _LinkedHashMap();
 
 
   int get length => _length;
diff --git a/sdk/lib/_internal/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
index 0fabc0b..398d37c 100644
--- a/sdk/lib/_internal/lib/constant_map.dart
+++ b/sdk/lib/_internal/lib/constant_map.dart
@@ -122,4 +122,6 @@
   Iterable<V> get values {
     return _getMap().values;
   }
+
+  int get length => _getMap().length;
 }
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index d262d79..bc87e41 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -345,8 +345,9 @@
 }
 
 patch class _FileSystemWatcher {
-  patch factory _FileSystemWatcher(String path, int events, bool recursive) {
-    throw new UnsupportedError("_FileSystemWatcher._FileSystemWatcher");
+  patch static Stream<FileSystemEvent> watch(
+      String path, int events, bool recursive) {
+    throw new UnsupportedError("_FileSystemWatcher.watch");
   }
   patch static bool get isSupported {
     throw new UnsupportedError("_FileSystemWatcher.isSupported");
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 474d6af..0ff3096 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -703,7 +703,7 @@
  ********************************************************/
 
 /** Common functionality to all send ports. */
-class _BaseSendPort implements SendPort {
+abstract class _BaseSendPort implements SendPort {
   /** Id for the destination isolate. */
   final int _isolateId;
 
@@ -1216,6 +1216,7 @@
     return copy;
   }
 
+  visitSendPort(SendPort x) => throw new UnimplementedError();
 }
 
 /** Visitor that serializes a message as a JSON array. */
@@ -1257,6 +1258,8 @@
     }
     return result;
   }
+
+  visitSendPort(SendPort x) => throw new UnimplementedError();
 }
 
 /** Deserializes arrays created with [_Serializer]. */
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index c62ffd2..b1fb4c4 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -183,9 +183,11 @@
 class JsTypeVariableMirror extends JsTypeMirror implements TypeVariableMirror {
   final DeclarationMirror owner;
   final TypeVariable _typeVariable;
+  final int _metadataIndex;
   TypeMirror _cachedUpperBound;
 
-  JsTypeVariableMirror(TypeVariable typeVariable, this.owner)
+  JsTypeVariableMirror(TypeVariable typeVariable, this.owner,
+                       this._metadataIndex)
       : this._typeVariable = typeVariable,
         super(s(typeVariable.name));
 
@@ -228,7 +230,9 @@
   List<InstanceMirror> get metadata => throw new UnimplementedError();
 
   bool get hasReflectedType => false;
-  Type get reflectedType => throw new UnsupportedError("This type does not support reflectedTypees");
+  Type get reflectedType {
+    throw new UnsupportedError("This type does not support reflectedTypees");
+  }
 
   List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
   List<TypeMirror> get typeArguments => const <TypeMirror>[];
@@ -273,7 +277,7 @@
 
   List<JsMethodMirror> get _methods => _functionMirrors;
 
-  Map<Symbol, ClassMirror> get classes {
+  Map<Symbol, ClassMirror> get __classes {
     if (_cachedClasses != null) return _cachedClasses;
     var result = new Map();
     for (String className in _classes) {
@@ -293,8 +297,8 @@
   InstanceMirror setField(Symbol fieldName, Object arg) {
     String name = n(fieldName);
     if (name.endsWith('=')) throw new ArgumentError('');
-    var mirror = functions[s('$name=')];
-    if (mirror == null) mirror = variables[fieldName];
+    var mirror = __functions[s('$name=')];
+    if (mirror == null) mirror = __variables[fieldName];
     if (mirror == null) {
       // TODO(ahe): What receiver to use?
       throw new NoSuchMethodError(this, setterSymbol(fieldName), [arg], null);
@@ -304,7 +308,7 @@
   }
 
   InstanceMirror getField(Symbol fieldName) {
-    JsMirror mirror = members[fieldName];
+    JsMirror mirror = __members[fieldName];
     if (mirror == null) {
       // TODO(ahe): What receiver to use?
       throw new NoSuchMethodError(this, fieldName, [], null);
@@ -318,7 +322,7 @@
     if (namedArguments != null && !namedArguments.isEmpty) {
       throw new UnsupportedError('Named arguments are not implemented.');
     }
-    JsDeclarationMirror mirror = members[memberName];
+    JsDeclarationMirror mirror = __members[memberName];
     if (mirror == null) {
       // TODO(ahe): What receiver to use?
       throw new NoSuchMethodError(
@@ -386,7 +390,7 @@
     return _cachedFields = result;
   }
 
-  Map<Symbol, MethodMirror> get functions {
+  Map<Symbol, MethodMirror> get __functions {
     if (_cachedFunctions != null) return _cachedFunctions;
     var result = new Map();
     for (JsMethodMirror mirror in _functionMirrors) {
@@ -396,7 +400,7 @@
         new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
-  Map<Symbol, MethodMirror> get getters {
+  Map<Symbol, MethodMirror> get __getters {
     if (_cachedGetters != null) return _cachedGetters;
     var result = new Map();
     // TODO(ahe): Implement this.
@@ -404,7 +408,7 @@
         new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
-  Map<Symbol, MethodMirror> get setters {
+  Map<Symbol, MethodMirror> get __setters {
     if (_cachedSetters != null) return _cachedSetters;
     var result = new Map();
     // TODO(ahe): Implement this.
@@ -412,7 +416,7 @@
         new UnmodifiableMapView<Symbol, MethodMirror>(result);
   }
 
-  Map<Symbol, VariableMirror> get variables {
+  Map<Symbol, VariableMirror> get __variables {
     if (_cachedVariables != null) return _cachedVariables;
     var result = new Map();
     for (JsVariableMirror mirror in _fields) {
@@ -422,16 +426,16 @@
         new UnmodifiableMapView<Symbol, VariableMirror>(result);
   }
 
-  Map<Symbol, Mirror> get members {
+  Map<Symbol, Mirror> get __members {
     if (_cachedMembers !=  null) return _cachedMembers;
-    Map<Symbol, Mirror> result = new Map.from(classes);
+    Map<Symbol, Mirror> result = new Map.from(__classes);
     addToResult(Symbol key, Mirror value) {
       result[key] = value;
     }
-    functions.forEach(addToResult);
-    getters.forEach(addToResult);
-    setters.forEach(addToResult);
-    variables.forEach(addToResult);
+    __functions.forEach(addToResult);
+    __getters.forEach(addToResult);
+    __setters.forEach(addToResult);
+    __variables.forEach(addToResult);
     return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(result);
   }
 
@@ -441,7 +445,7 @@
     addToResult(Symbol key, Mirror value) {
       result[key] = value;
     }
-    members.forEach(addToResult);
+    __members.forEach(addToResult);
     return _cachedDeclarations =
         new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
   }
@@ -455,6 +459,14 @@
 
   // TODO(ahe): Test this getter.
   DeclarationMirror get owner => null;
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get topLevelMembers
+      => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Function operator [](Symbol name)
+      => throw new UnimplementedError();
 }
 
 String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -676,15 +688,15 @@
   // TODO(ahe): Remove this method, only here to silence warning.
   get _mixin => mixin;
 
-  Map<Symbol, Mirror> get members => _mixin.members;
+  Map<Symbol, Mirror> get __members => _mixin.__members;
 
-  Map<Symbol, MethodMirror> get methods => _mixin.methods;
+  Map<Symbol, MethodMirror> get __methods => _mixin.__methods;
 
-  Map<Symbol, MethodMirror> get getters => _mixin.getters;
+  Map<Symbol, MethodMirror> get __getters => _mixin.__getters;
 
-  Map<Symbol, MethodMirror> get setters => _mixin.setters;
+  Map<Symbol, MethodMirror> get __setters => _mixin.__setters;
 
-  Map<Symbol, VariableMirror> get variables => _mixin.variables;
+  Map<Symbol, VariableMirror> get __variables => _mixin.__variables;
 
   Map<Symbol, DeclarationMirror> get declarations => mixin.declarations;
 
@@ -709,7 +721,7 @@
 
   List<ClassMirror> get superinterfaces => [mixin];
 
-  Map<Symbol, MethodMirror> get constructors => _mixin.constructors;
+  Map<Symbol, MethodMirror> get __constructors => _mixin.__constructors;
 
   InstanceMirror newInstance(
       Symbol constructorName,
@@ -729,6 +741,16 @@
   }
 
   List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get instanceMembers
+      => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Function operator [](Symbol name) => throw new UnimplementedError();
 }
 
 abstract class JsObjectMirror implements ObjectMirror {
@@ -879,6 +901,9 @@
 
   // TODO(ahe): Remove this method from the API.
   MirrorSystem get mirrors => currentJsMirrorSystem;
+
+  // TODO(ahe): Implement this method.
+  Function operator [](Symbol name) => throw new UnimplementedError();
 }
 
 /**
@@ -888,7 +913,8 @@
  * to JsCLassMirror that returns an empty list since it represents original
  * declarations and classes that are not generic.
  */
-class JsTypeBoundClassMirror extends JsDeclarationMirror implements ClassMirror {
+class JsTypeBoundClassMirror extends JsDeclarationMirror
+    implements ClassMirror {
   final JsClassMirror _class;
 
   /**
@@ -938,7 +964,7 @@
         TypeVariable typeVariable = getMetadata(parsedIndex);
         TypeMirror owner = reflectClass(typeVariable.owner);
         TypeVariableMirror typeMirror =
-            new JsTypeVariableMirror(typeVariable, owner);
+            new JsTypeVariableMirror(typeVariable, owner, parsedIndex);
         result.add(typeMirror);
       }
     }
@@ -980,32 +1006,32 @@
     return _cachedMethods =_class._getMethodsWithOwner(this);
   }
 
-  Map<Symbol, MethodMirror> get methods {
+  Map<Symbol, MethodMirror> get __methods {
     if (_cachedMethodsMap != null) return _cachedMethodsMap;
     return _cachedMethodsMap = new UnmodifiableMapView<Symbol, MethodMirror>(
         filterMethods(_methods));
   }
 
-  Map<Symbol, MethodMirror> get constructors {
+  Map<Symbol, MethodMirror> get __constructors {
     if (_cachedConstructors != null) return _cachedConstructors;
     return _cachedConstructors =
         new UnmodifiableMapView<Symbol, MethodMirror>(
             filterConstructors(_methods));
   }
 
-  Map<Symbol, MethodMirror> get getters {
+  Map<Symbol, MethodMirror> get __getters {
     if (_cachedGetters != null) return _cachedGetters;
     return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
-        filterGetters(_methods, variables));
+        filterGetters(_methods, __variables));
   }
 
-  Map<Symbol, MethodMirror> get setters {
+  Map<Symbol, MethodMirror> get __setters {
     if (_cachedSetters != null) return _cachedSetters;
     return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
-        filterSetters(_methods, variables));
+        filterSetters(_methods, __variables));
   }
 
-  Map<Symbol, VariableMirror> get variables {
+  Map<Symbol, VariableMirror> get __variables {
     if (_cachedVariables != null) return _cachedVariables;
     var result = new Map();
     for (JsVariableMirror mirror in  _class._getFieldsWithOwner(this)) {
@@ -1015,18 +1041,18 @@
         new UnmodifiableMapView<Symbol, VariableMirror>(result);
   }
 
-  Map<Symbol, DeclarationMirror> get members {
+  Map<Symbol, DeclarationMirror> get __members {
     if (_cachedMembers != null) return _cachedMembers;
     return _cachedMembers = new UnmodifiableMapView<Symbol, DeclarationMirror>(
-        filterMembers(_methods, variables));
+        filterMembers(_methods, __variables));
   }
 
   Map<Symbol, DeclarationMirror> get declarations {
     if (_cachedDeclarations != null) return _cachedDeclarations;
     Map<Symbol, DeclarationMirror> result =
         new Map<Symbol, DeclarationMirror>();
-    result.addAll(members);
-    result.addAll(constructors);
+    result.addAll(__members);
+    result.addAll(__constructors);
     typeVariables.forEach((tv) => result[tv.simpleName] = tv);
     return _cachedDeclarations =
         new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
@@ -1090,6 +1116,19 @@
   Type get reflectedType => _class.reflectedType;
 
   Symbol get simpleName => _class.simpleName;
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get instanceMembers
+      => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  ClassMirror get mixin => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Function operator [](Symbol name) => throw new UnimplementedError();
 }
 
 class JsClassMirror extends JsTypeMirror with JsObjectMirror
@@ -1134,7 +1173,7 @@
     }
   }
 
-  Map<Symbol, MethodMirror> get constructors {
+  Map<Symbol, MethodMirror> get __constructors {
     if (_cachedConstructors != null) return _cachedConstructors;
     return _cachedConstructors =
         new UnmodifiableMapView<Symbol, MethodMirror>(
@@ -1222,25 +1261,25 @@
     return _cachedFields = _getFieldsWithOwner(this);
   }
 
-  Map<Symbol, MethodMirror> get methods {
+  Map<Symbol, MethodMirror> get __methods {
     if (_cachedMethodsMap != null) return _cachedMethodsMap;
     return _cachedMethodsMap =
         new UnmodifiableMapView<Symbol, MethodMirror>(filterMethods(_methods));
   }
 
-  Map<Symbol, MethodMirror> get getters {
+  Map<Symbol, MethodMirror> get __getters {
     if (_cachedGetters != null) return _cachedGetters;
     return _cachedGetters = new UnmodifiableMapView<Symbol, MethodMirror>(
-        filterGetters(_methods, variables));
+        filterGetters(_methods, __variables));
   }
 
-  Map<Symbol, MethodMirror> get setters {
+  Map<Symbol, MethodMirror> get __setters {
     if (_cachedSetters != null) return _cachedSetters;
     return _cachedSetters = new UnmodifiableMapView<Symbol, MethodMirror>(
-        filterSetters(_methods, variables));
+        filterSetters(_methods, __variables));
   }
 
-  Map<Symbol, VariableMirror> get variables {
+  Map<Symbol, VariableMirror> get __variables {
     if (_cachedVariables != null) return _cachedVariables;
     var result = new Map();
     for (JsVariableMirror mirror in _fields) {
@@ -1250,10 +1289,10 @@
         new UnmodifiableMapView<Symbol, VariableMirror>(result);
   }
 
-  Map<Symbol, Mirror> get members {
+  Map<Symbol, Mirror> get __members {
     if (_cachedMembers != null) return _cachedMembers;
     return _cachedMembers = new UnmodifiableMapView<Symbol, Mirror>(
-        filterMembers(_methods, variables));
+        filterMembers(_methods, __variables));
   }
 
   Map<Symbol, DeclarationMirror> get declarations {
@@ -1262,15 +1301,15 @@
     addToResult(Symbol key, Mirror value) {
       result[key] = value;
     }
-    members.forEach(addToResult);
-    constructors.forEach(addToResult);
+    __members.forEach(addToResult);
+    __constructors.forEach(addToResult);
     typeVariables.forEach((tv) => result[tv.simpleName] = tv);
     return _cachedDeclarations =
         new UnmodifiableMapView<Symbol, DeclarationMirror>(result);
   }
 
   InstanceMirror setField(Symbol fieldName, Object arg) {
-    JsVariableMirror mirror = variables[fieldName];
+    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.
@@ -1286,7 +1325,7 @@
   }
 
   InstanceMirror getField(Symbol fieldName) {
-    JsVariableMirror mirror = variables[fieldName];
+    JsVariableMirror mirror = __variables[fieldName];
     if (mirror != null && mirror.isStatic) {
       String jsName = mirror._jsName;
       // '$' (JS_CURRENT_ISOLATE()) stores state which is read directly, so
@@ -1314,7 +1353,7 @@
     JsMethodMirror mirror =
         JsCache.fetch(_jsConstructorCache, n(constructorName));
     if (mirror == null) {
-      mirror = constructors.values.firstWhere(
+      mirror = __constructors.values.firstWhere(
           (m) => m.constructorName == constructorName,
           orElse: () {
             // TODO(ahe): What receiver to use?
@@ -1336,7 +1375,7 @@
             // This will set _owner field on all clasess as a side
             // effect.  This gives us a fast path to reflect on a
             // class without parsing reflection data.
-            library.classes;
+            library.__classes;
           }
         }
       }
@@ -1392,7 +1431,7 @@
     if (namedArguments != null && !namedArguments.isEmpty) {
       throw new UnsupportedError('Named arguments are not implemented.');
     }
-    JsMethodMirror mirror = methods[memberName];
+    JsMethodMirror mirror = __methods[memberName];
     if (mirror == null || !mirror.isStatic) {
       // TODO(ahe): What receiver to use?
       throw new NoSuchMethodError(
@@ -1438,12 +1477,26 @@
     if (typeVariables == null) return result;
     for (int i = 0; i < typeVariables.length; i++) {
       TypeVariable typeVariable = getMetadata(typeVariables[i]);
-      result.add(new JsTypeVariableMirror(typeVariable, this));
+      result.add(new JsTypeVariableMirror(typeVariable, this,
+                                          typeVariables[i]));
     }
     return _cachedTypeVariables = new UnmodifiableListView(result);
   }
 
   List<TypeMirror> get typeArguments => const <TypeMirror>[];
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get instanceMembers
+      => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  ClassMirror get mixin => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this.
+  Function operator [](Symbol name) => throw new UnimplementedError();
 }
 
 class JsVariableMirror extends JsDeclarationMirror implements VariableMirror {
@@ -1553,6 +1606,9 @@
     }
     receiver._storeField(_jsName, arg);
   }
+
+  // TODO(ahe): Implement this method.
+  bool get isConst => throw new UnimplementedError();
 }
 
 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
@@ -1607,11 +1663,16 @@
 
   String toString() => "ClosureMirror on '${Error.safeToString(reflectee)}'";
 
-  // TODO(ahe): Implement these.
+  // TODO(ahe): Implement this method.
   String get source => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
   InstanceMirror findInContext(Symbol name) {
     throw new UnsupportedError("ClosureMirror.findInContext not yet supported");
   }
+
+  // TODO(ahe): Implement this method.
+  Function operator [](Symbol name) => throw new UnimplementedError();
 }
 
 class JsMethodMirror extends JsDeclarationMirror implements MethodMirror {
@@ -1761,11 +1822,20 @@
   // TODO(ahe): Test this.
   bool get isRegularMethod => !isGetter && !isSetter && !isConstructor;
 
-  // TODO(ahe): Implement these.
+  // TODO(ahe): Implement this method.
   bool get isConstConstructor => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
   bool get isGenerativeConstructor => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
   bool get isRedirectingConstructor => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
   bool get isFactoryConstructor => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  String get source => throw new UnimplementedError();
 }
 
 class JsParameterMirror extends JsDeclarationMirror implements ParameterMirror {
@@ -1818,9 +1888,63 @@
   JsFunctionTypeMirror get value => referent;
 
   String get _prettyName => 'TypedefMirror';
+
+  // TODO(ahe): Implement this method.
+  List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  List<TypeMirror> get typeArguments => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  bool get isOriginalDeclaration => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  TypeMirror get originalDeclaration => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  DeclarationMirror get owner => throw new UnimplementedError();
+
+  // TODO(ahe): Implement this method.
+  List<InstanceMirror> get metadata => throw new UnimplementedError();
 }
 
-class JsFunctionTypeMirror implements FunctionTypeMirror {
+// TODO(ahe): Remove this class when API is updated.
+class BrokenClassMirror {
+  bool get hasReflectedType => throw new UnimplementedError();
+  Type get reflectedType => throw new UnimplementedError();
+  ClassMirror get superclass => throw new UnimplementedError();
+  List<ClassMirror> get superinterfaces => throw new UnimplementedError();
+  Map<Symbol, DeclarationMirror> get declarations
+      => throw new UnimplementedError();
+  Map<Symbol, MethodMirror> get instanceMembers
+      => throw new UnimplementedError();
+  Map<Symbol, MethodMirror> get staticMembers => throw new UnimplementedError();
+  ClassMirror get mixin => throw new UnimplementedError();
+  InstanceMirror newInstance(
+      Symbol constructorName,
+      List positionalArguments,
+      [Map<Symbol,dynamic> namedArguments]) => throw new UnimplementedError();
+  Function operator [](Symbol name) => throw new UnimplementedError();
+  InstanceMirror invoke(Symbol memberName,
+                        List positionalArguments,
+                        [Map<Symbol, dynamic> namedArguments])
+      => throw new UnimplementedError();
+  InstanceMirror getField(Symbol fieldName) => throw new UnimplementedError();
+  InstanceMirror setField(Symbol fieldName, Object value)
+      => throw new UnimplementedError();
+  List<TypeVariableMirror> get typeVariables => throw new UnimplementedError();
+  List<TypeMirror> get typeArguments => throw new UnimplementedError();
+  TypeMirror get originalDeclaration => throw new UnimplementedError();
+  Symbol get simpleName => throw new UnimplementedError();
+  Symbol get qualifiedName => throw new UnimplementedError();
+  bool get isPrivate => throw new UnimplementedError();
+  bool get isTopLevel => throw new UnimplementedError();
+  SourceLocation get location => throw new UnimplementedError();
+  List<InstanceMirror> get metadata => throw new UnimplementedError();
+}
+
+class JsFunctionTypeMirror extends BrokenClassMirror
+    implements FunctionTypeMirror {
   final _typeData;
   String _cachedToString;
   TypeMirror _cachedReturnType;
@@ -1920,6 +2044,9 @@
     }
     return _cachedToString = "$s'";
   }
+
+  // TODO(ahe): Implement this method.
+  MethodMirror get callMethod => throw new UnimplementedError();
 }
 
 int findTypeVariableIndex(List<TypeVariableMirror> typeVariables, String name) {
@@ -1952,7 +2079,7 @@
   } else if (ownerClass == null) {
     representation = runtimeTypeToString(type);
   } else if (ownerClass.isOriginalDeclaration) {
-    if (type is int) {
+    if (type is num) {
       // [type] represents a type variable so in the context of an original
       // declaration the corresponding type variable should be returned.
       TypeVariable typeVariable = getMetadata(type);
@@ -1965,11 +2092,24 @@
       representation = runtimeTypeToString(type);
     }
   } else {
-    String substituteTypeVariable(int index) {
+    getTypeArgument(int index) {
       TypeVariable typeVariable = getMetadata(index);
       int variableIndex =
           findTypeVariableIndex(ownerClass.typeVariables, typeVariable.name);
-      var typeArgument = ownerClass.typeArguments[variableIndex];
+      return ownerClass.typeArguments[variableIndex];
+    }
+
+    if (type is num) {
+      // [type] represents a type variable used as type argument for example
+      // the type argument of Bar: class Foo<T> extends Bar<T> {}
+      TypeMirror typeArgument = getTypeArgument(type);
+      if (typeArgument is JsTypeVariableMirror)
+        return typeArgument;
+    }
+    String substituteTypeVariable(int index) {
+      var typeArgument = getTypeArgument(index);
+      if (typeArgument is JsTypeVariableMirror)
+        return '${typeArgument._metadataIndex}';
       assert(typeArgument is JsClassMirror ||
              typeArgument is JsTypeBoundClassMirror);
       return typeArgument._mangledName;
@@ -1978,7 +2118,8 @@
         runtimeTypeToString(type, onTypeVariable: substituteTypeVariable);
   }
   if (representation != null) {
-    return reflectType(createRuntimeType(representation));
+    return reflectClassByMangledName(
+        getMangledTypeName(createRuntimeType(representation)));
   }
   return reflectClass(Function);
 }
diff --git a/sdk/lib/_internal/lib/js_number.dart b/sdk/lib/_internal/lib/js_number.dart
index b40aa4b..d389a93 100644
--- a/sdk/lib/_internal/lib/js_number.dart
+++ b/sdk/lib/_internal/lib/js_number.dart
@@ -58,7 +58,7 @@
   }
 
   num abs() => JS('num', r'Math.abs(#)', this);
-  
+
   static const int _MIN_INT32 = -0x80000000;
   static const int _MAX_INT32 = 0x7FFFFFFF;
 
diff --git a/sdk/lib/_internal/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
index 7def542..e3aabe3 100644
--- a/sdk/lib/_internal/lib/math_patch.dart
+++ b/sdk/lib/_internal/lib/math_patch.dart
@@ -42,17 +42,21 @@
   return JS('num', r'Math.pow(#, #)', x, exponent);
 }
 
+const int _POW2_32 = 0x100000000;
+
 patch class Random {
-  patch factory Random([int seed]) => const _Random();
+  patch factory Random([int seed]) =>
+      (seed == null) ? const _JSRandom() : new _Random(seed);
 }
 
-class _Random implements Random {
+class _JSRandom implements Random {
   // The Dart2JS implementation of Random doesn't use a seed.
-  const _Random();
+  const _JSRandom();
 
   int nextInt(int max) {
-    if (max < 0) throw new ArgumentError("negative max: $max");
-    if (max > 0xFFFFFFFF) max = 0xFFFFFFFF;
+    if (max <= 0 || max > _POW2_32) {
+      throw new RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+    }
     return JS("int", "(Math.random() * #) >>> 0", max);
   }
 
@@ -67,3 +71,97 @@
    */
   bool nextBool() => JS("bool", "Math.random() < 0.5");
 }
+
+
+class _Random implements Random {
+  // Constants used by the algorithm or masking.
+  static const double _POW2_53_D = 1.0 * (0x20000000000000);
+  static const double _POW2_27_D = 1.0 * (1 << 27);
+  static const int _MASK32 = 0xFFFFFFFF;
+
+  // State comprised of two unsigned 32 bit integers.
+  int _lo;
+  int _hi;
+
+  // Implements:
+  //   do {
+  //     seed = (seed + 0x5A17) & _Random._MASK_64;
+  //   } while (seed == 0);
+  //   _lo = seed & _MASK_32;
+  //   _hi = seed >> 32;
+  // and then does four _nextState calls to shuffle bits around.
+  _Random(int seed) {
+    // Works the same as the VM version for positive integers up to 2^53.
+    // For bigints, the VM always uses zero as seed. That is really a bug, and
+    // we don't simulate that.
+    seed += 0x5A17;
+    _lo = seed & _MASK32;
+    _hi = (seed - _lo) ~/ _POW2_32;
+    if (_hi == 0 && _lo == 0) {
+      _lo = 0x5A17;
+    }
+    _nextState();
+    _nextState();
+    _nextState();
+    _nextState();
+  }
+
+  // The algorithm used here is Multiply with Carry (MWC) with a Base b = 2^32.
+  // http://en.wikipedia.org/wiki/Multiply-with-carry
+  // The constant A (0xFFFFDA61) is selected from "Numerical Recipes 3rd
+  // Edition" p.348 B1.
+
+  // Implements:
+  //   var state = (A * _lo + _hi) & _MASK_64;
+  //   _lo = state & _MASK_32;
+  //   _hi = state >> 32;
+  void _nextState() {
+    // Simulate (0xFFFFDA61 * lo + hi) without overflowing 53 bits.
+    int tmpHi = 0xFFFF0000 * _lo;  // At most 48 bits of significant result.
+    int tmpHiLo = tmpHi & _MASK32;             // Get the lower 32 bits.
+    int tmpHiHi = tmpHi - tmpHiLo;            // And just the upper 32 bits.
+    int tmpLo = 0xDA61 * _lo;
+    int tmpLoLo = tmpLo & _MASK32;
+    int tmpLoHi = tmpLo - tmpLoLo;
+
+    int newLo = tmpLoLo + tmpHiLo + _hi;
+    _lo = newLo & _MASK32;
+    int newLoHi = newLo - _lo;
+    _hi = ((tmpLoHi + tmpHiHi + newLoHi) ~/ _POW2_32) & _MASK32;
+    assert(_lo < _POW2_32);
+    assert(_hi < _POW2_32);
+  }
+
+  int nextInt(int max) {
+    if (max <= 0 || max > _POW2_32) {
+      throw new RangeError("max must be in range 0 < max ≤ 2^32, was $max");
+    }
+    if ((max & (max - 1)) == 0) {
+      // Fast case for powers of two.
+      _nextState();
+      return _lo & (max - 1);
+    }
+
+    int rnd32;
+    int result;
+    do {
+      _nextState();
+      rnd32 = _lo;
+      result = rnd32.remainder(max); // % max;
+    } while ((rnd32 - result + max) >= _POW2_32);
+    return result;
+  }
+
+  double nextDouble() {
+    _nextState();
+    int bits26 = _lo & ((1 << 26) - 1);
+    _nextState();
+    int bits27 = _lo & ((1 << 27) - 1);
+    return (bits26 * _POW2_27_D + bits27) / _POW2_53_D;
+  }
+
+  bool nextBool() {
+    _nextState();
+    return (_lo & 1) == 0;
+  }
+}
diff --git a/sdk/lib/_internal/lib/native_helper.dart b/sdk/lib/_internal/lib/native_helper.dart
index bc77c48..6608481 100644
--- a/sdk/lib/_internal/lib/native_helper.dart
+++ b/sdk/lib/_internal/lib/native_helper.dart
@@ -442,7 +442,12 @@
 
 const _baseHooks = const JS_CONST(r'''
 function() {
-  function typeNameInChrome(obj) { return obj.constructor.name; }
+  function typeNameInChrome(o) {
+    var name = o.constructor.name;
+    if (name) return name;
+    var s = Object.prototype.toString.call(o);
+    return s.substring(8, s.length - 1);
+  }
   function getUnknownTag(object, tag) {
     // This code really belongs in [getUnknownTagGenericBrowser] but having it
     // here allows [getUnknownTag] to be tested on d8.
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index 06be67a..e19d9a0 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.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.
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:io';
 import 'dart:math' as math;
 
diff --git a/sdk/lib/_internal/pub/lib/src/barback.dart b/sdk/lib/_internal/pub/lib/src/barback.dart
index 08e5665..bd06b66 100644
--- a/sdk/lib/_internal/pub/lib/src/barback.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback.dart
@@ -17,9 +17,31 @@
 import 'log.dart' as log;
 import 'package_graph.dart';
 import 'utils.dart';
+import 'version.dart';
 
 export 'barback/sources.dart' show WatcherType;
 
+/// The currently supported version of the Barback package that this version of
+/// pub works with.
+///
+/// Pub implicitly constrains barback to this version or later patch versions.
+///
+/// Barback is in a unique position. Pub imports it, so a copy of Barback is
+/// physically included in the SDK. Packages also depend on Barback (from
+/// pub.dartlang.org) when they implement their own transformers. Pub's plug-in
+/// API dynamically loads transformers into their own isolate.
+///
+/// This includes a string literal of Dart code ([_TRANSFORMER_ISOLATE] in
+/// load_transformers.dart). That code imports "package:barback/barback.dart".
+/// This string is included in the SDK, but that import is resolved using the
+/// application’s version of Barback. That means it must tightly control which
+/// version of Barback the application is using so that it's one that pub
+/// supports.
+///
+/// Whenever a new non-patch version of barback is published, this *must* be
+/// incremented to synchronize with that.
+final supportedVersion = new Version(0, 10, 0);
+
 /// An identifier for a transformer and the configuration that will be passed to
 /// it.
 ///
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
index 604a881..c4b0597 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -4,7 +4,8 @@
 
 library pub.dart2js_transformer;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:analyzer/analyzer.dart';
@@ -84,7 +85,7 @@
         return null;
       }
 
-      var provider = new _BarbackInputProvider(_graph, transform);
+      var provider = new _BarbackCompilerProvider(_graph, transform);
 
       // Create a "path" to the entrypoint script. The entrypoint may not
       // actually be on disk, but this gives dart2js a root to resolve
@@ -100,22 +101,11 @@
       // Need to report compile errors to the user in an easily visible way.
       // Need to make sure paths in errors are mapped to the original source
       // path so they can understand them.
-      return dart.compile(entrypoint,
+      return dart.compile(entrypoint, provider,
           packageRoot: packageRoot,
-          minify: _mode == BarbackMode.RELEASE,
-          inputProvider: provider.readStringFromUri,
-          diagnosticHandler: provider.handleDiagnostic).then((js) {
-        var id = transform.primaryInput.id.changeExtension(".dart.js");
-        transform.addOutput(new Asset.fromString(id, js));
-
+          minify: _mode == BarbackMode.RELEASE).then((_) {
         stopwatch.stop();
-        transform.logger.info("Generated $id (${js.length} characters) in "
-            "${stopwatch.elapsed}");
-      }).catchError((error) {
-        // The compile failed and errors have been reported through the
-        // diagnostic handler, so just do nothing here.
-        if (error is dart.CompilerException) return;
-        throw error;
+        transform.logger.info("Took ${stopwatch.elapsed} to compile $id.");
       });
     }).whenComplete(() {
       completer.complete();
@@ -124,14 +114,13 @@
   }
 }
 
-/// Defines methods implementig [CompilerInputProvider] and [DiagnosticHandler]
-/// for dart2js to use to load files from Barback and report errors.
+/// Defines an interface for dart2js to communicate with barback and pub.
 ///
 /// Note that most of the implementation of diagnostic handling here was
 /// copied from [FormattingDiagnosticHandler] in dart2js. The primary
 /// difference is that it uses barback's logging code and, more importantly, it
 /// handles missing source files more gracefully.
-class _BarbackInputProvider {
+class _BarbackCompilerProvider implements dart.CompilerProvider {
   final PackageGraph _graph;
   final Transform _transform;
 
@@ -166,10 +155,10 @@
       compiler.Diagnostic.INFO.ordinal |
       compiler.Diagnostic.VERBOSE_INFO.ordinal;
 
-  _BarbackInputProvider(this._graph, this._transform);
+  _BarbackCompilerProvider(this._graph, this._transform);
 
   /// A [CompilerInputProvider] for dart2js.
-  Future<String> readStringFromUri(Uri resourceUri) {
+  Future<String> provideInput(Uri resourceUri) {
     // We only expect to get absolute "file:" URLs from dart2js.
     assert(resourceUri.isAbsolute);
     assert(resourceUri.scheme == "file");
@@ -182,6 +171,29 @@
     });
   }
 
+  /// A [CompilerOutputProvider] for dart2js.
+  EventSink<String> provideOutput(String name, String extension) {
+    // Dart2js uses an empty string for the name of the entrypoint library.
+    // We only expect to get output files associated with that right now. For
+    // other files, we'd need some logic to determine the right relative path
+    // for it.
+    assert(name == "");
+
+    var primaryId = _transform.primaryInput.id;
+    var id = new AssetId(primaryId.package, "${primaryId.path}.$extension");
+
+    // Make a sink that dart2js can write to.
+    var sink = new StreamController<String>();
+
+    // dart2js gives us strings, but stream assets expect byte lists.
+    var stream = UTF8.encoder.bind(sink.stream);
+
+    // And give it to barback as a stream it can read from.
+    _transform.addOutput(new Asset.fromStream(id, stream));
+
+    return sink;
+  }
+
   /// A [DiagnosticHandler] for dart2js, loosely based on
   /// [FormattingDiagnosticHandler].
   void handleDiagnostic(Uri uri, int begin, int end,
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
index 5418b91..1c2c38b 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_all_transformers.dart
@@ -21,7 +21,7 @@
 /// loaded, then adds the transformers to `server.barback`.
 ///
 /// Any [builtInTransformers] that are provided will automatically be added to
-/// the end of every package's cascade.
+/// the end of the root package's cascade.
 Future loadAllTransformers(BarbackServer server, PackageGraph graph,
     BarbackMode mode, Iterable<Transformer> builtInTransformers) {
   // In order to determine in what order we should load transformers, we need to
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 aff85de..7c4e2a1 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
@@ -61,7 +61,9 @@
 
   // 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) {
+  return mirrors.libraries[uri].declarations.values.map((declaration) {
+    if (declaration is! ClassMirror) return null;
+    var classMirror = declaration;
     if (classMirror.isPrivate) return null;
     if (isAbstract(classMirror)) return null;
     if (!classIsA(classMirror, transformerClass) &&
@@ -139,21 +141,15 @@
 }
 
 /// Returns the mirror for the root Object type.
-ClassMirror get objectMirror {
-  if (_objectMirror == null) {
-    _objectMirror = currentMirrorSystem()
-        .libraries[Uri.parse('dart:core')]
-        .classes[const Symbol('Object')];
-  }
-  return _objectMirror;
-}
-ClassMirror _objectMirror;
+ClassMirror get objectMirror => reflectClass(Object);
 
 // 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];
+  var candidate = classMirror.declarations[name];
+  if (candidate is MethodMirror && candidate.isConstructor) return candidate;
+  return null;
 }
 
 // TODO(nweiz): get rid of this when issue 12439 is fixed.
@@ -169,7 +165,7 @@
 
 // TODO(nweiz): get rid of this when issue 12826 is fixed.
 /// Returns whether or not [mirror] is an abstract class.
-bool isAbstract(ClassMirror mirror) => mirror.members.values
+bool isAbstract(ClassMirror mirror) => mirror.declarations.values
     .any((member) => member is MethodMirror && member.isAbstract);
 
 /// Converts [transformerOrGroup] into a serializable map.
@@ -299,26 +295,26 @@
   /// property.
   final String message;
 
-  /// The exception's stack trace, or `null` if no stack trace was available.
-  final Trace stackTrace;
+  /// The exception's stack chain, or `null` if no stack chain was available.
+  final Chain stackTrace;
 
-  /// Loads a [CrossIsolateException] from a map.
+  /// Loads a [CrossIsolateException] from a serialized representation.
   ///
   /// [error] should be the result of [CrossIsolateException.serialize].
   CrossIsolateException.deserialize(Map error)
       : type = error['type'],
         message = error['message'],
         stackTrace = error['stack'] == null ? null :
-            new Trace.parse(error['stack']);
+            new Chain.parse(error['stack']);
 
-  /// Serializes [error] to a map that can safely be passed across isolate
+  /// Serializes [error] to an object that can safely be passed across isolate
   /// boundaries.
   static Map serialize(error, [StackTrace stack]) {
     if (stack == null && error is Error) stack = error.stackTrace;
     return {
       'type': error.runtimeType.toString(),
       'message': getErrorMessage(error),
-      'stack': stack == null ? null : stack.toString()
+      'stack': stack == null ? null : new Chain.forTrace(stack).toString()
     };
   }
 
diff --git a/sdk/lib/_internal/pub/lib/src/barback/sources.dart b/sdk/lib/_internal/pub/lib/src/barback/sources.dart
index 8d2a79a..ece690b 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/sources.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/sources.dart
@@ -4,7 +4,7 @@
 
 library pub.barback.sources;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:barback/barback.dart';
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index ffd7fff..221bc45 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -5,7 +5,7 @@
 library pub.command;
 
 import 'dart:io';
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/build.dart b/sdk/lib/_internal/pub/lib/src/command/build.dart
index ef2e80b..1c9e37e 100644
--- a/sdk/lib/_internal/pub/lib/src/command/build.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/build.dart
@@ -4,7 +4,7 @@
 
 library pub.command.build;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:barback/barback.dart';
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache.dart b/sdk/lib/_internal/pub/lib/src/command/cache.dart
index 6479781..97e5dbe 100644
--- a/sdk/lib/_internal/pub/lib/src/command/cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/cache.dart
@@ -4,7 +4,7 @@
 
 library pub.command.cache;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:convert';
 
 import '../command.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/command/help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
index 9467721..f02841f 100644
--- a/sdk/lib/_internal/pub/lib/src/command/help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -4,7 +4,7 @@
 
 library pub.command.help;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import '../command.dart';
 import '../exit_codes.dart' as exit_codes;
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index 6a8b744..1cc95ac 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -4,7 +4,7 @@
 
 library pub.command.lish;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:http/http.dart' as http;
 
diff --git a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
index 15fb4da..31c6916 100644
--- a/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/list_package_dirs.dart
@@ -4,7 +4,7 @@
 
 library pub.command.list_package_dirs;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:convert';
 
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index 0d07f7b..f6df4ce 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -4,7 +4,7 @@
 
 library pub.command.serve;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:barback/barback.dart';
 
diff --git a/sdk/lib/_internal/pub/lib/src/command/uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
index d02472b..330efcc 100644
--- a/sdk/lib/_internal/pub/lib/src/command/uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -4,7 +4,7 @@
 
 library pub.command.uploader;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index fcd27b15..bf6cb2a 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -5,7 +5,7 @@
 /// A library for compiling Dart code and manipulating analyzer parse trees.
 library pub.dart;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:isolate';
 
 import 'package:analyzer/analyzer.dart';
@@ -21,21 +21,38 @@
 import 'sdk.dart' as sdk;
 import 'utils.dart';
 
-/// Returns [entrypoint] compiled to JavaScript (or to Dart if [toDart] is
-/// true).
+/// Interface to communicate with dart2js.
+///
+/// This is basically an amalgamation of dart2js's
+/// [compiler.CompilerInputProvider], [compiler.CompilerOutputProvider], and
+/// [compiler.DiagnosticHandler] function types so that we can provide them
+/// as a single unit.
+abstract class CompilerProvider {
+  /// Given [uri], responds with a future that completes to the contents of
+  /// the input file at that URI.
+  ///
+  /// The future can complete to a string or a list of bytes.
+  Future/*<String | List<int>>*/ provideInput(Uri uri);
+
+  /// Reports a diagnostic message from dart2js to the user.
+  void handleDiagnostic(Uri uri, int begin, int end, String message,
+                        compiler.Diagnostic kind);
+
+  /// Given a [name] (which will be "" for the entrypoint) and a file extension,
+  /// returns an [EventSink] that dart2js can write to to emit an output file.
+  EventSink<String> provideOutput(String name, String extension);
+}
+
+/// Compiles [entrypoint] to JavaScript (or to Dart if [toDart] is true) as
+/// well as any ancillary outputs dart2js creates.
+///
+/// Uses [provider] to communcate between dart2js and the caller. Returns a
+/// future that completes when compilation is done.
 ///
 /// By default, the package root is assumed to be adjacent to [entrypoint], but
 /// if [packageRoot] is passed that will be used instead.
-///
-/// If [inputProvider] and [diagnosticHandler] are omitted, uses a default
-/// [compiler.CompilerInputProvider] that loads directly from the filesystem.
-/// If either is provided, both must be.
-Future<String> compile(String entrypoint, {
-    String packageRoot,
-    bool toDart: false,
-    bool minify: true,
-    compiler.CompilerInputProvider inputProvider,
-    compiler.DiagnosticHandler diagnosticHandler}) {
+Future compile(String entrypoint, CompilerProvider provider, {
+    String packageRoot, bool toDart: false, bool minify: true}) {
   return new Future.sync(() {
     var options = <String>['--categories=Client,Server'];
     if (toDart) options.add('--output-type=dart');
@@ -45,27 +62,14 @@
       packageRoot = path.join(path.dirname(entrypoint), 'packages');
     }
 
-    // Must either pass both of these or neither.
-    if ((inputProvider == null) != (diagnosticHandler == null)) {
-      throw new ArgumentError("If either inputProvider or diagnosticHandler "
-          "is passed, then both must be.");
-    }
-
-    if (inputProvider == null) {
-      var provider = new CompilerSourceFileProvider();
-      inputProvider = provider.readStringFromUri;
-      diagnosticHandler = new FormattingDiagnosticHandler(provider)
-          .diagnosticHandler;
-    }
-
     return compiler.compile(
         path.toUri(entrypoint),
         path.toUri(appendSlash(_libPath)),
         path.toUri(appendSlash(packageRoot)),
-        inputProvider, diagnosticHandler, options).then((js) {
-      if (js == null) throw new CompilerException(entrypoint);
-      return js;
-    });
+        provider.provideInput,
+        provider.handleDiagnostic,
+        options,
+        provider.provideOutput);
   });
 }
 
@@ -150,24 +154,17 @@
   /// property.
   final String message;
 
-  /// The exception's stack trace, or `null` if no stack trace was available.
-  final Trace stackTrace;
+  /// The exception's stack chain, or `null` if no stack chain was available.
+  final Chain stackTrace;
 
   /// Loads a [CrossIsolateException] from a serialized representation.
   ///
   /// [error] should be the result of [CrossIsolateException.serialize].
-  factory CrossIsolateException.deserialize(Map error) {
-    var type = error['type'];
-    var message = error['message'];
-    var stackTrace = error['stack'] == null ? null :
-            new Trace.parse(error['stack']);
-    return new CrossIsolateException._(type, message, stackTrace);
-  }
-
-  /// Loads a [CrossIsolateException] from a serialized representation.
-  ///
-  /// [error] should be the result of [CrossIsolateException.serialize].
-  CrossIsolateException._(this.type, this.message, this.stackTrace);
+  CrossIsolateException.deserialize(Map error)
+      : type = error['type'],
+        message = error['message'],
+        stackTrace = error['stack'] == null ? null :
+            new Chain.parse(error['stack']);
 
   /// Serializes [error] to an object that can safely be passed across isolate
   /// boundaries.
@@ -176,15 +173,9 @@
     return {
       'type': error.runtimeType.toString(),
       'message': getErrorMessage(error),
-      'stack': stack == null ? null : stack.toString()
+      'stack': stack == null ? null : new Chain.forTrace(stack).toString()
     };
   }
 
   String toString() => "$message\n$stackTrace";
 }
-
-/// An exception thrown when dart2js generates compiler errors.
-class CompilerException extends ApplicationException {
-  CompilerException(String entrypoint)
-      : super('Failed to compile "$entrypoint".');
-}
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index 65cecc3..cf7e5d0 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -4,7 +4,7 @@
 
 library pub.entrypoint;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
@@ -14,9 +14,10 @@
 import 'log.dart' as log;
 import 'package.dart';
 import 'package_graph.dart';
+import 'solver/version_solver.dart';
 import 'system_cache.dart';
 import 'utils.dart';
-import 'solver/version_solver.dart';
+import 'version.dart';
 
 /// Pub operates over a directed graph of dependencies that starts at a root
 /// "entrypoint" package. This is typically the package where the current
@@ -146,9 +147,18 @@
       // Warn the user if any overrides were in effect.
       if (result.overrides.isNotEmpty) {
         var buffer = new StringBuffer();
-        buffer.write("Warning: You are overriding these dependencies:");
+        buffer.write("Warning: You are using these overridden dependencies:");
         for (var override in result.overrides) {
-          buffer.write("\n- $override");
+          var source = cache.sources[override.source];
+          buffer.write("\n- ${override.name}");
+          if (override.constraint != VersionConstraint.any) {
+            buffer.write(" version ${override.constraint}");
+          }
+          if (source != cache.sources.defaultSource) {
+            var description = source.formatDescription(root.dir,
+                override.description);
+            buffer.write(" (from ${override.source} $description)");
+          }
         }
         log.warning(buffer);
       }
@@ -178,10 +188,8 @@
   /// This will be `false` if there is no lockfile at all, or if the pubspec
   /// contains dependencies that are not in the lockfile or that don't match
   /// what's in there.
-  bool isLockFileUpToDate() {
-    var lockFile = loadLockFile();
-
-    checkDependency(package) {
+  bool _isLockFileUpToDate(LockFile lockFile) {
+    return root.immediateDependencies.every((package) {
       var locked = lockFile.packages[package.name];
       if (locked == null) return false;
 
@@ -189,36 +197,75 @@
       if (!package.constraint.allows(locked.version)) return false;
 
       var source = cache.sources[package.source];
-      if (!source.descriptionsEqual(package.description, locked.description)) {
-        return false;
-      }
+      if (source == null) return false;
 
-      return true;
-    }
+      return source.descriptionsEqual(package.description, locked.description);
+    });
+  }
 
-    if (!root.dependencies.every(checkDependency)) return false;
-    if (!root.devDependencies.every(checkDependency)) return false;
+  /// Determines whether all of the packages in the lockfile are already
+  /// installed and available.
+  ///
+  /// Note: this assumes [isLockFileUpToDate] has already been called and
+  /// returned `true`.
+  Future<bool> _arePackagesAvailable(LockFile lockFile) {
+    return Future.wait(lockFile.packages.values.map((package) {
+      var source = cache.sources[package.source];
 
-    return true;
+      // This should only be called after [_isLockFileUpToDate] has returned
+      // `true`, which ensures all of the sources in the lock file are valid.
+      assert(source != null);
+
+      // We only care about cached sources. Uncached sources aren't "installed".
+      // If one of those is missing, we want to show the user the file not
+      // found error later since installing won't accomplish anything.
+      if (!source.shouldCache) return new Future.value(true);
+
+      // Get the directory.
+      return source.getDirectory(package).then((dir) {
+        // See if the directory is there and looks like a package.
+        return dirExists(dir) || fileExists(path.join(dir, "pubspec.yaml"));
+      });
+    })).then((results) {
+      // Make sure they are all true.
+      return results.every((result) => result);
+    });
   }
 
   /// Gets dependencies if the lockfile is out of date with respect to the
   /// pubspec.
   Future ensureLockFileIsUpToDate() {
     return new Future.sync(() {
-      if (isLockFileUpToDate()) return null;
+      var lockFile = loadLockFile();
 
-      if (lockFileExists) {
-        log.message(
-            "Your pubspec has changed, so we need to update your lockfile:");
-      } else {
-        log.message(
-            "You don't have a lockfile, so we need to generate that:");
+      // If we don't have a current lock file, we definitely need to install.
+      if (!_isLockFileUpToDate(lockFile)) {
+        if (lockFileExists) {
+          log.message(
+              "Your pubspec has changed, so we need to update your lockfile:");
+        } else {
+          log.message(
+              "You don't have a lockfile, so we need to generate that:");
+        }
+
+        return false;
       }
 
-      return getDependencies().then((_) {
-        log.message("Got dependencies!");
+      // If we do have a lock file, we still need to make sure the packages
+      // are actually installed. The user may have just gotten a package that
+      // includes a lockfile.
+      return _arePackagesAvailable(lockFile).then((available) {
+        if (!available) {
+          log.message(
+              "You are missing some dependencies, so we need to install them "
+              "first:");
+        }
+
+        return available;
       });
+    }).then((upToDate) {
+      if (upToDate) return null;
+      return getDependencies().then((_) => log.message("Got dependencies!"));
     });
   }
 
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index ae0410f..52a284c 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -194,9 +194,9 @@
     return _completer.future.whenComplete(action);
   }
 
-  Future timeout(Duration timeLimit, [void onTimeout()]) {
+  Future timeout(Duration timeLimit, {void onTimeout()}) {
     _hasListeners = true;
-    return _completer.future.timeout(timeLimit, onTimeout);
+    return _completer.future.timeout(timeLimit, onTimeout: onTimeout);
   }
 
   Stream asStream() {
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index e692a47..e94e493 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -5,7 +5,7 @@
 /// Helper functionality for invoking Git.
 library pub.git;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'io.dart';
 import 'log.dart' as log;
 
diff --git a/sdk/lib/_internal/pub/lib/src/http.dart b/sdk/lib/_internal/pub/lib/src/http.dart
index 969042f..017b387 100644
--- a/sdk/lib/_internal/pub/lib/src/http.dart
+++ b/sdk/lib/_internal/pub/lib/src/http.dart
@@ -5,7 +5,7 @@
 /// Helpers for dealing with HTTP.
 library pub.http;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
 
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 90b06f9..533790c 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -5,7 +5,7 @@
 /// Helper functionality to make working with IO easier.
 library pub.io;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:collection';
 import 'dart:convert';
 import 'dart:io';
@@ -16,11 +16,20 @@
 
 import 'error_group.dart';
 import 'log.dart' as log;
+import 'pool.dart';
 import 'sdk.dart' as sdk;
 import 'utils.dart';
 
 export 'package:http/http.dart' show ByteStream;
 
+/// The pool used for restricting access to asynchronous operations that consume
+/// file descriptors.
+///
+/// The maximum number of allocated descriptors is based on empirical tests that
+/// indicate that beyond 32, additional file reads don't provide substantial
+/// additional throughput.
+final _descriptorPool = new Pool(32);
+
 /// Returns whether or not [entry] is nested somewhere within [dir]. This just
 /// performs a path comparison; it doesn't look at the actual filesystem.
 bool isBeneath(String entry, String dir) {
@@ -177,11 +186,21 @@
 /// Writes [stream] to a new file at path [file]. Will replace any file already
 /// at that path. Completes when the file is done being written.
 Future<String> createFileFromStream(Stream<List<int>> stream, String file) {
-  log.io("Creating $file from stream.");
+  // TODO(nweiz): remove extra logging when we figure out the windows bot issue.
+  log.io("Creating $file from stream (is the stream broadcast? "
+      "${stream.isBroadcast}).");
 
-  return stream.pipe(new File(file).openWrite()).then((_) {
-    log.fine("Created $file from stream.");
-    return file;
+  var pair = tee(stream);
+  pair.first.listen(
+      (data) => log.io("stream emitted ${data.length} bytes"),
+      onError: (error, st) => log.io("stream emitted $error\n$st"),
+      onDone: () => log.io("stream is done"));
+
+  return _descriptorPool.withResource(() {
+    return pair.last.pipe(new File(file).openWrite()).then((_) {
+      log.fine("Created $file from stream.");
+      return file;
+    });
   });
 }
 
@@ -207,27 +226,11 @@
   return dir;
 }
 
-/// Ensures that [dirPath] and all its parent directories exist. If they don't
+/// Ensures that [dir] and all its parent directories exist. If they don't
 /// exist, creates them.
-String ensureDir(String dirPath) {
-  log.fine("Ensuring directory $dirPath exists.");
-  var dir = new Directory(dirPath);
-  if (dirPath == '.' || dirExists(dirPath)) return dirPath;
-
-  ensureDir(path.dirname(dirPath));
-
-  try {
-    createDir(dirPath);
-  } on FileSystemException catch (ex) {
-    // Error 17 means the directory already exists (or 183 on Windows).
-    if (ex.osError.errorCode == 17 || ex.osError.errorCode == 183) {
-      log.fine("Got 'already exists' error when creating directory.");
-    } else {
-      throw ex;
-    }
-  }
-
-  return dirPath;
+String ensureDir(String dir) {
+  new Directory(dir).createSync(recursive: true);
+  return dir;
 }
 
 /// Creates a temp directory in [dir], whose name will be [prefix] with
@@ -486,21 +489,23 @@
 /// the inherited variables.
 Future<PubProcessResult> runProcess(String executable, List<String> args,
     {workingDir, Map<String, String> environment}) {
-  return _doProcess(Process.run, executable, args, workingDir, environment)
-      .then((result) {
-    // TODO(rnystrom): Remove this and change to returning one string.
-    List<String> toLines(String output) {
-      var lines = splitLines(output);
-      if (!lines.isEmpty && lines.last == "") lines.removeLast();
-      return lines;
-    }
+  return _descriptorPool.withResource(() {
+    return _doProcess(Process.run, executable, args, workingDir, environment)
+        .then((result) {
+      // TODO(rnystrom): Remove this and change to returning one string.
+      List<String> toLines(String output) {
+        var lines = splitLines(output);
+        if (!lines.isEmpty && lines.last == "") lines.removeLast();
+        return lines;
+      }
 
-    var pubResult = new PubProcessResult(toLines(result.stdout),
-                                toLines(result.stderr),
-                                result.exitCode);
+      var pubResult = new PubProcessResult(toLines(result.stdout),
+                                  toLines(result.stderr),
+                                  result.exitCode);
 
-    log.processResult(executable, pubResult);
-    return pubResult;
+      log.processResult(executable, pubResult);
+      return pubResult;
+    });
   });
 }
 
@@ -511,9 +516,16 @@
 /// [environment] is provided, that will be used to augment (not replace) the
 /// the inherited variables.
 Future<PubProcess> startProcess(String executable, List<String> args,
-    {workingDir, Map<String, String> environment}) =>
-  _doProcess(Process.start, executable, args, workingDir, environment)
-      .then((process) => new PubProcess(process));
+    {workingDir, Map<String, String> environment}) {
+  return _descriptorPool.request().then((resource) {
+    return _doProcess(Process.start, executable, args, workingDir, environment)
+        .then((ioProcess) {
+      var process = new PubProcess(ioProcess);
+      process.exitCode.whenComplete(resource.release);
+      return process;
+    });
+  });
+}
 
 /// A wrapper around [Process] that exposes `dart:async`-style APIs.
 class PubProcess {
@@ -630,10 +642,12 @@
 /// Note that timing out will not cancel the asynchronous operation behind
 /// [input].
 Future timeout(Future input, int milliseconds, String description) {
+  // TODO(nwiez): Replace this with [Future.timeout].
   var completer = new Completer();
-  var timer = new Timer(new Duration(milliseconds: milliseconds), () {
+  var duration = new Duration(milliseconds: milliseconds);
+  var timer = new Timer(duration, () {
     completer.completeError(new TimeoutException(
-        'Timed out while $description.'),
+        'Timed out while $description.', duration),
         new Trace.current());
   });
   input.then((value) {
@@ -750,79 +764,61 @@
 /// considered to be [baseDir], which defaults to the current working directory.
 /// Returns a [ByteStream] that will emit the contents of the archive.
 ByteStream createTarGz(List contents, {baseDir}) {
-  var buffer = new StringBuffer();
-  buffer.write('Creating .tag.gz stream containing:\n');
-  contents.forEach((file) => buffer.write('$file\n'));
-  log.fine(buffer.toString());
+  return new ByteStream(futureStream(new Future.sync(() {
+    var buffer = new StringBuffer();
+    buffer.write('Creating .tag.gz stream containing:\n');
+    contents.forEach((file) => buffer.write('$file\n'));
+    log.fine(buffer.toString());
 
-  var controller = new StreamController<List<int>>(sync: true);
+    var controller = new StreamController<List<int>>(sync: true);
 
-  if (baseDir == null) baseDir = path.current;
-  baseDir = path.absolute(baseDir);
-  contents = contents.map((entry) {
-    entry = path.absolute(entry);
-    if (!isBeneath(entry, baseDir)) {
-      throw new ArgumentError('Entry $entry is not inside $baseDir.');
+    if (baseDir == null) baseDir = path.current;
+    baseDir = path.absolute(baseDir);
+    contents = contents.map((entry) {
+      entry = path.absolute(entry);
+      if (!isBeneath(entry, baseDir)) {
+        throw new ArgumentError('Entry $entry is not inside $baseDir.');
+      }
+      return path.relative(entry, from: baseDir);
+    }).toList();
+
+    if (Platform.operatingSystem != "windows") {
+      var args = ["--create", "--gzip", "--directory", baseDir];
+      args.addAll(contents);
+      // TODO(nweiz): It's possible that enough command-line arguments will
+      // make the process choke, so at some point we should save the arguments
+      // to a file and pass them in via --files-from for tar and -i@filename
+      // for 7zip.
+      return startProcess("tar", args).then((process) => process.stdout);
     }
-    return path.relative(entry, from: baseDir);
-  }).toList();
 
-  if (Platform.operatingSystem != "windows") {
-    var args = ["--create", "--gzip", "--directory", baseDir];
-    args.addAll(contents);
-    // TODO(nweiz): It's possible that enough command-line arguments will make
-    // the process choke, so at some point we should save the arguments to a
-    // file and pass them in via --files-from for tar and -i@filename for 7zip.
-    startProcess("tar", args).then((process) {
-      store(process.stdout, controller);
-    }).catchError((e, stackTrace) {
-      // We don't have to worry about double-signaling here, since the store()
-      // above will only be reached if startProcess succeeds.
-      controller.addError(e, stackTrace);
-      controller.close();
+    // Don't use [withTempDir] here because we don't want to delete the temp
+    // directory until the returned stream has closed.
+    var tempDir = createSystemTempDir();
+    return new Future.sync(() {
+      // Create the tar file.
+      var tarFile = path.join(tempDir, "intermediate.tar");
+      var args = ["a", "-w$baseDir", tarFile];
+      args.addAll(contents.map((entry) => '-i!$entry'));
+
+      // We're passing 'baseDir' both as '-w' and setting it as the working
+      // directory explicitly here intentionally. The former ensures that the
+      // files added to the archive have the correct relative path in the
+      // archive. The latter enables relative paths in the "-i" args to be
+      // resolved.
+      return runProcess(pathTo7zip, args, workingDir: baseDir).then((_) {
+        // GZIP it. 7zip doesn't support doing both as a single operation.
+        // Send the output to stdout.
+        args = ["a", "unused", "-tgzip", "-so", tarFile];
+        return startProcess(pathTo7zip, args);
+      }).then((process) => process.stdout);
+    }).then((stream) {
+      return stream.transform(onDoneTransformer(() => deleteEntry(tempDir)));
+    }).catchError((e) {
+      deleteEntry(tempDir);
+      throw e;
     });
-    return new ByteStream(controller.stream);
-  }
-
-  withTempDir((tempDir) {
-    // Create the tar file.
-    var tarFile = path.join(tempDir, "intermediate.tar");
-    var args = ["a", "-w$baseDir", tarFile];
-    args.addAll(contents.map((entry) => '-i!$entry'));
-
-    // We're passing 'baseDir' both as '-w' and setting it as the working
-    // directory explicitly here intentionally. The former ensures that the
-    // files added to the archive have the correct relative path in the archive.
-    // The latter enables relative paths in the "-i" args to be resolved.
-    return runProcess(pathTo7zip, args, workingDir: baseDir).then((_) {
-      // GZIP it. 7zip doesn't support doing both as a single operation. Send
-      // the output to stdout.
-      args = ["a", "unused", "-tgzip", "-so", tarFile];
-      return startProcess(pathTo7zip, args);
-    }).then((process) {
-      // Ignore 7zip's stderr. 7zip writes its normal output to stderr. We don't
-      // want to show that since it's meaningless.
-      //
-      // TODO(rnystrom): Should log the stderr and display it if an actual error
-      // occurs.
-      return store(process.stdout, controller);
-    });
-  }).catchError((e, stackTrace) {
-    // We don't have to worry about double-signaling here, since the store()
-    // above will only be reached if everything succeeds.
-    controller.addError(e, stackTrace);
-    controller.close();
-  });
-  return new ByteStream(controller.stream);
-}
-
-/// Exception thrown when an operation times out.
-class TimeoutException implements Exception {
-  final String message;
-
-  const TimeoutException(this.message);
-
-  String toString() => message;
+  })));
 }
 
 /// Contains the results of invoking a [Process] and waiting for it to complete.
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index 83e5edc..10f220d 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -6,7 +6,7 @@
 library pub.log;
 
 import 'dart:io';
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'io.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/oauth2.dart b/sdk/lib/_internal/pub/lib/src/oauth2.dart
index 1bc1d9f..7146817 100644
--- a/sdk/lib/_internal/pub/lib/src/oauth2.dart
+++ b/sdk/lib/_internal/pub/lib/src/oauth2.dart
@@ -4,7 +4,7 @@
 
 library pub.oauth2;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:io';
 
 import 'package:oauth2/oauth2.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/package.dart b/sdk/lib/_internal/pub/lib/src/package.dart
index 6b31e56..e783221 100644
--- a/sdk/lib/_internal/pub/lib/src/package.dart
+++ b/sdk/lib/_internal/pub/lib/src/package.dart
@@ -40,6 +40,25 @@
   /// The dependency overrides this package specifies in its pubspec.
   List<PackageDep> get dependencyOverrides => pubspec.dependencyOverrides;
 
+  /// All immediate dependencies this package specifies.
+  ///
+  /// This includes regular, dev dependencies, and overrides.
+  Set<PackageDep> get immediateDependencies {
+    var deps = {};
+
+    addToMap(dep) {
+      deps[dep.name] = dep;
+    }
+
+    dependencies.forEach(addToMap);
+    devDependencies.forEach(addToMap);
+
+    // Make sure to add these last so they replace normal dependencies.
+    dependencyOverrides.forEach(addToMap);
+
+    return deps.values.toSet();
+  }
+
   /// Returns the path to the README file at the root of the entrypoint, or null
   /// if no README file is found. If multiple READMEs are found, this uses the
   /// same conventions as pub.dartlang.org for choosing the primary one: the
diff --git a/sdk/lib/_internal/pub/lib/src/pool.dart b/sdk/lib/_internal/pub/lib/src/pool.dart
new file mode 100644
index 0000000..24100ca
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/pool.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library barback.pool;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:stack_trace/stack_trace.dart';
+
+import 'utils.dart';
+
+// TODO(nweiz): put this somewhere that it can be shared between packages.
+/// Manages an abstract pool of resources with a limit on how many may be in use
+/// at once.
+///
+/// When a resource is needed, the user should call [request]. When the returned
+/// future completes with a [PoolResource], the resource may be allocated. Once
+/// the resource has been released, the user should call [PoolResource.release].
+/// The pool will ensure that only a certain number of [PoolResource]s may be
+/// allocated at once.
+class Pool {
+  /// Completers for requests beyond the first [_maxAllocatedResources].
+  ///
+  /// When an item is released, the next element of [_requestedResources] will
+  /// be completed.
+  final _requestedResources = new Queue<Completer<PoolResource>>();
+
+  /// The maximum number of resources that may be allocated at once.
+  final int _maxAllocatedResources;
+
+  /// The number of resources that are currently allocated.
+  int _allocatedResources = 0;
+
+  /// The timeout timer.
+  ///
+  /// If [_timeout] isn't null, this timer is set as soon as the resource limit
+  /// is reached and is reset every time an resource is released or a new
+  /// resource is requested. If it fires, that indicates that the caller became
+  /// deadlocked, likely due to files waiting for additional files to be read
+  /// before they could be closed.
+  Timer _timer;
+
+  /// The amount of time to wait before timing out the pending resources.
+  Duration _timeout;
+
+  /// Creates a new pool with the given limit on how many resources may be
+  /// allocated at once.
+  ///
+  /// If [timeout] is passed, then if that much time passes without any activity
+  /// all pending [request] futures will throw an exception. This is indented
+  /// to avoid deadlocks.
+  Pool(this._maxAllocatedResources, {Duration timeout})
+      : _timeout = timeout;
+
+  /// Request a [PoolResource].
+  ///
+  /// If the maximum number of resources is already allocated, this will delay
+  /// until one of them is released.
+  Future<PoolResource> request() {
+    if (_allocatedResources < _maxAllocatedResources) {
+      _allocatedResources++;
+      return new Future.value(new PoolResource._(this));
+    } else {
+      var completer = new Completer<PoolResource>();
+      _requestedResources.add(completer);
+      _resetTimer();
+      return completer.future;
+    }
+  }
+
+  /// Requests a resource for the duration of [callback], which may return a
+  /// Future.
+  ///
+  /// The return value of [callback] is piped to the returned Future.
+  Future withResource(callback()) {
+    return request().then((resource) =>
+        syncFuture(callback).whenComplete(resource.release));
+  }
+
+  /// If there are any pending requests, this will fire the oldest one.
+  void _onResourceReleased() {
+    if (_requestedResources.isEmpty) {
+      _allocatedResources--;
+      if (_timer != null) {
+        _timer.cancel();
+        _timer = null;
+      }
+      return;
+    }
+
+    _resetTimer();
+    var pending = _requestedResources.removeFirst();
+    pending.complete(new PoolResource._(this));
+  }
+
+  /// A resource has been requested, allocated, or released.
+  void _resetTimer() {
+    if (_timer != null) _timer.cancel();
+    if (_timeout == null) {
+      _timer = null;
+    } else {
+      _timer = new Timer(_timeout, _onTimeout);
+    }
+  }
+
+  /// Handles [_timer] timing out by causing all pending resource completers to
+  /// emit exceptions.
+  void _onTimeout() {
+    for (var completer in _requestedResources) {
+      completer.completeError("Pool deadlock: all resources have been "
+          "allocated for too long.", new Chain.current());
+    }
+    _requestedResources.clear();
+    _timer = null;
+  }
+}
+
+/// A member of a [Pool].
+///
+/// A [PoolResource] is a token that indicates that a resource is allocated.
+/// When the associated resource is released, the user should call [release].
+class PoolResource {
+  final Pool _pool;
+
+  /// Whether [this] has been released yet.
+  bool _released = false;
+
+  PoolResource._(this._pool);
+
+  /// Tells the parent [Pool] that the resource associated with this resource is
+  /// no longer allocated, and that a new [PoolResource] may be allocated.
+  void release() {
+    if (_released) {
+      throw new StateError("A PoolResource may only be released once.");
+    }
+    _released = true;
+    _pool._onResourceReleased();
+  }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
index c38295c..5ff0d08 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -36,6 +36,7 @@
 import 'dart:async';
 import 'dart:collection' show Queue;
 
+import '../barback.dart' as barback;
 import '../lock_file.dart';
 import '../log.dart' as log;
 import '../package.dart';
@@ -594,9 +595,24 @@
   /// Gets the combined [VersionConstraint] currently being placed on package
   /// [name].
   VersionConstraint _getConstraint(String name) {
-    return _getDependencies(name)
+    var constraint = _getDependencies(name)
         .map((dep) => dep.dep.constraint)
         .fold(VersionConstraint.any, (a, b) => a.intersect(b));
+
+    // If the package is barback, pub has an implicit version constraint on it
+    // since pub itself uses barback too. Note that we don't check for the
+    // hosted source here because we still want to do this even when people on
+    // the Dart team are on the bleeding edge and have a path dependency on the
+    // tip version of barback in the Dart repo.
+    if (name == "barback") {
+      var range = new VersionRange(
+          min: barback.supportedVersion, includeMin: true,
+          max: barback.supportedVersion.nextMinor, includeMax: false);
+      constraint = constraint.intersect(range);
+      _solver.logSolve('add implicit $range constraint to barback');
+    }
+
+    return constraint;
   }
 
   /// Gets the package [name] that's currently contained in the lockfile if it
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index 78b4450..a27a909 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -4,7 +4,7 @@
 
 library pub.source;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
@@ -228,12 +228,23 @@
   }
 
   /// When a [LockFile] is serialized, it uses this method to get the
-  /// [description] in the right format. [containingPath] references the
-  /// containing directory of the root package.
+  /// [description] in the right format.
+  ///
+  /// [containingPath] is the containing directory of the root package.
   dynamic serializeDescription(String containingPath, description) {
     return description;
   }
 
+  /// When a package [description] is shown to the user, this is called to
+  /// convert it into a human-friendly form.
+  ///
+  /// By default, it just converts the description to a string, but sources
+  /// may customize this. [containingPath] is the containing directory of the
+  /// root package.
+  String formatDescription(String containingPath, description) {
+    return description.toString();
+  }
+
   /// Returns whether or not [description1] describes the same package as
   /// [description2] for this source. This method should be light-weight. It
   /// doesn't need to validate that either package exists.
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index 7caf1dae..5a7f5e5 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -4,7 +4,7 @@
 
 library pub.source.git;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/source/hosted.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
index 295d2a5..1429e28 100644
--- a/sdk/lib/_internal/pub/lib/src/source/hosted.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -4,7 +4,7 @@
 
 library pub.source.hosted;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:io' as io;
 import "dart:convert";
 
@@ -30,10 +30,7 @@
   /// Gets the default URL for the package server for hosted dependencies.
   static String get defaultUrl {
     var url = io.Platform.environment["PUB_HOSTED_URL"];
-    if (url != null) {
-      log.fine("Got server $url from PUB_HOSTED_URL.");
-      return url;
-    }
+    if (url != null) return url;
 
     return "https://pub.dartlang.org";
   }
@@ -86,7 +83,7 @@
           "$server/packages/$package/versions/$version.tar.gz");
       log.io("Get package from $url.");
 
-      log.message('Downloading $id...');
+      log.message('Downloading ${id.name} ${id.version}...');
 
       // Download and extract the archive to a temp directory.
       var tempDir = systemCache.createTempDir();
diff --git a/sdk/lib/_internal/pub/lib/src/source/path.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
index 4d57069..76892e1 100644
--- a/sdk/lib/_internal/pub/lib/src/source/path.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -4,7 +4,7 @@
 
 library pub.source.path;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
@@ -113,6 +113,16 @@
     return description;
   }
 
+  /// Converts a parsed relative path to its original relative form.
+  String formatDescription(String containingPath, description) {
+    var sourcePath = description["path"];
+    if (description["relative"]) {
+      sourcePath = path.relative(description['path'], from: containingPath);
+    }
+
+    return sourcePath;
+  }
+
   /// Ensures that [description] is a valid path description and returns a
   /// normalized path to the package.
   ///
diff --git a/sdk/lib/_internal/pub/lib/src/system_cache.dart b/sdk/lib/_internal/pub/lib/src/system_cache.dart
index fe28502..bfc6cea 100644
--- a/sdk/lib/_internal/pub/lib/src/system_cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/system_cache.dart
@@ -4,7 +4,7 @@
 
 library pub.system_cache;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 711b224..222941a 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -77,10 +77,71 @@
   Future<List> get future => _completer.future;
 }
 
+/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
+/// Returns a buffered stream that will emit the same values as the stream
+/// returned by [future] once [future] completes.
+///
+/// If [future] completes to an error, the return value will emit that error and
+/// then close.
+///
+/// If [broadcast] is true, a broadcast stream is returned. This assumes that
+/// the stream returned by [future] will be a broadcast stream as well.
+/// [broadcast] defaults to false.
+Stream futureStream(Future<Stream> future, {bool broadcast: false}) {
+  var subscription;
+  var controller;
+
+  future = future.catchError((e, stackTrace) {
+    // Since [controller] is synchronous, it's likely that emitting an error
+    // will cause it to be cancelled before we call close.
+    if (controller != null) controller.addError(e, stackTrace);
+    if (controller != null) controller.close();
+    controller = null;
+  });
+
+  onListen() {
+    future.then((stream) {
+      if (controller == null) return;
+      subscription = stream.listen(
+          controller.add,
+          onError: controller.addError,
+          onDone: controller.close);
+    });
+  }
+
+  onCancel() {
+    if (subscription != null) subscription.cancel();
+    subscription = null;
+    controller = null;
+  }
+
+  if (broadcast) {
+    controller = new StreamController.broadcast(
+        sync: true, onListen: onListen, onCancel: onCancel);
+  } else {
+    controller = new StreamController(
+        sync: true, onListen: onListen, onCancel: onCancel);
+  }
+  return controller.stream;
+}
+
 /// Like [new Future], but avoids around issue 11911 by using [new Future.value]
 /// under the covers.
 Future newFuture(callback()) => new Future.value().then((_) => callback());
 
+/// Returns a [StreamTransformer] that will call [onDone] when the stream
+/// completes.
+///
+/// The stream will be passed through unchanged.
+StreamTransformer onDoneTransformer(void onDone()) {
+  return new StreamTransformer.fromHandlers(handleDone: (sink) {
+    onDone();
+    sink.close();
+  });
+}
+
 // TODO(rnystrom): Move into String?
 /// Pads [source] to [length] by adding spaces at the end.
 String padRight(String source, int length) {
diff --git a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
index ab98a18..d6abf6d 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.compiled_dartdoc;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 01ddf91..6039fc5 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.directory;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/lib.dart b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
index 622ee03..98bed28 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/lib.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.lib;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index 0948860..222d693 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.license;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/name.dart b/sdk/lib/_internal/pub/lib/src/validator/name.dart
index d62325d..1285fb1 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/name.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/name.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.name;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 
diff --git a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
index d14e674..9f30d65 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
@@ -4,7 +4,7 @@
 
 library pub.validator.utf8_readme;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:convert';
 
 import '../entrypoint.dart';
diff --git a/sdk/lib/_internal/pub/lib/src/version.dart b/sdk/lib/_internal/pub/lib/src/version.dart
index dcba9d4..e8738ff 100644
--- a/sdk/lib/_internal/pub/lib/src/version.dart
+++ b/sdk/lib/_internal/pub/lib/src/version.dart
@@ -64,7 +64,7 @@
 
   Version._(this.major, this.minor, this.patch, String preRelease, String build,
             this._text)
-      : preRelease = preRelease == null ? [] : _splitParts(preRelease), 
+      : preRelease = preRelease == null ? [] : _splitParts(preRelease),
         build = build == null ? [] : _splitParts(build) {
     if (major < 0) throw new ArgumentError(
         'Major version must be non-negative.');
@@ -154,6 +154,45 @@
   /// Whether or not this is a pre-release version.
   bool get isPreRelease => preRelease.isNotEmpty;
 
+  /// Gets the next major version number that follows this one.
+  ///
+  /// If this version is a pre-release of a major version release (i.e. the
+  /// minor and patch versions are zero), then it just strips the pre-release
+  /// suffix. Otherwise, it increments the major version and resets the minor
+  /// and patch.
+  Version get nextMajor {
+    if (isPreRelease && minor == 0 && patch == 0) {
+      return new Version(major, minor, patch);
+    }
+
+    return new Version(major + 1, 0, 0);
+  }
+
+  /// Gets the next minor version number that follows this one.
+  ///
+  /// If this version is a pre-release of a minor version release (i.e. the
+  /// patch version is zero), then it just strips the pre-release suffix.
+  /// Otherwise, it increments the minor version and resets the patch.
+  Version get nextMinor {
+    if (isPreRelease && patch == 0) {
+      return new Version(major, minor, patch);
+    }
+
+    return new Version(major, minor + 1, 0);
+  }
+
+  /// Gets the next patch version number that follows this one.
+  ///
+  /// If this version is a pre-release, then it just strips the pre-release
+  /// suffix. Otherwise, it increments the patch version.
+  Version get nextPatch {
+    if (isPreRelease) {
+      return new Version(major, minor, patch);
+    }
+
+    return new Version(major, minor, patch + 1);
+  }
+
   /// Tests if [other] matches this version exactly.
   bool allows(Version other) => this == other;
 
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index bf04ee6..3e49ab9 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -2,14 +2,13 @@
 # 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/serve/missing_file_test: Pass, Fail # Issue 12570
-
 test/hosted/version_negotiation_test: Pass, Timeout # Issue 14346
 
 test/upgrade/hosted/upgrade_removed_constraints_test: Pass, Fail # Issue 15349
 
 [ $runtime == vm && $system == windows ]
 test/serve/watch_removed_file_test: Pass, Fail # Issue 13026
+test/serve/missing_file_test: Pass, Fail # Issue 15431
 
 # Pub only runs on the VM, so just rule out all compilers.
 [ $compiler == dart2js || $compiler == dart2dart ]
diff --git a/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart b/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
index 725fac5..bc8319f 100644
--- a/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
+++ b/sdk/lib/_internal/pub/test/build/compiles_dart_entrypoints_to_js_test.dart
@@ -10,9 +10,6 @@
 main() {
   initConfig();
 
-  // TODO(rnystrom): Should also add tests that other transformers work
-  // (#14556).
-
   integration("compiles Dart entrypoints to JS", () {
     // Dart2js can take a long time to compile dart code, so we increase the
     // timeout to cope with that.
@@ -32,16 +29,20 @@
     // TODO(rnystrom): If we flesh out the command-line output, validate that
     // here.
     schedulePub(args: ["build"],
-        output: new RegExp(r"Built 2 files!"),
+        output: new RegExp(r"Built 6 files!"),
         exitCode: 0);
 
     d.dir(appPath, [
       d.dir('build', [
         d.matcherFile('file.dart.js', isNot(isEmpty)),
+        d.matcherFile('file.dart.precompiled.js', isNot(isEmpty)),
+        d.matcherFile('file.dart.js.map', isNot(isEmpty)),
         d.nothing('file.dart'),
         d.nothing('lib.dart'),
         d.dir('subdir', [
           d.matcherFile('subfile.dart.js', isNot(isEmpty)),
+          d.matcherFile('subfile.dart.precompiled.js', isNot(isEmpty)),
+          d.matcherFile('subfile.dart.js.map', isNot(isEmpty)),
           d.nothing('subfile.dart')
         ])
       ])
diff --git a/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart b/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
index a8e22f4..9bd4ff4 100644
--- a/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
+++ b/sdk/lib/_internal/pub/test/build/copies_browser_js_next_to_entrypoints_test.dart
@@ -62,12 +62,14 @@
     pubGet();
 
     schedulePub(args: ["build"],
-        output: new RegExp(r"Built 8 files!"),
+        output: new RegExp(r"Built 12 files!"),
         exitCode: 0);
 
     d.dir(appPath, [
       d.dir('build', [
         d.matcherFile('file.dart.js', isNot(isEmpty)),
+        d.matcherFile('file.dart.precompiled.js', isNot(isEmpty)),
+        d.matcherFile('file.dart.js.map', isNot(isEmpty)),
         d.dir('packages', [d.dir('browser', [
           d.file('dart.js', 'contents of dart.js'),
           d.file('interop.js', 'contents of interop.js')
@@ -77,7 +79,9 @@
             d.file('dart.js', 'contents of dart.js'),
             d.file('interop.js', 'contents of interop.js')
           ])]),
-          d.matcherFile('subfile.dart.js', isNot(isEmpty))
+          d.matcherFile('subfile.dart.js', isNot(isEmpty)),
+          d.matcherFile('subfile.dart.precompiled.js', isNot(isEmpty)),
+          d.matcherFile('subfile.dart.js.map', isNot(isEmpty))
         ])
       ])
     ]).validate();
diff --git a/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart b/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
index 0778ab1..fd8a7ac 100644
--- a/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
+++ b/sdk/lib/_internal/pub/test/build/dart2js_finds_imports_across_packages_test.dart
@@ -47,12 +47,14 @@
     ]).create();
 
     schedulePub(args: ["build"],
-        output: new RegExp(r"Built 1 file!"),
+        output: new RegExp(r"Built 3 files!"),
         exitCode: 0);
 
     d.dir(appPath, [
       d.dir('build', [
-        d.matcherFile('main.dart.js', isNot(isEmpty))
+        d.matcherFile('main.dart.js', isNot(isEmpty)),
+        d.matcherFile('main.dart.precompiled.js', isNot(isEmpty)),
+        d.matcherFile('main.dart.js.map', isNot(isEmpty))
       ])
     ]).validate();
   });
diff --git a/sdk/lib/_internal/pub/test/dependency_override_test.dart b/sdk/lib/_internal/pub/test/dependency_override_test.dart
index c930dd5..7e0f229 100644
--- a/sdk/lib/_internal/pub/test/dependency_override_test.dart
+++ b/sdk/lib/_internal/pub/test/dependency_override_test.dart
@@ -2,6 +2,8 @@
 // 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:path/path.dart' as path;
+
 import 'descriptor.dart' as d;
 import 'test_pub.dart';
 
@@ -86,27 +88,33 @@
     integration("warns about overridden dependencies", () {
       servePackages([
         packageMap("foo", "1.0.0"),
-        packageMap("bar", "1.0.0"),
-        packageMap("baz", "1.0.0")
+        packageMap("bar", "1.0.0")
       ]);
 
+      d.dir("baz", [
+        d.libDir("baz"),
+        d.libPubspec("baz", "0.0.1")
+      ]).create();
+
       d.dir(appPath, [
         d.pubspec({
           "name": "myapp",
           "dependency_overrides": {
             "foo": "any",
             "bar": "any",
-            "baz": "any"
+            "baz": {"path": "../baz"}
           }
         })
       ]).create();
 
+      var bazPath = path.join("..", "baz");
+
       schedulePub(args: [command.name], output: command.success, error:
           """
-          Warning: You are overriding these dependencies:
-          - bar any from hosted (bar)
-          - baz any from hosted (baz)
-          - foo any from hosted (foo)
+          Warning: You are using these overridden dependencies:
+          - bar
+          - baz (from path $bazPath)
+          - foo
           """);
     });
   });
diff --git a/sdk/lib/_internal/pub/test/descriptor/tar.dart b/sdk/lib/_internal/pub/test/descriptor/tar.dart
index f297abb..2a04a03 100644
--- a/sdk/lib/_internal/pub/test/descriptor/tar.dart
+++ b/sdk/lib/_internal/pub/test/descriptor/tar.dart
@@ -4,7 +4,7 @@
 
 library descriptor.tar;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 
 import 'package:path/path.dart' as path;
 import 'package:scheduled_test/scheduled_test.dart';
diff --git a/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
new file mode 100644
index 0000000..02f2363
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
@@ -0,0 +1,84 @@
+// 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 'descriptor.dart' as d;
+import 'test_pub.dart';
+import '../lib/src/barback.dart' as barback;
+import '../lib/src/version.dart';
+
+main() {
+  initConfig();
+
+  var previousVersion = new Version(
+      barback.supportedVersion.major, barback.supportedVersion.minor - 1, 0);
+
+  forBothPubGetAndUpgrade((command) {
+    integration("implicitly constrains barback to versions pub supports", () {
+      servePackages([
+        packageMap("barback", previousVersion.toString()),
+        packageMap("barback", barback.supportedVersion.toString()),
+        packageMap("barback", barback.supportedVersion.nextPatch.toString()),
+        packageMap("barback", barback.supportedVersion.nextMinor.toString())
+      ]);
+
+      d.appDir({
+        "barback": "any"
+      }).create();
+
+      pubCommand(command);
+
+      d.packagesDir({
+        "barback": barback.supportedVersion.nextPatch.toString()
+      }).validate();
+    });
+
+    integration("discovers transitive dependency on barback", () {
+      servePackages([
+        packageMap("barback", previousVersion.toString()),
+        packageMap("barback", barback.supportedVersion.toString()),
+        packageMap("barback", barback.supportedVersion.nextPatch.toString()),
+        packageMap("barback", barback.supportedVersion.nextMinor.toString())
+      ]);
+
+      d.dir("foo", [
+        d.libDir("foo", "foo 0.0.1"),
+        d.libPubspec("foo", "0.0.1", deps: {
+          "barback": "any"
+        })
+      ]).create();
+
+      d.appDir({
+        "foo": {"path": "../foo"}
+      }).create();
+
+      pubCommand(command);
+
+      d.packagesDir({
+        "barback": barback.supportedVersion.nextPatch.toString(),
+        "foo": "0.0.1"
+      }).validate();
+    });
+  });
+
+  integration("unlock if the locked version doesn't meet pub's constraint", () {
+    servePackages([
+      packageMap("barback", previousVersion.toString()),
+      packageMap("barback", barback.supportedVersion.toString())
+    ]);
+
+    d.appDir({"barback": "any"}).create();
+
+    // Hand-create a lockfile to pin barback to an older version.
+    createLockFile("myapp", hosted: {
+      "barback": previousVersion.toString()
+    });
+
+    pubGet();
+
+    // It should be upgraded.
+    d.packagesDir({
+      "barback": barback.supportedVersion.toString()
+    }).validate();
+  });
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/io_test.dart b/sdk/lib/_internal/pub/test/io_test.dart
index c4f5151..bc8d708 100644
--- a/sdk/lib/_internal/pub/test/io_test.dart
+++ b/sdk/lib/_internal/pub/test/io_test.dart
@@ -4,7 +4,7 @@
 
 library io_test;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:io';
 
 import 'package:path/path.dart' as path;
diff --git a/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_test.dart b/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_test.dart
new file mode 100644
index 0000000..5c4ed3a
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/does_not_get_first_if_locked_matches_override_test.dart
@@ -0,0 +1,41 @@
+// 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() {
+  // This is a regression test for https://dartbug.com/15180.
+  initConfig();
+  integration("does not get if the locked version matches the override", () {
+    d.dir("foo", [
+      d.libPubspec("foo", "0.0.1"),
+      d.libDir("foo")
+    ]).create();
+
+    // Get "foo" into the lock file.
+    d.dir(appPath, [
+      d.pubspec({
+        "name": "myapp",
+        "dependencies": {
+          "foo": "any"
+        },
+        "dependency_overrides": {
+          "foo": {
+            "path": "../foo",
+            "version": ">=0.0.1"
+          }
+        }
+      })
+    ]).create();
+    pubGet();
+
+    pubServe(shouldGetFirst: false);
+    requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_test.dart b/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_test.dart
new file mode 100644
index 0000000..8926faf
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/gets_first_if_dependency_is_not_installed_test.dart
@@ -0,0 +1,32 @@
+// 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:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../lib/src/io.dart';
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("gets first if a dependency is not installed", () {
+    servePackages([packageMap("foo", "1.2.3")]);
+
+    d.appDir({"foo": "1.2.3"}).create();
+
+    // Run pub to get a lock file.
+    pubGet();
+
+    // Delete the system cache so it isn't installed any more.
+    schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+    pubServe(shouldGetFirst: true, numDownloads: 1);
+    requestShouldSucceed("packages/foo/foo.dart", 'main() => "foo 1.2.3";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_test.dart b/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_test.dart
new file mode 100644
index 0000000..963eb09
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/gets_first_if_transitive_dependency_is_not_installed_test.dart
@@ -0,0 +1,41 @@
+// 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:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../lib/src/io.dart';
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+main() {
+  initConfig();
+  integration("gets first if a transitive dependency is not installed", () {
+    servePackages([packageMap("bar", "1.2.3")]);
+
+    d.dir("foo", [
+      d.libPubspec("foo", "1.0.0", deps: {
+        "bar": "any"
+      }),
+      d.libDir("foo")
+    ]).create();
+
+    d.appDir({
+      "foo": {"path": "../foo"}
+    }).create();
+
+    // Run pub to install everything.
+    pubGet();
+
+    // Delete the system cache so bar isn't installed any more.
+    schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+    pubServe(shouldGetFirst: true, numDownloads: 1);
+    requestShouldSucceed("packages/bar/bar.dart", 'main() => "bar 1.2.3";');
+    endPubServe();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/serve/utils.dart b/sdk/lib/_internal/pub/test/serve/utils.dart
index b57a984..43f1966 100644
--- a/sdk/lib/_internal/pub/test/serve/utils.dart
+++ b/sdk/lib/_internal/pub/test/serve/utils.dart
@@ -114,11 +114,13 @@
 /// Schedules starting the "pub serve" process and records its port number for
 /// future requests.
 ///
-/// If [shouldGetFirst] is `true`, validates that pub get is run first.
+/// If [shouldGetFirst] is `true`, validates that pub get is run first. In that
+/// case, you can also pass [numDownloads] to specify how many packages should
+/// be downloaded during the get.
 ///
 /// Returns the `pub serve` process.
 ScheduledProcess pubServe({bool shouldGetFirst: false,
-    Iterable<String> args}) {
+    Iterable<String> args, int numDownloads: 0}) {
   _pubServer = startPubServe(args);
 
   currentSchedule.onComplete.schedule(() {
@@ -133,9 +135,16 @@
     expect(_pubServer.nextLine(),
         completion(anyOf(
              startsWith("Your pubspec has changed"),
-             startsWith("You don't have a lockfile"))));
+             startsWith("You don't have a lockfile"),
+             startsWith("You are missing some dependencies"))));
     expect(_pubServer.nextLine(),
         completion(startsWith("Resolving dependencies...")));
+
+    for (var i = 0; i < numDownloads; i++) {
+      expect(_pubServer.nextLine(),
+          completion(startsWith("Downloading")));
+    }
+
     expect(_pubServer.nextLine(),
         completion(equals("Got dependencies!")));
   }
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index f398887..6eef80b 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -8,7 +8,7 @@
 /// tests like that.
 library test_pub;
 
-import 'dart:async' hide TimeoutException;
+import 'dart:async';
 import 'dart:convert';
 import 'dart:io';
 import 'dart:math';
@@ -32,6 +32,7 @@
 import '../lib/src/log.dart' as log;
 import '../lib/src/package.dart';
 import '../lib/src/safe_http_server.dart';
+import '../lib/src/source/hosted.dart';
 import '../lib/src/source/path.dart';
 import '../lib/src/source_registry.dart';
 import '../lib/src/system_cache.dart';
@@ -331,9 +332,12 @@
 
 void _integration(String description, void body(), [Function testFn]) {
   testFn(description, () {
+    // TODO(nweiz): remove this when issue 15362 is fixed.
+    currentSchedule.timeout *= 2;
+
     // The windows bots are very slow, so we increase the default timeout.
     if (Platform.operatingSystem == "windows") {
-      currentSchedule.timeout = new Duration(seconds: 10);
+      currentSchedule.timeout *= 2;
     }
 
     _sandboxDir = createSystemTempDir();
@@ -395,7 +399,7 @@
 
     if (outputJson == null) {
       _validateOutput(failures, 'stdout', output, results[0]);
-      return;
+      return null;
     }
 
     // Allow the expected JSON to contain futures.
@@ -608,12 +612,15 @@
 
 /// Create a lock file for [package] without running `pub get`.
 ///
-/// 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.
+/// [sandbox] is a list of path 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.
+///
+/// [hosted] is a list of package names to version strings for dependencies on
+/// hosted packages.
 void createLockFile(String package, {Iterable<String> sandbox,
-    Iterable<String> pkg}) {
+    Iterable<String> pkg, Map<String, Version> hosted}) {
   var dependencies = {};
 
   if (sandbox != null) {
@@ -650,8 +657,16 @@
     lockFile.packages[name] = id;
   });
 
-  var sources = new SourceRegistry()
-    ..register(new PathSource());
+  if (hosted != null) {
+    hosted.forEach((name, version) {
+      var id = new PackageId(name, 'hosted', new Version.parse(version), name);
+      lockFile.packages[name] = id;
+    });
+  }
+
+  var sources = new SourceRegistry();
+  sources.register(new HostedSource());
+  sources.register(new PathSource());
 
   d.file(path.join(package, 'pubspec.lock'),
       lockFile.serialize(null, sources)).create();
diff --git a/sdk/lib/_internal/pub/test/version_test.dart b/sdk/lib/_internal/pub/test/version_test.dart
index f2c8c2c..0e7452a 100644
--- a/sdk/lib/_internal/pub/test/version_test.dart
+++ b/sdk/lib/_internal/pub/test/version_test.dart
@@ -11,10 +11,13 @@
 main() {
   initConfig();
 
-  final v123 = new Version.parse('1.2.3');
   final v114 = new Version.parse('1.1.4');
+  final v123 = new Version.parse('1.2.3');
   final v124 = new Version.parse('1.2.4');
+  final v130 = new Version.parse('1.3.0');
+  final v140 = new Version.parse('1.4.0');
   final v200 = new Version.parse('2.0.0');
+  final v201 = new Version.parse('2.0.1');
   final v234 = new Version.parse('2.3.4');
   final v250 = new Version.parse('2.5.0');
   final v300 = new Version.parse('3.0.0');
@@ -118,6 +121,46 @@
       expect(v123.isEmpty, isFalse);
     });
 
+    test('nextMajor', () {
+      expect(v123.nextMajor, equals(v200));
+      expect(v114.nextMajor, equals(v200));
+      expect(v200.nextMajor, equals(v300));
+
+      // Ignores pre-release if not on a major version.
+      expect(new Version.parse('1.2.3-dev').nextMajor, equals(v200));
+
+      // Just removes it if on a major version.
+      expect(new Version.parse('2.0.0-dev').nextMajor, equals(v200));
+
+      // Strips build suffix.
+      expect(new Version.parse('1.2.3+patch').nextMajor, equals(v200));
+    });
+
+    test('nextMinor', () {
+      expect(v123.nextMinor, equals(v130));
+      expect(v130.nextMinor, equals(v140));
+
+      // Ignores pre-release if not on a minor version.
+      expect(new Version.parse('1.2.3-dev').nextMinor, equals(v130));
+
+      // Just removes it if on a minor version.
+      expect(new Version.parse('1.3.0-dev').nextMinor, equals(v130));
+
+      // Strips build suffix.
+      expect(new Version.parse('1.2.3+patch').nextMinor, equals(v130));
+    });
+
+    test('nextPatch', () {
+      expect(v123.nextPatch, equals(v124));
+      expect(v200.nextPatch, equals(v201));
+
+      // Just removes pre-release version if present.
+      expect(new Version.parse('1.2.4-dev').nextPatch, equals(v124));
+
+      // Strips build suffix.
+      expect(new Version.parse('1.2.3+patch').nextPatch, equals(v124));
+    });
+
     test('parse()', () {
       expect(new Version.parse('0.0.0'), equals(new Version(0, 0, 0)));
       expect(new Version.parse('12.34.56'), equals(new Version(12, 34, 56)));
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 7b77f8b..18ff654 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -130,6 +130,16 @@
   /** Whether there are currently one or more subscribers. */
   bool get hasListener => !_isEmpty;
 
+  /**
+   * Test whether the stream has exactly one listener.
+   *
+   * Assumes that the stream has a listener (not [_isEmpty]).
+   */
+  bool get _hasOneListener {
+    assert(!_isEmpty);
+    return identical(_next._next, this);
+  }
+
   /** Whether an event is being fired (sent to some, but not all, listeners). */
   bool get _isFiring => (_state & _STATE_FIRING) != 0;
 
@@ -321,6 +331,16 @@
 
   void _sendData(T data) {
     if (_isEmpty) return;
+    if (_hasOneListener) {
+      _state |= _BroadcastStreamController._STATE_FIRING;
+      _BroadcastSubscription subscription = _next;
+      subscription._add(data);
+      _state &= ~_BroadcastStreamController._STATE_FIRING;
+      if (_isEmpty) {
+        _callOnCancel();
+      }
+      return;
+    }
     _forEachListener((_BufferingStreamSubscription<T> subscription) {
       subscription._add(data);
     });
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index db26cee..f18cb1dd 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -422,19 +422,28 @@
    * If `onTimeout` is omitted, a timeout will cause the returned future to
    * complete with a [TimeoutException].
    */
-  Future timeout(Duration timeLimit, [void onTimeout()]);
+  Future timeout(Duration timeLimit, {void onTimeout()});
 }
 
 /**
  * Thrown when a scheduled timeout happens while waiting for an async result.
  */
 class TimeoutException implements Exception {
-  /** The duration that was exceeded without a result. */
+  /** Description of the cause of the timeout. */
+  final String message;
+  /** The duration that was exceeded. */
   final Duration duration;
 
-  TimeoutException(this.duration);
+  TimeoutException(this.message, [this.duration]);
 
-  String toString() => "Timeout after $duration";
+  String toString() {
+    if (message != null) {
+      if (duration != null) return "TimeoutException after $duration: $message";
+      return "TimeoutException: $message";
+    }
+    if (duration != null) return "TimeoutException after $duration";
+    return "TimeoutException";
+  }
 }
 
 /**
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index fb1280c..114614c 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -538,13 +538,14 @@
     }
   }
 
-  Future timeout(Duration timeLimit, [void onTimeout()]) {
+  Future timeout(Duration timeLimit, {void onTimeout()}) {
     if (_isComplete) return new _Future.immediate(this);
     _Future result = new _Future();
     Timer timer;
     if (onTimeout == null) {
       timer = new Timer(timeLimit, () {
-        result._completeError(new TimeoutException(timeLimit));
+        result._completeError(new TimeoutException("Future not completed",
+                                                   timeLimit));
       });
     } else {
       Zone zone = Zone.current;
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 58bb090..957ca2e 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -649,7 +649,7 @@
    * as [test] returns [:true:] for the event data. The stream is done
    * when either this stream is done, or when this stream first provides
    * a value that [test] doesn't accept.
-   * 
+   *
    * Stops listening to the stream after the accepted elements.
    *
    * Internally the method cancels its subscription after these elements. This
@@ -960,6 +960,88 @@
       cancelOnError: true);
     return future;
   }
+
+  /**
+   * Creates a new stream with the same events as this stream.
+   *
+   * Whenever more than [timeLimit] passes between two events from this stream,
+   * the [onTimeout] function is called.
+   *
+   * The countdown doesn't start until the returned stream is listened to.
+   * The countdown is reset every time an event is forwarded from this stream,
+   * or when the stream is paused and resumed.
+   *
+   * The [onTimeout] function is called with one argument: an
+   * [EventSink] that allows putting events into the returned stream.
+   * This `EventSink` is only valid during the call to `onTimeout`.
+   *
+   * If `onTimeout` is omitted, a timeout will just put a [TimeoutException]
+   * into the error channel of the returned stream.
+   */
+  Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) {
+    StreamSubscription<T> subscription;
+    _StreamController controller;
+    // The following variables are set on listen.
+    Timer timer;
+    Zone zone;
+    Function timeout;
+
+    void onData(T event) {
+      timer.cancel();
+      controller.add(event);
+      timer = zone.createTimer(timeLimit, timeout);
+    }
+    void onError(error, StackTrace stackTrace) {
+      timer.cancel();
+      controller.addError(error, stackTrace);
+      timer = zone.createTimer(timeLimit, timeout);
+    }
+    void onDone() {
+      timer.cancel();
+      controller.close();
+    }
+    controller = new _SyncStreamController(
+        () {
+          // This is the onListen callback for of controller.
+          // It runs in the same zone that the subscription was created in.
+          // Use that zone for creating timers and running the onTimeout
+          // callback.
+          zone = Zone.current;
+          if (onTimeout == null) {
+            timeout = () {
+              controller.addError(new TimeoutException("No stream event",
+                                                       timeLimit));
+            };
+          } else {
+            onTimeout = zone.registerUnaryCallback(onTimeout);
+            _ControllerEventSinkWrapper wrapper =
+                new _ControllerEventSinkWrapper(null);
+            timeout = () {
+              wrapper._sink = controller;  // Only valid during call.
+              zone.runUnaryGuarded(onTimeout, wrapper);
+              wrapper._sink = null;
+            };
+          }
+
+          subscription = this.listen(onData, onError: onError, onDone: onDone);
+          timer = zone.createTimer(timeLimit, timeout);
+        },
+        () {
+          timer.cancel();
+          subscription.pause();
+        },
+        () {
+          subscription.resume();
+          timer = zone.createTimer(timeLimit, timeout);
+        },
+        () {
+          timer.cancel();
+          Future result = subscription.cancel();
+          subscription = null;
+          return result;
+        });
+    return controller.stream;
+  }
 }
 
 /**
@@ -1282,3 +1364,18 @@
    */
   Future cancel();
 }
+
+
+/**
+ * Wraps an [_EventSink] so it exposes only the [EventSink] interface.
+ */
+class _ControllerEventSinkWrapper<T> implements EventSink<T> {
+  EventSink _sink;
+  _ControllerEventSinkWrapper(this._sink);
+
+  void add(T data) { _sink.add(data); }
+  void addError(error, [StackTrace stackTrace]) {
+    _sink.addError(error, stackTrace);
+  }
+  void close() { _sink.close(); }
+}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index fd104b0..3d7a2b3 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -144,17 +144,17 @@
 
   void onData(void handleData(T event)) {
     if (handleData == null) handleData = _nullDataHandler;
-    _onData = Zone.current.registerUnaryCallback(handleData);
+    _onData = _zone.registerUnaryCallback(handleData);
   }
 
   void onError(Function handleError) {
     if (handleError == null) handleError = _nullErrorHandler;
-    _onError = _registerErrorHandler(handleError, Zone.current);
+    _onError = _registerErrorHandler(handleError, _zone);
   }
 
   void onDone(void handleDone()) {
     if (handleDone == null) handleDone = _nullDoneHandler;
-    _onDone = Zone.current.registerCallback(handleDone);
+    _onDone = _zone.registerCallback(handleDone);
   }
 
   void pause([Future resumeSignal]) {
diff --git a/sdk/lib/core/annotations.dart b/sdk/lib/core/annotations.dart
index 68ba572..7b8462f 100644
--- a/sdk/lib/core/annotations.dart
+++ b/sdk/lib/core/annotations.dart
@@ -113,21 +113,30 @@
 }
 
 /**
- * The annotation `@proxy` marks a class as implementing members through
- * `noSuchMethod`.
+ * The annotation `@proxy` marks a class as implementing interfaces and members
+ * dynamically through `noSuchMethod`.
  *
- * The annotation applies to concrete classes. It is not inherited by
- * subclasses.
+ * The annotation applies to any class. It is inherited by subclasses from both
+ * superclass and interfaces.
  *
- * The marked class is considerer to implement any method, getter or setter
- * declared by its interface, even if there is no implementation in the
- * class. It will not generate the warning that is otherwise specified for an
- * unimplemented method in a non-abstract class.
+ * If a class is annotated with `@proxy`, or it implements any class that is
+ * annotated, then the class is considered to implement any interface and
+ * any member with regard to static type analysis. As such, it is not a static
+ * type warning to assign the object to a variable of any type, and it is not
+ * a static type warning to access any member of the object.
+ *
+ * This only applies to static type warnings. The runtime type of the object
+ * is unaffected. It is not considered to implement any special interfaces at
+ * runtime, so assigning it to a typed variable may fail in checked mode, and
+ * testing it with the `is` operator will not work for any type except the
+ * ones it actually implements.
  *
  * Tools that understand `@proxy` should tell the user if a class using `@proxy`
  * does not override the `noSuchMethod` declared on [Object].
  *
- * The intent of the `@proxy` notation is to avoid irrelevant warnings when
- * a class implements its interface through `noSuchMethod`.
+ * The intent of the `@proxy` notation is to create objects that implement a
+ * type (or multiple types) that are not known at compile time. If the types
+ * are known at compile time, a class can be written that implements these
+ * types.
  */
 const Object proxy = const _Proxy();
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 8b27a25..65f888e 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, Encoding;
+import "dart:convert" show UTF8, LATIN1, Encoding;
 import "dart:math" show Random;  // Used by List.shuffle.
 
 part "annotations.dart";
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index c6bb4f8..7e4bf45 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -124,9 +124,9 @@
  /**
    * Returns the remainder of the truncating division of `this` by [other].
    *
-   * The result `r` of this operation satisfies: `this == this ~/ other + r`.
-   * As a consequence the remainder `r` has the same sign as the dividend
-   * `this`.
+   * The result `r` of this operation satisfies:
+   * `this == (this ~/ other) * other + r`.
+   * As a consequence the remainder `r` has the same sign as the divider `this`.
    */
   num remainder(num other);
 
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index f645d2c..d2e2a7a 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -681,7 +681,7 @@
 
     while (index < length) {
 
-      // Normalize percent encoding to uppercase and don't encode
+      // Normalize percent-encoding to uppercase and don't encode
       // unreserved characters.
       if (component.codeUnitAt(index) == _PERCENT) {
         if (length < index + 2) {
@@ -1114,11 +1114,23 @@
    * for encoding the posting of a HTML form as a query string
    * component.
    *
-   * Spaces will be replaced with plus and all characters except for
-   * uppercase and lowercase letters, decimal digits and the
-   * characters `-._~`. Note that the set of characters encoded is a
-   * superset of what HTML 4.01 says as it refers to RFC 1738 for
-   * reserved characters.
+   * Encode the string [component] according to the HTML 4.01 rules
+   * for encoding the posting of a HTML form as a query string
+   * component.
+
+   * The component is first encoded to bytes using [encoding].
+   * The default is to use [UTF8] encoding, which preserves all
+   * the characters that don't need encoding.
+
+   * Then the resulting bytes are "percent-encoded". This transforms
+   * spaces (U+0020) to a plus sign ('+') and all bytes that are not
+   * the ASCII decimal digits, letters or one of '-._~' are written as
+   * a percent sign '%' followed by the two-digit hexadecimal
+   * representation of the byte.
+
+   * Note that the set of characters which are percent-encoded is a
+   * superset of what HTML 4.01 requires, since it refers to RFC 1738
+   * for reserved characters.
    *
    * When manually encoding query components remember to encode each
    * part separately before building the query string.
@@ -1130,8 +1142,10 @@
    * See http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2 for more
    * details.
    */
-  static String encodeQueryComponent(String component) {
-    return _uriEncode(_unreservedTable, component, spaceToPlus: true);
+  static String encodeQueryComponent(String component,
+                                     {Encoding encoding: UTF8}) {
+    return _uriEncode(
+        _unreservedTable, component, encoding: encoding, spaceToPlus: true);
   }
 
   /**
@@ -1353,6 +1367,7 @@
   }
 
   // Frequently used character codes.
+  static const int _SPACE = 0x20;
   static const int _DOUBLE_QUOTE = 0x22;
   static const int _PERCENT = 0x25;
   static const int _ASTERISK = 0x2A;
@@ -1382,36 +1397,29 @@
    * that appear in [canonicalTable], and returns the escaped string.
    */
   static String _uriEncode(List<int> canonicalTable,
-                    String text,
-                    {bool spaceToPlus: false}) {
-    byteToHex(int v) {
-      final String hex = '0123456789ABCDEF';
-      return '%${hex[v >> 4]}${hex[v & 0x0f]}';
+                           String text,
+                           {Encoding encoding: UTF8,
+                            bool spaceToPlus: false}) {
+    byteToHex(byte, buffer) {
+      const String hex = '0123456789ABCDEF';
+      buffer.writeCharCode(hex.codeUnitAt(byte >> 4));
+      buffer.writeCharCode(hex.codeUnitAt(byte & 0x0f));
     }
 
+    // Encode the string into bytes then generate an ASCII only string
+    // by percent encoding selected bytes.
     StringBuffer result = new StringBuffer();
-    for (int i = 0; i < text.length; i++) {
-      int ch = text.codeUnitAt(i);
-      if (ch < 128 && ((canonicalTable[ch >> 4] & (1 << (ch & 0x0f))) != 0)) {
-        result.write(text[i]);
-      } else if (spaceToPlus && text[i] == " ") {
-        result.write("+");
+    var bytes = encoding.encode(text);
+    for (int i = 0; i < bytes.length; i++) {
+      int byte = bytes[i];
+      if (byte < 128 &&
+          ((canonicalTable[byte >> 4] & (1 << (byte & 0x0f))) != 0)) {
+        result.writeCharCode(byte);
+      } else if (spaceToPlus && byte == _SPACE) {
+        result.writeCharCode(_PLUS);
       } else {
-        if (ch >= 0xD800 && ch < 0xDC00) {
-          // Low surrogate. We expect a next char high surrogate.
-          ++i;
-          int nextCh = text.length == i ? 0 : text.codeUnitAt(i);
-          if (nextCh >= 0xDC00 && nextCh < 0xE000) {
-            // convert the pair to a U+10000 codepoint
-            ch = 0x10000 + ((ch - 0xD800) << 10) + (nextCh - 0xDC00);
-          } else {
-            throw new ArgumentError('Malformed URI');
-          }
-        }
-        // TODO(floitsch): don't allocate a new string.
-        for (int codepoint in UTF8.encode(new String.fromCharCode(ch))) {
-          result.write(byteToHex(codepoint));
-        }
+        result.writeCharCode(_PERCENT);
+        byteToHex(byte, result);
       }
     }
     return result.toString();
@@ -1455,32 +1463,40 @@
   static String _uriDecode(String text,
                            {bool plusToSpace: false,
                             Encoding encoding: UTF8}) {
-    StringBuffer result = new StringBuffer();
-    List<int> codepoints = new List<int>();
-    for (int i = 0; i < text.length;) {
-      int ch = text.codeUnitAt(i);
-      if (ch != _PERCENT) {
-        if (plusToSpace && ch == _PLUS) {
-          result.write(" ");
-        } else {
-          result.writeCharCode(ch);
-        }
-        i++;
+    // First check whether there is any characters which need special handling.
+    bool simple = true;
+    for (int i = 0; i < text.length && simple; i++) {
+      var codeUnit = text.codeUnitAt(i);
+      simple = codeUnit != _PERCENT && codeUnit != _PLUS;
+    }
+    List<int> bytes;
+    if (simple) {
+      if (encoding == UTF8 || encoding == LATIN1) {
+        return text;
       } else {
-        codepoints.clear();
-        while (ch == _PERCENT) {
-          if (++i > text.length - 2) {
+        bytes = text.codeUnits;
+      }
+    } else {
+      bytes = new List();
+      for (int i = 0; i < text.length; i++) {
+        var codeUnit = text.codeUnitAt(i);
+        if (codeUnit > 127) {
+          throw new ArgumentError("Illegal percent encoding in URI");
+        }
+        if (codeUnit == _PERCENT) {
+          if (i + 3 > text.length) {
             throw new ArgumentError('Truncated URI');
           }
-          codepoints.add(_hexCharPairToByte(text, i));
+          bytes.add(_hexCharPairToByte(text, i + 1));
           i += 2;
-          if (i == text.length) break;
-          ch = text.codeUnitAt(i);
+        } else if (plusToSpace && codeUnit == _PLUS) {
+          bytes.add(_SPACE);
+        } else {
+          bytes.add(codeUnit);
         }
-        result.write(encoding.decode(codepoints));
       }
     }
-    return result.toString();
+    return encoding.decode(bytes);
   }
 
   static bool _isAlphabeticCharacter(int codeUnit)
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 944d6e6..a5c5443 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -34418,10 +34418,8 @@
 
   var options = JS('=Object', '{prototype: #}', proto);
 
-  if (baseClassName != 'HTMLElement') {
-    if (extendsTagName != null) {
-      JS('=Object', '#.extends = #', options, extendsTagName);
-    }
+  if (extendsTagName != null) {
+    JS('=Object', '#.extends = #', options, extendsTagName);
   }
 
   JS('void', '#.register(#, #)', document, tag, options);
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 18735d0..29a417a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -27945,13 +27945,13 @@
     if ((blob_OR_source_OR_stream is Blob || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_1(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_2(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is MediaSource || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_3(blob_OR_source_OR_stream);
     }
-    if ((blob_OR_source_OR_stream is MediaStream || blob_OR_source_OR_stream == null)) {
+    if ((blob_OR_source_OR_stream is _WebKitMediaSource || blob_OR_source_OR_stream == null)) {
       return _createObjectURL_4(blob_OR_source_OR_stream);
     }
     throw new ArgumentError("Incorrect number or type of arguments");
@@ -36918,7 +36918,7 @@
       throw new UnsupportedError("Invalid custom element from $libName.");
     }
     var className = MirrorSystem.getName(cls.simpleName);
-    var createdConstructor = cls.constructors[new Symbol('$className.created')];
+    var createdConstructor = cls.declarations[new Symbol('$className.created')];
     if (createdConstructor == null ||
         createdConstructor is! MethodMirror ||
         !createdConstructor.isConstructor) {
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 896ef26..0a8d230 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -370,9 +370,9 @@
    */
   Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL,
                                  bool recursive: false})
-     => new _FileSystemWatcher(_trimTrailingPathSeparators(path),
-                               events,
-                               recursive).stream;
+     => _FileSystemWatcher.watch(_trimTrailingPathSeparators(path),
+                                 events,
+                                 recursive);
 
   Future<FileSystemEntity> _delete({bool recursive: false});
   void _deleteSync({bool recursive: false});
@@ -741,9 +741,8 @@
 }
 
 
-abstract class _FileSystemWatcher {
-  external factory _FileSystemWatcher(String path, int events, bool recursive);
+class _FileSystemWatcher {
+  external static Stream<FileSystemEvent> watch(
+      String path, int events, bool recursive);
   external static bool get isSupported;
-
-  Stream<FileSystemEvent> get stream;
 }
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 7a4f917..3c0f0fe 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -14,16 +14,37 @@
 }
 
 /**
- * Exit the Dart VM process immediately with the given [status] code.
+ * Exit the Dart VM process immediately with the given exit code.
  *
  * This does not wait for any asynchronous operations to terminate. Using
  * [exit] is therefore very likely to lose data.
+ *
+ * The handling of exit codes is platform specific.
+ *
+ * On Linux and Mac OS an exit code for normal termination will always
+ * be in the range [0..255]. If an exit code outside this range is
+ * set the actual exit code will be the lower 8 bits masked off and
+ * treated as an unsigned value. E.g. using an exit code of -1 will
+ * result in an actual exit code of 255 being reported.
+ *
+ * On Windows the exit code can be set to any 32-bit value. However
+ * some of these values are reserved for reporting system errors like
+ * crashes.
+ *
+ * Besides this the Dart executable itself uses an exit code of `254`
+ * for reporting compile time errors and an exit code of `255` for
+ * reporting runtime error (unhandled exception).
+ *
+ * Due to these facts it is recommended to only use exit codes in the
+ * range [0..127] for communicating the result of running a Dart
+ * program to the surrounding environment. This will avoid any
+ * cross-platform issues.
  */
-void exit(int status) {
-  if (status is !int) {
-    throw new ArgumentError("exit: int status expected");
+void exit(int code) {
+  if (code is !int) {
+    throw new ArgumentError("Integer value for exit code expected");
   }
-  _ProcessUtils._exit(status);
+  _ProcessUtils._exit(code);
 }
 
 /**
@@ -32,12 +53,15 @@
  * The exit code is global for the Dart VM and the last assignment to
  * exitCode from any isolate determines the exit code of the Dart VM
  * on normal termination.
+ *
+ * See [exit] for more information on how to chose a value for the
+ * exit code.
  */
-set exitCode(int status) {
-  if (status is !int) {
-    throw new ArgumentError("setExitCode: int status expected");
+set exitCode(int code) {
+  if (code is !int) {
+    throw new ArgumentError("Integer value for exit code expected");
   }
-  _ProcessUtils._setExitCode(status);
+  _ProcessUtils._setExitCode(code);
 }
 
 /**
@@ -185,25 +209,16 @@
 
   /**
    * Returns the standard output stream of the process as a [:Stream:].
-   *
-   * Throws an [UnsupportedError] if the process is
-   * non-interactive.
    */
   Stream<List<int>> get stdout;
 
   /**
    * Returns the standard error stream of the process as a [:Stream:].
-   *
-   * Throws an [UnsupportedError] if the process is
-   * non-interactive.
    */
   Stream<List<int>> get stderr;
 
   /**
    * Returns the standard input stream of the process as an [IOSink].
-   *
-   * Throws an [UnsupportedError] if the process is
-   * non-interactive.
    */
   IOSink get stdin;
 
@@ -216,8 +231,24 @@
    * Returns a [:Future:] which completes with the exit code of the process
    * when the process completes.
    *
-   * Throws an [UnsupportedError] if the process is
-   * non-interactive.
+   * The handling of exit codes is platform specific.
+   *
+   * On Linux and Mac a normal exit code will be a positive value in
+   * the range [0..255]. If the process was terminated due to a signal
+   * the exit code will be a negative value in the range [-255..0[,
+   * where the absolute value of the exit code is the signal
+   * number. For example, if a process crashes due to a segmentation
+   * violation the exit code will be -11, as the signal SIGSEGV has the
+   * number 11.
+   *
+   * On Windows a process can report any 32-bit value as an exit
+   * code. When returning the exit code this exit code is turned into
+   * a signed value. Some special values are used to report
+   * termination due to some system event. E.g. if a process crashes
+   * due to an access violation the 32-bit exit code is `0xc0000005`,
+   * which will be returned as the negative number `-1073741819`. To
+   * get the original 32-bit value use `(0x100000000 + exitCode) &
+   * 0xffffffff`.
    */
   Future<int> exitCode;
 
@@ -245,6 +276,9 @@
 abstract class ProcessResult {
   /**
    * Exit code for the process.
+   *
+   * See [Process.exitCode] for more information in the exit code
+   * value.
    */
   int get exitCode;
 
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index f1ceec5..2f78958 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -145,6 +145,11 @@
   String get name;
 
   /**
+   * Get the index of the [NetworkInterface].
+   */
+  String get index;
+
+  /**
    * Get a list of [InternetAddress]s currently bound to this
    * [NetworkInterface].
    */
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 1d7b277..f03b618 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -29,7 +29,10 @@
     }
     timer._milliSeconds = repeating ? milliSeconds : -1;
     timer._addTimerToList();
-    timer._notifyEventHandler();
+    if (identical(timer, _timers.first)) {
+      // The new timer is the first in queue. Update event handler.
+      timer._notifyEventHandler();
+    }
     return timer;
   }
 
@@ -72,9 +75,8 @@
     _wakeupTime += _milliSeconds;
   }
 
-  // Adds a timer to the timer list and resets the native timer if it is the
-  // earliest timer in the list. Timers with the same wakeup time are enqueued
-  // in order and notified in FIFO order.
+  // Adds a timer to the timer list. Timers with the same wakeup time are
+  // enqueued in order and notified in FIFO order.
   void _addTimerToList() {
     _Timer entry = _timers.isEmpty ? null : _timers.first;
     while (entry != null) {
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index ce9c8e7..28d7174 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -1104,7 +1104,7 @@
 }
 
 /**
- * EXPERIMENTAL API: Description of how "dart:mirrors" is used.
+ * Annotation describing how "dart:mirrors" is used (EXPERIMENTAL).
  *
  * When used as metadata on an import of "dart:mirrors" in library *L*, this
  * class describes how "dart:mirrors" is used by library *L* unless overridden.
@@ -1124,7 +1124,7 @@
  *
  *     class Foo {
  *       noSuchMethod(Invocation invocation) {
- *         print(Mirrors.getName(invocation.memberName));
+ *         print(MirrorSystem.getName(invocation.memberName));
  *       }
  *     }
  *
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 6a4e0f1..83044ce 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -456,16 +456,78 @@
       JS('ByteData', 'new DataView(#, #, #)', arg1, arg2, arg3);
 }
 
+
+// TODO(sra): Move this type to a public name in a private library so that other
+// platform libraries like dart:html and dart:webaudio can tell a native array
+// from a list that implements the implicit interface.
+abstract class _NativeTypedArray extends TypedData
+    implements JavaScriptIndexingBehavior {
+  int get length => JS("JSUInt32", '#.length', this);
+
+  bool _setRangeFast(int start, int end,
+      _NativeTypedArray source, int skipCount) {
+    int targetLength = this.length;
+    _checkIndex(start, targetLength + 1);
+    _checkIndex(end, targetLength + 1);
+    if (start > end) throw new RangeError.range(start, 0, end);
+    int count = end - start;
+
+    if (skipCount < 0) throw new ArgumentError(skipCount);
+
+    int sourceLength = source.length;
+    if (sourceLength - skipCount < count)  {
+      throw new StateError("Not enough elements");
+    }
+
+    if (skipCount != 0 || sourceLength != count) {
+      // Create a view of the exact subrange that is copied from the source.
+      source = JS('', '#.subarray(#, #)',
+          source, skipCount, skipCount + count);
+    }
+    JS('void', '#.set(#, #)', this, source, start);
+  }
+}
+
+// TODO(sra): Move to private library, like [_NativeTypedArray].
+abstract class _NativeTypedArrayOfDouble
+    extends _NativeTypedArray
+        with ListMixin<double>, FixedLengthListMixin<double>
+    implements List<double> {
+
+  void setRange(int start, int end, Iterable<double> iterable,
+                [int skipCount = 0]) {
+    if (iterable is _NativeTypedArrayOfDouble) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+// TODO(sra): Move to private library, like [_NativeTypedArray].
+abstract class _NativeTypedArrayOfInt
+    extends _NativeTypedArray
+        with ListMixin<int>, FixedLengthListMixin<int>
+    implements List<int> {
+
+  void setRange(int start, int end, Iterable<int> iterable,
+                [int skipCount = 0]) {
+    if (iterable is _NativeTypedArrayOfInt) {
+      _setRangeFast(start, end, iterable, skipCount);
+      return;
+    }
+    super.setRange(start, end, iterable, skipCount);
+  }
+}
+
+
 /**
  * A fixed-length list of IEEE 754 single-precision binary floating-point
  * numbers  that is viewable as a [TypedData]. For long lists, this
  * implementation can be considerably more space- and time-efficient than
  * the default [List] implementation.
  */
-class Float32List
-    extends TypedData with ListMixin<double>, FixedLengthListMixin<double>
-    implements JavaScriptIndexingBehavior, List<double>
-    native "Float32Array" {
+class Float32List extends _NativeTypedArrayOfDouble native "Float32Array" {
   /**
    * Creates a [Float32List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -502,8 +564,6 @@
 
   static const int BYTES_PER_ELEMENT = 4;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   num operator[](int index) {
     _checkIndex(index, length);
     return JS("num", "#[#]", this, index);
@@ -537,10 +597,7 @@
  * implementation can be considerably more space- and time-efficient than
  * the default [List] implementation.
  */
-class Float64List
-    extends TypedData with ListMixin<double>, FixedLengthListMixin<double>
-    implements JavaScriptIndexingBehavior, List<double>
-    native "Float64Array" {
+class Float64List extends _NativeTypedArrayOfDouble native "Float64Array" {
   /**
    * Creates a [Float64List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -577,8 +634,6 @@
 
   static const int BYTES_PER_ELEMENT = 8;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   num operator[](int index) {
     _checkIndex(index, length);
     return JS("num", "#[#]", this, index);
@@ -614,10 +669,7 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Int16List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
-    native "Int16Array" {
+class Int16List extends _NativeTypedArrayOfInt native "Int16Array" {
   /**
    * Creates an [Int16List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -653,8 +705,6 @@
 
   static const int BYTES_PER_ELEMENT = 2;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   int operator[](int index) {
     _checkIndex(index, length);
     return JS("int", "#[#]", this, index);
@@ -687,10 +737,7 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Int32List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
-    native "Int32Array" {
+class Int32List extends _NativeTypedArrayOfInt native "Int32Array" {
   /**
    * Creates an [Int32List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -726,8 +773,6 @@
 
   static const int BYTES_PER_ELEMENT = 4;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   int operator[](int index) {
     _checkIndex(index, length);
     return JS("int", "#[#]", this, index);
@@ -760,10 +805,7 @@
  * For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Int8List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
-    native "Int8Array" {
+class Int8List extends _NativeTypedArrayOfInt native "Int8Array" {
   /**
    * Creates an [Int8List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -796,8 +838,6 @@
 
   static const int BYTES_PER_ELEMENT = 1;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   int operator[](int index) {
     _checkIndex(index, length);
     return JS("int", "#[#]", this, index);
@@ -830,10 +870,7 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Uint16List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
-    native "Uint16Array" {
+class Uint16List extends _NativeTypedArrayOfInt native "Uint16Array" {
   /**
    * Creates a [Uint16List] of the specified length (in elements), all
    * of whose elements are initially zero.
@@ -870,8 +907,6 @@
 
   static const int BYTES_PER_ELEMENT = 2;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   int operator[](int index) {
     _checkIndex(index, length);
     return JS("JSUInt31", "#[#]", this, index);
@@ -904,10 +939,7 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Uint32List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
-    native "Uint32Array" {
+class Uint32List extends _NativeTypedArrayOfInt native "Uint32Array" {
   /**
    * Creates a [Uint32List] of the specified length (in elements), all
    * of whose elements are initially zero.
@@ -944,8 +976,6 @@
 
   static const int BYTES_PER_ELEMENT = 4;
 
-  int get length => JS("JSUInt32", '#.length', this);
-
   int operator[](int index) {
     _checkIndex(index, length);
     return JS("JSUInt32", "#[#]", this, index);
@@ -979,8 +1009,7 @@
  * more space- and time-efficient than the default [List] implementation.
  * Indexed store clamps the value to range 0..0xFF.
  */
-class Uint8ClampedList extends TypedData with ListMixin<int>,
-    FixedLengthListMixin<int> implements JavaScriptIndexingBehavior, List<int>
+class Uint8ClampedList extends _NativeTypedArrayOfInt
     native "Uint8ClampedArray,CanvasPixelArray" {
   /**
    * Creates a [Uint8ClampedList] of the specified length (in elements), all of
@@ -1050,9 +1079,7 @@
  * For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Uint8List
-    extends TypedData with ListMixin<int>, FixedLengthListMixin<int>
-    implements JavaScriptIndexingBehavior, List<int>
+class Uint8List extends _NativeTypedArrayOfInt
     // 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
@@ -1125,7 +1152,8 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Int64List extends TypedData implements JavaScriptIndexingBehavior, List<int> {
+abstract class Int64List extends TypedData
+                         implements JavaScriptIndexingBehavior, List<int> {
   /**
    * Creates an [Int64List] of the specified length (in elements), all of
    * whose elements are initially zero.
@@ -1170,7 +1198,8 @@
  * [TypedData]. For long lists, this implementation can be considerably
  * more space- and time-efficient than the default [List] implementation.
  */
-class Uint64List extends TypedData implements JavaScriptIndexingBehavior, List<int> {
+abstract class Uint64List extends TypedData
+                          implements JavaScriptIndexingBehavior, List<int> {
   /**
    * Creates a [Uint64List] of the specified length (in elements), all
    * of whose elements are initially zero.
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 211c085..8196b61 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -131,7 +131,7 @@
 Language/07_Classes/10_Superinterfaces_A07_t05: StaticWarning # co19-roll r667: Please triage this failure
 LibTest/convert/JsonEncoder/JsonEncoder_A01_t01: StaticWarning # co19-roll r667: Please triage this failure
 LibTest/isolate/Isolate/spawnFunction_A02_t02: CompileTimeError # co19-roll r667: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t01: CompileTimeError # co19-roll r667: Please triage this failure
+LibTest/async/Zone/operator_subscript_A01_t01: StaticWarning # co19-roll r672: Please triage this failure
 
 # co19 issue 656
 LibTest/typed_data/Uint32x4/*: Skip # co19 issue 656
@@ -142,4 +142,4 @@
 LibTest/typed_data/Float32x4/greaterThan_A01_t01: Skip # co19 issue 656
 LibTest/typed_data/Float32x4/greaterThanOrEqual_A01_t01: Skip # co19 issue 656
 LibTest/typed_data/Float32x4/lessThan_A01_t01: Skip # co19 issue 656
-LibTest/typed_data/Float32x4/lessThanOrEqual_A01_t01: Skip # co19 issue 656
\ No newline at end of file
+LibTest/typed_data/Float32x4/lessThanOrEqual_A01_t01: Skip # co19 issue 656
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index b93b952..184d3aa 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -131,9 +131,7 @@
 Language/07_Classes/10_Superinterfaces_A07_t05: StaticWarning # co19-roll r667: Please triage this failure
 LibTest/convert/JsonEncoder/JsonEncoder_A01_t01: StaticWarning # co19-roll r667: Please triage this failure
 LibTest/isolate/Isolate/spawnFunction_A02_t02: CompileTimeError # co19-roll r667: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t01: CompileTimeError # co19-roll r667: Please triage this failure
-  
-
+LibTest/async/Zone/operator_subscript_A01_t01: StaticWarning # co19-roll r672: Please triage this failure
 
 # co19 issue 656
 LibTest/typed_data/Uint32x4/*: Skip # co19 issue 656
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 3212583..dfadfa8 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -15,19 +15,11 @@
 LibTest/core/Stopwatch/start_A01_t02: PASS, FAIL, OK # co19 issue 657
 LibTest/core/Stopwatch/elapsedTicks_A01_t01: PASS, FAIL, OK # co19 issue 657
 
-LibTest/isolate/Isolate/spawnUri_A01_t01: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t02: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t03: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t04: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A01_t05: Fail, OK # co19 issue 639
 LibTest/isolate/Isolate/spawnFunction_A02_t01: Fail, OK # co19 issue 639
 LibTest/isolate/Isolate/spawnFunction_A03_t01: Fail, OK # co19 issue 639
 LibTest/isolate/Isolate/spawnFunction_A04_t01: Fail, OK # co19 issue 639
 LibTest/isolate/Isolate/spawnFunction_A04_t02: Fail, OK # co19 issue 639
 LibTest/isolate/Isolate/spawnFunction_A04_t03: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A02_t02: Fail, OK # co19 issue 639
-LibTest/isolate/Isolate/spawnUri_A02_t03: Fail, OK # co19 issue 639
-
 
 [ $runtime == vm || $runtime == dartium || $compiler == dart2dart || $compiler == dart2js ]
 Language/12_Expressions/30_Identifier_Reference_A02_t01: fail, pass, ok # co19 issue 649
@@ -57,6 +49,8 @@
 LibTest/collection/ListBase/ListBase_class_A01_t01: Skip, OK # co19 issue 661
 LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip, OK # co19 issue 661
 
+LibTest/isolate/Isolate/spawnUri_A02_t04: Timeout, Fail # co19-roll r672: Please triage this failure
+
 [ $runtime == vm || $runtime == dartium || $compiler == dart2js ]
 LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
 LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
@@ -77,8 +71,6 @@
 LibTest/isolate/SendPort/send_A02_t02: SKIP # co19 issue 493
 LibTest/isolate/SendPort/send_A02_t03: SKIP # co19 issue 495
 
-LibTest/typed_data/Int8List/Int8List.fromList_A01_t02: Fail # co19-roll r559: Please triage this failure
-
 
 [ $runtime == vm || $compiler == dart2js ]
 Language/07_Classes/6_Constructors_A02_t01: SKIP # co19 issue 415.
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index c03f3c0..74fd8a5 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -115,7 +115,6 @@
 Language/07_Classes/6_Constructors/2_Factories_A10_t01: crash # co19-roll r587: Please triage this failure
 Language/07_Classes/6_Constructors/2_Factories_A10_t04: crash # co19-roll r587: Please triage this failure
 Language/12_Expressions/01_Constants_A20_t02: fail # co19-roll r546: Please triage this failure
-Language/12_Expressions/05_Strings/1_String_Interpolation_A01_t09: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/12_Instance_Creation/1_New_A02_t03: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/12_Instance_Creation/1_New_A02_t05: fail # co19-roll r546: Please triage this failure
 Language/12_Expressions/12_Instance_Creation/1_New_A02_t06: fail # co19-roll r546: Please triage this failure
@@ -173,4 +172,4 @@
 Language/12_Expressions/32_Type_Test_A02_t04: RuntimeError # co19-roll to r667: Please triage this failure
 
 [ $compiler == dart2dart && $unminified ]
-Language/14_Libraries_and_Scripts/1_Imports_A03_t31: RuntimeError # co19-roll r667: Please triage this failure
\ No newline at end of file
+Language/14_Libraries_and_Scripts/1_Imports_A03_t31: RuntimeError # co19-roll r667: Please triage this failure
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index ce36919..6a983cd 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -7,6 +7,7 @@
 LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
 
 [ $compiler == dart2js && $checked && $runtime == ie9 ]
+LibTest/core/Uri/encodeComponent_A01_t02: Pass, Slow
 LibTest/core/Uri/encodeFull_A01_t02: Pass, Slow
 LibTest/core/Uri/encodeQueryComponent_A01_t02: Pass, Timeout # co19-roll r576: Please triage this failure
 
@@ -114,7 +115,6 @@
 Language/15_Types/2_Dynamic_Type_System_A01_t02: RuntimeError # co19-roll r607: Please triage this failure
 Language/15_Types/8_Parameterized_Types_A03_t07: RuntimeError # co19-roll r607: Please triage this failure
 Language/15_Types/1_Static_Types_A03_t01: RuntimeError # co19-roll r623: Please triage this failure
-LibTest/typed_data/Float32x4List/reduce_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
 
 [ $compiler == dart2js ]
 LibTest/core/int/operator_GT_A01_t01: RuntimeError, OK # co19 issue 200
@@ -151,53 +151,6 @@
 
 LibTest/core/RegExp/Pattern_semantics/firstMatch_Term_A04_t01: RuntimeError, OK # co19 issue 212
 
-[ $compiler == dart2js || $compiler == dart2dart ]
-
-Language/12_Expressions/05_Strings_A02_t02: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t03: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t04: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t05: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t06: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t07: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t08: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t09: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t10: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t11: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t12: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t13: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t14: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t15: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t16: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t17: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t18: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t19: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t20: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t21: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t22: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t23: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t24: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t25: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t28: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t29: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t32: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t32: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t33: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t34: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t36: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t38: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t40: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t42: Crash # Issue 15237
-Language/12_Expressions/05_Strings_A02_t44: Crash # Issue 15237
-
-
-Language/13_Statements/05_If_A01_t04: Crash # Issue 15237
-Language/13_Statements/07_While_A01_t01: Crash # Issue 15237
-Language/13_Statements/08_Do_A01_t03: Crash # Issue 15237
-Language/13_Statements/09_Switch_A01_t04: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A15_t06: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A22_t06: Crash # Issue 15237
-Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A29_t06: Crash # Issue 15237
-
 #
 # Issues with co19 test suite.
 #
@@ -349,7 +302,6 @@
 # Missing compile-time errors.
 #
 [ $compiler == dart2js ]
-Language/12_Expressions/05_Strings/1_String_Interpolation_A01_t09: MissingCompileTimeError # Checks that it is a compile-time error if a string interpolation construct does not start with IDENTIFIER_NO_DOLLAR or opening brace.
 Language/16_Reference/1_Lexical_Rules/1_Reserved_Words_A40_t04: MissingCompileTimeError # Checks that other Unicode whitespaces are not allowed:  check NO-BREAK SPACE (U+00A0)
 Language/16_Reference/1_Lexical_Rules_A02_t06: MissingCompileTimeError # Checks that Unicode whitespaces other than WHITESPACE are not permitted in the source code. Checks symbol U+00a0.
 
@@ -438,6 +390,43 @@
 LibTest/typed_data/ByteData/toString_A01_t01: fail # co19-roll r569: Please triage this failure
 LibTest/typed_data/ByteData/elementSizeInBytes_A01_t01: fail # co19-roll r569: Please triage this failure
 
+LibTest/typed_data/Int32x4/flagW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagW_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagW_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagX_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagY_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/flagZ_A01_t03: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.bool_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.fromFloat32x4Bits_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/Int32x4.fromFloat32x4Bits_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_AND_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_OR_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_XOR_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/select_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/w_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/w_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withFlagZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withW_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withX_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withY_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/withZ_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/x_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/x_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/y_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/y_A01_t02: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/z_A01_t01: fail # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/z_A01_t02: fail # co19-roll r672: Please triage this failure
+
 [ $compiler == dart2js ]
 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
@@ -585,6 +574,29 @@
 LibTest/async/Timer/isActive_A01_t01: RuntimeError # co19-roll r641: Please triage this failure
 LibTest/async/Future/wait_A01_t07: RuntimeError # co19-roll r641: Please triage this failure
 LibTest/async/Timer/isActive_A01_t02: RuntimeError # co19-roll r641: Please triage this failure
+LibTest/async/Zone/createPeriodicTimer_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/async/Zone/createTimer_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/typed_data/Int32x4/operator_OR_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+
+[ $compiler == dart2js && $runtime == d8 ]
+LibTest/core/Stopwatch/elapsedInMs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedInUs_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsedTicks_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/elapsed_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/start_A01_t03: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/core/Stopwatch/stop_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
 
 [ $compiler == dart2js && $minified ]
 Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail # co19-roll r559: Please triage this failure
@@ -622,6 +634,13 @@
 Language/14_Libraries_and_Scripts/2_Exports_A05_t03: MissingCompileTimeError # co19-roll r623: Please triage this failure
 Language/15_Types/4_Interface_Types_A11_t04: fail # Issue 14654
 LibTest/core/Symbol/Symbol_A01_t02: CompileTimeError # co19-roll r607: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t01: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t02: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t03: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t04: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t05: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t02: Fail # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t03: Fail # co19-roll r672: Please triage this failure
 
 [ $compiler == dart2js ]
 LibTest/core/List/List_class_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 554f5ae..c60ac8c 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -10,13 +10,21 @@
 Language/14_Libraries_and_Scripts/3_Parts_A02_t02: Pass, Timeout # Issue 13719: Please triage this failure.
 Language/14_Libraries_and_Scripts/4_Scripts_A03_t03: Pass # Issue 14478: This should break.
 LibTest/async/Completer/completeError_A02_t01: Pass, Fail # Issue 13719: Please triage this failure.
-LibTest/async/Future/Future_A01_t03: Fail # co19-roll r641: Please triage this failure
 LibTest/core/int/operator_left_shift_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
 LibTest/isolate/ReceivePort/toSendPort_A01_t02: Pass, Fail # Issue 13719: Please triage this failure.
 LibTest/isolate/SendPort/send_A02_t01: Fail # Issue 13921
 LibTest/isolate/SendPort/send_A02_t04: Fail # Issue 13921
 LibTest/isolate/SendPort/send_A02_t05: Fail # Issue 13921
 LibTest/isolate/SendPort/send_A02_t06: Fail # Issue 13921
+LibTest/isolate/Isolate/spawnUri_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t02: Timeout  # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t03: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t04: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A01_t05: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # co19-roll r672: Please triage this failure
+LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # co19-roll r672: Please triage this failure
 
 
 Language/12_Expressions/13_Spawning_an_Isolate_A01_t01: RuntimeError # co19-roll r667: Please triage this failure
@@ -26,7 +34,6 @@
 LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # co19-roll r667: Please triage this failure
 LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
 
-
 [ $compiler == none && $runtime == dartium && $checked ]
 Language/13_Statements/09_Switch_A09_t01: Fail # Please triage this failure (enabled checked mode tests on dartium)
-LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
\ No newline at end of file
+LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index df0e9c9..1e73cf2 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -36,6 +36,9 @@
 LibTest/isolate/ReceivePort/receive_A01_t02: Fail # VM triage, check spec.
 LibTest/isolate/SendPort/send_A01_t01: fail # co19-roll r546: Please triage this failure
 
+LibTest/isolate/Isolate/spawnUri_A02_t02: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawnUri_A02_t03: Timeout # co19-roll r672: Please triage this failure
+
 LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # co19-roll r607: Please triage this failure
 LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
 LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # co19-roll r607: Please triage this failure
@@ -89,3 +92,6 @@
 [ $compiler == none && $runtime == vm && $system == windows && $mode == debug ]
 Language/15_Types/4_Interface_Types_A11_t01: pass, timeout # Issue 13349
 Language/15_Types/4_Interface_Types_A11_t02: pass, timeout # Issue 13349
+
+[ $runtime == vm ]
+LibTest/isolate/Isolate/spawn_A02_t01: Timeout # co19-roll r672: Please triage this failure
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index de48a2e..8965a92 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -20,6 +20,29 @@
 // TODO(johnniwinther): Support canonical URIs as keys and message kinds as
 // values.
 const Map<String, List<String>> WHITE_LIST = const {
+  // The following notices go away when bugs 15417 is fixed.
+  "sdk/lib/core/map.dart": const [
+      "Info: This is the method declaration."],
+
+  // Bug 15417.
+  "sdk/lib/html/dart2js/html_dart2js.dart": const ["""
+Warning: '_DataAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: '_NamespacedAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: '_ElementAttributeMap' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""", """
+Warning: 'Window' doesn't implement 'clearInterval'.
+Try adding an implementation of 'clearInterval'.""", """
+Warning: 'Window' doesn't implement 'clearTimeout'.
+Try adding an implementation of 'clearTimeout'.""", """
+Warning: 'Window' doesn't implement 'setInterval'.
+Try adding an implementation of 'setInterval'.""", """
+Warning: 'Window' doesn't implement 'setTimeout'.
+Try adding an implementation of 'setTimeout'.""", """
+Warning: 'Storage' doesn't implement 'addAll'.
+Try adding an implementation of 'addAll'.""",
+"Info: This is the method declaration."],
 };
 
 void main() {
diff --git a/tests/compiler/dart2js/analyze_dart2js_test.dart b/tests/compiler/dart2js/analyze_dart2js_test.dart
index 9508083..ccd379e 100644
--- a/tests/compiler/dart2js/analyze_dart2js_test.dart
+++ b/tests/compiler/dart2js/analyze_dart2js_test.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 analyze_api;
+library analyze_dart2js;
 
 import "package:expect/expect.dart";
 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
diff --git a/tests/compiler/dart2js/analyze_helper.dart b/tests/compiler/dart2js/analyze_helper.dart
index adb0673..2c2c02d 100644
--- a/tests/compiler/dart2js/analyze_helper.dart
+++ b/tests/compiler/dart2js/analyze_helper.dart
@@ -123,20 +123,29 @@
   }
 }
 
-Future analyze(List<Uri> uriList, Map<String, List<String>> whiteList) {
+Future analyze(List<Uri> uriList,
+               Map<String, List<String>> whiteList,
+               {bool analyzeAll: true}) {
   var libraryRoot = currentDirectory.resolve('sdk/');
   var provider = new CompilerSourceFileProvider();
   var handler = new CollectingDiagnosticHandler(whiteList, provider);
+  var options = <String>['--analyze-only', '--categories=Client,Server'];
+  if (analyzeAll) options.add('--analyze-all');
   var compiler = new Compiler(
       provider.readStringFromUri,
       null,
       handler.diagnosticHandler,
       libraryRoot, libraryRoot,
-      <String>['--analyze-only', '--analyze-all',
-               '--categories=Client,Server'],
+      options,
       {});
-  compiler.librariesToAnalyzeWhenRun = uriList;
-  return compiler.run(null).then((_) {
-    handler.checkResults();
-  });
+  if (analyzeAll) {
+    compiler.librariesToAnalyzeWhenRun = uriList;
+    return compiler.run(null).then((_) {
+      handler.checkResults();
+    });
+  } else {
+    return compiler.run(uriList.single).then((_) {
+      handler.checkResults();
+    });
+  }
 }
diff --git a/tests/compiler/dart2js/analyze_unused_dart2js_test.dart b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
new file mode 100644
index 0000000..03d08e6
--- /dev/null
+++ b/tests/compiler/dart2js/analyze_unused_dart2js_test.dart
@@ -0,0 +1,18 @@
+// 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 analyze_unused_dart2js;
+
+import 'package:async_helper/async_helper.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
+
+import 'analyze_helper.dart';
+
+void main() {
+  var uri = currentDirectory.resolve(
+      'sdk/lib/_internal/compiler/implementation/use_unused_api.dart');
+  asyncTest(
+      () => analyze([uri], {}, analyzeAll: false));
+}
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index 68cfa76..c74f6f5 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -195,6 +195,10 @@
 }

 

 void main() {

+  bool isCheckedMode = false;

+  assert(isCheckedMode = true);

+  Expect.isTrue(isCheckedMode, 'This test must be run in checked mode.');

+

   const beforeRun = const {

     '': 0,

     'NoSuchMethodError': 253,

diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index 414e5cd..9366565 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -74,6 +74,9 @@
   return handler;
 }
 
+Expando<MemorySourceFileProvider> expando =
+    new Expando<MemorySourceFileProvider>();
+
 Compiler compilerFor(Map<String,String> memorySourceFiles,
                      {DiagnosticHandler diagnosticHandler,
                       List<String> options: const [],
@@ -83,7 +86,24 @@
   Uri libraryRoot = script.resolve('../../../sdk/');
   Uri packageRoot = script.resolve('./packages/');
 
-  var provider = new MemorySourceFileProvider(memorySourceFiles);
+  MemorySourceFileProvider provider;
+  var readStringFromUri;
+  if (cachedCompiler == null) {
+    provider = new MemorySourceFileProvider(memorySourceFiles);
+    readStringFromUri = provider.readStringFromUri;
+    // Saving the provider in case we need it later for a cached compiler.
+    expando[readStringFromUri] = provider;
+  } else {
+    // When using a cached compiler, it has read a number of files from disk
+    // already (and will not attemp to read them again due to caching). These
+    // files must be available to the new diagnostic handler.
+    provider = expando[cachedCompiler.provider];
+    readStringFromUri = cachedCompiler.provider;
+    provider.memorySourceFiles.clear();
+    memorySourceFiles.forEach((key, value) {
+      provider.memorySourceFiles[key] = value;
+    });
+  }
   var handler =
       createDiagnosticHandler(diagnosticHandler, provider, showDiagnostics);
 
@@ -92,7 +112,7 @@
     return new NullSink('$name.$extension');
   }
 
-  Compiler compiler = new Compiler(provider.readStringFromUri,
+  Compiler compiler = new Compiler(readStringFromUri,
                                    outputProvider,
                                    handler,
                                    libraryRoot,
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 37e0729..1eb5892 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -58,7 +58,7 @@
     // 2. Some code was refactored, and there are more methods.
     // Either situation could be problematic, but in situation 2, it is often
     // acceptable to increase [expectedMethodCount] a little.
-    int expectedMethodCount = 344;
+    int expectedMethodCount = 346;
     Expect.isTrue(
         generatedCode.length <= expectedMethodCount,
         'Too many compiled methods: '
@@ -123,7 +123,9 @@
 
 const MEMORY_SOURCE_FILES = const <String, String> {
   'main.dart': """
-@MirrorsUsed(targets: const [Foo], override: '*')
+// The repeated constant value for symbols and targets used to crash dart2js in
+// host-checked mode, and could potentially lead to other problems.
+@MirrorsUsed(symbols: 'Foo', targets: 'Foo', override: '*')
 import 'dart:mirrors';
 
 import 'library.dart';
diff --git a/tests/compiler/dart2js/mixin_typevariable_test.dart b/tests/compiler/dart2js/mixin_typevariable_test.dart
new file mode 100644
index 0000000..9e9f8fb
--- /dev/null
+++ b/tests/compiler/dart2js/mixin_typevariable_test.dart
@@ -0,0 +1,158 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file

+// for details. All rights reserved. Use of this source code is governed by a

+// BSD-style license that can be found in the LICENSE file.

+

+library mixin_typevariable_test;

+

+import 'package:expect/expect.dart';

+import "package:async_helper/async_helper.dart";

+import 'type_test_helper.dart';

+import '../../../sdk/lib/_internal/compiler/implementation/dart_types.dart';

+import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart"

+       show Element, ClassElement;

+

+void main() {

+  testMixinSupertypes();

+  testNonTrivialSubstitutions();

+}

+

+void testMixinSupertypes() {

+  asyncTest(() => TypeEnvironment.create(r"""

+      class S<S_T> {}

+      class M1<M1_T> {}

+      class M2<M2_T> {}

+      class M3<M3_T> {}

+      

+      class C1<C1_T> extends S<C1_T> with M1<C1_T>, M2<C1_T>, M3<C1_T> {}

+      class C2<C2_T> = S<C2_T> with M1<C2_T>, M2<C2_T>, M3<C2_T>;

+      """, expectNoWarningsOrErrors: true).then((env) {

+

+    ClassElement Object = env.getElement('Object');

+    ClassElement S = env.getElement('S');

+    ClassElement M1 = env.getElement('M1');

+    ClassElement M2 = env.getElement('M2');

+    ClassElement M3 = env.getElement('M3');

+    ClassElement C1 = env.getElement('C1');

+    ClassElement C2 = env.getElement('C2');

+

+    ClassElement C1_S_M1_M2_M3 = C1.superclass;

+    ClassElement C1_S_M1_M2 = C1_S_M1_M2_M3.superclass;

+    ClassElement C1_S_M1 = C1_S_M1_M2.superclass;

+

+    ClassElement C2_S_M1_M2 = C2.superclass;

+    ClassElement C2_S_M1 = C2_S_M1_M2.superclass;

+

+    void testSupertypes(ClassElement element) {

+      if (element != Object) {

+        Expect.isTrue(element.typeVariables.slowLength() == 1);

+        Expect.equals(element,

+                      element.typeVariables.head.element.enclosingElement);

+      }

+      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {

+        if (!supertype.typeArguments.isEmpty) {

+          Expect.equals(element.typeVariables, supertype.typeArguments,

+              "Type argument mismatch on supertype $supertype of $element.");

+        } else {

+          Expect.equals(Object, supertype.element);

+        }

+      }

+    }

+

+    testSupertypes(Object);

+    testSupertypes(S);

+    testSupertypes(M1);

+    testSupertypes(M2);

+    testSupertypes(C1_S_M1);

+    testSupertypes(C1_S_M1_M2);

+    testSupertypes(C1_S_M1_M2_M3);

+    testSupertypes(C1);

+    testSupertypes(C2_S_M1);

+    testSupertypes(C2_S_M1_M2);

+    testSupertypes(C2);

+  }));

+}

+

+void testNonTrivialSubstitutions() {

+  asyncTest(() => TypeEnvironment.create(r"""

+      class _ {}

+      class A<A_T> {}

+      class B<B_T, B_S> {}

+      

+      class C1<C1_T> extends A with B {}

+      class C2<C2_T> = A with B;

+      

+      class D1<D1_T> extends A<D1_T> with B<D1_T, A<D1_T>> {}

+      class D2<D2_T> = A<D2_T> with B<D2_T, A<D2_T>>;

+      

+      class E1<E1_T> extends A<_> with B<_, A<_>> {}

+      class E2<E2_T> = A<_> with B<_, A<_>>;

+      

+      class F1<F1_T> extends A<_> with B<_, B<F1_T, _>> {}

+      class F2<F2_T> = A<_> with B<_, B<F2_T, _>>;

+      """, expectNoWarningsOrErrors: true).then((env) {

+    DartType _dynamic = env['dynamic'];

+    DartType _ = env['_'];

+

+    ClassElement Object = env.getElement('Object');

+    ClassElement A = env.getElement('A');

+    ClassElement B = env.getElement('B');

+    ClassElement C1 = env.getElement('C1');

+    ClassElement C2 = env.getElement('C2');

+    ClassElement D1 = env.getElement('D1');

+    ClassElement D2 = env.getElement('D2');

+    ClassElement E1 = env.getElement('E1');

+    ClassElement E2 = env.getElement('E2');

+    ClassElement F1 = env.getElement('F1');

+    ClassElement F2 = env.getElement('F2');

+

+    ClassElement C1_A_B = C1.superclass;

+    ClassElement D1_A_B = D1.superclass;

+    ClassElement E1_A_B = E1.superclass;

+    ClassElement F1_A_B = F1.superclass;

+

+    void testSupertypes(ClassElement element,

+                        Map<ClassElement, List<DartType>> typeArguments) {

+      if (element != Object) {

+        Expect.isTrue(element.typeVariables.slowLength() == 1);

+        Expect.equals(element,

+                      element.typeVariables.head.element.enclosingElement);

+      }

+      for (InterfaceType supertype in element.allSupertypesAndSelf.types) {

+        if (typeArguments.containsKey(supertype.element)) {

+          Expect.listEquals(typeArguments[supertype.element],

+                            supertype.typeArguments.toList(),

+              "Type argument mismatch on supertype $supertype of $element.");

+        } else if (!supertype.typeArguments.isEmpty) {

+          Expect.equals(element.typeVariables, supertype.typeArguments,

+              "Type argument mismatch on supertype $supertype of $element.");

+        } else {

+          Expect.equals(Object, supertype.element);

+        }

+      }

+    }

+

+    testSupertypes(C1, {A: [_dynamic], B: [_dynamic, _dynamic]});

+    testSupertypes(C1.superclass, {A: [_dynamic], B: [_dynamic, _dynamic]});

+    testSupertypes(C2, {A: [_dynamic], B: [_dynamic, _dynamic]});

+

+    DartType D1_T = D1.typeVariables.head;

+    testSupertypes(D1, {A: [D1_T], B: [D1_T, instantiate(A, [D1_T])]});

+    DartType D1_superclass_T = D1.superclass.typeVariables.head;

+    testSupertypes(D1.superclass,

+        {A: [D1_superclass_T],

+         B: [D1_superclass_T, instantiate(A, [D1_superclass_T])]});

+    DartType D2_T = D2.typeVariables.head;

+    testSupertypes(D2, {A: [D2_T], B: [D2_T, instantiate(A, [D2_T])]});

+

+    testSupertypes(E1, {A: [_], B: [_, instantiate(A, [_])]});

+    testSupertypes(E1.superclass, {A: [_], B: [_, instantiate(A, [_])]});

+    testSupertypes(E2, {A: [_], B: [_, instantiate(A, [_])]});

+

+    DartType F1_T = F1.typeVariables.head;

+    testSupertypes(F1, {A: [_], B: [_, instantiate(B, [F1_T, _])]});

+    DartType F1_superclass_T = F1.superclass.typeVariables.head;

+    testSupertypes(F1.superclass, {A: [_], B: [_, instantiate(B, [F1_superclass_T, _])]});

+    DartType F2_T = F2.typeVariables.head;

+    testSupertypes(F2, {A: [_], B: [_, instantiate(B, [F2_T, _])]});

+  }));

+}

diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 8269768..b24b0f2 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -19,7 +19,8 @@
 import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
     show ElementX,
          LibraryElementX,
-         ErroneousElementX;
+         ErroneousElementX,
+         FunctionElementX;
 
 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
     hide TreeElementMapping;
@@ -394,7 +395,8 @@
 
   resolverVisitor() {
     Element mockElement =
-        new ElementX('', ElementKind.FUNCTION, mainApp.entryCompilationUnit);
+      new FunctionElementX('', ElementKind.FUNCTION, Modifiers.EMPTY,
+                           mainApp.entryCompilationUnit, false);
     ResolverVisitor visitor =
         new ResolverVisitor(this, mockElement,
                             new CollectingTreeElements(mockElement));
@@ -437,25 +439,62 @@
   }
 }
 
-void compareWarningKinds(String text, expectedWarnings, foundWarnings) {
+/// A function the checks [message]. If the check fails or if [message] is
+/// `null`, an error string is returned. Otherwise `null` is returned.
+typedef String CheckMessage(Message message);
+
+CheckMessage checkMessage(MessageKind kind, Map arguments) {
+  return (Message message) {
+    if (message == null) return '$kind';
+    if (message.kind != kind) return 'Expected message $kind, found $message.';
+    for (var key in arguments.keys) {
+      if (!message.arguments.containsKey(key)) {
+        return 'Expected argument $key not found in $message.kind.';
+      }
+      String expectedValue = '${arguments[key]}';
+      String foundValue = '${message.arguments[key]}';
+      if (expectedValue != foundValue) {
+        return 'Expected argument $key with value $expectedValue, '
+               'found $foundValue.';
+      }
+    }
+    return null;
+  };
+}
+
+/// [expectedWarnings] must be a list of either [MessageKind] or [CheckMessage].
+void compareWarningKinds(String text,
+                         List expectedWarnings,
+                         List<WarningMessage> foundWarnings) {
   var fail = (message) => Expect.fail('$text: $message');
-  HasNextIterator<MessageKind> expected =
+  HasNextIterator expectedIterator =
       new HasNextIterator(expectedWarnings.iterator);
-  HasNextIterator<WarningMessage> found =
+  HasNextIterator<WarningMessage> foundIterator =
       new HasNextIterator(foundWarnings.iterator);
-  while (expected.hasNext && found.hasNext) {
-    Expect.equals(expected.next(), found.next().message.kind);
+  while (expectedIterator.hasNext && foundIterator.hasNext) {
+    var expected = expectedIterator.next();
+    var found = foundIterator.next();
+    if (expected is MessageKind) {
+      Expect.equals(expected, found.message.kind);
+    } else if (expected is CheckMessage) {
+      String error = expected(found.message);
+      Expect.isNull(error, error);
+    } else {
+      Expect.fail("Unexpected expectedWarnings value: $expected.");
+    }
   }
-  if (expected.hasNext) {
+  if (expectedIterator.hasNext) {
     do {
-      print('Expected warning "${expected.next()}" did not occur');
-    } while (expected.hasNext);
+      var expected = expectedIterator.next();
+      if (expected is CheckMessage) expected = expected(null);
+      print('Expected warning "${expected}" did not occur');
+    } while (expectedIterator.hasNext);
     fail('Too few warnings');
   }
-  if (found.hasNext) {
+  if (foundIterator.hasNext) {
     do {
-      print('Additional warning "${found.next()}"');
-    } while (found.hasNext);
+      print('Additional warning "${foundIterator.next()}"');
+    } while (foundIterator.hasNext);
     fail('Too many warnings');
   }
 }
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 8ca53a8..02f1b6b 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -11,7 +11,7 @@
 import 'parser_helper.dart';
 
 import '../../../sdk/lib/_internal/compiler/implementation/elements/modelx.dart'
-    show ElementX, CompilationUnitElementX;
+  show ElementX, CompilationUnitElementX, FunctionElementX;
 
 import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart';
 
@@ -1518,6 +1518,12 @@
                            class E<T> extends D<T> {
                              T e;
                            }
+                           class F<S, U> extends E<S> {
+                             S f;
+                           }
+                           class G<V> extends F<V, V> {
+                             V g;
+                           }
                            ''');
 
   check(String text, {warnings, hints, infos}) {
@@ -1530,7 +1536,7 @@
               var x = a.c;
             }''',
         warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
-        hints: [MessageKind.NOT_MORE_SPECIFIC],
+        hints: [MessageKind.NOT_MORE_SPECIFIC_SUBTYPE],
         infos: []);
 
   check(r'''
@@ -1540,7 +1546,7 @@
             }''',
         warnings: [MessageKind.MEMBER_NOT_FOUND.warning,
                    MessageKind.MEMBER_NOT_FOUND.warning],
-        hints: [MessageKind.NOT_MORE_SPECIFIC],
+        hints: [MessageKind.NOT_MORE_SPECIFIC_SUBTYPE],
         infos: []);
 
   check(r'''
@@ -1555,10 +1561,40 @@
 
   check('''
            D<int> d = new E();
-           if (d is E) {
+           if (d is E) { // Suggest E<int>.
              var x = d.e;
            }''',
         warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+        hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+                             {'shownTypeSuggestion': 'E<int>'})],
+        infos: []);
+
+  check('''
+           D<int> d = new F();
+           if (d is F) { // Suggest F<int, dynamic>.
+             var x = d.f;
+           }''',
+        warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+        hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+                             {'shownTypeSuggestion': 'F<int, dynamic>'})],
+        infos: []);
+
+  check('''
+           D<int> d = new G();
+           if (d is G) { // Suggest G<int>.
+             var x = d.f;
+           }''',
+        warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
+        hints: [checkMessage(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+                             {'shownTypeSuggestion': 'G<int>'})],
+        infos: []);
+
+  check('''
+           F<double, int> f = new G();
+           if (f is G) { // Cannot suggest a more specific type.
+             var x = f.g;
+           }''',
+        warnings: [MessageKind.MEMBER_NOT_FOUND.warning],
         hints: [MessageKind.NOT_MORE_SPECIFIC],
         infos: []);
 
@@ -1803,8 +1839,8 @@
   Node node = listener.popNode();
   Element compilationUnit =
     new CompilationUnitElementX(new Script(null, null), compiler.mainApp);
-  Element function = new ElementX(
-      '', ElementKind.FUNCTION, compilationUnit);
+  Element function = new FunctionElementX(
+      '', ElementKind.FUNCTION, Modifiers.EMPTY, compilationUnit, false);
   TreeElements elements = compiler.resolveNodeStatement(node, function);
   TypeCheckerVisitor checker = new TypeCheckerVisitor(compiler, elements,
                                                                 types);
diff --git a/tests/compiler/dart2js/type_test_helper.dart b/tests/compiler/dart2js/type_test_helper.dart
index d616835..01e8c16 100644
--- a/tests/compiler/dart2js/type_test_helper.dart
+++ b/tests/compiler/dart2js/type_test_helper.dart
@@ -22,7 +22,9 @@
 class TypeEnvironment {
   final MockCompiler compiler;
 
-  static Future<TypeEnvironment> create(String source) {
+  static Future<TypeEnvironment> create(
+      String source, {bool expectNoErrors: false,
+                      bool expectNoWarningsOrErrors: false}) {
     var uri = new Uri(scheme: 'source');
     MockCompiler compiler = compilerFor('''
         main() {}
@@ -31,6 +33,14 @@
         analyzeAll: true,
         analyzeOnly: true);
     return compiler.runCompiler(uri).then((_) {
+      if (expectNoErrors || expectNoWarningsOrErrors) {
+        Expect.isTrue(compiler.errors.isEmpty,
+            'Unexpected errors: ${compiler.errors}');
+      }
+      if (expectNoWarningsOrErrors) {
+        Expect.isTrue(compiler.warnings.isEmpty,
+            'Unexpected warnings: ${compiler.warnings}');
+      }
       return new TypeEnvironment._(compiler);
     });
   }
diff --git a/tests/compiler/dart2js_extra/mirror_printer_test.dart b/tests/compiler/dart2js_extra/mirror_printer_test.dart
index 63c1d12..72e4878 100644
--- a/tests/compiler/dart2js_extra/mirror_printer_test.dart
+++ b/tests/compiler/dart2js_extra/mirror_printer_test.dart
@@ -56,12 +56,14 @@
       return '$reflectee';
     }
     StringBuffer buffer = new StringBuffer();
-    Map<Symbol, VariableMirror> variables = mirror.type.variables;
+    Map<Symbol, DeclarationMirror> declarations = mirror.type.declarations;
     buffer
         ..write(n(mirror.type.simpleName))
         ..write('(');
     bool first = true;
-    variables.forEach((Symbol name, VariableMirror variable) {
+    declarations.forEach((Symbol name, DeclarationMirror declaration) {
+      if (declaration is! VariableMirror) return;
+      VariableMirror variable = declaration;
       if (variable.isStatic) return;
       // TODO(ahe): Include superclasses.
       if (first) {
@@ -130,7 +132,7 @@
     w(' {');
     bool first = true;
     indented(() {
-      for (DeclarationMirror declaration in mirror.members.values) {
+      for (DeclarationMirror declaration in mirror.declarations.values) {
         if (first) {
           first = false;
         } else {
@@ -165,7 +167,9 @@
 
   writeLibrary(LibraryMirror library) {
     w('library ${n(library.simpleName)};\n\n');
-    library.members.values.forEach(writeDeclaration);
+    library.declarations.values
+        .where((d)=> d is! TypeMirror)
+        .forEach(writeDeclaration);
     w('\n');
   }
 
diff --git a/tests/corelib/uri_test.dart b/tests/corelib/uri_test.dart
index 351c3b9..3e66ac9 100644
--- a/tests/corelib/uri_test.dart
+++ b/tests/corelib/uri_test.dart
@@ -30,11 +30,35 @@
   Expect.stringEquals(orig, d);
 }
 
-testEncodeDecodeQueryComponent(String orig, String encoded) {
-  var e = Uri.encodeQueryComponent(orig);
-  Expect.stringEquals(encoded, e);
-  var d = Uri.decodeQueryComponent(encoded);
+testEncodeDecodeQueryComponent(String orig,
+                               String encodedUTF8,
+                               String encodedLatin1,
+                               String encodedAscii) {
+  var e, d;
+  e = Uri.encodeQueryComponent(orig);
+  Expect.stringEquals(encodedUTF8, e);
+  d = Uri.decodeQueryComponent(encodedUTF8);
   Expect.stringEquals(orig, d);
+
+  e = Uri.encodeQueryComponent(orig, encoding: UTF8);
+  Expect.stringEquals(encodedUTF8, e);
+  d = Uri.decodeQueryComponent(encodedUTF8, encoding: UTF8);
+  Expect.stringEquals(orig, d);
+
+  e = Uri.encodeQueryComponent(orig, encoding: LATIN1);
+  Expect.stringEquals(encodedLatin1, e);
+  d = Uri.decodeQueryComponent(encodedLatin1, encoding: LATIN1);
+  Expect.stringEquals(orig, d);
+
+  if (encodedAscii != null) {
+    e = Uri.encodeQueryComponent(orig, encoding: ASCII);
+    Expect.stringEquals(encodedAscii, e);
+    d = Uri.decodeQueryComponent(encodedAscii, encoding: ASCII);
+    Expect.stringEquals(orig, d);
+  } else {
+    Expect.throws(() => Uri.encodeQueryComponent(orig, encoding: ASCII),
+                  (e) => e is ArgumentError);
+  }
 }
 
 testUriPerRFCs(Uri base) {
@@ -229,5 +253,7 @@
   testEncodeDecodeComponent("\u0800", "%E0%A0%80");
   testEncodeDecodeComponent(":/@',;?&=+\$", "%3A%2F%40'%2C%3B%3F%26%3D%2B%24");
   testEncodeDecodeComponent(s, "%F0%90%80%80");
-  testEncodeDecodeQueryComponent("A + B", "A+%2B+B");
+  testEncodeDecodeQueryComponent("A + B", "A+%2B+B", "A+%2B+B", "A+%2B+B");
+  testEncodeDecodeQueryComponent(
+      "æ ø å", "%C3%A6+%C3%B8+%C3%A5", "%E6+%F8+%E5", null);
 }
diff --git a/tests/html/custom/constructor_calls_created_synchronously_test.dart b/tests/html/custom/constructor_calls_created_synchronously_test.dart
index f9f242d..d2bc3af 100644
--- a/tests/html/custom/constructor_calls_created_synchronously_test.dart
+++ b/tests/html/custom/constructor_calls_created_synchronously_test.dart
@@ -49,4 +49,18 @@
     expect(A.ncallbacks, 2);
     expect(b is A, isTrue);
   });
+
+  test("can extend elements that don't have special prototypes", () {
+    document.register('fancy-section', FancySection, extendsTag: 'section');
+    var fancy = document.createElement('section', 'fancy-section');
+    expect(fancy is FancySection, true, reason: 'fancy-section was registered');
+    expect(fancy.wasCreated, true, reason: 'FancySection ctor was called');
+  });
+}
+
+class FancySection extends HtmlElement {
+  bool wasCreated = false;
+  FancySection.created() : super.created() {
+    wasCreated = true;
+  }
 }
diff --git a/tests/html/html.status b/tests/html/html.status
index 4117007..bda8941 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -102,6 +102,7 @@
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium) && $mode == debug]
 websql_test: Fail, Pass # Issue 4941: stderr contains a backtrace.
+native_gc_test: Pass, Slow
 
 [ $compiler == dart2js && $runtime == drt && $system == macos]
 audiobuffersourcenode_test: Pass, Fail
diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart
index 20e4802..e43dc4a 100644
--- a/tests/language/arithmetic_test.dart
+++ b/tests/language/arithmetic_test.dart
@@ -432,6 +432,17 @@
     var b = -1;
     for (var i = 0; i < 10; i++) Expect.equals(0x40000000, divMod(a, b));
   }
+  
+  static double sinCosSub(double a) => sin(a) - cos(a);
+  
+  static void testSinCos() {
+    var e = sin(1.234) - cos(1.234);
+    for (var i = 0; i < 20; i++) {
+      Expect.approxEquals(e, sinCosSub(1.234));
+    }
+    Expect.approxEquals(1.0, sinCosSub(3.14159265));
+    Expect.approxEquals(1.0, sinCosSub(3.14159265 / 2.0));
+  }
 
   static mySqrt(var x) => sqrt(x);
 
@@ -460,6 +471,7 @@
       testSmiDivModDeopt();
       testSqrtDeopt();
       testDoubleEquality();
+      testSinCos();
     }
   }
 }
diff --git a/tests/language/assignable_expression_test.dart b/tests/language/assignable_expression_test.dart
new file mode 100644
index 0000000..c29e366
--- /dev/null
+++ b/tests/language/assignable_expression_test.dart
@@ -0,0 +1,44 @@
+// 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 to detect syntactically illegal left-hand-side (assignable)
+// expressions.
+
+class C {
+  static var static_field = 0;
+}
+
+var tl_static_var = 0;
+
+main() {
+  tl_static_var = 0;
+  (tl_static_var) = 0;    /// 01: compile-time error
+  (tl_static_var)++;      /// 02: compile-time error
+  ++(tl_static_var);      /// 03: compile-time error
+
+  C.static_field = 0;
+  (C.static_field) = 0;   /// 11: compile-time error
+  (C.static_field)++;     /// 12: compile-time error
+  ++(C.static_field);     /// 13: compile-time error
+
+  tl_static_var = [1, 2, 3];
+  tl_static_var[0] = 0;
+  (tl_static_var)[0] = 0;
+  (tl_static_var[0]) = 0;    /// 21: compile-time error
+  (tl_static_var[0])++;      /// 22: compile-time error
+  ++(tl_static_var[0]);      /// 23: compile-time error
+
+  C.static_field = [1, 2, 3];
+  (C.static_field[0]) = 0;   /// 31: compile-time error
+  (C.static_field[0])++;     /// 32: compile-time error
+  ++(C.static_field[0]);     /// 33: compile-time error
+
+  var a = 0;
+  (a) = 0;   /// 41: compile-time error
+  (a)++;     /// 42: compile-time error
+  ++(a);     /// 43: compile-time error
+
+  // Neat palindrome expression. x is assignable, ((x)) is not.
+  var funcnuf = (x) => ((x))=((x)) <= (x);  /// 50: compile-time error
+}
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index aecedf1..98fc880 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -18,6 +18,12 @@
 override_field_test/03: fail
 method_override7_test/03: Fail # Issue 11496
 
+assignable_expression_test/02: Fail # Issue 15471
+assignable_expression_test/12: Fail # Issue 15471
+assignable_expression_test/22: Fail # Issue 15471
+assignable_expression_test/32: Fail # Issue 15471
+assignable_expression_test/42: Fail # Issue 15471
+
 # Please add new failing tests before this line.
 # Section below is for invalid tests.
 #
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 11c06e8..7f9c48b 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -9,11 +9,10 @@
 # Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
 built_in_identifier_prefix_test: CompileTimeError # Issue 12694
 
-# TBD: these look like bad tests, no issue number
+# Issue 15315
 class_literal_test: fail
 constructor_call_as_function_test/01: fail
-
-function_type_alias9_test/00: crash # Issue 11987
+call_type_literal_test/01: fail
 
 # TBF: we should check conflicts not only for methods, but for accessors too
 override_field_test/03: fail
@@ -153,8 +152,22 @@
 # test issue 14736, It is a static warning if a class C declares an instance method named n and has a setter named n=.
 setter4_test: StaticWarning
 
-
-
+# test issue 15060
+least_upper_bound_test/23: StaticWarning # Issue 15060
+least_upper_bound_test/24: StaticWarning # Issue 15060
+least_upper_bound_test/25: MissingStaticWarning # Issue 15060
+least_upper_bound_test/26: MissingStaticWarning # Issue 15060
+least_upper_bound_test/29: StaticWarning # Issue 15060
+least_upper_bound_test/30: StaticWarning # Issue 15060
+least_upper_bound_test/31: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/02: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/04: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/05: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/06: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/08: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/10: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/11: MissingStaticWarning # Issue 15060
+least_upper_bound_expansive_test/12: MissingStaticWarning # Issue 15060
 
 abstract_exact_selector_test: StaticWarning
 abstract_getter_test: StaticWarning
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 408d7a0..70f90358 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -157,12 +157,6 @@
 [ $compiler == dart2js || $compiler == dart2dart ]
 
 function_type_alias9_test/00: Crash # Issue 15237
-string_interpolation9_test/11: Crash # Issue 15237
-string_interpolation9_test/12: Crash # Issue 15237
-string_interpolation9_test/13: Crash # Issue 15237
-string_interpolation9_test/16: Crash # Issue 15237
-string_interpolation9_test/17: Crash # Issue 15237
-string_interpolation9_test/18: Crash # Issue 15237
 mixin_invalid_inheritance2_test/03: Crash # Issue 15237
 
 [ ($compiler == dart2js || $compiler == dart2dart) && $checked ]
diff --git a/tests/language/typed_message_test.dart b/tests/language/typed_message_test.dart
index e034d3e..d098c5c 100644
--- a/tests/language/typed_message_test.dart
+++ b/tests/language/typed_message_test.dart
@@ -8,6 +8,7 @@
 library TypedMessageTest;
 import "dart:async";
 import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
 import "dart:isolate";
 
 void logMessages(SendPort replyTo) {
@@ -29,6 +30,7 @@
 }
 
 main() {
+  asyncStart();
   ReceivePort receivePort = new ReceivePort();
   Future<Isolate> remote = Isolate.spawn(logMessages, receivePort.sendPort);
   List<int> msg = new List<int>(5);
@@ -43,5 +45,6 @@
   }).then((b) {
     Expect.equals(1, iterator.current);
     receivePort.close();
+    asyncEnd();
   });
 }
diff --git a/tests/language/vm/optimized_guarded_field_test.dart b/tests/language/vm/optimized_guarded_field_test.dart
index c6aea4d..aefdace 100644
--- a/tests/language/vm/optimized_guarded_field_test.dart
+++ b/tests/language/vm/optimized_guarded_field_test.dart
@@ -6,6 +6,7 @@
 // VMOptions=--optimization_counter_threshold=10
 
 import "package:expect/expect.dart";
+import "dart:typed_data";
 
 class A {
   var foo;
@@ -52,6 +53,24 @@
 }
 
 
+class D {
+  final List f;
+  final Uint8List g;
+  D(this.f, this.g);
+  D.named(this.f, this.g);
+}
+
+
+test_guarded_length() {
+  var a = new D(new List(5), new Uint8List(5));
+  var b = new D.named(new List(5), new Uint8List(5));
+  Expect.equals(5, a.f.length);
+  Expect.equals(5, b.f.length);
+  Expect.equals(5, a.g.length);
+  Expect.equals(5, b.g.length);
+}
+
+
 main() {
   var a = new A();
   var b = new B();
@@ -76,4 +95,7 @@
 
   // Regression test for fields initialized in native code (Error._stackTrace).
   test_stacktrace();
+
+  // Test guarded list length.
+  for (var i = 0; i < 20; i++) test_guarded_length();
 }
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index d0eed98..d05992f 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -16,7 +16,6 @@
 lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError
 lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError
 lib/_internal/compiler/samples/darttags/darttags: CompileTimeError
-lib/_internal/compiler/samples/jsonify/jsonify: CompileTimeError
 lib/_internal/compiler/samples/leap/leap: CompileTimeError
 lib/_internal/compiler/samples/leap/leap_leg: CompileTimeError
 lib/_internal/compiler/samples/leap/request_cache: CompileTimeError
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 20ae1c5..ad6830a 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -808,8 +808,8 @@
   Future catchError(Function onError, {bool test(e)}) =>
       _realFuture.catchError(onError, test: test);
   Future whenComplete(action()) => _realFuture.whenComplete(action);
-  Future timeout(Duration timeLimit, [void onTimeout()]) =>
-      _realFuture.timeout(timeLimit, onTimeout);
+  Future timeout(Duration timeLimit, {void onTimeout()}) =>
+      _realFuture.timeout(timeLimit, onTimeout: onTimeout);
   Stream asStream() => _realFuture.asStream();
   String toString() => "CustomFuture@${_realFuture.hashCode}";
   int get hashCode => _realFuture.hashCode;
diff --git a/tests/lib/async/future_timeout_test.dart b/tests/lib/async/future_timeout_test.dart
index f123118..cd30645 100644
--- a/tests/lib/async/future_timeout_test.dart
+++ b/tests/lib/async/future_timeout_test.dart
@@ -11,7 +11,7 @@
   test("timeoutNoComplete", () {
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => 42);
+        const Duration(milliseconds: 5), onTimeout: () => 42);
     timedOut.then(expectAsync1((v) {
       expect(v, 42);
     }));
@@ -20,7 +20,7 @@
   test("timeoutCompleteAfterTimeout", () {
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => 42);
+        const Duration(milliseconds: 5), onTimeout: () => 42);
     Timer timer = new Timer(const Duration(seconds: 1), () {
       completer.complete(-1);
     });
@@ -35,7 +35,7 @@
       completer.complete(42);
     });
     Future timedOut = completer.future.timeout(
-        const Duration(seconds: 1), () => -1);
+        const Duration(seconds: 1), onTimeout: () => -1);
     timedOut.then(expectAsync1((v) {
       expect(v, 42);
     }));
@@ -45,7 +45,7 @@
     Completer completer = new Completer.sync();
     completer.complete(42);
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => -1);
+        const Duration(milliseconds: 5), onTimeout: () => -1);
     timedOut.then(expectAsync1((v) {
       expect(v, 42);
     }));
@@ -54,7 +54,7 @@
   test("timeoutThrows", () {
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () { throw "EXN1"; });
+        const Duration(milliseconds: 5), onTimeout: () { throw "EXN1"; });
     timedOut.catchError(expectAsync2((e, s) {
       expect(e, "EXN1");
     }));
@@ -63,7 +63,7 @@
   test("timeoutThrowAfterTimeout", () {
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => 42);
+        const Duration(milliseconds: 5), onTimeout: () => 42);
     Timer timer = new Timer(const Duration(seconds: 1), () {
       completer.completeError("EXN2");
     });
@@ -78,7 +78,7 @@
       completer.completeError("EXN3");
     });
     Future timedOut = completer.future.timeout(
-        const Duration(seconds: 1), () => -1);
+        const Duration(seconds: 1), onTimeout: () => -1);
     timedOut.catchError(expectAsync2((e, s) {
       expect(e, "EXN3");
     }));
@@ -89,7 +89,7 @@
     Completer completer = new Completer.sync()..future.catchError((e){});
     completer.completeError("EXN4");
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => -1);
+        const Duration(milliseconds: 5), onTimeout: () => -1);
     timedOut.catchError(expectAsync2((e, s) {
       expect(e, "EXN4");
     }));
@@ -99,7 +99,7 @@
     Future result = new Future.value(42);
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => result);
+        const Duration(milliseconds: 5), onTimeout: () => result);
     timedOut.then(expectAsync1((v) {
       expect(v, 42);
     }));
@@ -109,7 +109,7 @@
     Future result = new Future.error("EXN5")..catchError((e){});
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () => result);
+        const Duration(milliseconds: 5), onTimeout: () => result);
     timedOut.catchError(expectAsync2((e, s) {
       expect(e, "EXN5");
     }));
@@ -119,7 +119,7 @@
     Completer result = new Completer();
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () {
+        const Duration(milliseconds: 5), onTimeout: () {
       result.complete(42);
       return result.future;
     });
@@ -132,7 +132,7 @@
     Completer result = new Completer();
     Completer completer = new Completer();
     Future timedOut = completer.future.timeout(
-        const Duration(milliseconds: 5), () {
+        const Duration(milliseconds: 5), onTimeout: () {
       result.completeError("EXN6");
       return result.future;
     });
@@ -164,7 +164,7 @@
     Future timedOut;
     forked.run(() {
       timedOut = completer.future.timeout(const Duration(milliseconds: 5),
-                                          callback);
+                                          onTimeout: callback);
     });
     timedOut.then(expectAsync1((v) {
       expect(callbackCalled, true);
diff --git a/tests/lib/async/future_value_chain4_test.dart b/tests/lib/async/future_value_chain4_test.dart
index 926e1b4..2c909cf 100644
--- a/tests/lib/async/future_value_chain4_test.dart
+++ b/tests/lib/async/future_value_chain4_test.dart
@@ -13,7 +13,7 @@
   catchError(_, {test}) => null;
   whenComplete(_) => null;
   asStream() => null;
-  timeout(Duration timeLimit, [void onTimeout()]) => null;
+  timeout(Duration timeLimit, {void onTimeout()}) => null;
 }
 
 main() {
diff --git a/tests/lib/async/stream_listen_zone_test.dart b/tests/lib/async/stream_listen_zone_test.dart
new file mode 100644
index 0000000..3ac944b
--- /dev/null
+++ b/tests/lib/async/stream_listen_zone_test.dart
@@ -0,0 +1,148 @@
+// 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 stream_listen_zeno_test;
+
+import "dart:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+main() {
+  asyncStart();
+  var controller;
+  for (bool overrideDone in [false, true]) {
+    for (bool sync in [false, true]) {
+      var mode = "${sync ? "-sync" : ""}${overrideDone ? "-od": ""}";
+      controller = new StreamController(sync: sync);
+      testStream("SC$mode", controller, controller.stream, overrideDone);
+      controller = new StreamController.broadcast(sync: sync);
+      testStream("BSC$mode", controller, controller.stream, overrideDone);
+      controller = new StreamController(sync: sync);
+      testStream("SCAB$mode", controller, controller.stream.asBroadcastStream(),
+                 overrideDone, 3);
+      controller = new StreamController(sync: sync);
+      testStream("SCMap$mode", controller, controller.stream.map((x) => x),
+                 overrideDone, 3);
+    }
+  }
+  asyncEnd();
+}
+
+void testStream(String name, StreamController controller, Stream stream,
+                bool overrideDone, [int registerExpect = 0]) {
+  asyncStart();
+  StreamSubscription sub;
+  Zone zone;
+  int registerCount = 0;
+  int callbackBits = 0;
+  int stepCount = 0;
+  Function step;
+  void nextStep() { Zone.ROOT.scheduleMicrotask(step); }
+  runZoned(() {
+    zone = Zone.current;
+    sub = stream.listen((v) {
+      Expect.identical(zone, Zone.current, name);
+      Expect.equals(42, v, name);
+      callbackBits |= 1;
+      nextStep();
+    }, onError: (e, s) {
+      Expect.identical(zone, Zone.current, name);
+      Expect.equals("ERROR", e, name);
+      callbackBits |= 2;
+      nextStep();
+    }, onDone: () {
+      Expect.identical(zone, Zone.current, name);
+      if (overrideDone) throw "RUNNING WRONG ONDONE";
+      callbackBits |= 4;
+      nextStep();
+    });
+    registerExpect += 3;
+    Expect.equals(registerExpect, registerCount, name);
+  }, zoneSpecification: new ZoneSpecification(
+    registerCallback: (self, p, z, callback()) {
+      Expect.identical(zone, self, name);
+      registerCount++;
+      return () {
+        Expect.identical(zone, Zone.current, name);
+        callback();
+      };
+    },
+    registerUnaryCallback: (self, p, z, callback(a)) {
+      Expect.identical(zone, self, name);
+      registerCount++;
+      return (a) {
+        Expect.identical(zone, Zone.current, name);
+        callback(a);
+      };
+    },
+    registerBinaryCallback: (self, package, z, callback(a, b)) {
+      Expect.identical(zone, self, name);
+      registerCount++;
+      return (a, b) {
+        Expect.identical(zone, Zone.current, name);
+        callback(a, b);
+      };
+    }
+  ));
+
+  int expectedBits = 0;
+  step = () {
+    var stepName = "$name-$stepCount";
+    Expect.identical(Zone.ROOT, Zone.current, stepName);
+    Expect.equals(expectedBits, callbackBits, stepName);
+    switch (stepCount++) {
+      case 0:
+        expectedBits |= 1;
+        controller.add(42);
+        break;
+      case 1:
+        expectedBits |= 2;
+        controller.addError("ERROR", null);
+        break;
+      case 2:
+        Expect.equals(registerExpect, registerCount, stepName);
+        sub.onData((v) {
+          Expect.identical(zone, Zone.current, stepName);
+          Expect.equals(37, v);
+          callbackBits |= 8;
+          nextStep();
+        });
+        Expect.equals(++registerExpect, registerCount, stepName);
+        expectedBits |= 8;
+        controller.add(37);
+        break;
+      case 3:
+        Expect.equals(registerExpect, registerCount, stepName);
+        sub.onError((e, s) {
+          Expect.identical(zone, Zone.current);
+          Expect.equals("BAD", e);
+          callbackBits |= 16;
+          nextStep();
+        });
+        Expect.equals(++registerExpect, registerCount, stepName);
+        expectedBits |= 16;
+        controller.addError("BAD", null);
+        break;
+      case 4:
+        Expect.equals(registerExpect, registerCount, stepName);
+        if (overrideDone) {
+          sub.onDone(() {
+            Expect.identical(zone, Zone.current);
+            callbackBits |= 32;
+            nextStep();
+          });
+          registerExpect++;
+          expectedBits |= 32;
+        } else {
+          expectedBits |= 4;
+        }
+        Expect.equals(registerExpect, registerCount, stepName);
+        controller.close();
+        break;
+      case 5:
+        asyncEnd();
+    }
+  };
+  step();
+}
diff --git a/tests/lib/async/stream_timeout_test.dart b/tests/lib/async/stream_timeout_test.dart
new file mode 100644
index 0000000..ffd25d8
--- /dev/null
+++ b/tests/lib/async/stream_timeout_test.dart
@@ -0,0 +1,171 @@
+// 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:async";
+import "package:unittest/unittest.dart";
+
+main() {
+  const ms5 = const Duration(milliseconds: 5);
+  const halfSec = const Duration(milliseconds: 500);
+
+  test("stream timeout", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(ms5);
+    expect(tos.isBroadcast, false);
+    tos.handleError(expectAsync2((e, s) {
+      expect(e, new isInstanceOf<TimeoutException>());
+      expect(s, null);
+    })).listen((v){ fail("Unexpected event"); });
+  });
+
+  test("stream timeout add events", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(ms5, onTimeout: (sink) {
+      sink.add(42);
+      sink.addError("ERROR");
+      sink.close();
+    });
+    expect(tos.isBroadcast, false);
+    tos.listen(expectAsync1((v) { expect(v, 42); }),
+               onError: expectAsync2((e, s) { expect(e, "ERROR"); }),
+               onDone: expectAsync0((){}));
+  });
+
+  test("stream no timeout", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(halfSec);
+    int ctr = 0;
+    tos.listen((v) {
+                 expect(v, 42);
+                 ctr++;
+               },
+               onError: (e, s) { fail("No error expected"); },
+               onDone: expectAsync0(() {
+                 expect(ctr, 2);
+               }));
+    expect(tos.isBroadcast, false);
+    c..add(42)..add(42)..close();  // Faster than a timeout!
+  });
+
+  test("stream timeout after events", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(halfSec);
+    expect(tos.isBroadcast, false);
+    int ctr = 0;
+    tos.listen((v) {
+                 expect(v, 42);
+                 ctr++;
+               },
+               onError: expectAsync2((e, s) {
+                 expect(ctr, 2);
+                 expect(e, new isInstanceOf<TimeoutException>());
+               }));
+    c..add(42)..add(42);  // No close, timeout after two events.
+  });
+
+  test("broadcast stream timeout",  () {
+    StreamController c = new StreamController.broadcast();
+    Stream tos = c.stream.timeout(ms5);
+    expect(tos.isBroadcast, false);
+    tos.handleError(expectAsync2((e, s) {
+      expect(e, new isInstanceOf<TimeoutException>());
+      expect(s, null);
+    })).listen((v){ fail("Unexpected event"); });
+  });
+
+  test("asBroadcast stream timeout",  () {
+    StreamController c = new StreamController.broadcast();
+    Stream tos = c.stream.asBroadcastStream().timeout(ms5);
+    expect(tos.isBroadcast, false);
+    tos.handleError(expectAsync2((e, s) {
+      expect(e, new isInstanceOf<TimeoutException>());
+      expect(s, null);
+    })).listen((v){ fail("Unexpected event"); });
+  });
+
+  test("mapped stream timeout",  () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.map((x) => 2 * x).timeout(ms5);
+    expect(tos.isBroadcast, false);
+    tos.handleError(expectAsync2((e, s) {
+      expect(e, new isInstanceOf<TimeoutException>());
+      expect(s, null);
+    })).listen((v){ fail("Unexpected event"); });
+  });
+
+  test("events prevent timeout", () {
+    Stopwatch sw = new Stopwatch();
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+      int elapsed = sw.elapsedMilliseconds;
+      if (elapsed > 250) {
+        // This should not happen.
+        print("Periodic timer of 5 ms delayed $elapsed ms.");
+      }
+      fail("Timeout not prevented by events");
+      throw "ERROR";
+    });
+    tos.listen((v) { expect(v, 42);}, onDone: expectAsync0((){}));
+    int ctr = 200;  // send this many events at 5ms intervals. Then close.
+    new Timer.periodic(ms5, (timer) {
+      sw.reset();
+      c.add(42);
+      if (--ctr == 0) {
+        timer.cancel();
+        c.close();
+      }
+    });
+    sw.start();
+  });
+
+  test("errors prevent timeout", () {
+    Stopwatch sw = new Stopwatch();
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+      int elapsed = sw.elapsedMilliseconds;
+      if (elapsed > 250) {
+        // This should not happen.
+        print("Periodic timer of 5 ms delayed $elapsed ms.");
+      }
+      fail("Timeout not prevented by errors");
+    });
+    tos.listen((_) {},
+      onError: (e, s) {
+        expect(e, "ERROR");
+      },
+      onDone: expectAsync0((){}));
+    int ctr = 200;  // send this many error events at 5ms intervals. Then close.
+    new Timer.periodic(ms5, (timer) {
+      sw.reset();
+      c.addError("ERROR");
+      if (--ctr == 0) {
+        timer.cancel();
+        c.close();
+      }
+    });
+    sw.start();
+  });
+
+  test("closing prevents timeout", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(halfSec, onTimeout: (_) {
+      fail("Timeout not prevented by close");
+    });
+    tos.listen((_) {}, onDone: expectAsync0((){}));
+    c.close();
+  });
+
+  test("pausing prevents timeout", () {
+    StreamController c = new StreamController();
+    Stream tos = c.stream.timeout(ms5, onTimeout: (_) {
+      fail("Timeout not prevented by close");
+    });
+    var subscription = tos.listen((_) {}, onDone: expectAsync0((){}));
+    subscription.pause();
+    new Timer(halfSec, () {
+      c.close();
+      subscription.resume();
+    });
+  });
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index d0c4728..7567494 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -10,14 +10,13 @@
 
 math/double_pow_test: RuntimeError
 math/low_test: RuntimeError
-math/random_test: RuntimeError
 
 mirrors/basic_types_in_dart_core_test: RuntimeError # Issue 14025
 mirrors/class_declarations_test/none: RuntimeError # Issue 13440
 mirrors/closures_test/none: RuntimeError # Issue 6490
 mirrors/constructor_kinds_test: RuntimeError # Issue 13799
 mirrors/constructor_private_name_test: CompileTimeError # Issue 13597
-mirrors/equality_test/02: RuntimeError # Issue 12333
+mirrors/equality_test/02: RuntimeError # Issue 12785
 mirrors/fake_function_with_call_test: RuntimeError # Issue 11612
 mirrors/fake_function_without_call_test: RuntimeError # Issue 11612
 mirrors/find_in_context_test: Fail # Issue 6490
@@ -30,8 +29,7 @@
 mirrors/generic_local_function_test: RuntimeError # Issue 12333
 mirrors/generic_mixin_test: RuntimeError # Issue 12333
 mirrors/generic_mixin_applications_test: RuntimeError # Issue 12333
-mirrors/generics_substitution_test/01: RuntimeError # Issue 12087
-mirrors/hierarchy_invariants_test: RuntimeError # Issue 11863
+mirrors/hierarchy_invariants_test: RuntimeError # Issue 15262
 mirrors/immutable_collections_test: RuntimeError # Issue 14030
 mirrors/initializing_formals_test/01: RuntimeError # Issue 6490
 mirrors/initializing_formals_test/03: CompileTimeError # Issue 12164
@@ -71,11 +69,9 @@
 mirrors/redirecting_factory_test/02: RuntimeError # Issue 6490
 mirrors/reflected_type_test: RuntimeError # Issue 12607
 mirrors/repeated_private_anon_mixin_app_test: RuntimeError # Issue 14670
-mirrors/removed_api_test: RuntimeError # Issue 14878
 mirrors/static_members_test: CompileTimeError # Issue 14633, Issue 12164
 mirrors/symbol_validation_test: RuntimeError # Issue 13597
 mirrors/toplevel_members_test: CompileTimeError # Issue 14633, Issue 12164
-mirrors/type_argument_is_type_variable_test: RuntimeError # Issue 12333
 mirrors/typedef_test/none: RuntimeError # http://dartbug.com/6490
 mirrors/typedef_metadata_test: RuntimeError # Issue 12785
 mirrors/typevariable_mirror_metadata_test: CompileTimeError # Issue 10905
@@ -85,6 +81,8 @@
 
 [ $runtime == safari ]
 mirrors/return_type_test: Pass, Timeout # Issue 12858
+typed_data/setRange_2_test: Fail # Safari doesn't fully implement spec for TypedArray.set
+typed_data/setRange_3_test: Fail # Safari doesn't fully implement spec for TypedArray.set
 
 [ $compiler == dart2js && $runtime != jsshell && $runtime != safari && $runtime != ff && $runtime != ie9 && $runtime != ie10]
 math/math_test: RuntimeError
@@ -128,6 +126,7 @@
 async/run_zoned8_test: Fail # Timer interface not supported: dartbug.com/7728.
 async/zone_bind_test: Fail # Timer interface not supported: dartbug.com/7728.
 async/future_timeout_test: Fail # Timer interface not supported: dartbug.com/7728.
+async/stream_timeout_test: Fail # Timer interface not supported: dartbug.com/7728.
 
 [ $compiler == dart2js && $checked ]
 convert/utf85_test: Pass, Slow # Issue 12029.
@@ -179,6 +178,9 @@
 [ $runtime == vm ]
 async/timer_not_available_test: Fail, OK
 mirrors/native_class_test: Fail, OK # This test is meant to run in a browser.
+typed_data/setRange_1_test: Fail # Issue 15413
+typed_data/setRange_2_test: Fail # Issue 15413
+typed_data/setRange_3_test: Fail # Issue 15413
 
 [ $compiler == none  ]
 mirrors/hierarchy_test: Fail # TODO(ahe): This test is slightly broken. http://dartbug.com/12464
@@ -192,8 +194,6 @@
 
 mirrors/symbol_validation_test: RuntimeError # Issue 13596
 
-mirrors/removed_api_test: RuntimeError # Issue 14931
-
 mirrors/static_members_test: RuntimeError # Issue 14632
 mirrors/toplevel_members_test: RuntimeError # Issue 14632
 mirrors/instance_members_test: RuntimeError # Issue 14632
@@ -207,6 +207,9 @@
 mirrors/immutable_collections_test: Fail # Issue 11857, Issue 14321
 mirrors/library_uri_io_test: Skip # Not intended for drt as it uses dart:io.
 mirrors/local_isolate_test: Skip # http://dartbug.com/12188
+typed_data/setRange_1_test: Fail # Issue 15413
+typed_data/setRange_2_test: Fail # Issue 15413
+typed_data/setRange_3_test: Fail # Issue 15413
 
 [ $compiler == none && $runtime == drt && $system == windows ]
 async/multiple_timer_test: Fail, Pass # See Issue 10982
@@ -231,8 +234,8 @@
 # Issue 13921: spawnFunction is not allowed on Dartium's DOM thread.
 async/timer_isolate_test: Fail
 
-[ ($compiler != none && $runtime != none) || ($compiler == none && ($runtime != dartium && $runtime != drt)) ]
-async/schedule_microtask_test: Fail # Issue 9001, Issue 9002
+[ $compiler == dart2js ]
+async/schedule_microtask_test: Fail # Issue 9002
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 mirrors/generic_f_bounded_mixin_application_test: CompileTimeError # Issue 14116
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
index bb3b347..28cf084 100644
--- a/tests/lib/math/random_test.dart
+++ b/tests/lib/math/random_test.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.
 
-// Test that a coin toss with Random.nextBool() is fair.
+// Test that rnd.nextInt with a seed generates the same sequence each time.
 
 // Library tag to allow Dartium to run the test.
 library random_test;
@@ -13,42 +13,44 @@
 main() {
   var rnd = new Random(20130307);
   // Make sure we do not break the random number generation.
-  var i = 0;
-  Expect.equals(         1, rnd.nextInt(1 << ++i));
-  Expect.equals(         1, rnd.nextInt(1 << ++i));
-  Expect.equals(         7, rnd.nextInt(1 << ++i));
-  Expect.equals(         6, rnd.nextInt(1 << ++i));
-  Expect.equals(         6, rnd.nextInt(1 << ++i));
-  Expect.equals(        59, rnd.nextInt(1 << ++i));
-  Expect.equals(        11, rnd.nextInt(1 << ++i));
-  Expect.equals(       212, rnd.nextInt(1 << ++i));
-  Expect.equals(        17, rnd.nextInt(1 << ++i));
-  Expect.equals(       507, rnd.nextInt(1 << ++i));
-  Expect.equals(      1060, rnd.nextInt(1 << ++i));
-  Expect.equals(       891, rnd.nextInt(1 << ++i));
-  Expect.equals(      1534, rnd.nextInt(1 << ++i));
-  Expect.equals(      8404, rnd.nextInt(1 << ++i));
-  Expect.equals(     13839, rnd.nextInt(1 << ++i));
-  Expect.equals(     23298, rnd.nextInt(1 << ++i));
-  Expect.equals(     53622, rnd.nextInt(1 << ++i));
-  Expect.equals(    205997, rnd.nextInt(1 << ++i));
-  Expect.equals(    393823, rnd.nextInt(1 << ++i));
-  Expect.equals(    514614, rnd.nextInt(1 << ++i));
-  Expect.equals(    233715, rnd.nextInt(1 << ++i));
-  Expect.equals(    895357, rnd.nextInt(1 << ++i));
-  Expect.equals(   4726185, rnd.nextInt(1 << ++i));
-  Expect.equals(   7976427, rnd.nextInt(1 << ++i));
-  Expect.equals(  31792146, rnd.nextInt(1 << ++i));
-  Expect.equals(  35563210, rnd.nextInt(1 << ++i));
-  Expect.equals( 113261265, rnd.nextInt(1 << ++i));
-  Expect.equals( 205117298, rnd.nextInt(1 << ++i));
-  Expect.equals( 447729735, rnd.nextInt(1 << ++i));
-  Expect.equals(1072507596, rnd.nextInt(1 << ++i));
-  Expect.equals(2134030067, rnd.nextInt(1 << ++i));
-  Expect.equals(721180690, rnd.nextInt(1 << ++i));
-  Expect.equals(32, i);
+  // If the random algorithm changes, make sure both the VM and dart2js
+  // generate the same new sequence.
+  var i = 1;
+  Expect.equals(         1, rnd.nextInt(i *= 2));
+  Expect.equals(         1, rnd.nextInt(i *= 2));
+  Expect.equals(         7, rnd.nextInt(i *= 2));
+  Expect.equals(         6, rnd.nextInt(i *= 2));
+  Expect.equals(         6, rnd.nextInt(i *= 2));
+  Expect.equals(        59, rnd.nextInt(i *= 2));
+  Expect.equals(        11, rnd.nextInt(i *= 2));
+  Expect.equals(       212, rnd.nextInt(i *= 2));
+  Expect.equals(        17, rnd.nextInt(i *= 2));
+  Expect.equals(       507, rnd.nextInt(i *= 2));
+  Expect.equals(      1060, rnd.nextInt(i *= 2));
+  Expect.equals(       891, rnd.nextInt(i *= 2));
+  Expect.equals(      1534, rnd.nextInt(i *= 2));
+  Expect.equals(      8404, rnd.nextInt(i *= 2));
+  Expect.equals(     13839, rnd.nextInt(i *= 2));
+  Expect.equals(     23298, rnd.nextInt(i *= 2));
+  Expect.equals(     53622, rnd.nextInt(i *= 2));
+  Expect.equals(    205997, rnd.nextInt(i *= 2));
+  Expect.equals(    393823, rnd.nextInt(i *= 2));
+  Expect.equals(    514614, rnd.nextInt(i *= 2));
+  Expect.equals(    233715, rnd.nextInt(i *= 2));
+  Expect.equals(    895357, rnd.nextInt(i *= 2));
+  Expect.equals(   4726185, rnd.nextInt(i *= 2));
+  Expect.equals(   7976427, rnd.nextInt(i *= 2));
+  Expect.equals(  31792146, rnd.nextInt(i *= 2));
+  Expect.equals(  35563210, rnd.nextInt(i *= 2));
+  Expect.equals( 113261265, rnd.nextInt(i *= 2));
+  Expect.equals( 205117298, rnd.nextInt(i *= 2));
+  Expect.equals( 447729735, rnd.nextInt(i *= 2));
+  Expect.equals(1072507596, rnd.nextInt(i *= 2));
+  Expect.equals(2134030067, rnd.nextInt(i *= 2));
+  Expect.equals( 721180690, rnd.nextInt(i *= 2));
+  Expect.equals(0x100000000, i);
   // If max is too large expect an ArgumentError.
-  Expect.throws(() => rnd.nextInt((1 << i)+1), (e) => e is ArgumentError);
+  Expect.throws(() => rnd.nextInt(i + 1), (e) => e is ArgumentError);
 
   rnd = new Random(6790);
   Expect.approxEquals(0.7360144236, rnd.nextDouble());
diff --git a/tests/lib/mirrors/equality_test.dart b/tests/lib/mirrors/equality_test.dart
index b99c311..af15ca9 100644
--- a/tests/lib/mirrors/equality_test.dart
+++ b/tests/lib/mirrors/equality_test.dart
@@ -32,7 +32,7 @@
     equivalenceClass.forEach((name, member) {
       equivalenceClass.forEach((otherName, otherMember) {
         // Reflexivity, symmetry and transitivity.
-        Expect.equals(member, 
+        Expect.equals(member,
                       otherMember,
                       "$name == $otherName");
         Expect.equals(member.hashCode,
@@ -112,27 +112,29 @@
      'reflect(new A<int>()).type.originalDeclaration' :
           reflect(new A<int>()).type.originalDeclaration},
 
-    {'reflectClass(B).superclass' : reflectClass(B).superclass,  /// 02: ok
-     'reflect(new A<int>()).type' : reflect(new A<int>()).type}, /// 02: ok
+    {'reflectClass(B).superclass' : reflectClass(B).superclass,
+     'reflect(new A<int>()).type' : reflect(new A<int>()).type},
 
     {'reflectClass(B)' : reflectClass(B),
      'thisLibrary.declarations[#B]' : thisLibrary.declarations[#B],
      'reflect(new B()).type' : reflect(new B()).type},
 
-    {'reflectClass(BadEqualityHash).declarations[#==]'  /// 02: ok
-        : reflectClass(BadEqualityHash).declarations[#==],  /// 02: ok
-     'reflect(new BadEqualityHash()).type.declarations[#==]'  /// 02: ok
-        : reflect(new BadEqualityHash()).type.declarations[#==]},  /// 02: ok
+    {'reflectClass(BadEqualityHash).declarations[#==]'
+        : reflectClass(BadEqualityHash).declarations[#==],
+     'reflect(new BadEqualityHash()).type.declarations[#==]'
+        : reflect(new BadEqualityHash()).type.declarations[#==]},
 
-    {'reflectClass(BadEqualityHash).declarations[#==].parameters[0]'  /// 02: ok
-        : (reflectClass(BadEqualityHash).declarations[#==] as MethodMirror).parameters[0],  /// 02: ok
-     'reflect(new BadEqualityHash()).type.declarations[#==].parameters[0]'  /// 02: ok
-        : (reflect(new BadEqualityHash()).type.declarations[#==] as MethodMirror).parameters[0]},  /// 02: ok
+    {'reflectClass(BadEqualityHash).declarations[#==].parameters[0]'
+        : (reflectClass(BadEqualityHash).
+            declarations[#==] as MethodMirror).parameters[0],
+     'reflect(new BadEqualityHash()).type.declarations[#==].parameters[0]'
+        : (reflect(new BadEqualityHash()).type.
+            declarations[#==] as MethodMirror).parameters[0]},
 
-    {'reflectClass(BadEqualityHash).declarations[#count]'  /// 02: ok
-        : reflectClass(BadEqualityHash).declarations[#count],  /// 02: ok
-     'reflect(new BadEqualityHash()).type.declarations[#count]'  /// 02: ok
-        : reflect(new BadEqualityHash()).type.declarations[#count]},  /// 02: ok
+    {'reflectClass(BadEqualityHash).declarations[#count]'
+        : reflectClass(BadEqualityHash).declarations[#count],
+     'reflect(new BadEqualityHash()).type.declarations[#count]'
+        : reflect(new BadEqualityHash()).type.declarations[#count]},
 
     {'reflectType(Predicate)' : reflectType(Predicate),  /// 02: ok
      'thisLibrary.declarations[#somePredicate].type'  /// 02: ok
@@ -142,10 +144,10 @@
      'thisLibrary.declarations[#somePredicate].type.referent'  /// 02: ok
         : ((thisLibrary.declarations[#somePredicate] as VariableMirror).type as TypedefMirror).referent},  /// 02: ok
 
-    {'reflectClass(A).typeVariables.single'  /// 02: ok
-        : reflectClass(A).typeVariables.single,  /// 02: ok
-     'reflect(new A<int>()).type.originalDeclaration.typeVariables.single'  /// 02: ok
-        : reflect(new A<int>()).type.originalDeclaration.typeVariables.single},  /// 02: ok
+    {'reflectClass(A).typeVariables.single'
+        : reflectClass(A).typeVariables.single,
+     'reflect(new A<int>()).type.originalDeclaration.typeVariables.single'
+        : reflect(new A<int>()).type.originalDeclaration.typeVariables.single},
 
     {'currentMirrorSystem()' : currentMirrorSystem()},
 
diff --git a/tests/lib/mirrors/generics_substitution_test.dart b/tests/lib/mirrors/generics_substitution_test.dart
index 58a0269..de13f2e 100644
--- a/tests/lib/mirrors/generics_substitution_test.dart
+++ b/tests/lib/mirrors/generics_substitution_test.dart
@@ -36,20 +36,20 @@
   Symbol t(ClassMirror cm) =>
       (cm.declarations[#t] as MethodMirror).returnType.simpleName;
 
-  Expect.equals(#T, r(genericDecl.superclass)); /// 01: ok
+  Expect.equals(#T, r(genericDecl.superclass));
   Expect.equals(#int, s(genericDecl.superclass));
   Expect.equals(#T, t(genericDecl));
 
-  Expect.equals(#String, r(genericOfString.superclass)); /// 01: ok
+  Expect.equals(#String, r(genericOfString.superclass));
   Expect.equals(#int, s(genericOfString.superclass));
   Expect.equals(#String, t(genericOfString));
 
-  Expect.equals(#R, r(superGenericDecl)); /// 01: ok
+  Expect.equals(#R, r(superGenericDecl));
   Expect.equals(#S, s(superGenericDecl));
 
-  Expect.equals(#T, r(superOfTAndInt)); /// 01: ok
+  Expect.equals(#T, r(superOfTAndInt));
   Expect.equals(#int, s(superOfTAndInt));
 
-  Expect.equals(#String, r(superOfStringAndInt)); /// 01: ok
+  Expect.equals(#String, r(superOfStringAndInt));
   Expect.equals(#int, s(superOfStringAndInt));
 }
diff --git a/tests/lib/typed_data/setRange_1_test.dart b/tests/lib/typed_data/setRange_1_test.dart
new file mode 100644
index 0000000..ea7d6dc
--- /dev/null
+++ b/tests/lib/typed_data/setRange_1_test.dart
@@ -0,0 +1,16 @@
+// 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 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+sameTypeTest() {
+  checkSameSize(makeInt16List, makeInt16View, makeInt16View);
+  checkSameSize(makeUint16List, makeUint16View, makeUint16View);
+}
+
+main() {
+  sameTypeTest();
+}
diff --git a/tests/lib/typed_data/setRange_2_test.dart b/tests/lib/typed_data/setRange_2_test.dart
new file mode 100644
index 0000000..83abbba
--- /dev/null
+++ b/tests/lib/typed_data/setRange_2_test.dart
@@ -0,0 +1,17 @@
+// 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 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+sameElementSizeTest() {
+  // Views of elements with the same size but different 'types'.
+  checkSameSize(makeInt16List, makeInt16View, makeUint16View);
+  checkSameSize(makeInt16List, makeUint16View, makeInt16View);
+}
+
+main() {
+  sameElementSizeTest();
+}
diff --git a/tests/lib/typed_data/setRange_3_test.dart b/tests/lib/typed_data/setRange_3_test.dart
new file mode 100644
index 0000000..9774811
--- /dev/null
+++ b/tests/lib/typed_data/setRange_3_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'setRange_lib.dart';
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+expandContractTest() {
+  // Copying between views that have different element sizes can't be done with
+  // a single scan-up or scan-down.
+  //
+  // Typed lists a1 and a2 share a buffer as follows:
+  //
+  // a1:  aaaabbbbccccddddeeeeffffgggghhhh
+  // a2:              abcdefgh
+
+  var a1 = new Int32List(8);
+  var buffer = a1.buffer;
+  var a2 = new Int8List.view(buffer, 12, 8);
+
+  initialize(a2);
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a2');
+  a1.setRange(0, 8, a2);
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a1');
+
+  initialize(a1);
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a1');
+  a2.setRange(0, 8, a1);
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8]', '$a2');
+}
+
+main() {
+  expandContractTest();
+}
diff --git a/tests/lib/typed_data/setRange_lib.dart b/tests/lib/typed_data/setRange_lib.dart
new file mode 100644
index 0000000..bcdd302
--- /dev/null
+++ b/tests/lib/typed_data/setRange_lib.dart
@@ -0,0 +1,65 @@
+// 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 setRange_lib;
+
+import 'package:expect/expect.dart';
+import 'dart:typed_data';
+
+initialize(a) {
+  for (int i = 0; i < a.length; i++) {
+    a[i] = i + 1;
+  }
+}
+
+makeInt16View(buffer, byteOffset, length) =>
+    new Int16List.view(buffer, byteOffset, length);
+
+makeUint16View(buffer, byteOffset, length) =>
+    new Uint16List.view(buffer, byteOffset, length);
+
+makeInt16List(length) => new Int16List(length);
+makeUint16List(length) => new Uint16List(length);
+
+checkSameSize(constructor0, constructor1, constructor2) {
+  // Typed lists a1 and a2 share a buffer as follows (bytes):
+  //
+  //  a0:  aabbccddeeffgghhii
+  //  a1:  aabbccddeeffgg
+  //  a2:      aabbccddeeffgg
+
+  var a0 = constructor0(9);
+  var buffer = a0.buffer;
+  var a1 = constructor1(buffer, 0, 7);
+  var a2 = constructor2(buffer, 2 * a0.elementSizeInBytes, 7);
+
+  initialize(a0);
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7, 8, 9]', '$a0');
+  Expect.equals('[1, 2, 3, 4, 5, 6, 7]', '$a1');
+  Expect.equals('[3, 4, 5, 6, 7, 8, 9]', '$a2');
+
+  initialize(a0);
+  a1.setRange(0, 7, a2);
+  Expect.equals('[3, 4, 5, 6, 7, 8, 9, 8, 9]', '$a0');
+
+  initialize(a0);
+  a2.setRange(0, 7, a1);
+  Expect.equals('[1, 2, 1, 2, 3, 4, 5, 6, 7]', '$a0');
+
+  initialize(a0);
+  a1.setRange(1, 7, a2);
+  Expect.equals('[1, 3, 4, 5, 6, 7, 8, 8, 9]', '$a0');
+
+  initialize(a0);
+  a2.setRange(1, 7, a1);
+  Expect.equals('[1, 2, 3, 1, 2, 3, 4, 5, 6]', '$a0');
+
+  initialize(a0);
+  a1.setRange(0, 6, a2, 1);
+  Expect.equals('[4, 5, 6, 7, 8, 9, 7, 8, 9]', '$a0');
+
+  initialize(a0);
+  a2.setRange(0, 6, a1, 1);
+  Expect.equals('[1, 2, 2, 3, 4, 5, 6, 7, 9]', '$a0');
+}
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
index f813e3b..075115e 100644
--- a/tests/standalone/debugger/debug_lib.dart
+++ b/tests/standalone/debugger/debug_lib.dart
@@ -184,8 +184,9 @@
 class FrameMatcher extends Command {
   int frameIndex;
   List<String> functionNames;
+  bool exactMatch;
 
-  FrameMatcher(this.frameIndex, this.functionNames) {
+  FrameMatcher(this.frameIndex, this.functionNames, this.exactMatch) {
     template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
   }
 
@@ -211,7 +212,9 @@
       var idx = i + frameIndex;
       var name = frames[idx]["functionName"];
       assert(name != null);
-      if (name != functionNames[i]) {
+      bool isMatch = exactMatch ? name == functionNames[i]
+                                : name.contains(functionNames[i]);
+      if (!isMatch) {
         debugger.error("Error: call frame $idx: "
           "expected function name '${functionNames[i]}' but found '$name'");
         return;
@@ -221,12 +224,12 @@
 }
 
 
-MatchFrame(int frameIndex, String functionName) {
-  return new FrameMatcher(frameIndex, [ functionName ]);
+MatchFrame(int frameIndex, String functionName, {exactMatch: false}) {
+  return new FrameMatcher(frameIndex, [functionName], exactMatch);
 }
 
-MatchFrames(List<String> functionNames) {
-  return new FrameMatcher(0, functionNames);
+MatchFrames(List<String> functionNames, {exactMatch: false}) {
+  return new FrameMatcher(0, functionNames, exactMatch);
 }
 
 
diff --git a/tests/standalone/debugger/mixin_closure_debugger_test.dart b/tests/standalone/debugger/mixin_closure_debugger_test.dart
new file mode 100644
index 0000000..5e6fd5e
--- /dev/null
+++ b/tests/standalone/debugger/mixin_closure_debugger_test.dart
@@ -0,0 +1,54 @@
+// 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.
+
+// This test forks a second vm process that runs this dart script as
+// a debug target.
+// Run this test with option --wire to see the json messages sent
+// between the processes.
+// Run this test with option --verbose to see the stdout and stderr output
+// of the debug target process.
+
+// This test checks that a breakpoint can be set and is hit in a closure
+// inside a mixin function. Regression test for issue 15325.
+
+import "debug_lib.dart";
+
+class S { }
+
+class M {
+  m()  {
+    var sum = 0;
+    [1,2,3].forEach((e) {
+      sum += e;  // Breakpoint here.
+    });
+    return sum;
+  }
+}
+
+class A = S with M;
+
+main(List<String> arguments) {
+  if (RunScript(testScript, arguments)) return;
+  var a = new A();
+  print(a.m());
+}
+
+// Expected debugger events and commands.
+var testScript = [
+  MatchFrame(0, "main"),  // Top frame in trace is function "main".
+  SetBreakpoint(23),      // Set breakpoint inside the forEach closure.
+  Resume(),
+  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+              exactMatch: false),  // First iteration.
+  MatchLocals({"e": "1"}),
+  Resume(),
+  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+              exactMatch: false),  // Second iteration.
+  MatchLocals({"e": "2"}),
+  Resume(),
+  MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
+              exactMatch: false),  // Third iteration.
+  MatchLocals({"e": "3"}),
+  Resume(),
+];
diff --git a/tests/standalone/io/http_server_test.dart b/tests/standalone/io/http_server_test.dart
index 00dc5cd..b406f7f 100644
--- a/tests/standalone/io/http_server_test.dart
+++ b/tests/standalone/io/http_server_test.dart
@@ -60,6 +60,57 @@
   });
 }
 
+
+void testHttpServerZone() {
+  asyncStart();
+  Expect.equals(Zone.ROOT, Zone.current);
+  runZoned(() {
+    Expect.notEquals(Zone.ROOT, Zone.current);
+    HttpServer.bind("127.0.0.1", 0).then((server) {
+      Expect.notEquals(Zone.ROOT, Zone.current);
+      server.listen((request) {
+        Expect.notEquals(Zone.ROOT, Zone.current);
+        request.response.close();
+        server.close();
+      });
+      new HttpClient().get("127.0.0.1", server.port, '/')
+        .then((request) => request.close())
+        .then((response) => response.drain())
+        .then((_) => asyncEnd());
+    });
+  });
+}
+
+
+void testHttpServerZoneError() {
+  asyncStart();
+  Expect.equals(Zone.ROOT, Zone.current);
+  runZoned(() {
+    Expect.notEquals(Zone.ROOT, Zone.current);
+    HttpServer.bind("127.0.0.1", 0).then((server) {
+      Expect.notEquals(Zone.ROOT, Zone.current);
+      server.listen((request) {
+        Expect.notEquals(Zone.ROOT, Zone.current);
+        request.listen((_) {}, onError: (error) {
+          Expect.notEquals(Zone.ROOT, Zone.current);
+          server.close();
+          throw error;
+        });
+      });
+      Socket.connect("127.0.0.1", server.port).then((socket) {
+        socket.write('GET / HTTP/1.1\r\nContent-Length: 100\r\n\r\n');
+        socket.write('some body');
+        socket.close();
+      });
+    });
+  }, onError: (e) {
+    asyncEnd();
+  });
+}
+
+
 void main() {
   testListenOn();
+  testHttpServerZone();
+  testHttpServerZoneError();
 }
diff --git a/tests/standalone/io/network_interface_test.dart b/tests/standalone/io/network_interface_test.dart
index ee6a25e..2d49ce0 100644
--- a/tests/standalone/io/network_interface_test.dart
+++ b/tests/standalone/io/network_interface_test.dart
@@ -33,7 +33,21 @@
 }
 
 
+void testListIndex() {
+  var set = new Set();
+  NetworkInterface.list(includeLoopback: true).then((list) {
+    for (var i in list) {
+      Expect.isNotNull(i.index);
+      Expect.isFalse(set.contains(i.index));
+      set.add(i.index);
+      Expect.isTrue(set.contains(i.index));
+    }
+  });
+}
+
+
 void main() {
   testListLoopback();
   testListLinkLocal();
+  testListIndex();
 }
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
index 53a5e02..ddf5611 100644
--- a/tests/standalone/io/raw_socket_test.dart
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -376,6 +376,63 @@
   });
 }
 
+void testSocketZone() {
+  asyncStart();
+  Expect.equals(Zone.ROOT, Zone.current);
+  runZoned(() {
+    Expect.notEquals(Zone.ROOT, Zone.current);
+    RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
+      Expect.notEquals(Zone.ROOT, Zone.current);
+      server.listen((socket) {
+        Expect.notEquals(Zone.ROOT, Zone.current);
+        socket.close();
+        server.close();
+      });
+      RawSocket.connect("127.0.0.1", server.port).then((socket) {
+        socket.listen((event) {
+          if (event == RawSocketEvent.READ_CLOSED) {
+            socket.close();
+            asyncEnd();
+          }
+        });
+      });
+    });
+  });
+}
+
+void testSocketZoneError() {
+  asyncStart();
+  Expect.equals(Zone.ROOT, Zone.current);
+  runZoned(() {
+    Expect.notEquals(Zone.ROOT, Zone.current);
+    RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
+      Expect.notEquals(Zone.ROOT, Zone.current);
+      server.listen((socket) {
+        Expect.notEquals(Zone.ROOT, Zone.current);
+        var timer;
+        void write() {
+          socket.write(const [0]);
+          timer = new Timer(const Duration(milliseconds: 5), write);
+        }
+        write();
+        socket.listen((_) {
+        }, onError: (error) {
+          timer.cancel();
+          Expect.notEquals(Zone.ROOT, Zone.current);
+          socket.close();
+          server.close();
+          throw error;
+        });
+      });
+      RawSocket.connect("127.0.0.1", server.port).then((socket) {
+        socket.close();
+      });
+    });
+  }, onError: (e) {
+    asyncEnd();
+  });
+}
+
 main() {
   asyncStart();
   testArguments();
@@ -389,5 +446,7 @@
   testSimpleReadWrite(dropReads: true);
   testPauseServerSocket();
   testPauseSocket();
+  testSocketZone();
+  testSocketZoneError();
   asyncEnd();
 }
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index b66f951..c9a30bc 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -54,7 +54,7 @@
   get hashCode => throw 'Interceptor.hashCode not implemented.';
 }
 class JSIndexable {
-  get length;
+  get length {}
 }
 class JSMutableIndexable {}
 class JSArray<E> implements JSIndexable {
diff --git a/tools/VERSION b/tools/VERSION
index ef56901..0795e2b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,5 +1,5 @@
 CHANNEL dev
 MAJOR 1
 MINOR 0
-BUILD 2
-PATCH 1
+BUILD 3
+PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 0ed83e6..f54685e 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -144,7 +144,8 @@
                 '--time',
                 '--use-sdk',
                 '--report',
-                '--write-debug-log'])
+                '--write-debug-log',
+                '--write-test-outcome-log'])
 
     if user_test == 'yes':
       cmd.append('--progress=color')
diff --git a/tools/bots/cross-vm.py b/tools/bots/cross-vm.py
index 08ae335..691544c 100644
--- a/tools/bots/cross-vm.py
+++ b/tools/bots/cross-vm.py
@@ -70,7 +70,7 @@
   test_py = os.path.join('tools', 'test.py')
   test_args = [sys.executable, test_py, '--progress=line', '--report',
                '--time', '--compiler=none', '--runtime=vm', '--write-debug-log',
-               '--mode=' + mode, '--arch=' + arch]
+               '--write-test-outcome-log', '--mode=' + mode, '--arch=' + arch]
 
   revision = int(os.environ['BUILDBOT_GOT_REVISION'])
   tarball = tarball_name(arch, mode, revision)
@@ -87,7 +87,7 @@
       run(test_args)
 
     with bot.BuildStep('execute checked_tests'):
-      run(test_args + ['--checked'])
+      run(test_args + ['--checked', '--append_logs'])
   finally:
     for path in temporary_files:
       if os.path.exists(path):
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
index 4248459..918218f 100644
--- a/tools/ddbg.dart
+++ b/tools/ddbg.dart
@@ -8,6 +8,7 @@
 import "dart:convert";
 import "dart:io";
 import "dart:async";
+import "dart:math";
 
 import "ddbg/lib/commando.dart";
 
@@ -26,11 +27,14 @@
 
 Socket vmSock;
 String vmData;
+var cmdSubscription;
 Commando cmdo;
 var vmSubscription;
 int seqNum = 0;
 
-Process targetProcess;
+bool isDebugging = false;
+Process targetProcess = null;
+bool suppressNextExitCode = false;
 
 final verbose = false;
 final printMessages = false;
@@ -38,38 +42,7 @@
 TargetIsolate currentIsolate;
 TargetIsolate mainIsolate;
 
-
-void printHelp() {
-  print("""
-  q   Quit debugger shell
-  bt  Show backtrace
-  r   Resume execution
-  s   Single step
-  so  Step over
-  si  Step into
-  sbp [<file>] <line> Set breakpoint
-  rbp <id> Remove breakpoint with given id
-  po <id> Print object info for given id
-  eval obj <id> <expr> Evaluate expr on object id
-  eval cls <id> <expr> Evaluate expr on class id
-  eval lib <id> <expr> Evaluate expr in toplevel of library id
-  pl <id> <idx> [<len>] Print list element/slice
-  pc <id> Print class info for given id
-  ll  List loaded libraries
-  plib <id> Print library info for given library id
-  slib <id> <true|false> Set library id debuggable
-  pg <id> Print all global variables visible within given library id
-  ls <lib_id> List loaded scripts in library
-  gs <lib_id> <script_url> Get source text of script in library
-  tok <lib_id> <script_url> Get line and token table of script in library
-  epi <none|all|unhandled>  Set exception pause info
-  li List ids of all isolates in the VM
-  sci <id>  Set current target isolate
-  i <id> Interrupt execution of given isolate id
-  h   Print help
-""");
-}
-
+int debugPort = 5858;
 
 String formatLocation(Map location) {
   if (location == null) return "";
@@ -78,13 +51,6 @@
 }
 
 
-void quitShell() {
-  vmSubscription.cancel();
-  vmSock.close();
-  cmdo.done();
-}
-
-
 Future sendCmd(Map<String, dynamic> cmd) {
   var completer = new Completer.sync();
   int id = cmd["id"];
@@ -113,23 +79,427 @@
   return false;
 }
 
+// These settings are allowed in the 'set' and 'show' debugger commands.
+var validSettings = ['vm', 'vmargs', 'script', 'args'];
+
+// The current values for all settings.
+var settings = new Map();
+
+// Generates a string of 'count' spaces.
+String _spaces(int count) {
+  return new List.filled(count, ' ').join('');
+}
+
+// TODO(turnidge): Move all commands here.
+List<Command> commandList =
+    [ new HelpCommand(),
+      new QuitCommand(),
+      new RunCommand(),
+      new KillCommand(),
+      new ConnectCommand(),
+      new DisconnectCommand(),
+      new SetCommand(),
+      new ShowCommand() ];
+
+
+Command matchCommand(String commandName, bool exactMatchWins) {
+  List matches = [];
+  for (var command in commandList) {
+    if (command.name.startsWith(commandName)) {
+      if (exactMatchWins && command.name == commandName) {
+        // Exact match
+        return [command];
+      } else {
+        matches.add(command);
+      }
+    }
+  }
+  return matches;
+}
+
+abstract class Command {
+  String get name;
+  Future run(List<String> args);
+}
+
+class HelpCommand extends Command {
+  final name = 'help';
+  final helpShort = 'Show a list of debugger commands';
+  final helpLong ="""
+Show a list of debugger commands or get more information about a
+particular command.
+
+Usage:
+  help
+  help <command>
+""";
+
+  Future run(List<String> args) {
+    if (args.length == 1) {
+      print("Debugger commands:\n");
+      for (var command in commandList) {
+        const tabStop = 12;
+        var spaces = _spaces(max(1, (tabStop - command.name.length)));
+        print('  ${command.name}${spaces}${command.helpShort}');
+      }
+
+      // TODO(turnidge): Convert all commands to use the Command class.
+      print("""
+  bt          Show backtrace
+  r           Resume execution
+  s           Single step
+  so          Step over
+  si          Step into
+  sbp [<file>] <line> Set breakpoint
+  rbp <id>    Remove breakpoint with given id
+  po <id>     Print object info for given id
+  eval obj <id> <expr> Evaluate expr on object id
+  eval cls <id> <expr> Evaluate expr on class id
+  eval lib <id> <expr> Evaluate expr in toplevel of library id
+  pl <id> <idx> [<len>] Print list element/slice
+  pc <id>     Print class info for given id
+  ll          List loaded libraries
+  plib <id>   Print library info for given library id
+  slib <id> <true|false> Set library id debuggable
+  pg <id>     Print all global variables visible within given library id
+  ls <lib_id> List loaded scripts in library
+  gs <lib_id> <script_url> Get source text of script in library
+  tok <lib_id> <script_url> Get line and token table of script in library
+  epi <none|all|unhandled>  Set exception pause info
+  li          List ids of all isolates in the VM
+  sci <id>    Set current target isolate
+  i <id>      Interrupt execution of given isolate id
+""");
+
+      print("For more information about a particular command, type:\n\n"
+            "  help <command>\n");
+
+      print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
+    } else if (args.length == 2) {
+      var commandName = args[1];
+      var matches = matchCommand(commandName, true);
+      if (matches.length == 0) {
+        print("Command '$commandName' not recognized.  "
+              "Try 'help' for a list of commands.");
+      } else {
+        for (var command in matches) {
+          print("---- ${command.name} ----\n${command.helpLong}");
+        }
+      }
+    } else {
+      print("Command '$command' not recognized.  "
+            "Try 'help' for a list of commands.");
+    }
+
+    return new Future.value();
+  }
+}
+
+
+class QuitCommand extends Command {
+  final name = 'quit';
+  final helpShort = 'Quit the debugger.';
+  final helpLong ="""
+Quit the debugger.
+
+Usage:
+  quit
+""";
+
+  Future run(List<String> args) {
+    if (args.length > 1) {
+      print("Unexpected arguments to $name command.");
+      return new Future.value();
+    }
+    return debuggerQuit();
+  }
+}
+
+class SetCommand extends Command {
+  final name = 'set';
+  final helpShort = 'Change the value of a debugger setting.';
+  final helpLong ="""
+Change the value of a debugger setting.
+
+Usage:
+  set <setting> <value>
+
+Valid settings are:
+  ${validSettings.join('\n  ')}.
+
+See also 'help show'.
+""";
+
+  Future run(List<String> args) {
+    if (args.length < 3 || !validSettings.contains(args[1])) {
+      print("Undefined $name command.  Try 'help $name'.");
+      return new Future.value();
+    }
+    var option = args[1];
+    var value = args.getRange(2, args.length).join(' ');
+    settings[option] = value;
+    return new Future.value();
+  }
+}
+
+class ShowCommand extends Command {
+  final name = 'show';
+  final helpShort = 'Show the current value of a debugger setting.';
+  final helpLong ="""
+Show the current value of a debugger setting.
+
+Usage:
+  show
+  show <setting>
+
+If no <setting> is specified, all current settings are shown.
+
+Valid settings are:
+  ${validSettings.join('\n  ')}.
+
+See also 'help set'.
+""";
+
+  Future run(List<String> args) {
+    if (args.length == 1) {
+      for (var option in validSettings) {
+        var value = settings[option];
+        print("$option = '$value'");
+      }
+    } else if (args.length == 2 && validSettings.contains(args[1])) {
+      var option = args[1];
+      var value = settings[option];
+      if (value == null) {
+        print('$option has not been set.');
+      } else {
+        print("$option = '$value'");
+      }
+      return new Future.value();
+    } else {
+      print("Undefined $name command.  Try 'help $name'.");
+    }
+    return new Future.value();
+  }
+}
+
+class RunCommand extends Command {
+  final name = 'run';
+  final helpShort = "Run the currrent script.";
+  final helpLong ="""
+Runs the current script.
+
+Usage:
+  run
+  run <args>
+
+The current script will be run on the current vm.  The 'vm' and
+'vmargs' settings are used to specify the current vm and vm arguments.
+The 'script' and 'args' settings are used to specify the current
+script and script arguments.
+
+For more information on settings type 'help show' or 'help set'.
+
+If <args> are provided to the run command, it is the same as typing
+'set args <args>' followed by 'run'.
+""";
+
+  Future run(List<String> cmdArgs) {
+    if (isDebugging) {
+      // TODO(turnidge): Implement modal y/n dialog to stop running script.
+      print("There is already a running dart process.  "
+            "Try 'kill'.");
+      return new Future.value();
+    }
+    assert(targetProcess == null);
+    if (settings['script'] == null) {
+      print("There is no script specified.  "
+            "Use 'set script' to set the current script.");
+      return new Future.value();
+    }
+    if (cmdArgs.length > 1) {
+      settings['args'] = cmdArgs.getRange(1, cmdArgs.length);
+    }
+
+    // Build the process arguments.
+    var processArgs = ['--debug:$debugPort'];
+    if (verbose) {
+      processArgs.add('--verbose_debug');
+    }
+    if (settings['vmargs'] != null) {
+      processArgs.addAll(settings['vmargs'].split(' '));
+    }
+    processArgs.add(settings['script']);
+    if (settings['args'] != null) {
+      processArgs.addAll(settings['args'].split(' '));
+    }
+    String vm = settings['vm'];
+
+    isDebugging = true;
+    cmdo.hide();
+    return Process.start(vm, processArgs).then((Process process) {
+        print("Started process ${process.pid} '$vm ${processArgs.join(' ')}'");
+        targetProcess = process;
+        process.stdin.close();
+
+        // TODO(turnidge): For now we only show full lines of output
+        // from the debugged process.  Should show each character.
+        process.stdout
+            .transform(UTF8.decoder)
+            .transform(new LineSplitter())
+            .listen((String line) {
+                cmdo.hide();
+                // TODO(turnidge): Escape output in any way?
+                print(line);
+                cmdo.show();
+              });
+
+        process.stderr
+            .transform(UTF8.decoder)
+            .transform(new LineSplitter())
+            .listen((String line) {
+                cmdo.hide();
+                print(line);
+                cmdo.show();
+              });
+
+        process.exitCode.then((int exitCode) {
+            cmdo.hide();
+            if (suppressNextExitCode) {
+              suppressNextExitCode = false;
+            } else {
+              if (exitCode == 0) {
+                print('Process exited normally.');
+              } else {
+                print('Process exited with code $exitCode.');
+              }
+            }
+            targetProcess = null;
+            cmdo.show();
+          });
+
+        // Wait for the vm to open the debugging port.
+        return openVmSocket(0);
+      });
+  }
+}
+
+class KillCommand extends Command {
+  final name = 'kill';
+  final helpShort = 'Kill the currently executing script.';
+  final helpLong ="""
+Kill the currently executing script.
+
+Usage:
+  kill
+""";
+
+  Future run(List<String> cmdArgs) {
+    if (!isDebugging) {
+      print('There is no running script.');
+      return new Future.value();
+    }
+    if (targetProcess == null) {
+      print("The active dart process was not started with 'run'. "
+            "Try 'disconnect' instead.");
+      return new Future.value();
+    }
+    assert(targetProcess != null);
+    bool result = targetProcess.kill();
+    if (result) {
+      print('Process killed.');
+      suppressNextExitCode = true;
+    } else {
+      print('Unable to kill process ${targetProcess.pid}');
+    }
+    return new Future.value();
+  }
+}
+
+class ConnectCommand extends Command {
+  final name = 'connect';
+  final helpShort = "Connect to a running dart script.";
+  final helpLong ="""
+Connect to a running dart script.
+
+Usage:
+  connect
+  connect <port>
+
+The debugger will connect to a dart script which has already been
+started with the --debug option.  If no port is provided, the debugger
+will attempt to connect on the default debugger port.
+""";
+
+  Future run(List<String> cmdArgs) {
+    if (cmdArgs.length > 2) {
+      print("Too many arguments to 'connect'.");
+    }
+    if (isDebugging) {
+      // TODO(turnidge): Implement modal y/n dialog to stop running script.
+      print("There is already a running dart process.  "
+            "Try 'kill'.");
+      return new Future.value();
+    }
+    assert(targetProcess == null);
+    if (cmdArgs.length == 2) {
+      debugPort = int.parse(cmdArgs[1]);
+    }
+
+    isDebugging = true;
+    cmdo.hide();
+    return openVmSocket(0);
+  }
+}
+
+class DisconnectCommand extends Command {
+  final name = 'disconnect';
+  final helpShort = "Disconnect from a running dart script.";
+  final helpLong ="""
+Disconnect from a running dart script.
+
+Usage:
+  disconnect
+
+The debugger will disconnect from a dart script's debugging port.  The
+script must have been connected to earlier with the 'connect' command.
+""";
+
+  Future run(List<String> cmdArgs) {
+    if (cmdArgs.length > 1) {
+      print("Too many arguments to 'disconnect'.");
+    }
+    if (!isDebugging) {
+      // TODO(turnidge): Implement modal y/n dialog to stop running script.
+      print("There is no active dart process.  "
+            "Try 'connect'.");
+      return new Future.value();
+    }
+    if (targetProcess != null) {
+      print("The active dart process was started with 'run'.  "
+            "Try 'kill'.");
+    }
+
+    cmdo.hide();
+    return closeVmSocket();
+  }
+}
+
 typedef void HandlerType(Map response);
 
 HandlerType showPromptAfter(void handler(Map response)) {
-  // Hide the command prompt immediately.
   return (response) {
     handler(response);
     cmdo.show();
   };
 }
 
-
 void processCommand(String cmdLine) {
   
   void huh() {
-    print("'$cmdLine' not understood, try h for help");
+    print("'$cmdLine' not understood, try 'help' for help.");
   }
 
+  cmdo.hide();
   seqNum++;
   cmdLine = cmdLine.trim();
   var args = cmdLine.split(' ');
@@ -137,6 +507,7 @@
     return;
   }
   var command = args[0];
+
   var resume_commands =
       { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
   if (resume_commands[command] != null) {
@@ -144,19 +515,16 @@
     var cmd = { "id": seqNum,
                 "command": resume_commands[command],
                 "params": { "isolateId" : currentIsolate.id } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
   } else if (command == "bt") {
     var cmd = { "id": seqNum,
                 "command": "getStackTrace",
                 "params": { "isolateId" : currentIsolate.id } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
   } else if (command == "ll") {
     var cmd = { "id": seqNum,
                 "command": "getLibraries",
                 "params": { "isolateId" : currentIsolate.id } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
   } else if (command == "sbp" && args.length >= 2) {
     var url, line;
@@ -173,21 +541,18 @@
                 "params": { "isolateId" : currentIsolate.id,
                             "url": url,
                             "line": line }};
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
   } else if (command == "rbp" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "removeBreakpoint",
                 "params": { "isolateId" : currentIsolate.id,
                             "breakpointId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
   } else if (command == "ls" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "getScriptURLs",
                 "params": { "isolateId" : currentIsolate.id,
                             "libraryId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
   } else if (command == "eval" && args.length > 3) {
     var expr = args.getRange(3, args.length).join(" ");
@@ -207,14 +572,12 @@
                 "params": { "isolateId": currentIsolate.id,
                             target: int.parse(args[2]),
                             "expression": expr } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
   } else if (command == "po" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "getObjectProperties",
                 "params": { "isolateId" : currentIsolate.id,
                             "objectId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
   } else if (command == "pl" && args.length >= 3) {
     var cmd;
@@ -232,21 +595,18 @@
                           "index": int.parse(args[2]),
                           "length": int.parse(args[3]) } };
     }
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
   } else if (command == "pc" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "getClassProperties",
                 "params": { "isolateId" : currentIsolate.id,
                             "classId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
   } else if (command == "plib" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "getLibraryProperties",
                 "params": {"isolateId" : currentIsolate.id,
                            "libraryId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
   } else if (command == "slib" && args.length == 3) {
     var cmd = { "id": seqNum,
@@ -254,14 +614,12 @@
                 "params": {"isolateId" : currentIsolate.id,
                            "libraryId": int.parse(args[1]),
                            "debuggingEnabled": args[2] } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
   } else if (command == "pg" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "getGlobalVariables",
                 "params": { "isolateId" : currentIsolate.id,
                             "libraryId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
   } else if (command == "gs" && args.length == 3) {
     var cmd = { "id": seqNum,
@@ -269,7 +627,6 @@
                 "params": { "isolateId" : currentIsolate.id,
                             "libraryId": int.parse(args[1]),
                             "url": args[2] } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
   } else if (command == "tok" && args.length == 3) {
     var cmd = { "id": seqNum,
@@ -277,18 +634,15 @@
                 "params": { "isolateId" : currentIsolate.id,
                             "libraryId": int.parse(args[1]),
                             "url": args[2] } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
   } else if (command == "epi" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command":  "setPauseOnException",
                 "params": { "isolateId" : currentIsolate.id,
                             "exceptions": args[1] } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
   } else if (command == "li") {
     var cmd = { "id": seqNum, "command": "getIsolateIds" };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
   } else if (command == "sci" && args.length == 2) {
     var id = int.parse(args[1]);
@@ -298,22 +652,46 @@
     } else {
       print("$id is not a valid isolate id");
     }
+    cmdo.show();
   } else if (command == "i" && args.length == 2) {
     var cmd = { "id": seqNum,
                 "command": "interrupt",
                 "params": { "isolateId": int.parse(args[1]) } };
-    cmdo.hide();
     sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
-  } else if (command == "q") {
-    quitShell();
-  } else if (command == "h") {
-    printHelp();
-  } else {
+  } else if (command.length == 0) {
     huh();
+    cmdo.show();
+  } else {
+    // TODO(turnidge): Use this for all commands.
+    var matches = matchCommand(command, true);
+    if (matches.length == 0) {
+      huh();
+      cmdo.show();
+    } else if (matches.length == 1) {
+      matches[0].run(args).then((_) {
+          cmdo.show();
+        });
+    } else {
+      var matchNames = matches.map((handler) => handler.name);
+      print("Ambigous command '$command' : ${matchNames.toList()}");
+      cmdo.show();
+    }
   }
 }
 
 
+void processError(error, trace) {
+  cmdo.hide();
+  print("\nInternal error:\n$error\n$trace");
+  cmdo.show();
+}
+
+
+void processDone() {
+  debuggerQuit();
+}
+
+
 String remoteObject(value) {
   var kind = value["kind"];
   var text = value["text"];
@@ -762,85 +1140,169 @@
   // we hardcode the list here.
   //
   // TODO(turnidge): Implement completion for arguments as well.
-  List<String> allCommands = ['q', 'bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
+  List<String> oldCommands = ['bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
                               'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib',
-                              'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i', 'h'];
+                              'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i' ];
 
   // Completion of first word in the command.
   if (commandParts.length == 1) {
     String prefix = commandParts.last;
-    for (String command in allCommands) {
+    for (var command in oldCommands) {
       if (command.startsWith(prefix)) {
         completions.add(command);
       }
-    } 
+    }
+    for (var command in commandList) {
+      if (command.name.startsWith(prefix)) {
+        completions.add(command.name);
+      }
+    }
   }
 
   return completions;
 }
 
-void debuggerMain() {
+Future closeCommando() {
+  var subscription = cmdSubscription;
+  cmdSubscription = null;
+  cmdo = null;
+
+  var future = subscription.cancel();
+  if (future != null) {
+    return future;
+  } else {
+    return new Future.value();
+  }
+}
+
+
+Future openVmSocket(int attempt) {
+  return Socket.connect("127.0.0.1", debugPort).then(
+      setupVmSocket,
+      onError: (e) {
+        // We were unable to connect to the debugger's port.  Try again.
+        retryOpenVmSocket(e, attempt);
+      });
+}
+
+
+void setupVmSocket(Socket s) {
+  vmSock = s;
+  vmSock.setOption(SocketOption.TCP_NODELAY, true);
+  var stringStream = vmSock.transform(UTF8.decoder);
   outstandingCommands = new Map<int, Completer>();
-  Socket.connect("127.0.0.1", 5858).then((s) {
-    vmSock = s;
-    vmSock.setOption(SocketOption.TCP_NODELAY, true);
-    var stringStream = vmSock.transform(UTF8.decoder);
-    vmSubscription = stringStream.listen(
-        (String data) {
-          processVmData(data);
-        },
-        onDone: () {
+  vmSubscription = stringStream.listen(
+      (String data) {
+        processVmData(data);
+      },
+      onDone: () {
+        cmdo.hide();
+        if (verbose) {
           print("VM debugger connection closed");
-          quitShell();
-        },
-        onError: (err) {
-          print("Error in debug connection: $err");
-          // TODO(floitsch): do we want to print the stack trace?
-          quitShell();
-        });
-    cmdo = new Commando(stdin, stdout, processCommand,
-                        completer : debuggerCommandCompleter);
-  });
+        }
+        closeVmSocket().then((_) {
+            cmdo.show();
+          });
+      },
+      onError: (err) {
+        cmdo.hide();
+        // TODO(floitsch): do we want to print the stack trace?
+        print("Error in debug connection: $err");
+
+        // TODO(turnidge): Kill the debugged process here?
+        closeVmSocket().then((_) {
+            cmdo.show();
+          });
+      });
+}
+
+
+Future retryOpenVmSocket(error, int attempt) {
+  var delay;
+  if (attempt < 10) {
+    delay = new Duration(milliseconds:10);
+  } else if (attempt < 20) {
+    delay = new Duration(seconds:1);
+  } else {
+    // Too many retries.  Give up.
+    //
+    // TODO(turnidge): Kill the debugged process here?
+    print('Timed out waiting for debugger to start.\nError: $e');
+    return closeVmSocket();
+  }
+      
+  // Wait and retry.
+  return new Future.delayed(delay, () {
+      openVmSocket(attempt + 1);
+    });
+}
+
+
+Future closeVmSocket() {
+  if (vmSubscription == null) {
+    // Already closed, nothing to do.
+    assert(vmSock == null);
+    return new Future.value();
+  }
+
+  isDebugging = false;
+  var subscription = vmSubscription;
+  var sock = vmSock;
+
+  // Wait for the socket to close and the subscription to be
+  // cancelled.  Perhaps overkill, but it means we know these will be
+  // done.
+  //
+  // This is uglier than it needs to be since cancel can return null.
+  var cleanupFutures = [sock.close()];
+  var future = subscription.cancel();
+  if (future != null) {
+    cleanupFutures.add(future);
+  }
+
+  vmSubscription = null;
+  vmSock = null;
+  outstandingCommands = null;
+  
+  return Future.wait(cleanupFutures);
+}
+
+Future debuggerQuit() {
+  // Kill target process, if any.
+  if (targetProcess != null) {
+    if (!targetProcess.kill()) {
+      print('Unable to kill process ${targetProcess.pid}');
+    }
+  }
+
+  // Restore terminal settings, close connections.
+  return Future.wait([closeCommando(), closeVmSocket()]).then((_) {
+      exit(0);
+
+      // Unreachable.
+      return new Future.value();
+    });
+}
+
+
+void parseArgs(List<String> args) {
+  int pos = 0;
+  settings['vm'] = Platform.executable;
+  while (pos < args.length && args[pos].startsWith('-')) {
+    pos++;
+  }
+  if (pos < args.length) {
+    settings['vmargs'] = args.getRange(0, pos).join(' ');
+    settings['script'] = args[pos];
+    settings['args'] = args.getRange(pos + 1, args.length).join(' ');
+  }
 }
 
 void main(List<String> args) {
-  if (args.length > 0) {
-    if (verbose) {
-      args = <String>['--debug', '--verbose_debug']..addAll(args);
-    } else {
-      args = <String>['--debug']..addAll(args);
-    }
-    Process.start(Platform.executable, args).then((Process process) {
-        targetProcess = process;
-        process.stdin.close();
+  parseArgs(args);
 
-        // TODO(turnidge): For now we only show full lines of output
-        // from the debugged process.  Should show each character.
-        process.stdout
-            .transform(UTF8.decoder)
-            .transform(new LineSplitter())
-            .listen((String line) {
-                // Hide/show command prompt across asynchronous output.
-                if (cmdo != null) {
-                  cmdo.hide();
-                }
-                print("$line");
-                if (cmdo != null) {
-                  cmdo.show();
-                }
-              });
-
-        process.exitCode.then((int exitCode) {
-            if (exitCode == 0) {
-              print('Program exited normally.');
-            } else {
-              print('Program exited with code $exitCode.');
-            }
-          });
-
-      debuggerMain();
-    });
-  } else {
-    debuggerMain();
-  }
+  cmdo = new Commando(completer: debuggerCommandCompleter);
+  cmdSubscription = cmdo.commands.listen(processCommand,
+                                         onError: processError,
+                                         onDone: processDone);
 }
diff --git a/tools/ddbg/lib/commando.dart b/tools/ddbg/lib/commando.dart
index cb1fef2..f3ff3ea 100644
--- a/tools/ddbg/lib/commando.dart
+++ b/tools/ddbg/lib/commando.dart
@@ -30,18 +30,45 @@
   static const runeSpace   = 0x20;
   static const runeDEL     = 0x7F;
 
-  Commando(this._stdin,
-           this._stdout,
-           this._handleCommand,
-           {this.prompt : '> ', this.completer : null}) {
+  StreamController<String> _commandController;
+
+  Stream get commands => _commandController.stream;
+
+  Commando({consoleIn,
+            consoleOut,
+            this.prompt : '> ',
+          this.completer : null}) {
+    _stdin = (consoleIn != null ? consoleIn : stdin);
+    _stdout = (consoleOut != null ? consoleOut : stdout);
+    _commandController = new StreamController<String>(
+        onCancel: _onCancel);
     _stdin.echoMode = false;
     _stdin.lineMode = false;
     _screenWidth = _term.cols - 1;
     _writePrompt();
+    // TODO(turnidge): Handle errors in _stdin here.
     _stdinSubscription =
-        _stdin.transform(UTF8.decoder).listen(_handleText, onDone:done);
+        _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
   }
 
+  Future _onCancel() {
+    _stdin.echoMode = true;
+    _stdin.lineMode = true;
+    var future = _stdinSubscription.cancel();
+    if (future != null) {
+      return future;
+    } else {
+      return new Future.value();
+    }
+  }
+
+  // Before terminating, call close() to restore terminal settings.
+  void _done() {
+    _onCancel().then((_) {
+        _commandController.close();
+      });
+  }
+  
   void _handleText(String text) {
     try {
       if (!_promptShown) {
@@ -79,11 +106,7 @@
         }
       }
     } catch(e, trace) {
-      stderr.writeln('\nUnexpected exception: $e');
-      stderr.writeln(trace);
-      stderr.close().then((_) {
-          done();
-        });
+      _commandController.addError(e, trace);
     }
   }
 
@@ -102,8 +125,8 @@
       case runeCtrlD:
         if (_currentLine.length == 0) {
           // ^D on an empty line means quit.
-          _stdout.writeln();
-          done();
+          _stdout.writeln("^D");
+          _done();
         } else {
           _delete();
         }
@@ -207,12 +230,6 @@
     return (char >= 0x00 && char < 0x20) || (char == 0x7f);
   }
 
-  void done() {
-    _stdin.echoMode = true;
-    _stdin.lineMode = true;
-    _stdinSubscription.cancel();
-  }
-
   void _writePromptAndLine() {
     _writePrompt();
     var pos = _writeRange(_currentLine, 0, _currentLine.length);
@@ -263,6 +280,8 @@
 
   void _clearScreen() {
     _stdout.write(_term.clear);
+    _term.resize();
+    _screenWidth = _term.cols - 1;
     _writePromptAndLine();
   }
 
@@ -368,11 +387,10 @@
     _stdout.writeln();
 
     // Call the user's command handler.
-    _handleCommand(new String.fromCharCodes(_currentLine));
+    _commandController.add(new String.fromCharCodes(_currentLine));
     
     _currentLine = [];
     _cursorPos = 0;
-    _linePos = _lines.length;
     if (_promptShown) {
       _writePrompt();
     }
@@ -593,7 +611,6 @@
         
   int _nextMargin(int pos) {
     var truePos = pos + prompt.length;
-    var curLine = _getLine(pos);
     return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
   }
 
@@ -610,14 +627,12 @@
   Stdin _stdin;
   StreamSubscription _stdinSubscription;
   IOSink _stdout;
-  final _handleCommand;
   final String prompt;
   bool _promptShown = true;
   final CommandCompleter completer;
   TermInfo _term = new TermInfo();
 
-  // TODO(turnidge): Update screenwidth when we clear the screen.  See
-  // if we can get screen resize events too.
+  // TODO(turnidge): See if we can get screen resize events.
   int _screenWidth;
   List<int> _currentLine = [];  // A list of runes.
   StringBuffer _bufferedInput = new StringBuffer();
@@ -676,8 +691,11 @@
 
 void _handleCommand(String rawCommand) {
   String command = rawCommand.trim();
+  cmdo.hide();
   if (command == 'quit') {
-    cmdo.done();
+    cmdo.close().then((_) {
+        print('Exiting');
+      });
   } else if (command == 'help') {
     switch (_helpCount) {
       case 0:
@@ -702,11 +720,12 @@
   } else {
     print('Received command($command)');
   }
+  cmdo.show();
 }
 
 
 void main() {
-  stdout.writeln('[Commando demo]');
-  cmd = new Commando(stdin, stdout, _handleCommand,
-                     completer:_myCompleter);
+  print('[Commando demo]');
+  cmdo = new Commando(completer:_myCompleter);
+  cmdo.commands.listen(_handleCommand);
 }
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index f38bae1..665cd5e 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -113,10 +113,8 @@
 
   var options = JS('=Object', '{prototype: #}', proto);
 
-  if (baseClassName != 'HTMLElement') {
-    if (extendsTagName != null) {
-      JS('=Object', '#.extends = #', options, extendsTagName);
-    }
+  if (extendsTagName != null) {
+    JS('=Object', '#.extends = #', options, extendsTagName);
   }
 
   JS('void', '#.register(#, #)', document, tag, options);
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 75c699c..e54cc11 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -409,7 +409,7 @@
       throw new UnsupportedError("Invalid custom element from $libName.");
     }
     var className = MirrorSystem.getName(cls.simpleName);
-    var createdConstructor = cls.constructors[new Symbol('$className.created')];
+    var createdConstructor = cls.declarations[new Symbol('$className.created')];
     if (createdConstructor == null ||
         createdConstructor is! MethodMirror ||
         !createdConstructor.isConstructor) {
diff --git a/tools/publish_barback.py b/tools/publish_barback.py
deleted file mode 100755
index 87752b0..0000000
--- a/tools/publish_barback.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-#
-# 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.
-#
-# Script to push the barback package to pub. Barback is treated specially
-# because it is tightly coupled to the SDK. Pub includes its own copy of
-# barback but also includes code that is run against the user's copy of barback.
-# To ensure that those are in sync, each version of the SDK has a single
-# version of barback that it works with.
-#
-# We enforce this by placing a narrow SDK constraint in each version of barback.
-# This ensures the only barback that will be selected is the one that works
-# with the user's SDK. Once barback is more stable, we can loosen this.
-#
-# Usage: publish_barback.py
-#
-# "pub" must be in PATH.
-
-import os
-import os.path
-import shutil
-import sys
-import subprocess
-import tempfile
-
-import utils
-
-def Main(argv):
-  HOME = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-  BARBACK = os.path.join(HOME, 'pkg', 'barback')
-
-  (channel, major, minor, service, qualifier) = utils.ReadVersionFile()
-  major = int(major)
-  minor = int(minor)
-  service = int(service)
-
-  # The bleeding_edge branch has a fixed version number of 0.1.x.y. Don't allow
-  # users to publish packages from there.
-  if (major == 0 and minor <= 1) or channel == 'be':
-    print 'Error: Do not run this script from a bleeding_edge checkout.'
-    #return -1
-
-  # Convert the version to semver syntax.
-  version = '%d.%d.%d+%s' % (major, minor, service, qualifier)
-
-  # Copy the package to a temp directory so we can fill in its pubspec.
-  tmpDir = tempfile.mkdtemp()
-  shutil.copytree(os.path.join(HOME, BARBACK), os.path.join(tmpDir, 'barback'))
-
-  pubspecPath = os.path.join(tmpDir, 'barback', 'pubspec.yaml')
-  with open(pubspecPath) as pubspecFile:
-    pubspec = pubspecFile.read()
-
-  # Fill in the SDK version constraint. It pins barback to the current version
-  # of the SDK with a small amount of wiggle room for hotfixes.
-  constraint = '>=%d.%d.%d <%d.%d.0' % (major, minor, service, major, minor + 1)
-
-  # Fill in the SDK version constraint.
-  pubspec = pubspec.replace('$SDK_CONSTRAINT$', constraint)
-
-  # Give barback a new version that roughly mirrors the SDK, like so:
-  # SDK 1.2.3+4 --> barback 0.12.3+4.
-  barback_version = 'version: 0.%d.%d+%s # Set by publish_barback.py.' % (
-      10 + minor, service, qualifier)
-  pubspec = pubspec.replace(
-      'version: 0.9.0 # Replaced by publish_barback.py. Do not edit.',
-      barback_version)
-
-  return
-
-  with open(pubspecPath, 'w') as pubspecFile:
-    pubspecFile.write(pubspec)
-
-  print ('Publishing barback %s with SDK constraint "%s".' %
-      (version, constraint))
-  subprocess.call(['pub', 'lish'], cwd=os.path.join(tmpDir, 'barback'))
-  shutil.rmtree(tmpDir)
-
-if __name__ == '__main__':
-  sys.exit(Main(sys.argv))
diff --git a/tools/test.dart b/tools/test.dart
index c96084d..b7afb77 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -99,9 +99,12 @@
   }
 
   if (!firstConf['append_logs'])  {
-    var file = new File(TestUtils.flakyFileName());
-    if (file.existsSync()) {
-      file.deleteSync();
+    var files = [new File(TestUtils.flakyFileName()),
+                 new File(TestUtils.testOutcomeFileName())];
+    for (var file in files) {
+      if (file.existsSync()) {
+        file.deleteSync();
+      }
     }
   }
 
@@ -240,6 +243,9 @@
     eventListener.add(new SkippedCompilationsPrinter());
     eventListener.add(new LeftOverTempDirPrinter());
   }
+  if (firstConf['write_test_outcome_log']) {
+    eventListener.add(new TestOutcomeLogWriter());
+  }
   eventListener.add(new ExitCodeSetter());
 
   void startProcessQueue() {
diff --git a/tools/testing/dart/co19_test.dart b/tools/testing/dart/co19_test.dart
index dc28b47..e793344 100644
--- a/tools/testing/dart/co19_test.dart
+++ b/tools/testing/dart/co19_test.dart
@@ -42,13 +42,14 @@
                    '--minified'],
     const <String>['-mrelease', '-rd8,jsshell', '-cdart2js', '--use-sdk',
                    '--checked'],
+    const <String>['-mrelease', '-rdartium', '-cnone', '--use-sdk',
+                   '--checked'],
+    const <String>['-mrelease', '-rdartium', '-cnone', '--use-sdk'],
 ];
 
-void main() {
-  Options options = new Options();
-  File scriptFile = new File(options.script);
-  Path scriptPath =
-      new Path(scriptFile.fullPathSync())
+void main(List<String> args) {
+  File scriptFile = new File(new Path(Platform.script.path).toNativePath());
+  Path scriptPath = new Path(scriptFile.absolute.path)
       .directoryPath.directoryPath.directoryPath.append('test.dart');
   TestUtils.testScriptPath = scriptPath.toNativePath();
   var optionsParser = new TestOptionsParser();
@@ -56,7 +57,7 @@
   for (var commandLine in COMMAND_LINES) {
     List arguments = <String>[];
     arguments.addAll(COMMON_ARGUMENTS);
-    arguments.addAll(options.arguments);
+    arguments.addAll(args);
     arguments.addAll(commandLine);
     configurations.addAll(optionsParser.parse(arguments));
   }
diff --git a/tools/testing/dart/test_controller.js b/tools/testing/dart/test_controller.js
index 806a7f9..e0ca295 100644
--- a/tools/testing/dart/test_controller.js
+++ b/tools/testing/dart/test_controller.js
@@ -149,6 +149,9 @@
     // messages to the window.opener.
     var driver = getDriverWindow();
 
+    recordEvent('debug', 'Sending events to driver page (isFirstMessage = ' +
+                isFirstMessage + ', isStatusUpdate = ' +
+                isStatusUpdate + ', isDone = ' + isDone + ')');
     // Post the DOM and all events that happened.
     var events = recordedEventList.slice(0);
     events.push(buildDomEvent());
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index 48f1310..c0af640 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -301,6 +301,15 @@
               'bool'
               ),
           new _TestOptionSpecification(
+              'write_test_outcome_log',
+              'Write the outcome of all tests executed to a '
+              '"${TestUtils.flakyFileName()}" file.',
+              ['--write-test-outcome-log'],
+              [],
+              false,
+              'bool'
+          ),
+          new _TestOptionSpecification(
               'clear_safari_cache',
               'Clear the safari cache (i.e., delete it).',
               ['--clear_safari_cache'],
@@ -358,7 +367,7 @@
               [],
               null),
           new _TestOptionSpecification(
-              'vm-options',
+              'vm_options',
               'Extra options to send to the vm when running',
               ['--vm-options'],
               [],
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index ea31bfc..1ebc541 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -7,6 +7,7 @@
 import "dart:async";
 import "dart:io";
 import "dart:io" as io;
+import "dart:convert" show JSON;
 import "status_file_parser.dart";
 import "test_runner.dart";
 import "test_suite.dart";
@@ -189,6 +190,91 @@
   }
 }
 
+class TestOutcomeLogWriter extends EventListener {
+  /*
+   * The ".test-outcome.log" file contains one line for every executed test.
+   * Such a line is an encoded JSON data structure of the following form:
+   * The durations are double values in milliseconds.
+   *
+   *  {
+   *     name: 'co19/LibTest/math/x',
+   *     configuration: {
+   *       mode : 'release',
+   *       compiler : 'dart2js',
+   *       ....
+   *     },
+   *     test_result: {
+   *       outcome: 'RuntimeError',
+   *       expected_outcomes: ['Pass', 'Fail'],
+   *       duration: 2600.64,
+   *       command_results: [
+   *         {
+   *           name: 'dart2js',
+   *           duration: 2400.44,
+   *         },
+   *         {
+   *           name: 'ff',
+   *           duration: 200.2,
+   *         },
+   *       ],
+   *     }
+   *  },
+   */
+
+  static final INTERESTED_CONFIGURATION_PARAMETERS =
+      ['mode', 'arch', 'compiler', 'runtime', 'checked', 'host_checked',
+       'minified', 'csp', 'system', 'vm_options', 'use_sdk'];
+
+  IOSink _sink;
+
+  void done(TestCase test) {
+    var name = test.displayName;
+    var configuration = {};
+    for (var key in INTERESTED_CONFIGURATION_PARAMETERS) {
+      configuration[key] = test.configuration[key];
+    }
+    var outcome = '${test.lastCommandOutput.result(test)}';
+    var expectations =
+        test.expectedOutcomes.map((expectation) => "$expectation").toList();
+
+    var commandResults = [];
+    double totalDuration = 0.0;
+    for (var command in test.commands) {
+      var output = test.commandOutputs[command];
+      if (output != null) {
+        double duration = output.time.inMicroseconds/1000.0;
+        totalDuration += duration;
+        commandResults.add({
+          'name': command.displayName,
+          'duration': duration,
+        });
+      }
+    }
+    _writeTestOutcomeRecord({
+      'name' : name,
+      'configuration' : configuration,
+      'test_result' : {
+        'outcome' : outcome,
+        'expected_outcomes' : expectations,
+        'duration' : totalDuration,
+        'command_results' : commandResults,
+      },
+    });
+  }
+
+  void allDone() {
+    _sink.close();
+  }
+
+  void _writeTestOutcomeRecord(Map record) {
+    if (_sink == null) {
+      _sink = new File(TestUtils.testOutcomeFileName())
+          .openWrite(mode: FileMode.APPEND);
+    }
+    _sink.write("${JSON.encode(record)}\n");
+  }
+}
+
 class SummaryPrinter extends EventListener {
   void allTestsKnown() {
     if (SummaryReport.total > 0) {
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 867d374..9745387 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -1782,6 +1782,12 @@
     return ".flaky.log";
   }
 
+  static String testOutcomeFileName() {
+    // If test.py was invoked with '--write-test-outcome-log it will write
+    // test outcomes to this file.
+    return ".test-outcome.log";
+  }
+
   static void ensureExists(String filename, Map configuration) {
     if (!configuration['list'] && !(new File(filename).existsSync())) {
       throw "Executable '$filename' does not exist";
@@ -1917,8 +1923,8 @@
    */
   static List<String> getExtraVmOptions(Map configuration) {
     var extraVmOptions = [];
-    if (configuration['vm-options'] != null) {
-      extraVmOptions = configuration['vm-options'].split(" ");
+    if (configuration['vm_options'] != null) {
+      extraVmOptions = configuration['vm_options'].split(" ");
       extraVmOptions.removeWhere((s) => s.trim() == "");
     }
     return extraVmOptions;
diff --git a/utils/apidoc/apidoc.gyp b/utils/apidoc/apidoc.gyp
index 7707557..3c41afe 100644
--- a/utils/apidoc/apidoc.gyp
+++ b/utils/apidoc/apidoc.gyp
@@ -91,7 +91,6 @@
             '--exclude-lib=dartdoc',
             '--exclude-lib=docgen',
             '--exclude-lib=expect',
-            '--exclude-lib=http',
             '--exclude-lib=oauth2',
             '--exclude-lib=scheduled_test',
             '--exclude-lib=stack_trace',